File Coverage

blib/lib/Mail/Milter/Authentication/Net/Milter.pm
Criterion Covered Total %
statement 302 416 72.6
branch 121 218 55.5
condition 7 18 38.8
subroutine 31 31 100.0
pod 14 14 100.0
total 475 697 68.1


line stmt bran cond sub pod time code
1             package Mail::Milter::Authentication::Net::Milter;
2             ## no critic
3 115     115   2383 use strict;
  115         342  
  115         3798  
4 115     115   590 use Carp;
  115         523  
  115         8488  
5 115     115   815 use vars qw($DEBUG);
  115         237  
  115         7312  
6             # ABSTRACT: Local modified copy of Net::Milter
7             our $VERSION = '3.20230911'; # VERSION
8             $DEBUG=0;
9              
10 115     115   703 use constant PROTOCOL_NEGATION => 0;
  115         230  
  115         23592  
11              
12             ############
13             sub new
14             {
15             # create new blank class
16 33     33 1 789 my $proto = shift;
17 33   33     1352 my $class = ref($proto) || $proto;
18 33         606 my $self= {};
19              
20             # define the various negotiation options
21             # we'll put them here and not touch them so we can loop through and do bit wise checks later
22 33         1230 $self->{action_types} = ['SMFIF_ADDHDRS', 'SMFIF_CHGBODY', 'SMFIF_ADDRCPT', 'SMFIF_DELRCPT', 'SMFIF_CHGHDRS', 'SMFIF_QUARANTINE'];
23 33         1306 $self->{content_types} = ['SMFIP_NOCONNECT', 'SMFIP_NOHELO', 'SMFIP_NOMAIL', 'SMFIP_NORCPT', 'SMFIP_NOBODY', 'SMFIP_NOHDRS', 'SMFIP_NOEOH'];
24              
25 33         658 bless($self,$class);
26 33         694 return $self;
27             } # end sub new
28             ############
29              
30             ############
31             sub open {
32             # open the socket
33 115     115   1318 use IO::Socket;
  115         298  
  115         1265  
34              
35 33     33 1 181 my $self = shift;
36 33         177 my ($addr,$port,$proto) = @_;
37              
38 33 50       326 if ($DEBUG==1) {print STDERR "open\n";}
  0         0  
39              
40 33         538 my $sock;
41              
42 33 50 33     1857 if (lc($proto) eq 'tcp' || lc($proto) eq 'inet') {
    50 33        
43 0 0       0 if ($DEBUG==1) {print STDERR "\topen tcp socket\n";}
  0         0  
44 115     115   93185 use IO::Socket::INET;
  115         624  
  115         1436  
45 0 0       0 $sock = new IO::Socket::INET (PeerAddr => $addr,
46             PeerPort => $port,
47             Proto => 'tcp',
48             Type => SOCK_STREAM,
49             Timeout => 10,
50             ) or carp "Couldn't connect to $addr:$port : $@\n";
51             } # end if tcp
52             elsif (lc($proto) eq 'unix' || lc($proto) eq 'local') {
53 33 50       405 if ($DEBUG==1) {print STDERR "\topen unix socket\n";}
  0         0  
54 115     115   117760 use IO::Socket::UNIX;
  115         305  
  115         1326  
55 33 50       2850 $sock = new IO::Socket::UNIX (Peer => $addr,
56             Type => SOCK_STREAM,
57             Timeout => $port
58             ) or carp "Couldn't connect to unix socket on $addr : $@\n";
59             } # end if unix
60 0         0 else {carp "$proto is unknown to me\n";}
61              
62 33 50       37206 if (!defined($sock)) {return 0;}
  0         0  
63             else {
64 33         991 $self->{socket} = $sock;
65 33         269 return 1;
66             }
67              
68             } # end sub open
69             ############
70              
71             ############
72             sub protocol_negotiation {
73             # negotiate with the filter as to what options to use
74 33     33 1 157 my $self = shift;
75              
76 33         2934 my (%options) = @_;
77              
78 33 50       725 if ($DEBUG==1) {print STDERR "protocol_negotiation\n";}
  0         0  
79              
80             # set up the bit mask of allowed actions
81 33         135 my (@action_types) = @{$self->{action_types}};
  33         330  
82 33         144 my (@content_types) = @{$self->{content_types}};
  33         327  
83              
84 33         136 my ($count,$action,$content);
85              
86 33 50       270 if ($DEBUG==1) {print STDERR "\tsetting bits\n";}
  0         0  
87              
88 33         109 my $action_field = 0;
89              
90 33         147 $count=0;
91 33         261 while ($action = shift(@action_types)) {
92 198 100 100     1896 if (defined($options{$action}) && $options{$action}==0) {
93             # do nothing
94             }
95             else {
96 99         512 $action_field = $action_field | (2**$count);
97             }
98              
99 198         586 $count++;
100             } # end while
101              
102              
103             # set up the bit mask for possible protocols
104 33         148 my $protocol_field = 0;
105              
106 33         139 $count=0;
107 33         263 while ($content = shift(@content_types)) {
108 231 50 33     1590 if (defined($options{$content}) && $options{$content}==1) {
109 0         0 $protocol_field = $protocol_field | 2**$count;
110             }
111             else {
112             # do nothing
113             }
114              
115 231         627 $count++;
116             } # end while
117              
118             ### hmmm this bit might not be right on 64 bit architecture
119             # we want a 32 bit unsigned integer in network order
120 33         168 my $smfi_version = 2; # version of protocol
121 33         92 my $length = 13;
122              
123 33 50       171 if ($DEBUG==1) {print STDERR "\tpacking\n";}
  0         0  
124              
125 33         841 $action_field = $self->_pack_number($action_field);
126 33         217 $protocol_field = $self->_pack_number($protocol_field);
127 33         137 if (PROTOCOL_NEGATION == 1) {$protocol_field = ~$protocol_field;}
128 33         169 $smfi_version = $self->_pack_number($smfi_version);
129 33         271 $length = $self->_pack_number($length);
130              
131 33 50       1048 if ($DEBUG==1) {print STDERR "\tsendsubing\n";}
  0         0  
132              
133 33         2719 $self->{socket}->send($length);
134 33         12489 $self->{socket}->send('O');
135 33         1462 $self->{socket}->send($smfi_version);
136 33         2638 $self->{socket}->send($action_field);
137 33         2504 $self->{socket}->send($protocol_field);
138              
139 33 50       2074 if ($DEBUG==1) {print STDERR "\treceiving\n";}
  0         0  
140              
141 33         702 my ($command,$data)=$self->_receive();
142              
143 33 50       334 if ($command ne 'O') {carp "error in protocol negotiation \n";}
  0         0  
144              
145 33         692 my($ret_version,$ret_actions,$ret_protocol)=unpack "NNN",$data;
146              
147 33 50       374 if ($DEBUG==1) {print STDERR "\treturned version : $ret_version\n";}
  0         0  
148 33 50       307 if ($DEBUG==1) {printf STDERR "\treturned actions : %8b\n", $ret_actions;}
  0         0  
149 33 50       208 if ($DEBUG==1) {printf STDERR "\treturned protocol : %7b\n", $ret_protocol;}
  0         0  
150              
151             # translate returned bit mask into fields
152 33 50       218 if ($DEBUG==1) {print STDERR "\ttranslating bit mask\n";}
  0         0  
153              
154 33         306 my (@returned_actions, @returned_protocol);
155              
156 33         194 $count=0;
157 33         307 while ($action = shift(@action_types)) {
158 0 0       0 if ($ret_actions & 2**$count) {
159 0         0 push @returned_actions,$action;
160             }
161 0         0 $count++;
162             } # end while
163              
164 33         88 $count=0;
165 33         207 while ($content = shift(@content_types)) {
166 0 0       0 if ($ret_protocol & 2**$count) {
167 0         0 push @returned_protocol,$content;
168             }
169 0         0 $count++;
170             } # end while
171              
172              
173              
174 33         370 return ($ret_version,\@returned_actions,\@returned_protocol);
175             } # end sub protocol_negotiation
176             ############
177              
178             ############
179             sub send_abort {
180             # send an abort command, SMFIC_ABORT
181             # no response expected
182             # but dont close the connection
183 33 50   33 1 418 if ($DEBUG==1) {print STDERR "send_abort\n";}
  0         0  
184 33         181 my $self = shift;
185 33         316 $self->_send('A');
186              
187             } # end sub send_abort
188             ############
189              
190             ############
191             sub send_body {
192             # send body chunk of message, SMFIC_BODY
193              
194 31     31 1 101 my $self = shift;
195 31         214 my $body = shift;
196 31 50       889 if ($DEBUG==1) {print STDERR "send_body\n";}
  0         0  
197             # restrict body size to max allowable
198              
199 31 50       324 if ($DEBUG==1) {print STDERR "\tsending".substr($body,0,5).'...'."\n";}
  0         0  
200              
201 31 50       373 if (length ($body)>65535) {
202 0         0 warn "the message body is too big; its length must be less than 65536 bytes";
203 0         0 $self->_send('B',substr($body,0,65535));
204 0         0 $body = substr($body,65535);
205             }
206             else {
207 31         220 $self->_send('B',$body);
208             }
209              
210 31 50       422 if ($DEBUG==1) {print STDERR "\treceiving from body\n";}
  0         0  
211              
212             # get response
213 31         229 my (@replies)=$self->_retrieve_responses();
214 31         463 return(@replies);
215              
216             } # end sub send_body
217             ############
218              
219             ############
220             sub send_end_body {
221             # send body chunk of message, SMFIC_BODY
222              
223 33     33 1 150 my $self = shift;
224 33         141 my $body = shift;
225 33 50       370 if ($DEBUG==1) {print STDERR "send end_body\n";}
  0         0  
226              
227 33         369 $self->_send('E');
228 33 50       316 if ($DEBUG==1) {print STDERR "\treceiving\n";}
  0         0  
229              
230             # get response
231 33         263 my (@replies)=$self->_retrieve_responses();
232 33         760 return(@replies);
233              
234             } # end sub send_end_body
235             ############
236              
237             ############
238             sub send_connect {
239             # send connect message, SMFIC_CONNECT
240              
241 33     33 1 250 my $self = shift;
242 33         254 my ($hostname,$family,$port,$ip_address) = @_;
243              
244 33         148 my ($protocol_family);
245              
246 33         326 $hostname .="\0";
247 33         173 $ip_address .="\0";
248              
249 33 50       286 if ($DEBUG==1) {print STDERR "send connect\n";}
  0         0  
250              
251 33 50       562 if (lc($family) eq 'unix') {$protocol_family='L';}
  0 50       0  
    0          
252 33         515 elsif (lc($family) eq 'tcp4') {$protocol_family='4';}
253 0         0 elsif (lc($family) eq 'tcp6') {$protocol_family='6';}
254 0         0 else {$protocol_family='U';}
255              
256 33         436 $port = pack "n",$port;
257              
258 33 50       272 if ($DEBUG==1) {print STDERR "\tsending\n";}
  0         0  
259              
260 33         254 $self->_send('C',$hostname,$protocol_family,$port,$ip_address);
261              
262 33         613 my (@replies)=$self->_retrieve_responses();
263 33         530 return (@replies);
264             } # end sub send_connect
265             ############
266              
267             ############
268             sub send_helo {
269             # send helo string, SMFIC_HELO
270 33     33 1 164 my $self=shift;
271 33         202 my $helo_string = shift;
272 33 50       321 if ($DEBUG==1) {print STDERR "send_helo\n";}
  0         0  
273              
274 33         336 $helo_string .="\0";
275 33         311 $self->_send('H',$helo_string);
276              
277 33 50       271 if ($DEBUG==1) {print STDERR "\treceiving\n";}
  0         0  
278              
279 33         276 my (@replies)=$self->_retrieve_responses();
280 33         492 return (@replies);
281             } # end sub send_helo
282             ############
283              
284             ############
285             sub send_header {
286             # send a header name and value from message, SMFIC_HEADER
287              
288 399     399 1 1090 my $self=shift;
289 399         1090 my $header_name = shift;
290 399         1158 my $header_value = shift;
291              
292 399 50       1629 if ($DEBUG==1) {print STDERR "send_header\n";}
  0         0  
293              
294 399         1567 $header_name.="\0";
295 399         1199 $header_value.="\0";
296              
297 399         1876 $self->_send('L',$header_name,$header_value);
298              
299 399         1682 my (@replies)=$self->_retrieve_responses();
300 399         3424 return (@replies);
301             } # end sub send_header
302             ############
303              
304             ############
305             sub send_mail_from {
306             # send MAIL FROM information from message, SMFIC_MAIL
307              
308 33     33 1 172 my $self=shift;
309 33         132 my $mail_from = shift;
310              
311 33 50       264 if ($DEBUG==1) {print STDERR "send_mail_from\n";}
  0         0  
312              
313 33         196 $mail_from.="\0";
314              
315 33         259 $self->_send('M',$mail_from);
316              
317 33         276 my (@replies)=$self->_retrieve_responses();
318 33         663 return (@replies);
319             } # end sub send_mail_from
320             ############
321              
322             ############
323             sub send_end_headers {
324             # send end of headers marker, SMFIC_EOH
325              
326 33     33 1 257 my $self=shift;
327              
328 33 50       253 if ($DEBUG==1) {print STDERR "send_end_headers\n";}
  0         0  
329              
330 33         185 $self->_send('N');
331              
332 33         277 my (@replies)=$self->_retrieve_responses();
333 33         496 return (@replies);
334             } # end sub send_end_headers
335             ############
336              
337             ############
338             sub send_rcpt_to {
339             # send RCPT TO information from message, SMFIC_RCPT
340              
341 33     33 1 155 my $self=shift;
342 33         136 my $rcpt_to = shift;
343              
344 33 50       340 if ($DEBUG==1) {print STDERR "send_rcpt_to\n";}
  0         0  
345              
346 33         203 $rcpt_to.="\0";
347              
348 33         382 $self->_send('R',$rcpt_to);
349              
350 33         262 my (@replies)=$self->_retrieve_responses();
351 33         845 return (@replies);
352             } # end sub send_rcpt_to
353             ############
354              
355             ############
356             sub send_quit {
357             # send a quit command, SMFIC_QUIT
358             # no response expected
359             # close the connection
360 33     33 1 131 my $self=shift;
361              
362 33 50       294 if ($DEBUG==1) {print STDERR "send_quit\n";}
  0         0  
363              
364 33         284 $self->_send('Q');
365              
366 33         1293 $self->{socket}->close;
367              
368             } # end sub send_quit
369             ############
370              
371             ############
372             sub _send {
373             # concerned with the details of sending stuff
374              
375 890     890   2476 my $self = shift;
376 890         6459 my $command = shift;
377 890         4056 my (@data) = @_;
378              
379 890 50       3154 if ($DEBUG==1) {print STDERR "send\n";}
  0         0  
380              
381 890         4110 my $data = join '',@data;
382 890         2584 my $length = length($data);
383 890         2043 $length += 1;
384              
385 890 50       2764 if ($DEBUG==1) {
386 0         0 print STDERR "sending - command : $command\tlength : $length";
387 0 0       0 if (length($data)<100) {print STDERR "\tdata : $data\n";}
  0         0  
388 0         0 else {print STDERR "\n";}
389             }
390              
391 890         3200 $length = $self->_pack_number($length);
392              
393 890 50       3631 if (!defined($self->{socket})) {carp "can't connect no connection defined !\n";}
  0         0  
394 890         3635 $self->_io_send($length);
395 890         4004 $self->_io_send($command);
396 890 100       4256 $self->_io_send($data) if (length($data) > 0);
397              
398              
399             } # end sub _send
400             ############
401              
402             ############
403             sub _receive {
404             # concerned with the details of receiving stuff
405              
406 115     115   302614 use IO::Select;
  115         943  
  115         257690  
407              
408 743     743   1649 my $self = shift;
409              
410 743 50       2243 if ($DEBUG==1) {print STDERR "_receive\n";}
  0         0  
411              
412 743         2756 my $length = $self->_io_recv(4);
413 743         4315 my $command = $self->_io_recv(1);
414 743         3875 $length = $self->_unpack_number($length);
415 743 50       2652 if ($DEBUG==1) {print STDERR "\tcommand : $command\n\tlength : $length\n";}
  0         0  
416 743         2073 $length -= 1;
417              
418 743         1779 my $data;
419 743 100       2629 if ($length > 0) {
420 116         626 $data = $self->_io_recv($length);
421             }
422              
423 743         3960 return ($command,$data);
424             } # end sub _receive
425             ############
426              
427             ############
428             sub _pack_number {
429             # single place to pack numbers
430 1022     1022   2575 my $self = shift;
431 1022         2393 my $number = shift;
432              
433 1022 50       3471 if ($DEBUG==1) {print STDERR "_pack_number\n";}
  0         0  
434              
435 1022         4772 my $ret_number = pack "N",$number;
436              
437 1022         3911 return ($ret_number);
438             } # end sub _pack_number
439             ############
440              
441             ############
442             sub _unpack_number {
443             # single place to unpack numbers
444 816     816   2298 my $self = shift;
445 816         2199 my $number = shift;
446              
447 816 50       3090 if ($DEBUG==1) {print STDERR "_unpack_number\n";}
  0         0  
448              
449 816         4009 my $ret_number = unpack "N",$number;
450              
451 816         3011 return ($ret_number);
452             } # end sub _unpack_number
453             ############
454              
455             ############
456             sub _translate_response {
457             # turn what we get from the filter into something more manageable
458              
459 710     710   1857 my $self = shift;
460 710         2815 my ($command,$data)=@_;
461              
462 710 50       2715 if ($DEBUG==1) {
463 0         0 print STDERR "_translate_response\n";
464 0         0 print STDERR "\tcommand : $command\n";
465 0 0 0     0 if (defined($data) && $command !~/[hm]/) {print STDERR "\tdata : $data\n";}
  0         0  
466             }
467              
468 710         2064 my %reply=();
469              
470 710         6268 $reply{command}=$command;
471              
472 710 50       6635 if ($command eq '+') {
    50          
    50          
    50          
    100          
    50          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
473 0         0 $reply{explanation}='Add a recipient';
474 0         0 $reply{header}='To';
475 0         0 $reply{action}='add';
476 0         0 $reply{value}=$data;
477             }
478              
479             elsif ($command eq '-') {
480 0         0 $reply{explanation}='Remove a recipient';
481 0         0 $reply{header}='To';
482 0         0 $reply{action}='delete';
483 0         0 $reply{value}=$data;
484             }
485              
486             elsif ($command eq 'a') {
487 0         0 $reply{explanation}='Accept message completely';
488 0         0 $reply{action}='accept';
489             }
490              
491             elsif ($command eq 'b') {
492 0         0 $reply{explanation}='Replace body chunk';
493 0         0 $reply{header}='body';
494 0         0 $reply{action}='replace';
495 0         0 $reply{value}=$data;
496             }
497              
498             elsif ($command eq 'c') {
499 627         2910 $reply{explanation}='Accept and continue';
500 627         1991 $reply{action}='continue';
501             }
502              
503             elsif ($command eq 'd') {
504 0         0 $reply{explanation}='Reject message completely';
505 0         0 $reply{action}='reject';
506             }
507              
508             elsif ($command eq 'h') {
509 9         27 $reply{explanation}='Add header';
510 9         66 ($reply{header},$reply{value},undef)=split(/\0/,$data);
511 9         27 $reply{action}='add';
512             }
513              
514             elsif ($command eq 'i') {
515 60         343 $reply{explanation}='Insert header';
516 60         412 $reply{index}=$self->_unpack_number(substr($data,0,4));
517 60         442 $data = substr($data,4);
518 60         1120 ($reply{header},$reply{value},undef)=split(/\0/,$data);
519 60         397 $reply{action}='insert';
520             }
521              
522             elsif ($command eq 'm') {
523 13         36 $reply{explanation}='Replace body header';
524 13         74 $reply{index}=$self->_unpack_number(substr($data,0,4));
525 13         54 $data = substr($data,4);
526 13         114 ($reply{header},$reply{value},undef)=split(/\0/,$data);
527 13         42 $reply{action}='replace';
528             }
529              
530             elsif ($command eq 'p') {
531 0         0 $reply{explanation}='Progress';
532 0         0 $reply{action}='continue';
533             }
534              
535             elsif ($command eq 'r') {
536 0         0 $reply{explanation}='Reject command with 5xx error';
537 0         0 $reply{action}='reject';
538 0         0 $reply{value}=5;
539             }
540              
541             elsif ($command eq 't') {
542 0         0 $reply{explanation}='Reject command with 4xx error';
543 0         0 $reply{action}='reject';
544 0         0 $reply{value}=4;
545             }
546              
547             elsif ($command eq 'y') {
548 1         7 $reply{explanation}='Reject command with xxx error';
549 1         31 $reply{action}='reject';
550 1         19 $reply{value}=$data;
551             }
552              
553              
554 710         3173 return (\%reply);
555             } # end sub _translate_response
556             ############
557              
558             ############
559             sub _retrieve_responses {
560              
561 628     628   1581 my $self = shift;
562              
563 628         1675 my (@replies,$command,$data,$reply_ref);
564              
565 628 50       1983 if ($DEBUG==1) {print STDERR "_retrieve_response\n";}
  0         0  
566              
567 628         1269 while () {
568 710 50       2088 if ($DEBUG==1) {print STDERR "\twaiting for response\n";}
  0         0  
569 710         2133 ($command,$data)=$self->_receive();
570 710         2962 ($reply_ref)=$self->_translate_response($command,$data);
571              
572 710         2441 push @replies,$reply_ref;
573              
574 710 50       2801 if ($DEBUG==1) {print STDERR "\tcommand : $$reply_ref{command}";}
  0         0  
575 710 100       3709 if ($$reply_ref{command} eq 'c') {last;}
  627 50       2024  
    50          
    50          
    100          
    50          
576 0         0 elsif ($$reply_ref{command} eq 'a') {last;}
577 0         0 elsif ($$reply_ref{command} eq 'r') {last;}
578 0         0 elsif ($$reply_ref{command} eq 't') {last;}
579 1         13 elsif ($$reply_ref{command} eq 'y') {last;}
580 0         0 elsif ($$reply_ref{command} eq 'd') {last;}
581             } # end while
582              
583 628         3662 return (@replies);
584             } # end sub retrieve_responses
585             ############
586              
587             ############
588             sub send_macros {
589 196     196 1 622 my $self=shift;
590 196         4671 my %macros = @_;
591              
592 196 50       1211 if ($DEBUG==1) {print STDERR "retrieve_response\n";}
  0         0  
593              
594 196         708 my (@data);
595              
596 196 50       937 if ($DEBUG==1) {
597 0         0 foreach (keys(%macros)) {
598 0         0 print STDERR "\tmacro : $_ = $macros{$_}\n";
599             }
600             } # end if DEBUG
601              
602 196 100       935 if (defined($macros{j})) {push @data,'j'."\0".$macros{j}."\0";}
  33         391  
603 196 50       972 if (defined($macros{_})) {push @data,'_'."\0",$macros{_}."\0";}
  0         0  
604 196 50       812 if (defined($macros{'{daemon_name}'})) {push @data,'{daemon_name}'."\0".$macros{'{daemon_name}'}."\0";}
  0         0  
605 196 50       814 if (defined($macros{'{if_name}'})) {push @data,'{if_name}'."\0".$macros{'{if_name}'}."\0";}
  0         0  
606 196 50       911 if (defined($macros{'{if_addr}'})) {push @data,'{if_addr}'."\0".$macros{'{if_addr}'}."\0";}
  0         0  
607              
608 196 100       901 if (@data) {
609 33 50       214 if ($DEBUG==1) {print STDERR "\tsending D,C\n";}
  0         0  
610 33         1056 $self->_send('D','C',@data);
611             }
612              
613 196         621 @data=();
614 196 50       785 if (defined($macros{'{tls_version}'})) {push @data,'{tls_version}'."\0".$macros{'{tls_version}'}."\0";}
  0         0  
615 196 50       947 if (defined($macros{'{cipher}'})) {push @data,'{cipher}'."\0".$macros{'{cipher}'}."\0";}
  0         0  
616 196 50       718 if (defined($macros{'{cipher_bits}'})) {push @data,'{cipher_bits}'."\0".$macros{'{cipher_bits}'}."\0";}
  0         0  
617 196 50       873 if (defined($macros{'{cert_subject}'})) {push @data,'{cert_subject}'."\0".$macros{'{cert_subject}'}."\0";}
  0         0  
618 196 50       1001 if (defined($macros{'{cert_issuer}'})) {push @data,'{cert_issuer}'."\0".$macros{'{cert_issuer}'}."\0";}
  0         0  
619              
620 196 50       932 if (@data) {
621 0 0       0 if ($DEBUG==1) {print STDERR "\tsending D,H\n";}
  0         0  
622 0         0 $self->_send('D','H',@data);
623             }
624              
625              
626              
627 196         584 @data=();
628 196 100       975 if (defined($macros{i})) {push @data,'i'."\0".$macros{i}."\0";}
  97         677  
629 196 50       1095 if (defined($macros{'{auth_type}'})) {push @data,'{auth_type}'."\0".$macros{'{auth_type}'}."\0";}
  0         0  
630 196 50       883 if (defined($macros{'{auth_authen}'})) {push @data,'{auth_authen}'."\0".$macros{'{auth_authen}'}."\0";}
  0         0  
631 196 50       871 if (defined($macros{'{auth_ssf}'})) {push @data,'{auth_ssf}'."\0".$macros{'{auth_ssf}'}."\0";}
  0         0  
632 196 50       840 if (defined($macros{'{auth_author}'})) {push @data,'{auth_author}'."\0".$macros{'{auth_author}'}."\0";}
  0         0  
633 196 100       860 if (defined($macros{'{mail_mailer}'})) {push @data,'{mail_mailer}'."\0".$macros{'{mail_mailer}'}."\0";}
  33         320  
634 196 100       876 if (defined($macros{'{mail_host}'})) {push @data,'{mail_host}'."\0".$macros{'{mail_host}'}."\0";}
  33         379  
635 196 100       896 if (defined($macros{'{mail_addr}'})) {push @data,'{mail_addr}'."\0".$macros{'{mail_addr}'}."\0";}
  33         435  
636              
637 196 100       841 if (@data) {
638 130 50       615 if ($DEBUG==1) {print STDERR "\tsending D,M\n";}
  0         0  
639 130         738 $self->_send('D','M',@data);
640             }
641              
642              
643 196         677 @data=();
644 196 100       937 if (defined($macros{'{rcpt_mailer}'})) {push @data,'{rcpt_mailer}'."\0".$macros{'{rcpt_mailer}'}."\0";}
  33         431  
645 196 100       858 if (defined($macros{'{rcpt_host}'})) {push @data,'{rcpt_host}'."\0".$macros{'{rcpt_host}'}."\0";}
  33         276  
646 196 100       843 if (defined($macros{'{rcpt_addr}'})) {push @data,'{rcpt_addr}'."\0".$macros{'{rcpt_addr}'}."\0";}
  33         357  
647              
648 196 100       885 if (@data) {
649 33 50       378 if ($DEBUG==1) {print STDERR "\tsending D,R\n";}
  0         0  
650 33         282 $self->_send('D','R',@data);
651             }
652              
653              
654             # no response after sending macros
655 196         1124 return 1;
656              
657             } # end sub send_macros
658             ############
659              
660             ############
661             sub _io_send {
662 2538     2538   5531 my $self = shift;
663 2538         7396 my ($data) = @_;
664              
665 2538         5263 my $must_send = length($data);
666 2538         4881 my $did_send = 0;
667 2538         6785 while ($did_send < $must_send) {
668 2538         14960 my $len = $self->{socket}->send(substr($data, $did_send));
669 2538 50       162468 if (defined($len)) {
670 2538         9070 $did_send += $len;
671             }
672             else {
673 0         0 carp "Error while writing to the socket: $!";
674             }
675             }
676              
677 2538         6971 return 1;
678             }
679             ############
680              
681             ############
682             sub _io_recv {
683 1602     1602   3549 my $self = shift;
684 1602         4485 my ($must_recv) = @_;
685              
686 1602         3339 my $did_recv = 0;
687 1602         4312 my $data = "";
688 1602         4809 while ($did_recv < $must_recv) {
689 1602         10401 my $len = $self->{socket}->sysread($data, $must_recv-$did_recv, $did_recv);
690 1602 50       31878808 if (defined($len)) {
691 1602         8374 $did_recv += $len;
692             }
693             else {
694 0         0 carp "Error while reading from the socket: $!";
695             }
696             }
697              
698 1602         8623 return $data;
699             }
700             ############
701              
702             ############
703             sub DESTROY {
704 33     33   212 my $self = shift;
705 33 50       258 if (defined($self->{socket})) {
706 33         251 $self->{socket}->close;
707             } # end if
708              
709             } # end sub DESTROY
710             ############
711              
712             1;
713              
714             __END__
715              
716             =pod
717              
718             =encoding UTF-8
719              
720             =head1 NAME
721              
722             Mail::Milter::Authentication::Net::Milter - Local modified copy of Net::Milter
723              
724             =head1 VERSION
725              
726             version 3.20230911
727              
728             =head1 SYNOPSIS
729              
730             use Net::Milter;
731             my $milter = new Net::Milter;
732             $milter->open('127.0.0.1',5513,'tcp');
733              
734             my ($milter_version,$returned_actions_ref,$returned_protocol_ref) =
735             $milter->protocol_negotiation();
736              
737             my (@results) = $milter->send_header('From','martin@localhost');
738             foreach (@results) {
739             if ($$_{action} eq 'reject') {exit;}
740             }
741              
742             Also see example in scripts directory.
743              
744             =head1 DESCRIPTION
745              
746             Perl module to provide a pure Perl implementation of the MTA part the
747             milter interface. The goal of this module is to allow other email
748             systems to easily integrate with the various email filters that accept
749             content via milter.
750              
751             This implementation of milter is developed from the description provided
752             by Todd Vierling,
753             cvs.sourceforge.net/viewcvs.py/pmilter/pmilter/doc/milter-protocol.txt?rev=1.2
754             and from examining the tcp output from Sendmail.
755              
756             =head2 Attributes
757              
758             =over
759              
760             =item action_types
761              
762             Reference to an array of the set of actions defined within Sendmail's milter code.
763              
764             =item content_types
765              
766             Reference to an array of the set of content types which may be witheld.
767              
768             =back
769              
770             =head2 Methods
771              
772             =over
773              
774             =item new
775              
776             Constructor, creates a new blank Net::Milter object.
777              
778             =item open
779              
780             Open a socket to a milter filter. Takes three arguments, the last
781             argument, can be 'tcp' or 'unix' depending if the connection is to be
782             made to a TCP socket or through a UNIX file system socket. For TCP
783             sockets, the first two argument are the IP address and the port number;
784             for UNIX sockets the first argument is the file path, the second the
785             timeout value.
786             Accepted synonyms for tcp and unix are inet and local respecively.
787              
788             e.g.
789              
790             $milter->open('127.0.0.1',5513,'tcp');
791              
792             to open a connection to port 5513 on address 127.0.0.1,
793             or
794              
795             $milter->open('/tmp/file.sck',10,'unix');
796              
797             to open a connection to /tmp/file.sck with a timeout of 10 seconds.
798              
799             The method creates the attribute, 'socket' containing an IO::Handle
800             object.
801              
802             =item protocol_negotiation
803              
804             Talk to the milter filter, describing the list of actions it may
805             perform, and any email content that won't be sent.
806             Accepts as argument the hash of allowable actions and withheld content.
807             The hash keys are :
808             Allowable actions by the filter :
809              
810             =over
811              
812             =item SMFIF_ADDHDRS - Add message headers.
813              
814             =item SMFIF_CHGBODY - Alter the message body.
815              
816             =item SMFIF_ADDRCPT - Add recipients to the message.
817              
818             =item SMFIF_DELRCPT - Delete recipients from the message.
819              
820             =item SMFIF_CHGHDRS - Change or delete message headers.
821              
822             =back
823              
824             The default is to allow all actions, setting the value to be '0' of any
825             of these keys in the argument hash informs the filter not perform the
826             action.
827              
828             e.g.
829              
830             $milter->protocol_negotiation(
831             SMFIF_ADDHDRS => 0,
832             SMFIF_CHGBODY => 1
833             );
834              
835             informs the filter it is able to change the contents of the message
836             body, but it may not add message headers.
837              
838             Withheld content :
839              
840             =over
841              
842             =item SMFIP_NOCONNECT - Do not expect the connection details.
843              
844             =item SMFIP_NOHELO - Do not expect the HELO string.
845              
846             =item SMFIP_NOMAIL - Do not expect the MAIL FROM string.
847              
848             =item SMFIP_NORCPT - Do not expect the RCPT TO string.
849              
850             =item SMFIP_NOBODY - Do not expect the email body.
851              
852             =item SMFIP_NOHDRS - Do not expect any email headers.
853              
854             =item SMFIP_NOEOH - Do not expect an end of headers signal.
855              
856             =back
857              
858             The default is to inform the filter to expect everything, setting the
859             value of the key to '1' informs the filter to not expect the content.
860              
861             e.g.
862              
863             $milter->protocol_negotiation(
864             SMFIF_ADDHDRS => 0,
865             SMFIF_CHGBODY => 1,
866             SMFIP_NOEHO => 1,
867             SMFIP_NOCONNECT => 1
868             );
869              
870             informs the filter it is able to change the contents of the message
871             body, but it may not add message headers, it will not receive an end
872             of headers signal, nor will it receive the connection details.
873              
874             The method returns three parameters, the protocol version, an array
875             reference containing all the names of the actions the filter
876             understands it is able to perform, and an array reference
877             containing the names of the content it understands it won't be sent.
878              
879             =item send_abort
880              
881             Send an abort signal to the mail filter.
882             Accepts nothing, returns nothing.
883              
884             =item send_body
885              
886             Send the body of the email to the mail filter.
887             NOTE the filter will only accept up to 65535 bytes of body at a time.
888             Feed the body to the filter piece by piece by repeat calls to send_body
889             with each body chunk until all the body is sent.
890             Accepts the message body, returns reference to an array of return codes
891             (see RETURN CODE section).
892              
893             =item send_end_body
894              
895             Send an end of body signal, i.e. no more body information will
896             follow. Returns a reference to an array of return codes (see RETURN
897             CODE section).
898              
899             =item send_connect
900              
901             Send the SMTP connect information to the mail filter.
902             Accepts the hostname, the family ('unix' for file sockets, 'tcp4' for
903             tcp connections (v4), 'tcp6' for version 6 tcp connections), the sending
904             connection port, the IP address of the sender. Returns a reference to an
905             array of return codes (see RETURN CODE section).
906              
907             e.g.
908              
909             $milter->send_connect(
910             'host.domain',
911             'tcp4',
912             '12345',
913             '127.0.0.1'
914             );
915              
916             The machine host.domain with IP address 127.0.0.1 connected to
917             us from port 12345 using TCP version 4.
918              
919             =item send_helo
920              
921             Send the HELO (or EHLO) string provided by the connecting computer.
922             Accepts the HELO string as an argument. Returns a reference to an array
923             of return codes (see RETURN CODE section).
924              
925             =item send_header
926              
927             Send a single header name and contents to the filter, accepts two
928             arguments, the header name and the header contents. Returns a reference
929             to an array of return codes (see RETURN CODE section).
930              
931             =item send_mail_from
932              
933             Send the MAIL FROM string to the filter, accepts the MAIL FROM data as
934             an argument. Returns a reference to an array of return codes (see
935             RETURN CODE section).
936              
937             =item send_end_headers
938              
939             Send an end of headers signal, i.e. no more header information will
940             follow. Returns a reference to an array of return codes (see RETURN
941             CODE section).
942              
943             =item send_rcpt_to
944              
945             Send the RCPT TO string to the filter, accepts an array of RCPT TO
946             recipients as argument. Returns a reference to an array of return
947             codes (see RETURN CODE section).
948              
949             =item send_quit
950              
951             Quit the milter communication, accepts nothing, returns nothing.
952              
953             =item send_macros
954              
955             Send Sendmail macro information to the filter. The method accepts a
956             hash of the Sendmail macro names, returns a reference to an array of
957             return codes (see RETURN CODE section).
958              
959             The potential macro names (hash keys) are :
960              
961             =over
962              
963             =item _ - email address of the Sendmail user.
964              
965             =item j - canonical hostname of the recipeint machine.
966              
967             =item {daemon_name} - name of the daemon from DaemonPortOptions.
968              
969             =item {if_name} - hostname of the incoming connection.
970              
971             =item {if_addr} - IP address of the incoming connection.
972              
973             =item {tls_version} - TLS/SSL version used for connection.
974              
975             =item {cipher} - cipher suite used for the connection.
976              
977             =item {cipher_bits} - keylength of the encryption algorith.
978              
979             =item {cert_subject} - distinguished name of the presented certificate.
980              
981             =item {cert_issuer} - name of the certificate authority.
982              
983             =item i - queue ID.
984              
985             =item {auth_type} - SMTP authentication mechanism.
986              
987             =item {auth_authen} - client's authenticated username.
988              
989             =item {auth_ssf} - keylength of encryption algorithm.
990              
991             =item {auth_author} - authorization identity.
992              
993             =item {mail_mailer} - mailer from SMTP MAIL command.
994              
995             =item {mail_host} - host from SMTP MAIL command.
996              
997             =item {mail_addr} - address from SMTP MAIL command.
998              
999             =item {rcpt_mailer} - mailer from SMTP RCPT command.
1000              
1001             =item {rcpt_host} - host from SMTP RCPT command.
1002              
1003             =item {rcpt_addr} - address from SMTP RCPT command.
1004              
1005             =back
1006              
1007             Yes I know most of this is redundant, since other methods repeat this
1008             information, but this is what the spec says.
1009              
1010             e.g.
1011             $milter->send_macros(
1012             mail_addr => '127.0.0.1',
1013             mail_host => 'localhost',
1014             rcpt_addr => '127.0.0.1',
1015             rcpt_addr => 'postmaster@localhost.localdomain'
1016             );
1017              
1018             For further explanation of macros see :
1019              
1020             http://people.freenet.de/slgig/op_en/macros.html
1021             and
1022             http://www.sendmail.com/idemo/prod_guide/switch/switchdemo/helplets/en/Macros.html
1023              
1024             =back
1025              
1026             =head1 NAME
1027              
1028             Net::Milter - Masquerade as the MTA to communicate with email
1029             filters through a milter interface.
1030              
1031             =head1 RETURN CODES
1032              
1033             Many methods return an array of hash references. Each hash describes
1034             one response from the filter, a filter may return more than one
1035             response to any sent data, such as 'add a header','modify body',
1036             'continue'.
1037             The hash keys are :
1038              
1039             =over
1040              
1041             =item command - the response from the filter
1042              
1043             =item explanation - verbose explanation of the required action
1044              
1045             =item action - action to perform, may be I<add>, I<delete>, I<accept>, I<replace>, I<continue> or I<reject>
1046              
1047             =item header - the name of header the action refers to (may be equal to 'body' to refer to the message body)
1048              
1049             =item value - the value relating to the action
1050              
1051             =back
1052              
1053             =head1 TIPS
1054              
1055             Call the various methods in the order that they would be called if accepting
1056             a SMTP stream, ie send_connect(), send_helo(), send_mail_from(), send_rcpt_to(),
1057             send_header(), send_end_headers(), send_body(). Some milter filters expect this
1058             and refuse to return values when expected.
1059             Equally continuing to send data when a filter has rejected or accepted a
1060             message may confuse it, and refuse to return values for subsequent data, so
1061             always check the codes returned.
1062              
1063             In some circumstantes 'read' has not worked, now replaced by 'sysread' which is
1064             reported to fix the problem. If this doesn't work, change 'sysread' to 'read' and
1065             email me please.
1066              
1067             Some filters appear to expect a bitwise negation of the protocol field. This is
1068             now disabled as default. If you wish to enable this, please set
1069             PROTOCOL_NEGATION => 1
1070              
1071             =head1 SEE ALSO
1072              
1073             This module is the Yang to Ying's Sendmail::Milter, which can act as the other end
1074             of the communication.
1075              
1076             =head1 NAMING
1077              
1078             I choose not to put this module in the Sendmail namespace, as it has nothing to do
1079             with Sendmail itself, neither is it anything to do with SMTP, its a net protocol,
1080             hence the Net namespace.
1081              
1082             =head1 AUTHOR
1083              
1084             Martin Lee, MessageLabs Ltd. (mlee@messagelabs.com)
1085              
1086             Copyright (c) 2003 Star Technology Group Ltd / 2004 MessageLabs Ltd.
1087              
1088             =head1 AUTHOR
1089              
1090             Marc Bradshaw <marc@marcbradshaw.net>
1091              
1092             =head1 COPYRIGHT AND LICENSE
1093              
1094             This software is copyright (c) 2020 by Marc Bradshaw.
1095              
1096             This is free software; you can redistribute it and/or modify it under
1097             the same terms as the Perl 5 programming language system itself.
1098              
1099             =cut