14 #include "gen_alloc.h"
15 #include "gen_allocdefs.h"
21 #include "headerbody.h"
22 #include "auto_qmail.h"
27 datetime_sec starttime
;
30 int flagdeletesender
= 0;
31 int flagdeletefrom
= 0;
32 int flagdeletemessid
= 0;
33 int flagnamecomment
= 0;
35 int flaghackrecip
= 0;
38 int mailusertokentype
;
42 stralloc control_idhost
= {0};
43 stralloc control_defaultdomain
= {0};
44 stralloc control_defaulthost
= {0};
45 stralloc control_plusdomain
= {0};
47 stralloc sender
= {0};
48 stralloc envsbuf
= {0};
49 token822_alloc envs
= {0};
55 void put(s
,len
) char *s
; int len
;
56 { if (flagqueue
) qmail_put(&qqt
,s
,len
); else substdio_put(subfdout
,s
,len
); }
57 void puts(s
) char *s
; { put(s
,str_len(s
)); }
59 void perm() { _exit(100); }
60 void temp() { _exit(111); }
62 substdio_putsflush(subfderr
,"qmail-inject: fatal: out of memory\n"); temp(); }
63 void die_invalid(sa
) stralloc
*sa
; {
64 substdio_putsflush(subfderr
,"qmail-inject: fatal: invalid header field: ");
65 substdio_putflush(subfderr
,sa
->s
,sa
->len
); perm(); }
67 substdio_putsflush(subfderr
,"qmail-inject: fatal: unable to exec qmail-queue\n"); temp(); }
69 substdio_putsflush(subfderr
,"qmail-inject: fatal: unable to run qmail-queue\n"); temp(); }
71 substdio_putsflush(subfderr
,"qmail-inject: fatal: internal bug\n"); temp(); }
73 substdio_putsflush(subfderr
,"qmail-inject: fatal: internal bug\n"); temp(); }
75 if (errno
== error_nomem
) die_nomem();
76 substdio_putsflush(subfderr
,"qmail-inject: fatal: read error\n"); temp(); }
77 void doordie(sa
,r
) stralloc
*sa
; int r
; {
78 if (r
== 1) return; if (r
== -1) die_nomem();
79 substdio_putsflush(subfderr
,"qmail-inject: fatal: unable to parse this line:\n");
80 substdio_putflush(subfderr
,sa
->s
,sa
->len
); perm(); }
83 substdio_putsflush(subfderr
,"qmail-inject: fatal: qmail-queue lost communications link\n"); temp(); }
85 substdio_putsflush(subfderr
,"qmail-inject: fatal: qmail-queue died\n"); temp(); }
87 substdio_putsflush(subfderr
,"qmail-inject: fatal: qmail-queue unable to write message to disk; disk full?\n"); temp(); }
89 substdio_putsflush(subfderr
,"qmail-inject: fatal: qmail-queue was killed\n"); temp(); }
90 void die_qqtimeout() {
91 substdio_putsflush(subfderr
,"qmail-inject: fatal: qmail-queue timed out\n"); temp(); }
92 void die_qqtoolong() {
93 substdio_putsflush(subfderr
,"qmail-inject: fatal: qmail-queue unhappy with long addresses\n"); perm(); }
95 GEN_ALLOC_typedef(saa
,stralloc
,sa
,len
,a
)
96 GEN_ALLOC_readyplus(saa
,stralloc
,sa
,len
,a
,i
,n
,x
,10,saa_readyplus
)
98 static stralloc sauninit
= {0};
108 if (!flagqueue
) substdio_flush(subfdout
);
114 if (!stralloc_0(&sender
)) die_nomem();
115 qmail_from(&qqt
,sender
.s
);
117 for (i
= 0;i
< reciplist
.len
;++i
)
119 if (!stralloc_0(&reciplist
.sa
[i
])) die_nomem();
120 qmail_to(&qqt
,reciplist
.sa
[i
].s
);
124 for (i
= 0;i
< hrrlist
.len
;++i
)
126 if (!stralloc_0(&hrrlist
.sa
[i
])) die_nomem();
127 qmail_to(&qqt
,hrrlist
.sa
[i
].s
);
130 for (i
= 0;i
< hrlist
.len
;++i
)
132 if (!stralloc_0(&hrlist
.sa
[i
])) die_nomem();
133 qmail_to(&qqt
,hrlist
.sa
[i
].s
);
136 switch(qmail_close(&qqt
))
139 case QMAIL_CRASHED
: die_qqsig();
140 case QMAIL_USAGE
: case QMAIL_BUG
: die_bug();
141 case QMAIL_EXECSOFT
: die_exec();
142 case QMAIL_NOMEM
: die_nomem();
143 case QMAIL_READ
: die_comm();
144 case QMAIL_WRITE
: die_qqwrite();
145 case QMAIL_TOOLONG
: die_qqtoolong();
146 case QMAIL_TIMEOUT
: die_qqtimeout();
154 void savedh_append(h
)
157 if (!saa_readyplus(&savedh
,1)) die_nomem();
158 savedh
.sa
[savedh
.len
] = sauninit
;
159 if (!stralloc_copy(savedh
.sa
+ savedh
.len
,h
)) die_nomem();
167 for (i
= 0;i
< savedh
.len
;++i
)
168 put(savedh
.sa
[i
].s
,savedh
.sa
[i
].len
);
171 stralloc defaultdomainbuf
= {0};
172 token822_alloc defaultdomain
= {0};
173 stralloc defaulthostbuf
= {0};
174 token822_alloc defaulthost
= {0};
175 stralloc plusdomainbuf
= {0};
176 token822_alloc plusdomain
= {0};
179 token822_alloc
*addr
;
181 if (addr
->t
[addr
->len
- 1].type
== TOKEN822_AT
)
183 if (addr
->t
[--addr
->len
].type
== TOKEN822_COLON
)
188 token822_alloc
*addr
;
191 if (addr
->t
[0].type
== TOKEN822_AT
)
194 for (i
= 0;i
< addr
->len
;++i
)
195 addr
->t
[i
] = addr
->t
[i
+ 1];
199 void rwextradot(addr
)
200 token822_alloc
*addr
;
203 if (addr
->t
[0].type
== TOKEN822_DOT
)
206 for (i
= 0;i
< addr
->len
;++i
)
207 addr
->t
[i
] = addr
->t
[i
+ 1];
212 token822_alloc
*addr
;
217 for (i
= 0;i
< addr
->len
;++i
)
218 if (addr
->t
[i
].type
== TOKEN822_AT
)
220 shift
= defaulthost
.len
;
221 if (!token822_readyplus(addr
,shift
)) die_nomem();
222 for (i
= addr
->len
- 1;i
>= 0;--i
)
223 addr
->t
[i
+ shift
] = addr
->t
[i
];
225 for (i
= 0;i
< shift
;++i
)
226 addr
->t
[i
] = defaulthost
.t
[shift
- 1 - i
];
230 token822_alloc
*addr
;
234 for (i
= 0;i
< addr
->len
;++i
)
236 if (addr
->t
[i
].type
== TOKEN822_DOT
)
238 if (addr
->t
[i
].type
== TOKEN822_AT
)
241 for (i
= 0;i
< addr
->len
;++i
)
243 if (addr
->t
[i
].type
== TOKEN822_LITERAL
)
245 if (addr
->t
[i
].type
== TOKEN822_AT
)
248 shift
= defaultdomain
.len
;
249 if (!token822_readyplus(addr
,shift
)) die_nomem();
250 for (i
= addr
->len
- 1;i
>= 0;--i
)
251 addr
->t
[i
+ shift
] = addr
->t
[i
];
253 for (i
= 0;i
< shift
;++i
)
254 addr
->t
[i
] = defaultdomain
.t
[shift
- 1 - i
];
258 token822_alloc
*addr
;
263 if (addr
->t
[0].type
!= TOKEN822_ATOM
) return;
264 if (!addr
->t
[0].slen
) return;
265 if (addr
->t
[0].s
[addr
->t
[0].slen
- 1] != '+') return;
267 --addr
->t
[0].slen
; /* remove + */
269 shift
= plusdomain
.len
;
270 if (!token822_readyplus(addr
,shift
)) die_nomem();
271 for (i
= addr
->len
- 1;i
>= 0;--i
)
272 addr
->t
[i
+ shift
] = addr
->t
[i
];
274 for (i
= 0;i
< shift
;++i
)
275 addr
->t
[i
] = plusdomain
.t
[shift
- 1 - i
];
279 token822_alloc
*addr
;
281 if (!addr
->len
) return; /* don't rewrite <> */
283 if (addr
->t
[1].type
== TOKEN822_AT
)
284 if (addr
->t
[0].type
== TOKEN822_LITERAL
)
285 if (!addr
->t
[0].slen
) /* don't rewrite <foo@[]> */
288 if (!addr
->len
) return; /* <@foo:> -> <> */
290 if (!addr
->len
) return; /* <.> -> <> */
292 if (!addr
->len
) return; /* <@> -> <> */
299 token822_alloc
*addr
;
303 token822_reverse(addr
);
304 if (token822_unquote(&sender
,addr
) != 1) die_nomem();
306 if (!stralloc_cats(&sender
,"-@[]")) die_nomem();
307 token822_reverse(addr
);
313 token822_alloc
*addr
;
321 token822_alloc
*addr
;
327 void rwrecip(addr
,xl
)
328 token822_alloc
*addr
;
332 token822_reverse(addr
);
333 if (!saa_readyplus(xl
,1)) die_nomem();
334 xl
->sa
[xl
->len
] = sauninit
;
335 if (token822_unquote(&xl
->sa
[xl
->len
],addr
) != 1) die_nomem();
337 token822_reverse(addr
);
340 int rwhrr(addr
) token822_alloc
*addr
;
341 { rwrecip(addr
,&hrrlist
); return 1; }
342 int rwhr(addr
) token822_alloc
*addr
;
343 { rwrecip(addr
,&hrlist
); return 1; }
345 int htypeseen
[H_NUM
];
346 stralloc hfbuf
= {0};
347 token822_alloc hfin
= {0};
348 token822_alloc hfrewrite
= {0};
349 token822_alloc hfaddr
= {0};
351 void doheaderfield(h
)
359 htype
= hfield_known(h
->s
,h
->len
);
360 if (flagdeletefrom
) if (htype
== H_FROM
) return;
361 if (flagdeletemessid
) if (htype
== H_MESSAGEID
) return;
362 if (flagdeletesender
) if (htype
== H_RETURNPATH
) return;
365 htypeseen
[htype
] = 1;
367 if (!hfield_valid(h
->s
,h
->len
))
375 case H_R_TO
: case H_R_CC
: case H_R_BCC
:
377 case H_TO
: case H_CC
: case H_BCC
: case H_APPARENTLYTO
:
379 case H_SENDER
: case H_FROM
: case H_REPLYTO
:
380 case H_RETURNRECEIPTTO
: case H_ERRORSTO
: case H_RETURNPATH
:
381 case H_R_SENDER
: case H_R_FROM
: case H_R_REPLYTO
:
388 doordie(h
,token822_parse(&hfin
,h
,&hfbuf
));
389 doordie(h
,token822_addrlist(&hfrewrite
,&hfaddr
,&hfin
,(htype
== H_RETURNPATH
) ? rwreturn
: (flagrecip ?
(flagrr ? rwhrr
: rwhr
) : rwsender
)));
390 if (token822_unparse(h
,&hfrewrite
,LINELEN
) != 1)
394 if (htype
== H_BCC
) return;
395 if (htype
== H_R_BCC
) return;
396 if (htype
== H_RETURNPATH
) return;
397 if (htype
== H_CONTENTLENGTH
) return; /* some things are just too stupid */
407 stralloc torecip
= {0};
408 token822_alloc tr
= {0};
413 if (!quote2(&torecip
,s
)) die_nomem();
414 switch(token822_parse(&tr
,&torecip
,&hfbuf
))
416 case -1: die_nomem();
418 substdio_puts(subfderr
,"qmail-inject: fatal: unable to parse address: ");
419 substdio_puts(subfderr
,s
);
420 substdio_putsflush(subfderr
,"\n");
423 token822_reverse(&tr
);
424 rwrecip(&tr
,&reciplist
);
427 stralloc defaultfrom
= {0};
428 token822_alloc df
= {0};
430 void defaultfrommake()
433 fullname
= env_get("QMAILNAME");
434 if (!fullname
) fullname
= env_get("MAILNAME");
435 if (!fullname
) fullname
= env_get("NAME");
436 if (!token822_ready(&df
,20)) die_nomem();
438 df
.t
[df
.len
].type
= TOKEN822_ATOM
;
439 df
.t
[df
.len
].s
= "From";
440 df
.t
[df
.len
].slen
= 4;
442 df
.t
[df
.len
].type
= TOKEN822_COLON
;
444 if (fullname
&& !flagnamecomment
)
446 df
.t
[df
.len
].type
= TOKEN822_QUOTE
;
447 df
.t
[df
.len
].s
= fullname
;
448 df
.t
[df
.len
].slen
= str_len(fullname
);
450 df
.t
[df
.len
].type
= TOKEN822_LEFT
;
453 df
.t
[df
.len
].type
= mailusertokentype
;
454 df
.t
[df
.len
].s
= mailuser
;
455 df
.t
[df
.len
].slen
= str_len(mailuser
);
459 df
.t
[df
.len
].type
= TOKEN822_AT
;
461 df
.t
[df
.len
].type
= TOKEN822_ATOM
;
462 df
.t
[df
.len
].s
= mailhost
;
463 df
.t
[df
.len
].slen
= str_len(mailhost
);
466 if (fullname
&& !flagnamecomment
)
468 df
.t
[df
.len
].type
= TOKEN822_RIGHT
;
471 if (fullname
&& flagnamecomment
)
473 df
.t
[df
.len
].type
= TOKEN822_COMMENT
;
474 df
.t
[df
.len
].s
= fullname
;
475 df
.t
[df
.len
].slen
= str_len(fullname
);
478 if (token822_unparse(&defaultfrom
,&df
,LINELEN
) != 1) die_nomem();
479 doordie(&defaultfrom
,token822_parse(&df
,&defaultfrom
,&hfbuf
));
480 doordie(&defaultfrom
,token822_addrlist(&hfrewrite
,&hfaddr
,&df
,rwsender
));
481 if (token822_unparse(&defaultfrom
,&hfrewrite
,LINELEN
) != 1) die_nomem();
484 stralloc defaultreturnpath
= {0};
485 token822_alloc drp
= {0};
486 stralloc hackedruser
= {0};
487 char strnum
[FMT_ULONG
];
489 void dodefaultreturnpath()
491 if (!stralloc_copys(&hackedruser
,mailruser
)) die_nomem();
494 if (!stralloc_cats(&hackedruser
,"-")) die_nomem();
495 if (!stralloc_catb(&hackedruser
,strnum
,fmt_ulong(strnum
,(unsigned long) starttime
))) die_nomem();
496 if (!stralloc_cats(&hackedruser
,".")) die_nomem();
497 if (!stralloc_catb(&hackedruser
,strnum
,fmt_ulong(strnum
,(unsigned long) getpid()))) die_nomem();
500 if (!stralloc_cats(&hackedruser
,"-")) die_nomem();
501 if (!token822_ready(&drp
,10)) die_nomem();
503 drp
.t
[drp
.len
].type
= TOKEN822_ATOM
;
504 drp
.t
[drp
.len
].s
= "Return-Path";
505 drp
.t
[drp
.len
].slen
= 11;
507 drp
.t
[drp
.len
].type
= TOKEN822_COLON
;
509 drp
.t
[drp
.len
].type
= TOKEN822_QUOTE
;
510 drp
.t
[drp
.len
].s
= hackedruser
.s
;
511 drp
.t
[drp
.len
].slen
= hackedruser
.len
;
515 drp
.t
[drp
.len
].type
= TOKEN822_AT
;
517 drp
.t
[drp
.len
].type
= TOKEN822_ATOM
;
518 drp
.t
[drp
.len
].s
= mailrhost
;
519 drp
.t
[drp
.len
].slen
= str_len(mailrhost
);
522 if (token822_unparse(&defaultreturnpath
,&drp
,LINELEN
) != 1) die_nomem();
523 doordie(&defaultreturnpath
,token822_parse(&drp
,&defaultreturnpath
,&hfbuf
));
524 doordie(&defaultreturnpath
525 ,token822_addrlist(&hfrewrite
,&hfaddr
,&drp
,rwreturn
));
526 if (token822_unparse(&defaultreturnpath
,&hfrewrite
,LINELEN
) != 1) die_nomem();
532 htypeseen
[H_R_SENDER
] || htypeseen
[H_R_FROM
] || htypeseen
[H_R_REPLYTO
]
533 || htypeseen
[H_R_TO
] || htypeseen
[H_R_CC
] || htypeseen
[H_R_BCC
]
534 || htypeseen
[H_R_DATE
] || htypeseen
[H_R_MESSAGEID
];
537 dodefaultreturnpath();
541 static stralloc sa
= {0};
542 static stralloc sa2
= {0};
544 if (!stralloc_copy(&sa
,&sender
)) die_nomem();
545 if (!stralloc_0(&sa
)) die_nomem();
546 if (!quote2(&sa2
,sa
.s
)) die_nomem();
548 puts("Return-Path: <");
553 /* could check at this point whether there are any recipients */
555 if (qmail_open(&qqt
) == -1) die_qqt();
559 if (!htypeseen
[H_R_DATE
])
561 if (!newfield_datemake(starttime
)) die_nomem();
563 put(newfield_date
.s
,newfield_date
.len
);
565 if (!htypeseen
[H_R_MESSAGEID
])
567 if (!newfield_msgidmake(control_idhost
.s
,control_idhost
.len
,starttime
)) die_nomem();
569 put(newfield_msgid
.s
,newfield_msgid
.len
);
571 if (!htypeseen
[H_R_FROM
])
575 put(defaultfrom
.s
,defaultfrom
.len
);
577 if (!htypeseen
[H_R_TO
] && !htypeseen
[H_R_CC
])
578 puts("Resent-Cc: recipient list not shown: ;\n");
582 if (!htypeseen
[H_DATE
])
584 if (!newfield_datemake(starttime
)) die_nomem();
585 put(newfield_date
.s
,newfield_date
.len
);
587 if (!htypeseen
[H_MESSAGEID
])
589 if (!newfield_msgidmake(control_idhost
.s
,control_idhost
.len
,starttime
)) die_nomem();
590 put(newfield_msgid
.s
,newfield_msgid
.len
);
592 if (!htypeseen
[H_FROM
])
595 put(defaultfrom
.s
,defaultfrom
.len
);
597 if (!htypeseen
[H_TO
] && !htypeseen
[H_CC
])
598 puts("Cc: recipient list not shown: ;\n");
606 static stralloc sa
= {0};
609 if (control_init() == -1) die_read();
611 if (control_rldef(&control_defaultdomain
,"control/defaultdomain",1,"defaultdomain") != 1)
613 x
= env_get("QMAILDEFAULTDOMAIN");
614 if (x
) if (!stralloc_copys(&control_defaultdomain
,x
)) die_nomem();
615 if (!stralloc_copys(&sa
,".")) die_nomem();
616 if (!stralloc_cat(&sa
,&control_defaultdomain
)) die_nomem();
617 doordie(&sa
,token822_parse(&defaultdomain
,&sa
,&defaultdomainbuf
));
619 if (control_rldef(&control_defaulthost
,"control/defaulthost",1,"defaulthost") != 1)
621 x
= env_get("QMAILDEFAULTHOST");
622 if (x
) if (!stralloc_copys(&control_defaulthost
,x
)) die_nomem();
623 if (!stralloc_copys(&sa
,"@")) die_nomem();
624 if (!stralloc_cat(&sa
,&control_defaulthost
)) die_nomem();
625 doordie(&sa
,token822_parse(&defaulthost
,&sa
,&defaulthostbuf
));
627 if (control_rldef(&control_plusdomain
,"control/plusdomain",1,"plusdomain") != 1)
629 x
= env_get("QMAILPLUSDOMAIN");
630 if (x
) if (!stralloc_copys(&control_plusdomain
,x
)) die_nomem();
631 if (!stralloc_copys(&sa
,".")) die_nomem();
632 if (!stralloc_cat(&sa
,&control_plusdomain
)) die_nomem();
633 doordie(&sa
,token822_parse(&plusdomain
,&sa
,&plusdomainbuf
));
635 if (control_rldef(&control_idhost
,"control/idhost",1,"idhost") != 1)
637 x
= env_get("QMAILIDHOST");
638 if (x
) if (!stralloc_copys(&control_idhost
,x
)) die_nomem();
641 #define RECIP_DEFAULT 1
643 #define RECIP_HEADER 3
658 qmopts
= env_get("QMAILINJECT");
663 case 'c': flagnamecomment
= 1; break;
664 case 's': flagdeletesender
= 1; break;
665 case 'f': flagdeletefrom
= 1; break;
666 case 'i': flagdeletemessid
= 1; break;
667 case 'r': flaghackrecip
= 1; break;
668 case 'm': flaghackmess
= 1; break;
671 mailhost
= env_get("QMAILHOST");
672 if (!mailhost
) mailhost
= env_get("MAILHOST");
673 mailrhost
= env_get("QMAILSHOST");
674 if (!mailrhost
) mailrhost
= mailhost
;
676 mailuser
= env_get("QMAILUSER");
677 if (!mailuser
) mailuser
= env_get("MAILUSER");
678 if (!mailuser
) mailuser
= env_get("USER");
679 if (!mailuser
) mailuser
= env_get("LOGNAME");
680 if (!mailuser
) mailuser
= "anonymous";
681 mailusertokentype
= TOKEN822_ATOM
;
682 if (quote_need(mailuser
,str_len(mailuser
))) mailusertokentype
= TOKEN822_QUOTE
;
683 mailruser
= env_get("QMAILSUSER");
684 if (!mailruser
) mailruser
= mailuser
;
686 for (i
= 0;i
< H_NUM
;++i
) htypeseen
[i
] = 0;
688 recipstrategy
= RECIP_DEFAULT
;
691 if (chdir(auto_qmail
) == -1)
695 if (!saa_readyplus(&hrlist
,1)) die_nomem();
696 if (!saa_readyplus(&hrrlist
,1)) die_nomem();
697 if (!saa_readyplus(&reciplist
,1)) die_nomem();
699 while ((opt
= getopt(argc
,argv
,"aAhHnNf:")) != opteof
)
702 case 'a': recipstrategy
= RECIP_ARGS
; break;
703 case 'A': recipstrategy
= RECIP_DEFAULT
; break;
704 case 'h': recipstrategy
= RECIP_HEADER
; break;
705 case 'H': recipstrategy
= RECIP_AH
; break;
706 case 'n': flagqueue
= 0; break;
707 case 'N': flagqueue
= 1; break;
709 if (!quote2(&sender
,optarg
)) die_nomem();
710 doordie(&sender
,token822_parse(&envs
,&sender
,&envsbuf
));
711 token822_reverse(&envs
);
713 token822_reverse(&envs
);
714 if (token822_unquote(&sender
,&envs
) != 1) die_nomem();
723 if (recipstrategy
== RECIP_DEFAULT
)
724 recipstrategy
= (*argv ? RECIP_ARGS
: RECIP_HEADER
);
726 if (recipstrategy
!= RECIP_HEADER
)
730 flagrh
= (recipstrategy
!= RECIP_ARGS
);
732 if (headerbody(subfdin
,doheaderfield
,finishheader
,dobody
) == -1)