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