schleuder 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/LICENSE +339 -0
- data/README +32 -0
- data/bin/schleuder +96 -0
- data/bin/schleuder-fix-gem-dependencies +30 -0
- data/bin/schleuder-init-setup +37 -0
- data/bin/schleuder-migrate-v2.1-to-v2.2 +205 -0
- data/bin/schleuder-newlist +384 -0
- data/contrib/check-expired-keys.rb +59 -0
- data/contrib/mutt-schleuder-colors.rc +10 -0
- data/contrib/mutt-schleuder-resend.vim +24 -0
- data/contrib/smtpserver.rb +76 -0
- data/ext/default-list.conf +146 -0
- data/ext/default-members.conf +7 -0
- data/ext/list.conf.example +14 -0
- data/ext/schleuder.conf +62 -0
- data/lib/schleuder.rb +49 -0
- data/lib/schleuder/archiver.rb +46 -0
- data/lib/schleuder/crypt.rb +188 -0
- data/lib/schleuder/errors.rb +5 -0
- data/lib/schleuder/list.rb +177 -0
- data/lib/schleuder/list_config.rb +146 -0
- data/lib/schleuder/log/listlogger.rb +56 -0
- data/lib/schleuder/log/outputter/emailoutputter.rb +118 -0
- data/lib/schleuder/log/outputter/metaemailoutputter.rb +50 -0
- data/lib/schleuder/log/schleuderlogger.rb +23 -0
- data/lib/schleuder/mail.rb +861 -0
- data/lib/schleuder/mailer.rb +26 -0
- data/lib/schleuder/member.rb +69 -0
- data/lib/schleuder/plugin.rb +54 -0
- data/lib/schleuder/processor.rb +363 -0
- data/lib/schleuder/schleuder_config.rb +72 -0
- data/lib/schleuder/storage.rb +84 -0
- data/lib/schleuder/utils.rb +80 -0
- data/lib/schleuder/version.rb +3 -0
- data/man/schleuder-newlist.8 +191 -0
- data/man/schleuder.8 +400 -0
- data/plugins/README +20 -0
- data/plugins/manage_keys_plugin.rb +113 -0
- data/plugins/manage_members_plugin.rb +152 -0
- data/plugins/manage_self_plugin.rb +26 -0
- data/plugins/resend_plugin.rb +35 -0
- data/plugins/version_plugin.rb +12 -0
- metadata +178 -0
- metadata.gz.sig +2 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# We need to install one more gem depending on the used ruby-version.
|
4
|
+
# Unfortunately this isn't possible inside of rubygems, therefore we do it
|
5
|
+
# here.
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubygems/dependency_installer.rb'
|
9
|
+
|
10
|
+
inst = Gem::DependencyInstaller.new
|
11
|
+
spec = Gem::Specification.find_by_name 'schleuder'
|
12
|
+
|
13
|
+
begin
|
14
|
+
if RUBY_VERSION < "1.9"
|
15
|
+
name = 'tmail'
|
16
|
+
ver = '=1.2.3.1'
|
17
|
+
else
|
18
|
+
name = 'actionmailer'
|
19
|
+
ver = '=2.3.14'
|
20
|
+
end
|
21
|
+
inst.install name, ver
|
22
|
+
spec.add_dependency name, ver
|
23
|
+
# Write spec back to file, from rubygems/installer.rb
|
24
|
+
File.open(spec.spec_file.untaint, "w") do |f|
|
25
|
+
f << spec.to_ruby_for_cache
|
26
|
+
end
|
27
|
+
rescue Gem::FilePermissionError => e
|
28
|
+
$stderr.puts "Error: #{e.message}"
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$VERBOSE = nil
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
require 'schleuder/utils'
|
7
|
+
require 'highline/system_extensions'
|
8
|
+
|
9
|
+
def usage
|
10
|
+
puts "Usage: #{File.basename(__FILE__)} --gem | /path/to/schleuder"
|
11
|
+
puts "Creates neccessary directories and copies default configurations to /etc/schleuder.\n".fmt
|
12
|
+
end
|
13
|
+
|
14
|
+
def copy(basedir)
|
15
|
+
%w(/etc/schleuder /var/log/schleuder).each do |dir|
|
16
|
+
FileUtils.mkdir(dir) unless File.directory?(dir)
|
17
|
+
end
|
18
|
+
files = Dir.glob(File.join(basedir, 'ext', '*')).reject { |f| ['Rakefile'].include?(f) }
|
19
|
+
FileUtils.cp(files, '/etc/schleuder/')
|
20
|
+
rescue Errno::EACCES => e
|
21
|
+
puts "#{e.message}"
|
22
|
+
puts "Please retry with appropriate privileges!"
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
|
26
|
+
case ARGV.first
|
27
|
+
when nil,/-h|--help/
|
28
|
+
usage
|
29
|
+
exit 1
|
30
|
+
when /--gem/
|
31
|
+
require 'rubygems'
|
32
|
+
spec = Gem::Specification.find_by_name('schleuder')
|
33
|
+
copy(spec.gem_dir)
|
34
|
+
else
|
35
|
+
copy(ARGV.first)
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,205 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
4
|
+
require 'schleuder'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'yaml'
|
7
|
+
require 'open3'
|
8
|
+
require 'highline/system_extensions'
|
9
|
+
|
10
|
+
def usage
|
11
|
+
puts "Usage: #{File.basename(__FILE__)} [-c /path/to/base/schleuder.conf] /path/to/a/list.config"
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
usage if ![1,3].include?(ARGV.length)
|
16
|
+
|
17
|
+
if (list_config = ARGV.shift) == '-c'
|
18
|
+
baseconfig = File.expand_path(ARGV.shift)
|
19
|
+
usage unless File.exist?(baseconfig)
|
20
|
+
Schleuder.config(baseconfig)
|
21
|
+
list_config = ARGV.shift
|
22
|
+
end
|
23
|
+
|
24
|
+
usage unless File.exist?(list_config = File.expand_path(list_config))
|
25
|
+
|
26
|
+
def notice(msg)
|
27
|
+
puts msg.fmt
|
28
|
+
end
|
29
|
+
|
30
|
+
def move_listdir(old_dir,old_config)
|
31
|
+
list_dir = old_config['myaddr'].split('@').reverse
|
32
|
+
if old_dir =~ /#{list_dir.join('\/')}/
|
33
|
+
notice("The current directory of the list seems already to match the new style. Did you already migrate that list? As I can't be sure what might be right or wrong, I exit here.")
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
|
37
|
+
hostdir = File.expand_path(File.join(Schleuder.config.lists_dir, list_dir.first))
|
38
|
+
FileUtils.mkdir_p(hostdir) unless File.directory?(hostdir)
|
39
|
+
|
40
|
+
FileUtils.mv(old_dir, hostdir)
|
41
|
+
notice("Moved list-dir to #{File.join(hostdir, Schleuder.list.listname)}.")
|
42
|
+
File.expand_path(File.join(Schleuder.config.lists_dir, list_dir.join('/')))
|
43
|
+
end
|
44
|
+
|
45
|
+
def member_key(member)
|
46
|
+
key,msg = member.key
|
47
|
+
unless key
|
48
|
+
notice("Can't find unique key for #{member}. Reason: #{msg}")
|
49
|
+
end
|
50
|
+
member
|
51
|
+
end
|
52
|
+
|
53
|
+
def fix_list_conf(old_config,new_dir)
|
54
|
+
if old_config.delete('logging').to_s == 'true' && !old_config['lists_logfile'].nil?
|
55
|
+
old_config['log_file'] = old_config.delete('lists_logfile')
|
56
|
+
end
|
57
|
+
|
58
|
+
unless old_config['loglevel'].nil?
|
59
|
+
old_config['log_level'] = old_config.delete('loglevel')
|
60
|
+
end
|
61
|
+
|
62
|
+
if old_config.delete('log_rotate_keep')
|
63
|
+
notice("Schleuder doesn't care about log-rotation anymore, please set up logrotate.conf or similar instead.")
|
64
|
+
end
|
65
|
+
|
66
|
+
old_config['admins'] = old_config.delete('adminaddr').collect do |admin|
|
67
|
+
m = member_key(Schleuder::Member.new(:email => admin))
|
68
|
+
m.to_hash
|
69
|
+
end
|
70
|
+
old_config['key_fingerprint'] = Schleuder.list.key_fingerprint
|
71
|
+
|
72
|
+
File.open(File.join(new_dir, Schleuder.config.lists_configfile),'w') { |f| f << YAML::dump(old_config.to_hash) }
|
73
|
+
# reload list config
|
74
|
+
Schleuder.list = Schleuder::List.new(old_config['myaddr'])
|
75
|
+
end
|
76
|
+
|
77
|
+
def harden_members
|
78
|
+
Schleuder.list.members = Schleuder.list.members.collect { |member| member_key(member) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def change_pubkey(old_config)
|
82
|
+
_name = old_config['myname']
|
83
|
+
_email = old_config['myaddr']
|
84
|
+
_pass = old_config['gpg_password']
|
85
|
+
|
86
|
+
# Fix for gpgme-ruby >= 1.0.8
|
87
|
+
GPGME::check_version('0.0.0') if GPGME.respond_to?('check_version')
|
88
|
+
|
89
|
+
# Add listname-request@ and listname-ownerhostname as UID.
|
90
|
+
gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email} adduid"
|
91
|
+
Open3.popen3(gpg_adduid) do |stdin, stdout, stderr|
|
92
|
+
owner_done = false
|
93
|
+
request_done = false
|
94
|
+
while line = stdout.readline rescue nil;
|
95
|
+
case line.chomp
|
96
|
+
when '[GNUPG:] GET_LINE keygen.name' then
|
97
|
+
reply = _name
|
98
|
+
when '[GNUPG:] GET_LINE keygen.email' then
|
99
|
+
if !request_done
|
100
|
+
email = _email.sub(/@/, '-request@')
|
101
|
+
request_done = true
|
102
|
+
else
|
103
|
+
email = _email.sub(/@/, '-owner@')
|
104
|
+
end
|
105
|
+
reply = email
|
106
|
+
when '[GNUPG:] GET_LINE keygen.comment' then
|
107
|
+
reply = 'schleuder list'
|
108
|
+
when '[GNUPG:] GET_HIDDEN passphrase.enter' then
|
109
|
+
reply = _pass
|
110
|
+
when '[GNUPG:] GET_LINE keyedit.prompt' then
|
111
|
+
if !owner_done
|
112
|
+
reply = "adduid"
|
113
|
+
owner_done = true
|
114
|
+
else
|
115
|
+
reply = "save"
|
116
|
+
end
|
117
|
+
else
|
118
|
+
reply = nil
|
119
|
+
end
|
120
|
+
#$stderr.puts line
|
121
|
+
if reply
|
122
|
+
#$stderr.puts reply
|
123
|
+
stdin.puts reply
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Make list@host the primary UID to avoid confusion.
|
129
|
+
# For some f***** up reason these two time calling gpg do not work in one run.
|
130
|
+
gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email}"
|
131
|
+
Open3.popen3(gpg_adduid) do |stdin, stdout,stderr|
|
132
|
+
uid_done = false
|
133
|
+
primary_done = false
|
134
|
+
while line = stdout.readline rescue nil;
|
135
|
+
case line.chomp
|
136
|
+
when '[GNUPG:] GET_LINE keyedit.prompt' then
|
137
|
+
if ! uid_done
|
138
|
+
reply = "uid 2"
|
139
|
+
uid_done = true
|
140
|
+
elsif ! primary_done
|
141
|
+
reply = "primary"
|
142
|
+
primary_done = true
|
143
|
+
else
|
144
|
+
reply = "save"
|
145
|
+
end
|
146
|
+
when '[GNUPG:] GET_HIDDEN passphrase.enter' then
|
147
|
+
reply = _pass
|
148
|
+
else
|
149
|
+
reply = nil
|
150
|
+
end
|
151
|
+
#$stderr.puts line
|
152
|
+
if reply
|
153
|
+
#$stderr.puts reply
|
154
|
+
stdin.puts reply
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
$stderr.puts
|
159
|
+
notice("Added address-extensions as UIDs to public key of list.")
|
160
|
+
end
|
161
|
+
|
162
|
+
## run
|
163
|
+
|
164
|
+
|
165
|
+
old_config = YAML.load_file(list_config)
|
166
|
+
old_config['myname']||=File.basename(File.dirname(list_config))
|
167
|
+
Schleuder.list = Schleuder::List.new(File.basename(File.dirname(list_config)))
|
168
|
+
old_dir = File.dirname(list_config)
|
169
|
+
|
170
|
+
files = Dir["#{old_dir}/*"].inject({}) do |files, file|
|
171
|
+
files[File.basename(file)] = [:uid, :gid, :mode].inject({}) do |hash, sym|
|
172
|
+
hash[sym] = File.stat(file).send(sym)
|
173
|
+
hash
|
174
|
+
end
|
175
|
+
files
|
176
|
+
end
|
177
|
+
|
178
|
+
ENV['GNUPGHOME'] = new_dir = move_listdir(old_dir,old_config)
|
179
|
+
ENV.delete('GPG_AGENT_INFO') # might interfer with changing uids
|
180
|
+
|
181
|
+
change_pubkey(old_config)
|
182
|
+
fix_list_conf(old_config, new_dir)
|
183
|
+
harden_members
|
184
|
+
|
185
|
+
# Fix owner/modes if changed
|
186
|
+
files.each do |file, stat|
|
187
|
+
file = File.join(new_dir,file)
|
188
|
+
[file, "#{file}~"].each do |f|
|
189
|
+
if File.exist?(f)
|
190
|
+
File.chown(stat[:uid], stat[:gid], f) if File.stat(f).uid != stat[:uid] || File.stat(f).gid != stat[:gid]
|
191
|
+
File.chmod(stat[:mode], f) if File.stat(f).mode != stat[:mode]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
puts "There're some manual steps required to finalize the migration:
|
197
|
+
- add two aliases for the list to your MTA:
|
198
|
+
#{Schleuder.list.request_addr}
|
199
|
+
and
|
200
|
+
#{Schleuder.list.owner_addr}
|
201
|
+
|
202
|
+
Running now the Schleuder test routine, which might give additional hints if something might be wrong"
|
203
|
+
|
204
|
+
Schleuder::Processor.test(old_config['myaddr'])
|
205
|
+
|
@@ -0,0 +1,384 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
4
|
+
require 'schleuder'
|
5
|
+
require 'etc'
|
6
|
+
require 'open3'
|
7
|
+
|
8
|
+
class ListCreator
|
9
|
+
def self.usage
|
10
|
+
puts "Usage:
|
11
|
+
Required options:
|
12
|
+
listname@hostname.tld
|
13
|
+
Not required options (user will be promted unless -nointeractive is set or not run in a terminal),
|
14
|
+
-realname \"Foo List\"
|
15
|
+
-adminaddress listadmin@foobar.com
|
16
|
+
-initmember member1@foobar.com -initmemberkey /path/to/initmember_publickey
|
17
|
+
Optional options (flags on the same line have to be used together):
|
18
|
+
-mailuser mail (The user, which will invoke schleuder from your MTA, if non is supplied, the current user is taken)
|
19
|
+
-privatekeyfile /path/to/privatekey -publickeyfile /path/to/publickey -passphrase key_passphrase
|
20
|
+
-nointeractive
|
21
|
+
|
22
|
+
#{File.basename($0)} listname@hostname.tld (-realname \"Foo List\") (-adminaddress listadmin@foobar.com) (-initmember member1@foobar.com -initmemberkey /path/to/initmember_publickey) [-privatekeyfile /path/to/privatekey -publickeyfile /path/to/publickey -passphrase key_passphrase] [-nointeractive]"
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def self.process(arg)
|
28
|
+
# set safe umask
|
29
|
+
File.umask(0077)
|
30
|
+
|
31
|
+
listname = ARGV.shift.to_s
|
32
|
+
usage unless listname.split('@').size == 2
|
33
|
+
args = Hash.new
|
34
|
+
interactive = STDIN.tty?
|
35
|
+
while nextarg = ARGV.shift
|
36
|
+
if nextarg == '-realname'
|
37
|
+
args[:list_realname] = ARGV.shift
|
38
|
+
elsif nextarg == '-c'
|
39
|
+
Schleuder.config(ARGV.shift)
|
40
|
+
elsif nextarg == '-adminaddress'
|
41
|
+
args[:list_adminaddress] = ARGV.shift
|
42
|
+
elsif nextarg == '-initmember'
|
43
|
+
args[:list_initmember] = ARGV.shift
|
44
|
+
elsif nextarg == '-initmemberkey'
|
45
|
+
args[:list_initmemberkey] = ARGV.shift
|
46
|
+
elsif nextarg == '-privatekeyfile'
|
47
|
+
args[:list_privatekeyfile] = ARGV.shift
|
48
|
+
elsif nextarg == '-publickeyfile'
|
49
|
+
args[:list_publickeyfile] = ARGV.shift
|
50
|
+
elsif nextarg == '-passphrase'
|
51
|
+
args[:list_passphrase] = ARGV.shift
|
52
|
+
elsif nextarg == '-mailuser'
|
53
|
+
args[:mailuser] = ARGV.shift
|
54
|
+
elsif nextarg == '-nointeractive'
|
55
|
+
interactive = false
|
56
|
+
else
|
57
|
+
usage
|
58
|
+
end
|
59
|
+
end
|
60
|
+
Schleuder.log.debug "Calling Processor.newlist(#{listname})"
|
61
|
+
begin
|
62
|
+
ListCreator::create(listname,interactive,args)
|
63
|
+
rescue NewListError => e
|
64
|
+
puts "Error while creating new list: " + e.message
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a new list
|
70
|
+
# listname: name of the list
|
71
|
+
# interactive: Wether we can ask for missing informations. This requires ruby-highline! (Default: true)
|
72
|
+
# args: additional parameters as hash
|
73
|
+
def self.create(listname,interactive=true,args=nil)
|
74
|
+
|
75
|
+
# verfiy all arguments quite in a huge block
|
76
|
+
Schleuder.log.debug "Verifying arguments..."
|
77
|
+
args = Hash.new if args.nil?
|
78
|
+
begin
|
79
|
+
require 'highline/import' if interactive
|
80
|
+
rescue LoadError => ex
|
81
|
+
puts "Unable to load 'highline'.\n\n"
|
82
|
+
puts "Please install the highline gem before trying to use"
|
83
|
+
puts "#{$0} in interactive mode."
|
84
|
+
exit 1
|
85
|
+
end
|
86
|
+
|
87
|
+
# verify basic information
|
88
|
+
Schleuder.log.debug "Verifying basic information..."
|
89
|
+
listname = ListCreator::verify_strvar(listname,interactive,"The listname")
|
90
|
+
listdir = File.join([Schleuder.config.lists_dir, listname.split('@').reverse].flatten)
|
91
|
+
raise NewListError, "List or parts of a list named: #{listname} already exists!" if File.directory?(listdir)
|
92
|
+
list_email = ListCreator::verify_emailvar(listname,interactive,"The lists's email address")
|
93
|
+
list_realname = ListCreator::verify_strvar(args[:list_realname],interactive,"'Realname' (for GPG-key and email-headers)")
|
94
|
+
list_adminaddress = ListCreator::verify_emailvar(args[:list_adminaddress],interactive,"Admin email address")
|
95
|
+
|
96
|
+
raise NewListError,"Lists' email address and the admin address can't be the same" if list_email == list_adminaddress
|
97
|
+
|
98
|
+
# verify keyfiles
|
99
|
+
Schleuder.log.debug "Verifying keyfiles..."
|
100
|
+
list_privatekeyfile = args[:list_privatekeyfile] || 'none'
|
101
|
+
list_publickeyfile = args[:list_publickeyfile] || 'none'
|
102
|
+
list_passphrase = args[:list_passphrase] || 'none'
|
103
|
+
unless args[:mailuser].nil?
|
104
|
+
mailuser = Etc.getpwnam(args[:mailuser]).uid
|
105
|
+
else
|
106
|
+
mailuser = Process::Sys.getuid
|
107
|
+
end
|
108
|
+
unless (list_privatekeyfile == 'none') and
|
109
|
+
(list_publickeyfile == 'none') and
|
110
|
+
(list_passphrase == 'none') then
|
111
|
+
list_privatekeyfile = ListCreator::verify_filevar(
|
112
|
+
args[:list_privatekeyfile] || '',
|
113
|
+
interactive,
|
114
|
+
"the lists' private key file"
|
115
|
+
)
|
116
|
+
list_publickeyfile = ListCreator::verify_filevar(
|
117
|
+
args[:list_publickeyfile] || '',
|
118
|
+
interactive,
|
119
|
+
"the lists' public key file"
|
120
|
+
)
|
121
|
+
list_passphrase = ListCreator::verify_strvar(
|
122
|
+
args[:list_passphrase] || '',
|
123
|
+
interactive,
|
124
|
+
"the lists' key passphrase",
|
125
|
+
false
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Verify init member
|
130
|
+
Schleuder.log.debug "Verifying init member..."
|
131
|
+
list_initmember = ListCreator::verify_emailvar(
|
132
|
+
args[:list_initmember] || '',
|
133
|
+
interactive,
|
134
|
+
"Email address of the lists' initial member"
|
135
|
+
)
|
136
|
+
list_initmemberkey = ListCreator::verify_filevar(
|
137
|
+
args[:list_initmemberkey] || '',
|
138
|
+
interactive,
|
139
|
+
"the public key of the lists' initial member"
|
140
|
+
)
|
141
|
+
Schleuder.log.debug "Arguments verified..."
|
142
|
+
|
143
|
+
Schleuder.log.debug "Initialize list..."
|
144
|
+
list = ListCreator::init_list(listname,listdir)
|
145
|
+
|
146
|
+
Schleuder.log.debug "Set list options..."
|
147
|
+
list.config.myaddr = list_email.to_s
|
148
|
+
list.config.myname = list_realname.to_s
|
149
|
+
|
150
|
+
if list_passphrase == 'none' then
|
151
|
+
list.config.gpg_password = Schleuder::Utils::random_password.to_s
|
152
|
+
else
|
153
|
+
list.config.gpg_password = list_passphrase.to_s
|
154
|
+
end
|
155
|
+
|
156
|
+
if (list_privatekeyfile == 'none' and list_publickeyfile == 'none') then
|
157
|
+
Schleuder.log.debug "Generate list's keypair..."
|
158
|
+
puts "Creating list key, this can take some time..." if interactive
|
159
|
+
ListCreator::generate_fresh_keypair(listdir,list.config,interactive)
|
160
|
+
else
|
161
|
+
Schleuder.log.debug "Import list's keypair..."
|
162
|
+
ListCreator::import_keypair(list,list_privatekeyfile,list_publickeyfile)
|
163
|
+
end
|
164
|
+
if (list_initmember != 'none' and list_initmemberkey != 'none') then
|
165
|
+
Schleuder.log.debug "Add initmember to list..."
|
166
|
+
ListCreator::add_init_member(list,list_initmember,list_initmemberkey)
|
167
|
+
end
|
168
|
+
|
169
|
+
# set the lists key_fingerprint
|
170
|
+
list.config.key_fingerprint = list.key_fingerprint
|
171
|
+
|
172
|
+
# add the admin here, as we should have already imported the key at this point
|
173
|
+
new_admin = Schleuder::Member.new(:email => list_adminaddress.to_s)
|
174
|
+
key, msg = new_admin.key
|
175
|
+
if key
|
176
|
+
new_admin.key_fingerprint = key.subkeys.first.fingerprint
|
177
|
+
list.config.admins = new_admin
|
178
|
+
else
|
179
|
+
raise NewListError,"Could not find a suitable key for the list admin. Reason: #{msg}"
|
180
|
+
end
|
181
|
+
|
182
|
+
# store the config
|
183
|
+
Schleuder.log.debug "Store list config..."
|
184
|
+
list.config = list.config
|
185
|
+
Schleuder.log.debug "Changing ownership..."
|
186
|
+
ListCreator::filepermissions(listdir,mailuser)
|
187
|
+
Schleuder.log.debug "List successfully created..."
|
188
|
+
ListCreator::print_list_infos(list) if interactive
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def self.init_list(listname,listdir)
|
194
|
+
require 'fileutils'
|
195
|
+
FileUtils.mkdir_p(listdir)
|
196
|
+
list = Schleuder::List.new(listname,true)
|
197
|
+
ENV['GNUPGHOME'] = listdir
|
198
|
+
list
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.add_init_member(list,list_initmember,list_initmemberkey)
|
202
|
+
if key = Schleuder::Crypt.new(list.config.gpg_password).add_key_from_file(list_initmemberkey).imports.first
|
203
|
+
list.members = Array.new(1,Schleuder::Member.new({ :email => list_initmember, :key_fingerprint => key.fingerprint }))
|
204
|
+
else
|
205
|
+
raise NewListError,"Importing the init member key failed for some reason. Please verify the passed keyfile!"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.verify_strvar(var,interactive,question, echo=true)
|
210
|
+
if (var.nil? or var.empty?) and interactive then
|
211
|
+
str = question+": "
|
212
|
+
if echo
|
213
|
+
var = ask(str)
|
214
|
+
else
|
215
|
+
var = ask(str) { |question| question.echo = '*' }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
raise NewListError,"Missing mandatory variable: "+question if (var.nil? or var.empty?)
|
219
|
+
var
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.verify_emailvar(var,interactive,question)
|
223
|
+
var = ListCreator::verify_strvar(var,interactive,question)
|
224
|
+
begin
|
225
|
+
Schleuder::Utils::verify_addr(question,var)
|
226
|
+
rescue Exception => e
|
227
|
+
raise NewListError,"Mandatory emailaddress (#{question}) is not valid: " + e.message
|
228
|
+
end
|
229
|
+
var
|
230
|
+
end
|
231
|
+
|
232
|
+
def self.verify_filevar(var,interactive,question)
|
233
|
+
if (not var.nil? and not File.exist?(var)) and interactive then
|
234
|
+
var = ask("Filepath for "+question+": ")
|
235
|
+
end
|
236
|
+
raise NewListError,"Missing mandatory file: "+question if (not var.nil? and not File.exist?(var))
|
237
|
+
var
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.progfunc(hook, what, type, current, total)
|
241
|
+
$stderr.write("#{what}: #{current}/#{total}\r")
|
242
|
+
$stderr.flush
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
def self.generate_fresh_keypair(listdir,listconfig,interactive)
|
247
|
+
_name = listconfig.myname
|
248
|
+
_email = listconfig.myaddr
|
249
|
+
_pass = listconfig.gpg_password
|
250
|
+
_type = Schleuder.config.gpg_key_type
|
251
|
+
_length = Schleuder.config.gpg_key_length
|
252
|
+
_sub_type = Schleuder.config.gpg_subkey_type
|
253
|
+
_sub_length = Schleuder.config.gpg_subkey_length
|
254
|
+
if GPGME.respond_to? 'check_version'
|
255
|
+
GPGME::check_version('0.0.0')
|
256
|
+
end
|
257
|
+
GPGME::Ctx.new.genkey(
|
258
|
+
ListCreator::create_gnupg_params_template(_name,_email,_pass,_type,_length,_sub_type,_sub_length),
|
259
|
+
nil,nil
|
260
|
+
)
|
261
|
+
|
262
|
+
# Add listname-request@hostname as UID.
|
263
|
+
gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email} adduid"
|
264
|
+
Open3.popen3(gpg_adduid) do |stdin, stdout|
|
265
|
+
owner_done = false
|
266
|
+
request_done = false
|
267
|
+
while line = stdout.readline rescue nil;
|
268
|
+
case line.chomp
|
269
|
+
when '[GNUPG:] GET_LINE keygen.name' then
|
270
|
+
reply = _name
|
271
|
+
when '[GNUPG:] GET_LINE keygen.email' then
|
272
|
+
if ! request_done
|
273
|
+
email = _email.sub(/@/, '-request@')
|
274
|
+
request_done = true
|
275
|
+
else
|
276
|
+
email = _email.sub(/@/, '-owner@')
|
277
|
+
end
|
278
|
+
reply = email
|
279
|
+
when '[GNUPG:] GET_LINE keygen.comment' then
|
280
|
+
reply = 'schleuder list'
|
281
|
+
when '[GNUPG:] GET_HIDDEN passphrase.enter' then
|
282
|
+
reply = _pass
|
283
|
+
when '[GNUPG:] GET_LINE keyedit.prompt' then
|
284
|
+
if ! owner_done
|
285
|
+
reply = "adduid"
|
286
|
+
owner_done = true
|
287
|
+
else
|
288
|
+
reply = "save"
|
289
|
+
end
|
290
|
+
else
|
291
|
+
reply = nil
|
292
|
+
end
|
293
|
+
#$stderr.puts line
|
294
|
+
if reply
|
295
|
+
#$stderr.puts reply
|
296
|
+
stdin.puts reply
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
# Make list@host the primary UID to avoid confusion.
|
302
|
+
# For some f***** up reason these two time calling gpg do not work in one run.
|
303
|
+
gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email}"
|
304
|
+
Open3.popen3(gpg_adduid) do |stdin, stdout|
|
305
|
+
uid_done = false
|
306
|
+
primary_done = false
|
307
|
+
while line = stdout.readline rescue nil;
|
308
|
+
case line.chomp
|
309
|
+
when '[GNUPG:] GET_LINE keyedit.prompt' then
|
310
|
+
if ! uid_done
|
311
|
+
reply = "uid 2"
|
312
|
+
uid_done = true
|
313
|
+
elsif ! primary_done
|
314
|
+
reply = "primary"
|
315
|
+
primary_done = true
|
316
|
+
else
|
317
|
+
reply = "save"
|
318
|
+
end
|
319
|
+
when '[GNUPG:] GET_HIDDEN passphrase.enter' then
|
320
|
+
reply = _pass
|
321
|
+
else
|
322
|
+
reply = nil
|
323
|
+
end
|
324
|
+
#$stderr.puts line
|
325
|
+
if reply
|
326
|
+
#$stderr.puts reply
|
327
|
+
stdin.puts reply
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
$stderr.puts
|
332
|
+
end
|
333
|
+
|
334
|
+
def self.import_keypair(list,list_privatekeyfile,list_publickeyfile)
|
335
|
+
crypt = Schleuder::Crypt.new(list.config.gpg_password)
|
336
|
+
Schleuder.log.debug "Importing private key from #{list_privatekeyfile}"
|
337
|
+
crypt.add_key_from_file(list_privatekeyfile)
|
338
|
+
Schleuder.log.debug "Importing public key from #{list_publickeyfile}"
|
339
|
+
crypt.add_key_from_file(list_publickeyfile)
|
340
|
+
end
|
341
|
+
|
342
|
+
def self.create_gnupg_params_template(name,email,pass,type,length,sub_type,sub_length)
|
343
|
+
"<GnupgKeyParms format=\"internal\">
|
344
|
+
Key-Type: #{type}
|
345
|
+
Key-Length: #{length}
|
346
|
+
Subkey-Type: #{sub_type}
|
347
|
+
Subkey-Length: #{sub_length}
|
348
|
+
Name-Real: #{name}
|
349
|
+
Name-Comment: schleuder list
|
350
|
+
Name-Email: #{email}
|
351
|
+
Expire-Date: 0
|
352
|
+
Passphrase: #{pass}
|
353
|
+
</GnupgKeyParms>"
|
354
|
+
end
|
355
|
+
|
356
|
+
def self.filepermissions(listdir, mailuser)
|
357
|
+
File.chown(mailuser,nil,listdir)
|
358
|
+
File.chmod(0700,listdir)
|
359
|
+
Dir.new(listdir).each{ |f|
|
360
|
+
unless f =~ /^\./
|
361
|
+
File.chown(mailuser,nil,listdir+"/"+f)
|
362
|
+
File.chmod(0600)
|
363
|
+
end
|
364
|
+
}
|
365
|
+
end
|
366
|
+
|
367
|
+
def self.print_list_infos(list)
|
368
|
+
puts "A new schleuder list called '#{list.config.myname}' has been created.".fmt
|
369
|
+
puts
|
370
|
+
puts "To get a working list you have to tell your MTA to handle this list. For various examples have a look at <http://schleuder.nadir.org/documentation/creating_lists.html>".fmt
|
371
|
+
puts
|
372
|
+
puts "Lists' key fingerprint:".fmt
|
373
|
+
crypt = Schleuder::Crypt.new(list.config.gpg_password)
|
374
|
+
key = crypt.get_key(list.config.myaddr).first
|
375
|
+
puts Schleuder::Utils::get_pretty_fingerprint(key)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
begin
|
380
|
+
ListCreator.process(ARGV)
|
381
|
+
rescue NewListError => e
|
382
|
+
puts "Error while creating new list: " + e.message
|
383
|
+
exit 1
|
384
|
+
end
|