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 |
49de3ce1 | 13 | static char sccsid[] = "@(#)alias.c 8.18 (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. | |
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 | 43 | alias(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--; |
e8c32825 | 98 | if (!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 | ||
144 | char * | |
595aeb43 | 145 | aliaslookup(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 |
178 | setalias(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 | |
fe3849ea EA |
257 | ** |
258 | ** Parameters: | |
259 | ** map -- a pointer to the map descriptor for this alias file. | |
260 | ** ext -- the filename extension (e.g., ".db") for the | |
261 | ** database file. | |
262 | ** isopen -- if set, the database is already open, and we | |
263 | ** should check for validity; otherwise, we are | |
264 | ** just checking to see if it should be created. | |
265 | ** | |
266 | ** Returns: | |
267 | ** TRUE -- if the database is open when we return. | |
268 | ** FALSE -- if the database is closed when we return. | |
595aeb43 EA |
269 | */ |
270 | ||
fe3849ea EA |
271 | bool |
272 | aliaswait(map, ext, isopen) | |
713c523f | 273 | MAP *map; |
31f1ab13 | 274 | char *ext; |
fe3849ea | 275 | int isopen; |
595aeb43 EA |
276 | { |
277 | int atcnt; | |
278 | time_t mtime; | |
279 | struct stat stb; | |
280 | char buf[MAXNAME]; | |
281 | ||
2248d45f | 282 | if (tTd(27, 3)) |
31f1ab13 EA |
283 | printf("aliaswait(%s:%s)\n", |
284 | map->map_class->map_cname, map->map_file); | |
fd93a56c EA |
285 | if (bitset(MF_ALIASWAIT, map->map_mflags)) |
286 | return; | |
287 | map->map_mflags |= MF_ALIASWAIT; | |
2248d45f | 288 | |
560a80d9 EA |
289 | atcnt = SafeAlias * 2; |
290 | if (atcnt > 0) | |
291 | { | |
713c523f EA |
292 | auto int st; |
293 | ||
fe3849ea | 294 | while (isopen && atcnt-- >= 0 && |
713c523f | 295 | map->map_class->map_lookup(map, "@", NULL, &st) == NULL) |
a1a07282 EA |
296 | { |
297 | /* | |
595aeb43 EA |
298 | ** Close and re-open the alias database in case |
299 | ** the one is mv'ed instead of cp'ed in. | |
a1a07282 EA |
300 | */ |
301 | ||
2248d45f EA |
302 | if (tTd(27, 2)) |
303 | printf("aliaswait: sleeping\n"); | |
304 | ||
713c523f | 305 | map->map_class->map_close(map); |
560a80d9 | 306 | sleep(30); |
fe3849ea | 307 | isopen = map->map_class->map_open(map, O_RDONLY); |
a1a07282 | 308 | } |
560a80d9 | 309 | } |
d6b27179 | 310 | |
595aeb43 | 311 | /* see if we need to go into auto-rebuild mode */ |
31f1ab13 EA |
312 | if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) |
313 | { | |
314 | if (tTd(27, 3)) | |
315 | printf("aliaswait: not rebuildable\n"); | |
fd93a56c | 316 | map->map_mflags &= ~MF_ALIASWAIT; |
fe3849ea | 317 | return isopen; |
31f1ab13 EA |
318 | } |
319 | if (stat(map->map_file, &stb) < 0) | |
320 | { | |
321 | if (tTd(27, 3)) | |
322 | printf("aliaswait: no source file\n"); | |
fd93a56c | 323 | map->map_mflags &= ~MF_ALIASWAIT; |
fe3849ea | 324 | return isopen; |
31f1ab13 | 325 | } |
595aeb43 | 326 | mtime = stb.st_mtime; |
713c523f | 327 | (void) strcpy(buf, map->map_file); |
31f1ab13 EA |
328 | if (ext != NULL) |
329 | (void) strcat(buf, ext); | |
595aeb43 | 330 | if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0) |
f4dbf345 | 331 | { |
595aeb43 | 332 | /* database is out of date */ |
915f268d | 333 | if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) |
d6b27179 | 334 | { |
713c523f | 335 | message("auto-rebuilding alias database %s", buf); |
fe3849ea EA |
336 | if (isopen) |
337 | map->map_class->map_close(map); | |
31f1ab13 | 338 | rebuildaliases(map, TRUE); |
fe3849ea | 339 | isopen = map->map_class->map_open(map, O_RDONLY); |
d6b27179 EA |
340 | } |
341 | else | |
342 | { | |
f12e5a74 | 343 | #ifdef LOG |
68f7099c | 344 | if (LogLevel > 3) |
595aeb43 | 345 | syslog(LOG_INFO, "alias database %s out of date", |
713c523f | 346 | buf); |
f3d8f6d6 | 347 | #endif /* LOG */ |
713c523f | 348 | message("Warning: alias database %s out of date", buf); |
d6b27179 EA |
349 | } |
350 | } | |
fd93a56c | 351 | map->map_mflags &= ~MF_ALIASWAIT; |
fe3849ea | 352 | return isopen; |
595aeb43 EA |
353 | } |
354 | \f/* | |
355 | ** REBUILDALIASES -- rebuild the alias database. | |
356 | ** | |
357 | ** Parameters: | |
713c523f | 358 | ** map -- the database to rebuild. |
595aeb43 | 359 | ** automatic -- set if this was automatically generated. |
595aeb43 EA |
360 | ** |
361 | ** Returns: | |
362 | ** none. | |
363 | ** | |
364 | ** Side Effects: | |
365 | ** Reads the text version of the database, builds the | |
366 | ** DBM or DB version. | |
367 | */ | |
368 | ||
31f1ab13 | 369 | rebuildaliases(map, automatic) |
713c523f | 370 | register MAP *map; |
595aeb43 | 371 | bool automatic; |
595aeb43 EA |
372 | { |
373 | FILE *af; | |
7cd18d97 | 374 | bool nolock = FALSE; |
e88b60c9 | 375 | sigfunc_t oldsigint; |
f4dbf345 | 376 | |
31f1ab13 | 377 | if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) |
595aeb43 | 378 | return; |
d6b27179 | 379 | |
595aeb43 | 380 | /* try to lock the source file */ |
713c523f | 381 | if ((af = fopen(map->map_file, "r+")) == NULL) |
7bdc419c | 382 | { |
7cd18d97 EA |
383 | if (errno != EACCES || automatic || |
384 | (af = fopen(map->map_file, "r")) == NULL) | |
385 | { | |
386 | int saveerr = errno; | |
387 | ||
388 | if (tTd(27, 1)) | |
389 | printf("Can't open %s: %s\n", | |
390 | map->map_file, errstring(saveerr)); | |
391 | if (!automatic) | |
392 | message("newaliases: cannot open %s: %s", | |
393 | map->map_file, errstring(saveerr)); | |
394 | errno = 0; | |
395 | return; | |
396 | } | |
397 | nolock = TRUE; | |
398 | message("warning: cannot lock %s: %s", | |
399 | map->map_file, errstring(errno)); | |
595aeb43 | 400 | } |
9327783c | 401 | |
595aeb43 | 402 | /* see if someone else is rebuilding the alias file */ |
7cd18d97 EA |
403 | if (!nolock && |
404 | !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) | |
595aeb43 EA |
405 | { |
406 | /* yes, they are -- wait until done */ | |
407 | message("Alias file %s is already being rebuilt", | |
713c523f | 408 | map->map_file); |
595aeb43 EA |
409 | if (OpMode != MD_INITALIAS) |
410 | { | |
411 | /* wait for other rebuild to complete */ | |
71936fbe | 412 | (void) lockfile(fileno(af), map->map_file, NULL, |
595aeb43 | 413 | LOCK_EX); |
9327783c | 414 | } |
49de3ce1 | 415 | (void) xfclose(af, "rebuildaliases1", map->map_file); |
595aeb43 EA |
416 | errno = 0; |
417 | return; | |
7bdc419c | 418 | } |
595aeb43 | 419 | |
39270cfd | 420 | oldsigint = setsignal(SIGINT, SIG_IGN); |
595aeb43 | 421 | |
31f1ab13 | 422 | if (map->map_class->map_open(map, O_RDWR)) |
713c523f | 423 | { |
9a47e53c EA |
424 | #ifdef LOG |
425 | if (LogLevel > 7) | |
426 | { | |
427 | syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", | |
428 | map->map_file, automatic ? "auto" : "", | |
429 | username()); | |
430 | } | |
431 | #endif /* LOG */ | |
31f1ab13 EA |
432 | map->map_mflags |= MF_OPEN|MF_WRITABLE; |
433 | readaliases(map, af, automatic); | |
434 | } | |
435 | else | |
436 | { | |
437 | if (tTd(27, 1)) | |
438 | printf("Can't create database for %s: %s\n", | |
439 | map->map_file, errstring(errno)); | |
440 | if (!automatic) | |
441 | syserr("Cannot create database for alias file %s", | |
442 | map->map_file); | |
713c523f | 443 | } |
595aeb43 EA |
444 | |
445 | /* close the file, thus releasing locks */ | |
49de3ce1 | 446 | xfclose(af, "rebuildaliases2", map->map_file); |
595aeb43 EA |
447 | |
448 | /* add distinguished entries and close the database */ | |
31f1ab13 | 449 | if (bitset(MF_OPEN, map->map_mflags)) |
713c523f | 450 | map->map_class->map_close(map); |
595aeb43 EA |
451 | |
452 | /* restore the old signal */ | |
39270cfd | 453 | (void) setsignal(SIGINT, oldsigint); |
f4dbf345 EA |
454 | } |
455 | \f/* | |
456 | ** READALIASES -- read and process the alias file. | |
457 | ** | |
458 | ** This routine implements the part of initaliases that occurs | |
459 | ** when we are not going to use the DBM stuff. | |
460 | ** | |
461 | ** Parameters: | |
713c523f | 462 | ** map -- the alias database descriptor. |
595aeb43 | 463 | ** af -- file to read the aliases from. |
cce258e2 | 464 | ** automatic -- set if this was an automatic rebuild. |
f4dbf345 EA |
465 | ** |
466 | ** Returns: | |
467 | ** none. | |
468 | ** | |
469 | ** Side Effects: | |
470 | ** Reads aliasfile into the symbol table. | |
471 | ** Optionally, builds the .dir & .pag files. | |
472 | */ | |
473 | ||
31f1ab13 | 474 | readaliases(map, af, automatic) |
713c523f | 475 | register MAP *map; |
595aeb43 | 476 | FILE *af; |
cce258e2 | 477 | int automatic; |
f4dbf345 | 478 | { |
cdb17311 | 479 | register char *p; |
41173b8f | 480 | char *lhs; |
cdb17311 EA |
481 | char *rhs; |
482 | bool skipping; | |
595aeb43 | 483 | long naliases, bytes, longest; |
7338e3d4 | 484 | ADDRESS al, bl; |
7338e3d4 | 485 | char line[BUFSIZ]; |
e6e345fa | 486 | |
74c5fe7c EA |
487 | /* |
488 | ** Read and interpret lines | |
489 | */ | |
490 | ||
713c523f | 491 | FileName = map->map_file; |
7338e3d4 | 492 | LineNumber = 0; |
d6b27179 | 493 | naliases = bytes = longest = 0; |
cdb17311 EA |
494 | skipping = FALSE; |
495 | while (fgets(line, sizeof (line), af) != NULL) | |
496 | { | |
d6b27179 EA |
497 | int lhssize, rhssize; |
498 | ||
7338e3d4 | 499 | LineNumber++; |
f3d8f6d6 | 500 | p = strchr(line, '\n'); |
3312f93c EA |
501 | if (p != NULL) |
502 | *p = '\0'; | |
cdb17311 EA |
503 | switch (line[0]) |
504 | { | |
505 | case '#': | |
cdb17311 EA |
506 | case '\0': |
507 | skipping = FALSE; | |
508 | continue; | |
bdfaa762 | 509 | |
cdb17311 EA |
510 | case ' ': |
511 | case '\t': | |
512 | if (!skipping) | |
b6edea3d | 513 | syserr("554 Non-continuation line starts with space"); |
cdb17311 | 514 | skipping = TRUE; |
bdfaa762 | 515 | continue; |
cdb17311 EA |
516 | } |
517 | skipping = FALSE; | |
bdfaa762 | 518 | |
74c5fe7c EA |
519 | /* |
520 | ** Process the LHS | |
41173b8f | 521 | ** |
6feb509e | 522 | ** Find the colon separator, and parse the address. |
41173b8f EA |
523 | ** It should resolve to a local name. |
524 | ** | |
525 | ** Alternatively, it can be "@hostname" for host | |
526 | ** aliases -- all we do here is map case. Hostname | |
527 | ** need not be a single token. | |
74c5fe7c EA |
528 | */ |
529 | ||
cdb17311 | 530 | for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) |
bdfaa762 | 531 | continue; |
41173b8f | 532 | if (*p != ':') |
cdb17311 | 533 | { |
1bcdf0a2 | 534 | syserr("%s, line %d: syntax error", aliasfile, lineno); |
bdfaa762 | 535 | continue; |
cdb17311 | 536 | } |
41173b8f EA |
537 | *p++ = '\0'; |
538 | if (line[0] == '@') | |
cdb17311 | 539 | { |
41173b8f EA |
540 | /* a host alias */ |
541 | makelower(line); | |
542 | lhs = line; | |
543 | } | |
544 | else | |
545 | { | |
546 | /* a user alias */ | |
547 | if (parseaddr(line, &al, 1, ':') == NULL) | |
548 | { | |
549 | syserr("illegal alias name"); | |
550 | continue; | |
551 | } | |
552 | loweraddr(&al); | |
553 | if (al.q_mailer != LocalMailer) | |
554 | { | |
555 | syserr("cannot alias non-local names"); | |
556 | continue; | |
557 | } | |
558 | lhs = al.q_user; | |
cdb17311 | 559 | } |
74c5fe7c EA |
560 | |
561 | /* | |
562 | ** Process the RHS. | |
563 | ** 'al' is the internal form of the LHS address. | |
564 | ** 'p' points to the text of the RHS. | |
1bcdf0a2 EA |
565 | ** 'p' may begin with a colon (i.e., the |
566 | ** separator was "::") which will use the | |
567 | ** first address as the person to send | |
568 | ** errors to -- i.e., designates the | |
569 | ** list maintainer. | |
74c5fe7c EA |
570 | */ |
571 | ||
5854bceb EA |
572 | while (isascii(*p) && isspace(*p)) |
573 | p++; | |
1bcdf0a2 EA |
574 | if (*p == ':') |
575 | { | |
576 | ADDRESS *maint; | |
577 | ||
578 | while (isspace(*++p)) | |
579 | continue; | |
580 | rhs = p; | |
581 | while (*p != '\0' && *p != ',') | |
582 | p++; | |
583 | if (*p != ',') | |
584 | goto syntaxerr; | |
585 | *p++ = '\0'; | |
586 | maint = parse(p, (ADDRESS *) NULL, 1); | |
587 | if (maint == NULL) | |
588 | syserr("Illegal list maintainer for list %s", al.q_user); | |
589 | else if (CurEnv->e_returnto == &CurEnv->e_from) | |
590 | { | |
591 | CurEnv->e_returnto = maint; | |
592 | MailBack++; | |
593 | } | |
594 | } | |
595 | ||
cdb17311 | 596 | rhs = p; |
cdb17311 EA |
597 | for (;;) |
598 | { | |
599 | register char c; | |
0957ee6f EA |
600 | register char *nlp; |
601 | ||
602 | nlp = &p[strlen(p)]; | |
603 | if (nlp[-1] == '\n') | |
604 | *--nlp = '\0'; | |
d916f0ca | 605 | |
595aeb43 | 606 | if (CheckAliases) |
cdb17311 | 607 | { |
f4dbf345 | 608 | /* do parsing & compression of addresses */ |
3312f93c | 609 | while (*p != '\0') |
cdb17311 | 610 | { |
9e2cf26f | 611 | auto char *delimptr; |
3312f93c | 612 | |
2bee003d EA |
613 | while ((isascii(*p) && isspace(*p)) || |
614 | *p == ',') | |
c49d661c | 615 | p++; |
3312f93c EA |
616 | if (*p == '\0') |
617 | break; | |
28f94061 EA |
618 | if (parseaddr(p, &bl, RF_COPYNONE, ',', |
619 | &delimptr, CurEnv) == NULL) | |
b6edea3d | 620 | usrerr("553 %s... bad address", p); |
9e2cf26f | 621 | p = delimptr; |
cdb17311 | 622 | } |
cdb17311 | 623 | } |
f4dbf345 | 624 | else |
634c8ff3 | 625 | { |
0957ee6f | 626 | p = nlp; |
634c8ff3 | 627 | } |
d916f0ca | 628 | |
cdb17311 | 629 | /* see if there should be a continuation line */ |
9e25d1f0 EA |
630 | c = fgetc(af); |
631 | if (!feof(af)) | |
74c5fe7c | 632 | (void) ungetc(c, af); |
9e25d1f0 | 633 | if (c != ' ' && c != '\t') |
cdb17311 EA |
634 | break; |
635 | ||
636 | /* read continuation line */ | |
cdb17311 EA |
637 | if (fgets(p, sizeof line - (p - line), af) == NULL) |
638 | break; | |
7338e3d4 | 639 | LineNumber++; |
07b49560 EA |
640 | |
641 | /* check for line overflow */ | |
642 | if (strchr(p, '\n') == NULL) | |
643 | { | |
b6edea3d | 644 | usrerr("554 alias too long"); |
07b49560 EA |
645 | break; |
646 | } | |
cdb17311 | 647 | } |
74c5fe7c EA |
648 | |
649 | /* | |
650 | ** Insert alias into symbol table or DBM file | |
651 | */ | |
652 | ||
41173b8f | 653 | lhssize = strlen(lhs) + 1; |
d6b27179 | 654 | |
595aeb43 EA |
655 | lhssize = strlen(al.q_user); |
656 | rhssize = strlen(rhs); | |
713c523f | 657 | map->map_class->map_store(map, al.q_user, rhs); |
f4dbf345 | 658 | |
595aeb43 EA |
659 | if (al.q_paddr != NULL) |
660 | free(al.q_paddr); | |
661 | if (al.q_host != NULL) | |
662 | free(al.q_host); | |
663 | if (al.q_user != NULL) | |
664 | free(al.q_user); | |
d6b27179 EA |
665 | |
666 | /* statistics */ | |
667 | naliases++; | |
668 | bytes += lhssize + rhssize; | |
669 | if (rhssize > longest) | |
670 | longest = rhssize; | |
d916f0ca | 671 | } |
e6e345fa | 672 | |
31f1ab13 | 673 | CurEnv->e_to = NULL; |
595aeb43 | 674 | FileName = NULL; |
cce258e2 EA |
675 | if (Verbose || !automatic) |
676 | message("%s: %d aliases, longest %d bytes, %d bytes total", | |
713c523f | 677 | map->map_file, naliases, longest, bytes); |
595aeb43 EA |
678 | # ifdef LOG |
679 | if (LogLevel > 7) | |
680 | syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", | |
713c523f | 681 | map->map_file, naliases, longest, bytes); |
595aeb43 EA |
682 | # endif /* LOG */ |
683 | } | |
684 | \f/* | |
b3cbe40f EA |
685 | ** FORWARD -- Try to forward mail |
686 | ** | |
687 | ** This is similar but not identical to aliasing. | |
688 | ** | |
b3cbe40f | 689 | ** Parameters: |
74c5fe7c EA |
690 | ** user -- the name of the user who's mail we would like |
691 | ** to forward to. It must have been verified -- | |
692 | ** i.e., the q_home field must have been filled | |
693 | ** in. | |
d4f42161 EA |
694 | ** sendq -- a pointer to the head of the send queue to |
695 | ** put this user's aliases in. | |
b3cbe40f EA |
696 | ** |
697 | ** Returns: | |
cdb17311 | 698 | ** none. |
b3cbe40f EA |
699 | ** |
700 | ** Side Effects: | |
9e3c0a28 | 701 | ** New names are added to send queues. |
b3cbe40f EA |
702 | */ |
703 | ||
a4076aed | 704 | forward(user, sendq, e) |
a530c75f | 705 | ADDRESS *user; |
d4f42161 | 706 | ADDRESS **sendq; |
a4076aed | 707 | register ENVELOPE *e; |
b3cbe40f | 708 | { |
e0136832 EA |
709 | char *pp; |
710 | char *ep; | |
56678245 | 711 | |
9678c96d | 712 | if (tTd(27, 1)) |
cdb17311 | 713 | printf("forward(%s)\n", user->q_paddr); |
cdb17311 | 714 | |
179c1218 | 715 | if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) |
cdb17311 | 716 | return; |
74c5fe7c | 717 | if (user->q_home == NULL) |
c25096f0 | 718 | { |
b6edea3d | 719 | syserr("554 forward: no home"); |
c25096f0 EA |
720 | user->q_home = "/nosuchdirectory"; |
721 | } | |
56678245 | 722 | |
56678245 | 723 | /* good address -- look for .forward file in home */ |
a4076aed | 724 | define('z', user->q_home, e); |
e0136832 EA |
725 | define('u', user->q_user, e); |
726 | define('h', user->q_host, e); | |
727 | if (ForwardPath == NULL) | |
2bee003d | 728 | ForwardPath = newstr("\201z/.forward"); |
e0136832 EA |
729 | |
730 | for (pp = ForwardPath; pp != NULL; pp = ep) | |
731 | { | |
118e6693 | 732 | int err; |
f43b04ce | 733 | char buf[MAXPATHLEN+1]; |
e0136832 EA |
734 | |
735 | ep = strchr(pp, ':'); | |
736 | if (ep != NULL) | |
737 | *ep = '\0'; | |
738 | expand(pp, buf, &buf[sizeof buf - 1], e); | |
739 | if (ep != NULL) | |
740 | *ep++ = ':'; | |
741 | if (tTd(27, 3)) | |
742 | printf("forward: trying %s\n", buf); | |
8e5c6745 | 743 | |
118e6693 EA |
744 | err = include(buf, TRUE, user, sendq, e); |
745 | if (err == 0) | |
e0136832 | 746 | break; |
a614cf3b | 747 | else if (transienterror(err)) |
118e6693 EA |
748 | { |
749 | /* we have to suspend this message */ | |
d50bcc17 EA |
750 | if (tTd(27, 2)) |
751 | printf("forward: transient error on %s\n", buf); | |
752 | #ifdef LOG | |
753 | if (LogLevel > 2) | |
3f0792d1 EA |
754 | syslog(LOG_ERR, "%s: forward %s: transient error: %s", |
755 | e->e_id, buf, errstring(err)); | |
d50bcc17 | 756 | #endif |
dd61ea05 | 757 | message("%s: %s: message queued", buf, errstring(err)); |
c069e0df | 758 | user->q_flags |= QQUEUEUP; |
118e6693 EA |
759 | return; |
760 | } | |
e0136832 | 761 | } |
b3cbe40f | 762 | } |
41173b8f EA |
763 | \f/* |
764 | ** MAPHOST -- given a host description, produce a mapping. | |
765 | ** | |
766 | ** This is done by looking up the name in the alias file, | |
767 | ** preceeded by an "@". This can be used for UUCP mapping. | |
768 | ** For example, a call with {blia, ., UUCP} as arguments | |
769 | ** might return {ucsfcgl, !, blia, ., UUCP} as the result. | |
770 | ** | |
771 | ** We first break the input into three parts -- before the | |
772 | ** lookup, the lookup itself, and after the lookup. We | |
773 | ** then do the lookup, concatenate them together, and rescan | |
774 | ** the result. | |
775 | ** | |
776 | ** Parameters: | |
777 | ** pvp -- the parameter vector to map. | |
778 | ** | |
779 | ** Returns: | |
780 | ** The result of the mapping. If nothing found, it | |
781 | ** should just concatenate the three parts together and | |
782 | ** return that. | |
783 | ** | |
784 | ** Side Effects: | |
785 | ** none. | |
786 | */ | |
787 | ||
788 | char ** | |
789 | maphost(pvp) | |
790 | char **pvp; | |
791 | { | |
792 | register char **avp; | |
793 | register char **bvp; | |
794 | char *p; | |
795 | char buf1[MAXNAME]; | |
796 | char buf2[MAXNAME]; | |
797 | char buf3[MAXNAME]; | |
798 | extern char **prescan(); | |
799 | ||
800 | /* | |
801 | ** Extract the three parts of the input as strings. | |
802 | */ | |
803 | ||
804 | /* find the part before the lookup */ | |
805 | for (bvp = pvp; *bvp != NULL && **bvp != MATCHLOOKUP; bvp++) | |
806 | continue; | |
807 | if (*bvp == NULL) | |
808 | return (pvp); | |
809 | p = *bvp; | |
810 | *bvp = NULL; | |
811 | cataddr(pvp, buf1, sizeof buf1); | |
812 | *bvp++ = p; | |
813 | ||
814 | /* find the rest of the lookup */ | |
815 | for (avp = bvp; *pvp != NULL && **bvp != MATCHELOOKUP; bvp++) | |
816 | continue; | |
817 | if (*bvp == NULL) | |
818 | return (pvp); | |
819 | p = *bvp; | |
820 | *bvp = NULL; | |
821 | cataddr(avp, buf2, sizeof buf2); | |
822 | *bvp++ = p; | |
823 | ||
824 | /* save the part after the lookup */ | |
825 | cataddr(bvp, buf3, sizeof buf3); | |
826 | ||
827 | /* | |
828 | ** Now look up the middle part. | |
829 | */ | |
830 | ||
831 | p = aliaslookup(buf2); | |
832 | if (p != NULL) | |
833 | strcpy(buf2, p); | |
834 | ||
835 | /* | |
836 | ** Put the three parts back together and break into tokens. | |
837 | */ | |
838 | ||
839 | strcat(buf1, buf2); | |
840 | strcat(buf1, buf3); | |
841 | avp = prescan(buf1, '\0'); | |
842 | ||
843 | /* return this mapping */ | |
844 | return (avp); | |
845 | } |