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