]> diplodocus.org Git - nmh/blob - mts/smtp/smtp.c
fix for bug #578 repl leaks umask; there are several other
[nmh] / mts / smtp / smtp.c
1 /*
2 * smtp.c -- nmh SMTP interface
3 *
4 * $Id$
5 *
6 * This code is Copyright (c) 2002, by the authors of nmh. See the
7 * COPYRIGHT file in the root directory of the nmh distribution for
8 * complete copyright information.
9 */
10
11 #include <h/mh.h>
12 #include "smtp.h"
13 #include <h/mts.h>
14 #include <signal.h>
15 #include <h/signals.h>
16 #ifdef MPOP
17 #include <errno.h>
18 #endif
19
20 #ifdef CYRUS_SASL
21 #include <sasl.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26 #include <errno.h>
27 #endif /* CYRUS_SASL */
28
29 /*
30 * This module implements an interface to SendMail very similar
31 * to the MMDF mm_(3) routines. The sm_() routines herein talk
32 * SMTP to a sendmail process, mapping SMTP reply codes into
33 * RP_-style codes.
34 */
35
36 /*
37 * On older 4.2BSD machines without the POSIX function `sigaction',
38 * the alarm handing stuff for time-outs will NOT work due to the way
39 * syscalls get restarted. This is not really crucial, since SendMail
40 * is generally well-behaved in this area.
41 */
42
43 #ifdef SENDMAILBUG
44 /*
45 * It appears that some versions of Sendmail will return Code 451
46 * when they don't really want to indicate a failure.
47 * "Code 451 almost always means sendmail has deferred; we don't
48 * really want bomb out at this point since sendmail will rectify
49 * things later." So, if you define SENDMAILBUG, Code 451 is
50 * considered the same as Code 250. Yuck!
51 */
52 #endif
53
54 #define TRUE 1
55 #define FALSE 0
56
57 #define NBITS ((sizeof (int)) * 8)
58
59 /*
60 * these codes must all be different!
61 */
62 #define SM_OPEN 90 /* Changed from 30 in case of nameserver flakiness */
63 #define SM_HELO 20
64 #define SM_RSET 15
65 #define SM_MAIL 40
66 #define SM_RCPT 120
67 #define SM_DATA 20
68 #define SM_TEXT 150
69 #define SM_DOT 180
70 #define SM_QUIT 30
71 #define SM_CLOS 10
72 #define SM_AUTH 45
73
74 static int sm_addrs = 0;
75 static int sm_alarmed = 0;
76 static int sm_child = NOTOK;
77 static int sm_debug = 0;
78 static int sm_nl = TRUE;
79 static int sm_verbose = 0;
80
81 static FILE *sm_rfp = NULL;
82 static FILE *sm_wfp = NULL;
83
84 #ifdef MPOP
85 static int sm_ispool = 0;
86 static char sm_tmpfil[BUFSIZ];
87 #endif /* MPOP */
88
89 #ifdef CYRUS_SASL
90 /*
91 * Some globals needed by SASL
92 */
93
94 static sasl_conn_t *conn = NULL; /* SASL connection state */
95 static int sasl_complete = 0; /* Has authentication succeded? */
96 static sasl_ssf_t sasl_ssf; /* Our security strength factor */
97 static char *sasl_pw_context[2]; /* Context to pass into sm_get_pass */
98 static int maxoutbuf; /* Maximum crypto output buffer */
99 static int sm_get_user(void *, int, const char **, unsigned *);
100 static int sm_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **);
101
102 static sasl_callback_t callbacks[] = {
103 { SASL_CB_USER, sm_get_user, NULL },
104 #define SM_SASL_N_CB_USER 0
105 { SASL_CB_PASS, sm_get_pass, NULL },
106 #define SM_SASL_N_CB_PASS 1
107 { SASL_CB_LIST_END, NULL, NULL },
108 };
109 #endif /* CYRUS_SASL */
110
111 static char *sm_noreply = "No reply text given";
112 static char *sm_moreply = "; ";
113
114 struct smtp sm_reply; /* global... */
115
116 #define MAXEHLO 20
117
118 static int doingEHLO;
119 char *EHLOkeys[MAXEHLO + 1];
120
121 /*
122 * static prototypes
123 */
124 static int smtp_init (char *, char *, int, int, int, int, int, int,
125 char *, char *);
126 static int sendmail_init (char *, char *, int, int, int, int, int);
127
128 static int rclient (char *, char *, char *);
129 static int sm_ierror (char *fmt, ...);
130 static int smtalk (int time, char *fmt, ...);
131 static int sm_wrecord (char *, int);
132 static int sm_wstream (char *, int);
133 static int sm_werror (void);
134 static int smhear (void);
135 static int sm_rrecord (char *, int *);
136 static int sm_rerror (void);
137 static RETSIGTYPE alrmser (int);
138 static char *EHLOset (char *);
139
140 #ifdef MPOP
141 /*
142 * smtp.c's own static copy of several nmh library subroutines
143 */
144 static char **smail_brkstring (char *, char *, char *);
145 static int smail_brkany (char, char *);
146 char **smail_copyip (char **, char **, int);
147 #endif
148
149 #ifdef CYRUS_SASL
150 /*
151 * Function prototypes needed for SASL
152 */
153
154 static int sm_auth_sasl(char *, char *, char *);
155 #endif /* CYRUS_SASL */
156
157 /* from mts/generic/client.c */
158 int client (char *, char *, char *, int, char *, int);
159
160 int
161 sm_init (char *client, char *server, int watch, int verbose,
162 int debug, int onex, int queued, int sasl, char *saslmech,
163 char *user)
164 {
165 if (sm_mts == MTS_SMTP)
166 return smtp_init (client, server, watch, verbose,
167 debug, onex, queued, sasl, saslmech, user);
168 else
169 return sendmail_init (client, server, watch, verbose,
170 debug, onex, queued);
171 }
172
173 static int
174 smtp_init (char *client, char *server, int watch, int verbose,
175 int debug, int onex, int queued, int sasl, char *saslmech,
176 char *user)
177 {
178 #ifdef CYRUS_SASL
179 char *server_mechs;
180 #endif /* CYRUS_SASL */
181 int result, sd1, sd2;
182
183 if (watch)
184 verbose = TRUE;
185
186 sm_verbose = verbose;
187 sm_debug = debug;
188
189 #ifdef MPOP
190 if (sm_ispool)
191 goto all_done;
192 #endif
193
194 if (sm_rfp != NULL && sm_wfp != NULL)
195 goto send_options;
196
197 if (client == NULL || *client == '\0') {
198 if (clientname) {
199 client = clientname;
200 } else {
201 client = LocalName(); /* no clientname -> LocalName */
202 }
203 }
204
205 #ifdef ZMAILER
206 if (client == NULL || *client == '\0')
207 client = "localhost";
208 #endif
209
210 if ((sd1 = rclient (server, "tcp", "smtp")) == NOTOK)
211 return RP_BHST;
212
213 #ifdef MPOP
214 if (sm_ispool) {
215 if (sm_rfp) {
216 alarm (SM_CLOS);
217 fclose (sm_rfp);
218 alarm (0);
219 sm_rfp = NULL;
220 }
221 if ((sm_wfp = fdopen (sd1, "w")) == NULL) {
222 unlink (sm_tmpfil);
223 close (sd1);
224 return sm_ierror ("unable to fdopen");
225 }
226 all_done: ;
227 sm_reply.text[sm_reply.length = 0] = NULL;
228 return (sm_reply.code = RP_OK);
229 }
230 #endif /* MPOP */
231
232 if ((sd2 = dup (sd1)) == NOTOK) {
233 close (sd1);
234 return sm_ierror ("unable to dup");
235 }
236
237 SIGNAL (SIGALRM, alrmser);
238 SIGNAL (SIGPIPE, SIG_IGN);
239
240 if ((sm_rfp = fdopen (sd1, "r")) == NULL
241 || (sm_wfp = fdopen (sd2, "w")) == NULL) {
242 close (sd1);
243 close (sd2);
244 sm_rfp = sm_wfp = NULL;
245 return sm_ierror ("unable to fdopen");
246 }
247
248 sm_alarmed = 0;
249 alarm (SM_OPEN);
250 result = smhear ();
251 alarm (0);
252
253 switch (result) {
254 case 220:
255 break;
256
257 default:
258 sm_end (NOTOK);
259 return RP_RPLY;
260 }
261
262 /*
263 * Give EHLO or HELO command
264 */
265 if (client && *client) {
266 doingEHLO = 1;
267 result = smtalk (SM_HELO, "EHLO %s", client);
268 doingEHLO = 0;
269
270 if (result >= 500 && result <= 599)
271 result = smtalk (SM_HELO, "HELO %s", client);
272
273 if (result != 250) {
274 sm_end (NOTOK);
275 return RP_RPLY;
276 }
277 }
278
279 #ifdef CYRUS_SASL
280 /*
281 * If the user asked for SASL, then check to see if the SMTP server
282 * supports it. Otherwise, error out (because the SMTP server
283 * might have been spoofed; we don't want to just silently not
284 * do authentication
285 */
286
287 if (sasl) {
288 if (! (server_mechs = EHLOset("AUTH"))) {
289 sm_end(NOTOK);
290 return sm_ierror("SMTP server does not support SASL");
291 }
292
293 if (saslmech && stringdex(saslmech, server_mechs) == -1) {
294 sm_end(NOTOK);
295 return sm_ierror("Requested SASL mech \"%s\" is not in the "
296 "list of supported mechanisms:\n%s",
297 saslmech, server_mechs);
298 }
299
300 if (sm_auth_sasl(user, saslmech ? saslmech : server_mechs,
301 server) != RP_OK) {
302 sm_end(NOTOK);
303 return NOTOK;
304 }
305 }
306 #endif /* CYRUS_SASL */
307
308 send_options: ;
309 if (watch && EHLOset ("XVRB"))
310 smtalk (SM_HELO, "VERB on");
311 if (onex && EHLOset ("XONE"))
312 smtalk (SM_HELO, "ONEX");
313 if (queued && EHLOset ("XQUE"))
314 smtalk (SM_HELO, "QUED");
315
316 return RP_OK;
317 }
318
319 int
320 sendmail_init (char *client, char *server, int watch, int verbose,
321 int debug, int onex, int queued)
322 {
323 int i, result, vecp;
324 int pdi[2], pdo[2];
325 char *vec[15];
326
327 if (watch)
328 verbose = TRUE;
329
330 sm_verbose = verbose;
331 sm_debug = debug;
332 if (sm_rfp != NULL && sm_wfp != NULL)
333 return RP_OK;
334
335 if (client == NULL || *client == '\0') {
336 if (clientname)
337 client = clientname;
338 else
339 client = LocalName(); /* no clientname -> LocalName */
340 }
341
342 #ifdef ZMAILER
343 if (client == NULL || *client == '\0')
344 client = "localhost";
345 #endif
346
347 if (pipe (pdi) == NOTOK)
348 return sm_ierror ("no pipes");
349 if (pipe (pdo) == NOTOK) {
350 close (pdi[0]);
351 close (pdi[1]);
352 return sm_ierror ("no pipes");
353 }
354
355 for (i = 0; (sm_child = fork ()) == NOTOK && i < 5; i++)
356 sleep (5);
357
358 switch (sm_child) {
359 case NOTOK:
360 close (pdo[0]);
361 close (pdo[1]);
362 close (pdi[0]);
363 close (pdi[1]);
364 return sm_ierror ("unable to fork");
365
366 case OK:
367 if (pdo[0] != fileno (stdin))
368 dup2 (pdo[0], fileno (stdin));
369 if (pdi[1] != fileno (stdout))
370 dup2 (pdi[1], fileno (stdout));
371 if (pdi[1] != fileno (stderr))
372 dup2 (pdi[1], fileno (stderr));
373 for (i = fileno (stderr) + 1; i < NBITS; i++)
374 close (i);
375
376 vecp = 0;
377 vec[vecp++] = r1bindex (sendmail, '/');
378 vec[vecp++] = "-bs";
379 #ifndef ZMAILER
380 vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb";
381 vec[vecp++] = "-oem";
382 vec[vecp++] = "-om";
383 # ifndef RAND
384 if (verbose)
385 vec[vecp++] = "-ov";
386 # endif /* not RAND */
387 #endif /* not ZMAILER */
388 vec[vecp++] = NULL;
389
390 setgid (getegid ());
391 setuid (geteuid ());
392 execvp (sendmail, vec);
393 fprintf (stderr, "unable to exec ");
394 perror (sendmail);
395 _exit (-1); /* NOTREACHED */
396
397 default:
398 SIGNAL (SIGALRM, alrmser);
399 SIGNAL (SIGPIPE, SIG_IGN);
400
401 close (pdi[1]);
402 close (pdo[0]);
403 if ((sm_rfp = fdopen (pdi[0], "r")) == NULL
404 || (sm_wfp = fdopen (pdo[1], "w")) == NULL) {
405 close (pdi[0]);
406 close (pdo[1]);
407 sm_rfp = sm_wfp = NULL;
408 return sm_ierror ("unable to fdopen");
409 }
410 sm_alarmed = 0;
411 alarm (SM_OPEN);
412 result = smhear ();
413 alarm (0);
414 switch (result) {
415 case 220:
416 break;
417
418 default:
419 sm_end (NOTOK);
420 return RP_RPLY;
421 }
422
423 if (client && *client) {
424 doingEHLO = 1;
425 result = smtalk (SM_HELO, "EHLO %s", client);
426 doingEHLO = 0;
427
428 if (500 <= result && result <= 599)
429 result = smtalk (SM_HELO, "HELO %s", client);
430
431 switch (result) {
432 case 250:
433 break;
434
435 default:
436 sm_end (NOTOK);
437 return RP_RPLY;
438 }
439 }
440
441 #ifndef ZMAILER
442 if (onex)
443 smtalk (SM_HELO, "ONEX");
444 #endif
445 if (watch)
446 smtalk (SM_HELO, "VERB on");
447
448 return RP_OK;
449 }
450 }
451
452 #ifdef MPOP
453 # define MAXARGS 1000
454 #endif /* MPOP */
455
456 static int
457 rclient (char *server, char *protocol, char *service)
458 {
459 int sd;
460 char response[BUFSIZ];
461 #ifdef MPOP
462 char *cp;
463 #endif /* MPOP */
464
465 if ((sd = client (server, protocol, service, FALSE, response, sizeof(response))) != NOTOK)
466 return sd;
467
468 #ifdef MPOP
469 if (!server && servers && (cp = strchr(servers, '/'))) {
470 char **ap;
471 char *arguments[MAXARGS];
472
473 smail_copyip (smail_brkstring (cp = getcpy (servers), " ", "\n"), arguments, MAXARGS);
474
475 for (ap = arguments; *ap; ap++)
476 if (**ap == '/') {
477 char *dp;
478
479 if ((dp = strrchr(*ap, '/')) && *++dp == NULL)
480 *--dp = NULL;
481 snprintf (sm_tmpfil, sizeof(sm_tmpfil), "%s/smtpXXXXXX", *ap);
482 #ifdef HAVE_MKSTEMP
483 sd = mkstemp (sm_tmpfil);
484 #else
485 mktemp (sm_tmpfil);
486
487 if ((sd = creat (sm_tmpfil, 0600)) != NOTOK) {
488 sm_ispool = 1;
489 break;
490 }
491 #endif
492 }
493
494 free (cp);
495 if (sd != NOTOK)
496 return sd;
497 }
498 #endif /* MPOP */
499
500 sm_ierror ("%s", response);
501 return NOTOK;
502 }
503
504 #ifdef CYRUS_SASL
505 #include <sasl.h>
506 #include <sys/socket.h>
507 #include <netinet/in.h>
508 #include <arpa/inet.h>
509 #include <netdb.h>
510 #include <errno.h>
511 #endif /* CYRUS_SASL */
512
513 int
514 sm_winit (int mode, char *from)
515 {
516 char *smtpcom;
517
518 #ifdef MPOP
519 if (sm_ispool && !sm_wfp) {
520 strlen (strcpy (sm_reply.text, "unable to create new spool file"));
521 sm_reply.code = NOTOK;
522 return RP_BHST;
523 }
524 #endif /* MPOP */
525
526 switch (mode) {
527 case S_MAIL:
528 smtpcom = "MAIL";
529 break;
530
531 case S_SEND:
532 smtpcom = "SEND";
533 break;
534
535 case S_SOML:
536 smtpcom = "SOML";
537 break;
538
539 case S_SAML:
540 smtpcom = "SAML";
541 break;
542 }
543
544 switch (smtalk (SM_MAIL, "%s FROM:<%s>", smtpcom, from)) {
545 case 250:
546 sm_addrs = 0;
547 return RP_OK;
548
549 case 500:
550 case 501:
551 case 552:
552 return RP_PARM;
553
554 default:
555 return RP_RPLY;
556 }
557 }
558
559
560 int
561 sm_wadr (char *mbox, char *host, char *path)
562 {
563 switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@%s>"
564 : "RCPT TO:<%s%s>",
565 path ? path : "", mbox, host)) {
566 case 250:
567 case 251:
568 sm_addrs++;
569 return RP_OK;
570
571 case 451:
572 #ifdef SENDMAILBUG
573 sm_addrs++;
574 return RP_OK;
575 #endif /* SENDMAILBUG */
576 case 421:
577 case 450:
578 case 452:
579 return RP_NO;
580
581 case 500:
582 case 501:
583 return RP_PARM;
584
585 case 550:
586 case 551:
587 case 552:
588 case 553:
589 return RP_USER;
590
591 default:
592 return RP_RPLY;
593 }
594 }
595
596
597 int
598 sm_waend (void)
599 {
600 switch (smtalk (SM_DATA, "DATA")) {
601 case 354:
602 sm_nl = TRUE;
603 return RP_OK;
604
605 case 451:
606 #ifdef SENDMAILBUG
607 sm_nl = TRUE;
608 return RP_OK;
609 #endif /* SENDMAILBUG */
610 case 421:
611 return RP_NO;
612
613 case 500:
614 case 501:
615 case 503:
616 case 554:
617 return RP_NDEL;
618
619 default:
620 return RP_RPLY;
621 }
622 }
623
624
625 int
626 sm_wtxt (char *buffer, int len)
627 {
628 int result;
629
630 sm_alarmed = 0;
631 alarm (SM_TEXT);
632 result = sm_wstream (buffer, len);
633 alarm (0);
634
635 return (result == NOTOK ? RP_BHST : RP_OK);
636 }
637
638
639 int
640 sm_wtend (void)
641 {
642 if (sm_wstream ((char *) NULL, 0) == NOTOK)
643 return RP_BHST;
644
645 switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) {
646 case 250:
647 case 251:
648 return RP_OK;
649
650 case 451:
651 #ifdef SENDMAILBUG
652 return RP_OK;
653 #endif /* SENDMAILBUG */
654 case 452:
655 default:
656 return RP_NO;
657
658 case 552:
659 case 554:
660 return RP_NDEL;
661 }
662 }
663
664
665 int
666 sm_end (int type)
667 {
668 int status;
669 struct smtp sm_note;
670
671 if (sm_mts == MTS_SENDMAIL) {
672 switch (sm_child) {
673 case NOTOK:
674 case OK:
675 return RP_OK;
676
677 default:
678 break;
679 }
680 }
681
682 if (sm_rfp == NULL && sm_wfp == NULL)
683 return RP_OK;
684
685 switch (type) {
686 case OK:
687 smtalk (SM_QUIT, "QUIT");
688 break;
689
690 case NOTOK:
691 sm_note.code = sm_reply.code;
692 strncpy (sm_note.text, sm_reply.text, sm_note.length = sm_reply.length);/* fall */
693 case DONE:
694 if (smtalk (SM_RSET, "RSET") == 250 && type == DONE)
695 return RP_OK;
696 if (sm_mts == MTS_SMTP)
697 smtalk (SM_QUIT, "QUIT");
698 else {
699 kill (sm_child, SIGKILL);
700 discard (sm_rfp);
701 discard (sm_wfp);
702 }
703 if (type == NOTOK) {
704 sm_reply.code = sm_note.code;
705 strncpy (sm_reply.text, sm_note.text, sm_reply.length = sm_note.length);
706 }
707 break;
708 }
709
710 #ifdef MPOP
711 if (sm_ispool) {
712 sm_ispool = 0;
713
714 if (sm_wfp) {
715 unlink (sm_tmpfil);
716 fclose (sm_wfp);
717 sm_wfp = NULL;
718 }
719 }
720 #endif /* MPOP */
721
722 if (sm_rfp != NULL) {
723 alarm (SM_CLOS);
724 fclose (sm_rfp);
725 alarm (0);
726 }
727 if (sm_wfp != NULL) {
728 alarm (SM_CLOS);
729 fclose (sm_wfp);
730 alarm (0);
731 }
732
733 if (sm_mts == MTS_SMTP) {
734 status = 0;
735 #ifdef CYRUS_SASL
736 if (conn)
737 sasl_dispose(&conn);
738 #endif /* CYRUS_SASL */
739 } else {
740 status = pidwait (sm_child, OK);
741 sm_child = NOTOK;
742 }
743
744 sm_rfp = sm_wfp = NULL;
745 return (status ? RP_BHST : RP_OK);
746 }
747
748
749 #ifdef MPOP
750
751 int
752 sm_bulk (char *file)
753 {
754 int cc, i, j, k, result;
755 long pos;
756 char *dp, *bp, *cp, s;
757 char buffer[BUFSIZ], sender[BUFSIZ];
758 FILE *fp, *gp;
759
760 gp = NULL;
761 k = strlen (file) - sizeof(".bulk");
762 if ((fp = fopen (file, "r")) == NULL) {
763 int len;
764
765 snprintf (sm_reply.text, sizeof(sm_reply.text),
766 "unable to read %s: ", file);
767 bp = sm_reply.text;
768 len = strlen (bp);
769 bp += len;
770 if ((s = strerror (errno)))
771 strncpy (bp, s, sizeof(sm_reply.text) - len);
772 else
773 snprintf (bp, sizeof(sm_reply.text) - len, "Error %d", errno);
774 sm_reply.length = strlen (sm_reply.text);
775 sm_reply.code = NOTOK;
776 return RP_BHST;
777 }
778 if (sm_debug) {
779 printf ("reading file %s\n", file);
780 fflush (stdout);
781 }
782
783 i = j = 0;
784 while (fgets (buffer, sizeof(buffer), fp)) {
785 if (j++ == 0)
786 strncpy (sender, buffer + sizeof("MAIL FROM:") - 1, sizeof(sender));
787 if (strcmp (buffer, "DATA\r\n") == 0) {
788 i = 1;
789 break;
790 }
791 }
792 if (i == 0) {
793 if (sm_debug) {
794 printf ("no DATA...\n");
795 fflush (stdout);
796 }
797 losing0:
798 snprintf (buffer, sizeof(buffer), "%s.bad", file);
799 rename (file, buffer);
800 if (gp) {
801 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
802 unlink (buffer);
803 fclose (gp);
804 }
805 fclose (fp);
806 return RP_OK;
807 }
808 if (j < 3) {
809 if (sm_debug) {
810 printf ("no %srecipients...\n", j < 1 ? "sender or " : "");
811 fflush (stdout);
812 }
813 goto losing0;
814 }
815
816 if ((cp = malloc ((size_t) (cc = (pos = ftell (fp)) + 1))) == NULL) {
817 sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
818 losing1: ;
819 sm_reply.code = NOTOK;
820 fclose (fp);
821 return RP_BHST;
822 }
823 fseek (fp, 0L, SEEK_SET);
824 for (dp = cp, i = 0; i++ < j; dp += strlen (dp))
825 if (fgets (dp, cc - (dp - cp), fp) == NULL) {
826 sm_reply.length = strlen (strcpy (sm_reply.text, "premature eof"));
827 losing2:
828 free (cp);
829 goto losing1;
830 }
831 *dp = NULL;
832
833 for (dp = cp, i = cc - 1; i > 0; dp += cc, i -= cc)
834 if ((cc = write (fileno (sm_wfp), dp, i)) == NOTOK) {
835 int len;
836 losing3:
837 strcpy (sm_reply.text, "error writing to server: ",
838 sizeof(sm_reply.text));
839 bp = sm_reply.text;
840 len = strlen (bp);
841 bp += len;
842 if ((s = strerror (errno)))
843 strncpy (bp, s, sizeof(sm_reply.text) - len);
844 else
845 snprintf (bp, sizeof(sm_reply.text) - len,
846 "unknown error %d", errno);
847 sm_reply.length = strlen (sm_reply.text);
848 goto losing2;
849 }
850 else
851 if (sm_debug) {
852 printf ("wrote %d octets to server\n", cc);
853 fflush (stdout);
854 }
855
856 for (dp = cp, i = 0; i++ < j; dp = strchr(dp, '\n'), dp++) {
857 if (sm_debug) {
858 if (bp = strchr(dp, '\r'))
859 *bp = NULL;
860 printf ("=> %s\n", dp);
861 fflush (stdout);
862 if (bp)
863 *bp = '\r';
864 }
865
866 switch (smhear () + (i == 1 ? 1000 : i != j ? 2000 : 3000)) {
867 case 1000 + 250:
868 sm_addrs = 0;
869 result = RP_OK;
870 break;
871
872 case 1000 + 500:
873 case 1000 + 501:
874 case 1000 + 552:
875 case 2000 + 500:
876 case 2000 + 501:
877 result = RP_PARM;
878 smtalk (SM_RSET, "RSET");
879 free (cp);
880 goto losing0;
881
882 case 2000 + 250:
883 case 2000 + 251:
884 sm_addrs++;
885 result = RP_OK;
886 break;
887
888 case 2000 + 451:
889 #ifdef SENDMAILBUG
890 sm_addrs++;
891 result = RP_OK;
892 break;
893 #endif
894 case 2000 + 421:
895 case 2000 + 450:
896 case 2000 + 452:
897 result = RP_NO;
898 goto bad_addr;
899
900 case 2000 + 550:
901 case 2000 + 551:
902 case 2000 + 552:
903 case 2000 + 553:
904 result = RP_USER;
905 bad_addr:
906 if (k <= 0 || strcmp (sender, "<>\r\n") == 0)
907 break;
908 if (gp == NULL) {
909 int l;
910 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
911 if ((gp = fopen (buffer, "w+")) == NULL)
912 goto bad_data;
913 fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
914 l = strlen (sender);
915 fprintf (gp,
916 "To: %*.*s\r\nSubject: Invalid addresses (%s)\r\n",
917 l - 4, l - 4, sender + 1, file);
918 fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
919 dtimenow (0), LocalName ());
920 }
921 if (bp = strchr(dp, '\r'))
922 *bp = NULL;
923 fprintf (gp, "=> %s\r\n", dp);
924 if (bp)
925 *bp = '\r';
926 fprintf (gp, "<= %s\r\n", rp_string (result));
927 fflush (gp);
928 break;
929
930 case 3000 + 354:
931 #ifdef SENDMAILBUG
932 ok_data:
933 #endif
934 result = RP_OK;
935 break;
936
937 case 3000 + 451:
938 #ifdef SENDMAILBUG
939 goto ok_data;
940 #endif
941 case 3000 + 421:
942 result = RP_NO;
943 bad_data:
944 smtalk (SM_RSET, "RSET");
945 free (cp);
946 if (gp) {
947 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
948 unlink (buffer);
949 fclose (gp);
950 }
951 fclose (fp);
952 return result;
953
954 case 3000 + 500:
955 case 3000 + 501:
956 case 3000 + 503:
957 case 3000 + 554:
958 smtalk (SM_RSET, "RSET");
959 free (cp);
960 goto no_dice;
961
962 default:
963 result = RP_RPLY;
964 goto bad_data;
965 }
966 }
967 free (cp);
968
969 {
970 #ifdef HAVE_ST_BLKSIZE
971 struct stat st;
972
973 if (fstat (fileno (sm_wfp), &st) == NOTOK || (cc = st.st_blksize) < BUFSIZ)
974 cc = BUFSIZ;
975 #else
976 cc = BUFSIZ;
977 #endif
978 if ((cp = malloc ((size_t) cc)) == NULL) {
979 smtalk (SM_RSET, "RSET");
980 sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
981 goto losing1;
982 }
983 }
984
985 fseek (fp, pos, SEEK_SET);
986 for (;;) {
987 int eof = 0;
988
989 for (dp = cp, i = cc; i > 0; dp += j, i -= j)
990 if ((j = fread (cp, sizeof(*cp), i, fp)) == OK) {
991 if (ferror (fp)) {
992 int len;
993
994 snprintf (sm_reply.text, sizeof(sm_reply.text),
995 "error reading %s: ", file);
996 bp = sm_reply.text;
997 len = strlen (bp);
998 bp += len;
999 if ((s = strerror (errno)))
1000 strncpy (bp, s, sizeof(sm_reply.text) - len);
1001 else
1002 snprintf (bp, sizeof(sm_reply.text) - len,
1003 "unknown error %d", errno);
1004 sm_reply.length = strlen (sm_reply.text);
1005 goto losing2;
1006 }
1007 cc = dp - cp;
1008 eof = 1;
1009 break;
1010 }
1011
1012 for (dp = cp, i = cc; i > 0; dp += j, i -= j)
1013 if ((j = write (fileno (sm_wfp), dp, i)) == NOTOK)
1014 goto losing3;
1015 else
1016 if (sm_debug) {
1017 printf ("wrote %d octets to server\n", j);
1018 fflush (stdout);
1019 }
1020
1021 if (eof)
1022 break;
1023 }
1024 free (cp);
1025
1026 switch (smhear ()) {
1027 case 250:
1028 case 251:
1029 #ifdef SENDMAILBUG
1030 ok_dot:
1031 #endif
1032 result = RP_OK;
1033 unlink (file);
1034 break;
1035
1036 case 451:
1037 #ifdef SENDMAILBUG
1038 goto ok_dot;
1039 #endif
1040 case 452:
1041 default:
1042 result = RP_NO;
1043 if (gp) {
1044 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
1045 unlink (buffer);
1046 fclose (gp);
1047 gp = NULL;
1048 }
1049 break;
1050
1051 case 552:
1052 case 554:
1053 no_dice:
1054 result = RP_NDEL;
1055 if (k <= 0 || strcmp (sender, "<>\r\n") == 0) {
1056 unlink (file);
1057 break;
1058 }
1059 if (gp) {
1060 fflush (gp);
1061 ftruncate (fileno (gp), 0L);
1062 fseek (gp, 0L, SEEK_SET);
1063 }
1064 else {
1065 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
1066 if ((gp = fopen (buffer, "w")) == NULL)
1067 break;
1068 }
1069 fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
1070 i = strlen (sender);
1071 fprintf (gp, "To: %*.*s\r\nSubject: Failed mail (%s)\r\n",
1072 i - 4, i - 4, sender + 1, file);
1073 fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
1074 dtimenow (0), LocalName ());
1075 break;
1076 }
1077
1078 if (gp) {
1079 fputs ("\r\n------- Begin Returned message\r\n\r\n", gp);
1080 fseek (fp, pos, SEEK_SET);
1081 while (fgets (buffer, sizeof(buffer), fp)) {
1082 if (buffer[0] == '-')
1083 fputs ("- ", gp);
1084 if (strcmp (buffer, ".\r\n"))
1085 fputs (buffer, gp);
1086 }
1087 fputs ("\r\n------- End Returned Message\r\n\r\n.\r\n", gp);
1088 fflush (gp);
1089 if (!ferror (gp))
1090 unlink (file);
1091 fclose (gp);
1092 }
1093 fclose (fp);
1094
1095 return result;
1096 }
1097 #endif /* MPOP */
1098
1099
1100 #ifdef CYRUS_SASL
1101 /*
1102 * This function implements SASL authentication for SMTP. If this function
1103 * completes successfully, then authentication is successful and we've
1104 * (optionally) negotiated a security layer.
1105 *
1106 * Right now we don't support session encryption.
1107 */
1108 static int
1109 sm_auth_sasl(char *user, char *mechlist, char *host)
1110 {
1111 int result, status, outlen;
1112 unsigned int buflen;
1113 char *buf, outbuf[BUFSIZ];
1114 const char *chosen_mech;
1115 sasl_security_properties_t secprops;
1116 sasl_external_properties_t extprops;
1117 sasl_ssf_t *ssf;
1118 int *outbufmax;
1119
1120 /*
1121 * Initialize the callback contexts
1122 */
1123
1124 if (user == NULL)
1125 user = getusername();
1126
1127 callbacks[SM_SASL_N_CB_USER].context = user;
1128
1129 /*
1130 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
1131 * to us on the command line, then call getpeername and do a
1132 * reverse-address lookup on the IP address to get the name.
1133 */
1134
1135 if (!host) {
1136 struct sockaddr_in sin;
1137 int len = sizeof(sin);
1138 struct hostent *hp;
1139
1140 if (getpeername(fileno(sm_wfp), (struct sockaddr *) &sin, &len) < 0) {
1141 sm_ierror("getpeername on SMTP socket failed: %s",
1142 strerror(errno));
1143 return NOTOK;
1144 }
1145
1146 if ((hp = gethostbyaddr((void *) &sin.sin_addr, sizeof(sin.sin_addr),
1147 sin.sin_family)) == NULL) {
1148 sm_ierror("DNS lookup on IP address %s failed",
1149 inet_ntoa(sin.sin_addr));
1150 return NOTOK;
1151 }
1152
1153 host = strdup(hp->h_name);
1154 }
1155
1156 sasl_pw_context[0] = host;
1157 sasl_pw_context[1] = user;
1158
1159 callbacks[SM_SASL_N_CB_PASS].context = sasl_pw_context;
1160
1161 result = sasl_client_init(callbacks);
1162
1163 if (result != SASL_OK) {
1164 sm_ierror("SASL library initialization failed: %s",
1165 sasl_errstring(result, NULL, NULL));
1166 return NOTOK;
1167 }
1168
1169 result = sasl_client_new("smtp", host, NULL, SASL_SECURITY_LAYER, &conn);
1170
1171 if (result != SASL_OK) {
1172 sm_ierror("SASL client initialization failed: %s",
1173 sasl_errstring(result, NULL, NULL));
1174 return NOTOK;
1175 }
1176
1177 /*
1178 * Initialize the security properties
1179 */
1180
1181 memset(&secprops, 0, sizeof(secprops));
1182 secprops.maxbufsize = BUFSIZ;
1183 secprops.max_ssf = 0; /* XXX change this when we do encryption */
1184 memset(&extprops, 0, sizeof(extprops));
1185
1186 result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
1187
1188 if (result != SASL_OK) {
1189 sm_ierror("SASL security property initialization failed: %s",
1190 sasl_errstring(result, NULL, NULL));
1191 return NOTOK;
1192 }
1193
1194 result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops);
1195
1196 if (result != SASL_OK) {
1197 sm_ierror("SASL external property initialization failed: %s",
1198 sasl_errstring(result, NULL, NULL));
1199 return NOTOK;
1200 }
1201
1202 /*
1203 * Start the actual protocol. Feed the mech list into the library
1204 * and get out a possible initial challenge
1205 */
1206
1207 result = sasl_client_start(conn, mechlist, NULL, NULL, &buf, &buflen,
1208 &chosen_mech);
1209
1210 if (result != SASL_OK && result != SASL_CONTINUE) {
1211 sm_ierror("SASL client start failed: %s",
1212 sasl_errstring(result, NULL, NULL));
1213 return NOTOK;
1214 }
1215
1216 /*
1217 * If we got an initial challenge, send it as part of the AUTH
1218 * command; otherwise, just send a plain AUTH command.
1219 */
1220
1221 if (buflen) {
1222 status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
1223 free(buf);
1224 if (status != SASL_OK) {
1225 sm_ierror("SASL base64 encode failed: %s",
1226 sasl_errstring(status, NULL, NULL));
1227 return NOTOK;
1228 }
1229
1230 status = smtalk(SM_AUTH, "AUTH %s %s", chosen_mech, outbuf);
1231 } else
1232 status = smtalk(SM_AUTH, "AUTH %s", chosen_mech);
1233
1234 /*
1235 * Now we loop until we either fail, get a SASL_OK, or a 235
1236 * response code. Receive the challenges and process them until
1237 * we're all done.
1238 */
1239
1240 while (result == SASL_CONTINUE) {
1241
1242 /*
1243 * If we get a 235 response, that means authentication has
1244 * succeeded and we need to break out of the loop (yes, even if
1245 * we still get SASL_CONTINUE from sasl_client_step()).
1246 *
1247 * Otherwise, if we get a message that doesn't seem to be a
1248 * valid response, then abort
1249 */
1250
1251 if (status == 235)
1252 break;
1253 else if (status < 300 || status > 399)
1254 return RP_BHST;
1255
1256 /*
1257 * Special case; a zero-length response from the SMTP server
1258 * is returned as a single =. If we get that, then set buflen
1259 * to be zero. Otherwise, just decode the response.
1260 */
1261
1262 if (strcmp("=", sm_reply.text) == 0) {
1263 outlen = 0;
1264 } else {
1265 result = sasl_decode64(sm_reply.text, sm_reply.length,
1266 outbuf, &outlen);
1267
1268 if (result != SASL_OK) {
1269 smtalk(SM_AUTH, "*");
1270 sm_ierror("SASL base64 decode failed: %s",
1271 sasl_errstring(result, NULL, NULL));
1272 return NOTOK;
1273 }
1274 }
1275
1276 result = sasl_client_step(conn, outbuf, outlen, NULL, &buf, &buflen);
1277
1278 if (result != SASL_OK && result != SASL_CONTINUE) {
1279 smtalk(SM_AUTH, "*");
1280 sm_ierror("SASL client negotiation failed: %s",
1281 sasl_errstring(result, NULL, NULL));
1282 return NOTOK;
1283 }
1284
1285 status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
1286 free(buf);
1287
1288 if (status != SASL_OK) {
1289 smtalk(SM_AUTH, "*");
1290 sm_ierror("SASL base64 encode failed: %s",
1291 sasl_errstring(status, NULL, NULL));
1292 return NOTOK;
1293 }
1294
1295 status = smtalk(SM_AUTH, outbuf);
1296 }
1297
1298 /*
1299 * Make sure that we got the correct response
1300 */
1301
1302 if (status < 200 || status > 299)
1303 return RP_BHST;
1304
1305 /*
1306 * Depending on the mechanism, we need to do a FINAL call to
1307 * sasl_client_step(). Do that now.
1308 */
1309
1310 result = sasl_client_step(conn, NULL, 0, NULL, &buf, &buflen);
1311
1312 if (result != SASL_OK) {
1313 sm_ierror("SASL final client negotiation failed: %s",
1314 sasl_errstring(result, NULL, NULL));
1315 return NOTOK;
1316 }
1317
1318 /*
1319 * We _should_ have completed the authentication successfully.
1320 * Get a few properties from the authentication exchange.
1321 */
1322
1323 result = sasl_getprop(conn, SASL_MAXOUTBUF, (void **) &outbufmax);
1324
1325 if (result != SASL_OK) {
1326 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1327 sasl_errstring(result, NULL, NULL));
1328 return NOTOK;
1329 }
1330
1331 maxoutbuf = *outbufmax;
1332
1333 result = sasl_getprop(conn, SASL_SSF, (void **) &ssf);
1334
1335 sasl_ssf = *ssf;
1336
1337 if (result != SASL_OK) {
1338 sm_ierror("Cannot retrieve SASL negotiated security strength "
1339 "factor: %s", sasl_errstring(result, NULL, NULL));
1340 return NOTOK;
1341 }
1342
1343 if (maxoutbuf == 0 || maxoutbuf > BUFSIZ)
1344 maxoutbuf = BUFSIZ;
1345
1346 sasl_complete = 1;
1347
1348 return RP_OK;
1349 }
1350
1351 /*
1352 * Our callback functions to feed data to the SASL library
1353 */
1354
1355 static int
1356 sm_get_user(void *context, int id, const char **result, unsigned *len)
1357 {
1358 char *user = (char *) context;
1359
1360 if (! result || id != SASL_CB_USER)
1361 return SASL_BADPARAM;
1362
1363 *result = user;
1364 if (len)
1365 *len = strlen(user);
1366
1367 return SASL_OK;
1368 }
1369
1370 static int
1371 sm_get_pass(sasl_conn_t *conn, void *context, int id,
1372 sasl_secret_t **psecret)
1373 {
1374 char **pw_context = (char **) context;
1375 char *pass = NULL;
1376 int len;
1377
1378 if (! psecret || id != SASL_CB_PASS)
1379 return SASL_BADPARAM;
1380
1381 ruserpass(pw_context[0], &(pw_context[1]), &pass);
1382
1383 len = strlen(pass);
1384
1385 *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
1386
1387 if (! *psecret) {
1388 free(pass);
1389 return SASL_NOMEM;
1390 }
1391
1392 (*psecret)->len = len;
1393 strcpy((*psecret)->data, pass);
1394 /* free(pass); */
1395
1396 return SASL_OK;
1397 }
1398 #endif /* CYRUS_SASL */
1399
1400 static int
1401 sm_ierror (char *fmt, ...)
1402 {
1403 va_list ap;
1404
1405 va_start(ap, fmt);
1406 vsnprintf (sm_reply.text, sizeof(sm_reply.text), fmt, ap);
1407 va_end(ap);
1408
1409 sm_reply.length = strlen (sm_reply.text);
1410 sm_reply.code = NOTOK;
1411
1412 return RP_BHST;
1413 }
1414
1415
1416 static int
1417 smtalk (int time, char *fmt, ...)
1418 {
1419 va_list ap;
1420 int result;
1421 char buffer[BUFSIZ];
1422
1423 va_start(ap, fmt);
1424 vsnprintf (buffer, sizeof(buffer), fmt, ap);
1425 va_end(ap);
1426
1427 if (sm_debug) {
1428 printf ("=> %s\n", buffer);
1429 fflush (stdout);
1430 }
1431
1432 #ifdef MPOP
1433 if (sm_ispool) {
1434 char file[BUFSIZ];
1435
1436 if (strcmp (buffer, ".") == 0)
1437 time = SM_DOT;
1438 fprintf (sm_wfp, "%s\r\n", buffer);
1439 switch (time) {
1440 case SM_DOT:
1441 fflush (sm_wfp);
1442 if (ferror (sm_wfp))
1443 return sm_werror ();
1444 snprintf (file, sizeof(file), "%s%c.bulk", sm_tmpfil,
1445 (char) (sm_ispool + 'a' - 1));
1446 if (rename (sm_tmpfil, file) == NOTOK) {
1447 int len;
1448 char *bp;
1449
1450 snprintf (sm_reply.text, sizeof(sm_reply.text),
1451 "error renaming %s to %s: ", sm_tmpfil, file);
1452 bp = sm_reply.text;
1453 len = strlen (bp);
1454 bp += len;
1455 if ((s = strerror (errno)))
1456 strncpy (bp, s, sizeof(sm_reply.text) - len);
1457 else
1458 snprintf (bp, sizeof(sm_reply.text) - len,
1459 "unknown error %d", errno);
1460 sm_reply.length = strlen (sm_reply.text);
1461 sm_reply.code = NOTOK;
1462 return RP_BHST;
1463 }
1464 fclose (sm_wfp);
1465 if (sm_wfp = fopen (sm_tmpfil, "w"))
1466 chmod (sm_tmpfil, 0600);
1467 sm_ispool++;
1468 /* and fall... */
1469
1470 case SM_MAIL:
1471 case SM_RCPT:
1472 result = 250;
1473 break;
1474
1475 case SM_RSET:
1476 fflush (sm_wfp);
1477 ftruncate (fileno (sm_wfp), 0L);
1478 fseek (sm_wfp, 0L, SEEK_SET);
1479 result = 250;
1480 break;
1481
1482 case SM_DATA:
1483 result = 354;
1484 break;
1485
1486 case SM_QUIT:
1487 unlink (sm_tmpfil);
1488 sm_ispool = 0;
1489 result = 221;
1490 break;
1491
1492 default:
1493 result = 500;
1494 break;
1495 }
1496 if (sm_debug) {
1497 printf ("<= %d\n", result);
1498 fflush (stdout);
1499 }
1500
1501 sm_reply.text[sm_reply.length = 0] = NULL;
1502 return (sm_reply.code = result);
1503 }
1504 #endif /* MPOP */
1505
1506 sm_alarmed = 0;
1507 alarm ((unsigned) time);
1508 if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
1509 result = smhear ();
1510 alarm (0);
1511
1512 return result;
1513 }
1514
1515
1516 /*
1517 * write the buffer to the open SMTP channel
1518 */
1519
1520 static int
1521 sm_wrecord (char *buffer, int len)
1522 {
1523 if (sm_wfp == NULL)
1524 return sm_werror ();
1525
1526 fwrite (buffer, sizeof(*buffer), len, sm_wfp);
1527 fputs ("\r\n", sm_wfp);
1528 fflush (sm_wfp);
1529
1530 return (ferror (sm_wfp) ? sm_werror () : OK);
1531 }
1532
1533
1534 static int
1535 sm_wstream (char *buffer, int len)
1536 {
1537 char *bp;
1538 static char lc = '\0';
1539
1540 if (sm_wfp == NULL)
1541 return sm_werror ();
1542
1543 if (buffer == NULL && len == 0) {
1544 if (lc != '\n')
1545 fputs ("\r\n", sm_wfp);
1546 lc = '\0';
1547 return (ferror (sm_wfp) ? sm_werror () : OK);
1548 }
1549
1550 for (bp = buffer; len > 0; bp++, len--) {
1551 switch (*bp) {
1552 case '\n':
1553 sm_nl = TRUE;
1554 fputc ('\r', sm_wfp);
1555 break;
1556
1557 case '.':
1558 if (sm_nl)
1559 fputc ('.', sm_wfp);/* FALL THROUGH */
1560 default:
1561 sm_nl = FALSE;
1562 }
1563 fputc (*bp, sm_wfp);
1564 if (ferror (sm_wfp))
1565 return sm_werror ();
1566 }
1567
1568 if (bp > buffer)
1569 lc = *--bp;
1570 return (ferror (sm_wfp) ? sm_werror () : OK);
1571 }
1572
1573
1574 /*
1575 * On some systems, strlen and strcpy are defined as preprocessor macros. This
1576 * causes compile problems with the #ifdef MPOP in the middle. Should the
1577 * #ifdef MPOP be removed, remove these #undefs.
1578 */
1579 #ifdef strlen
1580 # undef strlen
1581 #endif
1582 #ifdef strcpy
1583 # undef strcpy
1584 #endif
1585
1586 static int
1587 sm_werror (void)
1588 {
1589 sm_reply.length =
1590 strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
1591 : sm_alarmed ? "write to socket timed out"
1592 #ifdef MPOP
1593 : sm_ispool ? "error writing to spool file"
1594 #endif
1595 : "error writing to socket"));
1596
1597 return (sm_reply.code = NOTOK);
1598 }
1599
1600
1601 static int
1602 smhear (void)
1603 {
1604 int i, code, cont, bc, rc, more;
1605 char *bp, *rp;
1606 char **ehlo, buffer[BUFSIZ];
1607
1608 if (doingEHLO) {
1609 static int at_least_once = 0;
1610
1611 if (at_least_once) {
1612 char *ep;
1613
1614 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1615 ep = *ehlo;
1616 free (ep);
1617 }
1618 } else {
1619 at_least_once = 1;
1620 }
1621
1622 ehlo = EHLOkeys;
1623 *ehlo = NULL;
1624 }
1625
1626 again: ;
1627
1628 sm_reply.length = 0;
1629 sm_reply.text[0] = 0;
1630 rp = sm_reply.text;
1631 rc = sizeof(sm_reply.text) - 1;
1632
1633 for (more = FALSE; sm_rrecord (bp = buffer, &bc) != NOTOK;) {
1634 if (sm_debug) {
1635 printf ("<= %s\n", buffer);
1636 fflush (stdout);
1637 }
1638
1639 if (doingEHLO
1640 && strncmp (buffer, "250", sizeof("250") - 1) == 0
1641 && (buffer[3] == '-' || doingEHLO == 2)
1642 && buffer[4]) {
1643 if (doingEHLO == 2) {
1644 if ((*ehlo = malloc ((size_t) (strlen (buffer + 4) + 1)))) {
1645 strcpy (*ehlo++, buffer + 4);
1646 *ehlo = NULL;
1647 if (ehlo >= EHLOkeys + MAXEHLO)
1648 doingEHLO = 0;
1649 }
1650 else
1651 doingEHLO = 0;
1652 }
1653 else
1654 doingEHLO = 2;
1655 }
1656
1657 for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--)
1658 continue;
1659
1660 cont = FALSE;
1661 code = atoi (bp);
1662 bp += 3, bc -= 3;
1663 for (; bc > 0 && isspace (*bp); bp++, bc--)
1664 continue;
1665 if (bc > 0 && *bp == '-') {
1666 cont = TRUE;
1667 bp++, bc--;
1668 for (; bc > 0 && isspace (*bp); bp++, bc--)
1669 continue;
1670 }
1671
1672 if (more) {
1673 if (code != sm_reply.code || cont)
1674 continue;
1675 more = FALSE;
1676 } else {
1677 sm_reply.code = code;
1678 more = cont;
1679 if (bc <= 0) {
1680 strncpy (buffer, sm_noreply, sizeof(buffer));
1681 bp = buffer;
1682 bc = strlen (sm_noreply);
1683 }
1684 }
1685
1686 if ((i = min (bc, rc)) > 0) {
1687 strncpy (rp, bp, i);
1688 rp += i;
1689 rc -= i;
1690 if (more && rc > strlen (sm_moreply) + 1) {
1691 strncpy (sm_reply.text + rc, sm_moreply, sizeof(sm_reply.text) - rc);
1692 rc += strlen (sm_moreply);
1693 }
1694 }
1695 if (more)
1696 continue;
1697 if (sm_reply.code < 100) {
1698 if (sm_verbose) {
1699 printf ("%s\n", sm_reply.text);
1700 fflush (stdout);
1701 }
1702 goto again;
1703 }
1704
1705 sm_reply.length = rp - sm_reply.text;
1706 return sm_reply.code;
1707 }
1708 return NOTOK;
1709 }
1710
1711
1712 static int
1713 sm_rrecord (char *buffer, int *len)
1714 {
1715 if (sm_rfp == NULL)
1716 return sm_rerror ();
1717
1718 buffer[*len = 0] = 0;
1719
1720 fgets (buffer, BUFSIZ, sm_rfp);
1721 *len = strlen (buffer);
1722 if (ferror (sm_rfp) || feof (sm_rfp))
1723 return sm_rerror ();
1724 if (buffer[*len - 1] != '\n')
1725 while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp))
1726 continue;
1727 else
1728 if (buffer[*len - 2] == '\r')
1729 *len -= 1;
1730 buffer[*len - 1] = 0;
1731
1732 return OK;
1733 }
1734
1735
1736 static int
1737 sm_rerror (void)
1738 {
1739 if (sm_mts == MTS_SMTP)
1740 sm_reply.length =
1741 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
1742 : sm_alarmed ? "read from socket timed out"
1743 : feof (sm_rfp) ? "premature end-of-file on socket"
1744 : "error reading from socket"));
1745 else
1746 sm_reply.length =
1747 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
1748 : sm_alarmed ? "read from pipe timed out"
1749 : feof (sm_rfp) ? "premature end-of-file on pipe"
1750 : "error reading from pipe"));
1751
1752 return (sm_reply.code = NOTOK);
1753 }
1754
1755
1756 static RETSIGTYPE
1757 alrmser (int i)
1758 {
1759 #ifndef RELIABLE_SIGNALS
1760 SIGNAL (SIGALRM, alrmser);
1761 #endif
1762
1763 sm_alarmed++;
1764 if (sm_debug) {
1765 printf ("timed out...\n");
1766 fflush (stdout);
1767 }
1768 }
1769
1770
1771 char *
1772 rp_string (int code)
1773 {
1774 char *text;
1775 static char buffer[BUFSIZ];
1776
1777 switch (sm_reply.code != NOTOK ? code : NOTOK) {
1778 case RP_AOK:
1779 text = "AOK";
1780 break;
1781
1782 case RP_MOK:
1783 text = "MOK";
1784 break;
1785
1786 case RP_OK:
1787 text = "OK";
1788 break;
1789
1790 case RP_RPLY:
1791 text = "RPLY";
1792 break;
1793
1794 case RP_BHST:
1795 default:
1796 text = "BHST";
1797 snprintf (buffer, sizeof(buffer), "[%s] %s", text, sm_reply.text);
1798 return buffer;
1799
1800 case RP_PARM:
1801 text = "PARM";
1802 break;
1803
1804 case RP_NO:
1805 text = "NO";
1806 break;
1807
1808 case RP_USER:
1809 text = "USER";
1810 break;
1811
1812 case RP_NDEL:
1813 text = "NDEL";
1814 break;
1815 }
1816
1817 snprintf (buffer, sizeof(buffer), "[%s] %3d %s",
1818 text, sm_reply.code, sm_reply.text);
1819 return buffer;
1820 }
1821
1822
1823 #ifdef MPOP
1824
1825 static char *broken[MAXARGS + 1];
1826
1827 static char **
1828 smail_brkstring (char *strg, char *brksep, char *brkterm)
1829 {
1830 int bi;
1831 char c, *sp;
1832
1833 sp = strg;
1834
1835 for (bi = 0; bi < MAXARGS; bi++) {
1836 while (smail_brkany (c = *sp, brksep))
1837 *sp++ = 0;
1838 if (!c || smail_brkany (c, brkterm)) {
1839 *sp = 0;
1840 broken[bi] = 0;
1841 return broken;
1842 }
1843
1844 broken[bi] = sp;
1845 while ((c = *++sp) && !smail_brkany (c, brksep) && !smail_brkany (c, brkterm))
1846 continue;
1847 }
1848 broken[MAXARGS] = 0;
1849
1850 return broken;
1851 }
1852
1853
1854 /*
1855 * returns 1 if chr in strg, 0 otherwise
1856 */
1857 static int
1858 smail_brkany (char chr, char *strg)
1859 {
1860 char *sp;
1861
1862 if (strg)
1863 for (sp = strg; *sp; sp++)
1864 if (chr == *sp)
1865 return 1;
1866 return 0;
1867 }
1868
1869 /*
1870 * copy a string array and return pointer to end
1871 */
1872 char **
1873 smail_copyip (char **p, char **q, int len_q)
1874 {
1875 while (*p && --len_q > 0)
1876 *q++ = *p++;
1877
1878 *q = NULL;
1879
1880 return q;
1881 }
1882
1883 #endif /* MPOP */
1884
1885
1886 static char *
1887 EHLOset (char *s)
1888 {
1889 size_t len;
1890 char *ep, **ehlo;
1891
1892 len = strlen (s);
1893
1894 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1895 ep = *ehlo;
1896 if (strncmp (ep, s, len) == 0) {
1897 for (ep += len; *ep == ' '; ep++)
1898 continue;
1899 return ep;
1900 }
1901 }
1902
1903 return 0;
1904 }