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