Pass the delimiter character to parseaddr so that we can correctly
[unix-history] / usr / src / usr.sbin / sendmail / src / envelope.c
CommitLineData
c6f91078
EA
1#include <pwd.h>
2#include <time.h>
3#include "sendmail.h"
4#include <sys/stat.h>
5
d3f52e20 6SCCSID(@(#)envelope.c 3.12 %G%);
c6f91078
EA
7
8/*
9** NEWENVELOPE -- allocate a new envelope
10**
11** Supports inheritance.
12**
13** Parameters:
14** e -- the new envelope to fill in.
15**
16** Returns:
17** e.
18**
19** Side Effects:
20** none.
21*/
22
23ENVELOPE *
24newenvelope(e)
25 register ENVELOPE *e;
26{
27 register HDR *bh;
28 register HDR **nhp;
29 register ENVELOPE *parent;
30 extern putheader(), putbody();
31 extern ENVELOPE BlankEnvelope;
32
33 parent = CurEnv;
34 if (e == CurEnv)
35 parent = e->e_parent;
36 clear((char *) e, sizeof *e);
37 bmove((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
38 e->e_parent = parent;
39 e->e_ctime = curtime();
40 e->e_puthdr = putheader;
41 e->e_putbody = putbody;
42 bh = BlankEnvelope.e_header;
43 nhp = &e->e_header;
44 while (bh != NULL)
45 {
46 *nhp = (HDR *) xalloc(sizeof *bh);
47 bmove((char *) bh, (char *) *nhp, sizeof *bh);
48 bh = bh->h_link;
49 nhp = &(*nhp)->h_link;
50 }
51 if (CurEnv->e_xfp != NULL)
52 (void) fflush(CurEnv->e_xfp);
53
54 return (e);
55}
56\f/*
57** DROPENVELOPE -- deallocate an envelope.
58**
59** Parameters:
60** e -- the envelope to deallocate.
61**
62** Returns:
63** none.
64**
65** Side Effects:
66** housekeeping necessary to dispose of an envelope.
67** Unlocks this queue file.
68*/
69
70dropenvelope(e)
71 register ENVELOPE *e;
72{
73 bool queueit = FALSE;
74 register ADDRESS *q;
75
76#ifdef DEBUG
77 if (tTd(50, 1))
78 {
79 printf("dropenvelope %x id=", e);
80 xputs(e->e_id);
81 printf(" flags=%o\n", e->e_flags);
82 }
83#endif DEBUG
84#ifdef LOG
85 if (LogLevel > 10)
86 syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d",
87 e->e_id == NULL ? "(none)" : e->e_id,
88 e->e_flags, getpid());
89#endif LOG
90
91 /* we must have an id to remove disk files */
92 if (e->e_id == NULL)
93 return;
94
95 /*
96 ** Extract state information from dregs of send list.
97 */
98
99 for (q = e->e_sendqueue; q != NULL; q = q->q_next)
100 {
101 if (bitset(QQUEUEUP, q->q_flags))
102 queueit = TRUE;
103 }
104
105 /*
106 ** Send back return receipts as requested.
107 */
108
109 if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags))
110 {
e7d41cfe 111 auto ADDRESS *rlist = NULL;
c6f91078 112
811a6cf3 113 sendtolist(CurEnv->e_receiptto, (ADDRESS *) NULL, &rlist);
c6f91078
EA
114 (void) returntosender("Return receipt", rlist, FALSE);
115 }
116
c6f91078
EA
117 /*
118 ** Arrange to send error messages if there are fatal errors.
119 */
120
2ec2faaa 121 if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && ErrorMode != EM_QUIET)
c6f91078
EA
122 savemail(e);
123
124 /*
125 ** Instantiate or deinstantiate the queue.
126 */
127
128 if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
129 bitset(EF_CLRQUEUE, e->e_flags))
130 {
131 if (e->e_dfp != NULL)
132 (void) fclose(e->e_dfp);
133 if (e->e_df != NULL)
134 xunlink(e->e_df);
135 xunlink(queuename(e, 'q'));
136 }
137 else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
2ec2faaa
EA
138 {
139#ifdef QUEUE
c6f91078 140 queueup(e, FALSE, FALSE);
2ec2faaa
EA
141#else QUEUE
142 syserr("dropenvelope: queueup");
143#endif QUEUE
144 }
c6f91078
EA
145
146 /* now unlock the job */
bcf74f25 147 closexscript(e);
c6f91078
EA
148 unlockqueue(e);
149
150 /* make sure that this envelope is marked unused */
151 e->e_id = e->e_df = NULL;
bcf74f25 152 e->e_dfp = NULL;
c6f91078
EA
153}
154\f/*
155** CLEARENVELOPE -- clear an envelope without unlocking
156**
157** This is normally used by a child process to get a clean
158** envelope without disturbing the parent.
159**
160** Parameters:
161** e -- the envelope to clear.
162**
163** Returns:
164** none.
165**
166** Side Effects:
167** Closes files associated with the envelope.
168** Marks the envelope as unallocated.
169*/
170
171clearenvelope(e)
172 register ENVELOPE *e;
173{
174 /* clear out any file information */
175 if (e->e_xfp != NULL)
176 (void) fclose(e->e_xfp);
177 if (e->e_dfp != NULL)
178 (void) fclose(e->e_dfp);
179 e->e_xfp = e->e_dfp = NULL;
180
181 /* now expunge names of objects */
182 e->e_df = e->e_id = NULL;
183
184 /* and the flags which are now meaningless */
185 e->e_flags = 0;
186}
187\f/*
188** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
189**
190** Parameters:
191** e -- the envelope to unlock.
192**
193** Returns:
194** none
195**
196** Side Effects:
197** unlocks the queue for `e'.
198*/
199
200unlockqueue(e)
201 ENVELOPE *e;
202{
203 /* remove the transcript */
204#ifdef DEBUG
bcf74f25
EA
205# ifdef LOG
206 if (LogLevel > 19)
207 syslog(LOG_DEBUG, "%s: unlock", e->e_id);
208# endif LOG
c6f91078
EA
209 if (!tTd(51, 4))
210#endif DEBUG
211 xunlink(queuename(e, 'x'));
212
2ec2faaa 213# ifdef QUEUE
c6f91078
EA
214 /* last but not least, remove the lock */
215 xunlink(queuename(e, 'l'));
2ec2faaa 216# endif QUEUE
c6f91078
EA
217}
218\f/*
219** INITSYS -- initialize instantiation of system
220**
221** In Daemon mode, this is done in the child.
222**
223** Parameters:
224** none.
225**
226** Returns:
227** none.
228**
229** Side Effects:
230** Initializes the system macros, some global variables,
231** etc. In particular, the current time in various
232** forms is set.
233*/
234
235initsys()
236{
237 auto time_t now;
238 static char cbuf[5]; /* holds hop count */
239 static char dbuf[30]; /* holds ctime(tbuf) */
240 static char pbuf[10]; /* holds pid */
241 static char tbuf[20]; /* holds "current" time */
242 static char ybuf[10]; /* holds tty id */
243 register char *p;
244 register struct tm *tm;
245 extern char *ttyname();
246 extern char *arpadate();
247 extern struct tm *gmtime();
248 extern char *macvalue();
249 extern char Version[];
250
251 /*
252 ** Give this envelope a reality.
253 ** I.e., an id, a transcript, and a creation time.
254 */
255
256 openxscript(CurEnv);
257 CurEnv->e_ctime = curtime();
258
259 /*
260 ** Set OutChannel to something useful if stdout isn't it.
261 ** This arranges that any extra stuff the mailer produces
262 ** gets sent back to the user on error (because it is
263 ** tucked away in the transcript).
264 */
265
266 if (OpMode == MD_DAEMON && QueueRun)
267 OutChannel = CurEnv->e_xfp;
268
269 /*
270 ** Set up some basic system macros.
271 */
272
273 /* process id */
274 (void) sprintf(pbuf, "%d", getpid());
275 define('p', pbuf, CurEnv);
276
277 /* hop count */
278 (void) sprintf(cbuf, "%d", CurEnv->e_hopcount);
279 define('c', cbuf, CurEnv);
280
281 /* time as integer, unix time, arpa time */
282 now = curtime();
283 tm = gmtime(&now);
378e8da7 284 (void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1,
c6f91078
EA
285 tm->tm_mday, tm->tm_hour, tm->tm_min);
286 define('t', tbuf, CurEnv);
287 (void) strcpy(dbuf, ctime(&now));
288 *index(dbuf, '\n') = '\0';
289 if (macvalue('d', CurEnv) == NULL)
290 define('d', dbuf, CurEnv);
291 p = newstr(arpadate(dbuf));
292 if (macvalue('a', CurEnv) == NULL)
293 define('a', p, CurEnv);
294 define('b', p, CurEnv);
295
c6f91078
EA
296 /* tty name */
297 if (macvalue('y', CurEnv) == NULL)
298 {
299 p = ttyname(2);
300 if (p != NULL)
301 {
302 if (rindex(p, '/') != NULL)
303 p = rindex(p, '/') + 1;
304 (void) strcpy(ybuf, p);
305 define('y', ybuf, CurEnv);
306 }
307 }
308}
309\f/*
310** QUEUENAME -- build a file name in the queue directory for this envelope.
311**
312** Assigns an id code if one does not already exist.
313** This code is very careful to avoid trashing existing files
314** under any circumstances.
315** We first create an nf file that is only used when
316** assigning an id. This file is always empty, so that
317** we can never accidently truncate an lf file.
318**
319** Parameters:
320** e -- envelope to build it in/from.
321** type -- the file type, used as the first character
322** of the file name.
323**
324** Returns:
325** a pointer to the new file name (in a static buffer).
326**
327** Side Effects:
328** Will create the lf and qf files if no id code is
329** already assigned. This will cause the envelope
330** to be modified.
331*/
332
333char *
334queuename(e, type)
335 register ENVELOPE *e;
336 char type;
337{
338 static char buf[MAXNAME];
339 static int pid = -1;
340 char c1 = 'A';
341 char c2 = 'A';
342
343 if (e->e_id == NULL)
344 {
345 char qf[20];
346 char lf[20];
347 char nf[20];
348
349 /* find a unique id */
350 if (pid != getpid())
351 {
352 /* new process -- start back at "AA" */
353 pid = getpid();
354 c1 = 'A';
355 c2 = 'A' - 1;
356 }
357 (void) sprintf(qf, "qfAA%05d", pid);
358 strcpy(lf, qf);
359 lf[0] = 'l';
360 strcpy(nf, qf);
361 nf[0] = 'n';
362
363 while (c1 < '~' || c2 < 'Z')
364 {
365 int i;
366
367 if (c2 >= 'Z')
368 {
369 c1++;
370 c2 = 'A' - 1;
371 }
372 qf[2] = lf[2] = nf[2] = c1;
373 qf[3] = lf[3] = nf[3] = ++c2;
374# ifdef DEBUG
375 if (tTd(7, 20))
376 printf("queuename: trying \"%s\"\n", nf);
377# endif DEBUG
2ec2faaa 378# ifdef QUEUE
c6f91078
EA
379 if (access(lf, 0) >= 0 || access(qf, 0) >= 0)
380 continue;
381 errno = 0;
382 i = creat(nf, FileMode);
383 if (i < 0)
384 {
385 (void) unlink(nf); /* kernel bug */
386 continue;
387 }
388 (void) close(i);
389 i = link(nf, lf);
390 (void) unlink(nf);
391 if (i < 0)
392 continue;
393 if (link(lf, qf) >= 0)
394 break;
395 (void) unlink(lf);
2ec2faaa
EA
396# else QUEUE
397 if (close(creat(qf, FileMode)) < 0)
398 continue;
399# endif QUEUE
c6f91078
EA
400 }
401 if (c1 >= '~' && c2 >= 'Z')
402 {
403 syserr("queuename: Cannot create \"%s\" in \"%s\"",
404 lf, QueueDir);
405 exit(EX_OSERR);
406 }
407 e->e_id = newstr(&qf[2]);
408 define('i', e->e_id, e);
409# ifdef DEBUG
410 if (tTd(7, 1))
411 printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
bcf74f25
EA
412# ifdef LOG
413 if (LogLevel > 16)
414 syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
415# endif LOG
c6f91078
EA
416# endif DEBUG
417 }
418
419 if (type == '\0')
420 return (NULL);
421 (void) sprintf(buf, "%cf%s", type, e->e_id);
422# ifdef DEBUG
423 if (tTd(7, 2))
424 printf("queuename: %s\n", buf);
425# endif DEBUG
426 return (buf);
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
444openxscript(e)
445 register ENVELOPE *e;
446{
447 register char *p;
448
bcf74f25
EA
449# ifdef LOG
450 if (LogLevel > 19)
451 syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)");
452# endif LOG
c6f91078
EA
453 if (e->e_xfp != NULL)
454 return;
455 p = queuename(e, 'x');
456 e->e_xfp = fopen(p, "w");
457 if (e->e_xfp == NULL)
458 syserr("Can't create %s", p);
459 else
460 (void) chmod(p, 0644);
461}
462\f/*
bcf74f25
EA
463** CLOSEXSCRIPT -- close the transcript file.
464**
465** Parameters:
466** e -- the envelope containing the transcript to close.
467**
468** Returns:
469** none.
470**
471** Side Effects:
472** none.
473*/
474
475closexscript(e)
476 register ENVELOPE *e;
477{
478 if (e->e_xfp == NULL)
479 return;
480 (void) fclose(e->e_xfp);
481 e->e_xfp = NULL;
482}
483\f/*
c6f91078
EA
484** SETSENDER -- set the person who this message is from
485**
486** Under certain circumstances allow the user to say who
487** s/he is (using -f or -r). These are:
488** 1. The user's uid is zero (root).
489** 2. The user's login name is in an approved list (typically
490** from a network server).
491** 3. The address the user is trying to claim has a
492** "!" character in it (since #2 doesn't do it for
493** us if we are dialing out for UUCP).
494** A better check to replace #3 would be if the
495** effective uid is "UUCP" -- this would require me
496** to rewrite getpwent to "grab" uucp as it went by,
497** make getname more nasty, do another passwd file
498** scan, or compile the UID of "UUCP" into the code,
499** all of which are reprehensible.
500**
501** Assuming all of these fail, we figure out something
502** ourselves.
503**
504** Parameters:
505** from -- the person we would like to believe this message
506** is from, as specified on the command line.
507**
508** Returns:
509** none.
510**
511** Side Effects:
512** sets sendmail's notion of who the from person is.
513*/
514
515setsender(from)
516 char *from;
517{
518 register char **pvp;
519 register struct passwd *pw = NULL;
520 char *realname = NULL;
521 char buf[MAXNAME];
522 extern char *macvalue();
523 extern char **prescan();
524 extern bool safefile();
525 extern char *FullName;
526
527# ifdef DEBUG
528 if (tTd(45, 1))
529 printf("setsender(%s)\n", from);
530# endif DEBUG
531
532 /*
533 ** Figure out the real user executing us.
534 ** Username can return errno != 0 on non-errors.
535 */
536
537 if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP)
538 realname = from;
539 if (realname == NULL || realname[0] == '\0')
540 {
541 extern char *username();
542
543 realname = username();
544 errno = 0;
545 }
546 if (realname == NULL || realname[0] == '\0')
547 {
548 extern struct passwd *getpwuid();
549
550 pw = getpwuid(getruid());
551 if (pw != NULL)
552 realname = pw->pw_name;
553 }
554 if (realname == NULL || realname[0] == '\0')
555 {
556 syserr("Who are you?");
557 realname = "root";
558 }
559
560 /*
561 ** Determine if this real person is allowed to alias themselves.
562 */
563
564 if (from != NULL)
565 {
566 extern bool trusteduser();
567
568 if (!trusteduser(realname) &&
569# ifdef DEBUG
570 (!tTd(1, 9) || getuid() != geteuid()) &&
571# endif DEBUG
572 index(from, '!') == NULL && getuid() != 0)
573 {
574 /* network sends -r regardless (why why why?) */
575 /* syserr("%s, you cannot use the -f flag", realname); */
576 from = NULL;
577 }
578 }
579
580 SuprErrs = TRUE;
d3f52e20 581 if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL)
c6f91078
EA
582 {
583 from = newstr(realname);
d3f52e20 584 (void) parseaddr(from, &CurEnv->e_from, 1, '\0');
c6f91078
EA
585 }
586 else
587 FromFlag = TRUE;
588 CurEnv->e_from.q_flags |= QDONTSEND;
589 SuprErrs = FALSE;
590
591 if (pw == NULL && CurEnv->e_from.q_mailer == LocalMailer)
592 {
593 extern struct passwd *getpwnam();
594
595 pw = getpwnam(CurEnv->e_from.q_user);
596 }
597
598 /*
599 ** Process passwd file entry.
600 */
601
602 if (pw != NULL)
603 {
604 /* extract home directory */
605 CurEnv->e_from.q_home = newstr(pw->pw_dir);
606
607 /* run user's .mailcf file */
608 define('z', CurEnv->e_from.q_home, CurEnv);
609 expand("$z/.mailcf", buf, &buf[sizeof buf - 1], CurEnv);
610 if (safefile(buf, getruid(), S_IREAD))
611 readcf(buf, FALSE);
612
613 /* if the user has given fullname already, don't redefine */
614 if (FullName == NULL)
615 FullName = macvalue('x', CurEnv);
616 if (FullName[0] == '\0')
617 FullName = NULL;
618
619 /* extract full name from passwd file */
84853f5f
EA
620 if (FullName == NULL && pw->pw_gecos != NULL &&
621 strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0)
c6f91078
EA
622 {
623 buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf);
624 if (buf[0] != '\0')
625 FullName = newstr(buf);
626 }
627 if (FullName != NULL)
628 define('x', FullName, CurEnv);
629 }
630
631#ifndef V6
632 if (CurEnv->e_from.q_home == NULL)
633 CurEnv->e_from.q_home = getenv("HOME");
634#endif V6
635 CurEnv->e_from.q_uid = getuid();
636 CurEnv->e_from.q_gid = getgid();
637 if (CurEnv->e_from.q_uid != 0)
638 {
639 DefUid = CurEnv->e_from.q_uid;
640 DefGid = CurEnv->e_from.q_gid;
641 }
642
643 /*
644 ** Rewrite the from person to dispose of possible implicit
645 ** links in the net.
646 */
647
648 pvp = prescan(from, '\0');
649 if (pvp == NULL)
650 {
651 syserr("cannot prescan from (%s)", from);
652 finis();
653 }
654 rewrite(pvp, 3);
655 rewrite(pvp, 1);
c9665b44 656 rewrite(pvp, 4);
c6f91078
EA
657 cataddr(pvp, buf, sizeof buf);
658 define('f', newstr(buf), CurEnv);
659
660 /* save the domain spec if this mailer wants it */
1dbda134 661 if (bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags))
c6f91078
EA
662 {
663 extern char **copyplist();
664
665 while (*pvp != NULL && strcmp(*pvp, "@") != 0)
666 pvp++;
667 if (*pvp != NULL)
668 CurEnv->e_fromdomain = copyplist(pvp, TRUE);
669 }
670}
671\f/*
672** TRUSTEDUSER -- tell us if this user is to be trusted.
673**
674** Parameters:
675** user -- the user to be checked.
676**
677** Returns:
678** TRUE if the user is in an approved list.
679** FALSE otherwise.
680**
681** Side Effects:
682** none.
683*/
684
685bool
686trusteduser(user)
687 char *user;
688{
689 register char **ulist;
690 extern char *TrustedUsers[];
691
692 for (ulist = TrustedUsers; *ulist != NULL; ulist++)
693 if (strcmp(*ulist, user) == 0)
694 return (TRUE);
695 return (FALSE);
696}