Commit | Line | Data |
---|---|---|
ed45aae1 | 1 | # define _DEFINE |
b3cbe40f | 2 | # include <signal.h> |
1a12c7d6 | 3 | # include <pwd.h> |
96faada8 | 4 | # include "sendmail.h" |
ed45aae1 | 5 | # include <sys/stat.h> |
b3cbe40f | 6 | # ifdef LOG |
882642f7 | 7 | # include <syslog.h> |
b3cbe40f EA |
8 | # endif LOG |
9 | ||
da6a9b77 | 10 | SCCSID(@(#)main.c 3.81 %G%); |
916b3375 | 11 | |
b3cbe40f | 12 | /* |
96faada8 | 13 | ** SENDMAIL -- Post mail to a set of destinations. |
b3cbe40f EA |
14 | ** |
15 | ** This is the basic mail router. All user mail programs should | |
96faada8 | 16 | ** call this routine to actually deliver mail. Sendmail in |
b3cbe40f EA |
17 | ** turn calls a bunch of mail servers that do the real work of |
18 | ** delivering the mail. | |
19 | ** | |
96faada8 | 20 | ** Sendmail is driven by tables defined in conf.c. This |
b3cbe40f EA |
21 | ** file will be different from system to system, but the rest |
22 | ** of the code will be the same. This table could be read in, | |
23 | ** but it seemed nicer to have it compiled in, since deliver- | |
24 | ** mail will potentially be exercised a lot. | |
25 | ** | |
26 | ** Usage: | |
96faada8 | 27 | ** /etc/sendmail [-f name] [-a] [-q] [-v] [-n] [-m] addr ... |
b3cbe40f EA |
28 | ** |
29 | ** Positional Parameters: | |
30 | ** addr -- the address to deliver the mail to. There | |
31 | ** can be several. | |
32 | ** | |
33 | ** Flags: | |
34 | ** -f name The mail is from "name" -- used for | |
35 | ** the header in local mail, and to | |
36 | ** deliver reports of failures to. | |
37 | ** -r name Same as -f; however, this flag is | |
38 | ** reserved to indicate special processing | |
39 | ** for remote mail delivery as needed | |
40 | ** in the future. So, network servers | |
41 | ** should use -r. | |
6da7b890 EA |
42 | ** -Ffullname Select what the full-name should be |
43 | ** listed as. | |
b3cbe40f | 44 | ** -a This mail should be in ARPANET std |
74c5fe7c EA |
45 | ** format (obsolete version). |
46 | ** -am Called from an FTP "MAIL" command. | |
47 | ** -af Called from an FTP "MLFL" command. | |
b3cbe40f EA |
48 | ** -n Don't do aliasing. This might be used |
49 | ** when delivering responses, for | |
50 | ** instance. | |
51 | ** -d Run in debug mode. | |
52 | ** -em Mail back a response if there was an | |
53 | ** error in processing. This should be | |
54 | ** used when the origin of this message | |
55 | ** is another machine. | |
56 | ** -ew Write back a response if the user is | |
57 | ** still logged in, otherwise, act like | |
58 | ** -em. | |
59 | ** -eq Don't print any error message (just | |
60 | ** return exit status). | |
61 | ** -ep (default) Print error messages | |
62 | ** normally. | |
3b661a43 EA |
63 | ** -ee Send BerkNet style errors. This |
64 | ** is equivalent to MailBack except | |
65 | ** that it has gives zero return code | |
66 | ** (unless there were errors during | |
67 | ** returning). This used to be | |
68 | ** "EchoBack", but you know how the old | |
69 | ** software bounces. | |
b3cbe40f EA |
70 | ** -m In group expansion, send to the |
71 | ** sender also (stands for the Mail metoo | |
72 | ** option. | |
73 | ** -i Do not terminate mail on a line | |
74 | ** containing just dot. | |
75 | ** -s Save UNIX-like "From" lines on the | |
76 | ** front of messages. | |
d59b067a EA |
77 | ** -v Give blow-by-blow description of |
78 | ** everything that happens. | |
bfcddd93 EA |
79 | ** -t Read "to" addresses from message. |
80 | ** Looks at To:, Cc:, and Bcc: lines. | |
74c5fe7c EA |
81 | ** -I Initialize the DBM alias files from |
82 | ** the text format files. | |
6da7b890 | 83 | ** -Cfilename Use alternate configuration file. |
cdb17311 | 84 | ** -Afilename Use alternate alias file. |
6da7b890 | 85 | ** -DXvalue Define macro X to have value. |
b3cbe40f EA |
86 | ** |
87 | ** Return Codes: | |
88 | ** As defined in <sysexits.h>. | |
89 | ** | |
90 | ** These codes are actually returned from the auxiliary | |
91 | ** mailers; it is their responsibility to make them | |
92 | ** correct. | |
93 | ** | |
b3cbe40f | 94 | ** Compilation Flags: |
b3cbe40f | 95 | ** LOG -- if set, everything is logged. |
b3cbe40f | 96 | ** |
b3cbe40f EA |
97 | ** Author: |
98 | ** Eric Allman, UCB/INGRES | |
b3cbe40f EA |
99 | */ |
100 | ||
101 | ||
102 | ||
103 | ||
104 | ||
2654b031 | 105 | int NextMailer = 0; /* "free" index into Mailer struct */ |
cbdb7357 | 106 | static char *FullName; /* sender's full name */ |
2654b031 | 107 | ENVELOPE MainEnvelope; /* the envelope around the basic letter */ |
b3cbe40f | 108 | |
4aebfe5d EA |
109 | #ifdef DAEMON |
110 | #ifndef SMTP | |
111 | ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR | |
112 | #endif SMTP | |
113 | #endif DAEMON | |
114 | ||
b3cbe40f EA |
115 | |
116 | ||
117 | ||
118 | ||
119 | ||
120 | main(argc, argv) | |
121 | int argc; | |
122 | char **argv; | |
123 | { | |
124 | register char *p; | |
17df0fcb | 125 | char *locname; |
b3cbe40f | 126 | extern int finis(); |
b3cbe40f | 127 | extern char Version[]; |
b3cbe40f | 128 | char *from; |
b3cbe40f | 129 | typedef int (*fnptr)(); |
9e3c0a28 | 130 | register int i; |
eb211e2c | 131 | bool safecf = TRUE; /* this conf file is sys default */ |
2768afe3 | 132 | char ibuf[30]; /* holds HostName */ |
aba51985 | 133 | bool queuemode = FALSE; /* process queue requests */ |
f4dbf345 | 134 | bool aliasinit = FALSE; |
f6a0cc15 | 135 | extern bool safefile(); |
179c1218 | 136 | STAB *st; |
ed45aae1 | 137 | extern time_t convtime(); |
dd1fe05b | 138 | extern putheader(), putbody(); |
abae7b2d | 139 | extern ADDRESS *recipient(); |
17df0fcb | 140 | bool canrename; |
b3cbe40f | 141 | |
d6b27179 | 142 | argv[argc] = NULL; |
cbdb7357 EA |
143 | InChannel = stdin; |
144 | OutChannel = stdout; | |
b3cbe40f | 145 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) |
29871fef | 146 | (void) signal(SIGINT, finis); |
eb211e2c EA |
147 | if (signal(SIGHUP, SIG_IGN) != SIG_IGN) |
148 | (void) signal(SIGHUP, finis); | |
29871fef | 149 | (void) signal(SIGTERM, finis); |
a0554f81 | 150 | OldUmask = umask(0); |
d0bd03ce | 151 | Mode = MD_DEFAULT; |
dd1fe05b EA |
152 | |
153 | /* set up the main envelope */ | |
154 | MainEnvelope.e_puthdr = putheader; | |
155 | MainEnvelope.e_putbody = putbody; | |
2654b031 | 156 | CurEnv = &MainEnvelope; |
dd1fe05b | 157 | |
b3cbe40f | 158 | # ifdef LOG |
96faada8 | 159 | openlog("sendmail", 0); |
b3cbe40f | 160 | # endif LOG |
49086753 | 161 | openxscrpt(); |
b3cbe40f EA |
162 | # ifdef DEBUG |
163 | # ifdef DEBUGFILE | |
164 | if ((i = open(DEBUGFILE, 1)) > 0) | |
165 | { | |
29871fef EA |
166 | (void) lseek(i, 0L, 2); |
167 | (void) close(1); | |
168 | (void) dup(i); | |
169 | (void) close(i); | |
b3cbe40f EA |
170 | Debug++; |
171 | } | |
172 | # endif DEBUGFILE | |
b3cbe40f EA |
173 | # endif |
174 | errno = 0; | |
175 | from = NULL; | |
2654b031 | 176 | CurEnv->e_oldstyle = TRUE; |
721fad23 | 177 | initmacros(); |
b3cbe40f EA |
178 | |
179 | /* | |
180 | ** Crack argv. | |
181 | */ | |
182 | ||
183 | while (--argc > 0 && (p = *++argv)[0] == '-') | |
184 | { | |
185 | switch (p[1]) | |
186 | { | |
187 | case 'r': /* obsolete -f flag */ | |
188 | case 'f': /* from address */ | |
189 | p += 2; | |
190 | if (*p == '\0') | |
191 | { | |
192 | p = *++argv; | |
193 | if (--argc <= 0 || *p == '-') | |
194 | { | |
195 | syserr("No \"from\" person"); | |
196 | argc++; | |
197 | argv--; | |
198 | break; | |
199 | } | |
200 | } | |
201 | if (from != NULL) | |
202 | { | |
203 | syserr("More than one \"from\" person"); | |
204 | break; | |
205 | } | |
206 | from = p; | |
207 | break; | |
208 | ||
6da7b890 | 209 | case 'F': /* set full name */ |
74c5fe7c EA |
210 | p += 2; |
211 | if (*p == '\0') | |
212 | { | |
213 | p = *++argv; | |
214 | if (--argc <= 0 || *p == '-') | |
215 | { | |
216 | syserr("Bad -F flag"); | |
217 | argc++; | |
218 | argv--; | |
219 | break; | |
220 | } | |
221 | } | |
cbdb7357 | 222 | FullName = p; |
6da7b890 EA |
223 | break; |
224 | ||
b3cbe40f EA |
225 | case 'h': /* hop count */ |
226 | p += 2; | |
227 | if (*p == '\0') | |
228 | { | |
229 | p = *++argv; | |
230 | if (--argc <= 0 || *p < '0' || *p > '9') | |
231 | { | |
232 | syserr("Bad hop count (%s)", p); | |
233 | argc++; | |
234 | argv--; | |
235 | break; | |
236 | } | |
237 | } | |
238 | HopCount = atoi(p); | |
239 | break; | |
240 | ||
241 | case 'e': /* error message disposition */ | |
242 | switch (p[2]) | |
243 | { | |
244 | case 'p': /* print errors normally */ | |
245 | break; /* (default) */ | |
246 | ||
247 | case 'q': /* be silent about it */ | |
29871fef | 248 | (void) freopen("/dev/null", "w", stdout); |
b3cbe40f EA |
249 | break; |
250 | ||
251 | case 'm': /* mail back */ | |
49086753 EA |
252 | MailBack = TRUE; |
253 | HoldErrs = TRUE; | |
b3cbe40f EA |
254 | break; |
255 | ||
3b661a43 | 256 | case 'e': /* do berknet error processing */ |
49086753 EA |
257 | BerkNet = TRUE; |
258 | HoldErrs = TRUE; | |
b3cbe40f EA |
259 | break; |
260 | ||
261 | case 'w': /* write back (or mail) */ | |
49086753 EA |
262 | WriteBack = TRUE; |
263 | HoldErrs = TRUE; | |
b3cbe40f EA |
264 | break; |
265 | } | |
266 | break; | |
267 | ||
268 | # ifdef DEBUG | |
269 | case 'd': /* debug */ | |
6da7b890 EA |
270 | Debug = atoi(&p[2]); |
271 | if (Debug <= 0) | |
272 | Debug = 1; | |
62fff4f9 | 273 | setbuf(stdout, (char *) NULL); |
6da7b890 | 274 | printf("Version %s Debug %d\n", Version, Debug); |
b3cbe40f | 275 | break; |
1a12c7d6 | 276 | |
f6a0cc15 | 277 | case 'M': /* redefine internal macro */ |
dc39c568 | 278 | define(p[2], &p[3]); |
1a12c7d6 | 279 | break; |
b3cbe40f | 280 | # endif DEBUG |
d6a28dd8 | 281 | |
6da7b890 | 282 | case 'C': /* select configuration file */ |
6a5effbb | 283 | if (p[2] == '\0') |
4e1f4d4b | 284 | ConfFile = "sendmail.cf"; |
6a5effbb | 285 | else |
4e1f4d4b | 286 | ConfFile = &p[2]; |
eb211e2c | 287 | safecf = FALSE; |
d6a28dd8 | 288 | break; |
cdb17311 EA |
289 | |
290 | case 'A': /* select alias file */ | |
6a5effbb | 291 | if (p[2] == '\0') |
4e1f4d4b | 292 | AliasFile = "aliases"; |
6a5effbb | 293 | else |
4e1f4d4b | 294 | AliasFile = &p[2]; |
cdb17311 | 295 | break; |
ed45aae1 EA |
296 | |
297 | case 'Q': /* select queue dir */ | |
298 | if (p[2] == '\0') | |
b715ed3c | 299 | QueueDir = "mqueue"; |
ed45aae1 | 300 | else |
b715ed3c | 301 | QueueDir = &p[2]; |
ed45aae1 EA |
302 | break; |
303 | ||
304 | case 'T': /* set timeout interval */ | |
305 | TimeOut = convtime(&p[2]); | |
306 | break; | |
b3cbe40f EA |
307 | |
308 | case 'n': /* don't alias */ | |
309 | NoAlias++; | |
310 | break; | |
311 | ||
f4dbf345 EA |
312 | # ifdef DBM |
313 | case 'I': /* initialize alias DBM file */ | |
314 | aliasinit = TRUE; | |
d6b27179 | 315 | Verbose = TRUE; |
f4dbf345 EA |
316 | break; |
317 | # endif DBM | |
318 | ||
b3cbe40f EA |
319 | case 'm': /* send to me too */ |
320 | MeToo++; | |
321 | break; | |
322 | ||
323 | case 'i': /* don't let dot stop me */ | |
324 | IgnrDot++; | |
325 | break; | |
326 | ||
327 | case 'a': /* arpanet format */ | |
49086753 EA |
328 | ArpaMode = TRUE; |
329 | if (p[2] == 's') | |
dc39c568 | 330 | { |
49086753 | 331 | /* running smtp */ |
884a20cb | 332 | # ifdef SMTP |
49086753 | 333 | Smtp = TRUE; |
884a20cb EA |
334 | # else SMTP |
335 | syserr("I don't speak SMTP"); | |
336 | # endif SMTP | |
dc39c568 | 337 | } |
b3cbe40f | 338 | break; |
3135d20c EA |
339 | |
340 | # ifdef QUEUE | |
341 | case 'c': /* don't connect to non-local mailers */ | |
342 | NoConnect = TRUE; | |
343 | break; | |
344 | # endif QUEUE | |
b3cbe40f EA |
345 | |
346 | case 's': /* save From lines in headers */ | |
347 | SaveFrom++; | |
348 | break; | |
349 | ||
d59b067a EA |
350 | case 'v': /* give blow-by-blow description */ |
351 | Verbose++; | |
352 | break; | |
353 | ||
bfcddd93 EA |
354 | case 't': /* read recipients from message */ |
355 | GrabTo = TRUE; | |
356 | break; | |
357 | ||
d0bd03ce EA |
358 | case 'b': /* operations mode */ |
359 | Mode = p[2]; | |
360 | switch (Mode) | |
361 | { | |
362 | case MD_DAEMON: /* run as a daemon */ | |
14a39063 | 363 | #ifdef DAEMON |
d0bd03ce | 364 | ArpaMode = Smtp = TRUE; |
4aebfe5d | 365 | #else DAEMON |
d0bd03ce | 366 | syserr("Daemon mode not implemented"); |
14a39063 | 367 | #endif DAEMON |
d0bd03ce EA |
368 | break; |
369 | ||
370 | case '\0': /* default: do full delivery */ | |
371 | Mode = MD_DEFAULT; | |
372 | /* fall through....... */ | |
373 | ||
374 | case MD_DELIVER: /* do everything (default) */ | |
375 | case MD_FORK: /* fork after verification */ | |
376 | case MD_QUEUE: /* queue only */ | |
377 | case MD_VERIFY: /* verify only */ | |
378 | break; | |
379 | ||
380 | default: | |
381 | syserr("Unknown operation mode -b%c", Mode); | |
382 | exit(EX_USAGE); | |
383 | } | |
14a39063 | 384 | break; |
cbdb7357 | 385 | |
ed45aae1 | 386 | case 'q': /* run queue files at intervals */ |
884a20cb | 387 | # ifdef QUEUE |
aba51985 | 388 | queuemode = TRUE; |
25b9d645 | 389 | QueueIntvl = convtime(&p[2]); |
884a20cb EA |
390 | # else QUEUE |
391 | syserr("I don't know about queues"); | |
392 | # endif QUEUE | |
ed45aae1 EA |
393 | break; |
394 | ||
49a45ae5 | 395 | case 'o': /* take new-style headers (with commas) */ |
2654b031 | 396 | CurEnv->e_oldstyle = FALSE; |
35cc3fad EA |
397 | break; |
398 | ||
b3cbe40f EA |
399 | default: |
400 | /* at Eric Schmidt's suggestion, this will not be an error.... | |
401 | syserr("Unknown flag %s", p); | |
402 | ... seems that upward compatibility will be easier. */ | |
403 | break; | |
404 | } | |
405 | } | |
406 | ||
9e3c0a28 | 407 | /* |
f6a0cc15 | 408 | ** Read system control file. |
179c1218 | 409 | ** Extract special fields for local use. |
9e3c0a28 EA |
410 | */ |
411 | ||
4e1f4d4b | 412 | readcf(ConfFile, safecf); |
ed45aae1 | 413 | initsys(); |
179c1218 EA |
414 | |
415 | /* our name for SMTP codes */ | |
dd1fe05b | 416 | expand("$i", ibuf, &ibuf[sizeof ibuf - 1], CurEnv); |
2768afe3 | 417 | HostName = ibuf; |
d6a28dd8 | 418 | |
179c1218 EA |
419 | /* the indices of local and program mailers */ |
420 | st = stab("local", ST_MAILER, ST_FIND); | |
421 | if (st == NULL) | |
422 | syserr("No local mailer defined"); | |
423 | else | |
424 | LocalMailer = st->s_mailer; | |
425 | st = stab("prog", ST_MAILER, ST_FIND); | |
426 | if (st == NULL) | |
427 | syserr("No prog mailer defined"); | |
428 | else | |
429 | ProgMailer = st->s_mailer; | |
430 | ||
f6a0cc15 EA |
431 | /* |
432 | ** Initialize aliases. | |
433 | */ | |
8acb5142 | 434 | |
4e1f4d4b | 435 | initaliases(AliasFile, aliasinit); |
f4dbf345 EA |
436 | # ifdef DBM |
437 | if (aliasinit) | |
438 | exit(EX_OK); | |
439 | # endif DBM | |
cdb17311 | 440 | |
9c6d4c70 EA |
441 | # ifdef DEBUG |
442 | if (Debug > 15) | |
443 | { | |
f6a0cc15 | 444 | /* print configuration table (or at least part of it) */ |
9c6d4c70 EA |
445 | printrules(); |
446 | for (i = 0; i < MAXMAILERS; i++) | |
447 | { | |
448 | register struct mailer *m = Mailer[i]; | |
449 | ||
450 | if (m == NULL) | |
451 | continue; | |
8a6c20a5 | 452 | printf("mailer %d: %s %s %lo %s\n", i, m->m_name, |
9c6d4c70 EA |
453 | m->m_mailer, m->m_flags, m->m_from); |
454 | } | |
455 | } | |
456 | # endif DEBUG | |
457 | ||
14a39063 | 458 | #ifdef DAEMON |
f6a0cc15 EA |
459 | /* |
460 | ** If a daemon, wait for a request. | |
461 | ** getrequests will always return in a child. | |
25b9d645 EA |
462 | ** If we should also be processing the queue, start |
463 | ** doing it in background. | |
f6a0cc15 EA |
464 | */ |
465 | ||
d0bd03ce | 466 | if (Mode == MD_DAEMON) |
25b9d645 EA |
467 | { |
468 | # ifdef QUEUE | |
469 | if (queuemode) | |
470 | runqueue(TRUE); | |
471 | # endif QUEUE | |
f6a0cc15 | 472 | getrequests(); |
25b9d645 | 473 | } |
14a39063 | 474 | #endif DAEMON |
cbdb7357 | 475 | |
884a20cb | 476 | # ifdef SMTP |
b3cbe40f | 477 | /* |
cbdb7357 EA |
478 | if (Smtp) |
479 | smtp(); | |
884a20cb | 480 | # endif SMTP |
a9e0e597 | 481 | |
884a20cb | 482 | # ifdef QUEUE |
ed45aae1 EA |
483 | /* |
484 | ** If collecting stuff from the queue, go start doing that. | |
485 | */ | |
486 | ||
d0bd03ce | 487 | if (queuemode && Mode != MD_DAEMON) |
ed45aae1 | 488 | { |
2cf55cb7 | 489 | runqueue(FALSE); |
ed45aae1 EA |
490 | finis(); |
491 | } | |
884a20cb | 492 | # endif QUEUE |
ed45aae1 | 493 | |
f6a0cc15 | 494 | /* |
cbdb7357 | 495 | ** Set the sender |
f6a0cc15 EA |
496 | */ |
497 | ||
cbdb7357 | 498 | setsender(from); |
a9e0e597 | 499 | |
d0bd03ce | 500 | if (Mode != MD_DAEMON && argc <= 0 && !GrabTo) |
e863b1fa | 501 | { |
96faada8 | 502 | usrerr("Usage: /etc/sendmail [flags] addr..."); |
e863b1fa EA |
503 | finis(); |
504 | } | |
b3cbe40f EA |
505 | |
506 | /* | |
507 | ** Process Hop count. | |
508 | ** The Hop count tells us how many times this message has | |
96faada8 | 509 | ** been processed by sendmail. If it exceeds some |
b3cbe40f EA |
510 | ** fairly large threshold, then we assume that we have |
511 | ** an infinite forwarding loop and die. | |
512 | */ | |
513 | ||
514 | if (++HopCount > MAXHOP) | |
2654b031 | 515 | syserr("Infinite forwarding loop (%s->%s)", CurEnv->e_from.q_paddr, *argv); |
b3cbe40f | 516 | |
b3cbe40f | 517 | /* |
d6b27179 EA |
518 | ** Scan argv and deliver the message to everyone. |
519 | ** Actually, suppress delivery if we are taking To: | |
520 | ** lines from the message. | |
b3cbe40f EA |
521 | */ |
522 | ||
23a54ee3 EA |
523 | if (GrabTo) |
524 | DontSend = TRUE; | |
cbdb7357 | 525 | sendtoargv(argv); |
b3cbe40f | 526 | |
a4b004a6 | 527 | /* if we have had errors sofar, drop out now */ |
d916f0ca | 528 | if (Errors > 0 && ExitStat == EX_OK) |
a4b004a6 | 529 | ExitStat = EX_USAGE; |
a4b004a6 | 530 | |
dc39c568 EA |
531 | /* |
532 | ** Read the input mail. | |
533 | */ | |
534 | ||
23a54ee3 | 535 | DontSend = FALSE; |
2654b031 | 536 | CurEnv->e_to = NULL; |
d0bd03ce | 537 | if (Mode != MD_VERIFY || GrabTo) |
49086753 | 538 | collect(FALSE); |
d829793b | 539 | errno = 0; |
35cc3fad EA |
540 | |
541 | /* | |
542 | ** If we don't want to wait around for actual delivery, this | |
543 | ** is a good time to fork off. | |
544 | ** We have examined what we can without doing actual | |
545 | ** delivery, so we will inform our caller of | |
546 | ** whatever we can now. | |
547 | ** Since the parent process will go away immediately, | |
548 | ** the child will be caught by init. | |
549 | ** If the fork fails, we will just continue in the | |
550 | ** parent; this is perfectly safe, albeit | |
551 | ** slower than it must be. | |
552 | */ | |
553 | ||
d0bd03ce | 554 | if (Mode == MD_FORK) |
35cc3fad EA |
555 | { |
556 | if (fork() > 0) | |
557 | { | |
558 | /* parent -- quit */ | |
559 | exit(ExitStat); | |
560 | } | |
561 | } | |
d0bd03ce EA |
562 | else if (Mode == MD_QUEUE) |
563 | { | |
564 | queueup(CurEnv, TRUE); | |
565 | exit(ExitStat); | |
566 | } | |
35cc3fad | 567 | |
ed45aae1 | 568 | initsys(); |
bfcddd93 | 569 | |
4e1f4d4b | 570 | /* collect statistics */ |
2654b031 EA |
571 | Stat.stat_nf[CurEnv->e_from.q_mailer->m_mno]++; |
572 | Stat.stat_bf[CurEnv->e_from.q_mailer->m_mno] += kbytes(CurEnv->e_msgsize); | |
4e1f4d4b | 573 | |
b3cbe40f | 574 | /* |
dc39c568 EA |
575 | ** Arrange that the person who is sending the mail |
576 | ** will not be expanded (unless explicitly requested). | |
b3cbe40f EA |
577 | */ |
578 | ||
d6b27179 EA |
579 | # ifdef DEBUG |
580 | if (Debug) | |
2654b031 | 581 | printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); |
d6b27179 EA |
582 | # endif DEBUG |
583 | ||
2654b031 | 584 | CurEnv->e_from.q_flags |= QDONTSEND; |
b3cbe40f | 585 | if (!MeToo) |
2654b031 EA |
586 | recipient(&CurEnv->e_from, &CurEnv->e_sendqueue); |
587 | CurEnv->e_to = NULL; | |
b3cbe40f EA |
588 | |
589 | /* | |
590 | ** Actually send everything. | |
d6b27179 | 591 | ** If verifying, just ack. |
b3cbe40f EA |
592 | */ |
593 | ||
3c7fe765 | 594 | sendall(CurEnv, Mode == MD_VERIFY); |
b3cbe40f EA |
595 | |
596 | /* | |
597 | ** All done. | |
598 | */ | |
599 | ||
2654b031 | 600 | CurEnv->e_to = NULL; |
d0bd03ce | 601 | if (Mode != MD_VERIFY) |
d6b27179 | 602 | poststats(StatFile); |
b3cbe40f EA |
603 | finis(); |
604 | } | |
605 | \f/* | |
f65e7ded EA |
606 | ** SETFROM -- set the person who this message is from |
607 | ** | |
608 | ** Under certain circumstances allow the user to say who | |
609 | ** s/he is (using -f or -r). These are: | |
610 | ** 1. The user's uid is zero (root). | |
611 | ** 2. The user's login name is "network" (mail from | |
612 | ** a network server). | |
613 | ** 3. The user's login name is "uucp" (mail from the | |
614 | ** uucp network). | |
615 | ** 4. The address the user is trying to claim has a | |
616 | ** "!" character in it (since #3 doesn't do it for | |
617 | ** us if we are dialing out). | |
618 | ** A better check to replace #3 & #4 would be if the | |
619 | ** effective uid is "UUCP" -- this would require me | |
620 | ** to rewrite getpwent to "grab" uucp as it went by, | |
621 | ** make getname more nasty, do another passwd file | |
622 | ** scan, or compile the UID of "UUCP" into the code, | |
623 | ** all of which are reprehensible. | |
624 | ** | |
625 | ** Assuming all of these fail, we figure out something | |
626 | ** ourselves. | |
627 | ** | |
628 | ** Parameters: | |
629 | ** from -- the person it is from. | |
630 | ** realname -- the actual person executing sendmail. | |
dc39c568 EA |
631 | ** If NULL, then take whoever we previously |
632 | ** thought was the from person. | |
f65e7ded EA |
633 | ** |
634 | ** Returns: | |
635 | ** none. | |
636 | ** | |
637 | ** Side Effects: | |
638 | ** sets sendmail's notion of who the from person is. | |
639 | */ | |
640 | ||
641 | setfrom(from, realname) | |
642 | char *from; | |
643 | char *realname; | |
644 | { | |
645 | register char **pvp; | |
646 | char frombuf[MAXNAME]; | |
647 | extern char **prescan(); | |
648 | extern char *index(); | |
da6a9b77 | 649 | extern char *macvalue(); |
f65e7ded | 650 | |
dc39c568 | 651 | if (realname == NULL) |
2654b031 | 652 | realname = CurEnv->e_from.q_paddr; |
84b4028f EA |
653 | |
654 | # ifdef DEBUG | |
655 | if (Debug > 1) | |
656 | printf("setfrom(%s, %s)\n", from, realname); | |
657 | # endif DEBUG | |
658 | ||
1bcdf0a2 EA |
659 | /* |
660 | ** Do validation to determine whether this user is allowed | |
661 | ** to change the sender name. | |
662 | */ | |
663 | ||
f65e7ded EA |
664 | if (from != NULL) |
665 | { | |
46af5a18 EA |
666 | if (strcmp(realname, "network") != 0 && |
667 | strcmp(realname, "uucp") != 0 && | |
668 | strcmp(realname, "daemon") != 0 && | |
d829793b EA |
669 | # ifdef DEBUG |
670 | (Debug == 0 || getuid() != geteuid()) && | |
671 | # endif DEBUG | |
f65e7ded EA |
672 | index(from, '!') == NULL && getuid() != 0) |
673 | { | |
674 | /* network sends -r regardless (why why why?) */ | |
675 | /* syserr("%s, you cannot use the -f flag", realname); */ | |
676 | from = NULL; | |
677 | } | |
678 | } | |
679 | ||
1bcdf0a2 EA |
680 | /* |
681 | ** Parse the sender name. | |
682 | ** Arrange to send return messages to the same person. | |
683 | ** Set up some environment info. | |
684 | */ | |
685 | ||
f65e7ded | 686 | SuprErrs = TRUE; |
2654b031 | 687 | if (from == NULL || parse(from, &CurEnv->e_from, 1) == NULL) |
f65e7ded EA |
688 | { |
689 | from = newstr(realname); | |
2654b031 | 690 | (void) parse(from, &CurEnv->e_from, 1); |
f65e7ded EA |
691 | } |
692 | else | |
693 | FromFlag = TRUE; | |
1bcdf0a2 | 694 | CurEnv->e_returnto = &CurEnv->e_from; |
f65e7ded | 695 | SuprErrs = FALSE; |
2654b031 EA |
696 | CurEnv->e_from.q_uid = getuid(); |
697 | CurEnv->e_from.q_gid = getgid(); | |
1bf7c76b | 698 | # ifndef V6 |
2654b031 | 699 | CurEnv->e_from.q_home = getenv("HOME"); |
1bf7c76b | 700 | # endif V6 |
2654b031 | 701 | if (CurEnv->e_from.q_uid != 0) |
35cc3fad | 702 | { |
2654b031 EA |
703 | DefUid = CurEnv->e_from.q_uid; |
704 | DefGid = CurEnv->e_from.q_gid; | |
35cc3fad | 705 | } |
f65e7ded | 706 | |
d87a0dbb EA |
707 | /* |
708 | ** Set up the $r and $s macros to show who it came from. | |
709 | */ | |
710 | ||
da6a9b77 EA |
711 | if (macvalue('s') == NULL && CurEnv->e_from.q_host != NULL && |
712 | CurEnv->e_from.q_host[0] != '\0') | |
d87a0dbb | 713 | { |
2654b031 | 714 | define('s', CurEnv->e_from.q_host); |
d87a0dbb EA |
715 | |
716 | /* should determine network type here */ | |
717 | } | |
718 | ||
f65e7ded EA |
719 | /* |
720 | ** Rewrite the from person to dispose of possible implicit | |
721 | ** links in the net. | |
722 | */ | |
723 | ||
724 | pvp = prescan(from, '\0'); | |
725 | if (pvp == NULL) | |
726 | { | |
727 | syserr("cannot prescan from (%s)", from); | |
728 | finis(); | |
729 | } | |
730 | rewrite(pvp, 1); | |
31b33174 | 731 | cataddr(pvp, frombuf, sizeof frombuf); |
f65e7ded EA |
732 | define('f', newstr(frombuf)); |
733 | } | |
734 | \f/* | |
b3cbe40f EA |
735 | ** FINIS -- Clean up and exit. |
736 | ** | |
b3cbe40f EA |
737 | ** Parameters: |
738 | ** none | |
739 | ** | |
740 | ** Returns: | |
741 | ** never | |
742 | ** | |
743 | ** Side Effects: | |
96faada8 | 744 | ** exits sendmail |
b3cbe40f EA |
745 | */ |
746 | ||
747 | finis() | |
748 | { | |
3c7fe765 EA |
749 | CurEnv = &MainEnvelope; |
750 | ||
aba51985 | 751 | # ifdef DEBUG |
79bd7c07 | 752 | if (Debug > 0) |
3c7fe765 | 753 | { |
2654b031 EA |
754 | printf("\n====finis: stat %d sendreceipt %d FatalErrors %d\n", |
755 | ExitStat, CurEnv->e_sendreceipt, FatalErrors); | |
3c7fe765 | 756 | } |
aba51985 EA |
757 | # endif DEBUG |
758 | ||
79bd7c07 | 759 | /* send back return receipts as requested */ |
2654b031 | 760 | if (CurEnv->e_sendreceipt && ExitStat == EX_OK) |
f9566d23 | 761 | (void) returntosender("Return receipt", &CurEnv->e_from, FALSE); |
79bd7c07 | 762 | |
3c7fe765 EA |
763 | /* do error handling */ |
764 | checkerrors(CurEnv); | |
b3cbe40f | 765 | |
3c7fe765 | 766 | /* now clean up bookeeping information */ |
ed45aae1 | 767 | if (Transcript != NULL) |
29871fef | 768 | (void) unlink(Transcript); |
3c7fe765 | 769 | if (!CurEnv->e_queueup) |
1ff06f70 | 770 | (void) unlink(CurEnv->e_df); |
b3cbe40f EA |
771 | exit(ExitStat); |
772 | } | |
773 | \f/* | |
b3cbe40f EA |
774 | ** OPENXSCRPT -- Open transcript file |
775 | ** | |
776 | ** Creates a transcript file for possible eventual mailing or | |
777 | ** sending back. | |
778 | ** | |
779 | ** Parameters: | |
780 | ** none | |
781 | ** | |
782 | ** Returns: | |
783 | ** none | |
784 | ** | |
785 | ** Side Effects: | |
786 | ** Turns the standard output into a special file | |
787 | ** somewhere. | |
b3cbe40f EA |
788 | */ |
789 | ||
790 | openxscrpt() | |
791 | { | |
7b9c35c8 | 792 | extern char *mktemp(); |
49086753 | 793 | register char *p; |
7b9c35c8 | 794 | |
49086753 EA |
795 | p = newstr(XcriptFile); |
796 | (void) mktemp(p); | |
797 | Xscript = fopen(p, "w"); | |
798 | if (Xscript == NULL) | |
aba51985 | 799 | { |
49086753 EA |
800 | Xscript = stdout; |
801 | syserr("Can't create %s", p); | |
aba51985 | 802 | } |
49086753 EA |
803 | Transcript = p; |
804 | (void) chmod(p, 0600); | |
b3cbe40f | 805 | } |
cbdb7357 EA |
806 | \f/* |
807 | ** SETSENDER -- set sendmail's idea of the sender. | |
808 | ** | |
809 | ** Parameters: | |
810 | ** from -- the person we would like to believe this | |
811 | ** is from. | |
812 | ** | |
813 | ** Returns: | |
814 | ** none. | |
815 | ** | |
816 | ** Side Effects: | |
817 | ** Sets the idea of the sender. | |
818 | */ | |
819 | ||
820 | setsender(from) | |
821 | char *from; | |
822 | { | |
823 | register char *p; | |
824 | extern char *getlogin(); | |
825 | register struct passwd *pw; | |
826 | char *realname; | |
827 | char cfbuf[40]; | |
e863b1fa | 828 | bool nofullname; |
61bc683a | 829 | extern char *macvalue(); |
cbdb7357 EA |
830 | |
831 | /* | |
832 | ** Figure out the real user executing us. | |
833 | ** Getlogin can return errno != 0 on non-errors. | |
834 | */ | |
835 | ||
aba51985 | 836 | if (!Smtp && !QueueRun) |
cbdb7357 EA |
837 | { |
838 | errno = 0; | |
839 | p = getlogin(); | |
840 | errno = 0; | |
e863b1fa | 841 | nofullname = (from != NULL); |
cbdb7357 | 842 | } |
df7a9713 | 843 | else |
e863b1fa | 844 | { |
df7a9713 | 845 | p = from; |
e863b1fa EA |
846 | nofullname = FALSE; |
847 | } | |
110bf461 | 848 | if (p != NULL && p[0] != '\0') |
df7a9713 EA |
849 | { |
850 | extern struct passwd *getpwnam(); | |
851 | ||
852 | pw = getpwnam(p); | |
853 | if (pw == NULL) | |
854 | { | |
aba51985 | 855 | if (!Smtp && !QueueRun) |
df7a9713 EA |
856 | syserr("Who are you? (name=%s)", p); |
857 | p = NULL; | |
858 | } | |
859 | } | |
110bf461 | 860 | if (p == NULL || p[0] == '\0') |
cbdb7357 EA |
861 | { |
862 | extern struct passwd *getpwuid(); | |
863 | int uid; | |
864 | ||
e863b1fa | 865 | nofullname = TRUE; |
cbdb7357 EA |
866 | uid = getruid(); |
867 | pw = getpwuid(uid); | |
868 | if (pw == NULL) | |
869 | syserr("Who are you? (uid=%d)", uid); | |
870 | else | |
871 | p = pw->pw_name; | |
872 | } | |
cbdb7357 EA |
873 | if (p == NULL || p[0] == '\0' || pw == NULL) |
874 | finis(); | |
875 | ||
876 | realname = p; | |
877 | ||
878 | /* | |
879 | ** Process passwd file entry. | |
880 | */ | |
881 | ||
882 | /* run user's .mailcf file */ | |
883 | define('z', pw->pw_dir); | |
dd1fe05b | 884 | expand("$z/.mailcf", cfbuf, &cfbuf[sizeof cfbuf - 1], CurEnv); |
e863b1fa | 885 | if (!nofullname && safefile(cfbuf, getruid(), S_IREAD)) |
cbdb7357 EA |
886 | readcf(cfbuf, FALSE); |
887 | ||
61bc683a EA |
888 | /* if the user has given fullname already, don't redefine */ |
889 | if (FullName == NULL) | |
890 | FullName = macvalue('x'); | |
891 | ||
cbdb7357 | 892 | /* extract full name from passwd file */ |
e863b1fa | 893 | if (!nofullname && (FullName == NULL || FullName[0] == '\0') && |
cbdb7357 EA |
894 | pw != NULL && pw->pw_gecos != NULL) |
895 | { | |
896 | char nbuf[MAXNAME]; | |
897 | ||
abae7b2d | 898 | fullname(pw, nbuf); |
df7a9713 | 899 | if (nbuf[0] != '\0') |
cbdb7357 EA |
900 | FullName = newstr(nbuf); |
901 | } | |
902 | if (FullName != NULL && FullName[0] != '\0') | |
903 | define('x', FullName); | |
904 | ||
905 | setfrom(from, realname); | |
906 | } | |
ed45aae1 EA |
907 | \f/* |
908 | ** INITSYS -- initialize instantiation of system | |
909 | ** | |
910 | ** In Daemon mode, this is done in the child. | |
911 | ** | |
912 | ** Parameters: | |
913 | ** none. | |
914 | ** | |
915 | ** Returns: | |
916 | ** none. | |
917 | ** | |
918 | ** Side Effects: | |
919 | ** Initializes the system macros, some global variables, | |
920 | ** etc. In particular, the current time in various | |
921 | ** forms is set. | |
922 | */ | |
923 | ||
924 | initsys() | |
925 | { | |
926 | static char cbuf[5]; /* holds hop count */ | |
927 | static char dbuf[30]; /* holds ctime(tbuf) */ | |
928 | static char pbuf[10]; /* holds pid */ | |
929 | static char tbuf[10]; /* holds "current" time */ | |
930 | static char ybuf[10]; /* holds tty id */ | |
931 | register char *p; | |
932 | extern char *ttyname(); | |
933 | extern char *arpadate(); | |
ed45aae1 EA |
934 | |
935 | /* convert timeout interval to absolute time */ | |
aba51985 | 936 | TimeOut -= CurTime; |
ed45aae1 EA |
937 | (void) time(&CurTime); |
938 | TimeOut += CurTime; | |
939 | ||
940 | /* process id */ | |
941 | (void) sprintf(pbuf, "%d", getpid()); | |
942 | define('p', pbuf); | |
943 | ||
944 | /* hop count */ | |
945 | (void) sprintf(cbuf, "%d", HopCount); | |
946 | define('c', cbuf); | |
947 | ||
948 | /* time as integer, unix time, arpa time */ | |
949 | (void) sprintf(tbuf, "%ld", &CurTime); | |
950 | define('t', tbuf); | |
951 | (void) strcpy(dbuf, ctime(&CurTime)); | |
952 | *index(dbuf, '\n') = '\0'; | |
e863b1fa EA |
953 | if (macvalue('d') == NULL) |
954 | define('d', dbuf); | |
955 | p = newstr(arpadate(dbuf)); | |
956 | if (macvalue('a') == NULL) | |
957 | define('a', p); | |
ed45aae1 EA |
958 | define('b', p); |
959 | ||
960 | /* version */ | |
961 | define('v', Version); | |
962 | ||
963 | /* tty name */ | |
e863b1fa | 964 | if (macvalue('y') == NULL) |
ed45aae1 | 965 | { |
e863b1fa EA |
966 | p = ttyname(2); |
967 | if (p != NULL) | |
968 | { | |
969 | if (rindex(p, '/') != NULL) | |
970 | p = rindex(p, '/') + 1; | |
f9566d23 | 971 | (void) strcpy(ybuf, p); |
e863b1fa EA |
972 | define('y', ybuf); |
973 | } | |
ed45aae1 EA |
974 | } |
975 | } | |
721fad23 EA |
976 | \f/* |
977 | ** INITMACROS -- initialize the macro system | |
978 | ** | |
979 | ** This just involves defining some macros that are actually | |
980 | ** used internally as metasymbols to be themselves. | |
981 | ** | |
982 | ** Parameters: | |
983 | ** none. | |
984 | ** | |
985 | ** Returns: | |
986 | ** none. | |
987 | ** | |
988 | ** Side Effects: | |
989 | ** initializes several macros to be themselves. | |
990 | */ | |
991 | ||
9dbc8d99 | 992 | struct metamac |
721fad23 | 993 | { |
9dbc8d99 EA |
994 | char metaname; |
995 | char metaval; | |
996 | }; | |
721fad23 | 997 | |
9dbc8d99 EA |
998 | struct metamac MetaMacros[] = |
999 | { | |
721fad23 | 1000 | /* these are important on the LHS */ |
9dbc8d99 | 1001 | '+', MATCHANY, '-', MATCHONE, '=', MATCHCLASS, |
721fad23 EA |
1002 | |
1003 | /* these are RHS metasymbols */ | |
9dbc8d99 | 1004 | '#', CANONNET, '@', CANONHOST, ':', CANONUSER, |
721fad23 | 1005 | |
9dbc8d99 EA |
1006 | /* and finally the conditional operations */ |
1007 | '?', CONDIF, '|', CONDELSE, '.', CONDFI, | |
1008 | ||
1009 | '\0' | |
721fad23 EA |
1010 | }; |
1011 | ||
1012 | initmacros() | |
1013 | { | |
9dbc8d99 EA |
1014 | register struct metamac *m; |
1015 | char buf[5]; | |
1016 | register int c; | |
721fad23 | 1017 | |
9dbc8d99 EA |
1018 | for (m = MetaMacros; m->metaname != '\0'; m++) |
1019 | { | |
1020 | buf[0] = m->metaval; | |
1021 | buf[1] = '\0'; | |
1022 | define(m->metaname, newstr(buf)); | |
1023 | } | |
1024 | buf[0] = MATCHREPL; | |
1025 | buf[2] = '\0'; | |
1026 | for (c = '0'; c <= '9'; c++) | |
1027 | { | |
1028 | buf[1] = c; | |
1029 | define(c, newstr(buf)); | |
1030 | } | |
721fad23 | 1031 | } |
dd1fe05b EA |
1032 | \f/* |
1033 | ** NEWENVELOPE -- allocate a new envelope | |
1034 | ** | |
1035 | ** Supports inheritance. | |
1036 | ** | |
1037 | ** Parameters: | |
1038 | ** e -- the new envelope to fill in. | |
1039 | ** | |
1040 | ** Returns: | |
1041 | ** e. | |
1042 | ** | |
1043 | ** Side Effects: | |
1044 | ** none. | |
1045 | */ | |
1046 | ||
1047 | ENVELOPE * | |
1048 | newenvelope(e) | |
1049 | register ENVELOPE *e; | |
1050 | { | |
f9566d23 | 1051 | bmove((char *) CurEnv, (char *) e, sizeof *e); |
dd1fe05b EA |
1052 | e->e_header = NULL; |
1053 | e->e_queueup = FALSE; | |
1054 | e->e_oldstyle = FALSE; | |
1055 | e->e_retreceipt = FALSE; | |
1056 | e->e_sendreceipt = FALSE; | |
1057 | e->e_origfrom = NULL; | |
1058 | e->e_to = NULL; | |
1059 | e->e_sendqueue = NULL; | |
3c7fe765 | 1060 | e->e_errorqueue = NULL; |
dd1fe05b EA |
1061 | e->e_parent = CurEnv; |
1062 | e->e_df = NULL; | |
1ff06f70 EA |
1063 | |
1064 | return (e); | |
dd1fe05b | 1065 | } |