|
|
1.1 root 1: /* smail.c - MH interface to SendMail/SMTP */
2:
3: /* LINTLIBRARY */
4:
5: /* This module implements an interface to SendMail very similar to the
6: MMDF mm_(3) routines. The sm_() routines herein talk SMTP to a
7: sendmail process, mapping SMTP reply codes into RP_-style codes.
8: */
9:
10: #ifdef BSD42
11: /* Under 4.2BSD, the alarm handing stuff for time-outs will NOT work due to
12: the way syscalls get restarted. This really is not crucial, since we
13: expect SendMail to be well-behaved and not hang on us. The only time
14: I've ever seen Sendmail hang was with a bogus configuration file...
15: */
16: #endif BSD42
17:
18: #ifndef BSD42
19: #undef SMTP
20: #endif not BSD42
21: #ifdef SMTP
22: #undef SENDMAIL
23: #endif SMTP
24:
25:
26: #include "../h/strings.h"
27: #include <stdio.h>
28: #include "smail.h"
29: #include "../zotnet/mts.h"
30: #include <ctype.h>
31: #include <signal.h>
32:
33: #define NOTOK (-1)
34: #define OK 0
35: #define DONE 1
36:
37: #define TRUE 1
38: #define FALSE 0
39:
40: #define NBITS ((sizeof (int)) * 8)
41:
42: #define min(a,b) ((a) < (b) ? (a) : (b))
43:
44:
45: #define SM_OPEN 30
46: #define SM_HELO 20
47: #define SM_RSET 15
48: #define SM_MAIL 40
49: #define SM_RCPT 120
50: #define SM_DATA 20
51: #define SM_TEXT 120
52: #define SM_DOT 120
53: #define SM_QUIT 20
54: #define SM_CLOS 10
55:
56: /* */
57:
58: int alrmser ();
59:
60: static int sm_addrs = 0;
61: static int sm_alarmed = 0;
62: #ifndef SMTP
63: static int sm_child = NOTOK;
64: #endif not SMTP
65: static int sm_debug = 0;
66: static int sm_nl = TRUE;
67: static int sm_verbose = 0;
68:
69: static FILE * sm_rfp = NULL;
70: static FILE * sm_wfp = NULL;
71:
72: static char *sm_noreply = "No reply text given";
73: static char *sm_moreply = "; ";
74:
75: struct smtp sm_reply; /* global... */
76:
77:
78: char *r1bindex ();
79:
80: /* */
81:
82: #ifndef SMTP
83:
84: /* ARGSUSED */
85:
86: int sm_init (client, server, watch, verbose, debug)
87: register char *client;
88: char *server;
89: register int watch,
90: verbose,
91: debug;
92: {
93: register int i,
94: result,
95: vecp;
96: int pdi[2],
97: pdo[2];
98: char *vec[15];
99:
100: if (watch)
101: verbose = TRUE;
102: sm_verbose = verbose;
103: sm_debug = debug;
104: if (sm_rfp != NULL && sm_wfp != NULL)
105: return RP_OK;
106:
107: if (pipe (pdi) == NOTOK)
108: return sm_ierror ("no pipes");
109: if (pipe (pdo) == NOTOK) {
110: (void) close (pdi[0]);
111: (void) close (pdi[1]);
112: return sm_ierror ("no pipes");
113: }
114:
115: for (i = 0; (sm_child = fork ()) == NOTOK && i < 5; i++)
116: sleep (5);
117: switch (sm_child) {
118: case NOTOK:
119: (void) close (pdo[0]);
120: (void) close (pdo[1]);
121: (void) close (pdi[0]);
122: (void) close (pdi[1]);
123: return sm_ierror ("unable to fork");
124:
125: case OK:
126: if (pdo[0] != fileno (stdin))
127: (void) dup2 (pdo[0], fileno (stdin));
128: if (pdi[1] != fileno (stdout))
129: (void) dup2 (pdi[1], fileno (stdout));
130: if (pdi[1] != fileno (stderr))
131: (void) dup2 (pdi[1], fileno (stderr));
132: for (i = fileno (stderr) + 1; i < NBITS; i++)
133: (void) close (i);
134:
135: vecp = 0;
136: vec[vecp++] = r1bindex (sendmail, '/');
137: vec[vecp++] = "-bs";
138: vec[vecp++] = watch ? "-odi" : "-odb";
139: vec[vecp++] = "-oem";
140: vec[vecp++] = "-om";
141: #ifndef RAND
142: if (verbose)
143: vec[vecp++] = "-ov";
144: #endif not RAND
145: vec[vecp++] = NULL;
146:
147: (void) setgid (getegid ());
148: (void) setuid (geteuid ());
149: execvp (sendmail, vec);
150: fprintf (stderr, "unable to exec ");
151: perror (sendmail);
152: _exit (-1); /* NOTREACHED */
153:
154: default:
155: (void) signal (SIGALRM, alrmser);
156: (void) signal (SIGPIPE, SIG_IGN);
157:
158: (void) close (pdi[1]);
159: (void) close (pdo[0]);
160: if ((sm_rfp = fdopen (pdi[0], "r")) == NULL
161: || (sm_wfp = fdopen (pdo[1], "w")) == NULL) {
162: (void) close (pdi[0]);
163: (void) close (pdo[1]);
164: sm_rfp = sm_wfp = NULL;
165: return sm_ierror ("unable to fdopen");
166: }
167: sm_alarmed = 0;
168: (void) alarm (SM_OPEN);
169: result = smhear ();
170: (void) alarm (0);
171: switch (result) {
172: case 220:
173: break;
174:
175: default:
176: (void) sm_end (NOTOK);
177: return RP_RPLY;
178: }
179: if (client)
180: switch (smtalk (SM_HELO, "HELO %s", client)) {
181: case 250:
182: break;
183:
184: default:
185: (void) sm_end (NOTOK);
186: return RP_RPLY;
187: }
188: return RP_OK;
189: }
190: }
191: #else SMTP
192:
193: /* */
194:
195: int sm_init (client, server, watch, verbose, debug)
196: register char *client,
197: *server;
198: register int watch,
199: verbose,
200: debug;
201: {
202: register int result,
203: sd1,
204: sd2;
205:
206: if (watch)
207: verbose = TRUE;
208: sm_verbose = verbose;
209: sm_debug = debug;
210: if (sm_rfp != NULL && sm_wfp != NULL)
211: return RP_OK;
212: #ifndef SENDMTS
213: if (client == NULL || *client == NULL)
214: client = LocalName ();
215: #endif not SENDMTS
216:
217: if ((sd1 = rclient (server, "tcp", "smtp")) == NOTOK)
218: return RP_BHST;
219: if ((sd2 = dup (sd1)) == NOTOK) {
220: (void) close (sd1);
221: return sm_ierror ("unable to dup");
222: }
223:
224: (void) signal (SIGALRM, alrmser);
225: (void) signal (SIGPIPE, SIG_IGN);
226:
227: if ((sm_rfp = fdopen (sd1, "r")) == NULL
228: || (sm_wfp = fdopen (sd2, "w")) == NULL) {
229: (void) close (sd1);
230: (void) close (sd2);
231: sm_rfp = sm_wfp = NULL;
232: return sm_ierror ("unable to fdopen");
233: }
234: sm_alarmed = 0;
235: (void) alarm (SM_OPEN);
236: result = smhear ();
237: (void) alarm (0);
238: switch (result) {
239: case 220:
240: break;
241:
242: default:
243: (void) sm_end (NOTOK);
244: return RP_RPLY;
245: }
246: if (client && *client)
247: switch (smtalk (SM_HELO, "HELO %s", client)) {
248: case 250:
249: break;
250:
251: default:
252: (void) sm_end (NOTOK);
253: return RP_RPLY;
254: }
255:
256: return RP_OK;
257: }
258:
259:
260: static int rclient (server, protocol, service)
261: char *server,
262: *protocol,
263: *service;
264: {
265: int sd;
266: char response[BUFSIZ];
267:
268: if ((sd = client (server, protocol, service, FALSE, response)) != NOTOK)
269: return sd;
270:
271: (void) sm_ierror ("%s", response);
272: return NOTOK;
273: }
274: #endif SMTP
275:
276: /* */
277:
278: int sm_winit (mode, from)
279: register int mode;
280: register char *from;
281: {
282: switch (smtalk (SM_MAIL, "%s FROM:<%s>",
283: mode == S_SEND ? "SEND" : mode == S_SOML ? "SOML"
284: : mode == S_SAML ? "SAML" : "MAIL", from)) {
285: case 250:
286: sm_addrs = 0;
287: return RP_OK;
288:
289: case 500:
290: case 501:
291: case 552:
292: return RP_PARM;
293:
294: default:
295: return RP_RPLY;
296: }
297: }
298:
299: /* */
300:
301: #ifdef BERK
302: /* ARGUSED */
303: #endif BERK
304:
305: int sm_wadr (mbox, host, path)
306: register char *mbox;
307: #ifndef BERK
308: register
309: #endif not BERK
310: char *host,
311: *path;
312: {
313: #ifndef BERK
314: switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@%s>"
315: : "RCPT TO:<%s%s>",
316: path ? path : "", mbox, host)) {
317: #else BERK
318: switch (smtalk (SM_RCPT, "RCPT TO:%s", mbox)) {
319: #endif BERK
320: case 250:
321: case 251:
322: sm_addrs++;
323: return RP_OK;
324:
325: case 421:
326: case 450:
327: case 451:
328: case 452:
329: return RP_NO;
330:
331: case 500:
332: case 501:
333: return RP_PARM;
334:
335: case 550:
336: case 551:
337: case 552:
338: case 553:
339: return RP_USER;
340:
341: default:
342: return RP_RPLY;
343: }
344: }
345:
346: /* */
347:
348: int sm_waend () {
349: switch (smtalk (SM_DATA, "DATA")) {
350: case 354:
351: sm_nl = TRUE;
352: return RP_OK;
353:
354: case 421:
355: case 451:
356: return RP_NO;
357:
358: case 500:
359: case 501:
360: case 503:
361: case 554:
362: return RP_NDEL;
363:
364: default:
365: return RP_RPLY;
366: }
367: }
368:
369: /* */
370:
371: int sm_wtxt (buffer, len)
372: register char *buffer;
373: register int len;
374: {
375: register int result;
376:
377: sm_alarmed = 0;
378: (void) alarm (SM_TEXT);
379: result = sm_wstream (buffer, len);
380: (void) alarm (0);
381:
382: return (result == NOTOK ? RP_BHST : RP_OK);
383: }
384:
385: /* */
386:
387: int sm_wtend () {
388: if (sm_wstream ((char *) NULL, 0) == NOTOK)
389: return RP_BHST;
390:
391: switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) {
392: case 250:
393: case 251:
394: return RP_OK;
395:
396: case 451:
397: case 452:
398: default:
399: return RP_NO;
400:
401: case 552:
402: case 554:
403: return RP_NDEL;
404: }
405: }
406:
407: /* */
408:
409: int sm_end (type)
410: register int type;
411: {
412: register int status;
413: struct smtp sm_note;
414:
415: #ifndef SMTP
416: switch (sm_child) {
417: case NOTOK:
418: case OK:
419: return RP_OK;
420:
421: default:
422: break;
423: }
424: #endif not SMTP
425: if (sm_rfp == NULL && sm_wfp == NULL)
426: return RP_OK;
427:
428: switch (type) {
429: case OK:
430: (void) smtalk (SM_QUIT, "QUIT");
431: break;
432:
433: case NOTOK:
434: sm_note.code = sm_reply.code;
435: (void) strncpy (sm_note.text, sm_reply.text,
436: sm_note.length = sm_reply.length);/* fall */
437: case DONE:
438: if (smtalk (SM_RSET, "RSET") == 250 && type == DONE)
439: return RP_OK;
440: #ifndef SMTP
441: (void) kill (sm_child, SIGKILL);
442: discard (sm_rfp);
443: discard (sm_wfp);
444: #else SMTP
445: (void) smtalk (SM_QUIT, "QUIT");
446: #endif not SMTP
447: if (type == NOTOK) {
448: sm_reply.code = sm_note.code;
449: (void) strncpy (sm_reply.text, sm_note.text,
450: sm_reply.length = sm_note.length);
451: }
452: break;
453: }
454: if (sm_rfp != NULL) {
455: (void) alarm (SM_CLOS);
456: (void) fclose (sm_rfp);
457: (void) alarm (0);
458: }
459: if (sm_wfp != NULL) {
460: (void) alarm (SM_CLOS);
461: (void) fclose (sm_wfp);
462: (void) alarm (0);
463: }
464:
465: #ifndef SMTP
466: status = pidwait (sm_child);
467:
468: sm_child = NOTOK;
469: #else SMTP
470: status = 0;
471: #endif SMTP
472: sm_rfp = sm_wfp = NULL;
473:
474: return (status ? RP_BHST : RP_OK);
475: }
476:
477: /* */
478:
479: /* VARARGS */
480:
481: static int sm_ierror (fmt, a, b, c, d)
482: char *fmt,
483: *a,
484: *b,
485: *c,
486: *d;
487: {
488: (void) sprintf (sm_reply.text, fmt, a, b, c, d);
489: sm_reply.length = strlen (sm_reply.text);
490: sm_reply.code = NOTOK;
491:
492: return RP_BHST;
493: }
494:
495: /* */
496:
497: /* VARARGS2 */
498:
499: static int smtalk (time, fmt, a, b, c, d)
500: register int time;
501: register char *fmt;
502: {
503: register int result;
504: char buffer[BUFSIZ];
505:
506: (void) sprintf (buffer, fmt, a, b, c, d);
507: if (sm_debug) {
508: printf ("=> %s\n", buffer);
509: (void) fflush (stdout);
510: }
511:
512: sm_alarmed = 0;
513: (void) alarm ((unsigned) time);
514: if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
515: result = smhear ();
516: (void) alarm (0);
517:
518: return result;
519: }
520:
521: /* */
522:
523: static int sm_wrecord (buffer, len)
524: register char *buffer;
525: register int len;
526: {
527: if (sm_wfp == NULL)
528: return sm_werror ();
529:
530: (void) fwrite (buffer, sizeof *buffer, len, sm_wfp);
531: fputs ("\r\n", sm_wfp);
532: (void) fflush (sm_wfp);
533:
534: return (ferror (sm_wfp) ? sm_werror () : OK);
535: }
536:
537: /* */
538:
539: static int sm_wstream (buffer, len)
540: register char *buffer;
541: register int len;
542: {
543: register char *bp;
544: static char lc = NULL;
545:
546: if (sm_wfp == NULL)
547: return sm_werror ();
548:
549: if (buffer == NULL && len == 0) {
550: if (lc != '\n')
551: fputs ("\r\n", sm_wfp);
552: lc = NULL;
553: return (ferror (sm_wfp) ? sm_werror () : OK);
554: }
555:
556: for (bp = buffer; len > 0; bp++, len--) {
557: switch (*bp) {
558: case '\n':
559: sm_nl = TRUE;
560: (void) fputc ('\r', sm_wfp);
561: break;
562:
563: case '.':
564: if (sm_nl)
565: (void) fputc ('.', sm_wfp);/* FALL THROUGH */
566: default:
567: sm_nl = FALSE;
568: }
569: (void) fputc (*bp, sm_wfp);
570: if (ferror (sm_wfp))
571: return sm_werror ();
572: }
573:
574: if (bp > buffer)
575: lc = *--bp;
576: return (ferror (sm_wfp) ? sm_werror () : OK);
577: }
578:
579: /* */
580:
581: static int sm_werror () {
582: sm_reply.length =
583: #ifdef SMTP
584: strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
585: : sm_alarmed ? "write to socket timed out"
586: : "error writing to socket"));
587: #else not SMTP
588: strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no pipe opened"
589: : sm_alarmed ? "write to pipe timed out"
590: : "error writing to pipe"));
591: #endif not SMTP
592:
593: return (sm_reply.code = NOTOK);
594: }
595:
596: /* */
597:
598: static int smhear () {
599: register int i,
600: code,
601: cont,
602: rc,
603: more;
604: int bc;
605: register char *bp,
606: *rp;
607: char buffer[BUFSIZ];
608:
609: again: ;
610:
611: sm_reply.text[sm_reply.length = 0] = NULL;
612:
613: rp = sm_reply.text, rc = sizeof sm_reply.text - 1;
614: for (more = FALSE; sm_rrecord (bp = buffer, &bc) != NOTOK;) {
615: if (sm_debug) {
616: printf ("<= %s\n", buffer);
617: (void) fflush (stdout);
618: }
619:
620: for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--)
621: continue;
622:
623: cont = FALSE;
624: code = atoi (bp);
625: bp += 3, bc -= 3;
626: for (; bc > 0 && isspace (*bp); bp++, bc--)
627: continue;
628: if (bc > 0 && *bp == '-') {
629: cont = TRUE;
630: bp++, bc--;
631: for (; bc > 0 && isspace (*bp); bp++, bc--)
632: continue;
633: }
634:
635: if (more) {
636: if (code != sm_reply.code || cont)
637: continue;
638: more = FALSE;
639: }
640: else {
641: sm_reply.code = code;
642: more = cont;
643: if (bc <= 0) {
644: (void) strcpy (bp = buffer, sm_noreply);
645: bc = strlen (sm_noreply);
646: }
647: }
648: if ((i = min (bc, rc)) > 0) {
649: (void) strncpy (rp, bp, i);
650: rp += i, rc -= i;
651: if (more && rc > strlen (sm_moreply) + 1) {
652: (void) strcpy (sm_reply.text + rc, sm_moreply);
653: rc += strlen (sm_moreply);
654: }
655: }
656: if (more)
657: continue;
658: if (sm_reply.code < 100) {
659: if (sm_verbose) {
660: printf ("%s\n", sm_reply.text);
661: (void) fflush (stdout);
662: }
663: goto again;
664: }
665:
666: sm_reply.length = rp - sm_reply.text;
667: return sm_reply.code;
668: }
669:
670: return NOTOK;
671: }
672:
673: /* */
674:
675: static int sm_rrecord (buffer, len)
676: register char *buffer;
677: register int *len;
678: {
679: if (sm_rfp == NULL)
680: return sm_rerror ();
681:
682: buffer[*len = 0] = NULL;
683:
684: (void) fgets (buffer, BUFSIZ, sm_rfp);
685: *len = strlen (buffer);
686: if (ferror (sm_rfp) || feof (sm_rfp))
687: return sm_rerror ();
688: if (buffer[*len - 1] != '\n')
689: while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp))
690: continue;
691: else
692: if (buffer[*len - 2] == '\r')
693: *len -= 1;
694: buffer[*len - 1] = NULL;
695:
696: return OK;
697: }
698:
699: /* */
700:
701: static int sm_rerror () {
702: sm_reply.length =
703: #ifdef SMTP
704: strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
705: : sm_alarmed ? "read from socket timed out"
706: : feof (sm_rfp) ? "premature end-of-file on socket"
707: : "error reading from socket"));
708: #else not SMTP
709: strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
710: : sm_alarmed ? "read from pipe timed out"
711: : feof (sm_rfp) ? "premature end-of-file on pipe"
712: : "error reading from pipe"));
713: #endif not SMTP
714:
715: return (sm_reply.code = NOTOK);
716: }
717:
718: /* */
719:
720: /* ARGSUSED */
721:
722: static int alrmser (i)
723: int i;
724: {
725: #ifndef BSD42
726: signal (SIGALRM, alrmser);
727: #endif BSD42
728: sm_alarmed++;
729:
730: if (sm_debug) {
731: printf ("timed out...\n");
732: (void) fflush (stdout);
733: }
734: }
735:
736: /* */
737:
738: char *rp_string (code)
739: register int code;
740: {
741: register char *text;
742: static char buffer[BUFSIZ];
743:
744: switch (sm_reply.code != NOTOK ? code : NOTOK) {
745: case RP_AOK:
746: text = "AOK";
747: break;
748:
749: case RP_MOK:
750: text = "MOK";
751: break;
752:
753: case RP_OK:
754: text = "OK";
755: break;
756:
757: case RP_RPLY:
758: text = "RPLY";
759: break;
760:
761: case RP_BHST:
762: default:
763: text = "BHST";
764: (void) sprintf (buffer, "[%s] %s", text, sm_reply.text);
765: return buffer;
766:
767: case RP_PARM:
768: text = "PARM";
769: break;
770:
771: case RP_NO:
772: text = "NO";
773: break;
774:
775: case RP_USER:
776: text = "USER";
777: break;
778:
779: case RP_NDEL:
780: text = "NDEL";
781: break;
782: }
783:
784: (void) sprintf (buffer, "[%s] %3d %s", text, sm_reply.code, sm_reply.text);
785: return buffer;
786: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.