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