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