Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1983 Eric P. Allman | |
6f14531a RG |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
15637ed4 RG |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
6f14531a | 35 | # include "sendmail.h" |
6f14531a RG |
36 | # include <pwd.h> |
37 | ||
15637ed4 | 38 | #ifndef lint |
69fc843f | 39 | static char sccsid[] = "@(#)alias.c 8.19 (Berkeley) 10/31/93"; |
15637ed4 RG |
40 | #endif /* not lint */ |
41 | ||
15637ed4 | 42 | |
6f14531a RG |
43 | MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */ |
44 | int NAliasDBs; /* number of alias databases */ | |
45 | \f/* | |
15637ed4 RG |
46 | ** ALIAS -- Compute aliases. |
47 | ** | |
48 | ** Scans the alias file for an alias for the given address. | |
49 | ** If found, it arranges to deliver to the alias list instead. | |
50 | ** Uses libdbm database if -DDBM. | |
51 | ** | |
52 | ** Parameters: | |
53 | ** a -- address to alias. | |
54 | ** sendq -- a pointer to the head of the send queue | |
55 | ** to put the aliases in. | |
6f14531a | 56 | ** e -- the current envelope. |
15637ed4 RG |
57 | ** |
58 | ** Returns: | |
59 | ** none | |
60 | ** | |
61 | ** Side Effects: | |
62 | ** Aliases found are expanded. | |
63 | ** | |
15637ed4 RG |
64 | ** Deficiencies: |
65 | ** It should complain about names that are aliased to | |
66 | ** nothing. | |
67 | */ | |
68 | ||
6f14531a | 69 | alias(a, sendq, e) |
15637ed4 RG |
70 | register ADDRESS *a; |
71 | ADDRESS **sendq; | |
6f14531a | 72 | register ENVELOPE *e; |
15637ed4 RG |
73 | { |
74 | register char *p; | |
6f14531a RG |
75 | int naliases; |
76 | char *owner; | |
77 | char obuf[MAXNAME + 6]; | |
15637ed4 RG |
78 | extern char *aliaslookup(); |
79 | ||
80 | if (tTd(27, 1)) | |
81 | printf("alias(%s)\n", a->q_paddr); | |
82 | ||
83 | /* don't realias already aliased names */ | |
6f14531a | 84 | if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) |
15637ed4 RG |
85 | return; |
86 | ||
6f14531a RG |
87 | if (NoAlias) |
88 | return; | |
89 | ||
90 | e->e_to = a->q_paddr; | |
15637ed4 RG |
91 | |
92 | /* | |
93 | ** Look up this name | |
94 | */ | |
95 | ||
6f14531a | 96 | p = aliaslookup(a->q_user, e); |
15637ed4 RG |
97 | if (p == NULL) |
98 | return; | |
99 | ||
100 | /* | |
101 | ** Match on Alias. | |
102 | ** Deliver to the target list. | |
103 | */ | |
104 | ||
105 | if (tTd(27, 1)) | |
106 | printf("%s (%s, %s) aliased to %s\n", | |
107 | a->q_paddr, a->q_host, a->q_user, p); | |
6f14531a RG |
108 | if (bitset(EF_VRFYONLY, e->e_flags)) |
109 | { | |
110 | a->q_flags |= QVERIFIED; | |
111 | e->e_nrcpts++; | |
112 | return; | |
113 | } | |
114 | message("aliased to %s", p); | |
115 | #ifdef LOG | |
116 | if (LogLevel > 9) | |
117 | syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); | |
118 | #endif | |
119 | a->q_flags &= ~QSELFREF; | |
15637ed4 | 120 | AliasLevel++; |
6f14531a | 121 | naliases = sendtolist(p, a, sendq, e); |
15637ed4 | 122 | AliasLevel--; |
d747e748 | 123 | if (!bitset(QSELFREF, a->q_flags)) |
6f14531a RG |
124 | { |
125 | if (tTd(27, 5)) | |
126 | { | |
127 | printf("alias: QDONTSEND "); | |
128 | printaddr(a, FALSE); | |
129 | } | |
130 | a->q_flags |= QDONTSEND; | |
131 | } | |
132 | ||
133 | /* | |
134 | ** Look for owner of alias | |
135 | */ | |
136 | ||
137 | (void) strcpy(obuf, "owner-"); | |
138 | if (strncmp(a->q_user, "owner-", 6) == 0) | |
139 | (void) strcat(obuf, "owner"); | |
140 | else | |
141 | (void) strcat(obuf, a->q_user); | |
142 | if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) | |
143 | makelower(obuf); | |
144 | owner = aliaslookup(obuf, e); | |
145 | if (owner != NULL) | |
146 | { | |
147 | if (strchr(owner, ',') != NULL) | |
148 | owner = obuf; | |
149 | a->q_owner = newstr(owner); | |
150 | } | |
15637ed4 RG |
151 | } |
152 | \f/* | |
153 | ** ALIASLOOKUP -- look up a name in the alias file. | |
154 | ** | |
155 | ** Parameters: | |
156 | ** name -- the name to look up. | |
157 | ** | |
158 | ** Returns: | |
159 | ** the value of name. | |
160 | ** NULL if unknown. | |
161 | ** | |
162 | ** Side Effects: | |
163 | ** none. | |
164 | ** | |
165 | ** Warnings: | |
166 | ** The return value will be trashed across calls. | |
167 | */ | |
168 | ||
169 | char * | |
6f14531a | 170 | aliaslookup(name, e) |
15637ed4 | 171 | char *name; |
6f14531a | 172 | ENVELOPE *e; |
15637ed4 | 173 | { |
6f14531a RG |
174 | register int dbno; |
175 | register MAP *map; | |
176 | register char *p; | |
177 | ||
178 | for (dbno = 0; dbno < NAliasDBs; dbno++) | |
179 | { | |
180 | auto int stat; | |
181 | ||
182 | map = AliasDB[dbno]; | |
183 | if (!bitset(MF_OPEN, map->map_mflags)) | |
184 | continue; | |
185 | p = (*map->map_class->map_lookup)(map, name, NULL, &stat); | |
186 | if (p != NULL) | |
187 | return p; | |
188 | } | |
189 | return NULL; | |
15637ed4 RG |
190 | } |
191 | \f/* | |
6f14531a | 192 | ** SETALIAS -- set up an alias map |
15637ed4 | 193 | ** |
6f14531a | 194 | ** Called when reading configuration file. |
15637ed4 RG |
195 | ** |
196 | ** Parameters: | |
6f14531a | 197 | ** spec -- the alias specification |
15637ed4 RG |
198 | ** |
199 | ** Returns: | |
200 | ** none. | |
15637ed4 RG |
201 | */ |
202 | ||
6f14531a RG |
203 | setalias(spec) |
204 | char *spec; | |
15637ed4 | 205 | { |
6f14531a RG |
206 | register char *p; |
207 | register MAP *map; | |
208 | char *class; | |
209 | STAB *s; | |
15637ed4 | 210 | |
6f14531a RG |
211 | if (tTd(27, 8)) |
212 | printf("setalias(%s)\n", spec); | |
15637ed4 | 213 | |
6f14531a | 214 | for (p = spec; p != NULL; ) |
15637ed4 | 215 | { |
6f14531a RG |
216 | char aname[50]; |
217 | ||
218 | while (isspace(*p)) | |
219 | p++; | |
220 | if (*p == '\0') | |
221 | break; | |
222 | spec = p; | |
223 | ||
224 | if (NAliasDBs >= MAXALIASDB) | |
225 | { | |
226 | syserr("Too many alias databases defined, %d max", MAXALIASDB); | |
227 | return; | |
228 | } | |
229 | (void) sprintf(aname, "Alias%d", NAliasDBs); | |
230 | s = stab(aname, ST_MAP, ST_ENTER); | |
231 | map = &s->s_map; | |
232 | AliasDB[NAliasDBs] = map; | |
233 | bzero(map, sizeof *map); | |
234 | ||
235 | p = strpbrk(p, " ,/:"); | |
236 | if (p != NULL && *p == ':') | |
237 | { | |
238 | /* map name */ | |
239 | *p++ = '\0'; | |
240 | class = spec; | |
241 | spec = p; | |
242 | } | |
243 | else | |
244 | { | |
245 | class = "implicit"; | |
246 | map->map_mflags = MF_OPTIONAL|MF_INCLNULL; | |
247 | } | |
248 | ||
249 | /* find end of spec */ | |
250 | if (p != NULL) | |
251 | p = strchr(p, ','); | |
252 | if (p != NULL) | |
253 | *p++ = '\0'; | |
254 | ||
255 | /* look up class */ | |
256 | s = stab(class, ST_MAPCLASS, ST_FIND); | |
257 | if (s == NULL) | |
258 | { | |
259 | if (tTd(27, 1)) | |
260 | printf("Unknown alias class %s\n", class); | |
261 | } | |
262 | else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) | |
263 | { | |
264 | syserr("setalias: map class %s can't handle aliases", | |
265 | class); | |
266 | } | |
267 | else | |
268 | { | |
269 | map->map_class = &s->s_mapclass; | |
270 | if (map->map_class->map_parse(map, spec)) | |
271 | { | |
272 | map->map_mflags |= MF_VALID|MF_ALIAS; | |
273 | NAliasDBs++; | |
274 | } | |
275 | } | |
15637ed4 | 276 | } |
6f14531a RG |
277 | } |
278 | \f/* | |
279 | ** ALIASWAIT -- wait for distinguished @:@ token to appear. | |
280 | ** | |
281 | ** This can decide to reopen or rebuild the alias file | |
d747e748 JH |
282 | ** |
283 | ** Parameters: | |
284 | ** map -- a pointer to the map descriptor for this alias file. | |
285 | ** ext -- the filename extension (e.g., ".db") for the | |
286 | ** database file. | |
287 | ** isopen -- if set, the database is already open, and we | |
288 | ** should check for validity; otherwise, we are | |
289 | ** just checking to see if it should be created. | |
290 | ** | |
291 | ** Returns: | |
292 | ** TRUE -- if the database is open when we return. | |
293 | ** FALSE -- if the database is closed when we return. | |
6f14531a | 294 | */ |
15637ed4 | 295 | |
d747e748 JH |
296 | bool |
297 | aliaswait(map, ext, isopen) | |
6f14531a RG |
298 | MAP *map; |
299 | char *ext; | |
d747e748 | 300 | int isopen; |
6f14531a | 301 | { |
69fc843f | 302 | bool attimeout = FALSE; |
6f14531a RG |
303 | time_t mtime; |
304 | struct stat stb; | |
305 | char buf[MAXNAME]; | |
306 | ||
307 | if (tTd(27, 3)) | |
308 | printf("aliaswait(%s:%s)\n", | |
309 | map->map_class->map_cname, map->map_file); | |
d747e748 | 310 | if (bitset(MF_ALIASWAIT, map->map_mflags)) |
69fc843f | 311 | return isopen; |
d747e748 | 312 | map->map_mflags |= MF_ALIASWAIT; |
15637ed4 | 313 | |
69fc843f | 314 | if (SafeAlias > 0) |
15637ed4 | 315 | { |
6f14531a | 316 | auto int st; |
69fc843f AM |
317 | time_t toolong = curtime() + SafeAlias; |
318 | unsigned int sleeptime = 2; | |
6f14531a | 319 | |
69fc843f | 320 | while (isopen && |
6f14531a | 321 | map->map_class->map_lookup(map, "@", NULL, &st) == NULL) |
15637ed4 | 322 | { |
69fc843f AM |
323 | if (curtime() > toolong) |
324 | { | |
325 | /* we timed out */ | |
326 | attimeout = TRUE; | |
327 | break; | |
328 | } | |
329 | ||
15637ed4 | 330 | /* |
6f14531a RG |
331 | ** Close and re-open the alias database in case |
332 | ** the one is mv'ed instead of cp'ed in. | |
15637ed4 RG |
333 | */ |
334 | ||
6f14531a | 335 | if (tTd(27, 2)) |
69fc843f AM |
336 | printf("aliaswait: sleeping for %d seconds\n", |
337 | sleeptime); | |
6f14531a RG |
338 | |
339 | map->map_class->map_close(map); | |
69fc843f AM |
340 | sleep(sleeptime); |
341 | sleeptime *= 2; | |
342 | if (sleeptime > 60) | |
343 | sleeptime = 60; | |
d747e748 | 344 | isopen = map->map_class->map_open(map, O_RDONLY); |
15637ed4 RG |
345 | } |
346 | } | |
15637ed4 | 347 | |
6f14531a RG |
348 | /* see if we need to go into auto-rebuild mode */ |
349 | if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) | |
15637ed4 | 350 | { |
6f14531a RG |
351 | if (tTd(27, 3)) |
352 | printf("aliaswait: not rebuildable\n"); | |
d747e748 JH |
353 | map->map_mflags &= ~MF_ALIASWAIT; |
354 | return isopen; | |
6f14531a RG |
355 | } |
356 | if (stat(map->map_file, &stb) < 0) | |
357 | { | |
358 | if (tTd(27, 3)) | |
359 | printf("aliaswait: no source file\n"); | |
d747e748 JH |
360 | map->map_mflags &= ~MF_ALIASWAIT; |
361 | return isopen; | |
6f14531a RG |
362 | } |
363 | mtime = stb.st_mtime; | |
364 | (void) strcpy(buf, map->map_file); | |
365 | if (ext != NULL) | |
366 | (void) strcat(buf, ext); | |
69fc843f | 367 | if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) |
6f14531a RG |
368 | { |
369 | /* database is out of date */ | |
15637ed4 RG |
370 | if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) |
371 | { | |
6f14531a | 372 | message("auto-rebuilding alias database %s", buf); |
d747e748 JH |
373 | if (isopen) |
374 | map->map_class->map_close(map); | |
6f14531a | 375 | rebuildaliases(map, TRUE); |
d747e748 | 376 | isopen = map->map_class->map_open(map, O_RDONLY); |
15637ed4 RG |
377 | } |
378 | else | |
379 | { | |
380 | #ifdef LOG | |
6f14531a RG |
381 | if (LogLevel > 3) |
382 | syslog(LOG_INFO, "alias database %s out of date", | |
383 | buf); | |
384 | #endif /* LOG */ | |
385 | message("Warning: alias database %s out of date", buf); | |
15637ed4 RG |
386 | } |
387 | } | |
d747e748 JH |
388 | map->map_mflags &= ~MF_ALIASWAIT; |
389 | return isopen; | |
15637ed4 RG |
390 | } |
391 | \f/* | |
6f14531a | 392 | ** REBUILDALIASES -- rebuild the alias database. |
15637ed4 RG |
393 | ** |
394 | ** Parameters: | |
6f14531a RG |
395 | ** map -- the database to rebuild. |
396 | ** automatic -- set if this was automatically generated. | |
15637ed4 RG |
397 | ** |
398 | ** Returns: | |
399 | ** none. | |
400 | ** | |
401 | ** Side Effects: | |
6f14531a RG |
402 | ** Reads the text version of the database, builds the |
403 | ** DBM or DB version. | |
15637ed4 RG |
404 | */ |
405 | ||
6f14531a RG |
406 | rebuildaliases(map, automatic) |
407 | register MAP *map; | |
408 | bool automatic; | |
15637ed4 | 409 | { |
15637ed4 | 410 | FILE *af; |
d747e748 JH |
411 | bool nolock = FALSE; |
412 | sigfunc_t oldsigint; | |
15637ed4 | 413 | |
6f14531a RG |
414 | if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) |
415 | return; | |
416 | ||
6f14531a RG |
417 | /* try to lock the source file */ |
418 | if ((af = fopen(map->map_file, "r+")) == NULL) | |
15637ed4 | 419 | { |
d747e748 JH |
420 | if (errno != EACCES || automatic || |
421 | (af = fopen(map->map_file, "r")) == NULL) | |
422 | { | |
423 | int saveerr = errno; | |
424 | ||
425 | if (tTd(27, 1)) | |
426 | printf("Can't open %s: %s\n", | |
427 | map->map_file, errstring(saveerr)); | |
428 | if (!automatic) | |
429 | message("newaliases: cannot open %s: %s", | |
430 | map->map_file, errstring(saveerr)); | |
431 | errno = 0; | |
432 | return; | |
433 | } | |
434 | nolock = TRUE; | |
435 | message("warning: cannot lock %s: %s", | |
436 | map->map_file, errstring(errno)); | |
15637ed4 RG |
437 | } |
438 | ||
6f14531a | 439 | /* see if someone else is rebuilding the alias file */ |
d747e748 JH |
440 | if (!nolock && |
441 | !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) | |
15637ed4 | 442 | { |
6f14531a RG |
443 | /* yes, they are -- wait until done */ |
444 | message("Alias file %s is already being rebuilt", | |
445 | map->map_file); | |
15637ed4 RG |
446 | if (OpMode != MD_INITALIAS) |
447 | { | |
448 | /* wait for other rebuild to complete */ | |
d747e748 | 449 | (void) lockfile(fileno(af), map->map_file, NULL, |
6f14531a | 450 | LOCK_EX); |
15637ed4 | 451 | } |
69fc843f | 452 | (void) xfclose(af, "rebuildaliases1", map->map_file); |
15637ed4 RG |
453 | errno = 0; |
454 | return; | |
455 | } | |
456 | ||
d747e748 | 457 | oldsigint = setsignal(SIGINT, SIG_IGN); |
15637ed4 | 458 | |
6f14531a | 459 | if (map->map_class->map_open(map, O_RDWR)) |
15637ed4 | 460 | { |
d747e748 JH |
461 | #ifdef LOG |
462 | if (LogLevel > 7) | |
463 | { | |
464 | syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", | |
465 | map->map_file, automatic ? "auto" : "", | |
466 | username()); | |
467 | } | |
468 | #endif /* LOG */ | |
6f14531a RG |
469 | map->map_mflags |= MF_OPEN|MF_WRITABLE; |
470 | readaliases(map, af, automatic); | |
15637ed4 | 471 | } |
6f14531a RG |
472 | else |
473 | { | |
474 | if (tTd(27, 1)) | |
475 | printf("Can't create database for %s: %s\n", | |
476 | map->map_file, errstring(errno)); | |
477 | if (!automatic) | |
478 | syserr("Cannot create database for alias file %s", | |
479 | map->map_file); | |
480 | } | |
481 | ||
482 | /* close the file, thus releasing locks */ | |
69fc843f | 483 | xfclose(af, "rebuildaliases2", map->map_file); |
6f14531a RG |
484 | |
485 | /* add distinguished entries and close the database */ | |
486 | if (bitset(MF_OPEN, map->map_mflags)) | |
487 | map->map_class->map_close(map); | |
488 | ||
489 | /* restore the old signal */ | |
d747e748 | 490 | (void) setsignal(SIGINT, oldsigint); |
6f14531a RG |
491 | } |
492 | \f/* | |
493 | ** READALIASES -- read and process the alias file. | |
494 | ** | |
495 | ** This routine implements the part of initaliases that occurs | |
496 | ** when we are not going to use the DBM stuff. | |
497 | ** | |
498 | ** Parameters: | |
499 | ** map -- the alias database descriptor. | |
500 | ** af -- file to read the aliases from. | |
501 | ** automatic -- set if this was an automatic rebuild. | |
502 | ** | |
503 | ** Returns: | |
504 | ** none. | |
505 | ** | |
506 | ** Side Effects: | |
507 | ** Reads aliasfile into the symbol table. | |
508 | ** Optionally, builds the .dir & .pag files. | |
509 | */ | |
510 | ||
511 | readaliases(map, af, automatic) | |
512 | register MAP *map; | |
513 | FILE *af; | |
514 | int automatic; | |
515 | { | |
516 | register char *p; | |
517 | char *rhs; | |
518 | bool skipping; | |
519 | long naliases, bytes, longest; | |
520 | ADDRESS al, bl; | |
521 | char line[BUFSIZ]; | |
15637ed4 RG |
522 | |
523 | /* | |
524 | ** Read and interpret lines | |
525 | */ | |
526 | ||
6f14531a | 527 | FileName = map->map_file; |
15637ed4 RG |
528 | LineNumber = 0; |
529 | naliases = bytes = longest = 0; | |
530 | skipping = FALSE; | |
531 | while (fgets(line, sizeof (line), af) != NULL) | |
532 | { | |
533 | int lhssize, rhssize; | |
534 | ||
535 | LineNumber++; | |
6f14531a | 536 | p = strchr(line, '\n'); |
15637ed4 RG |
537 | if (p != NULL) |
538 | *p = '\0'; | |
539 | switch (line[0]) | |
540 | { | |
541 | case '#': | |
542 | case '\0': | |
543 | skipping = FALSE; | |
544 | continue; | |
545 | ||
546 | case ' ': | |
547 | case '\t': | |
548 | if (!skipping) | |
6f14531a | 549 | syserr("554 Non-continuation line starts with space"); |
15637ed4 RG |
550 | skipping = TRUE; |
551 | continue; | |
552 | } | |
553 | skipping = FALSE; | |
554 | ||
555 | /* | |
556 | ** Process the LHS | |
6f14531a | 557 | ** Find the colon separator, and parse the address. |
15637ed4 RG |
558 | ** It should resolve to a local name -- this will |
559 | ** be checked later (we want to optionally do | |
560 | ** parsing of the RHS first to maximize error | |
561 | ** detection). | |
562 | */ | |
563 | ||
564 | for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) | |
565 | continue; | |
566 | if (*p++ != ':') | |
567 | { | |
6f14531a | 568 | syserr("554 missing colon"); |
15637ed4 RG |
569 | continue; |
570 | } | |
d747e748 | 571 | if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) |
15637ed4 | 572 | { |
d747e748 | 573 | syserr("554 %s... illegal alias name", al.q_paddr); |
15637ed4 RG |
574 | continue; |
575 | } | |
15637ed4 RG |
576 | |
577 | /* | |
578 | ** Process the RHS. | |
579 | ** 'al' is the internal form of the LHS address. | |
580 | ** 'p' points to the text of the RHS. | |
581 | */ | |
582 | ||
6f14531a RG |
583 | while (isascii(*p) && isspace(*p)) |
584 | p++; | |
15637ed4 RG |
585 | rhs = p; |
586 | for (;;) | |
587 | { | |
588 | register char c; | |
6f14531a RG |
589 | register char *nlp; |
590 | ||
591 | nlp = &p[strlen(p)]; | |
592 | if (nlp[-1] == '\n') | |
593 | *--nlp = '\0'; | |
15637ed4 | 594 | |
6f14531a | 595 | if (CheckAliases) |
15637ed4 RG |
596 | { |
597 | /* do parsing & compression of addresses */ | |
598 | while (*p != '\0') | |
599 | { | |
6f14531a | 600 | auto char *delimptr; |
15637ed4 | 601 | |
6f14531a RG |
602 | while ((isascii(*p) && isspace(*p)) || |
603 | *p == ',') | |
15637ed4 RG |
604 | p++; |
605 | if (*p == '\0') | |
606 | break; | |
d747e748 JH |
607 | if (parseaddr(p, &bl, RF_COPYNONE, ',', |
608 | &delimptr, CurEnv) == NULL) | |
6f14531a RG |
609 | usrerr("553 %s... bad address", p); |
610 | p = delimptr; | |
15637ed4 RG |
611 | } |
612 | } | |
613 | else | |
614 | { | |
6f14531a | 615 | p = nlp; |
15637ed4 RG |
616 | } |
617 | ||
618 | /* see if there should be a continuation line */ | |
619 | c = fgetc(af); | |
620 | if (!feof(af)) | |
621 | (void) ungetc(c, af); | |
622 | if (c != ' ' && c != '\t') | |
623 | break; | |
624 | ||
625 | /* read continuation line */ | |
626 | if (fgets(p, sizeof line - (p - line), af) == NULL) | |
627 | break; | |
628 | LineNumber++; | |
6f14531a RG |
629 | |
630 | /* check for line overflow */ | |
631 | if (strchr(p, '\n') == NULL) | |
632 | { | |
633 | usrerr("554 alias too long"); | |
634 | break; | |
635 | } | |
15637ed4 RG |
636 | } |
637 | if (al.q_mailer != LocalMailer) | |
638 | { | |
d747e748 JH |
639 | syserr("554 %s... cannot alias non-local names", |
640 | al.q_paddr); | |
15637ed4 RG |
641 | continue; |
642 | } | |
643 | ||
644 | /* | |
645 | ** Insert alias into symbol table or DBM file | |
646 | */ | |
647 | ||
6f14531a RG |
648 | if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) |
649 | makelower(al.q_user); | |
15637ed4 | 650 | |
6f14531a RG |
651 | lhssize = strlen(al.q_user); |
652 | rhssize = strlen(rhs); | |
653 | map->map_class->map_store(map, al.q_user, rhs); | |
15637ed4 | 654 | |
6f14531a RG |
655 | if (al.q_paddr != NULL) |
656 | free(al.q_paddr); | |
657 | if (al.q_host != NULL) | |
658 | free(al.q_host); | |
659 | if (al.q_user != NULL) | |
660 | free(al.q_user); | |
15637ed4 RG |
661 | |
662 | /* statistics */ | |
663 | naliases++; | |
664 | bytes += lhssize + rhssize; | |
665 | if (rhssize > longest) | |
666 | longest = rhssize; | |
667 | } | |
668 | ||
15637ed4 RG |
669 | CurEnv->e_to = NULL; |
670 | FileName = NULL; | |
6f14531a RG |
671 | if (Verbose || !automatic) |
672 | message("%s: %d aliases, longest %d bytes, %d bytes total", | |
673 | map->map_file, naliases, longest, bytes); | |
15637ed4 | 674 | # ifdef LOG |
6f14531a RG |
675 | if (LogLevel > 7) |
676 | syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", | |
677 | map->map_file, naliases, longest, bytes); | |
678 | # endif /* LOG */ | |
15637ed4 RG |
679 | } |
680 | \f/* | |
681 | ** FORWARD -- Try to forward mail | |
682 | ** | |
683 | ** This is similar but not identical to aliasing. | |
684 | ** | |
685 | ** Parameters: | |
686 | ** user -- the name of the user who's mail we would like | |
687 | ** to forward to. It must have been verified -- | |
688 | ** i.e., the q_home field must have been filled | |
689 | ** in. | |
690 | ** sendq -- a pointer to the head of the send queue to | |
691 | ** put this user's aliases in. | |
692 | ** | |
693 | ** Returns: | |
694 | ** none. | |
695 | ** | |
696 | ** Side Effects: | |
697 | ** New names are added to send queues. | |
698 | */ | |
699 | ||
6f14531a | 700 | forward(user, sendq, e) |
15637ed4 RG |
701 | ADDRESS *user; |
702 | ADDRESS **sendq; | |
6f14531a | 703 | register ENVELOPE *e; |
15637ed4 | 704 | { |
6f14531a RG |
705 | char *pp; |
706 | char *ep; | |
15637ed4 RG |
707 | |
708 | if (tTd(27, 1)) | |
709 | printf("forward(%s)\n", user->q_paddr); | |
710 | ||
711 | if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) | |
712 | return; | |
713 | if (user->q_home == NULL) | |
6f14531a RG |
714 | { |
715 | syserr("554 forward: no home"); | |
716 | user->q_home = "/nosuchdirectory"; | |
717 | } | |
15637ed4 RG |
718 | |
719 | /* good address -- look for .forward file in home */ | |
6f14531a RG |
720 | define('z', user->q_home, e); |
721 | define('u', user->q_user, e); | |
722 | define('h', user->q_host, e); | |
723 | if (ForwardPath == NULL) | |
724 | ForwardPath = newstr("\201z/.forward"); | |
15637ed4 | 725 | |
6f14531a RG |
726 | for (pp = ForwardPath; pp != NULL; pp = ep) |
727 | { | |
728 | int err; | |
729 | char buf[MAXPATHLEN+1]; | |
730 | ||
731 | ep = strchr(pp, ':'); | |
732 | if (ep != NULL) | |
733 | *ep = '\0'; | |
734 | expand(pp, buf, &buf[sizeof buf - 1], e); | |
735 | if (ep != NULL) | |
736 | *ep++ = ':'; | |
737 | if (tTd(27, 3)) | |
738 | printf("forward: trying %s\n", buf); | |
3a363396 | 739 | |
6f14531a RG |
740 | err = include(buf, TRUE, user, sendq, e); |
741 | if (err == 0) | |
742 | break; | |
d747e748 | 743 | else if (transienterror(err)) |
6f14531a RG |
744 | { |
745 | /* we have to suspend this message */ | |
746 | if (tTd(27, 2)) | |
747 | printf("forward: transient error on %s\n", buf); | |
748 | #ifdef LOG | |
749 | if (LogLevel > 2) | |
750 | syslog(LOG_ERR, "%s: forward %s: transient error: %s", | |
751 | e->e_id, buf, errstring(err)); | |
752 | #endif | |
753 | message("%s: %s: message queued", buf, errstring(err)); | |
d747e748 | 754 | user->q_flags |= QQUEUEUP; |
6f14531a RG |
755 | return; |
756 | } | |
757 | } | |
15637ed4 | 758 | } |