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