7 #include "auto_qmail.h"
27 substdio ssout
= SUBSTDIO_FDBUF(write
,1,ssoutbuf
,sizeof(ssoutbuf
));
29 void die() { substdio_flush(&ssout
); _exit(1); }
30 void flush() { if (substdio_flush(&ssout
) == -1) _exit(1); }
31 void out(s
) char *s
; { if (substdio_puts(&ssout
,s
) == -1) die(); }
33 int timeoutread(fd
,buf
,n
) int fd
; char *buf
; int n
;
38 r
= read(fd
,buf
,n
); saveerrno
= errno
;
40 errno
= saveerrno
; return r
;
44 substdio ssin
= SUBSTDIO_FDBUF(timeoutread
,0,ssinbuf
,sizeof(ssinbuf
));
47 void outofmem() { out("421 out of memory (#4.3.0)\r\n"); die(); }
48 void sigalrm() { out("451 timeout (#4.4.2)\r\n"); die(); }
51 stralloc greeting
= {0};
53 stralloc liphost
= {0};
55 stralloc rcpthosts
= {0};
56 struct constmap maprcpthosts
;
59 struct constmap mapbmf
;
60 int flagbarf
; /* defined if seenmail */
62 stralloc helohost
= {0};
63 stralloc mailfrom
= {0};
64 stralloc rcptto
= {0};
67 stralloc addr
= {0}; /* will be 0-terminated, if addrparse returns 1 */
75 void dohelo(arg
) char *arg
;
77 if (!stralloc_copys(&helohost
,arg
)) outofmem();
78 if (!stralloc_0(&helohost
)) outofmem();
83 remoteip
= env_get("TCPREMOTEIP");
84 if (!remoteip
) remoteip
= "unknown";
85 local
= env_get("TCPLOCALHOST");
86 if (!local
) local
= env_get("TCPLOCALIP");
87 if (!local
) local
= "unknown";
88 remotehost
= env_get("TCPREMOTEHOST");
89 if (!remotehost
) remotehost
= "unknown";
90 remoteinfo
= env_get("TCPREMOTEINFO");
91 relayclient
= env_get("RELAYCLIENT");
98 Put ,E=\\r\\n at the end of Mether, Mtcp, or Msmtp in sendmail.cf \
99 if you are using Solaris 2.5 (fixed in 2.5.1). \
100 I cannot accept messages with stray newlines. \
101 Many SMTP servers will time out waiting for \\r\\n.\\r\\n.\
106 void blast(ssfrom
,hops
)
113 int pos
; /* number of bytes since most recent \n, if fih */
114 int flagmaybex
; /* 1 if this line might match RECEIVED, if fih */
115 int flagmaybey
; /* 1 if this line might match \r\n, if fih */
116 int flagmaybez
; /* 1 if this line might match DELIVERED, if fih */
121 pos
= 0; flagmaybex
= flagmaybey
= flagmaybez
= 1;
124 if (substdio_get(ssfrom
,&ch
,1) <= 0) die();
129 if (ch
!= "delivered"[pos
]) if (ch
!= "DELIVERED"[pos
]) flagmaybez
= 0;
130 if (flagmaybez
) if (pos
== 8) ++*hops
;
132 if (ch
!= "received"[pos
]) if (ch
!= "RECEIVED"[pos
]) flagmaybex
= 0;
133 if (flagmaybex
) if (pos
== 7) ++*hops
;
134 if (pos
< 2) if (ch
!= "\r\n"[pos
]) flagmaybey
= 0;
135 if (flagmaybey
) if (pos
== 1) flaginheader
= 0;
138 if (ch
== '\n') { pos
= 0; flagmaybex
= flagmaybey
= flagmaybez
= 1; }
143 if (ch
== '\n') straynewline();
144 if (ch
== '\r') { state
= 4; continue; }
147 if (ch
== '\n') straynewline();
148 if (ch
== '.') { state
= 2; continue; }
149 if (ch
== '\r') { state
= 4; continue; }
152 case 2: /* \r\n + . */
153 if (ch
== '\n') straynewline();
154 if (ch
== '\r') { state
= 3; continue; }
157 case 3: /* \r\n + .\r */
158 if (ch
== '\n') return;
159 qmail_put(&qqt
,".\r",2);
160 if (ch
== '\r') { state
= 4; continue; }
164 if (ch
== '\n') { state
= 1; break; }
165 if (ch
!= '\r') { qmail_put(&qqt
,"\r",1); state
= 0; }
167 qmail_put(&qqt
,&ch
,1);
176 struct ip_address ip
;
180 arg
+= str_chr(arg
,'<');
181 if (*arg
!= '<') return 0;
184 /* strip source route */
185 if (*arg
== '@') while (*arg
) if (*arg
++ == ':') break;
188 if (!stralloc_copys(&addr
,"")) outofmem();
191 for (i
= 0;ch
= arg
[i
];++i
) /* copy arg to addr, stripping quotes */
194 { if (!stralloc_append(&addr
,&ch
)) outofmem(); flagesc
= 0; }
197 if (!flagquoted
&& (ch
== '>')) break;
200 case '\\': flagesc
= 1; break;
201 case '"': flagquoted
= !flagquoted
; break;
202 default: if (!stralloc_append(&addr
,&ch
)) outofmem();
207 if (!stralloc_append(&addr
,"")) outofmem();
211 if (!case_diffs(arg
+ i
," BODY=8BITMIME")) i
+= 14;
212 else if (!case_diffs(arg
+ i
," BODY=7BIT")) i
+= 10;
218 i
= byte_rchr(addr
.s
,addr
.len
,'@');
219 if (i
< addr
.len
) /* if not, partner should go read rfc 821 */
220 if (addr
.s
[i
+ 1] == '[')
221 if (!addr
.s
[i
+ 1 + ip_scanbracket(addr
.s
+ i
+ 1,&ip
)])
225 if (!stralloc_cat(&addr
,&liphost
)) outofmem();
226 if (!stralloc_0(&addr
)) outofmem();
237 j
= byte_rchr(addr
.s
,addr
.len
,'@');
238 if (j
>= addr
.len
) return 1; /* can be taken care of by envnoathost */
239 if (constmap(&maprcpthosts
,addr
.s
+ j
+ 1,addr
.len
- j
- 2)) return 1;
240 for (;j
< addr
.len
;++j
)
241 if (addr
.s
[j
] == '.')
242 if (constmap(&maprcpthosts
,addr
.s
+ j
,addr
.len
- j
- 1)) return 1;
251 if (constmap(&mapbmf
,addr
.s
,addr
.len
- 1)) { flagbarf
= 1; return; }
252 j
= byte_rchr(addr
.s
,addr
.len
,'@');
254 if (constmap(&mapbmf
,addr
.s
+ j
,addr
.len
- j
- 1)) flagbarf
= 1;
257 void smtp_greet(code
) char *code
; {
258 if (substdio_puts(&ssout
,code
) == -1) die();
259 if (substdio_put(&ssout
,greeting
.s
,greeting
.len
) == -1) die(); }
260 void smtp_quit() { smtp_greet("221 "); out("\r\n"); die(); }
261 void smtp_help() { out("214-qmail home page: http://pobox.com/~djb/qmail.html\r\n214 send comments to qmail@pobox.com\r\n"); }
262 void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
263 void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
264 void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
265 void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
266 void err_seenmail() { out("503 one MAIL per message (#5.5.1)\r\n"); }
267 void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
268 void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
269 void err_noop() { out("250 ok\r\n"); }
270 void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
271 void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
272 void smtp_helo(arg
) char *arg
; {
273 smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
275 dohelo(arg ? arg
: ""); }
278 out("250 flushed\r\n"); }
279 void smtp_mail(arg
) char *arg
; {
280 if (seenmail
) { err_seenmail(); return; }
281 if (!arg
) { err_syntax(); return; }
282 if (!addrparse(arg
)) { err_syntax(); return; }
284 seenmail
= 1; out("250 ok\r\n");
285 if (!stralloc_copys(&rcptto
,"")) outofmem();
286 if (!stralloc_copys(&mailfrom
,addr
.s
)) outofmem();
287 if (!stralloc_0(&mailfrom
)) outofmem(); }
288 void smtp_rcpt(arg
) char *arg
; {
289 if (!seenmail
) { err_wantmail(); return; }
290 if (!arg
) { err_syntax(); return; }
291 if (!addrparse(arg
)) { err_syntax(); return; }
292 if (flagbarf
) { err_bmf(); return; }
296 if (!stralloc_cats(&addr
,relayclient
)) outofmem();
297 if (!stralloc_0(&addr
)) outofmem();
300 if (!addrallowed()) { err_nogateway(); return; }
302 if (!stralloc_cats(&rcptto
,"T")) outofmem();
303 if (!stralloc_cats(&rcptto
,addr
.s
)) outofmem();
304 if (!stralloc_0(&rcptto
)) outofmem(); }
306 char accept_buf
[FMT_ULONG
];
307 void acceptmessage(qp
) unsigned long qp
;
312 accept_buf
[fmt_ulong(accept_buf
,(unsigned long) when
)] = 0;
315 accept_buf
[fmt_ulong(accept_buf
,qp
)] = 0;
321 int hops
; int r
; unsigned long qp
;
322 if (!seenmail
) { err_wantmail(); return; }
323 if (!rcptto
.len
) { err_wantrcpt(); return; }
325 if (qmail_open(&qqt
) == -1) { err_qqt(); return; }
327 out("354 go ahead\r\n");
329 received(&qqt
,"SMTP",local
,remoteip
,remotehost
,remoteinfo
,case_diffs(remotehost
,helohost
.s
) ? helohost
.s
: 0);
331 hops
= (hops
>= MAXHOPS
);
332 if (hops
) qmail_fail(&qqt
);
333 qmail_from(&qqt
,mailfrom
.s
);
334 qmail_put(&qqt
,rcptto
.s
,rcptto
.len
);
336 r
= qmail_close(&qqt
);
337 if (!r
) { acceptmessage(qp
); return; }
338 if (hops
) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
341 case QMAIL_TOOLONG
: out("554 address too long (#5.1.3)\r\n"); return;
342 case QMAIL_SYS
: out("451 qq system error (#4.3.0)\r\n"); return;
343 case QMAIL_READ
: out("451 qq read error (#4.3.0)\r\n"); return;
344 case QMAIL_WRITE
: out("451 qq write error or disk full (#4.3.0)\r\n"); return;
345 case QMAIL_NOMEM
: out("451 qq out of memory (#4.3.0)\r\n"); return;
346 case QMAIL_EXECSOFT
: out("451 could not exec qq (#4.3.0)\r\n"); return;
347 case QMAIL_TIMEOUT
: out("451 qq timeout (#4.3.0)\r\n"); return;
348 case QMAIL_WAITPID
: out("451 qq waitpid surprise (#4.3.0)\r\n"); return;
349 case QMAIL_CRASHED
: out("451 qq crashed (#4.3.0)\r\n"); return;
350 case QMAIL_USAGE
: out("451 qq usage surprise (#4.3.0)\r\n"); return;
351 default: out("451 qq internal bug (#4.3.0)\r\n"); return;
355 static struct { void (*fun
)(); char *text
; int flagflush
; } smtpcmd
[] = {
356 { smtp_rcpt
, "rcpt", 0 }
357 , { smtp_mail
, "mail", 0 }
358 , { smtp_data
, "data", 1 }
359 , { smtp_quit
, "quit", 1 }
360 , { smtp_helo
, "helo", 1 }
361 , { smtp_helo
, "ehlo", 1 }
362 , { smtp_rset
, "rset", 0 }
363 , { smtp_help
, "help", 1 }
364 , { err_noop
, "noop", 1 }
365 , { err_vrfy
, "vrfy", 1 }
376 for (i
= 0;smtpcmd
[i
].fun
;++i
)
378 for (j
= 0;ch
= smtpcmd
[i
].text
[j
];++j
)
379 if ((cmd
[j
] != ch
) && (cmd
[j
] != ch
- 32))
382 if (!cmd
[j
] || (cmd
[j
] == ' '))
384 while (cmd
[j
] == ' ') ++j
;
386 smtpcmd
[i
].fun((char *) 0);
388 smtpcmd
[i
].fun(cmd
+ j
);
389 if (smtpcmd
[i
].flagflush
) flush();
399 if (control_init() == -1) die();
400 if (control_rldef(&greeting
,"control/smtpgreeting",1,(char *) 0) != 1) die();
401 switch(control_rldef(&liphost
,"control/localiphost",1,(char *) 0))
402 { case -1: die(); case 1: liphostok
= 1; }
403 if (control_readint(&timeout
,"control/timeoutsmtpd") == -1) die();
404 if (timeout
<= 0) timeout
= 1;
405 switch(control_readfile(&rcpthosts
,"control/rcpthosts",0))
410 if (!constmap_init(&maprcpthosts
,rcpthosts
.s
,rcpthosts
.len
,0)) die();
412 switch(control_readfile(&bmf
,"control/badmailfrom",0))
417 if (!constmap_init(&mapbmf
,bmf
.s
,bmf
.len
,0)) die();
423 static stralloc cmd
= {0};
426 sig_alarmcatch(sigalrm
);
429 if (chdir(auto_qmail
) == -1) die();
433 if (ipme_init() != 1) die();
440 /* XXX: recipient can contain quoted lf. aargh. */
441 if (getln(&ssin
,&cmd
,&match
,'\n') == -1) die();
443 if (cmd
.len
== 0) die();
444 if (cmd
.s
[--cmd
.len
] != '\n') die();
445 if ((cmd
.len
> 0) && (cmd
.s
[cmd
.len
- 1] == '\r')) --cmd
.len
;
446 cmd
.s
[cmd
.len
++] = 0;