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