/[echolot]/trunk/Echolot/Conf.pm
ViewVC logotype

Contents of /trunk/Echolot/Conf.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 212 - (show annotations) (download)
Mon Jul 22 02:18:30 2002 UTC (10 years, 11 months ago) by weasel
File size: 15208 byte(s)
You no longer need an extra Mixmaster installation for your pinger
The config hash �Pinger::Mix� is obsolete
Default gnupghome changed from �gnupg� to �gnupghome�
New config options: mixmaster, mixhome, gnupg
1 package Echolot::Conf;
2
3 # (c) 2002 Peter Palfrader <peter@palfrader.org>
4 # $Id: Conf.pm,v 1.23 2002/07/22 02:18:30 weasel Exp $
5 #
6
7 =pod
8
9 =head1 Name
10
11 Echolot::Conf - remailer Configuration/Capabilities
12
13 =head1 DESCRIPTION
14
15 This package provides functions for requesting, parsing, and analyzing
16 remailer-conf and remailer-key replies.
17
18 =head1 CAVEATS
19
20 When parsing OpenPGP keys only the address of the primary user id is taken into
21 account (This is the one with the latest self signature I think).
22
23 =cut
24
25 use strict;
26 use Carp qw{cluck};
27 use GnuPG::Interface;
28 use IO::Handle;
29
30
31 sub is_not_a_remailer($) {
32 my ($reply) = @_;
33 if ($reply =~ /^\s* not \s+ a \s+ remailer\b/xi) {
34 return 1;
35 } else {
36 return 0;
37 };
38 };
39
40 sub send_requests($;$) {
41 my ($scheduled_for, $which) = @_;
42
43 $which = '' unless defined $which;
44
45 my $call_intervall = Echolot::Config::get()->{'getkeyconf_interval'};
46 my $send_every_n_calls = Echolot::Config::get()->{'getkeyconf_every_nth_time'};
47
48 my $timemod = ($scheduled_for / $call_intervall);
49 my $this_call_id = $timemod % $send_every_n_calls;
50
51 Echolot::Globals::get()->{'storage'}->delay_commit();
52
53 for my $remailer (Echolot::Globals::get()->{'storage'}->get_addresses()) {
54 next unless ($remailer->{'status'} eq 'active');
55 next unless ($remailer->{'fetch'});
56 my $address = $remailer->{'address'};
57
58 for my $type (qw{conf key help stats adminkey}) {
59
60 next if ($this_call_id ne (Echolot::Tools::makeShortNumHash($address.$type) % $send_every_n_calls) &&
61 $which ne 'all' &&
62 $which ne $address );
63
64 print "Sending $type requests to ".$address."\n"
65 if Echolot::Config::get()->{'verbose'};
66
67 my $source_text = Echolot::Config::get()->{'remailerxxxtext'};
68 my $template = HTML::Template->new(
69 scalarref => \$source_text,
70 strict => 0,
71 global_vars => 1 );
72 $template->param ( address => $address );
73 $template->param ( operator_address => Echolot::Config::get()->{'operator_address'} );
74 my $body = $template->output();
75
76 Echolot::Tools::send_message(
77 'To' => $address,
78 'Subject' => 'remailer-'.$type,
79 'Token' => $type.'.'.$remailer->{'id'},
80 'Body' => $body);
81
82 Echolot::Globals::get()->{'storage'}->decrease_ttl($address) if ($type eq 'conf');
83 };
84 };
85 Echolot::Globals::get()->{'storage'}->enable_commit();
86 };
87
88 sub check_resurrection() {
89 Echolot::Globals::get()->{'storage'}->delay_commit();
90 for my $remailer (Echolot::Globals::get()->{'storage'}->get_addresses()) {
91 next unless ($remailer->{'status'} eq 'ttl timeout');
92 next unless ($remailer->{'fetch'});
93 next unless ($remailer->{'resurrection_ttl'});
94 print "Sending requests to ".$remailer->{'address'}." to check for resurrection\n"
95 if Echolot::Config::get()->{'verbose'};
96 for my $type (qw{conf key help stats adminkey}) {
97 Echolot::Tools::send_message(
98 'To' => $remailer->{'address'},
99 'Subject' => 'remailer-'.$type,
100 'Token' => $type.'.'.$remailer->{'id'})
101 };
102 Echolot::Globals::get()->{'storage'}->decrease_resurrection_ttl($remailer->{'address'});
103 };
104 Echolot::Globals::get()->{'storage'}->enable_commit();
105 };
106
107
108 sub remailer_caps($$$;$) {
109 my ($conf, $token, $time, $dontexpire) = @_;
110
111 my ($id) = $token =~ /^conf\.(\d+)$/;
112 (defined $id) or
113 cluck ("Returned token '$token' has no id at all"),
114 return 0;
115
116 cluck("Could not find id in token '$token'"), return 0 unless defined $id;
117 my ($remailer_type) = ($conf =~ /^\s*Remailer-Type:\s* (.*?) \s*$/imx);
118 cluck("No remailer type found in remailer_caps from '$token'"), return 0 unless defined $remailer_type;
119 my ($remailer_caps) = ($conf =~ /^\s*( \$remailer{".*"} \s*=\s* "<.*@.*>.*"; )\s*$/imx);
120 cluck("No remailer caps found in remailer_caps from '$token'"), return 0 unless defined $remailer_caps;
121 my ($remailer_nick, $remailer_address) = ($remailer_caps =~ /^\s* \$remailer{"(.*)"} \s*=\s* "<(.*@.*)>.*"; \s*$/ix);
122 cluck("No remailer nick found in remailer_caps from '$token': '$remailer_caps'"), return 0 unless defined $remailer_nick;
123 cluck("No remailer address found in remailer_caps from '$token': '$remailer_caps'"), return 0 unless defined $remailer_address;
124
125
126 my $remailer = Echolot::Globals::get()->{'storage'}->get_address_by_id($id);
127 cluck("No remailer found for id '$id'"), return 0 unless defined $remailer;
128 if ($remailer->{'address'} ne $remailer_address) {
129 # Address mismatch -> Ignore reply and add $remailer_address to prospective addresses
130 cluck("Remailer address mismatch $remailer->{'address'} vs $remailer_address. Adding latter to prospective remailers.");
131 Echolot::Globals::get()->{'storage'}->add_prospective_address($remailer_address, 'self-capsstring-conf', $remailer_address);
132 } else {
133 Echolot::Globals::get()->{'storage'}->restore_ttl( $remailer->{'address'} );
134 Echolot::Globals::get()->{'storage'}->set_caps($remailer_type, $remailer_caps, $remailer_nick, $remailer_address, $time, $dontexpire);
135
136 # if remailer is cpunk and not pgponly
137 if (($remailer_caps =~ /\bcpunk\b/) && !($remailer_caps =~ /\bpgponly\b/)) {
138 Echolot::Globals::get()->{'storage'}->set_key(
139 'cpunk-clear',
140 $remailer_nick,
141 $remailer->{'address'},
142 'N/A',
143 'none',
144 'N/A',
145 'N/A',
146 'N/A',
147 $time);
148 }
149 }
150
151
152 # Fetch prospective remailers from reliable's remailer-conf reply:
153 my @lines = split /\r?\n/, $conf;
154 while (@lines) {
155 my $head = $lines[0];
156 chomp $head;
157 shift @lines;
158 last if ($head eq 'SUPPORTED CPUNK (TYPE I) REMAILERS');
159 };
160
161 while (@lines) {
162 my $head = $lines[0];
163 chomp $head;
164 shift @lines;
165 last unless ($head =~ /<(.*?@.*?)>/);
166 Echolot::Globals::get()->{'storage'}->add_prospective_address($1, 'reliable-caps-reply-type1', $remailer_address);
167 };
168
169 while (@lines) {
170 my $head = $lines[0];
171 chomp $head;
172 shift @lines;
173 last if ($head eq 'SUPPORTED MIXMASTER (TYPE II) REMAILERS');
174 };
175
176 while (@lines) {
177 my $head = $lines[0];
178 chomp $head;
179 last unless ($head =~ /\s(.*?@.*?)\s/);
180 shift @lines;
181 Echolot::Globals::get()->{'storage'}->add_prospective_address($1, 'reliable-caps-reply-type2', $remailer_address);
182 };
183
184 return 1;
185 };
186
187 sub remailer_conf($$$) {
188 my ($reply, $token, $time) = @_;
189
190 my ($id) = $token =~ /^conf\.(\d+)$/;
191 (defined $id) or
192 cluck ("Returned token '$token' has no id at all"),
193 return 0;
194
195 Echolot::Globals::get()->{'storage'}->not_a_remailer($id), return 1
196 if (is_not_a_remailer($reply));
197 Echolot::Thesaurus::save_thesaurus('conf', $id, $reply);
198
199 remailer_caps($reply, $token, $time);
200 };
201
202 sub set_caps_manually($$) {
203 my ($addr, $caps) = @_;
204
205 defined $addr or
206 cluck("Address not defined."),
207 return 0;
208 defined $caps or
209 cluck("Caps not defined."),
210 return 0;
211
212 print "Setting caps for $addr manually to $caps\n"
213 if Echolot::Config::get()->{'verbose'};
214
215 my $remailer = Echolot::Globals::get()->{'storage'}->get_address($addr);
216 defined $remailer or
217 cluck("Remailer address $addr did not give a valid remailer."),
218 return 0;
219 my $id = $remailer->{'id'};
220 defined $id or
221 cluck("Remailer address $addr did not give a remailer with an id."),
222 return 0;
223 my $token = 'conf.'.$id;
224
225 my $conf = "Remailer-Type: set-manually\n$caps";
226 remailer_caps($conf, $token, time, 1);
227
228 return 1;
229 };
230
231 sub parse_mix_key($$$) {
232 my ($reply, $time, $remailer) = @_;
233
234 # -----Begin Mix Key-----
235 # 7f6d997678b19ccac110f6e669143126
236 # 258
237 # AASyedeKiP1/UKyfrBz2K6gIhv4jfXIaHo8dGmwD
238 # KqkG3DwytgSySSY3wYm0foT7KvEnkG2aTi/uJva/
239 # gymE+tsuM8l8iY1FOiXwHWLDdyUBPbrLjRkgm7GD
240 # Y7ogSjPhVLeMpzkSyO/ryeUfLZskBUBL0LxjLInB
241 # YBR3o6p/RiT0EQAAAAAAAAAAAAAAAAAAAAAAAAAA
242 # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
243 # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
244 # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
245 # AAAAAAAAAAAAAAAAAAAAAQAB
246 # -----End Mix Key-----
247
248 my %mixmasters;
249 # rot26 rot26@mix.uucico.de 7f6d997678b19ccac110f6e669143126 2.9b33 MC
250 my @mix_confs = ($reply =~ /^[a-z0-9]+ \s+ \S+\@\S+ \s+ [0-9a-f]{32} (?:\s+ \S+ (?:[ \t]+ \S+)?)?/xmg);
251 my @mix_keys = ($reply =~ /^-----Begin \s Mix \s Key-----\r?\n
252 [0-9a-f]{32}\r?\n
253 \d+\r?\n
254 (?:[a-zA-Z0-9+\/]*\r?\n)+
255 -----End \s Mix \s Key-----$/xmg );
256 for (@mix_confs) {
257 my ($nick, $address, $keyid, $version, $caps) = /^([a-z0-9]+) \s+ (\S+@\S+) \s+ ([0-9a-f]{32}) (?:(\S+) (?:[\t]+ (\S+)))?/x;
258 $mixmasters{$keyid} = {
259 nick => $nick,
260 address => $address,
261 version => $version,
262 caps => $caps,
263 summary => $_
264 };
265 };
266 for (@mix_keys) {
267 my ($keyid) = /^-----Begin \s Mix \s Key-----\r?\n
268 ([0-9a-f]{32})\r?\n
269 \d+\r?\n
270 (?:[a-zA-Z0-9+\/]*\r?\n)+
271 -----End \s Mix \s Key-----$/xmg;
272 $mixmasters{$keyid}->{'key'} = $_;
273 };
274
275 for my $keyid (keys %mixmasters) {
276 my $remailer_address = $mixmasters{$keyid}->{'address'};
277 (defined $mixmasters{$keyid}->{'nick'} && ! defined $mixmasters{$keyid}->{'key'}) and
278 cluck("Mixmaster key header without key in reply from $remailer_address"),
279 next;
280 (! defined $mixmasters{$keyid}->{'nick'} && defined $mixmasters{$keyid}->{'key'}) and
281 cluck("Mixmaster key without key header in reply from $remailer_address"),
282 next;
283
284 if ($remailer->{'address'} ne $remailer_address) {
285 # Address mismatch -> Ignore reply and add $remailer_address to prospective addresses
286 cluck("Remailer address mismatch $remailer->{'address'} vs $remailer_address. Adding latter to prospective remailers.");
287 Echolot::Globals::get()->{'storage'}->add_prospective_address($remailer_address, 'self-capsstring-key', $remailer_address);
288 } else {
289 Echolot::Globals::get()->{'storage'}->restore_ttl( $remailer->{'address'} );
290 Echolot::Globals::get()->{'storage'}->set_key(
291 'mix',
292 $mixmasters{$keyid}->{'nick'},
293 $mixmasters{$keyid}->{'address'},
294 $mixmasters{$keyid}->{'key'},
295 $keyid,
296 $mixmasters{$keyid}->{'version'},
297 $mixmasters{$keyid}->{'caps'},
298 $mixmasters{$keyid}->{'summary'},
299 $time);
300 }
301 };
302
303 return 1;
304 };
305
306 sub parse_cpunk_key($$$) {
307 my ($reply, $time, $remailer) = @_;
308
309 my $GnuPG = new GnuPG::Interface;
310 $GnuPG->call( Echolot::Config::get()->{'gnupg'} ) if (Echolot::Config::get()->{'gnupg'});
311 $GnuPG->options->hash_init(
312 homedir => Echolot::Config::get()->{'gnupghome'} );
313 $GnuPG->options->meta_interactive( 0 );
314 my %cypherpunk;
315
316 my @pgp_keys = ($reply =~ /^-----BEGIN \s PGP \s PUBLIC \s KEY \s BLOCK-----\r?\n
317 (?:.+\r?\n)*
318 \r?\n
319 (?:[a-zA-Z0-9+\/=]*\r?\n)+
320 -----END \s PGP \s PUBLIC \s KEY \s BLOCK-----$/xmg );
321 for my $key (@pgp_keys) {
322 my ( $stdin_fh, $stdout_fh, $stderr_fh, $status_fh )
323 = ( IO::Handle->new(),
324 IO::Handle->new(),
325 IO::Handle->new(),
326 IO::Handle->new(),
327 );
328 my $handles = GnuPG::Handles->new (
329 stdin => $stdin_fh,
330 stdout => $stdout_fh,
331 stderr => $stderr_fh,
332 status => $status_fh
333 );
334
335 my $pid = $GnuPG->wrap_call(
336 commands => [qw{--with-colons}],
337 command_args => [qw{--no-options --no-default-keyring --fast-list-mode}],
338 handles => $handles );
339 print $stdin_fh $key;
340 close($stdin_fh);
341
342 my $stdout = join '', <$stdout_fh>; close($stdout_fh);
343 my $stderr = join '', <$stderr_fh>; close($stderr_fh);
344 my $status = join '', <$status_fh>; close($status_fh);
345
346 waitpid $pid, 0;
347
348 ($stderr eq '') or
349 cluck("GnuPG returned something in stderr: '$stderr' when checking key '$key'; So what?\n");
350 ($status eq '') or
351 cluck("GnuPG returned something in status '$status' when checking key '$key': So what?\n");
352
353 my @included_keys = $stdout =~ /^pub:.*$/mg;
354 (scalar @included_keys >= 2) &&
355 cluck ("Cannot handle more than one key per block correctly yet. Found ".(scalar @included_keys)." in one block from ".$remailer->{'address'});
356 for my $included_key (@included_keys) {
357 my ($type, $keyid, $uid) = $included_key =~ /pub::\d+:(\d+):([0-9A-F]+):[^:]+:[^:]*:::([^:]+):/;
358 (defined $uid) or
359 cluck ("Unexpected format of '$included_key' by ".$remailer->{'address'}."; Skipping"),
360 next;
361 my ($address) = $uid =~ /<(.*?)>/;
362 $cypherpunk{$keyid} = {
363 address => $address,
364 type => $type,
365 key => $key # FIXME handle more than one key per block correctly
366 };
367 };
368 };
369
370 for my $keyid (keys %cypherpunk) {
371 my $remailer_address = $cypherpunk{$keyid}->{'address'};
372
373 if ($remailer->{'address'} ne $remailer_address) {
374 # Address mismatch -> Ignore reply and add $remailer_address to prospective addresses
375 cluck("Remailer address mismatch $remailer->{'address'} vs $remailer_address id key $keyid. Adding latter to prospective remailers.");
376 Echolot::Globals::get()->{'storage'}->add_prospective_address($remailer_address, 'self-capsstring-key', $remailer_address);
377 } else {
378 Echolot::Globals::get()->{'storage'}->restore_ttl( $remailer->{'address'} );
379 # 1 .. RSA
380 # 17 .. DSA
381 if ($cypherpunk{$keyid}->{'type'} == 1 || $cypherpunk{$keyid}->{'type'} == 17 ) {
382 Echolot::Globals::get()->{'storage'}->set_key(
383 (($cypherpunk{$keyid}->{'type'} == 1) ? 'cpunk-rsa' :
384 (($cypherpunk{$keyid}->{'type'} == 17) ? 'cpunk-dsa' :
385 'ERROR')),
386 $keyid, # as nick
387 $cypherpunk{$keyid}->{'address'},
388 $cypherpunk{$keyid}->{'key'},
389 $keyid,
390 'N/A',
391 'N/A',
392 'N/A',
393 $time);
394 } else {
395 cluck("$keyid from $remailer_address has algoid ".$cypherpunk{$keyid}->{'type'}.". Cannot handle those.");
396 };
397 }
398 };
399
400 return 1;
401 };
402
403 sub remailer_key($$$) {
404 my ($reply, $token, $time) = @_;
405
406 my $cp_reply = $reply;
407 $cp_reply =~ s/^- -/-/gm; # PGP Signed messages
408
409 my ($id) = $token =~ /^key\.(\d+)$/;
410 (defined $id) or
411 cluck ("Returned token '$token' has no id at all"),
412 return 0;
413
414 Echolot::Globals::get()->{'storage'}->not_a_remailer($id), return 1
415 if (is_not_a_remailer($reply));
416 Echolot::Thesaurus::save_thesaurus('key', $id, $reply);
417
418 my $remailer = Echolot::Globals::get()->{'storage'}->get_address_by_id($id);
419 cluck("No remailer found for id '$id'"), return 0 unless defined $remailer;
420
421 parse_mix_key($cp_reply, $time, $remailer);
422 parse_cpunk_key($cp_reply, $time, $remailer);
423
424 return 1;
425 };
426
427 sub remailer_stats($$$) {
428 my ($reply, $token, $time) = @_;
429
430 my ($id) = $token =~ /^stats\.(\d+)$/;
431 (defined $id) or
432 cluck ("Returned token '$token' has no id at all"),
433 return 0;
434
435 Echolot::Globals::get()->{'storage'}->not_a_remailer($id), return 1
436 if (is_not_a_remailer($reply));
437 Echolot::Thesaurus::save_thesaurus('stats', $id, $reply);
438 };
439
440 sub remailer_help($$$) {
441 my ($reply, $token, $time) = @_;
442
443 my ($id) = $token =~ /^help\.(\d+)$/;
444 (defined $id) or
445 cluck ("Returned token '$token' has no id at all"),
446 return 0;
447
448 Echolot::Globals::get()->{'storage'}->not_a_remailer($id), return 1
449 if (is_not_a_remailer($reply));
450 Echolot::Thesaurus::save_thesaurus('help', $id, $reply);
451 };
452
453 sub remailer_adminkey($$$) {
454 my ($reply, $token, $time) = @_;
455
456 my ($id) = $token =~ /^adminkey\.(\d+)$/;
457 (defined $id) or
458 cluck ("Returned token '$token' has no id at all"),
459 return 0;
460
461 Echolot::Globals::get()->{'storage'}->not_a_remailer($id), return 1
462 if (is_not_a_remailer($reply));
463 Echolot::Thesaurus::save_thesaurus('adminkey', $id, $reply);
464 };
465
466 1;
467 # vim: set ts=4 shiftwidth=4:

  ViewVC Help
Powered by ViewVC 1.1.5