Commit | Line | Data |
---|---|---|
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 | 13 | static char sccsid[] = "@(#)alias.c 8.40 (Berkeley) %G%"; |
bee79b64 | 14 | #endif /* not lint */ |
595aeb43 EA |
15 | |
16 | ||
36b09297 | 17 | MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */ |
595aeb43 EA |
18 | int 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 | 44 | void |
f8c2f9fd | 45 | alias(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 | ||
154 | char * | |
595aeb43 | 155 | aliaslookup(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 | 188 | void |
595aeb43 EA |
189 | setalias(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 |
303 | bool |
304 | aliaswait(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 | 418 | void |
31f1ab13 | 419 | rebuildaliases(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 | 539 | void |
d023870f | 540 | readaliases(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 | 773 | void |
f8c2f9fd | 774 | forward(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 | ||
862 | char ** | |
863 | maphost(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 | } |