This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.sbin / sendmail / src / envelope.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1983 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36static char sccsid[] = "@(#)envelope.c 8.3 (Berkeley) 7/13/93";
37#endif /* not lint */
38
39#include "sendmail.h"
40#include <sys/time.h>
41#include <pwd.h>
42
43/*
44** NEWENVELOPE -- allocate a new envelope
45**
46** Supports inheritance.
47**
48** Parameters:
49** e -- the new envelope to fill in.
50** parent -- the envelope to be the parent of e.
51**
52** Returns:
53** e.
54**
55** Side Effects:
56** none.
57*/
58
59ENVELOPE *
60newenvelope(e, parent)
61 register ENVELOPE *e;
62 register ENVELOPE *parent;
63{
64 extern putheader(), putbody();
65 extern ENVELOPE BlankEnvelope;
66
67 if (e == parent && e->e_parent != NULL)
68 parent = e->e_parent;
69 clearenvelope(e, TRUE);
70 if (e == CurEnv)
71 bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from);
72 else
73 bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
74 e->e_parent = parent;
75 e->e_ctime = curtime();
76 if (parent != NULL)
77 e->e_msgpriority = parent->e_msgsize;
78 e->e_puthdr = putheader;
79 e->e_putbody = putbody;
80 if (CurEnv->e_xfp != NULL)
81 (void) fflush(CurEnv->e_xfp);
82
83 return (e);
84}
85\f/*
86** DROPENVELOPE -- deallocate an envelope.
87**
88** Parameters:
89** e -- the envelope to deallocate.
90**
91** Returns:
92** none.
93**
94** Side Effects:
95** housekeeping necessary to dispose of an envelope.
96** Unlocks this queue file.
97*/
98
99void
100dropenvelope(e)
101 register ENVELOPE *e;
102{
103 bool queueit = FALSE;
104 register ADDRESS *q;
105 char *id = e->e_id;
106 char buf[MAXLINE];
107
108 if (tTd(50, 1))
109 {
110 printf("dropenvelope %x: id=", e);
111 xputs(e->e_id);
112 printf(", flags=%o\n", e->e_flags);
113 if (tTd(50, 10))
114 {
115 printf("sendq=");
116 printaddr(e->e_sendqueue, TRUE);
117 }
118 }
119
120 /* we must have an id to remove disk files */
121 if (id == NULL)
122 return;
123
124#ifdef LOG
125 if (LogLevel > 84)
126 syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d",
127 id, e->e_flags, getpid());
128#endif /* LOG */
129
130 /* post statistics */
131 poststats(StatFile);
132
133 /*
134 ** Extract state information from dregs of send list.
135 */
136
137 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
138 {
139 if (bitset(QQUEUEUP, q->q_flags))
140 queueit = TRUE;
141 }
142
143 /*
144 ** See if the message timed out.
145 */
146
147 if (!queueit)
148 /* nothing to do */ ;
149 else if (curtime() > e->e_ctime + TimeOuts.to_q_return)
150 {
151 if (!bitset(EF_TIMEOUT, e->e_flags))
152 {
153 (void) sprintf(buf, "Cannot send message for %s",
154 pintvl(TimeOuts.to_q_return, FALSE));
155 if (e->e_message != NULL)
156 free(e->e_message);
157 e->e_message = newstr(buf);
158 message(buf);
159 }
160 e->e_flags |= EF_TIMEOUT|EF_CLRQUEUE;
161 fprintf(e->e_xfp, "Message could not be delivered for %s\n",
162 pintvl(TimeOuts.to_q_return, FALSE));
163 fprintf(e->e_xfp, "Message will be deleted from queue\n");
164 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
165 {
166 if (bitset(QQUEUEUP, q->q_flags))
167 q->q_flags |= QBADADDR;
168 }
169 }
170 else if (TimeOuts.to_q_warning > 0 &&
171 curtime() > e->e_ctime + TimeOuts.to_q_warning)
172 {
173 if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
174 e->e_class >= 0 &&
175 strcmp(e->e_from.q_paddr, "<>") != 0)
176 {
177 (void) sprintf(buf,
178 "warning: cannot send message for %s",
179 pintvl(TimeOuts.to_q_warning, FALSE));
180 if (e->e_message != NULL)
181 free(e->e_message);
182 e->e_message = newstr(buf);
183 message(buf);
184 e->e_flags |= EF_WARNING|EF_TIMEOUT;
185 }
186 fprintf(e->e_xfp,
187 "Warning: message still undelivered after %s\n",
188 pintvl(TimeOuts.to_q_warning, FALSE));
189 fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
190 pintvl(TimeOuts.to_q_return, FALSE));
191 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
192 {
193 if (bitset(QQUEUEUP, q->q_flags))
194 q->q_flags |= QREPORT;
195 }
196 }
197
198 /*
199 ** Send back return receipts as requested.
200 */
201
202 if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags))
203 {
204 auto ADDRESS *rlist = NULL;
205
206 (void) sendtolist(e->e_receiptto, (ADDRESS *) NULL, &rlist, e);
207 (void) returntosender("Return receipt", rlist, FALSE, e);
208 }
209
210 /*
211 ** Arrange to send error messages if there are fatal errors.
212 */
213
214 if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) &&
215 e->e_errormode != EM_QUIET)
216 savemail(e);
217
218 /*
219 ** Instantiate or deinstantiate the queue.
220 */
221
222 if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
223 bitset(EF_CLRQUEUE, e->e_flags))
224 {
225 if (tTd(50, 2))
226 printf("Dropping envelope\n");
227 if (e->e_df != NULL)
228 xunlink(e->e_df);
229 xunlink(queuename(e, 'q'));
230 }
231 else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
232 {
233#ifdef QUEUE
234 queueup(e, FALSE, FALSE);
235#else /* QUEUE */
236 syserr("554 dropenvelope: queueup");
237#endif /* QUEUE */
238 }
239
240 /* now unlock the job */
241 closexscript(e);
242 unlockqueue(e);
243
244 /* make sure that this envelope is marked unused */
245 if (e->e_dfp != NULL)
246 (void) xfclose(e->e_dfp, "dropenvelope", e->e_df);
247 e->e_dfp = NULL;
248 e->e_id = e->e_df = NULL;
249
250#ifdef LOG
251 if (LogLevel > 74)
252 syslog(LOG_INFO, "%s: done", id);
253#endif /* LOG */
254}
255\f/*
256** CLEARENVELOPE -- clear an envelope without unlocking
257**
258** This is normally used by a child process to get a clean
259** envelope without disturbing the parent.
260**
261** Parameters:
262** e -- the envelope to clear.
263** fullclear - if set, the current envelope is total
264** garbage and should be ignored; otherwise,
265** release any resources it may indicate.
266**
267** Returns:
268** none.
269**
270** Side Effects:
271** Closes files associated with the envelope.
272** Marks the envelope as unallocated.
273*/
274
275void
276clearenvelope(e, fullclear)
277 register ENVELOPE *e;
278 bool fullclear;
279{
280 register HDR *bh;
281 register HDR **nhp;
282 extern ENVELOPE BlankEnvelope;
283
284 if (!fullclear)
285 {
286 /* clear out any file information */
287 if (e->e_xfp != NULL)
288 (void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id);
289 if (e->e_dfp != NULL)
290 (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_df);
291 e->e_xfp = e->e_dfp = NULL;
292 }
293
294 /* now clear out the data */
295 STRUCTCOPY(BlankEnvelope, *e);
296 if (Verbose)
297 e->e_sendmode = SM_DELIVER;
298 bh = BlankEnvelope.e_header;
299 nhp = &e->e_header;
300 while (bh != NULL)
301 {
302 *nhp = (HDR *) xalloc(sizeof *bh);
303 bcopy((char *) bh, (char *) *nhp, sizeof *bh);
304 bh = bh->h_link;
305 nhp = &(*nhp)->h_link;
306 }
307}
308\f/*
309** INITSYS -- initialize instantiation of system
310**
311** In Daemon mode, this is done in the child.
312**
313** Parameters:
314** none.
315**
316** Returns:
317** none.
318**
319** Side Effects:
320** Initializes the system macros, some global variables,
321** etc. In particular, the current time in various
322** forms is set.
323*/
324
325void
326initsys(e)
327 register ENVELOPE *e;
328{
329 static char cbuf[5]; /* holds hop count */
330 static char pbuf[10]; /* holds pid */
331#ifdef TTYNAME
332 static char ybuf[60]; /* holds tty id */
333 register char *p;
334#endif /* TTYNAME */
335 extern char *ttyname();
336 extern void settime();
337 extern char Version[];
338
339 /*
340 ** Give this envelope a reality.
341 ** I.e., an id, a transcript, and a creation time.
342 */
343
344 openxscript(e);
345 e->e_ctime = curtime();
346
347 /*
348 ** Set OutChannel to something useful if stdout isn't it.
349 ** This arranges that any extra stuff the mailer produces
350 ** gets sent back to the user on error (because it is
351 ** tucked away in the transcript).
352 */
353
354 if (OpMode == MD_DAEMON && !bitset(EF_QUEUERUN, e->e_flags) &&
355 e->e_xfp != NULL)
356 OutChannel = e->e_xfp;
357
358 /*
359 ** Set up some basic system macros.
360 */
361
362 /* process id */
363 (void) sprintf(pbuf, "%d", getpid());
364 define('p', pbuf, e);
365
366 /* hop count */
367 (void) sprintf(cbuf, "%d", e->e_hopcount);
368 define('c', cbuf, e);
369
370 /* time as integer, unix time, arpa time */
371 settime(e);
372
373#ifdef TTYNAME
374 /* tty name */
375 if (macvalue('y', e) == NULL)
376 {
377 p = ttyname(2);
378 if (p != NULL)
379 {
380 if (strrchr(p, '/') != NULL)
381 p = strrchr(p, '/') + 1;
382 (void) strcpy(ybuf, p);
383 define('y', ybuf, e);
384 }
385 }
386#endif /* TTYNAME */
387}
388\f/*
389** SETTIME -- set the current time.
390**
391** Parameters:
392** none.
393**
394** Returns:
395** none.
396**
397** Side Effects:
398** Sets the various time macros -- $a, $b, $d, $t.
399*/
400
401void
402settime(e)
403 register ENVELOPE *e;
404{
405 register char *p;
406 auto time_t now;
407 static char tbuf[20]; /* holds "current" time */
408 static char dbuf[30]; /* holds ctime(tbuf) */
409 register struct tm *tm;
410 extern char *arpadate();
411 extern struct tm *gmtime();
412
413 now = curtime();
414 tm = gmtime(&now);
415 (void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
416 tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
417 define('t', tbuf, e);
418 (void) strcpy(dbuf, ctime(&now));
419 p = strchr(dbuf, '\n');
420 if (p != NULL)
421 *p = '\0';
422 define('d', dbuf, e);
423 p = newstr(arpadate(dbuf));
424 if (macvalue('a', e) == NULL)
425 define('a', p, e);
426 define('b', p, e);
427}
428\f/*
429** OPENXSCRIPT -- Open transcript file
430**
431** Creates a transcript file for possible eventual mailing or
432** sending back.
433**
434** Parameters:
435** e -- the envelope to create the transcript in/for.
436**
437** Returns:
438** none
439**
440** Side Effects:
441** Creates the transcript file.
442*/
443
444#ifndef O_APPEND
445#define O_APPEND 0
446#endif
447
448void
449openxscript(e)
450 register ENVELOPE *e;
451{
452 register char *p;
453 int fd;
454
455 if (e->e_xfp != NULL)
456 return;
457 p = queuename(e, 'x');
458 fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644);
459 if (fd < 0)
460 {
461 syserr("Can't create transcript file %s", p);
462 fd = open("/dev/null", O_WRONLY, 0644);
463 if (fd < 0)
464 syserr("!Can't open /dev/null");
465 }
466 e->e_xfp = fdopen(fd, "w");
467}
468\f/*
469** CLOSEXSCRIPT -- close the transcript file.
470**
471** Parameters:
472** e -- the envelope containing the transcript to close.
473**
474** Returns:
475** none.
476**
477** Side Effects:
478** none.
479*/
480
481void
482closexscript(e)
483 register ENVELOPE *e;
484{
485 if (e->e_xfp == NULL)
486 return;
487 (void) xfclose(e->e_xfp, "closexscript", e->e_id);
488 e->e_xfp = NULL;
489}
490\f/*
491** SETSENDER -- set the person who this message is from
492**
493** Under certain circumstances allow the user to say who
494** s/he is (using -f or -r). These are:
495** 1. The user's uid is zero (root).
496** 2. The user's login name is in an approved list (typically
497** from a network server).
498** 3. The address the user is trying to claim has a
499** "!" character in it (since #2 doesn't do it for
500** us if we are dialing out for UUCP).
501** A better check to replace #3 would be if the
502** effective uid is "UUCP" -- this would require me
503** to rewrite getpwent to "grab" uucp as it went by,
504** make getname more nasty, do another passwd file
505** scan, or compile the UID of "UUCP" into the code,
506** all of which are reprehensible.
507**
508** Assuming all of these fail, we figure out something
509** ourselves.
510**
511** Parameters:
512** from -- the person we would like to believe this message
513** is from, as specified on the command line.
514** e -- the envelope in which we would like the sender set.
515** delimptr -- if non-NULL, set to the location of the
516** trailing delimiter.
517** internal -- set if this address is coming from an internal
518** source such as an owner alias.
519**
520** Returns:
521** none.
522**
523** Side Effects:
524** sets sendmail's notion of who the from person is.
525*/
526
527void
528setsender(from, e, delimptr, internal)
529 char *from;
530 register ENVELOPE *e;
531 char **delimptr;
532 bool internal;
533{
534 register char **pvp;
535 char *realname = NULL;
536 register struct passwd *pw;
537 char delimchar;
538 char buf[MAXNAME];
539 char pvpbuf[PSBUFSIZE];
540 extern struct passwd *getpwnam();
541 extern char *FullName;
542
543 if (tTd(45, 1))
544 printf("setsender(%s)\n", from == NULL ? "" : from);
545
546 /*
547 ** Figure out the real user executing us.
548 ** Username can return errno != 0 on non-errors.
549 */
550
551 if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP)
552 realname = from;
553 if (realname == NULL || realname[0] == '\0')
554 realname = username();
555
556 if (ConfigLevel < 2)
557 SuprErrs = TRUE;
558
559 delimchar = internal ? '\0' : ' ';
560 if (from == NULL ||
561 parseaddr(from, &e->e_from, 1, delimchar, delimptr, e) == NULL)
562 {
563 /* log garbage addresses for traceback */
564# ifdef LOG
565 if (from != NULL && LogLevel > 2)
566 {
567 char *p;
568 char ebuf[MAXNAME * 2 + 2];
569
570 p = macvalue('_', e);
571 if (p == NULL)
572 {
573 char *host = RealHostName;
574 if (host == NULL)
575 host = MyHostName;
576 (void) sprintf(ebuf, "%s@%s", realname, host);
577 p = ebuf;
578 }
579 syslog(LOG_NOTICE,
580 "from=%s unparseable, received from %s",
581 from, p);
582 }
583# endif /* LOG */
584 if (from != NULL)
585 SuprErrs = TRUE;
586 if (from == realname ||
587 parseaddr(from = newstr(realname), &e->e_from, 1, ' ', NULL, e) == NULL)
588 {
589 SuprErrs = TRUE;
590 if (parseaddr("postmaster", &e->e_from, 1, ' ', NULL, e) == NULL)
591 syserr("553 setsender: can't even parse postmaster!");
592 }
593 }
594 else
595 FromFlag = TRUE;
596 e->e_from.q_flags |= QDONTSEND;
597 if (tTd(45, 5))
598 {
599 printf("setsender: QDONTSEND ");
600 printaddr(&e->e_from, FALSE);
601 }
602 SuprErrs = FALSE;
603
604 pvp = NULL;
605 if (e->e_from.q_mailer == LocalMailer)
606 {
607# ifdef USERDB
608 register char *p;
609 extern char *udbsender();
610# endif
611
612 if (!internal)
613 {
614 /* if the user has given fullname already, don't redefine */
615 if (FullName == NULL)
616 FullName = macvalue('x', e);
617 if (FullName != NULL && FullName[0] == '\0')
618 FullName = NULL;
619
620# ifdef USERDB
621 p = udbsender(from);
622
623 if (p != NULL)
624 {
625 /*
626 ** We have an alternate address for the sender
627 */
628
629 pvp = prescan(p, '\0', pvpbuf, NULL);
630 }
631# endif /* USERDB */
632 }
633
634 if ((pw = getpwnam(e->e_from.q_user)) != NULL)
635 {
636 /*
637 ** Process passwd file entry.
638 */
639
640
641 /* extract home directory */
642 e->e_from.q_home = newstr(pw->pw_dir);
643 define('z', e->e_from.q_home, e);
644
645 /* extract user and group id */
646 e->e_from.q_uid = pw->pw_uid;
647 e->e_from.q_gid = pw->pw_gid;
648
649 /* extract full name from passwd file */
650 if (FullName == NULL && pw->pw_gecos != NULL &&
651 strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
652 !internal)
653 {
654 buildfname(pw->pw_gecos, e->e_from.q_user, buf);
655 if (buf[0] != '\0')
656 FullName = newstr(buf);
657 }
658 }
659 if (FullName != NULL && !internal)
660 define('x', FullName, e);
661 }
662 else if (!internal)
663 {
664 if (e->e_from.q_home == NULL)
665 e->e_from.q_home = getenv("HOME");
666 e->e_from.q_uid = RealUid;
667 e->e_from.q_gid = RealGid;
668 }
669
670 /*
671 ** Rewrite the from person to dispose of possible implicit
672 ** links in the net.
673 */
674
675 if (pvp == NULL)
676 pvp = prescan(from, '\0', pvpbuf, NULL);
677 if (pvp == NULL)
678 {
679 /* don't need to give error -- prescan did that already */
680# ifdef LOG
681 if (LogLevel > 2)
682 syslog(LOG_NOTICE, "cannot prescan from (%s)", from);
683# endif
684 finis();
685 }
686 (void) rewrite(pvp, 3, e);
687 (void) rewrite(pvp, 1, e);
688 (void) rewrite(pvp, 4, e);
689 cataddr(pvp, NULL, buf, sizeof buf, '\0');
690 e->e_sender = newstr(buf);
691 define('f', e->e_sender, e);
692
693 /* save the domain spec if this mailer wants it */
694 if (!internal && e->e_from.q_mailer != NULL &&
695 bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
696 {
697 extern char **copyplist();
698
699 while (*pvp != NULL && strcmp(*pvp, "@") != 0)
700 pvp++;
701 if (*pvp != NULL)
702 e->e_fromdomain = copyplist(pvp, TRUE);
703 }
704}