add QSELFREF bit
[unix-history] / usr / src / usr.sbin / sendmail / src / recipient.c
CommitLineData
b2a81223 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
bee79b64
KB
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
417f7a11 6 * %sccs.include.redist.c%
bee79b64 7 */
b2a81223
DF
8
9#ifndef lint
2bee003d 10static char sccsid[] = "@(#)recipient.c 6.10 (Berkeley) %G%";
bee79b64 11#endif /* not lint */
b2a81223 12
611050b6
KB
13# include <sys/types.h>
14# include <sys/stat.h>
f9344236 15# include <fcntl.h>
6eefe4f6 16# include <pwd.h>
6eefe4f6 17# include "sendmail.h"
6eefe4f6 18
6eefe4f6 19/*
811a6cf3 20** SENDTOLIST -- Designate a send list.
6eefe4f6
EA
21**
22** The parameter is a comma-separated list of people to send to.
23** This routine arranges to send to all of them.
24**
abae7b2d
EA
25** The `ctladdr' is the address that expanded to be this one,
26** e.g., in an alias expansion. This is used for a number of
27** purposed, most notably inheritance of uid/gid for protection
28** purposes. It is also used to detect self-reference in group
29** expansions and the like.
30**
6eefe4f6
EA
31** Parameters:
32** list -- the send list.
1bf7c76b
EA
33** ctladdr -- the address template for the person to
34** send to -- effective uid/gid are important.
d4f42161
EA
35** This is typically the alias that caused this
36** expansion.
37** sendq -- a pointer to the head of a queue to put
38** these people into.
abae7b2d 39** qflags -- special flags to set in the q_flags field.
6eefe4f6
EA
40**
41** Returns:
abae7b2d 42** pointer to chain of addresses.
6eefe4f6
EA
43**
44** Side Effects:
45** none.
46*/
47
48# define MAXRCRSN 10
49
abae7b2d
EA
50ADDRESS *
51sendto(list, copyf, ctladdr, qflags)
6eefe4f6 52 char *list;
1bf7c76b 53 ADDRESS *ctladdr;
4e5e456f 54 ADDRESS **sendq;
a4076aed 55 register ENVELOPE *e;
abae7b2d 56 u_short qflags;
6eefe4f6
EA
57{
58 register char *p;
7b955214 59 register ADDRESS *al; /* list of addresses to send to */
92f12b98 60 bool firstone; /* set on first address sent */
331b7c9f 61 bool selfref; /* set if this list includes ctladdr */
d3f52e20 62 char delimiter; /* the address delimiter */
abae7b2d
EA
63 ADDRESS *sibl; /* sibling pointer in tree */
64 ADDRESS *prev; /* previous sibling */
d6b27179 65
9678c96d 66 if (tTd(25, 1))
331b7c9f
EA
67 {
68 printf("sendto: %s\n ctladdr=", list);
69 printaddr(ctladdr, FALSE);
70 }
6eefe4f6 71
7b955214 72 /* heuristic to determine old versus new style addresses */
a2983993 73 if (ctladdr == NULL &&
f3d8f6d6
EA
74 (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
75 strchr(list, '<') != NULL || strchr(list, '(') != NULL))
a4076aed 76 e->e_flags &= ~EF_OLDSTYLE;
d3f52e20 77 delimiter = ' ';
a4076aed 78 if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
d3f52e20 79 delimiter = ',';
7b955214 80
92f12b98 81 firstone = TRUE;
331b7c9f 82 selfref = FALSE;
d6b27179 83 al = NULL;
7b955214 84
506fc377 85 for (p = list; *p != '\0'; )
6eefe4f6 86 {
506fc377
EA
87 register ADDRESS *a;
88 extern char *DelimChar; /* defined in prescan */
6eefe4f6
EA
89
90 /* parse the address */
2bee003d 91 while ((isascii(*p) && isspace(*p)) || *p == ',')
506fc377 92 p++;
a4076aed 93 a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter, e);
506fc377 94 p = DelimChar;
b9fadd5b
EA
95 if (a == NULL)
96 continue;
d6b27179 97 a->q_next = al;
1bf7c76b 98 a->q_alias = ctladdr;
abae7b2d
EA
99 if (ctladdr != NULL)
100 a->q_flags |= ctladdr->q_flags & ~QPRIMARY;
101 a->q_flags |= qflags;
331b7c9f
EA
102
103 /* see if this should be marked as a primary address */
92f12b98 104 if (ctladdr == NULL ||
506fc377 105 (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
92f12b98 106 a->q_flags |= QPRIMARY;
331b7c9f 107
7338e3d4 108 if (ctladdr != NULL && sameaddr(ctladdr, a))
331b7c9f 109 selfref = TRUE;
78bbbc48 110 al = a;
92f12b98 111 firstone = FALSE;
d6b27179
EA
112 }
113
331b7c9f
EA
114 /* if this alias doesn't include itself, delete ctladdr */
115 if (!selfref && ctladdr != NULL)
78bbbc48
EA
116 {
117 if (tTd(25, 5))
118 {
119 printf("sendtolist: QDONTSEND ");
120 printaddr(ctladdr, FALSE);
121 }
331b7c9f 122 ctladdr->q_flags |= QDONTSEND;
78bbbc48 123 }
331b7c9f 124
d6b27179 125 /* arrange to send to everyone on the local send list */
abae7b2d
EA
126 prev = sibl = NULL;
127 if (ctladdr != NULL)
128 prev = ctladdr->q_child;
d6b27179
EA
129 while (al != NULL)
130 {
131 register ADDRESS *a = al;
abae7b2d 132 extern ADDRESS *recipient();
d344c0b7 133 extern ADDRESS *recipient();
d6b27179
EA
134
135 al = a->q_next;
abae7b2d
EA
136 sibl = recipient(a);
137 if (sibl != NULL)
138 {
139 extern ADDRESS *addrref();
140
141 /* inherit full name */
142 if (sibl->q_fullname == NULL && ctladdr != NULL)
143 sibl->q_fullname = ctladdr->q_fullname;
144
145 /* link tree together (but only if the node is new) */
146 if (sibl == a)
147 {
148 sibl->q_sibling = prev;
149 prev = sibl;
150 }
151 }
6eefe4f6 152 }
d6b27179 153
a4076aed 154 e->e_to = NULL;
abae7b2d
EA
155 if (ctladdr != NULL)
156 ctladdr->q_child = prev;
157 return (prev);
158}
159\f/*
160** ADDRREF -- return pointer to address that references another address.
161**
162** Parameters:
163** a -- address to check.
164** r -- reference to find.
165**
166** Returns:
167** address of node in tree rooted at 'a' that references
168** 'r'.
169** NULL if no such node exists.
170**
171** Side Effects:
172** none.
173*/
174
175ADDRESS *
176addrref(a, r)
177 register ADDRESS *a;
178 register ADDRESS *r;
179{
180 register ADDRESS *q;
181
182 while (a != NULL)
183 {
184 if (a->q_child == r || a->q_sibling == r)
185 return (a);
186 q = addrref(a->q_child, r);
187 if (q != NULL)
188 return (q);
189 a = a->q_sibling;
190 }
191 return (NULL);
6eefe4f6
EA
192}
193\f/*
194** RECIPIENT -- Designate a message recipient
195**
196** Saves the named person for future mailing.
197**
198** Parameters:
199** a -- the (preparsed) address header for the recipient.
d4f42161
EA
200** sendq -- a pointer to the head of a queue to put the
201** recipient in. Duplicate supression is done
202** in this queue.
78bbbc48 203** e -- the current envelope.
6eefe4f6
EA
204**
205** Returns:
abae7b2d 206** pointer to address actually inserted in send list.
6eefe4f6
EA
207**
208** Side Effects:
209** none.
210*/
211
0df908a9 212extern ADDRESS *getctladdr();
ce46a48a 213extern char *RcptLogFile;
0df908a9 214
d344c0b7 215ADDRESS *
abae7b2d 216ADDRESS *
a4076aed 217recipient(a, sendq, e)
6eefe4f6 218 register ADDRESS *a;
d4f42161 219 register ADDRESS **sendq;
a4076aed 220 register ENVELOPE *e;
6eefe4f6
EA
221{
222 register ADDRESS *q;
74c5fe7c 223 ADDRESS **pq;
6eefe4f6 224 register struct mailer *m;
98f46225
EA
225 register char *p;
226 bool quoted = FALSE; /* set if the addr has a quote bit */
7f0fd60b 227 int findusercount = 0;
98f46225 228 char buf[MAXNAME]; /* unquoted image of the user name */
ed45aae1 229 extern bool safefile();
6eefe4f6 230
a4076aed 231 e->e_to = a->q_paddr;
179c1218 232 m = a->q_mailer;
6eefe4f6 233 errno = 0;
9678c96d 234 if (tTd(26, 1))
331b7c9f
EA
235 {
236 printf("\nrecipient: ");
237 printaddr(a, FALSE);
238 }
6eefe4f6
EA
239
240 /* break aliasing loops */
241 if (AliasLevel > MAXRCRSN)
242 {
243 usrerr("aliasing/forwarding loop broken");
abae7b2d 244 return (NULL);
6eefe4f6
EA
245 }
246
247 /*
ed45aae1 248 ** Finish setting up address structure.
6eefe4f6
EA
249 */
250
0fe3917f 251 /* set the queue timeout */
ed45aae1
EA
252 a->q_timeout = TimeOut;
253
0fe3917f
EA
254 /* map user & host to lower case if requested on non-aliases */
255 if (a->q_alias == NULL)
256 loweraddr(a);
257
258 /* get unquoted user for file, program or user.name check */
98f46225
EA
259 (void) strcpy(buf, a->q_user);
260 for (p = buf; *p != '\0' && !quoted; p++)
261 {
3eb4fac4 262 if (*p == '\\')
98f46225
EA
263 quoted = TRUE;
264 }
85c61679 265 stripquotes(buf);
98f46225 266
98e5062b 267 /* check for direct mailing to restricted mailers */
78bbbc48 268 if (a->q_alias == NULL && m == ProgMailer)
6eefe4f6 269 {
98e5062b
EA
270 a->q_flags |= QDONTSEND|QBADADDR;
271 usrerr("Cannot mail directly to programs", m->m_name);
6eefe4f6
EA
272 }
273
274 /*
b9ca6d11
EA
275 ** Look up this person in the recipient list.
276 ** If they are there already, return, otherwise continue.
277 ** If the list is empty, just add it. Notice the cute
278 ** hack to make from addresses suppress things correctly:
279 ** the QDONTSEND bit will be set in the send list.
280 ** [Please note: the emphasis is on "hack."]
6eefe4f6
EA
281 */
282
d4f42161 283 for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
6eefe4f6 284 {
7338e3d4 285 if (!ForceMail && sameaddr(q, a))
6eefe4f6 286 {
9678c96d 287 if (tTd(26, 1))
331b7c9f
EA
288 {
289 printf("%s in sendq: ", a->q_paddr);
290 printaddr(q, FALSE);
291 }
abae7b2d 292 if (Verbose && !bitset(QDONTSEND|QPSEUDO, a->q_flags))
d6b27179 293 message(Arpa_Info, "duplicate suppressed");
92f12b98
EA
294 if (!bitset(QPRIMARY, q->q_flags))
295 q->q_flags |= a->q_flags;
abae7b2d
EA
296 if (!bitset(QPSEUDO, a->q_flags))
297 q->q_flags &= ~QPSEUDO;
298 return (q);
6eefe4f6 299 }
6eefe4f6 300 }
74c5fe7c
EA
301
302 /* add address on list */
303 *pq = a;
6eefe4f6
EA
304 a->q_next = NULL;
305
ce46a48a
EA
306 if (a->q_alias == NULL && RcptLogFile != NULL &&
307 !bitset(QDONTSEND, a->q_flags))
308 {
309 static int RcptLogFd = -1;
310
311 /*
312 ** Log the incoming recipient name before aliasing,
313 ** expanding, forwarding, rewriting, and all that jazz.
314 ** We'll use this to track down out-of-date aliases,
315 ** host names, and so forth.
316 */
317
318 if (RcptLogFd < 0)
319 {
320 /* try to open the log file */
321 RcptLogFd = open(RcptLogFile, O_WRONLY|O_APPEND|O_CREAT, 0666);
3e901f38
EA
322 if (RcptLogFd >= 0)
323 (void) fcntl(RcptLogFd, F_SETFD, 1);
ce46a48a
EA
324 }
325 if (RcptLogFd >= 0)
326 {
327 int l = strlen(a->q_paddr);
328
329 a->q_paddr[l] = '\n';
330 if (write(RcptLogFd, a->q_paddr, l + 1) < 0)
331 {
332 (void) close(RcptLogFd);
333 RcptLogFd = -1;
334 }
335 a->q_paddr[l] = '\0';
336 }
337 }
338
6eefe4f6 339 /*
98e5062b 340 ** Alias the name and handle special mailer types.
6eefe4f6
EA
341 */
342
7f0fd60b 343 trylocaluser:
42450b5a
EA
344 if (tTd(29, 7))
345 printf("at trylocaluser %s\n", a->q_user);
346
98e5062b
EA
347 if (bitset(QDONTSEND, a->q_flags))
348 return (a);
349
350 if (m == InclMailer)
6eefe4f6 351 {
98e5062b 352 a->q_flags |= QDONTSEND;
78bbbc48 353 if (a->q_alias == NULL)
6eefe4f6 354 {
98e5062b
EA
355 a->q_flags |= QBADADDR;
356 usrerr("Cannot mail directly to :include:s");
6eefe4f6
EA
357 }
358 else
8a12fae4 359 {
51d9cc47
EA
360 message(Arpa_Info, "including file %s", a->q_user);
361 (void) include(a->q_user, FALSE, a, sendq, e);
8a12fae4 362 }
98e5062b 363 }
6e99f903 364 else if (m == FileMailer)
6eefe4f6 365 {
a0554f81
EA
366 struct stat stb;
367 extern bool writable();
6eefe4f6 368
f3d8f6d6 369 p = strrchr(buf, '/');
d13779b1 370 /* check if writable or creatable */
78bbbc48 371 if (a->q_alias == NULL && !QueueRun)
6eefe4f6 372 {
d13779b1
EA
373 a->q_flags |= QDONTSEND|QBADADDR;
374 usrerr("Cannot mail directly to files");
375 }
376 else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
377 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
378 {
379 a->q_flags |= QBADADDR;
a4076aed 380 giveresponse(EX_CANTCREAT, m, e);
d13779b1 381 }
d13779b1
EA
382 }
383
98e5062b 384 if (m != LocalMailer)
6e99f903
EA
385 {
386 if (!bitset(QDONTSEND, a->q_flags))
387 e->e_nrcpts++;
98e5062b 388 return (a);
6e99f903 389 }
98e5062b
EA
390
391 /* try aliasing */
392 alias(a, sendq, e);
393
394# ifdef USERDB
395 /* if not aliased, look it up in the user database */
396 if (!bitset(QDONTSEND|QNOTREMOTE, a->q_flags))
397 {
398 extern int udbexpand();
399
400 if (udbexpand(a, sendq, e) == EX_TEMPFAIL)
401 {
402 a->q_flags |= QQUEUEUP;
403 if (e->e_message == NULL)
404 e->e_message = newstr("Deferred: user database error");
405# ifdef LOG
68f7099c 406 if (LogLevel > 8)
98e5062b
EA
407 syslog(LOG_INFO, "%s: deferred: udbexpand",
408 e->e_id);
409# endif
410 message(Arpa_Info, "queued (user database error)");
6e99f903 411 e->e_nrcpts++;
98e5062b
EA
412 return (a);
413 }
414 }
415# endif
416
417 /* if it was an alias or a UDB expansion, just return now */
418 if (bitset(QDONTSEND, a->q_flags))
419 return (a);
420
d13779b1
EA
421 /*
422 ** If we have a level two config file, then pass the name through
423 ** Ruleset 5 before sending it off. Ruleset 5 has the right
424 ** to send rewrite it to another mailer. This gives us a hook
425 ** after local aliasing has been done.
426 */
427
428 if (tTd(29, 5))
429 {
430 printf("recipient: testing local? cl=%d, rr5=%x\n\t",
431 ConfigLevel, RewriteRules[5]);
432 printaddr(a, FALSE);
433 }
434 if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 &&
435 RewriteRules[5] != NULL)
436 {
a4076aed 437 maplocaluser(a, sendq, e);
d13779b1
EA
438 }
439
440 /*
441 ** If it didn't get rewritten to another mailer, go ahead
442 ** and deliver it.
443 */
444
445 if (!bitset(QDONTSEND, a->q_flags))
446 {
42450b5a 447 auto bool fuzzy;
d13779b1
EA
448 register struct passwd *pw;
449 extern struct passwd *finduser();
450
451 /* warning -- finduser may trash buf */
42450b5a 452 pw = finduser(buf, &fuzzy);
d13779b1
EA
453 if (pw == NULL)
454 {
455 a->q_flags |= QBADADDR;
a4076aed 456 giveresponse(EX_NOUSER, m, e);
6eefe4f6
EA
457 }
458 else
459 {
d13779b1 460 char nbuf[MAXNAME];
ff3e3c1c 461
42450b5a 462 if (fuzzy)
6eefe4f6 463 {
7f0fd60b 464 /* name was a fuzzy match */
d13779b1 465 a->q_user = newstr(pw->pw_name);
7f0fd60b
EA
466 if (findusercount++ > 3)
467 {
468 usrerr("aliasing/forwarding loop for %s broken",
469 pw->pw_name);
470 return (a);
471 }
472
473 /* see if it aliases */
d13779b1 474 (void) strcpy(buf, pw->pw_name);
7f0fd60b 475 goto trylocaluser;
6eefe4f6 476 }
d13779b1
EA
477 a->q_home = newstr(pw->pw_dir);
478 a->q_uid = pw->pw_uid;
479 a->q_gid = pw->pw_gid;
480 a->q_flags |= QGOODUID;
481 buildfname(pw->pw_gecos, pw->pw_name, nbuf);
482 if (nbuf[0] != '\0')
483 a->q_fullname = newstr(nbuf);
484 if (!quoted)
a4076aed 485 forward(a, sendq, e);
6eefe4f6
EA
486 }
487 }
6e99f903
EA
488 if (!bitset(QDONTSEND, a->q_flags))
489 e->e_nrcpts++;
d344c0b7 490 return (a);
abae7b2d
EA
491
492 return (a);
6eefe4f6
EA
493}
494\f/*
ff3e3c1c
EA
495** FINDUSER -- find the password entry for a user.
496**
497** This looks a lot like getpwnam, except that it may want to
498** do some fancier pattern matching in /etc/passwd.
499**
7338e3d4
EA
500** This routine contains most of the time of many sendmail runs.
501** It deserves to be optimized.
502**
ff3e3c1c
EA
503** Parameters:
504** name -- the name to match against.
42450b5a
EA
505** fuzzyp -- an outarg that is set to TRUE if this entry
506** was found using the fuzzy matching algorithm;
507** set to FALSE otherwise.
ff3e3c1c
EA
508**
509** Returns:
510** A pointer to a pw struct.
511** NULL if name is unknown or ambiguous.
512**
513** Side Effects:
29c33ff6 514** may modify name.
ff3e3c1c
EA
515*/
516
517struct passwd *
42450b5a 518finduser(name, fuzzyp)
ff3e3c1c 519 char *name;
42450b5a 520 bool *fuzzyp;
ff3e3c1c 521{
2b5e3c25 522 register struct passwd *pw;
29c33ff6 523 register char *p;
f74d8dce
EA
524 extern struct passwd *getpwent();
525 extern struct passwd *getpwnam();
29c33ff6 526
42450b5a
EA
527 if (tTd(29, 4))
528 printf("finduser(%s): ", name);
529
639d8b98 530 /* map upper => lower case */
29c33ff6
EA
531 for (p = name; *p != '\0'; p++)
532 {
639d8b98 533 if (isascii(*p) && isupper(*p))
577bce94 534 *p = tolower(*p);
29c33ff6 535 }
42450b5a 536 *fuzzyp = FALSE;
ff3e3c1c 537
639d8b98 538 /* look up this login name using fast path */
77b16ff1 539 if ((pw = getpwnam(name)) != NULL)
42450b5a
EA
540 {
541 if (tTd(29, 4))
542 printf("found (non-fuzzy)\n");
77b16ff1 543 return (pw);
42450b5a 544 }
77b16ff1 545
7f0fd60b
EA
546#ifdef MATCHGECOS
547 /* see if fuzzy matching allowed */
548 if (!MatchGecos)
42450b5a
EA
549 {
550 if (tTd(29, 4))
551 printf("not found (fuzzy disabled)\n");
7f0fd60b 552 return NULL;
42450b5a 553 }
7f0fd60b 554
77b16ff1 555 /* search for a matching full name instead */
639d8b98
EA
556 for (p = name; *p != '\0'; p++)
557 {
558 if (*p == (SpaceSub & 0177) || *p == '_')
559 *p = ' ';
560 }
03388044 561 (void) setpwent();
2b5e3c25
EA
562 while ((pw = getpwent()) != NULL)
563 {
abae7b2d 564 char buf[MAXNAME];
2b5e3c25 565
abae7b2d 566 fullname(pw, buf);
f3d8f6d6 567 if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
36292825 568 {
42450b5a
EA
569 if (tTd(29, 4))
570 printf("fuzzy matches %s\n", pw->pw_name);
abae7b2d
EA
571 message(Arpa_Info, "sending to %s <%s>",
572 buf, pw->pw_name);
2b5e3c25 573 return (pw);
36292825 574 }
2b5e3c25 575 }
7f0fd60b 576#endif
42450b5a
EA
577 if (tTd(29, 4))
578 printf("no fuzzy match found\n");
2b5e3c25 579 return (NULL);
ff3e3c1c
EA
580}
581\f/*
a0554f81
EA
582** WRITABLE -- predicate returning if the file is writable.
583**
584** This routine must duplicate the algorithm in sys/fio.c.
585** Unfortunately, we cannot use the access call since we
586** won't necessarily be the real uid when we try to
587** actually open the file.
588**
589** Notice that ANY file with ANY execute bit is automatically
590** not writable. This is also enforced by mailfile.
591**
592** Parameters:
593** s -- pointer to a stat struct for the file.
594**
595** Returns:
596** TRUE -- if we will be able to write this file.
597** FALSE -- if we cannot write this file.
598**
599** Side Effects:
600** none.
601*/
602
603bool
604writable(s)
605 register struct stat *s;
606{
44967af8
EA
607 uid_t euid;
608 gid_t egid;
a0554f81
EA
609 int bits;
610
611 if (bitset(0111, s->st_mode))
612 return (FALSE);
613 euid = getruid();
614 egid = getrgid();
615 if (geteuid() == 0)
616 {
617 if (bitset(S_ISUID, s->st_mode))
618 euid = s->st_uid;
619 if (bitset(S_ISGID, s->st_mode))
620 egid = s->st_gid;
621 }
622
623 if (euid == 0)
624 return (TRUE);
625 bits = S_IWRITE;
626 if (euid != s->st_uid)
627 {
628 bits >>= 3;
629 if (egid != s->st_gid)
630 bits >>= 3;
631 }
632 return ((s->st_mode & bits) != 0);
633}
634\f/*
6eefe4f6
EA
635** INCLUDE -- handle :include: specification.
636**
637** Parameters:
638** fname -- filename to include.
a90a7c55
EA
639** forwarding -- if TRUE, we are reading a .forward file.
640** if FALSE, it's a :include: file.
1bf7c76b
EA
641** ctladdr -- address template to use to fill in these
642** addresses -- effective user/group id are
643** the important things.
d4f42161
EA
644** sendq -- a pointer to the head of the send queue
645** to put these addresses in.
6eefe4f6
EA
646**
647** Returns:
e0136832 648** open error status
6eefe4f6
EA
649**
650** Side Effects:
651** reads the :include: file and sends to everyone
652** listed in that file.
653*/
654
a90a7c55
EA
655static jmp_buf CtxIncludeTimeout;
656
e0136832 657int
a4076aed 658include(fname, forwarding, ctladdr, sendq, e)
6eefe4f6 659 char *fname;
a90a7c55 660 bool forwarding;
1bf7c76b 661 ADDRESS *ctladdr;
d4f42161 662 ADDRESS **sendq;
a4076aed 663 ENVELOPE *e;
6eefe4f6 664{
6eefe4f6 665 register FILE *fp;
a4076aed 666 char *oldto = e->e_to;
7338e3d4
EA
667 char *oldfilename = FileName;
668 int oldlinenumber = LineNumber;
a90a7c55
EA
669 register EVENT *ev = NULL;
670 char buf[MAXLINE];
671 static int includetimeout();
672
b21ec539
EA
673 if (tTd(27, 2))
674 printf("include(%s)\n", fname);
675
a90a7c55
EA
676 /*
677 ** If home directory is remote mounted but server is down,
678 ** this can hang or give errors; use a timeout to avoid this
679 */
680
681 if (setjmp(CtxIncludeTimeout) != 0)
682 {
683 ctladdr->q_flags |= QQUEUEUP|QDONTSEND;
684 errno = 0;
685 usrerr("451 open timeout on %s", fname);
e0136832 686 return ETIMEDOUT;
a90a7c55
EA
687 }
688 ev = setevent((time_t) 60, includetimeout, 0);
689
690 /* if forwarding, the input file must be marked safe */
691 if (forwarding && !safefile(fname, ctladdr->q_uid, S_IREAD))
692 {
693 /* don't use this .forward file */
694 clrevent(ev);
b21ec539
EA
695 if (tTd(27, 4))
696 printf("include: not safe (uid=%d)\n", ctladdr->q_uid);
e0136832 697 return EPERM;
a90a7c55 698 }
6eefe4f6 699
6eefe4f6
EA
700 fp = fopen(fname, "r");
701 if (fp == NULL)
702 {
e0136832
EA
703 int ret = errno;
704
6eefe4f6 705 usrerr("Cannot open %s", fname);
e0136832 706 return ret;
6eefe4f6 707 }
a90a7c55 708
962c3fb2
EA
709 if (getctladdr(ctladdr) == NULL)
710 {
711 struct stat st;
712
713 if (fstat(fileno(fp), &st) < 0)
714 syserr("Cannot fstat %s!", fname);
715 ctladdr->q_uid = st.st_uid;
716 ctladdr->q_gid = st.st_gid;
717 ctladdr->q_flags |= QGOODUID;
718 }
6eefe4f6 719
a90a7c55
EA
720 clrevent(ev);
721
6eefe4f6 722 /* read the file -- each line is a comma-separated list. */
7338e3d4
EA
723 FileName = fname;
724 LineNumber = 0;
6eefe4f6
EA
725 while (fgets(buf, sizeof buf, fp) != NULL)
726 {
f3d8f6d6 727 register char *p = strchr(buf, '\n');
6eefe4f6 728
dd0758e5 729 LineNumber++;
6eefe4f6
EA
730 if (p != NULL)
731 *p = '\0';
b21ec539 732 if (buf[0] == '#' || buf[0] == '\0')
af04f6e4 733 continue;
51d9cc47 734 e->e_to = NULL;
a90a7c55
EA
735 message(Arpa_Info, "%s to %s",
736 forwarding ? "forwarding" : "sending", buf);
aa102c71 737#ifdef LOG
68f7099c 738 if (forwarding && LogLevel > 9)
aa102c71
EA
739 syslog(LOG_INFO, "%s: forward %s => %s",
740 e->e_id, oldto, buf);
741#endif
742
23008226 743 AliasLevel++;
abae7b2d 744 sendto(buf, 1, ctladdr, 0);
23008226 745 AliasLevel--;
6eefe4f6
EA
746 }
747
74c5fe7c 748 (void) fclose(fp);
7338e3d4
EA
749 FileName = oldfilename;
750 LineNumber = oldlinenumber;
e0136832 751 return 0;
6eefe4f6 752}
a90a7c55
EA
753
754static
755includetimeout()
756{
757 longjmp(CtxIncludeTimeout, 1);
758}
d6b27179
EA
759\f/*
760** SENDTOARGV -- send to an argument vector.
761**
762** Parameters:
763** argv -- argument vector to send to.
764**
765** Returns:
766** none.
767**
768** Side Effects:
769** puts all addresses on the argument vector onto the
770** send queue.
771*/
772
a4076aed 773sendtoargv(argv, e)
d6b27179 774 register char **argv;
a4076aed 775 register ENVELOPE *e;
d6b27179
EA
776{
777 register char *p;
d6b27179
EA
778
779 while ((p = *argv++) != NULL)
780 {
ed73ef1d 781 if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at"))
d6b27179
EA
782 {
783 char nbuf[MAXNAME];
784
785 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
786 usrerr("address overflow");
787 else
788 {
789 (void) strcpy(nbuf, p);
790 (void) strcat(nbuf, "@");
791 (void) strcat(nbuf, argv[1]);
792 p = newstr(nbuf);
793 argv += 2;
794 }
795 }
abae7b2d 796 sendto(p, 0, (ADDRESS *) NULL, 0);
d6b27179
EA
797 }
798}
1bf7c76b
EA
799\f/*
800** GETCTLADDR -- get controlling address from an address header.
801**
802** If none, get one corresponding to the effective userid.
803**
804** Parameters:
805** a -- the address to find the controller of.
806**
807** Returns:
808** the controlling address.
809**
810** Side Effects:
811** none.
812*/
813
814ADDRESS *
815getctladdr(a)
816 register ADDRESS *a;
817{
2c1457f0 818 while (a != NULL && !bitset(QGOODUID, a->q_flags))
1bf7c76b 819 a = a->q_alias;
1bf7c76b
EA
820 return (a);
821}