TIOCSTI fails for 8-bit chars (from comp.unix.bsd)
[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
e0136832 10static char sccsid[] = "@(#)recipient.c 5.38 (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
ed45aae1 261 /* do sickly crude mapping for program mailing, etc. */
98f46225 262 if (m == LocalMailer && buf[0] == '|')
6eefe4f6 263 {
98f46225
EA
264 a->q_mailer = m = ProgMailer;
265 a->q_user++;
f8a74171 266 if (a->q_alias == NULL && !ForceMail)
6eefe4f6 267 {
315314bd 268 a->q_flags |= QDONTSEND|QBADADDR;
4c34b183 269 usrerr("Cannot mail directly to programs");
6eefe4f6
EA
270 }
271 }
272
273 /*
b9ca6d11
EA
274 ** Look up this person in the recipient list.
275 ** If they are there already, return, otherwise continue.
276 ** If the list is empty, just add it. Notice the cute
277 ** hack to make from addresses suppress things correctly:
278 ** the QDONTSEND bit will be set in the send list.
279 ** [Please note: the emphasis is on "hack."]
6eefe4f6
EA
280 */
281
d4f42161 282 for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
6eefe4f6 283 {
7338e3d4 284 if (!ForceMail && sameaddr(q, a))
6eefe4f6 285 {
9678c96d 286 if (tTd(26, 1))
331b7c9f
EA
287 {
288 printf("%s in sendq: ", a->q_paddr);
289 printaddr(q, FALSE);
290 }
abae7b2d 291 if (Verbose && !bitset(QDONTSEND|QPSEUDO, a->q_flags))
d6b27179 292 message(Arpa_Info, "duplicate suppressed");
92f12b98
EA
293 if (!bitset(QPRIMARY, q->q_flags))
294 q->q_flags |= a->q_flags;
abae7b2d
EA
295 if (!bitset(QPSEUDO, a->q_flags))
296 q->q_flags &= ~QPSEUDO;
297 return (q);
6eefe4f6 298 }
6eefe4f6 299 }
74c5fe7c
EA
300
301 /* add address on list */
302 *pq = a;
6eefe4f6 303 a->q_next = NULL;
a4076aed 304 e->e_nrcpts++;
6eefe4f6 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
EA
339 /*
340 ** Alias the name and handle :include: specs.
341 */
342
7f0fd60b 343 trylocaluser:
42450b5a
EA
344 if (tTd(29, 7))
345 printf("at trylocaluser %s\n", a->q_user);
346
98f46225 347 if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags))
6eefe4f6
EA
348 {
349 if (strncmp(a->q_user, ":include:", 9) == 0)
350 {
351 a->q_flags |= QDONTSEND;
f8a74171 352 if (a->q_alias == NULL && !ForceMail)
315314bd
EA
353 {
354 a->q_flags |= QBADADDR;
1bf7c76b 355 usrerr("Cannot mail directly to :include:s");
315314bd 356 }
1bf7c76b
EA
357 else
358 {
91f69adf 359 message(Arpa_Info, "including file %s", &a->q_user[9]);
e0136832 360 (void) include(&a->q_user[9], FALSE, a, sendq, e);
1bf7c76b 361 }
6eefe4f6
EA
362 }
363 else
8a12fae4
EA
364 {
365 /* try aliasing */
a4076aed 366 alias(a, sendq, e);
8a12fae4
EA
367
368# ifdef USERDB
6ab0fb92 369 /* if not aliased, look it up in the user database */
83b7c7b1 370 if (!bitset(QDONTSEND|QNOTREMOTE, a->q_flags))
6ab0fb92
EA
371 {
372 extern int udbexpand();
373
a4076aed 374 if (udbexpand(a, sendq, e) == EX_TEMPFAIL)
6ab0fb92
EA
375 {
376 a->q_flags |= QQUEUEUP;
a4076aed
EA
377 if (e->e_message == NULL)
378 e->e_message = newstr("Deferred: user database error");
6ab0fb92
EA
379# ifdef LOG
380 if (LogLevel > 3)
381 syslog(LOG_INFO, "%s: deferred: udbexpand",
a4076aed 382 e->e_id);
6ab0fb92
EA
383# endif
384 message(Arpa_Info, "queued (user database error)");
385 return (a);
386 }
387 }
8a12fae4
EA
388# endif
389 }
6eefe4f6
EA
390 }
391
392 /*
393 ** If the user is local and still being sent, verify that
394 ** the address is good. If it is, try to forward.
395 ** If the address is already good, we have a forwarding
396 ** loop. This can be broken by just sending directly to
397 ** the user (which is probably correct anyway).
398 */
399
d13779b1
EA
400 if (bitset(QDONTSEND, a->q_flags) || m != LocalMailer)
401 return (a);
402
403 /* see if this is to a file */
404 if (buf[0] == '/')
6eefe4f6 405 {
a0554f81
EA
406 struct stat stb;
407 extern bool writable();
6eefe4f6 408
f3d8f6d6 409 p = strrchr(buf, '/');
d13779b1
EA
410 /* check if writable or creatable */
411 if (a->q_alias == NULL && !QueueRun && !ForceMail)
6eefe4f6 412 {
d13779b1
EA
413 a->q_flags |= QDONTSEND|QBADADDR;
414 usrerr("Cannot mail directly to files");
415 }
416 else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
417 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
418 {
419 a->q_flags |= QBADADDR;
a4076aed 420 giveresponse(EX_CANTCREAT, m, e);
d13779b1
EA
421 }
422 return (a);
423 }
424
425 /*
426 ** If we have a level two config file, then pass the name through
427 ** Ruleset 5 before sending it off. Ruleset 5 has the right
428 ** to send rewrite it to another mailer. This gives us a hook
429 ** after local aliasing has been done.
430 */
431
432 if (tTd(29, 5))
433 {
434 printf("recipient: testing local? cl=%d, rr5=%x\n\t",
435 ConfigLevel, RewriteRules[5]);
436 printaddr(a, FALSE);
437 }
438 if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 &&
439 RewriteRules[5] != NULL)
440 {
a4076aed 441 maplocaluser(a, sendq, e);
d13779b1
EA
442 }
443
444 /*
445 ** If it didn't get rewritten to another mailer, go ahead
446 ** and deliver it.
447 */
448
449 if (!bitset(QDONTSEND, a->q_flags))
450 {
42450b5a 451 auto bool fuzzy;
d13779b1
EA
452 register struct passwd *pw;
453 extern struct passwd *finduser();
454
455 /* warning -- finduser may trash buf */
42450b5a 456 pw = finduser(buf, &fuzzy);
d13779b1
EA
457 if (pw == NULL)
458 {
459 a->q_flags |= QBADADDR;
a4076aed 460 giveresponse(EX_NOUSER, m, e);
6eefe4f6
EA
461 }
462 else
463 {
d13779b1 464 char nbuf[MAXNAME];
ff3e3c1c 465
42450b5a 466 if (fuzzy)
6eefe4f6 467 {
7f0fd60b 468 /* name was a fuzzy match */
d13779b1 469 a->q_user = newstr(pw->pw_name);
7f0fd60b
EA
470 if (findusercount++ > 3)
471 {
472 usrerr("aliasing/forwarding loop for %s broken",
473 pw->pw_name);
474 return (a);
475 }
476
477 /* see if it aliases */
d13779b1 478 (void) strcpy(buf, pw->pw_name);
7f0fd60b 479 goto trylocaluser;
6eefe4f6 480 }
d13779b1
EA
481 a->q_home = newstr(pw->pw_dir);
482 a->q_uid = pw->pw_uid;
483 a->q_gid = pw->pw_gid;
484 a->q_flags |= QGOODUID;
485 buildfname(pw->pw_gecos, pw->pw_name, nbuf);
486 if (nbuf[0] != '\0')
487 a->q_fullname = newstr(nbuf);
488 if (!quoted)
a4076aed 489 forward(a, sendq, e);
6eefe4f6
EA
490 }
491 }
d344c0b7 492 return (a);
abae7b2d
EA
493
494 return (a);
6eefe4f6
EA
495}
496\f/*
ff3e3c1c
EA
497** FINDUSER -- find the password entry for a user.
498**
499** This looks a lot like getpwnam, except that it may want to
500** do some fancier pattern matching in /etc/passwd.
501**
7338e3d4
EA
502** This routine contains most of the time of many sendmail runs.
503** It deserves to be optimized.
504**
ff3e3c1c
EA
505** Parameters:
506** name -- the name to match against.
42450b5a
EA
507** fuzzyp -- an outarg that is set to TRUE if this entry
508** was found using the fuzzy matching algorithm;
509** set to FALSE otherwise.
ff3e3c1c
EA
510**
511** Returns:
512** A pointer to a pw struct.
513** NULL if name is unknown or ambiguous.
514**
515** Side Effects:
29c33ff6 516** may modify name.
ff3e3c1c
EA
517*/
518
519struct passwd *
42450b5a 520finduser(name, fuzzyp)
ff3e3c1c 521 char *name;
42450b5a 522 bool *fuzzyp;
ff3e3c1c 523{
2b5e3c25 524 register struct passwd *pw;
29c33ff6 525 register char *p;
f74d8dce
EA
526 extern struct passwd *getpwent();
527 extern struct passwd *getpwnam();
29c33ff6 528
42450b5a
EA
529 if (tTd(29, 4))
530 printf("finduser(%s): ", name);
531
639d8b98 532 /* map upper => lower case */
29c33ff6
EA
533 for (p = name; *p != '\0'; p++)
534 {
639d8b98 535 if (isascii(*p) && isupper(*p))
577bce94 536 *p = tolower(*p);
29c33ff6 537 }
42450b5a 538 *fuzzyp = FALSE;
ff3e3c1c 539
639d8b98 540 /* look up this login name using fast path */
77b16ff1 541 if ((pw = getpwnam(name)) != NULL)
42450b5a
EA
542 {
543 if (tTd(29, 4))
544 printf("found (non-fuzzy)\n");
77b16ff1 545 return (pw);
42450b5a 546 }
77b16ff1 547
7f0fd60b
EA
548#ifdef MATCHGECOS
549 /* see if fuzzy matching allowed */
550 if (!MatchGecos)
42450b5a
EA
551 {
552 if (tTd(29, 4))
553 printf("not found (fuzzy disabled)\n");
7f0fd60b 554 return NULL;
42450b5a 555 }
7f0fd60b 556
77b16ff1 557 /* search for a matching full name instead */
639d8b98
EA
558 for (p = name; *p != '\0'; p++)
559 {
560 if (*p == (SpaceSub & 0177) || *p == '_')
561 *p = ' ';
562 }
03388044 563 (void) setpwent();
2b5e3c25
EA
564 while ((pw = getpwent()) != NULL)
565 {
abae7b2d 566 char buf[MAXNAME];
2b5e3c25 567
abae7b2d 568 fullname(pw, buf);
f3d8f6d6 569 if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
36292825 570 {
42450b5a
EA
571 if (tTd(29, 4))
572 printf("fuzzy matches %s\n", pw->pw_name);
abae7b2d
EA
573 message(Arpa_Info, "sending to %s <%s>",
574 buf, pw->pw_name);
2b5e3c25 575 return (pw);
36292825 576 }
2b5e3c25 577 }
7f0fd60b 578#endif
42450b5a
EA
579 if (tTd(29, 4))
580 printf("no fuzzy match found\n");
2b5e3c25 581 return (NULL);
ff3e3c1c
EA
582}
583\f/*
a0554f81
EA
584** WRITABLE -- predicate returning if the file is writable.
585**
586** This routine must duplicate the algorithm in sys/fio.c.
587** Unfortunately, we cannot use the access call since we
588** won't necessarily be the real uid when we try to
589** actually open the file.
590**
591** Notice that ANY file with ANY execute bit is automatically
592** not writable. This is also enforced by mailfile.
593**
594** Parameters:
595** s -- pointer to a stat struct for the file.
596**
597** Returns:
598** TRUE -- if we will be able to write this file.
599** FALSE -- if we cannot write this file.
600**
601** Side Effects:
602** none.
603*/
604
605bool
606writable(s)
607 register struct stat *s;
608{
44967af8
EA
609 uid_t euid;
610 gid_t egid;
a0554f81
EA
611 int bits;
612
613 if (bitset(0111, s->st_mode))
614 return (FALSE);
615 euid = getruid();
616 egid = getrgid();
617 if (geteuid() == 0)
618 {
619 if (bitset(S_ISUID, s->st_mode))
620 euid = s->st_uid;
621 if (bitset(S_ISGID, s->st_mode))
622 egid = s->st_gid;
623 }
624
625 if (euid == 0)
626 return (TRUE);
627 bits = S_IWRITE;
628 if (euid != s->st_uid)
629 {
630 bits >>= 3;
631 if (egid != s->st_gid)
632 bits >>= 3;
633 }
634 return ((s->st_mode & bits) != 0);
635}
636\f/*
6eefe4f6
EA
637** INCLUDE -- handle :include: specification.
638**
639** Parameters:
640** fname -- filename to include.
a90a7c55
EA
641** forwarding -- if TRUE, we are reading a .forward file.
642** if FALSE, it's a :include: file.
1bf7c76b
EA
643** ctladdr -- address template to use to fill in these
644** addresses -- effective user/group id are
645** the important things.
d4f42161
EA
646** sendq -- a pointer to the head of the send queue
647** to put these addresses in.
6eefe4f6
EA
648**
649** Returns:
e0136832 650** open error status
6eefe4f6
EA
651**
652** Side Effects:
653** reads the :include: file and sends to everyone
654** listed in that file.
655*/
656
a90a7c55
EA
657static jmp_buf CtxIncludeTimeout;
658
e0136832 659int
a4076aed 660include(fname, forwarding, ctladdr, sendq, e)
6eefe4f6 661 char *fname;
a90a7c55 662 bool forwarding;
1bf7c76b 663 ADDRESS *ctladdr;
d4f42161 664 ADDRESS **sendq;
a4076aed 665 ENVELOPE *e;
6eefe4f6 666{
6eefe4f6 667 register FILE *fp;
a4076aed 668 char *oldto = e->e_to;
7338e3d4
EA
669 char *oldfilename = FileName;
670 int oldlinenumber = LineNumber;
a90a7c55
EA
671 register EVENT *ev = NULL;
672 char buf[MAXLINE];
673 static int includetimeout();
674
675 /*
676 ** If home directory is remote mounted but server is down,
677 ** this can hang or give errors; use a timeout to avoid this
678 */
679
680 if (setjmp(CtxIncludeTimeout) != 0)
681 {
682 ctladdr->q_flags |= QQUEUEUP|QDONTSEND;
683 errno = 0;
684 usrerr("451 open timeout on %s", fname);
e0136832 685 return ETIMEDOUT;
a90a7c55
EA
686 }
687 ev = setevent((time_t) 60, includetimeout, 0);
688
689 /* if forwarding, the input file must be marked safe */
690 if (forwarding && !safefile(fname, ctladdr->q_uid, S_IREAD))
691 {
692 /* don't use this .forward file */
693 clrevent(ev);
e0136832 694 return EPERM;
a90a7c55 695 }
6eefe4f6 696
6eefe4f6
EA
697 fp = fopen(fname, "r");
698 if (fp == NULL)
699 {
e0136832
EA
700 int ret = errno;
701
6eefe4f6 702 usrerr("Cannot open %s", fname);
e0136832 703 return ret;
6eefe4f6 704 }
a90a7c55 705
962c3fb2
EA
706 if (getctladdr(ctladdr) == NULL)
707 {
708 struct stat st;
709
710 if (fstat(fileno(fp), &st) < 0)
711 syserr("Cannot fstat %s!", fname);
712 ctladdr->q_uid = st.st_uid;
713 ctladdr->q_gid = st.st_gid;
714 ctladdr->q_flags |= QGOODUID;
715 }
6eefe4f6 716
a90a7c55
EA
717 clrevent(ev);
718
6eefe4f6 719 /* read the file -- each line is a comma-separated list. */
7338e3d4
EA
720 FileName = fname;
721 LineNumber = 0;
6eefe4f6
EA
722 while (fgets(buf, sizeof buf, fp) != NULL)
723 {
f3d8f6d6 724 register char *p = strchr(buf, '\n');
6eefe4f6 725
dd0758e5 726 LineNumber++;
6eefe4f6
EA
727 if (p != NULL)
728 *p = '\0';
a4076aed 729 e->e_to = oldto;
a90a7c55
EA
730 message(Arpa_Info, "%s to %s",
731 forwarding ? "forwarding" : "sending", buf);
23008226 732 AliasLevel++;
abae7b2d 733 sendto(buf, 1, ctladdr, 0);
23008226 734 AliasLevel--;
6eefe4f6
EA
735 }
736
74c5fe7c 737 (void) fclose(fp);
7338e3d4
EA
738 FileName = oldfilename;
739 LineNumber = oldlinenumber;
e0136832 740 return 0;
6eefe4f6 741}
a90a7c55
EA
742
743static
744includetimeout()
745{
746 longjmp(CtxIncludeTimeout, 1);
747}
d6b27179
EA
748\f/*
749** SENDTOARGV -- send to an argument vector.
750**
751** Parameters:
752** argv -- argument vector to send to.
753**
754** Returns:
755** none.
756**
757** Side Effects:
758** puts all addresses on the argument vector onto the
759** send queue.
760*/
761
a4076aed 762sendtoargv(argv, e)
d6b27179 763 register char **argv;
a4076aed 764 register ENVELOPE *e;
d6b27179
EA
765{
766 register char *p;
d6b27179
EA
767
768 while ((p = *argv++) != NULL)
769 {
ed73ef1d 770 if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at"))
d6b27179
EA
771 {
772 char nbuf[MAXNAME];
773
774 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
775 usrerr("address overflow");
776 else
777 {
778 (void) strcpy(nbuf, p);
779 (void) strcat(nbuf, "@");
780 (void) strcat(nbuf, argv[1]);
781 p = newstr(nbuf);
782 argv += 2;
783 }
784 }
abae7b2d 785 sendto(p, 0, (ADDRESS *) NULL, 0);
d6b27179
EA
786 }
787}
1bf7c76b
EA
788\f/*
789** GETCTLADDR -- get controlling address from an address header.
790**
791** If none, get one corresponding to the effective userid.
792**
793** Parameters:
794** a -- the address to find the controller of.
795**
796** Returns:
797** the controlling address.
798**
799** Side Effects:
800** none.
801*/
802
803ADDRESS *
804getctladdr(a)
805 register ADDRESS *a;
806{
2c1457f0 807 while (a != NULL && !bitset(QGOODUID, a->q_flags))
1bf7c76b 808 a = a->q_alias;
1bf7c76b
EA
809 return (a);
810}