Commit | Line | Data |
---|---|---|
d185cb11 | 1 | /* |
1f7bda54 | 2 | * Copyright (c) 1983 Eric P. Allman |
bee79b64 KB |
3 | * Copyright (c) 1988 Regents of the University of California. |
4 | * All rights reserved. | |
5 | * | |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 KB |
7 | */ |
8 | ||
ce8f0b62 EA |
9 | # include <sys/types.h> |
10 | # include <sys/stat.h> | |
11 | # include <signal.h> | |
ce8f0b62 EA |
12 | # include "sendmail.h" |
13 | # include <sys/file.h> | |
14 | # include <pwd.h> | |
76b607b2 EA |
15 | # ifdef LOCKF |
16 | # include <fcntl.h> | |
17 | # endif | |
ce8f0b62 | 18 | |
4099e6e8 | 19 | # ifdef DBM |
33fc5854 | 20 | ERROR: DBM is no longer supported -- use NDBM instead. |
4099e6e8 EA |
21 | # endif |
22 | ||
ce8f0b62 EA |
23 | # ifdef NEWDB |
24 | # include <db.h> | |
25 | # endif | |
26 | ||
6a2bb17b | 27 | # ifdef NDBM |
4099e6e8 | 28 | # include <ndbm.h> |
6a2bb17b EA |
29 | # endif |
30 | ||
bee79b64 | 31 | #ifndef lint |
b9357db9 | 32 | #ifdef NEWDB |
a0f5c935 | 33 | static char sccsid[] = "@(#)alias.c 6.1 (Berkeley) %G% (with NEWDB)"; |
07c0651f | 34 | #else |
4099e6e8 | 35 | #ifdef NDBM |
a0f5c935 | 36 | static char sccsid[] = "@(#)alias.c 6.1 (Berkeley) %G% (with NDBM)"; |
b9357db9 | 37 | #else |
a0f5c935 | 38 | static char sccsid[] = "@(#)alias.c 6.1 (Berkeley) %G% (without NDBM)"; |
b9357db9 | 39 | #endif |
bee79b64 KB |
40 | #endif |
41 | #endif /* not lint */ | |
07c0651f | 42 | \f/* |
b3cbe40f EA |
43 | ** ALIAS -- Compute aliases. |
44 | ** | |
7338e3d4 EA |
45 | ** Scans the alias file for an alias for the given address. |
46 | ** If found, it arranges to deliver to the alias list instead. | |
47 | ** Uses libdbm database if -DDBM. | |
b3cbe40f EA |
48 | ** |
49 | ** Parameters: | |
bdfaa762 | 50 | ** a -- address to alias. |
d4f42161 EA |
51 | ** sendq -- a pointer to the head of the send queue |
52 | ** to put the aliases in. | |
b3cbe40f EA |
53 | ** |
54 | ** Returns: | |
55 | ** none | |
56 | ** | |
57 | ** Side Effects: | |
9e3c0a28 | 58 | ** Aliases found are expanded. |
b3cbe40f | 59 | ** |
b3cbe40f EA |
60 | ** Notes: |
61 | ** If NoAlias (the "-n" flag) is set, no aliasing is | |
62 | ** done. | |
63 | ** | |
64 | ** Deficiencies: | |
65 | ** It should complain about names that are aliased to | |
66 | ** nothing. | |
b3cbe40f EA |
67 | */ |
68 | ||
69 | ||
6c6e2d3a EA |
70 | /* |
71 | ** Sun YP servers read the dbm files directly, so we have to build them | |
72 | ** even if NEWDB | |
73 | */ | |
74 | ||
4099e6e8 | 75 | #ifdef NDBM |
6c6e2d3a EA |
76 | # ifndef NEWDB |
77 | # define IF_MAKEDBMFILES | |
78 | # else | |
79 | # ifdef YPCOMPAT | |
80 | # define IF_MAKEDBMFILES if (makedbmfiles) | |
81 | # endif | |
82 | # endif | |
83 | #endif | |
84 | ||
4099e6e8 | 85 | typedef union |
a530c75f | 86 | { |
4099e6e8 EA |
87 | #ifdef NDBM |
88 | datum dbm; | |
07c0651f | 89 | #endif |
4099e6e8 EA |
90 | #ifdef NEWDB |
91 | DBT dbt; | |
92 | #endif | |
93 | struct | |
94 | { | |
95 | char *data; | |
96 | int size; | |
97 | } xx; | |
98 | } DBdatum; | |
b9357db9 EA |
99 | |
100 | #ifdef NEWDB | |
101 | static DB *AliasDBptr; | |
102 | #endif | |
4099e6e8 EA |
103 | #ifdef NDBM |
104 | static DBM *AliasDBMptr; | |
105 | #endif | |
b3cbe40f | 106 | |
a4076aed | 107 | alias(a, sendq, e) |
bdfaa762 | 108 | register ADDRESS *a; |
d4f42161 | 109 | ADDRESS **sendq; |
a4076aed | 110 | register ENVELOPE *e; |
b3cbe40f | 111 | { |
29871fef | 112 | register char *p; |
abae7b2d | 113 | extern ADDRESS *sendto(); |
35cc3fad | 114 | extern char *aliaslookup(); |
b3cbe40f | 115 | |
9678c96d | 116 | if (tTd(27, 1)) |
cdb17311 | 117 | printf("alias(%s)\n", a->q_paddr); |
b3cbe40f | 118 | |
cdb17311 EA |
119 | /* don't realias already aliased names */ |
120 | if (bitset(QDONTSEND, a->q_flags)) | |
121 | return; | |
122 | ||
a4076aed | 123 | e->e_to = a->q_paddr; |
cdb17311 | 124 | |
74c5fe7c EA |
125 | /* |
126 | ** Look up this name | |
127 | */ | |
128 | ||
2e3062fe EA |
129 | if (NoAlias) |
130 | p = NULL; | |
131 | else | |
132 | p = aliaslookup(a->q_user); | |
cdb17311 EA |
133 | if (p == NULL) |
134 | return; | |
b3cbe40f | 135 | |
d916f0ca | 136 | /* |
cdb17311 EA |
137 | ** Match on Alias. |
138 | ** Deliver to the target list. | |
d916f0ca EA |
139 | */ |
140 | ||
9678c96d | 141 | if (tTd(27, 1)) |
cdb17311 EA |
142 | printf("%s (%s, %s) aliased to %s\n", |
143 | a->q_paddr, a->q_host, a->q_user, p); | |
91f69adf | 144 | message(Arpa_Info, "aliased to %s", p); |
cdb17311 | 145 | AliasLevel++; |
abae7b2d | 146 | a->q_child = sendto(p, 1, a, 0); |
cdb17311 EA |
147 | AliasLevel--; |
148 | } | |
149 | \f/* | |
35cc3fad EA |
150 | ** ALIASLOOKUP -- look up a name in the alias file. |
151 | ** | |
152 | ** Parameters: | |
153 | ** name -- the name to look up. | |
154 | ** | |
155 | ** Returns: | |
156 | ** the value of name. | |
157 | ** NULL if unknown. | |
158 | ** | |
159 | ** Side Effects: | |
160 | ** none. | |
161 | ** | |
162 | ** Warnings: | |
163 | ** The return value will be trashed across calls. | |
164 | */ | |
165 | ||
166 | char * | |
167 | aliaslookup(name) | |
168 | char *name; | |
169 | { | |
4099e6e8 EA |
170 | # if defined(NEWDB) || defined(NDBM) |
171 | DBdatum rhs, lhs; | |
b9357db9 | 172 | int s; |
35cc3fad EA |
173 | |
174 | /* create a key for fetch */ | |
4099e6e8 EA |
175 | lhs.xx.data = name; |
176 | lhs.xx.size = strlen(name) + 1; | |
b9357db9 | 177 | # ifdef NEWDB |
07c0651f EA |
178 | if (AliasDBptr != NULL) |
179 | { | |
4099e6e8 | 180 | s = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0); |
07c0651f | 181 | if (s == 0) |
4099e6e8 | 182 | return (rhs.dbt.data); |
07c0651f | 183 | } |
4099e6e8 | 184 | # ifdef NDBM |
c796f255 | 185 | else if (AliasDBMptr != NULL) |
07c0651f | 186 | { |
4099e6e8 EA |
187 | rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); |
188 | return (rhs.dbm.dptr); | |
07c0651f | 189 | } |
4099e6e8 EA |
190 | # endif /* NDBM */ |
191 | # else /* not NEWDB */ | |
192 | rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); | |
193 | return (rhs.dbm.dptr); | |
194 | # endif /* NEWDB */ | |
195 | # else /* neither NEWDB nor NDBM */ | |
35cc3fad EA |
196 | register STAB *s; |
197 | ||
198 | s = stab(name, ST_ALIAS, ST_FIND); | |
07c0651f EA |
199 | if (s != NULL) |
200 | return (s->s_alias); | |
201 | # endif | |
202 | return (NULL); | |
35cc3fad EA |
203 | } |
204 | \f/* | |
cdb17311 EA |
205 | ** INITALIASES -- initialize for aliasing |
206 | ** | |
4099e6e8 | 207 | ** Very different depending on whether we are running NDBM or not. |
cdb17311 EA |
208 | ** |
209 | ** Parameters: | |
210 | ** aliasfile -- location of aliases. | |
4099e6e8 | 211 | ** init -- if set and if NDBM, initialize the NDBM files. |
cdb17311 EA |
212 | ** |
213 | ** Returns: | |
214 | ** none. | |
215 | ** | |
216 | ** Side Effects: | |
217 | ** initializes aliases: | |
4099e6e8 EA |
218 | ** if NDBM: opens the database. |
219 | ** if ~NDBM: reads the aliases into the symbol table. | |
cdb17311 EA |
220 | */ |
221 | ||
915f268d | 222 | # define DBMMODE 0644 |
f4dbf345 | 223 | |
a4076aed | 224 | initaliases(aliasfile, init, e) |
cdb17311 | 225 | char *aliasfile; |
f4dbf345 | 226 | bool init; |
a4076aed | 227 | register ENVELOPE *e; |
cdb17311 | 228 | { |
4099e6e8 | 229 | #if defined(NDBM) || defined(NEWDB) |
7bdc419c | 230 | int atcnt; |
d6b27179 | 231 | time_t modtime; |
9327783c EA |
232 | bool automatic = FALSE; |
233 | char buf[MAXNAME]; | |
b9357db9 | 234 | #endif |
7338e3d4 | 235 | struct stat stb; |
a78155b0 | 236 | static bool initialized = FALSE; |
0df908a9 | 237 | static int readaliases(); |
a78155b0 EA |
238 | |
239 | if (initialized) | |
240 | return; | |
241 | initialized = TRUE; | |
d6b27179 | 242 | |
bb09c502 | 243 | if (aliasfile == NULL || stat(aliasfile, &stb) < 0) |
7bdc419c | 244 | { |
9327783c EA |
245 | if (aliasfile != NULL && init) |
246 | syserr("Cannot open %s", aliasfile); | |
7bdc419c | 247 | NoAlias = TRUE; |
70faa7c8 | 248 | errno = 0; |
7bdc419c EA |
249 | return; |
250 | } | |
251 | ||
4099e6e8 | 252 | # if defined(NDBM) || defined(NEWDB) |
7bdc419c EA |
253 | /* |
254 | ** Check to see that the alias file is complete. | |
255 | ** If not, we will assume that someone died, and it is up | |
256 | ** to us to rebuild it. | |
257 | */ | |
258 | ||
a1a07282 | 259 | if (!init) |
b9357db9 EA |
260 | { |
261 | # ifdef NEWDB | |
262 | (void) strcpy(buf, aliasfile); | |
263 | (void) strcat(buf, ".db"); | |
15af6d40 | 264 | AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); |
aace356e EA |
265 | if (AliasDBptr == NULL) |
266 | { | |
4099e6e8 EA |
267 | # ifdef NDBM |
268 | AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); | |
c796f255 EA |
269 | if (AliasDBMptr == NULL) |
270 | { | |
271 | syserr("initaliases: cannot open %s", buf); | |
272 | NoAlias = TRUE; | |
273 | return; | |
274 | } | |
07c0651f | 275 | # else |
aace356e EA |
276 | syserr("initaliases: cannot open %s", buf); |
277 | NoAlias = TRUE; | |
278 | return; | |
07c0651f | 279 | # endif |
aace356e | 280 | } |
b9357db9 | 281 | # else |
4099e6e8 | 282 | AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); |
c796f255 EA |
283 | if (AliasDBMptr == NULL) |
284 | { | |
285 | syserr("initaliases: cannot open %s", buf); | |
286 | NoAlias = TRUE; | |
287 | return; | |
288 | } | |
b9357db9 EA |
289 | # endif |
290 | } | |
560a80d9 EA |
291 | atcnt = SafeAlias * 2; |
292 | if (atcnt > 0) | |
293 | { | |
294 | while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) | |
a1a07282 EA |
295 | { |
296 | /* | |
297 | ** Reinitialize alias file in case the new | |
298 | ** one is mv'ed in instead of cp'ed in. | |
299 | ** | |
300 | ** Only works with new DBM -- old one will | |
301 | ** just consume file descriptors forever. | |
302 | ** If you have a dbmclose() it can be | |
303 | ** added before the sleep(30). | |
304 | */ | |
305 | ||
b9357db9 | 306 | # ifdef NEWDB |
07c0651f EA |
307 | if (AliasDBptr != NULL) |
308 | AliasDBptr->close(AliasDBptr); | |
b9357db9 | 309 | # endif |
4099e6e8 EA |
310 | # ifdef NDBM |
311 | if (AliasDBMptr != NULL) | |
312 | dbm_close(AliasDBMptr); | |
313 | # endif | |
b9357db9 | 314 | |
560a80d9 | 315 | sleep(30); |
b9357db9 EA |
316 | # ifdef NEWDB |
317 | (void) strcpy(buf, aliasfile); | |
318 | (void) strcat(buf, ".db"); | |
15af6d40 KB |
319 | AliasDBptr = |
320 | dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); | |
aace356e EA |
321 | if (AliasDBptr == NULL) |
322 | { | |
07c0651f | 323 | # ifdef NDBM |
4099e6e8 | 324 | AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); |
07c0651f | 325 | # else |
aace356e EA |
326 | syserr("initaliases: cannot open %s", buf); |
327 | NoAlias = TRUE; | |
328 | return; | |
07c0651f | 329 | # endif |
aace356e | 330 | } |
b9357db9 | 331 | # else |
a1a07282 | 332 | # ifdef NDBM |
4099e6e8 | 333 | AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); |
c796f255 EA |
334 | if (AliasDBMptr == NULL) |
335 | { | |
336 | syserr("initaliases: cannot open %s", buf); | |
337 | NoAlias = TRUE; | |
338 | return; | |
339 | } | |
b9357db9 EA |
340 | # endif |
341 | # endif | |
a1a07282 | 342 | } |
560a80d9 EA |
343 | } |
344 | else | |
345 | atcnt = 1; | |
7bdc419c | 346 | |
d6b27179 | 347 | /* |
4099e6e8 | 348 | ** See if the NDBM version of the file is out of date with |
d6b27179 | 349 | ** the text version. If so, go into 'init' mode automatically. |
915f268d KB |
350 | ** This only happens if our effective userid owns the DBM. |
351 | ** Note the unpalatable hack to see if the stat succeeded. | |
d6b27179 EA |
352 | */ |
353 | ||
d6b27179 EA |
354 | modtime = stb.st_mtime; |
355 | (void) strcpy(buf, aliasfile); | |
b9357db9 EA |
356 | # ifdef NEWDB |
357 | (void) strcat(buf, ".db"); | |
358 | # else | |
d6b27179 | 359 | (void) strcat(buf, ".pag"); |
b9357db9 | 360 | # endif |
d6b27179 | 361 | stb.st_ino = 0; |
f12e5a74 | 362 | if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) |
f4dbf345 | 363 | { |
70faa7c8 | 364 | errno = 0; |
915f268d | 365 | if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) |
d6b27179 EA |
366 | { |
367 | init = TRUE; | |
9327783c | 368 | automatic = TRUE; |
91f69adf | 369 | message(Arpa_Info, "rebuilding alias database"); |
2e3062fe EA |
370 | #ifdef LOG |
371 | if (LogLevel >= 7) | |
372 | syslog(LOG_INFO, "rebuilding alias database"); | |
f3d8f6d6 | 373 | #endif /* LOG */ |
d6b27179 EA |
374 | } |
375 | else | |
376 | { | |
f12e5a74 | 377 | #ifdef LOG |
2e3062fe EA |
378 | if (LogLevel >= 7) |
379 | syslog(LOG_INFO, "alias database out of date"); | |
f3d8f6d6 | 380 | #endif /* LOG */ |
d6b27179 EA |
381 | message(Arpa_Info, "Warning: alias database out of date"); |
382 | } | |
383 | } | |
f4dbf345 | 384 | |
d6b27179 EA |
385 | |
386 | /* | |
4099e6e8 EA |
387 | ** If necessary, load the NDBM file. |
388 | ** If running without NDBM, load the symbol table. | |
d6b27179 EA |
389 | */ |
390 | ||
f4dbf345 | 391 | if (init) |
7bdc419c | 392 | { |
9327783c EA |
393 | #ifdef LOG |
394 | if (LogLevel >= 6) | |
395 | { | |
396 | extern char *username(); | |
397 | ||
398 | syslog(LOG_NOTICE, "alias database %srebuilt by %s", | |
399 | automatic ? "auto" : "", username()); | |
400 | } | |
f3d8f6d6 | 401 | #endif /* LOG */ |
a4076aed | 402 | readaliases(aliasfile, TRUE, e); |
7bdc419c | 403 | } |
4099e6e8 | 404 | # else /* NDBM */ |
a4076aed | 405 | readaliases(aliasfile, init, e); |
4099e6e8 | 406 | # endif /* NDBM */ |
f4dbf345 EA |
407 | } |
408 | \f/* | |
409 | ** READALIASES -- read and process the alias file. | |
410 | ** | |
411 | ** This routine implements the part of initaliases that occurs | |
412 | ** when we are not going to use the DBM stuff. | |
413 | ** | |
414 | ** Parameters: | |
415 | ** aliasfile -- the pathname of the alias file master. | |
4099e6e8 | 416 | ** init -- if set, initialize the NDBM stuff. |
f4dbf345 EA |
417 | ** |
418 | ** Returns: | |
419 | ** none. | |
420 | ** | |
421 | ** Side Effects: | |
422 | ** Reads aliasfile into the symbol table. | |
423 | ** Optionally, builds the .dir & .pag files. | |
424 | */ | |
425 | ||
426 | static | |
a4076aed | 427 | readaliases(aliasfile, init, e) |
f4dbf345 EA |
428 | char *aliasfile; |
429 | bool init; | |
a4076aed | 430 | register ENVELOPE *e; |
f4dbf345 | 431 | { |
cdb17311 | 432 | register char *p; |
41173b8f | 433 | char *lhs; |
cdb17311 EA |
434 | char *rhs; |
435 | bool skipping; | |
7338e3d4 | 436 | int naliases, bytes, longest; |
9e25d1f0 | 437 | FILE *af; |
6c6e2d3a | 438 | bool makedbmfiles; |
21c8ba49 | 439 | void (*oldsigint)(); |
7338e3d4 | 440 | ADDRESS al, bl; |
9e25d1f0 | 441 | register STAB *s; |
b9357db9 EA |
442 | # ifdef NEWDB |
443 | DB *dbp; | |
76b607b2 | 444 | # endif |
4099e6e8 EA |
445 | # ifdef NDBM |
446 | DBM *dbmp; | |
447 | # endif | |
76b607b2 EA |
448 | # ifdef LOCKF |
449 | struct flock fld; | |
b9357db9 | 450 | # endif |
7338e3d4 | 451 | char line[BUFSIZ]; |
cdb17311 | 452 | |
76b607b2 | 453 | if ((af = fopen(aliasfile, "r+")) == NULL) |
d916f0ca | 454 | { |
c796f255 EA |
455 | if (init) |
456 | syserr("Can't open %s", aliasfile); | |
457 | else if (tTd(27, 1)) | |
9e25d1f0 | 458 | printf("Can't open %s\n", aliasfile); |
cdb17311 EA |
459 | errno = 0; |
460 | NoAlias++; | |
461 | return; | |
462 | } | |
74c5fe7c | 463 | |
4099e6e8 | 464 | # if defined(NDBM) || defined(NEWDB) |
e6e345fa | 465 | /* see if someone else is rebuilding the alias file already */ |
4287d84d | 466 | # ifdef LOCKF |
76b607b2 EA |
467 | fld.l_type = F_WRLCK; |
468 | fld.l_whence = fld.l_start = fld.l_len = 0; | |
469 | if (fcntl(fileno(af), F_SETLK, &fld) < 0) | |
4287d84d | 470 | # else |
e6e345fa | 471 | if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) |
4287d84d | 472 | # endif |
e6e345fa EA |
473 | { |
474 | /* yes, they are -- wait until done and then return */ | |
475 | message(Arpa_Info, "Alias file is already being rebuilt"); | |
476 | if (OpMode != MD_INITALIAS) | |
477 | { | |
478 | /* wait for other rebuild to complete */ | |
4287d84d | 479 | # ifdef LOCKF |
76b607b2 | 480 | (void) fcntl(fileno(af), F_SETLKW, &fld); |
4287d84d | 481 | # else |
e6e345fa | 482 | (void) flock(fileno(af), LOCK_EX); |
4287d84d | 483 | # endif |
e6e345fa | 484 | } |
03388044 | 485 | (void) fclose(af); |
e6e345fa EA |
486 | errno = 0; |
487 | return; | |
488 | } | |
4099e6e8 | 489 | # endif /* NDBM */ |
e6e345fa EA |
490 | |
491 | /* | |
492 | ** If initializing, create the new DBM files. | |
493 | */ | |
494 | ||
495 | if (init) | |
496 | { | |
497 | oldsigint = signal(SIGINT, SIG_IGN); | |
07c0651f EA |
498 | # ifdef NEWDB |
499 | (void) strcpy(line, aliasfile); | |
500 | (void) strcat(line, ".db"); | |
501 | dbp = dbopen(line, | |
502 | O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); | |
503 | if (dbp == NULL) | |
504 | { | |
505 | syserr("readaliases: cannot create %s", line); | |
506 | (void) signal(SIGINT, oldsigint); | |
507 | return; | |
508 | } | |
6c6e2d3a EA |
509 | # endif |
510 | # ifdef IF_MAKEDBMFILES | |
511 | # ifdef NEWDB | |
512 | makedbmfiles = access("/var/yp/Makefile", R_OK) == 0; | |
513 | # endif | |
514 | IF_MAKEDBMFILES | |
e6e345fa | 515 | { |
4099e6e8 EA |
516 | dbmp = dbm_open(aliasfile, |
517 | O_RDWR|O_CREAT|O_TRUNC, DBMMODE); | |
518 | if (dbmp == NULL) | |
6c6e2d3a | 519 | { |
4099e6e8 EA |
520 | syserr("readaliases: cannot create %s.{dir,pag}", |
521 | aliasfile); | |
6c6e2d3a EA |
522 | (void) signal(SIGINT, oldsigint); |
523 | return; | |
524 | } | |
e6e345fa | 525 | } |
b9357db9 | 526 | # endif |
e6e345fa EA |
527 | } |
528 | ||
74c5fe7c EA |
529 | /* |
530 | ** Read and interpret lines | |
531 | */ | |
532 | ||
7338e3d4 EA |
533 | FileName = aliasfile; |
534 | LineNumber = 0; | |
d6b27179 | 535 | naliases = bytes = longest = 0; |
cdb17311 EA |
536 | skipping = FALSE; |
537 | while (fgets(line, sizeof (line), af) != NULL) | |
538 | { | |
d6b27179 EA |
539 | int lhssize, rhssize; |
540 | ||
7338e3d4 | 541 | LineNumber++; |
f3d8f6d6 | 542 | p = strchr(line, '\n'); |
3312f93c EA |
543 | if (p != NULL) |
544 | *p = '\0'; | |
cdb17311 EA |
545 | switch (line[0]) |
546 | { | |
547 | case '#': | |
cdb17311 EA |
548 | case '\0': |
549 | skipping = FALSE; | |
550 | continue; | |
bdfaa762 | 551 | |
cdb17311 EA |
552 | case ' ': |
553 | case '\t': | |
554 | if (!skipping) | |
7338e3d4 | 555 | syserr("Non-continuation line starts with space"); |
cdb17311 | 556 | skipping = TRUE; |
bdfaa762 | 557 | continue; |
cdb17311 EA |
558 | } |
559 | skipping = FALSE; | |
bdfaa762 | 560 | |
74c5fe7c EA |
561 | /* |
562 | ** Process the LHS | |
41173b8f | 563 | ** |
74c5fe7c | 564 | ** Find the final colon, and parse the address. |
41173b8f EA |
565 | ** It should resolve to a local name. |
566 | ** | |
567 | ** Alternatively, it can be "@hostname" for host | |
568 | ** aliases -- all we do here is map case. Hostname | |
569 | ** need not be a single token. | |
74c5fe7c EA |
570 | */ |
571 | ||
cdb17311 | 572 | for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) |
bdfaa762 | 573 | continue; |
41173b8f | 574 | if (*p != ':') |
cdb17311 | 575 | { |
1bcdf0a2 | 576 | syserr("%s, line %d: syntax error", aliasfile, lineno); |
bdfaa762 | 577 | continue; |
cdb17311 | 578 | } |
41173b8f EA |
579 | *p++ = '\0'; |
580 | if (line[0] == '@') | |
cdb17311 | 581 | { |
41173b8f EA |
582 | /* a host alias */ |
583 | makelower(line); | |
584 | lhs = line; | |
585 | } | |
586 | else | |
587 | { | |
588 | /* a user alias */ | |
589 | if (parseaddr(line, &al, 1, ':') == NULL) | |
590 | { | |
591 | syserr("illegal alias name"); | |
592 | continue; | |
593 | } | |
594 | loweraddr(&al); | |
595 | if (al.q_mailer != LocalMailer) | |
596 | { | |
597 | syserr("cannot alias non-local names"); | |
598 | continue; | |
599 | } | |
600 | lhs = al.q_user; | |
cdb17311 | 601 | } |
74c5fe7c EA |
602 | |
603 | /* | |
604 | ** Process the RHS. | |
605 | ** 'al' is the internal form of the LHS address. | |
606 | ** 'p' points to the text of the RHS. | |
1bcdf0a2 EA |
607 | ** 'p' may begin with a colon (i.e., the |
608 | ** separator was "::") which will use the | |
609 | ** first address as the person to send | |
610 | ** errors to -- i.e., designates the | |
611 | ** list maintainer. | |
74c5fe7c EA |
612 | */ |
613 | ||
1bcdf0a2 EA |
614 | if (*p == ':') |
615 | { | |
616 | ADDRESS *maint; | |
617 | ||
618 | while (isspace(*++p)) | |
619 | continue; | |
620 | rhs = p; | |
621 | while (*p != '\0' && *p != ',') | |
622 | p++; | |
623 | if (*p != ',') | |
624 | goto syntaxerr; | |
625 | *p++ = '\0'; | |
626 | maint = parse(p, (ADDRESS *) NULL, 1); | |
627 | if (maint == NULL) | |
628 | syserr("Illegal list maintainer for list %s", al.q_user); | |
629 | else if (CurEnv->e_returnto == &CurEnv->e_from) | |
630 | { | |
631 | CurEnv->e_returnto = maint; | |
632 | MailBack++; | |
633 | } | |
634 | } | |
635 | ||
cdb17311 | 636 | rhs = p; |
cdb17311 EA |
637 | for (;;) |
638 | { | |
639 | register char c; | |
d916f0ca | 640 | |
1e963db5 | 641 | if (init && CheckAliases) |
cdb17311 | 642 | { |
f4dbf345 | 643 | /* do parsing & compression of addresses */ |
3312f93c | 644 | while (*p != '\0') |
cdb17311 | 645 | { |
3312f93c EA |
646 | extern char *DelimChar; |
647 | ||
648 | while (isspace(*p) || *p == ',') | |
c49d661c | 649 | p++; |
3312f93c EA |
650 | if (*p == '\0') |
651 | break; | |
a4076aed | 652 | if (parseaddr(p, &bl, -1, ',', e) == NULL) |
3312f93c EA |
653 | usrerr("%s... bad address", p); |
654 | p = DelimChar; | |
cdb17311 | 655 | } |
cdb17311 | 656 | } |
f4dbf345 | 657 | else |
634c8ff3 | 658 | { |
34fe0a9b EA |
659 | p = &p[strlen(p)]; |
660 | if (p[-1] == '\n') | |
661 | *--p = '\0'; | |
634c8ff3 | 662 | } |
d916f0ca | 663 | |
cdb17311 | 664 | /* see if there should be a continuation line */ |
9e25d1f0 EA |
665 | c = fgetc(af); |
666 | if (!feof(af)) | |
74c5fe7c | 667 | (void) ungetc(c, af); |
9e25d1f0 | 668 | if (c != ' ' && c != '\t') |
cdb17311 EA |
669 | break; |
670 | ||
671 | /* read continuation line */ | |
cdb17311 EA |
672 | if (fgets(p, sizeof line - (p - line), af) == NULL) |
673 | break; | |
7338e3d4 | 674 | LineNumber++; |
07b49560 EA |
675 | |
676 | /* check for line overflow */ | |
677 | if (strchr(p, '\n') == NULL) | |
678 | { | |
679 | usrerr("alias too long"); | |
680 | break; | |
681 | } | |
cdb17311 | 682 | } |
74c5fe7c EA |
683 | |
684 | /* | |
685 | ** Insert alias into symbol table or DBM file | |
686 | */ | |
687 | ||
41173b8f | 688 | lhssize = strlen(lhs) + 1; |
d6b27179 EA |
689 | rhssize = strlen(rhs) + 1; |
690 | ||
4099e6e8 | 691 | # if defined(NDBM) || defined(NEWDB) |
f4dbf345 EA |
692 | if (init) |
693 | { | |
4099e6e8 | 694 | DBdatum key, content; |
f4dbf345 | 695 | |
4099e6e8 EA |
696 | key.xx.size = lhssize; |
697 | key.xx.data = al.q_user; | |
698 | content.xx.size = rhssize; | |
699 | content.xx.data = rhs; | |
07c0651f | 700 | # ifdef NEWDB |
4099e6e8 | 701 | if (dbp->put(dbp, &key.dbt, &content.dbt, 0) != 0) |
aace356e | 702 | syserr("readaliases: db put (%s)", al.q_user); |
6c6e2d3a EA |
703 | # endif |
704 | # ifdef IF_MAKEDBMFILES | |
705 | IF_MAKEDBMFILES | |
4099e6e8 EA |
706 | if (dbm_store(dbmp, key.dbm, content.dbm, DBM_REPLACE) != 0) |
707 | syserr("readaliases: dbm store (%s)", | |
708 | al.q_user); | |
b9357db9 | 709 | # endif |
f4dbf345 EA |
710 | } |
711 | else | |
4099e6e8 | 712 | # endif /* NDBM */ |
f4dbf345 EA |
713 | { |
714 | s = stab(al.q_user, ST_ALIAS, ST_ENTER); | |
715 | s->s_alias = newstr(rhs); | |
716 | } | |
d6b27179 EA |
717 | |
718 | /* statistics */ | |
719 | naliases++; | |
720 | bytes += lhssize + rhssize; | |
721 | if (rhssize > longest) | |
722 | longest = rhssize; | |
d916f0ca | 723 | } |
e6e345fa | 724 | |
4099e6e8 | 725 | # if defined(NDBM) || defined(NEWDB) |
e6e345fa EA |
726 | if (init) |
727 | { | |
728 | /* add the distinquished alias "@" */ | |
4099e6e8 | 729 | DBdatum key; |
b9357db9 | 730 | |
4099e6e8 EA |
731 | key.xx.size = 2; |
732 | key.xx.data = "@"; | |
b9357db9 | 733 | # ifdef NEWDB |
aace356e | 734 | if (dbp->sync(dbp) != 0 || |
4099e6e8 | 735 | dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 || |
aace356e EA |
736 | dbp->close(dbp) != 0) |
737 | syserr("readaliases: db close failure"); | |
6c6e2d3a | 738 | # endif |
a47061b6 | 739 | # ifdef IF_MAKEDBMFILES |
09098a56 | 740 | IF_MAKEDBMFILES |
4099e6e8 EA |
741 | { |
742 | if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 || | |
743 | dbm_error(dbmp)) | |
744 | syserr("readaliases: dbm close failure"); | |
745 | dbm_close(dbmp); | |
746 | } | |
b9357db9 | 747 | # endif |
e6e345fa EA |
748 | |
749 | /* restore the old signal */ | |
750 | (void) signal(SIGINT, oldsigint); | |
751 | } | |
4099e6e8 | 752 | # endif /* NDBM */ |
e6e345fa EA |
753 | |
754 | /* closing the alias file drops the lock */ | |
cdb17311 | 755 | (void) fclose(af); |
a4076aed | 756 | e->e_to = NULL; |
7338e3d4 | 757 | FileName = NULL; |
91f69adf | 758 | message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", |
d6b27179 | 759 | naliases, longest, bytes); |
2e3062fe EA |
760 | # ifdef LOG |
761 | if (LogLevel >= 8) | |
762 | syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", | |
763 | naliases, longest, bytes); | |
f3d8f6d6 | 764 | # endif /* LOG */ |
b3cbe40f EA |
765 | } |
766 | \f/* | |
767 | ** FORWARD -- Try to forward mail | |
768 | ** | |
769 | ** This is similar but not identical to aliasing. | |
770 | ** | |
b3cbe40f | 771 | ** Parameters: |
74c5fe7c EA |
772 | ** user -- the name of the user who's mail we would like |
773 | ** to forward to. It must have been verified -- | |
774 | ** i.e., the q_home field must have been filled | |
775 | ** in. | |
d4f42161 EA |
776 | ** sendq -- a pointer to the head of the send queue to |
777 | ** put this user's aliases in. | |
b3cbe40f EA |
778 | ** |
779 | ** Returns: | |
cdb17311 | 780 | ** none. |
b3cbe40f EA |
781 | ** |
782 | ** Side Effects: | |
9e3c0a28 | 783 | ** New names are added to send queues. |
b3cbe40f EA |
784 | */ |
785 | ||
a4076aed | 786 | forward(user, sendq, e) |
a530c75f | 787 | ADDRESS *user; |
d4f42161 | 788 | ADDRESS **sendq; |
a4076aed | 789 | register ENVELOPE *e; |
b3cbe40f | 790 | { |
e0136832 EA |
791 | char *pp; |
792 | char *ep; | |
f6a0cc15 | 793 | extern bool safefile(); |
56678245 | 794 | |
9678c96d | 795 | if (tTd(27, 1)) |
cdb17311 | 796 | printf("forward(%s)\n", user->q_paddr); |
cdb17311 | 797 | |
179c1218 | 798 | if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) |
cdb17311 | 799 | return; |
74c5fe7c EA |
800 | if (user->q_home == NULL) |
801 | syserr("forward: no home"); | |
56678245 | 802 | |
56678245 | 803 | /* good address -- look for .forward file in home */ |
a4076aed | 804 | define('z', user->q_home, e); |
e0136832 EA |
805 | define('u', user->q_user, e); |
806 | define('h', user->q_host, e); | |
807 | if (ForwardPath == NULL) | |
808 | ForwardPath = newstr("\001z/.forward"); | |
809 | ||
810 | for (pp = ForwardPath; pp != NULL; pp = ep) | |
811 | { | |
f43b04ce | 812 | char buf[MAXPATHLEN+1]; |
e0136832 EA |
813 | |
814 | ep = strchr(pp, ':'); | |
815 | if (ep != NULL) | |
816 | *ep = '\0'; | |
817 | expand(pp, buf, &buf[sizeof buf - 1], e); | |
818 | if (ep != NULL) | |
819 | *ep++ = ':'; | |
820 | if (tTd(27, 3)) | |
821 | printf("forward: trying %s\n", buf); | |
822 | if (include(buf, TRUE, user, sendq, e) == 0) | |
823 | break; | |
824 | } | |
b3cbe40f | 825 | } |
41173b8f EA |
826 | \f/* |
827 | ** MAPHOST -- given a host description, produce a mapping. | |
828 | ** | |
829 | ** This is done by looking up the name in the alias file, | |
830 | ** preceeded by an "@". This can be used for UUCP mapping. | |
831 | ** For example, a call with {blia, ., UUCP} as arguments | |
832 | ** might return {ucsfcgl, !, blia, ., UUCP} as the result. | |
833 | ** | |
834 | ** We first break the input into three parts -- before the | |
835 | ** lookup, the lookup itself, and after the lookup. We | |
836 | ** then do the lookup, concatenate them together, and rescan | |
837 | ** the result. | |
838 | ** | |
839 | ** Parameters: | |
840 | ** pvp -- the parameter vector to map. | |
841 | ** | |
842 | ** Returns: | |
843 | ** The result of the mapping. If nothing found, it | |
844 | ** should just concatenate the three parts together and | |
845 | ** return that. | |
846 | ** | |
847 | ** Side Effects: | |
848 | ** none. | |
849 | */ | |
850 | ||
851 | char ** | |
852 | maphost(pvp) | |
853 | char **pvp; | |
854 | { | |
855 | register char **avp; | |
856 | register char **bvp; | |
857 | char *p; | |
858 | char buf1[MAXNAME]; | |
859 | char buf2[MAXNAME]; | |
860 | char buf3[MAXNAME]; | |
861 | extern char **prescan(); | |
862 | ||
863 | /* | |
864 | ** Extract the three parts of the input as strings. | |
865 | */ | |
866 | ||
867 | /* find the part before the lookup */ | |
868 | for (bvp = pvp; *bvp != NULL && **bvp != MATCHLOOKUP; bvp++) | |
869 | continue; | |
870 | if (*bvp == NULL) | |
871 | return (pvp); | |
872 | p = *bvp; | |
873 | *bvp = NULL; | |
874 | cataddr(pvp, buf1, sizeof buf1); | |
875 | *bvp++ = p; | |
876 | ||
877 | /* find the rest of the lookup */ | |
878 | for (avp = bvp; *pvp != NULL && **bvp != MATCHELOOKUP; bvp++) | |
879 | continue; | |
880 | if (*bvp == NULL) | |
881 | return (pvp); | |
882 | p = *bvp; | |
883 | *bvp = NULL; | |
884 | cataddr(avp, buf2, sizeof buf2); | |
885 | *bvp++ = p; | |
886 | ||
887 | /* save the part after the lookup */ | |
888 | cataddr(bvp, buf3, sizeof buf3); | |
889 | ||
890 | /* | |
891 | ** Now look up the middle part. | |
892 | */ | |
893 | ||
894 | p = aliaslookup(buf2); | |
895 | if (p != NULL) | |
896 | strcpy(buf2, p); | |
897 | ||
898 | /* | |
899 | ** Put the three parts back together and break into tokens. | |
900 | */ | |
901 | ||
902 | strcat(buf1, buf2); | |
903 | strcat(buf1, buf3); | |
904 | avp = prescan(buf1, '\0'); | |
905 | ||
906 | /* return this mapping */ | |
907 | return (avp); | |
908 | } |