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   2441 use strict;
  115         244  
  115         4017  
4 115     115   632 use Carp;
  115         402  
  115         6008  
5 115     115   694 use vars qw($DEBUG);
  115         254  
  115         7104  
6             # ABSTRACT: Local modified copy of Net::Milter
7             our $VERSION = '3.20230629'; # VERSION
8             $DEBUG=0;
9              
10 115     115   753 use constant PROTOCOL_NEGATION => 0;
  115         287  
  115         26409  
11              
12             ############
13             sub new
14             {
15             # create new blank class
16 33     33 1 280 my $proto = shift;
17 33   33     1823 my $class = ref($proto) || $proto;
18 33         442 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         1251 $self->{action_types} = ['SMFIF_ADDHDRS', 'SMFIF_CHGBODY', 'SMFIF_ADDRCPT', 'SMFIF_DELRCPT', 'SMFIF_CHGHDRS', 'SMFIF_QUARANTINE'];
23 33         414 $self->{content_types} = ['SMFIP_NOCONNECT', 'SMFIP_NOHELO', 'SMFIP_NOMAIL', 'SMFIP_NORCPT', 'SMFIP_NOBODY', 'SMFIP_NOHDRS', 'SMFIP_NOEOH'];
24              
25 33         526 bless($self,$class);
26 33         896 return $self;
27             } # end sub new
28             ############
29              
30             ############
31             sub open {
32             # open the socket
33 115     115   1108 use IO::Socket;
  115         459  
  115         1584  
34              
35 33     33 1 169 my $self = shift;
36 33         198 my ($addr,$port,$proto) = @_;
37              
38 33 50       244 if ($DEBUG==1) {print STDERR "open\n";}
  0         0  
39              
40 33         115 my $sock;
41              
42 33 50 33     1605 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   93701 use IO::Socket::INET;
  115         355  
  115         1445  
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       459 if ($DEBUG==1) {print STDERR "\topen unix socket\n";}
  0         0  
54 115     115   118654 use IO::Socket::UNIX;
  115         345  
  115         2345  
55 33 50       3198 $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       36948 if (!defined($sock)) {return 0;}
  0         0  
63             else {
64 33         1029 $self->{socket} = $sock;
65 33         247 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 168 my $self = shift;
75              
76 33         2786 my (%options) = @_;
77              
78 33 50       281 if ($DEBUG==1) {print STDERR "protocol_negotiation\n";}
  0         0  
79              
80             # set up the bit mask of allowed actions
81 33         148 my (@action_types) = @{$self->{action_types}};
  33         316  
82 33         152 my (@content_types) = @{$self->{content_types}};
  33         286  
83              
84 33         174 my ($count,$action,$content);
85              
86 33 50       209 if ($DEBUG==1) {print STDERR "\tsetting bits\n";}
  0         0  
87              
88 33         108 my $action_field = 0;
89              
90 33         281 $count=0;
91 33         310 while ($action = shift(@action_types)) {
92 198 100 100     1513 if (defined($options{$action}) && $options{$action}==0) {
93             # do nothing
94             }
95             else {
96 99         460 $action_field = $action_field | (2**$count);
97             }
98              
99 198         568 $count++;
100             } # end while
101              
102              
103             # set up the bit mask for possible protocols
104 33         186 my $protocol_field = 0;
105              
106 33         84 $count=0;
107 33         555 while ($content = shift(@content_types)) {
108 231 50 33     1751 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         628 $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         191 my $smfi_version = 2; # version of protocol
121 33         158 my $length = 13;
122              
123 33 50       232 if ($DEBUG==1) {print STDERR "\tpacking\n";}
  0         0  
124              
125 33         942 $action_field = $self->_pack_number($action_field);
126 33         163 $protocol_field = $self->_pack_number($protocol_field);
127 33         288 if (PROTOCOL_NEGATION == 1) {$protocol_field = ~$protocol_field;}
128 33         185 $smfi_version = $self->_pack_number($smfi_version);
129 33         227 $length = $self->_pack_number($length);
130              
131 33 50       296 if ($DEBUG==1) {print STDERR "\tsendsubing\n";}
  0         0  
132              
133 33         1710 $self->{socket}->send($length);
134 33         5866 $self->{socket}->send('O');
135 33         1780 $self->{socket}->send($smfi_version);
136 33         1779 $self->{socket}->send($action_field);
137 33         1335 $self->{socket}->send($protocol_field);
138              
139 33 50       1339 if ($DEBUG==1) {print STDERR "\treceiving\n";}
  0         0  
140              
141 33         753 my ($command,$data)=$self->_receive();
142              
143 33 50       311 if ($command ne 'O') {carp "error in protocol negotiation \n";}
  0         0  
144              
145 33         885 my($ret_version,$ret_actions,$ret_protocol)=unpack "NNN",$data;
146              
147 33 50       263 if ($DEBUG==1) {print STDERR "\treturned version : $ret_version\n";}
  0         0  
148 33 50       336 if ($DEBUG==1) {printf STDERR "\treturned actions : %8b\n", $ret_actions;}
  0         0  
149 33 50       325 if ($DEBUG==1) {printf STDERR "\treturned protocol : %7b\n", $ret_protocol;}
  0         0  
150              
151             # translate returned bit mask into fields
152 33 50       326 if ($DEBUG==1) {print STDERR "\ttranslating bit mask\n";}
  0         0  
153              
154 33         262 my (@returned_actions, @returned_protocol);
155              
156 33         122 $count=0;
157 33         285 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         156 $count=0;
165 33         242 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         714 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 551 if ($DEBUG==1) {print STDERR "send_abort\n";}
  0         0  
184 33         170 my $self = shift;
185 33         786 $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 126 my $self = shift;
195 31         360 my $body = shift;
196 31 50       1090 if ($DEBUG==1) {print STDERR "send_body\n";}
  0         0  
197             # restrict body size to max allowable
198              
199 31 50       327 if ($DEBUG==1) {print STDERR "\tsending".substr($body,0,5).'...'."\n";}
  0         0  
200              
201 31 50       399 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         264 $self->_send('B',$body);
208             }
209              
210 31 50       401 if ($DEBUG==1) {print STDERR "\treceiving from body\n";}
  0         0  
211              
212             # get response
213 31         286 my (@replies)=$self->_retrieve_responses();
214 31         481 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 124 my $self = shift;
224 33         141 my $body = shift;
225 33 50       565 if ($DEBUG==1) {print STDERR "send end_body\n";}
  0         0  
226              
227 33         267 $self->_send('E');
228 33 50       429 if ($DEBUG==1) {print STDERR "\treceiving\n";}
  0         0  
229              
230             # get response
231 33         249 my (@replies)=$self->_retrieve_responses();
232 33         658 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 148 my $self = shift;
242 33         170 my ($hostname,$family,$port,$ip_address) = @_;
243              
244 33         146 my ($protocol_family);
245              
246 33         232 $hostname .="\0";
247 33         132 $ip_address .="\0";
248              
249 33 50       243 if ($DEBUG==1) {print STDERR "send connect\n";}
  0         0  
250              
251 33 50       557 if (lc($family) eq 'unix') {$protocol_family='L';}
  0 50       0  
    0          
252 33         388 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         369 $port = pack "n",$port;
257              
258 33 50       321 if ($DEBUG==1) {print STDERR "\tsending\n";}
  0         0  
259              
260 33         311 $self->_send('C',$hostname,$protocol_family,$port,$ip_address);
261              
262 33         334 my (@replies)=$self->_retrieve_responses();
263 33         511 return (@replies);
264             } # end sub send_connect
265             ############
266              
267             ############
268             sub send_helo {
269             # send helo string, SMFIC_HELO
270 33     33 1 175 my $self=shift;
271 33         239 my $helo_string = shift;
272 33 50       438 if ($DEBUG==1) {print STDERR "send_helo\n";}
  0         0  
273              
274 33         254 $helo_string .="\0";
275 33         344 $self->_send('H',$helo_string);
276              
277 33 50       230 if ($DEBUG==1) {print STDERR "\treceiving\n";}
  0         0  
278              
279 33         293 my (@replies)=$self->_retrieve_responses();
280 33         481 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 1144 my $self=shift;
289 399         1309 my $header_name = shift;
290 399         1513 my $header_value = shift;
291              
292 399 50       1830 if ($DEBUG==1) {print STDERR "send_header\n";}
  0         0  
293              
294 399         1742 $header_name.="\0";
295 399         1412 $header_value.="\0";
296              
297 399         2032 $self->_send('L',$header_name,$header_value);
298              
299 399         1692 my (@replies)=$self->_retrieve_responses();
300 399         3081 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 170 my $self=shift;
309 33         123 my $mail_from = shift;
310              
311 33 50       258 if ($DEBUG==1) {print STDERR "send_mail_from\n";}
  0         0  
312              
313 33         224 $mail_from.="\0";
314              
315 33         294 $self->_send('M',$mail_from);
316              
317 33         318 my (@replies)=$self->_retrieve_responses();
318 33         763 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 264 my $self=shift;
327              
328 33 50       224 if ($DEBUG==1) {print STDERR "send_end_headers\n";}
  0         0  
329              
330 33         342 $self->_send('N');
331              
332 33         311 my (@replies)=$self->_retrieve_responses();
333 33         534 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 209 my $self=shift;
342 33         142 my $rcpt_to = shift;
343              
344 33 50       303 if ($DEBUG==1) {print STDERR "send_rcpt_to\n";}
  0         0  
345              
346 33         258 $rcpt_to.="\0";
347              
348 33         306 $self->_send('R',$rcpt_to);
349              
350 33         254 my (@replies)=$self->_retrieve_responses();
351 33         613 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 240 my $self=shift;
361              
362 33 50       403 if ($DEBUG==1) {print STDERR "send_quit\n";}
  0         0  
363              
364 33         291 $self->_send('Q');
365              
366 33         1396 $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   2597 my $self = shift;
376 890         4933 my $command = shift;
377 890         4060 my (@data) = @_;
378              
379 890 50       3940 if ($DEBUG==1) {print STDERR "send\n";}
  0         0  
380              
381 890         4708 my $data = join '',@data;
382 890         2664 my $length = length($data);
383 890         2378 $length += 1;
384              
385 890 50       3212 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         3008 $length = $self->_pack_number($length);
392              
393 890 50       4282 if (!defined($self->{socket})) {carp "can't connect no connection defined !\n";}
  0         0  
394 890         4224 $self->_io_send($length);
395 890         4730 $self->_io_send($command);
396 890 100       4549 $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   296656 use IO::Select;
  115         452  
  115         254271  
407              
408 743     743   1966 my $self = shift;
409              
410 743 50       2868 if ($DEBUG==1) {print STDERR "_receive\n";}
  0         0  
411              
412 743         2585 my $length = $self->_io_recv(4);
413 743         4644 my $command = $self->_io_recv(1);
414 743         4356 $length = $self->_unpack_number($length);
415 743 50       3140 if ($DEBUG==1) {print STDERR "\tcommand : $command\n\tlength : $length\n";}
  0         0  
416 743         2091 $length -= 1;
417              
418 743         1839 my $data;
419 743 100       2759 if ($length > 0) {
420 116         703 $data = $self->_io_recv($length);
421             }
422              
423 743         4628 return ($command,$data);
424             } # end sub _receive
425             ############
426              
427             ############
428             sub _pack_number {
429             # single place to pack numbers
430 1022     1022   2609 my $self = shift;
431 1022         2484 my $number = shift;
432              
433 1022 50       3862 if ($DEBUG==1) {print STDERR "_pack_number\n";}
  0         0  
434              
435 1022         5465 my $ret_number = pack "N",$number;
436              
437 1022         4619 return ($ret_number);
438             } # end sub _pack_number
439             ############
440              
441             ############
442             sub _unpack_number {
443             # single place to unpack numbers
444 816     816   2769 my $self = shift;
445 816         2898 my $number = shift;
446              
447 816 50       4060 if ($DEBUG==1) {print STDERR "_unpack_number\n";}
  0         0  
448              
449 816         4421 my $ret_number = unpack "N",$number;
450              
451 816         2688 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   2147 my $self = shift;
460 710         2472 my ($command,$data)=@_;
461              
462 710 50       3211 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         2104 my %reply=();
469              
470 710         6982 $reply{command}=$command;
471              
472 710 50       7896 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         3081 $reply{explanation}='Accept and continue';
500 627         2422 $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         35 $reply{explanation}='Add header';
510 9         152 ($reply{header},$reply{value},undef)=split(/\0/,$data);
511 9         40 $reply{action}='add';
512             }
513              
514             elsif ($command eq 'i') {
515 60         344 $reply{explanation}='Insert header';
516 60         919 $reply{index}=$self->_unpack_number(substr($data,0,4));
517 60         586 $data = substr($data,4);
518 60         1258 ($reply{header},$reply{value},undef)=split(/\0/,$data);
519 60         379 $reply{action}='insert';
520             }
521              
522             elsif ($command eq 'm') {
523 13         41 $reply{explanation}='Replace body header';
524 13         147 $reply{index}=$self->_unpack_number(substr($data,0,4));
525 13         45 $data = substr($data,4);
526 13         151 ($reply{header},$reply{value},undef)=split(/\0/,$data);
527 13         45 $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         5 $reply{action}='reject';
550 1         6 $reply{value}=$data;
551             }
552              
553              
554 710         3636 return (\%reply);
555             } # end sub _translate_response
556             ############
557              
558             ############
559             sub _retrieve_responses {
560              
561 628     628   1736 my $self = shift;
562              
563 628         1615 my (@replies,$command,$data,$reply_ref);
564              
565 628 50       2525 if ($DEBUG==1) {print STDERR "_retrieve_response\n";}
  0         0  
566              
567 628         1399 while () {
568 710 50       2335 if ($DEBUG==1) {print STDERR "\twaiting for response\n";}
  0         0  
569 710         2571 ($command,$data)=$self->_receive();
570 710         3606 ($reply_ref)=$self->_translate_response($command,$data);
571              
572 710         2875 push @replies,$reply_ref;
573              
574 710 50       2908 if ($DEBUG==1) {print STDERR "\tcommand : $$reply_ref{command}";}
  0         0  
575 710 100       4209 if ($$reply_ref{command} eq 'c') {last;}
  627 50       2260  
    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         5 elsif ($$reply_ref{command} eq 'y') {last;}
580 0         0 elsif ($$reply_ref{command} eq 'd') {last;}
581             } # end while
582              
583 628         4175 return (@replies);
584             } # end sub retrieve_responses
585             ############
586              
587             ############
588             sub send_macros {
589 196     196 1 772 my $self=shift;
590 196         5035 my %macros = @_;
591              
592 196 50       1377 if ($DEBUG==1) {print STDERR "retrieve_response\n";}
  0         0  
593              
594 196         623 my (@data);
595              
596 196 50       1076 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       1107 if (defined($macros{j})) {push @data,'j'."\0".$macros{j}."\0";}
  33         395  
603 196 50       1151 if (defined($macros{_})) {push @data,'_'."\0",$macros{_}."\0";}
  0         0  
604 196 50       1084 if (defined($macros{'{daemon_name}'})) {push @data,'{daemon_name}'."\0".$macros{'{daemon_name}'}."\0";}
  0         0  
605 196 50       1105 if (defined($macros{'{if_name}'})) {push @data,'{if_name}'."\0".$macros{'{if_name}'}."\0";}
  0         0  
606 196 50       1061 if (defined($macros{'{if_addr}'})) {push @data,'{if_addr}'."\0".$macros{'{if_addr}'}."\0";}
  0         0  
607              
608 196 100       1165 if (@data) {
609 33 50       404 if ($DEBUG==1) {print STDERR "\tsending D,C\n";}
  0         0  
610 33         340 $self->_send('D','C',@data);
611             }
612              
613 196         801 @data=();
614 196 50       893 if (defined($macros{'{tls_version}'})) {push @data,'{tls_version}'."\0".$macros{'{tls_version}'}."\0";}
  0         0  
615 196 50       981 if (defined($macros{'{cipher}'})) {push @data,'{cipher}'."\0".$macros{'{cipher}'}."\0";}
  0         0  
616 196 50       941 if (defined($macros{'{cipher_bits}'})) {push @data,'{cipher_bits}'."\0".$macros{'{cipher_bits}'}."\0";}
  0         0  
617 196 50       988 if (defined($macros{'{cert_subject}'})) {push @data,'{cert_subject}'."\0".$macros{'{cert_subject}'}."\0";}
  0         0  
618 196 50       1051 if (defined($macros{'{cert_issuer}'})) {push @data,'{cert_issuer}'."\0".$macros{'{cert_issuer}'}."\0";}
  0         0  
619              
620 196 50       879 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         583 @data=();
628 196 100       1268 if (defined($macros{i})) {push @data,'i'."\0".$macros{i}."\0";}
  97         680  
629 196 50       1187 if (defined($macros{'{auth_type}'})) {push @data,'{auth_type}'."\0".$macros{'{auth_type}'}."\0";}
  0         0  
630 196 50       1183 if (defined($macros{'{auth_authen}'})) {push @data,'{auth_authen}'."\0".$macros{'{auth_authen}'}."\0";}
  0         0  
631 196 50       988 if (defined($macros{'{auth_ssf}'})) {push @data,'{auth_ssf}'."\0".$macros{'{auth_ssf}'}."\0";}
  0         0  
632 196 50       1010 if (defined($macros{'{auth_author}'})) {push @data,'{auth_author}'."\0".$macros{'{auth_author}'}."\0";}
  0         0  
633 196 100       1004 if (defined($macros{'{mail_mailer}'})) {push @data,'{mail_mailer}'."\0".$macros{'{mail_mailer}'}."\0";}
  33         600  
634 196 100       1052 if (defined($macros{'{mail_host}'})) {push @data,'{mail_host}'."\0".$macros{'{mail_host}'}."\0";}
  33         324  
635 196 100       1018 if (defined($macros{'{mail_addr}'})) {push @data,'{mail_addr}'."\0".$macros{'{mail_addr}'}."\0";}
  33         274  
636              
637 196 100       936 if (@data) {
638 130 50       829 if ($DEBUG==1) {print STDERR "\tsending D,M\n";}
  0         0  
639 130         967 $self->_send('D','M',@data);
640             }
641              
642              
643 196         812 @data=();
644 196 100       1197 if (defined($macros{'{rcpt_mailer}'})) {push @data,'{rcpt_mailer}'."\0".$macros{'{rcpt_mailer}'}."\0";}
  33         453  
645 196 100       1035 if (defined($macros{'{rcpt_host}'})) {push @data,'{rcpt_host}'."\0".$macros{'{rcpt_host}'}."\0";}
  33         262  
646 196 100       1198 if (defined($macros{'{rcpt_addr}'})) {push @data,'{rcpt_addr}'."\0".$macros{'{rcpt_addr}'}."\0";}
  33         281  
647              
648 196 100       1067 if (@data) {
649 33 50       340 if ($DEBUG==1) {print STDERR "\tsending D,R\n";}
  0         0  
650 33         473 $self->_send('D','R',@data);
651             }
652              
653              
654             # no response after sending macros
655 196         985 return 1;
656              
657             } # end sub send_macros
658             ############
659              
660             ############
661             sub _io_send {
662 2538     2538   6381 my $self = shift;
663 2538         7621 my ($data) = @_;
664              
665 2538         6125 my $must_send = length($data);
666 2538         5606 my $did_send = 0;
667 2538         8028 while ($did_send < $must_send) {
668 2538         17552 my $len = $self->{socket}->send(substr($data, $did_send));
669 2538 50       182984 if (defined($len)) {
670 2538         10364 $did_send += $len;
671             }
672             else {
673 0         0 carp "Error while writing to the socket: $!";
674             }
675             }
676              
677 2538         7938 return 1;
678             }
679             ############
680              
681             ############
682             sub _io_recv {
683 1602     1602   4051 my $self = shift;
684 1602         5544 my ($must_recv) = @_;
685              
686 1602         3755 my $did_recv = 0;
687 1602         3806 my $data = "";
688 1602         5001 while ($did_recv < $must_recv) {
689 1602         11998 my $len = $self->{socket}->sysread($data, $must_recv-$did_recv, $did_recv);
690 1602 50       31560889 if (defined($len)) {
691 1602         8389 $did_recv += $len;
692             }
693             else {
694 0         0 carp "Error while reading from the socket: $!";
695             }
696             }
697              
698 1602         8858 return $data;
699             }
700             ############
701              
702             ############
703             sub DESTROY {
704 33     33   194 my $self = shift;
705 33 50       281 if (defined($self->{socket})) {
706 33         274 $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.20230629
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