allow superuser to do anything
[unix-history] / usr / src / usr.sbin / sendmail / src / envelope.c
CommitLineData
c6f91078 1#include <pwd.h>
d06ce34f 2#include <sys/time.h>
c6f91078
EA
3#include "sendmail.h"
4#include <sys/stat.h>
5
ebe55058 6SCCSID(@(#)envelope.c 4.10 %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;
83f674d8
EA
36 bzero((char *) e, sizeof *e);
37 bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
c6f91078
EA
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);
83f674d8 47 bcopy((char *) bh, (char *) *nhp, sizeof *bh);
c6f91078
EA
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);
c6f91078
EA
133 xunlink(queuename(e, 'q'));
134 }
135 else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
2ec2faaa
EA
136 {
137#ifdef QUEUE
c6f91078 138 queueup(e, FALSE, FALSE);
2ec2faaa
EA
139#else QUEUE
140 syserr("dropenvelope: queueup");
141#endif QUEUE
142 }
c6f91078
EA
143
144 /* now unlock the job */
bcf74f25 145 closexscript(e);
c6f91078
EA
146 unlockqueue(e);
147
148 /* make sure that this envelope is marked unused */
ebe55058
EA
149 if (e->e_df != NULL)
150 xunlink(e->e_df);
c6f91078 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/*
c6f91078
EA
188** INITSYS -- initialize instantiation of system
189**
190** In Daemon mode, this is done in the child.
191**
192** Parameters:
193** none.
194**
195** Returns:
196** none.
197**
198** Side Effects:
199** Initializes the system macros, some global variables,
200** etc. In particular, the current time in various
201** forms is set.
202*/
203
204initsys()
205{
c6f91078 206 static char cbuf[5]; /* holds hop count */
c6f91078 207 static char pbuf[10]; /* holds pid */
c6f91078
EA
208 static char ybuf[10]; /* holds tty id */
209 register char *p;
c6f91078 210 extern char *ttyname();
c6f91078
EA
211 extern char *macvalue();
212 extern char Version[];
213
214 /*
215 ** Give this envelope a reality.
216 ** I.e., an id, a transcript, and a creation time.
217 */
218
219 openxscript(CurEnv);
220 CurEnv->e_ctime = curtime();
221
222 /*
223 ** Set OutChannel to something useful if stdout isn't it.
224 ** This arranges that any extra stuff the mailer produces
225 ** gets sent back to the user on error (because it is
226 ** tucked away in the transcript).
227 */
228
229 if (OpMode == MD_DAEMON && QueueRun)
230 OutChannel = CurEnv->e_xfp;
231
232 /*
233 ** Set up some basic system macros.
234 */
235
236 /* process id */
237 (void) sprintf(pbuf, "%d", getpid());
238 define('p', pbuf, CurEnv);
239
240 /* hop count */
241 (void) sprintf(cbuf, "%d", CurEnv->e_hopcount);
242 define('c', cbuf, CurEnv);
243
244 /* time as integer, unix time, arpa time */
4ddbb0b5 245 settime();
c6f91078 246
560a80d9 247#ifdef TTYNAME
c6f91078
EA
248 /* tty name */
249 if (macvalue('y', CurEnv) == NULL)
250 {
251 p = ttyname(2);
252 if (p != NULL)
253 {
254 if (rindex(p, '/') != NULL)
255 p = rindex(p, '/') + 1;
256 (void) strcpy(ybuf, p);
257 define('y', ybuf, CurEnv);
258 }
259 }
560a80d9 260#endif TTYNAME
c6f91078
EA
261}
262\f/*
4ddbb0b5
EA
263** SETTIME -- set the current time.
264**
265** Parameters:
266** none.
267**
268** Returns:
269** none.
270**
271** Side Effects:
272** Sets the various time macros -- $a, $b, $d, $t.
273*/
274
275settime()
276{
277 register char *p;
278 auto time_t now;
279 static char tbuf[20]; /* holds "current" time */
280 static char dbuf[30]; /* holds ctime(tbuf) */
281 register struct tm *tm;
282 extern char *arpadate();
283 extern struct tm *gmtime();
284 extern char *macvalue();
285
286 now = curtime();
287 tm = gmtime(&now);
288 (void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1,
289 tm->tm_mday, tm->tm_hour, tm->tm_min);
290 define('t', tbuf, CurEnv);
291 (void) strcpy(dbuf, ctime(&now));
292 *index(dbuf, '\n') = '\0';
293 if (macvalue('d', CurEnv) == NULL)
294 define('d', dbuf, CurEnv);
295 p = newstr(arpadate(dbuf));
296 if (macvalue('a', CurEnv) == NULL)
297 define('a', p, CurEnv);
298 define('b', p, CurEnv);
299}
300\f/*
c6f91078
EA
301** OPENXSCRIPT -- Open transcript file
302**
303** Creates a transcript file for possible eventual mailing or
304** sending back.
305**
306** Parameters:
307** e -- the envelope to create the transcript in/for.
308**
309** Returns:
310** none
311**
312** Side Effects:
313** Creates the transcript file.
314*/
315
316openxscript(e)
317 register ENVELOPE *e;
318{
319 register char *p;
320
bcf74f25
EA
321# ifdef LOG
322 if (LogLevel > 19)
323 syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)");
324# endif LOG
c6f91078
EA
325 if (e->e_xfp != NULL)
326 return;
327 p = queuename(e, 'x');
328 e->e_xfp = fopen(p, "w");
329 if (e->e_xfp == NULL)
330 syserr("Can't create %s", p);
331 else
332 (void) chmod(p, 0644);
333}
334\f/*
bcf74f25
EA
335** CLOSEXSCRIPT -- close the transcript file.
336**
337** Parameters:
338** e -- the envelope containing the transcript to close.
339**
340** Returns:
341** none.
342**
343** Side Effects:
344** none.
345*/
346
347closexscript(e)
348 register ENVELOPE *e;
349{
350 if (e->e_xfp == NULL)
351 return;
352 (void) fclose(e->e_xfp);
353 e->e_xfp = NULL;
354}
355\f/*
c6f91078
EA
356** SETSENDER -- set the person who this message is from
357**
358** Under certain circumstances allow the user to say who
359** s/he is (using -f or -r). These are:
360** 1. The user's uid is zero (root).
361** 2. The user's login name is in an approved list (typically
362** from a network server).
363** 3. The address the user is trying to claim has a
364** "!" character in it (since #2 doesn't do it for
365** us if we are dialing out for UUCP).
366** A better check to replace #3 would be if the
367** effective uid is "UUCP" -- this would require me
368** to rewrite getpwent to "grab" uucp as it went by,
369** make getname more nasty, do another passwd file
370** scan, or compile the UID of "UUCP" into the code,
371** all of which are reprehensible.
372**
373** Assuming all of these fail, we figure out something
374** ourselves.
375**
376** Parameters:
377** from -- the person we would like to believe this message
378** is from, as specified on the command line.
379**
380** Returns:
381** none.
382**
383** Side Effects:
384** sets sendmail's notion of who the from person is.
385*/
386
387setsender(from)
388 char *from;
389{
390 register char **pvp;
c6f91078 391 char *realname = NULL;
9c945e70 392 register struct passwd *pw;
c6f91078 393 char buf[MAXNAME];
217a0102 394 char pvpbuf[PSBUFSIZE];
9c945e70 395 extern struct passwd *getpwnam();
c6f91078
EA
396 extern char *macvalue();
397 extern char **prescan();
398 extern bool safefile();
399 extern char *FullName;
400
401# ifdef DEBUG
402 if (tTd(45, 1))
0577d7c0 403 printf("setsender(%s)\n", from == NULL ? "" : from);
c6f91078
EA
404# endif DEBUG
405
406 /*
407 ** Figure out the real user executing us.
408 ** Username can return errno != 0 on non-errors.
409 */
410
411 if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP)
412 realname = from;
413 if (realname == NULL || realname[0] == '\0')
414 {
415 extern char *username();
416
417 realname = username();
c6f91078
EA
418 }
419
420 /*
421 ** Determine if this real person is allowed to alias themselves.
422 */
423
424 if (from != NULL)
425 {
426 extern bool trusteduser();
427
428 if (!trusteduser(realname) &&
429# ifdef DEBUG
430 (!tTd(1, 9) || getuid() != geteuid()) &&
431# endif DEBUG
432 index(from, '!') == NULL && getuid() != 0)
433 {
434 /* network sends -r regardless (why why why?) */
435 /* syserr("%s, you cannot use the -f flag", realname); */
436 from = NULL;
437 }
438 }
439
440 SuprErrs = TRUE;
d3f52e20 441 if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL)
c6f91078 442 {
ebe55058
EA
443 /* log garbage addresses for traceback */
444 if (from != NULL)
445 {
446 syslog(LOG_ERR, "Unparseable user %s wants to be %s",
447 realname, from);
448 }
c6f91078 449 from = newstr(realname);
d3f52e20 450 (void) parseaddr(from, &CurEnv->e_from, 1, '\0');
c6f91078
EA
451 }
452 else
453 FromFlag = TRUE;
454 CurEnv->e_from.q_flags |= QDONTSEND;
0fe3917f 455 loweraddr(&CurEnv->e_from);
c6f91078
EA
456 SuprErrs = FALSE;
457
9c945e70
EA
458 if (CurEnv->e_from.q_mailer == LocalMailer &&
459 (pw = getpwnam(CurEnv->e_from.q_user)) != NULL)
c6f91078 460 {
560a80d9
EA
461 /*
462 ** Process passwd file entry.
463 */
c6f91078 464
c6f91078 465
c6f91078
EA
466 /* extract home directory */
467 CurEnv->e_from.q_home = newstr(pw->pw_dir);
240489b6 468 define('z', CurEnv->e_from.q_home, CurEnv);
c6f91078 469
ad264a19
EA
470 /* extract user and group id */
471 CurEnv->e_from.q_uid = pw->pw_uid;
472 CurEnv->e_from.q_gid = pw->pw_gid;
473
c6f91078
EA
474 /* if the user has given fullname already, don't redefine */
475 if (FullName == NULL)
476 FullName = macvalue('x', CurEnv);
4ddbb0b5 477 if (FullName != NULL && FullName[0] == '\0')
c6f91078
EA
478 FullName = NULL;
479
480 /* extract full name from passwd file */
84853f5f
EA
481 if (FullName == NULL && pw->pw_gecos != NULL &&
482 strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0)
c6f91078
EA
483 {
484 buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf);
485 if (buf[0] != '\0')
486 FullName = newstr(buf);
487 }
488 if (FullName != NULL)
489 define('x', FullName, CurEnv);
490 }
ad264a19
EA
491 else
492 {
c6f91078 493#ifndef V6
ad264a19
EA
494 if (CurEnv->e_from.q_home == NULL)
495 CurEnv->e_from.q_home = getenv("HOME");
c6f91078 496#endif V6
ad264a19
EA
497 CurEnv->e_from.q_uid = getuid();
498 CurEnv->e_from.q_gid = getgid();
499 }
500
c6f91078
EA
501 if (CurEnv->e_from.q_uid != 0)
502 {
503 DefUid = CurEnv->e_from.q_uid;
504 DefGid = CurEnv->e_from.q_gid;
505 }
506
507 /*
508 ** Rewrite the from person to dispose of possible implicit
509 ** links in the net.
510 */
511
217a0102 512 pvp = prescan(from, '\0', pvpbuf);
c6f91078
EA
513 if (pvp == NULL)
514 {
515 syserr("cannot prescan from (%s)", from);
516 finis();
517 }
518 rewrite(pvp, 3);
519 rewrite(pvp, 1);
c9665b44 520 rewrite(pvp, 4);
c6f91078
EA
521 cataddr(pvp, buf, sizeof buf);
522 define('f', newstr(buf), CurEnv);
523
524 /* save the domain spec if this mailer wants it */
1dbda134 525 if (bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags))
c6f91078
EA
526 {
527 extern char **copyplist();
528
529 while (*pvp != NULL && strcmp(*pvp, "@") != 0)
530 pvp++;
531 if (*pvp != NULL)
532 CurEnv->e_fromdomain = copyplist(pvp, TRUE);
533 }
534}
535\f/*
536** TRUSTEDUSER -- tell us if this user is to be trusted.
537**
538** Parameters:
539** user -- the user to be checked.
540**
541** Returns:
542** TRUE if the user is in an approved list.
543** FALSE otherwise.
544**
545** Side Effects:
546** none.
547*/
548
549bool
550trusteduser(user)
551 char *user;
552{
553 register char **ulist;
554 extern char *TrustedUsers[];
555
556 for (ulist = TrustedUsers; *ulist != NULL; ulist++)
557 if (strcmp(*ulist, user) == 0)
558 return (TRUE);
559 return (FALSE);
560}