schleuder 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data.tar.gz.sig +0 -0
  2. data/LICENSE +339 -0
  3. data/README +32 -0
  4. data/bin/schleuder +96 -0
  5. data/bin/schleuder-fix-gem-dependencies +30 -0
  6. data/bin/schleuder-init-setup +37 -0
  7. data/bin/schleuder-migrate-v2.1-to-v2.2 +205 -0
  8. data/bin/schleuder-newlist +384 -0
  9. data/contrib/check-expired-keys.rb +59 -0
  10. data/contrib/mutt-schleuder-colors.rc +10 -0
  11. data/contrib/mutt-schleuder-resend.vim +24 -0
  12. data/contrib/smtpserver.rb +76 -0
  13. data/ext/default-list.conf +146 -0
  14. data/ext/default-members.conf +7 -0
  15. data/ext/list.conf.example +14 -0
  16. data/ext/schleuder.conf +62 -0
  17. data/lib/schleuder.rb +49 -0
  18. data/lib/schleuder/archiver.rb +46 -0
  19. data/lib/schleuder/crypt.rb +188 -0
  20. data/lib/schleuder/errors.rb +5 -0
  21. data/lib/schleuder/list.rb +177 -0
  22. data/lib/schleuder/list_config.rb +146 -0
  23. data/lib/schleuder/log/listlogger.rb +56 -0
  24. data/lib/schleuder/log/outputter/emailoutputter.rb +118 -0
  25. data/lib/schleuder/log/outputter/metaemailoutputter.rb +50 -0
  26. data/lib/schleuder/log/schleuderlogger.rb +23 -0
  27. data/lib/schleuder/mail.rb +861 -0
  28. data/lib/schleuder/mailer.rb +26 -0
  29. data/lib/schleuder/member.rb +69 -0
  30. data/lib/schleuder/plugin.rb +54 -0
  31. data/lib/schleuder/processor.rb +363 -0
  32. data/lib/schleuder/schleuder_config.rb +72 -0
  33. data/lib/schleuder/storage.rb +84 -0
  34. data/lib/schleuder/utils.rb +80 -0
  35. data/lib/schleuder/version.rb +3 -0
  36. data/man/schleuder-newlist.8 +191 -0
  37. data/man/schleuder.8 +400 -0
  38. data/plugins/README +20 -0
  39. data/plugins/manage_keys_plugin.rb +113 -0
  40. data/plugins/manage_members_plugin.rb +152 -0
  41. data/plugins/manage_self_plugin.rb +26 -0
  42. data/plugins/resend_plugin.rb +35 -0
  43. data/plugins/version_plugin.rb +12 -0
  44. metadata +178 -0
  45. 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