improved debugging
[unix-history] / usr / src / usr.sbin / sendmail / src / alias.c
CommitLineData
d185cb11 1/*
1f7bda54 2 * Copyright (c) 1983 Eric P. Allman
31de980b
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
KB
7 */
8
72041f93 9# include "sendmail.h"
f9344236 10# include <pwd.h>
6a2bb17b 11
bee79b64 12#ifndef lint
28f94061 13static char sccsid[] = "@(#)alias.c 8.8 (Berkeley) %G%";
bee79b64 14#endif /* not lint */
595aeb43
EA
15
16
36b09297 17MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */
595aeb43
EA
18int NAliasDBs; /* number of alias databases */
19\f/*
b3cbe40f
EA
20** ALIAS -- Compute aliases.
21**
7338e3d4
EA
22** Scans the alias file for an alias for the given address.
23** If found, it arranges to deliver to the alias list instead.
24** Uses libdbm database if -DDBM.
b3cbe40f
EA
25**
26** Parameters:
bdfaa762 27** a -- address to alias.
d4f42161
EA
28** sendq -- a pointer to the head of the send queue
29** to put the aliases in.
8f48def8 30** e -- the current envelope.
b3cbe40f
EA
31**
32** Returns:
33** none
34**
35** Side Effects:
9e3c0a28 36** Aliases found are expanded.
b3cbe40f 37**
b3cbe40f
EA
38** Deficiencies:
39** It should complain about names that are aliased to
40** nothing.
b3cbe40f
EA
41*/
42
a4076aed 43alias(a, sendq, e)
bdfaa762 44 register ADDRESS *a;
d4f42161 45 ADDRESS **sendq;
a4076aed 46 register ENVELOPE *e;
b3cbe40f 47{
29871fef 48 register char *p;
1c7897ef 49 int naliases;
84daea29
EA
50 char *owner;
51 char obuf[MAXNAME + 6];
abae7b2d 52 extern ADDRESS *sendto();
35cc3fad 53 extern char *aliaslookup();
b3cbe40f 54
9678c96d 55 if (tTd(27, 1))
cdb17311 56 printf("alias(%s)\n", a->q_paddr);
b3cbe40f 57
cdb17311 58 /* don't realias already aliased names */
bc854e30 59 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
cdb17311
EA
60 return;
61
595aeb43
EA
62 if (NoAlias)
63 return;
64
a4076aed 65 e->e_to = a->q_paddr;
cdb17311 66
74c5fe7c
EA
67 /*
68 ** Look up this name
69 */
70
595aeb43 71 p = aliaslookup(a->q_user, e);
cdb17311
EA
72 if (p == NULL)
73 return;
b3cbe40f 74
d916f0ca 75 /*
cdb17311
EA
76 ** Match on Alias.
77 ** Deliver to the target list.
d916f0ca
EA
78 */
79
9678c96d 80 if (tTd(27, 1))
cdb17311
EA
81 printf("%s (%s, %s) aliased to %s\n",
82 a->q_paddr, a->q_host, a->q_user, p);
8f48def8 83 if (bitset(EF_VRFYONLY, e->e_flags))
8bcce465
EA
84 {
85 a->q_flags |= QVERIFIED;
a7dc53bd 86 e->e_nrcpts++;
8f48def8 87 return;
8bcce465
EA
88 }
89 message("aliased to %s", p);
aa102c71 90#ifdef LOG
68f7099c 91 if (LogLevel > 9)
aa102c71
EA
92 syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
93#endif
1c7897ef 94 a->q_flags &= ~QSELFREF;
cdb17311 95 AliasLevel++;
abae7b2d 96 a->q_child = sendto(p, 1, a, 0);
cdb17311 97 AliasLevel--;
1c7897ef 98 if (naliases > 0 && !bitset(QSELFREF, a->q_flags))
f7eca811
EA
99 {
100 if (tTd(27, 5))
101 {
102 printf("alias: QDONTSEND ");
103 printaddr(a, FALSE);
104 }
105 a->q_flags |= QDONTSEND;
106 }
84daea29
EA
107
108 /*
109 ** Look for owner of alias
110 */
111
112 (void) strcpy(obuf, "owner-");
113 if (strncmp(a->q_user, "owner-", 6) == 0)
114 (void) strcat(obuf, "owner");
115 else
116 (void) strcat(obuf, a->q_user);
117 if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
118 makelower(obuf);
595aeb43 119 owner = aliaslookup(obuf, e);
84daea29
EA
120 if (owner != NULL)
121 {
122 if (strchr(owner, ',') != NULL)
123 owner = obuf;
124 a->q_owner = newstr(owner);
125 }
cdb17311
EA
126}
127\f/*
35cc3fad
EA
128** ALIASLOOKUP -- look up a name in the alias file.
129**
130** Parameters:
131** name -- the name to look up.
132**
133** Returns:
134** the value of name.
135** NULL if unknown.
136**
137** Side Effects:
138** none.
139**
140** Warnings:
141** The return value will be trashed across calls.
142*/
143
144char *
595aeb43 145aliaslookup(name, e)
35cc3fad 146 char *name;
595aeb43 147 ENVELOPE *e;
35cc3fad 148{
595aeb43 149 register int dbno;
713c523f 150 register MAP *map;
595aeb43 151 register char *p;
35cc3fad 152
595aeb43
EA
153 for (dbno = 0; dbno < NAliasDBs; dbno++)
154 {
713c523f
EA
155 auto int stat;
156
36b09297 157 map = AliasDB[dbno];
31f1ab13 158 if (!bitset(MF_OPEN, map->map_mflags))
595aeb43 159 continue;
31f1ab13 160 p = (*map->map_class->map_lookup)(map, name, NULL, &stat);
595aeb43
EA
161 if (p != NULL)
162 return p;
163 }
164 return NULL;
165}
166\f/*
167** SETALIAS -- set up an alias map
168**
169** Called when reading configuration file.
170**
171** Parameters:
172** spec -- the alias specification
173**
174** Returns:
175** none.
176*/
698a71d9 177
595aeb43
EA
178setalias(spec)
179 char *spec;
180{
181 register char *p;
713c523f 182 register MAP *map;
595aeb43
EA
183 char *class;
184 STAB *s;
185
2248d45f
EA
186 if (tTd(27, 8))
187 printf("setalias(%s)\n", spec);
188
4f95e74e 189 for (p = spec; p != NULL; )
07c0651f 190 {
36b09297
EA
191 char aname[50];
192
4f95e74e
EA
193 while (isspace(*p))
194 p++;
54d35e43 195 if (*p == '\0')
595aeb43 196 break;
595aeb43 197 spec = p;
595aeb43 198
4f95e74e
EA
199 if (NAliasDBs >= MAXALIASDB)
200 {
201 syserr("Too many alias databases defined, %d max", MAXALIASDB);
202 return;
203 }
36b09297
EA
204 (void) sprintf(aname, "Alias%d", NAliasDBs);
205 s = stab(aname, ST_MAP, ST_ENTER);
206 map = &s->s_map;
207 AliasDB[NAliasDBs] = map;
713c523f 208 bzero(map, sizeof *map);
4f95e74e
EA
209
210 p = strpbrk(p, " ,/:");
211 if (p != NULL && *p == ':')
212 {
713c523f 213 /* map name */
4f95e74e
EA
214 *p++ = '\0';
215 class = spec;
216 spec = p;
217 }
218 else
219 {
4f95e74e 220 class = "implicit";
df88f2ef 221 map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
4f95e74e
EA
222 }
223
224 /* find end of spec */
225 if (p != NULL)
226 p = strchr(p, ',');
227 if (p != NULL)
228 *p++ = '\0';
229
230 /* look up class */
713c523f 231 s = stab(class, ST_MAPCLASS, ST_FIND);
4f95e74e
EA
232 if (s == NULL)
233 {
234 if (tTd(27, 1))
235 printf("Unknown alias class %s\n", class);
236 }
31f1ab13
EA
237 else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
238 {
239 syserr("setalias: map class %s can't handle aliases",
240 class);
241 }
4f95e74e
EA
242 else
243 {
31f1ab13 244 map->map_class = &s->s_mapclass;
713c523f
EA
245 if (map->map_class->map_parse(map, spec))
246 {
31f1ab13 247 map->map_mflags |= MF_VALID|MF_ALIAS;
713c523f
EA
248 NAliasDBs++;
249 }
4f95e74e 250 }
07c0651f 251 }
35cc3fad
EA
252}
253\f/*
595aeb43
EA
254** ALIASWAIT -- wait for distinguished @:@ token to appear.
255**
256** This can decide to reopen or rebuild the alias file
257*/
258
31f1ab13 259aliaswait(map, ext)
713c523f 260 MAP *map;
31f1ab13 261 char *ext;
595aeb43
EA
262{
263 int atcnt;
264 time_t mtime;
265 struct stat stb;
266 char buf[MAXNAME];
267
2248d45f 268 if (tTd(27, 3))
31f1ab13
EA
269 printf("aliaswait(%s:%s)\n",
270 map->map_class->map_cname, map->map_file);
2248d45f 271
560a80d9
EA
272 atcnt = SafeAlias * 2;
273 if (atcnt > 0)
274 {
713c523f
EA
275 auto int st;
276
595aeb43 277 while (atcnt-- >= 0 &&
713c523f 278 map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
a1a07282
EA
279 {
280 /*
595aeb43
EA
281 ** Close and re-open the alias database in case
282 ** the one is mv'ed instead of cp'ed in.
a1a07282
EA
283 */
284
2248d45f
EA
285 if (tTd(27, 2))
286 printf("aliaswait: sleeping\n");
287
713c523f 288 map->map_class->map_close(map);
560a80d9 289 sleep(30);
713c523f 290 map->map_class->map_open(map, O_RDONLY);
a1a07282 291 }
560a80d9 292 }
d6b27179 293
595aeb43 294 /* see if we need to go into auto-rebuild mode */
31f1ab13
EA
295 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
296 {
297 if (tTd(27, 3))
298 printf("aliaswait: not rebuildable\n");
595aeb43 299 return;
31f1ab13
EA
300 }
301 if (stat(map->map_file, &stb) < 0)
302 {
303 if (tTd(27, 3))
304 printf("aliaswait: no source file\n");
305 return;
306 }
595aeb43 307 mtime = stb.st_mtime;
713c523f 308 (void) strcpy(buf, map->map_file);
31f1ab13
EA
309 if (ext != NULL)
310 (void) strcat(buf, ext);
595aeb43 311 if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0)
f4dbf345 312 {
595aeb43 313 /* database is out of date */
915f268d 314 if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
d6b27179 315 {
713c523f 316 message("auto-rebuilding alias database %s", buf);
31f1ab13 317 rebuildaliases(map, TRUE);
d6b27179
EA
318 }
319 else
320 {
f12e5a74 321#ifdef LOG
68f7099c 322 if (LogLevel > 3)
595aeb43 323 syslog(LOG_INFO, "alias database %s out of date",
713c523f 324 buf);
f3d8f6d6 325#endif /* LOG */
713c523f 326 message("Warning: alias database %s out of date", buf);
d6b27179
EA
327 }
328 }
595aeb43
EA
329}
330\f/*
331** REBUILDALIASES -- rebuild the alias database.
332**
333** Parameters:
713c523f 334** map -- the database to rebuild.
595aeb43 335** automatic -- set if this was automatically generated.
595aeb43
EA
336**
337** Returns:
338** none.
339**
340** Side Effects:
341** Reads the text version of the database, builds the
342** DBM or DB version.
343*/
344
31f1ab13 345rebuildaliases(map, automatic)
713c523f 346 register MAP *map;
595aeb43 347 bool automatic;
595aeb43
EA
348{
349 FILE *af;
350 void (*oldsigint)();
f4dbf345 351
31f1ab13 352 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
595aeb43 353 return;
d6b27179 354
595aeb43
EA
355#ifdef LOG
356 if (LogLevel > 7)
357 {
595aeb43 358 syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
713c523f 359 map->map_file, automatic ? "auto" : "", username());
595aeb43
EA
360 }
361#endif /* LOG */
d6b27179 362
595aeb43 363 /* try to lock the source file */
713c523f 364 if ((af = fopen(map->map_file, "r+")) == NULL)
7bdc419c 365 {
dc02dc7c
EA
366 if (tTd(27, 1))
367 printf("Can't open %s: %s\n",
713c523f 368 map->map_file, errstring(errno));
595aeb43
EA
369 errno = 0;
370 return;
371 }
9327783c 372
595aeb43 373 /* see if someone else is rebuilding the alias file */
713c523f 374 if (!lockfile(fileno(af), map->map_file, LOCK_EX|LOCK_NB))
595aeb43
EA
375 {
376 /* yes, they are -- wait until done */
377 message("Alias file %s is already being rebuilt",
713c523f 378 map->map_file);
595aeb43
EA
379 if (OpMode != MD_INITALIAS)
380 {
381 /* wait for other rebuild to complete */
713c523f 382 (void) lockfile(fileno(af), map->map_file,
595aeb43 383 LOCK_EX);
9327783c 384 }
595aeb43
EA
385 (void) fclose(af);
386 errno = 0;
387 return;
7bdc419c 388 }
595aeb43 389
39270cfd 390 oldsigint = setsignal(SIGINT, SIG_IGN);
595aeb43 391
31f1ab13 392 if (map->map_class->map_open(map, O_RDWR))
713c523f 393 {
31f1ab13
EA
394 map->map_mflags |= MF_OPEN|MF_WRITABLE;
395 readaliases(map, af, automatic);
396 }
397 else
398 {
399 if (tTd(27, 1))
400 printf("Can't create database for %s: %s\n",
401 map->map_file, errstring(errno));
402 if (!automatic)
403 syserr("Cannot create database for alias file %s",
404 map->map_file);
713c523f 405 }
595aeb43
EA
406
407 /* close the file, thus releasing locks */
408 fclose(af);
409
410 /* add distinguished entries and close the database */
31f1ab13 411 if (bitset(MF_OPEN, map->map_mflags))
713c523f 412 map->map_class->map_close(map);
595aeb43
EA
413
414 /* restore the old signal */
39270cfd 415 (void) setsignal(SIGINT, oldsigint);
f4dbf345
EA
416}
417\f/*
418** READALIASES -- read and process the alias file.
419**
420** This routine implements the part of initaliases that occurs
421** when we are not going to use the DBM stuff.
422**
423** Parameters:
713c523f 424** map -- the alias database descriptor.
595aeb43 425** af -- file to read the aliases from.
cce258e2 426** automatic -- set if this was an automatic rebuild.
f4dbf345
EA
427**
428** Returns:
429** none.
430**
431** Side Effects:
432** Reads aliasfile into the symbol table.
433** Optionally, builds the .dir & .pag files.
434*/
435
31f1ab13 436readaliases(map, af, automatic)
713c523f 437 register MAP *map;
595aeb43 438 FILE *af;
cce258e2 439 int automatic;
f4dbf345 440{
cdb17311 441 register char *p;
41173b8f 442 char *lhs;
cdb17311
EA
443 char *rhs;
444 bool skipping;
595aeb43 445 long naliases, bytes, longest;
7338e3d4 446 ADDRESS al, bl;
7338e3d4 447 char line[BUFSIZ];
e6e345fa 448
74c5fe7c
EA
449 /*
450 ** Read and interpret lines
451 */
452
713c523f 453 FileName = map->map_file;
7338e3d4 454 LineNumber = 0;
d6b27179 455 naliases = bytes = longest = 0;
cdb17311
EA
456 skipping = FALSE;
457 while (fgets(line, sizeof (line), af) != NULL)
458 {
d6b27179
EA
459 int lhssize, rhssize;
460
7338e3d4 461 LineNumber++;
f3d8f6d6 462 p = strchr(line, '\n');
3312f93c
EA
463 if (p != NULL)
464 *p = '\0';
cdb17311
EA
465 switch (line[0])
466 {
467 case '#':
cdb17311
EA
468 case '\0':
469 skipping = FALSE;
470 continue;
bdfaa762 471
cdb17311
EA
472 case ' ':
473 case '\t':
474 if (!skipping)
b6edea3d 475 syserr("554 Non-continuation line starts with space");
cdb17311 476 skipping = TRUE;
bdfaa762 477 continue;
cdb17311
EA
478 }
479 skipping = FALSE;
bdfaa762 480
74c5fe7c
EA
481 /*
482 ** Process the LHS
41173b8f 483 **
6feb509e 484 ** Find the colon separator, and parse the address.
41173b8f
EA
485 ** It should resolve to a local name.
486 **
487 ** Alternatively, it can be "@hostname" for host
488 ** aliases -- all we do here is map case. Hostname
489 ** need not be a single token.
74c5fe7c
EA
490 */
491
cdb17311 492 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
bdfaa762 493 continue;
41173b8f 494 if (*p != ':')
cdb17311 495 {
1bcdf0a2 496 syserr("%s, line %d: syntax error", aliasfile, lineno);
bdfaa762 497 continue;
cdb17311 498 }
41173b8f
EA
499 *p++ = '\0';
500 if (line[0] == '@')
cdb17311 501 {
41173b8f
EA
502 /* a host alias */
503 makelower(line);
504 lhs = line;
505 }
506 else
507 {
508 /* a user alias */
509 if (parseaddr(line, &al, 1, ':') == NULL)
510 {
511 syserr("illegal alias name");
512 continue;
513 }
514 loweraddr(&al);
515 if (al.q_mailer != LocalMailer)
516 {
517 syserr("cannot alias non-local names");
518 continue;
519 }
520 lhs = al.q_user;
cdb17311 521 }
74c5fe7c
EA
522
523 /*
524 ** Process the RHS.
525 ** 'al' is the internal form of the LHS address.
526 ** 'p' points to the text of the RHS.
1bcdf0a2
EA
527 ** 'p' may begin with a colon (i.e., the
528 ** separator was "::") which will use the
529 ** first address as the person to send
530 ** errors to -- i.e., designates the
531 ** list maintainer.
74c5fe7c
EA
532 */
533
5854bceb
EA
534 while (isascii(*p) && isspace(*p))
535 p++;
1bcdf0a2
EA
536 if (*p == ':')
537 {
538 ADDRESS *maint;
539
540 while (isspace(*++p))
541 continue;
542 rhs = p;
543 while (*p != '\0' && *p != ',')
544 p++;
545 if (*p != ',')
546 goto syntaxerr;
547 *p++ = '\0';
548 maint = parse(p, (ADDRESS *) NULL, 1);
549 if (maint == NULL)
550 syserr("Illegal list maintainer for list %s", al.q_user);
551 else if (CurEnv->e_returnto == &CurEnv->e_from)
552 {
553 CurEnv->e_returnto = maint;
554 MailBack++;
555 }
556 }
557
cdb17311 558 rhs = p;
cdb17311
EA
559 for (;;)
560 {
561 register char c;
0957ee6f
EA
562 register char *nlp;
563
564 nlp = &p[strlen(p)];
565 if (nlp[-1] == '\n')
566 *--nlp = '\0';
d916f0ca 567
595aeb43 568 if (CheckAliases)
cdb17311 569 {
f4dbf345 570 /* do parsing & compression of addresses */
3312f93c 571 while (*p != '\0')
cdb17311 572 {
9e2cf26f 573 auto char *delimptr;
3312f93c 574
2bee003d
EA
575 while ((isascii(*p) && isspace(*p)) ||
576 *p == ',')
c49d661c 577 p++;
3312f93c
EA
578 if (*p == '\0')
579 break;
28f94061
EA
580 if (parseaddr(p, &bl, RF_COPYNONE, ',',
581 &delimptr, CurEnv) == NULL)
b6edea3d 582 usrerr("553 %s... bad address", p);
9e2cf26f 583 p = delimptr;
cdb17311 584 }
cdb17311 585 }
f4dbf345 586 else
634c8ff3 587 {
0957ee6f 588 p = nlp;
634c8ff3 589 }
d916f0ca 590
cdb17311 591 /* see if there should be a continuation line */
9e25d1f0
EA
592 c = fgetc(af);
593 if (!feof(af))
74c5fe7c 594 (void) ungetc(c, af);
9e25d1f0 595 if (c != ' ' && c != '\t')
cdb17311
EA
596 break;
597
598 /* read continuation line */
cdb17311
EA
599 if (fgets(p, sizeof line - (p - line), af) == NULL)
600 break;
7338e3d4 601 LineNumber++;
07b49560
EA
602
603 /* check for line overflow */
604 if (strchr(p, '\n') == NULL)
605 {
b6edea3d 606 usrerr("554 alias too long");
07b49560
EA
607 break;
608 }
cdb17311 609 }
74c5fe7c
EA
610
611 /*
612 ** Insert alias into symbol table or DBM file
613 */
614
41173b8f 615 lhssize = strlen(lhs) + 1;
d6b27179 616
595aeb43
EA
617 lhssize = strlen(al.q_user);
618 rhssize = strlen(rhs);
713c523f 619 map->map_class->map_store(map, al.q_user, rhs);
f4dbf345 620
595aeb43
EA
621 if (al.q_paddr != NULL)
622 free(al.q_paddr);
623 if (al.q_host != NULL)
624 free(al.q_host);
625 if (al.q_user != NULL)
626 free(al.q_user);
d6b27179
EA
627
628 /* statistics */
629 naliases++;
630 bytes += lhssize + rhssize;
631 if (rhssize > longest)
632 longest = rhssize;
d916f0ca 633 }
e6e345fa 634
31f1ab13 635 CurEnv->e_to = NULL;
595aeb43 636 FileName = NULL;
cce258e2
EA
637 if (Verbose || !automatic)
638 message("%s: %d aliases, longest %d bytes, %d bytes total",
713c523f 639 map->map_file, naliases, longest, bytes);
595aeb43
EA
640# ifdef LOG
641 if (LogLevel > 7)
642 syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
713c523f 643 map->map_file, naliases, longest, bytes);
595aeb43
EA
644# endif /* LOG */
645}
646\f/*
b3cbe40f
EA
647** FORWARD -- Try to forward mail
648**
649** This is similar but not identical to aliasing.
650**
b3cbe40f 651** Parameters:
74c5fe7c
EA
652** user -- the name of the user who's mail we would like
653** to forward to. It must have been verified --
654** i.e., the q_home field must have been filled
655** in.
d4f42161
EA
656** sendq -- a pointer to the head of the send queue to
657** put this user's aliases in.
b3cbe40f
EA
658**
659** Returns:
cdb17311 660** none.
b3cbe40f
EA
661**
662** Side Effects:
9e3c0a28 663** New names are added to send queues.
b3cbe40f
EA
664*/
665
a4076aed 666forward(user, sendq, e)
a530c75f 667 ADDRESS *user;
d4f42161 668 ADDRESS **sendq;
a4076aed 669 register ENVELOPE *e;
b3cbe40f 670{
e0136832
EA
671 char *pp;
672 char *ep;
ba6514e2 673#ifdef HASSETREUID
8e5c6745
EA
674 register ADDRESS *ca;
675 uid_t saveduid, uid;
676#endif
56678245 677
9678c96d 678 if (tTd(27, 1))
cdb17311 679 printf("forward(%s)\n", user->q_paddr);
cdb17311 680
179c1218 681 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
cdb17311 682 return;
74c5fe7c 683 if (user->q_home == NULL)
c25096f0 684 {
b6edea3d 685 syserr("554 forward: no home");
c25096f0
EA
686 user->q_home = "/nosuchdirectory";
687 }
56678245 688
56678245 689 /* good address -- look for .forward file in home */
a4076aed 690 define('z', user->q_home, e);
e0136832
EA
691 define('u', user->q_user, e);
692 define('h', user->q_host, e);
693 if (ForwardPath == NULL)
2bee003d 694 ForwardPath = newstr("\201z/.forward");
e0136832 695
ba6514e2 696#ifdef HASSETREUID
8e5c6745
EA
697 ca = getctladdr(user);
698 if (ca != NULL)
699 uid = ca->q_uid;
700 else
701 uid = DefUid;
702#endif
703
e0136832
EA
704 for (pp = ForwardPath; pp != NULL; pp = ep)
705 {
118e6693 706 int err;
f43b04ce 707 char buf[MAXPATHLEN+1];
e0136832
EA
708
709 ep = strchr(pp, ':');
710 if (ep != NULL)
711 *ep = '\0';
712 expand(pp, buf, &buf[sizeof buf - 1], e);
713 if (ep != NULL)
714 *ep++ = ':';
715 if (tTd(27, 3))
716 printf("forward: trying %s\n", buf);
8e5c6745 717
fd57f063
EA
718 if (tTd(27, 9))
719 printf("forward: old uid = %d/%d\n", getuid(), geteuid());
720
ba6514e2 721#ifdef HASSETREUID
8e5c6745
EA
722 saveduid = geteuid();
723 if (saveduid == 0 && uid != 0)
ba6514e2 724 (void) setreuid(0, uid);
8e5c6745
EA
725#endif
726
fd57f063
EA
727 if (tTd(27, 9))
728 printf("forward: new uid = %d/%d\n", getuid(), geteuid());
729
118e6693 730 err = include(buf, TRUE, user, sendq, e);
8e5c6745 731
ba6514e2 732#ifdef HASSETREUID
8e5c6745 733 if (saveduid == 0 && uid != 0)
ba6514e2
EA
734 if (setreuid(-1, 0) < 0 || setreuid(RealUid, 0) < 0)
735 syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
736 RealUid, getuid(), geteuid());
8e5c6745
EA
737#endif
738
fd57f063
EA
739 if (tTd(27, 9))
740 printf("forward: reset uid = %d/%d\n", getuid(), geteuid());
741
118e6693 742 if (err == 0)
e0136832 743 break;
118e6693
EA
744 if (transienterror(err))
745 {
746 /* we have to suspend this message */
d50bcc17
EA
747 if (tTd(27, 2))
748 printf("forward: transient error on %s\n", buf);
749#ifdef LOG
750 if (LogLevel > 2)
3f0792d1
EA
751 syslog(LOG_ERR, "%s: forward %s: transient error: %s",
752 e->e_id, buf, errstring(err));
d50bcc17 753#endif
dd61ea05 754 message("%s: %s: message queued", buf, errstring(err));
c069e0df 755 user->q_flags |= QQUEUEUP;
118e6693
EA
756 return;
757 }
e0136832 758 }
b3cbe40f 759}
41173b8f
EA
760\f/*
761** MAPHOST -- given a host description, produce a mapping.
762**
763** This is done by looking up the name in the alias file,
764** preceeded by an "@". This can be used for UUCP mapping.
765** For example, a call with {blia, ., UUCP} as arguments
766** might return {ucsfcgl, !, blia, ., UUCP} as the result.
767**
768** We first break the input into three parts -- before the
769** lookup, the lookup itself, and after the lookup. We
770** then do the lookup, concatenate them together, and rescan
771** the result.
772**
773** Parameters:
774** pvp -- the parameter vector to map.
775**
776** Returns:
777** The result of the mapping. If nothing found, it
778** should just concatenate the three parts together and
779** return that.
780**
781** Side Effects:
782** none.
783*/
784
785char **
786maphost(pvp)
787 char **pvp;
788{
789 register char **avp;
790 register char **bvp;
791 char *p;
792 char buf1[MAXNAME];
793 char buf2[MAXNAME];
794 char buf3[MAXNAME];
795 extern char **prescan();
796
797 /*
798 ** Extract the three parts of the input as strings.
799 */
800
801 /* find the part before the lookup */
802 for (bvp = pvp; *bvp != NULL && **bvp != MATCHLOOKUP; bvp++)
803 continue;
804 if (*bvp == NULL)
805 return (pvp);
806 p = *bvp;
807 *bvp = NULL;
808 cataddr(pvp, buf1, sizeof buf1);
809 *bvp++ = p;
810
811 /* find the rest of the lookup */
812 for (avp = bvp; *pvp != NULL && **bvp != MATCHELOOKUP; bvp++)
813 continue;
814 if (*bvp == NULL)
815 return (pvp);
816 p = *bvp;
817 *bvp = NULL;
818 cataddr(avp, buf2, sizeof buf2);
819 *bvp++ = p;
820
821 /* save the part after the lookup */
822 cataddr(bvp, buf3, sizeof buf3);
823
824 /*
825 ** Now look up the middle part.
826 */
827
828 p = aliaslookup(buf2);
829 if (p != NULL)
830 strcpy(buf2, p);
831
832 /*
833 ** Put the three parts back together and break into tokens.
834 */
835
836 strcat(buf1, buf2);
837 strcat(buf1, buf3);
838 avp = prescan(buf1, '\0');
839
840 /* return this mapping */
841 return (avp);
842}