Commit | Line | Data |
---|---|---|
b3cbe40f | 1 | # include <pwd.h> |
9c3f729b EA |
2 | # include <sys/types.h> |
3 | # include <sys/stat.h> | |
96faada8 | 4 | # include "sendmail.h" |
b3cbe40f | 5 | |
9e25d1f0 | 6 | # ifdef DBM |
1bcdf0a2 | 7 | SCCSID(@(#)alias.c 3.33.1.1 %G% (with DBM)); |
9e25d1f0 | 8 | # else DBM |
1bcdf0a2 | 9 | SCCSID(@(#)alias.c 3.33.1.1 %G% (without DBM)); |
9e25d1f0 | 10 | # endif DBM |
916b3375 | 11 | |
b3cbe40f EA |
12 | /* |
13 | ** ALIAS -- Compute aliases. | |
14 | ** | |
cdb17311 | 15 | ** Scans the file /usr/lib/aliases for a set of aliases. |
9e3c0a28 EA |
16 | ** If found, it arranges to deliver to them. Uses libdbm |
17 | ** database if -DDBM. | |
b3cbe40f EA |
18 | ** |
19 | ** Parameters: | |
bdfaa762 | 20 | ** a -- address to alias. |
d4f42161 EA |
21 | ** sendq -- a pointer to the head of the send queue |
22 | ** to put the aliases in. | |
b3cbe40f EA |
23 | ** |
24 | ** Returns: | |
25 | ** none | |
26 | ** | |
27 | ** Side Effects: | |
9e3c0a28 | 28 | ** Aliases found are expanded. |
b3cbe40f | 29 | ** |
b3cbe40f | 30 | ** Files: |
cdb17311 | 31 | ** /usr/lib/aliases -- the mail aliases. The format is |
f895a45d EA |
32 | ** a series of lines of the form: |
33 | ** alias:name1,name2,name3,... | |
34 | ** where 'alias' expands to all of | |
35 | ** 'name[i]'. Continuations begin with | |
36 | ** space or tab. | |
cdb17311 | 37 | ** /usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version |
c9b9c7a2 MH |
38 | ** of alias file. Keys are aliases, datums |
39 | ** (data?) are name1,name2, ... | |
b3cbe40f EA |
40 | ** |
41 | ** Notes: | |
42 | ** If NoAlias (the "-n" flag) is set, no aliasing is | |
43 | ** done. | |
44 | ** | |
45 | ** Deficiencies: | |
46 | ** It should complain about names that are aliased to | |
47 | ** nothing. | |
48 | ** It is unsophisticated about line overflows. | |
b3cbe40f EA |
49 | */ |
50 | ||
51 | ||
c9b9c7a2 | 52 | #ifdef DBM |
a530c75f EA |
53 | typedef struct |
54 | { | |
55 | char *dptr; | |
f4dbf345 EA |
56 | int dsize; |
57 | } DATUM; | |
f4dbf345 | 58 | extern DATUM fetch(); |
c9b9c7a2 | 59 | #endif DBM |
b3cbe40f | 60 | |
d4f42161 | 61 | alias(a, sendq) |
bdfaa762 | 62 | register ADDRESS *a; |
d4f42161 | 63 | ADDRESS **sendq; |
b3cbe40f | 64 | { |
29871fef | 65 | register char *p; |
abae7b2d | 66 | extern ADDRESS *sendto(); |
35cc3fad | 67 | extern char *aliaslookup(); |
b3cbe40f EA |
68 | |
69 | if (NoAlias) | |
70 | return; | |
71 | # ifdef DEBUG | |
72 | if (Debug) | |
cdb17311 | 73 | printf("alias(%s)\n", a->q_paddr); |
b3cbe40f EA |
74 | # endif |
75 | ||
cdb17311 EA |
76 | /* don't realias already aliased names */ |
77 | if (bitset(QDONTSEND, a->q_flags)) | |
78 | return; | |
79 | ||
2654b031 | 80 | CurEnv->e_to = a->q_paddr; |
cdb17311 | 81 | |
74c5fe7c EA |
82 | /* |
83 | ** Look up this name | |
84 | */ | |
85 | ||
35cc3fad | 86 | p = aliaslookup(a->q_user); |
cdb17311 EA |
87 | if (p == NULL) |
88 | return; | |
b3cbe40f | 89 | |
d916f0ca | 90 | /* |
cdb17311 EA |
91 | ** Match on Alias. |
92 | ** Deliver to the target list. | |
d916f0ca EA |
93 | */ |
94 | ||
cdb17311 EA |
95 | # ifdef DEBUG |
96 | if (Debug) | |
97 | printf("%s (%s, %s) aliased to %s\n", | |
98 | a->q_paddr, a->q_host, a->q_user, p); | |
99 | # endif | |
100 | if (Verbose) | |
15b28570 | 101 | message(Arpa_Info, "aliased to %s", p); |
cdb17311 | 102 | AliasLevel++; |
abae7b2d | 103 | a->q_child = sendto(p, 1, a, 0); |
cdb17311 EA |
104 | AliasLevel--; |
105 | } | |
106 | \f/* | |
35cc3fad EA |
107 | ** ALIASLOOKUP -- look up a name in the alias file. |
108 | ** | |
109 | ** Parameters: | |
110 | ** name -- the name to look up. | |
111 | ** | |
112 | ** Returns: | |
113 | ** the value of name. | |
114 | ** NULL if unknown. | |
115 | ** | |
116 | ** Side Effects: | |
117 | ** none. | |
118 | ** | |
119 | ** Warnings: | |
120 | ** The return value will be trashed across calls. | |
121 | */ | |
122 | ||
123 | char * | |
124 | aliaslookup(name) | |
125 | char *name; | |
126 | { | |
127 | # ifdef DBM | |
128 | DATUM rhs, lhs; | |
129 | ||
130 | /* create a key for fetch */ | |
131 | lhs.dptr = name; | |
132 | lhs.dsize = strlen(name) + 1; | |
133 | rhs = fetch(lhs); | |
134 | return (rhs.dptr); | |
135 | # else DBM | |
136 | register STAB *s; | |
137 | ||
138 | s = stab(name, ST_ALIAS, ST_FIND); | |
139 | if (s == NULL) | |
140 | return (NULL); | |
141 | return (s->s_alias); | |
142 | # endif DBM | |
143 | } | |
144 | \f/* | |
cdb17311 EA |
145 | ** INITALIASES -- initialize for aliasing |
146 | ** | |
147 | ** Very different depending on whether we are running DBM or not. | |
148 | ** | |
149 | ** Parameters: | |
150 | ** aliasfile -- location of aliases. | |
f4dbf345 | 151 | ** init -- if set and if DBM, initialize the DBM files. |
cdb17311 EA |
152 | ** |
153 | ** Returns: | |
154 | ** none. | |
155 | ** | |
156 | ** Side Effects: | |
157 | ** initializes aliases: | |
158 | ** if DBM: opens the database. | |
159 | ** if ~DBM: reads the aliases into the symbol table. | |
160 | */ | |
161 | ||
f4dbf345 EA |
162 | # define DBMMODE 0666 |
163 | ||
164 | initaliases(aliasfile, init) | |
cdb17311 | 165 | char *aliasfile; |
f4dbf345 | 166 | bool init; |
cdb17311 | 167 | { |
d6b27179 EA |
168 | char buf[MAXNAME]; |
169 | struct stat stb; | |
170 | time_t modtime; | |
171 | ||
172 | /* | |
173 | ** See if the DBM version of the file is out of date with | |
174 | ** the text version. If so, go into 'init' mode automatically. | |
175 | ** This only happens if our effective userid owns the DBM | |
f9ce44de | 176 | ** version or if the mode of the database is 666 -- this |
d6b27179 EA |
177 | ** is an attempt to avoid protection problems. Note the |
178 | ** unpalatable hack to see if the stat succeeded. | |
179 | */ | |
180 | ||
181 | if (stat(aliasfile, &stb) < 0) | |
182 | return; | |
cdb17311 | 183 | # ifdef DBM |
d6b27179 EA |
184 | modtime = stb.st_mtime; |
185 | (void) strcpy(buf, aliasfile); | |
186 | (void) strcat(buf, ".pag"); | |
187 | stb.st_ino = 0; | |
188 | if ((stat(buf, &stb) < 0 || stb.st_mtime < modtime) && !init) | |
f4dbf345 | 189 | { |
d6b27179 | 190 | if (stb.st_ino != 0 && |
f9ce44de | 191 | ((stb.st_mode & 0666) == 0666 || stb.st_uid == geteuid())) |
d6b27179 EA |
192 | { |
193 | init = TRUE; | |
194 | if (Verbose) | |
195 | message(Arpa_Info, "rebuilding alias database"); | |
196 | } | |
197 | else | |
198 | { | |
199 | message(Arpa_Info, "Warning: alias database out of date"); | |
200 | } | |
201 | } | |
202 | # endif DBM | |
f4dbf345 | 203 | |
d6b27179 EA |
204 | /* |
205 | ** If initializing, create the new files. | |
206 | ** We should lock the alias file here to prevent other | |
207 | ** instantiations of sendmail from reading an incomplete | |
208 | ** file -- or worse yet, doing a concurrent initialize. | |
209 | */ | |
210 | ||
211 | # ifdef DBM | |
212 | if (init) | |
213 | { | |
f4dbf345 EA |
214 | (void) strcpy(buf, aliasfile); |
215 | (void) strcat(buf, ".dir"); | |
216 | if (close(creat(buf, DBMMODE)) < 0) | |
217 | { | |
218 | syserr("cannot make %s", buf); | |
219 | return; | |
220 | } | |
221 | (void) strcpy(buf, aliasfile); | |
222 | (void) strcat(buf, ".pag"); | |
223 | if (close(creat(buf, DBMMODE)) < 0) | |
224 | { | |
225 | syserr("cannot make %s", buf); | |
226 | return; | |
227 | } | |
228 | } | |
d6b27179 EA |
229 | |
230 | /* | |
231 | ** Open and, if necessary, load the DBM file. | |
232 | ** If running without DBM, load the symbol table. | |
233 | */ | |
234 | ||
cdb17311 | 235 | dbminit(aliasfile); |
f4dbf345 EA |
236 | if (init) |
237 | readaliases(aliasfile, TRUE); | |
cdb17311 | 238 | # else DBM |
f4dbf345 EA |
239 | readaliases(aliasfile, init); |
240 | # endif DBM | |
241 | } | |
242 | \f/* | |
243 | ** READALIASES -- read and process the alias file. | |
244 | ** | |
245 | ** This routine implements the part of initaliases that occurs | |
246 | ** when we are not going to use the DBM stuff. | |
247 | ** | |
248 | ** Parameters: | |
249 | ** aliasfile -- the pathname of the alias file master. | |
250 | ** init -- if set, initialize the DBM stuff. | |
251 | ** | |
252 | ** Returns: | |
253 | ** none. | |
254 | ** | |
255 | ** Side Effects: | |
256 | ** Reads aliasfile into the symbol table. | |
257 | ** Optionally, builds the .dir & .pag files. | |
258 | */ | |
259 | ||
260 | static | |
261 | readaliases(aliasfile, init) | |
262 | char *aliasfile; | |
263 | bool init; | |
264 | { | |
cdb17311 EA |
265 | char line[BUFSIZ]; |
266 | register char *p; | |
267 | char *p2; | |
268 | char *rhs; | |
269 | bool skipping; | |
270 | ADDRESS al, bl; | |
9e25d1f0 EA |
271 | FILE *af; |
272 | int lineno; | |
273 | register STAB *s; | |
d6b27179 | 274 | int naliases, bytes, longest; |
cdb17311 EA |
275 | |
276 | if ((af = fopen(aliasfile, "r")) == NULL) | |
d916f0ca | 277 | { |
cdb17311 EA |
278 | # ifdef DEBUG |
279 | if (Debug) | |
9e25d1f0 | 280 | printf("Can't open %s\n", aliasfile); |
cdb17311 EA |
281 | # endif |
282 | errno = 0; | |
283 | NoAlias++; | |
284 | return; | |
285 | } | |
74c5fe7c EA |
286 | |
287 | /* | |
288 | ** Read and interpret lines | |
289 | */ | |
290 | ||
cdb17311 | 291 | lineno = 0; |
d6b27179 | 292 | naliases = bytes = longest = 0; |
cdb17311 EA |
293 | skipping = FALSE; |
294 | while (fgets(line, sizeof (line), af) != NULL) | |
295 | { | |
d6b27179 EA |
296 | int lhssize, rhssize; |
297 | ||
cdb17311 EA |
298 | lineno++; |
299 | switch (line[0]) | |
300 | { | |
301 | case '#': | |
302 | case '\n': | |
303 | case '\0': | |
304 | skipping = FALSE; | |
305 | continue; | |
bdfaa762 | 306 | |
cdb17311 EA |
307 | case ' ': |
308 | case '\t': | |
309 | if (!skipping) | |
310 | syserr("aliases: %d: Non-continuation line starts with space", lineno); | |
311 | skipping = TRUE; | |
bdfaa762 | 312 | continue; |
cdb17311 EA |
313 | } |
314 | skipping = FALSE; | |
bdfaa762 | 315 | |
74c5fe7c EA |
316 | /* |
317 | ** Process the LHS | |
318 | ** Find the final colon, and parse the address. | |
319 | ** It should resolve to a local name -- this will | |
320 | ** be checked later (we want to optionally do | |
321 | ** parsing of the RHS first to maximize error | |
322 | ** detection). | |
323 | */ | |
324 | ||
cdb17311 | 325 | for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) |
bdfaa762 | 326 | continue; |
cdb17311 EA |
327 | if (*p == '\0' || *p == '\n') |
328 | { | |
329 | syntaxerr: | |
1bcdf0a2 | 330 | syserr("%s, line %d: syntax error", aliasfile, lineno); |
bdfaa762 | 331 | continue; |
cdb17311 EA |
332 | } |
333 | *p++ = '\0'; | |
334 | if (parse(line, &al, 1) == NULL) | |
335 | { | |
336 | *--p = ':'; | |
337 | goto syntaxerr; | |
338 | } | |
74c5fe7c EA |
339 | |
340 | /* | |
341 | ** Process the RHS. | |
342 | ** 'al' is the internal form of the LHS address. | |
343 | ** 'p' points to the text of the RHS. | |
1bcdf0a2 EA |
344 | ** 'p' may begin with a colon (i.e., the |
345 | ** separator was "::") which will use the | |
346 | ** first address as the person to send | |
347 | ** errors to -- i.e., designates the | |
348 | ** list maintainer. | |
74c5fe7c EA |
349 | */ |
350 | ||
1bcdf0a2 EA |
351 | if (*p == ':') |
352 | { | |
353 | ADDRESS *maint; | |
354 | ||
355 | while (isspace(*++p)) | |
356 | continue; | |
357 | rhs = p; | |
358 | while (*p != '\0' && *p != ',') | |
359 | p++; | |
360 | if (*p != ',') | |
361 | goto syntaxerr; | |
362 | *p++ = '\0'; | |
363 | maint = parse(p, (ADDRESS *) NULL, 1); | |
364 | if (maint == NULL) | |
365 | syserr("Illegal list maintainer for list %s", al.q_user); | |
366 | else if (CurEnv->e_returnto == &CurEnv->e_from) | |
367 | { | |
368 | CurEnv->e_returnto = maint; | |
369 | MailBack++; | |
370 | } | |
371 | } | |
372 | ||
cdb17311 | 373 | rhs = p; |
cdb17311 EA |
374 | for (;;) |
375 | { | |
376 | register char c; | |
d916f0ca | 377 | |
f4dbf345 | 378 | if (init) |
cdb17311 | 379 | { |
f4dbf345 | 380 | /* do parsing & compression of addresses */ |
cdb17311 | 381 | c = *p; |
f4dbf345 | 382 | while (c != '\0') |
cdb17311 | 383 | { |
f4dbf345 EA |
384 | p2 = p; |
385 | while (*p != '\n' && *p != ',' && *p != '\0') | |
386 | p++; | |
387 | c = *p; | |
388 | *p++ = '\0'; | |
d6b27179 EA |
389 | if (c == '\n') |
390 | c = '\0'; | |
f4dbf345 EA |
391 | if (*p2 == '\0') |
392 | { | |
393 | p[-1] = c; | |
394 | continue; | |
395 | } | |
74c5fe7c | 396 | (void) parse(p2, &bl, -1); |
cdb17311 | 397 | p[-1] = c; |
f4dbf345 EA |
398 | while (isspace(*p)) |
399 | p++; | |
cdb17311 | 400 | } |
cdb17311 | 401 | } |
f4dbf345 EA |
402 | else |
403 | p = &p[strlen(p)]; | |
d916f0ca | 404 | |
cdb17311 | 405 | /* see if there should be a continuation line */ |
9e25d1f0 EA |
406 | c = fgetc(af); |
407 | if (!feof(af)) | |
74c5fe7c | 408 | (void) ungetc(c, af); |
9e25d1f0 | 409 | if (c != ' ' && c != '\t') |
cdb17311 EA |
410 | break; |
411 | ||
412 | /* read continuation line */ | |
413 | p--; | |
414 | if (fgets(p, sizeof line - (p - line), af) == NULL) | |
415 | break; | |
416 | lineno++; | |
cdb17311 | 417 | } |
179c1218 | 418 | if (al.q_mailer != LocalMailer) |
cdb17311 EA |
419 | { |
420 | syserr("aliases: %d: cannot alias non-local names", lineno); | |
421 | continue; | |
422 | } | |
74c5fe7c EA |
423 | |
424 | /* | |
425 | ** Insert alias into symbol table or DBM file | |
426 | */ | |
427 | ||
d6b27179 EA |
428 | lhssize = strlen(al.q_user) + 1; |
429 | rhssize = strlen(rhs) + 1; | |
430 | ||
f4dbf345 EA |
431 | # ifdef DBM |
432 | if (init) | |
433 | { | |
434 | DATUM key, content; | |
435 | ||
d6b27179 | 436 | key.dsize = lhssize; |
f4dbf345 | 437 | key.dptr = al.q_user; |
d6b27179 | 438 | content.dsize = rhssize; |
f4dbf345 EA |
439 | content.dptr = rhs; |
440 | store(key, content); | |
441 | } | |
442 | else | |
443 | # endif DBM | |
444 | { | |
445 | s = stab(al.q_user, ST_ALIAS, ST_ENTER); | |
446 | s->s_alias = newstr(rhs); | |
447 | } | |
d6b27179 EA |
448 | |
449 | /* statistics */ | |
450 | naliases++; | |
451 | bytes += lhssize + rhssize; | |
452 | if (rhssize > longest) | |
453 | longest = rhssize; | |
d916f0ca | 454 | } |
cdb17311 | 455 | (void) fclose(af); |
2654b031 | 456 | CurEnv->e_to = NULL; |
d6b27179 EA |
457 | if (Verbose) |
458 | message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", | |
459 | naliases, longest, bytes); | |
b3cbe40f EA |
460 | } |
461 | \f/* | |
462 | ** FORWARD -- Try to forward mail | |
463 | ** | |
464 | ** This is similar but not identical to aliasing. | |
465 | ** | |
b3cbe40f | 466 | ** Parameters: |
74c5fe7c EA |
467 | ** user -- the name of the user who's mail we would like |
468 | ** to forward to. It must have been verified -- | |
469 | ** i.e., the q_home field must have been filled | |
470 | ** in. | |
d4f42161 EA |
471 | ** sendq -- a pointer to the head of the send queue to |
472 | ** put this user's aliases in. | |
b3cbe40f EA |
473 | ** |
474 | ** Returns: | |
cdb17311 | 475 | ** none. |
b3cbe40f EA |
476 | ** |
477 | ** Side Effects: | |
9e3c0a28 | 478 | ** New names are added to send queues. |
b3cbe40f EA |
479 | */ |
480 | ||
d4f42161 | 481 | forward(user, sendq) |
a530c75f | 482 | ADDRESS *user; |
d4f42161 | 483 | ADDRESS **sendq; |
b3cbe40f | 484 | { |
4bb4503e | 485 | char buf[60]; |
f6a0cc15 | 486 | extern bool safefile(); |
56678245 | 487 | |
cdb17311 EA |
488 | # ifdef DEBUG |
489 | if (Debug) | |
490 | printf("forward(%s)\n", user->q_paddr); | |
491 | # endif DEBUG | |
492 | ||
179c1218 | 493 | if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) |
cdb17311 | 494 | return; |
74c5fe7c EA |
495 | # ifdef DEBUG |
496 | if (user->q_home == NULL) | |
497 | syserr("forward: no home"); | |
498 | # endif DEBUG | |
56678245 | 499 | |
56678245 | 500 | /* good address -- look for .forward file in home */ |
8163ce8d | 501 | define('z', user->q_home); |
dd1fe05b | 502 | expand("$z/.forward", buf, &buf[sizeof buf - 1], CurEnv); |
f6a0cc15 | 503 | if (!safefile(buf, user->q_uid, S_IREAD)) |
cdb17311 | 504 | return; |
56678245 EA |
505 | |
506 | /* we do have an address to forward to -- do it */ | |
d4f42161 | 507 | include(buf, "forwarding", user, sendq); |
b3cbe40f | 508 | } |
35cc3fad EA |
509 | \f/* |
510 | ** HOSTALIAS -- alias a host name | |
511 | ** | |
512 | ** Given a host name, look it up in the host alias table | |
513 | ** and return it's value. If nothing, return NULL. | |
514 | ** | |
515 | ** Parameters: | |
516 | ** a -- address to alias. | |
517 | ** | |
518 | ** Returns: | |
519 | ** text result of aliasing. | |
520 | ** NULL if none. | |
521 | ** | |
522 | ** Side Effects: | |
523 | ** none. | |
524 | */ | |
525 | ||
526 | char * | |
527 | hostalias(a) | |
528 | register ADDRESS *a; | |
529 | { | |
530 | char buf[MAXNAME+2]; | |
531 | register char *p; | |
532 | ||
f9566d23 EA |
533 | (void) strcpy(buf, "/"); |
534 | (void) strcat(buf, a->q_host); | |
35cc3fad EA |
535 | makelower(buf); |
536 | ||
537 | p = aliaslookup(buf); | |
538 | if (p == NULL) | |
539 | return (NULL); | |
40e27d12 | 540 | (void) sprintf(buf, p, a->q_user); |
35cc3fad EA |
541 | return (newstr(buf)); |
542 | } |