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