0
|
1 /* sendmail.c - */
|
|
2 #ifndef lint
|
12
|
3 static char Id[] = "$Id: sendmail.c,v 1.1.1.1 2005/04/18 14:46:07 kono Exp $";
|
0
|
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 }
|