comparison uip/sendmail.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children 441a2190cfae
comparison
equal deleted inserted replaced
-1:000000000000 0:bce86c4163a3
1 /* sendmail.c - */
2 #ifndef lint
3 static char Id[] = "$Id$";
4 #endif
5 /*
6 ** A Sendmail fake.
7 *
8 * Contributed by Scott Erickson <erickson@ics.uci.edu>
9 */
10 /* Include files glommed from post.c */
11
12 #include "../h/mh.h"
13 #include "../h/addrsbr.h"
14 #include "../h/aliasbr.h"
15 #include "../h/dropsbr.h"
16 #include "../zotnet/tws.h"
17 #ifndef MMDFMTS
18 #include <ctype.h>
19 #include <errno.h>
20 #include <setjmp.h>
21 #include <stdio.h>
22 #include <sys/types.h>
23 #else MMDFMTS
24 #include "../mts/mmdf/util.h"
25 #include "../mts/mmdf/mmdf.h"
26 #endif MMDFMTS
27 #include "../zotnet/mts.h"
28 #ifdef MHMTS
29 #ifndef V7
30 #include <sys/ioctl.h>
31 #endif not V7
32 #include <sys/stat.h>
33 #endif MHMTS
34 #ifdef SENDMTS
35 #include "../mts/sendmail/smail.h"
36 #undef MF
37 #endif SENDMTS
38 #include <signal.h>
39 #ifdef LOCALE
40 #include <locale.h>
41 #endif
42
43 char *SMTPSRVR = "smtpsrvr";
44
45 char msgfname[50]; /* name of message file */
46 char *FullName; /* sender's full name */
47 char *from; /* sender's mail address */
48 int verbose;
49 int verify;
50 int extract;
51 int dodist;
52 int rewritefrom;
53 int status; /* return value from procedures */
54 static int childid; /* id from smtp child process */
55 TYPESIG die();
56 time_t lclock = 0L; /* the time we started (more or less) */
57
58
59 FILE *fp; /* file pointer for message file */
60 extern FILE *tmpfile();
61
62 static struct swit switches[] = {
63 #define ARPASW 0
64 "ba", -2,
65 #define DAEMONSW 1
66 "bd", -2,
67 #define INITALSW 2
68 "bi", -2,
69 #define DELIVSW 3
70 "bm", -2,
71 #define QSUMSW 4
72 "bp", -2,
73 #define SMTPSW 5
74 "bs", -2,
75 #define ADRTSTSW 6
76 "bt", -2,
77 #define ADRVRFSW 7
78 "bv", -2,
79 #define CFGFRZSW 8
80 "bz", -2,
81 #define ALTCFGSW 9
82 "C", -1,
83 #define DBGVALSW 10
84 "d", -1,
85 #define FULLSW 11
86 "F", -1,
87 #define FROMSW 12
88 "f", -1,
89 #define HOPCNTSW 13
90 "h", -1,
91 #define MSGIDSW 14
92 "M", -1,
93 #define NOALISW 15
94 "n", -1,
95 #define QTIMESW 16
96 "q", -1,
97 #define OBSFRMSW 17
98 "r", -1,
99 #define EXTHDRSW 18
100 "t", -1,
101 #define VERBSW 19
102 "v", -1,
103 #define ALTALISW 20
104 "oA", -2,
105 #define NOCONSW 21
106 "oc", -2,
107 #define DLVMODSW 22
108 "od", -2,
109 #define NEWALISW 23
110 "oD", -2,
111 #define ERRMODSW 24
112 "oe", -2,
113 #define TMPMODSW 25
114 "oF", -2,
115 #define UFROMSW 26
116 "of", -2,
117 #define GIDSW 27
118 "og", -2,
119 #define HLPFILSW 28
120 "oH", -2,
121 #define NODOTSW 29
122 "oi", -2,
123 #define LOGLEVSW 30
124 "oL", -2,
125 #define MEOKSW 31
126 "om", -2,
127 #define OLDHDRSW 32
128 "oo", -2,
129 #define QDIRSW 33
130 "oQ", -2,
131 #define RTMOUTSW 34
132 "or", -2,
133 #define SFILESW 35
134 "oS", -2,
135 #define QMSGSW 36
136 "os", -2,
137 #define MTMOUTSW 37
138 "oT", -2,
139 #define TZSW 38
140 "ot", -2,
141 #define UIDSW 39
142 "ou", -2,
143
144 NULL, 0
145 };
146
147 #if !defined(POSIX) && !defined(_POSIX_SOURCE)
148 extern char *mktemp();
149 #endif
150
151 static void removemsg();
152 static int isheader(), sendfile();
153
154 /*ARGSUSED*/
155 main (argc, argv)
156 int argc;
157 char **argv;
158 {
159 register char *cp;
160 char **argp = argv + 1;
161
162 #ifdef LOCALE
163 setlocale(LC_ALL, "");
164 #endif
165 #ifdef JAPAN
166 ml_init();
167 #endif /* JAPAN */
168 invo_name = r1bindex (argv[0], '/');
169 mts_init(argv[0]);
170
171 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
172 (void) signal(SIGINT, die);
173 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
174 (void) signal(SIGHUP, die);
175 (void) signal(SIGTERM, die);
176 (void) signal(SIGPIPE, die);
177
178 FullName = getfullname();
179 from = adrsprintf(NULLCP,NULLCP);
180 (void) time (&lclock);
181
182 while ( (cp = *argp) && *cp == '-' ) {
183 argp++;
184 switch (smatch ( ++cp, switches )) {
185 case ARPASW: /* smtp on stdin */
186 case SMTPSW: /* smtp on stdin */
187 smtp();
188 exit(98); /* should never happen */
189
190 case DELIVSW: /* just send mail */
191 continue;
192
193 case ADRVRFSW: /* verify mode */
194 verify = 1;
195 continue;
196
197 case FROMSW: /* from address */
198 case OBSFRMSW: /* obsolete -f flag */
199 if (*(++cp) == '\0' &&
200 (!(cp = *argp++) || *cp == '-'))
201 adios (NULLCP, "missing argument to %s", argp[-2]);
202 /* At this point, cp points to the from name */
203 if (rewritefrom) {
204 adios (NULLCP, "More than one \"from\" person");
205 continue;
206 }
207 from = cp;
208 rewritefrom = 1;
209 continue;
210
211 case EXTHDRSW: /* read recipients from message */
212 extract = 1;
213 continue;
214
215 case VERBSW: /* give blow-by-blow description */
216 verbose = 1;
217 continue;
218
219 /* These switches have no args. */
220 case QMSGSW: /* always queue the message */
221 case DAEMONSW: /* run as a daemon & wait for SMTP */
222 case INITALSW: /* initialize the alias database */
223 case QSUMSW: /* print summary of mail queue */
224 case ADRTSTSW: /* test the addresses to debug config file */
225 case CFGFRZSW: /* create the configuration freeze file */
226 case NOALISW: /* do not do aliasing */
227 case NOCONSW: /* do not initiate immediate host connection */
228 case NEWALISW: /* run newaliases to rebuild db */
229 case UFROMSW: /* save UNIX-style From lines at front of msg*/
230 case NODOTSW: /* dots on line are not msg terminators */
231 case MEOKSW: /* ok to send to me if I'm in an alias */
232 case OLDHDRSW: /* msg may have old-style headers */
233 continue;
234
235 /* These switches have string args. */
236 case ALTALISW: /* use alternate alias file */
237 case ALTCFGSW: /* use alternate configuration file */
238 case DBGVALSW: /* set the debug value */
239 case FULLSW: /* set full name */
240 case MSGIDSW: /* try to deliver queued msg with msg-id */
241 case QTIMESW: /* interval between queue passes */
242 case DLVMODSW: /* set the delivery mode */
243 case ERRMODSW: /* set the error mode */
244 case TMPMODSW: /* the mode to use when creating tmp files */
245 case HLPFILSW: /* the SMTP help file */
246 case QDIRSW: /* directory into which to queue messages */
247 case RTMOUTSW: /* timeout on reads */
248 case SFILESW: /* save statistics in this file */
249 case MTMOUTSW: /* timeout on messages in the queue */
250 case TZSW: /* set the name of the timezone */
251 if (*(++cp) == '\0' &&
252 (!(cp = *argp++) || *cp == '-'))
253 adios (NULLCP, "missing argument to %s", argp[-2]);
254 /* At this point, cp points to the argument */
255 continue; /* Ignore */
256
257 /* These switches have numeric args. */
258 case HOPCNTSW: /* hop count */
259 case GIDSW: /* gid when calling mailers */
260 case LOGLEVSW: /* the log level */
261 case UIDSW: /* uid when calling mailers */
262 if (*(++cp) == '\0' &&
263 (!(cp = *argp++) || *cp == '-'))
264 adios (NULLCP, "missing argument to %s", argp[-2]);
265 /* At this point, cp points to the numeric arg */
266 if (!isdigit(*cp))
267 adios (NULLCP, "non-numeric argument to %s", argp[-2]);
268 continue; /* Ignore */
269 }
270 }
271
272 (void) setuid(getuid());
273
274 if (verify && extract)
275 adios (NULLCP, "mode not supported on header components");
276
277 if (*argp == NULL && !extract)
278 adios (NULLCP, "usage: ", sendmail, " [flags] addr...");
279
280 strcpy (msgfname, "/tmp/sendmhXXXXXX");
281 if ( mktemp(msgfname) == NULL )
282 adios (msgfname, "can't create msg file ");
283
284 if ( (fp = fopen(msgfname,"w") ) == NULL ) {
285 adios (msgfname, "error opening ");
286 }
287
288 doheader(argp);
289 if ( verify ) {
290 (void) fclose(fp);
291 status = doverify();
292 removemsg();
293 exit ( status ) ;
294 }
295 dobody();
296 status = sendfile();
297 removemsg();
298 exit ( status );
299 }
300
301 static void removemsg()
302 {
303 if ( unlink(msgfname) != 0 )
304 perror("unlink");
305 }
306
307 doheader(argp)
308 char **argp;
309 {
310 char line[BUFSIZ];
311 int gotdate, gotfrom, gotsender, gotto;
312
313 /* if we're not extracting the headers from the message, then we
314 * need to check to see if we need to do a "send" or a "dist".
315 */
316
317 if ( !extract ) {
318 /* If we're doing a verify, just create a "To:" header. */
319 if ( ! verify ) {
320 gotdate = gotfrom = gotto = gotsender = dodist = 0;
321 while (fgets (line, BUFSIZ, stdin) != NULL) {
322 if (line[0] == '\n') /* end of header */
323 break;
324 if ( !isheader(line) )
325 break;
326
327 /* if any of the following headers are present, then we
328 * want to do a dist.
329 */
330 if ( !gotdate && uprf(line, "date") )
331 gotdate = dodist = 1;
332
333 else if ( !gotto && (uprf(line, "to") || uprf(line, "cc")) )
334 gotto = dodist = 1;
335
336 else if ( uprf(line, "message-id") )
337 dodist = 1;
338
339 else if ( !gotsender && uprf(line, "sender") )
340 gotsender = dodist = 1;
341
342 else if ( uprf ( line, "resent-" ) ) {
343 dodist = 1;
344 (void) fputs("Prev-", fp);
345 }
346
347 /* See if we are re-writing the from line */
348 if ( uprf(line, "from") ) {
349 gotfrom = 1;
350 if ( rewritefrom )
351 dofrom();
352 else
353 (void) fputs(line,fp);
354 }
355 else
356 (void) fputs(line,fp);
357 }
358 }
359 /* Now, generate a "to" line. The first line is easy.
360 * Write the rest of the lines with a newline/tab so that we
361 * don't accidentally write a line that's too long to be parsed
362 * by post.
363 */
364 (void) fprintf (fp, "%sTo: %s", (dodist ? "Resent-" : "" ), *argp++);
365 while ( *argp )
366 (void) fprintf ( fp, ",\n\t%s", *argp++ );
367 (void) fputs("\n",fp);
368
369 /* If we're doing a dist, we must have a "Date:" and "From:" field.
370 */
371 if ( dodist ) {
372 if ( !gotdate )
373 (void) fprintf (fp, "Date: %s\n", dtime (&lclock));
374 if ( !gotfrom )
375 dofrom();
376 }
377 #ifdef MMDFI /* sigh */
378 if ( !gotsender )
379 (void) fprintf (fp, "Sender: %s\n", from);
380 #endif MMDFI
381 } else { /* we're verifying, so just pass everything through */
382 while (fgets (line, BUFSIZ, stdin) != NULL) {
383 if (line[0] == '\n') /* end of header */
384 break;
385
386 if ( rewritefrom && uprf(line, "from"))
387 dofrom();
388 else
389 (void) fputs(line,fp);
390 }
391 }
392 /* At this point, line is either a newline (end of header) or the
393 * first line of the body (poorly formatted message). If line
394 * contains a line of body from a poorly formatted message, then
395 * print a newline to separate the header correctly, then print
396 * the body line.
397 */
398 if ( line[0] != '\n' ) /* i.e. a "body" line */
399 (void) fputc('\n', fp);
400 (void) fputs(line, fp);
401 }
402
403 static int isheader(s)
404 char *s;
405 {
406 register char *cp;
407
408 /* If the first character is a space, assume a continuation of a header */
409 if ( isspace(*s) )
410 return 1;
411
412 /* If there's no ':', it's not a header */
413 if ( (cp = index(s,':')) == NULL )
414 return 0;
415
416 /* If there's a space between BOL and ':', it's not a header */
417 while ( s < cp ) {
418 if ( isspace(*s) )
419 return 0;
420 s++;
421 }
422 return 1;
423 }
424
425 /* This procedure does the verify and returns the status */
426 doverify() {
427 char *command, buf[BUFSIZ], *bp;
428 FILE *verfp, *popen();
429
430 /* set up the command line for post */
431 if ( (command = (char *)malloc((strlen(postproc) +
432 strlen(" -whom -check -verbose ") +
433 strlen(msgfname) + 1 )*sizeof(char)))
434 == NULL ) {
435 perror("malloc");
436 return NOTOK;
437 }
438
439 (void) strcpy(command,postproc);
440 (void) strcat(command," -whom -check ");
441 if ( verbose )
442 (void) strcat(command, "-verbose " );
443 (void) strcat(command, msgfname);
444
445 /* open up the pipe */
446 if ( (verfp = popen(command,"r")) == NULL )
447 return NOTOK;
448
449 while ( fgets(buf, BUFSIZ, verfp) != NULL )
450 /* sendmail returns:
451 * address: result
452 * so we need to strip the extra post headers.
453 */
454 if ( verbose ) {
455 bp = buf;
456 while (isspace(*bp))
457 bp++;
458 if ( *bp != '-' )
459 (void) fputs(bp,stdout);
460 }
461
462 /* return the error status of post */
463 return( pclose(verfp) >> 8 );
464 }
465
466 static int sendfile()
467 {
468 char *command, buf[BUFSIZ];
469 FILE *verfp, *popen();
470
471 /* set up the command line for post */
472 if ( (command = (char *)malloc((strlen(postproc) +
473 strlen(" -dist -verbose ") +
474 strlen(msgfname) + 1 )*sizeof(char)))
475 == NULL ) {
476 perror("malloc");
477 return NOTOK;
478 }
479
480 (void) strcpy(command,postproc);
481 (void) strcat(command," ");
482 if ( verbose )
483 (void) strcat(command, "-verbose " );
484 if ( dodist )
485 (void) strcat(command, "-dist " );
486 (void) strcat(command, msgfname);
487
488 /* open up the pipe */
489 if ( (verfp = popen(command,"r")) == NULL )
490 return NOTOK;
491
492 while ( fgets(buf, BUFSIZ, verfp) != NULL )
493 (void) fputs(buf,stdout);
494
495 /* return the error status of post */
496 return( pclose(verfp) >> 8 );
497 }
498
499 dofrom() {
500 char line[128];
501
502 if (FullName)
503 (void) sprintf(line, "From: %s <%s>\n", FullName, from);
504 else
505 (void) sprintf(line, "From: %s\n", from);
506 (void) fputs(line, fp);
507 }
508
509 dobody() {
510 register int i;
511 char buffer[BUFSIZ];
512
513 while (!feof (stdin) && !ferror (stdin) &&
514 (i = fread (buffer, sizeof (char), sizeof (buffer), stdin)) > 0)
515 if (fwrite (buffer, sizeof (char), i , fp) != i )
516 adios (NULLCP, "Problem writing body");
517
518 if (ferror (stdin))
519 adios (NULLCP, "Problem reading body");
520
521 if ( fclose(fp) != 0 )
522 adios (NULLCP, "problem ending submission");
523 }
524
525 TYPESIG silentdie();
526
527 smtp()
528 {
529 int sd,len;
530 char buf[BUFSIZ], response[BUFSIZ];
531
532 if ((sd = client(NULLCP, "tcp", "smtp", 0, response)) == NOTOK)
533 adios (NULLCP, "cannot open smtp client process");
534
535 (void) signal(SIGCHLD, silentdie);
536
537 switch ((childid = fork())) {
538 case NOTOK:
539 adios (NULLCP, "unable to fork smtp process");
540
541 case OK: /* i.e. child */
542 (void) dup2(sd,0);
543 break;
544
545 default: /* i.e. parent */
546 (void) dup2(sd,1);
547 break;
548 }
549 while ( (len = read(0, buf, BUFSIZ)) > 0)
550 (void) write (1, buf, len);
551
552 if (childid)
553 (void) kill(childid, SIGHUP);
554
555 exit(9);
556 }
557
558 /* ARGSUSED */
559 TYPESIG die(sig)
560 int sig;
561 {
562 if (fp) {
563 (void) fclose(fp);
564 (void) unlink(msgfname);
565 }
566 if (sig != SIGHUP)
567 (void) fprintf(stderr, "sendmail: dying from signal %d\n", sig);
568 exit(99);
569 }
570
571 /* ARGSUSED */
572
573 TYPESIG silentdie(sig)
574 int sig;
575 {
576 pidwait (childid, OK);
577 exit(0);
578 }