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