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