Commit | Line | Data |
---|---|---|
d185cb11 DF |
1 | /* |
2 | ** Sendmail | |
3 | ** Copyright (c) 1983 Eric P. Allman | |
4 | ** Berkeley, California | |
5 | ** | |
6 | ** Copyright (c) 1983 Regents of the University of California. | |
7 | ** All rights reserved. The Berkeley software License Agreement | |
8 | ** specifies the terms and conditions for redistribution. | |
9 | */ | |
10 | ||
b3cbe40f | 11 | # include <pwd.h> |
9c3f729b EA |
12 | # include <sys/types.h> |
13 | # include <sys/stat.h> | |
7bdc419c | 14 | # include <signal.h> |
e6e345fa | 15 | # include <errno.h> |
96faada8 | 16 | # include "sendmail.h" |
e6e345fa EA |
17 | # ifdef FLOCK |
18 | # include <sys/file.h> | |
19 | # endif FLOCK | |
b3cbe40f | 20 | |
1cc8903f EA |
21 | #ifndef lint |
22 | # ifdef DBM | |
a78155b0 | 23 | static char SccsId[] = "@(#)alias.c 5.13 (Berkeley) %G% (with DBM)"; |
1cc8903f | 24 | # else DBM |
a78155b0 | 25 | static char SccsId[] = "@(#)alias.c 5.13 (Berkeley) %G% (without DBM)"; |
1cc8903f EA |
26 | # endif DBM |
27 | #endif not lint | |
28 | ||
916b3375 | 29 | |
b3cbe40f EA |
30 | /* |
31 | ** ALIAS -- Compute aliases. | |
32 | ** | |
7338e3d4 EA |
33 | ** Scans the alias file for an alias for the given address. |
34 | ** If found, it arranges to deliver to the alias list instead. | |
35 | ** Uses libdbm database if -DDBM. | |
b3cbe40f EA |
36 | ** |
37 | ** Parameters: | |
bdfaa762 | 38 | ** a -- address to alias. |
d4f42161 EA |
39 | ** sendq -- a pointer to the head of the send queue |
40 | ** to put the aliases in. | |
b3cbe40f EA |
41 | ** |
42 | ** Returns: | |
43 | ** none | |
44 | ** | |
45 | ** Side Effects: | |
9e3c0a28 | 46 | ** Aliases found are expanded. |
b3cbe40f | 47 | ** |
b3cbe40f EA |
48 | ** Notes: |
49 | ** If NoAlias (the "-n" flag) is set, no aliasing is | |
50 | ** done. | |
51 | ** | |
52 | ** Deficiencies: | |
53 | ** It should complain about names that are aliased to | |
54 | ** nothing. | |
b3cbe40f EA |
55 | */ |
56 | ||
57 | ||
c9b9c7a2 | 58 | #ifdef DBM |
a530c75f EA |
59 | typedef struct |
60 | { | |
61 | char *dptr; | |
f4dbf345 EA |
62 | int dsize; |
63 | } DATUM; | |
f4dbf345 | 64 | extern DATUM fetch(); |
c9b9c7a2 | 65 | #endif DBM |
b3cbe40f | 66 | |
d4f42161 | 67 | alias(a, sendq) |
bdfaa762 | 68 | register ADDRESS *a; |
d4f42161 | 69 | ADDRESS **sendq; |
b3cbe40f | 70 | { |
29871fef | 71 | register char *p; |
abae7b2d | 72 | extern ADDRESS *sendto(); |
35cc3fad | 73 | extern char *aliaslookup(); |
b3cbe40f | 74 | |
b3cbe40f | 75 | # ifdef DEBUG |
9678c96d | 76 | if (tTd(27, 1)) |
cdb17311 | 77 | printf("alias(%s)\n", a->q_paddr); |
b3cbe40f EA |
78 | # endif |
79 | ||
cdb17311 EA |
80 | /* don't realias already aliased names */ |
81 | if (bitset(QDONTSEND, a->q_flags)) | |
82 | return; | |
83 | ||
2654b031 | 84 | CurEnv->e_to = a->q_paddr; |
cdb17311 | 85 | |
74c5fe7c EA |
86 | /* |
87 | ** Look up this name | |
88 | */ | |
89 | ||
2e3062fe EA |
90 | if (NoAlias) |
91 | p = NULL; | |
92 | else | |
93 | p = aliaslookup(a->q_user); | |
cdb17311 EA |
94 | if (p == NULL) |
95 | return; | |
b3cbe40f | 96 | |
d916f0ca | 97 | /* |
cdb17311 EA |
98 | ** Match on Alias. |
99 | ** Deliver to the target list. | |
d916f0ca EA |
100 | */ |
101 | ||
cdb17311 | 102 | # ifdef DEBUG |
9678c96d | 103 | if (tTd(27, 1)) |
cdb17311 EA |
104 | printf("%s (%s, %s) aliased to %s\n", |
105 | a->q_paddr, a->q_host, a->q_user, p); | |
106 | # endif | |
91f69adf | 107 | message(Arpa_Info, "aliased to %s", p); |
cdb17311 | 108 | AliasLevel++; |
abae7b2d | 109 | a->q_child = sendto(p, 1, a, 0); |
cdb17311 EA |
110 | AliasLevel--; |
111 | } | |
112 | \f/* | |
35cc3fad EA |
113 | ** ALIASLOOKUP -- look up a name in the alias file. |
114 | ** | |
115 | ** Parameters: | |
116 | ** name -- the name to look up. | |
117 | ** | |
118 | ** Returns: | |
119 | ** the value of name. | |
120 | ** NULL if unknown. | |
121 | ** | |
122 | ** Side Effects: | |
123 | ** none. | |
124 | ** | |
125 | ** Warnings: | |
126 | ** The return value will be trashed across calls. | |
127 | */ | |
128 | ||
129 | char * | |
130 | aliaslookup(name) | |
131 | char *name; | |
132 | { | |
133 | # ifdef DBM | |
134 | DATUM rhs, lhs; | |
135 | ||
136 | /* create a key for fetch */ | |
137 | lhs.dptr = name; | |
138 | lhs.dsize = strlen(name) + 1; | |
139 | rhs = fetch(lhs); | |
140 | return (rhs.dptr); | |
141 | # else DBM | |
142 | register STAB *s; | |
143 | ||
144 | s = stab(name, ST_ALIAS, ST_FIND); | |
145 | if (s == NULL) | |
146 | return (NULL); | |
147 | return (s->s_alias); | |
148 | # endif DBM | |
149 | } | |
150 | \f/* | |
cdb17311 EA |
151 | ** INITALIASES -- initialize for aliasing |
152 | ** | |
153 | ** Very different depending on whether we are running DBM or not. | |
154 | ** | |
155 | ** Parameters: | |
156 | ** aliasfile -- location of aliases. | |
f4dbf345 | 157 | ** init -- if set and if DBM, initialize the DBM files. |
cdb17311 EA |
158 | ** |
159 | ** Returns: | |
160 | ** none. | |
161 | ** | |
162 | ** Side Effects: | |
163 | ** initializes aliases: | |
164 | ** if DBM: opens the database. | |
165 | ** if ~DBM: reads the aliases into the symbol table. | |
166 | */ | |
167 | ||
f4dbf345 EA |
168 | # define DBMMODE 0666 |
169 | ||
170 | initaliases(aliasfile, init) | |
cdb17311 | 171 | char *aliasfile; |
f4dbf345 | 172 | bool init; |
cdb17311 | 173 | { |
7338e3d4 | 174 | #ifdef DBM |
7bdc419c | 175 | int atcnt; |
d6b27179 | 176 | time_t modtime; |
9327783c EA |
177 | bool automatic = FALSE; |
178 | char buf[MAXNAME]; | |
7338e3d4 EA |
179 | #endif DBM |
180 | struct stat stb; | |
a78155b0 EA |
181 | static bool initialized = FALSE; |
182 | ||
183 | if (initialized) | |
184 | return; | |
185 | initialized = TRUE; | |
d6b27179 | 186 | |
bb09c502 | 187 | if (aliasfile == NULL || stat(aliasfile, &stb) < 0) |
7bdc419c | 188 | { |
9327783c EA |
189 | if (aliasfile != NULL && init) |
190 | syserr("Cannot open %s", aliasfile); | |
7bdc419c | 191 | NoAlias = TRUE; |
70faa7c8 | 192 | errno = 0; |
7bdc419c EA |
193 | return; |
194 | } | |
195 | ||
d5fe2834 | 196 | # ifdef DBM |
7bdc419c EA |
197 | /* |
198 | ** Check to see that the alias file is complete. | |
199 | ** If not, we will assume that someone died, and it is up | |
200 | ** to us to rebuild it. | |
201 | */ | |
202 | ||
a1a07282 EA |
203 | if (!init) |
204 | dbminit(aliasfile); | |
560a80d9 EA |
205 | atcnt = SafeAlias * 2; |
206 | if (atcnt > 0) | |
207 | { | |
208 | while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) | |
a1a07282 EA |
209 | { |
210 | /* | |
211 | ** Reinitialize alias file in case the new | |
212 | ** one is mv'ed in instead of cp'ed in. | |
213 | ** | |
214 | ** Only works with new DBM -- old one will | |
215 | ** just consume file descriptors forever. | |
216 | ** If you have a dbmclose() it can be | |
217 | ** added before the sleep(30). | |
218 | */ | |
219 | ||
560a80d9 | 220 | sleep(30); |
a1a07282 EA |
221 | # ifdef NDBM |
222 | dbminit(aliasfile); | |
223 | # endif NDBM | |
224 | } | |
560a80d9 EA |
225 | } |
226 | else | |
227 | atcnt = 1; | |
7bdc419c | 228 | |
d6b27179 EA |
229 | /* |
230 | ** See if the DBM version of the file is out of date with | |
231 | ** the text version. If so, go into 'init' mode automatically. | |
232 | ** This only happens if our effective userid owns the DBM | |
f9ce44de | 233 | ** version or if the mode of the database is 666 -- this |
d6b27179 EA |
234 | ** is an attempt to avoid protection problems. Note the |
235 | ** unpalatable hack to see if the stat succeeded. | |
236 | */ | |
237 | ||
d6b27179 EA |
238 | modtime = stb.st_mtime; |
239 | (void) strcpy(buf, aliasfile); | |
240 | (void) strcat(buf, ".pag"); | |
241 | stb.st_ino = 0; | |
f12e5a74 | 242 | if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) |
f4dbf345 | 243 | { |
70faa7c8 | 244 | errno = 0; |
4871a357 | 245 | if (AutoRebuild && stb.st_ino != 0 && |
7338e3d4 | 246 | ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid())) |
d6b27179 EA |
247 | { |
248 | init = TRUE; | |
9327783c | 249 | automatic = TRUE; |
91f69adf | 250 | message(Arpa_Info, "rebuilding alias database"); |
2e3062fe EA |
251 | #ifdef LOG |
252 | if (LogLevel >= 7) | |
253 | syslog(LOG_INFO, "rebuilding alias database"); | |
254 | #endif LOG | |
d6b27179 EA |
255 | } |
256 | else | |
257 | { | |
f12e5a74 | 258 | #ifdef LOG |
2e3062fe EA |
259 | if (LogLevel >= 7) |
260 | syslog(LOG_INFO, "alias database out of date"); | |
f12e5a74 | 261 | #endif LOG |
d6b27179 EA |
262 | message(Arpa_Info, "Warning: alias database out of date"); |
263 | } | |
264 | } | |
f4dbf345 | 265 | |
d6b27179 EA |
266 | |
267 | /* | |
7bdc419c | 268 | ** If necessary, load the DBM file. |
d6b27179 EA |
269 | ** If running without DBM, load the symbol table. |
270 | */ | |
271 | ||
f4dbf345 | 272 | if (init) |
7bdc419c | 273 | { |
9327783c EA |
274 | #ifdef LOG |
275 | if (LogLevel >= 6) | |
276 | { | |
277 | extern char *username(); | |
278 | ||
279 | syslog(LOG_NOTICE, "alias database %srebuilt by %s", | |
280 | automatic ? "auto" : "", username()); | |
281 | } | |
282 | #endif LOG | |
f4dbf345 | 283 | readaliases(aliasfile, TRUE); |
7bdc419c | 284 | } |
cdb17311 | 285 | # else DBM |
f4dbf345 EA |
286 | readaliases(aliasfile, init); |
287 | # endif DBM | |
288 | } | |
289 | \f/* | |
290 | ** READALIASES -- read and process the alias file. | |
291 | ** | |
292 | ** This routine implements the part of initaliases that occurs | |
293 | ** when we are not going to use the DBM stuff. | |
294 | ** | |
295 | ** Parameters: | |
296 | ** aliasfile -- the pathname of the alias file master. | |
297 | ** init -- if set, initialize the DBM stuff. | |
298 | ** | |
299 | ** Returns: | |
300 | ** none. | |
301 | ** | |
302 | ** Side Effects: | |
303 | ** Reads aliasfile into the symbol table. | |
304 | ** Optionally, builds the .dir & .pag files. | |
305 | */ | |
306 | ||
307 | static | |
308 | readaliases(aliasfile, init) | |
309 | char *aliasfile; | |
310 | bool init; | |
311 | { | |
cdb17311 | 312 | register char *p; |
41173b8f | 313 | char *lhs; |
cdb17311 EA |
314 | char *rhs; |
315 | bool skipping; | |
7338e3d4 | 316 | int naliases, bytes, longest; |
9e25d1f0 | 317 | FILE *af; |
e6e345fa | 318 | int (*oldsigint)(); |
7338e3d4 | 319 | ADDRESS al, bl; |
9e25d1f0 | 320 | register STAB *s; |
7338e3d4 | 321 | char line[BUFSIZ]; |
cdb17311 EA |
322 | |
323 | if ((af = fopen(aliasfile, "r")) == NULL) | |
d916f0ca | 324 | { |
cdb17311 | 325 | # ifdef DEBUG |
9678c96d | 326 | if (tTd(27, 1)) |
9e25d1f0 | 327 | printf("Can't open %s\n", aliasfile); |
cdb17311 EA |
328 | # endif |
329 | errno = 0; | |
330 | NoAlias++; | |
331 | return; | |
332 | } | |
74c5fe7c | 333 | |
e6e345fa EA |
334 | # ifdef DBM |
335 | # ifdef FLOCK | |
336 | /* see if someone else is rebuilding the alias file already */ | |
337 | if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) | |
338 | { | |
339 | /* yes, they are -- wait until done and then return */ | |
340 | message(Arpa_Info, "Alias file is already being rebuilt"); | |
341 | if (OpMode != MD_INITALIAS) | |
342 | { | |
343 | /* wait for other rebuild to complete */ | |
344 | (void) flock(fileno(af), LOCK_EX); | |
345 | } | |
03388044 | 346 | (void) fclose(af); |
e6e345fa EA |
347 | errno = 0; |
348 | return; | |
349 | } | |
350 | # endif FLOCK | |
351 | # endif DBM | |
352 | ||
353 | /* | |
354 | ** If initializing, create the new DBM files. | |
355 | */ | |
356 | ||
357 | if (init) | |
358 | { | |
359 | oldsigint = signal(SIGINT, SIG_IGN); | |
360 | (void) strcpy(line, aliasfile); | |
361 | (void) strcat(line, ".dir"); | |
362 | if (close(creat(line, DBMMODE)) < 0) | |
363 | { | |
364 | syserr("cannot make %s", line); | |
365 | (void) signal(SIGINT, oldsigint); | |
366 | return; | |
367 | } | |
368 | (void) strcpy(line, aliasfile); | |
369 | (void) strcat(line, ".pag"); | |
370 | if (close(creat(line, DBMMODE)) < 0) | |
371 | { | |
372 | syserr("cannot make %s", line); | |
373 | (void) signal(SIGINT, oldsigint); | |
374 | return; | |
375 | } | |
1eff167f | 376 | dbminit(aliasfile); |
e6e345fa EA |
377 | } |
378 | ||
74c5fe7c EA |
379 | /* |
380 | ** Read and interpret lines | |
381 | */ | |
382 | ||
7338e3d4 EA |
383 | FileName = aliasfile; |
384 | LineNumber = 0; | |
d6b27179 | 385 | naliases = bytes = longest = 0; |
cdb17311 EA |
386 | skipping = FALSE; |
387 | while (fgets(line, sizeof (line), af) != NULL) | |
388 | { | |
d6b27179 EA |
389 | int lhssize, rhssize; |
390 | ||
7338e3d4 | 391 | LineNumber++; |
3312f93c EA |
392 | p = index(line, '\n'); |
393 | if (p != NULL) | |
394 | *p = '\0'; | |
cdb17311 EA |
395 | switch (line[0]) |
396 | { | |
397 | case '#': | |
cdb17311 EA |
398 | case '\0': |
399 | skipping = FALSE; | |
400 | continue; | |
bdfaa762 | 401 | |
cdb17311 EA |
402 | case ' ': |
403 | case '\t': | |
404 | if (!skipping) | |
7338e3d4 | 405 | syserr("Non-continuation line starts with space"); |
cdb17311 | 406 | skipping = TRUE; |
bdfaa762 | 407 | continue; |
cdb17311 EA |
408 | } |
409 | skipping = FALSE; | |
bdfaa762 | 410 | |
74c5fe7c EA |
411 | /* |
412 | ** Process the LHS | |
41173b8f | 413 | ** |
74c5fe7c | 414 | ** Find the final colon, and parse the address. |
41173b8f EA |
415 | ** It should resolve to a local name. |
416 | ** | |
417 | ** Alternatively, it can be "@hostname" for host | |
418 | ** aliases -- all we do here is map case. Hostname | |
419 | ** need not be a single token. | |
74c5fe7c EA |
420 | */ |
421 | ||
cdb17311 | 422 | for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) |
bdfaa762 | 423 | continue; |
41173b8f | 424 | if (*p != ':') |
cdb17311 | 425 | { |
1bcdf0a2 | 426 | syserr("%s, line %d: syntax error", aliasfile, lineno); |
bdfaa762 | 427 | continue; |
cdb17311 | 428 | } |
41173b8f EA |
429 | *p++ = '\0'; |
430 | if (line[0] == '@') | |
cdb17311 | 431 | { |
41173b8f EA |
432 | /* a host alias */ |
433 | makelower(line); | |
434 | lhs = line; | |
435 | } | |
436 | else | |
437 | { | |
438 | /* a user alias */ | |
439 | if (parseaddr(line, &al, 1, ':') == NULL) | |
440 | { | |
441 | syserr("illegal alias name"); | |
442 | continue; | |
443 | } | |
444 | loweraddr(&al); | |
445 | if (al.q_mailer != LocalMailer) | |
446 | { | |
447 | syserr("cannot alias non-local names"); | |
448 | continue; | |
449 | } | |
450 | lhs = al.q_user; | |
cdb17311 | 451 | } |
74c5fe7c EA |
452 | |
453 | /* | |
454 | ** Process the RHS. | |
455 | ** 'al' is the internal form of the LHS address. | |
456 | ** 'p' points to the text of the RHS. | |
1bcdf0a2 EA |
457 | ** 'p' may begin with a colon (i.e., the |
458 | ** separator was "::") which will use the | |
459 | ** first address as the person to send | |
460 | ** errors to -- i.e., designates the | |
461 | ** list maintainer. | |
74c5fe7c EA |
462 | */ |
463 | ||
1bcdf0a2 EA |
464 | if (*p == ':') |
465 | { | |
466 | ADDRESS *maint; | |
467 | ||
468 | while (isspace(*++p)) | |
469 | continue; | |
470 | rhs = p; | |
471 | while (*p != '\0' && *p != ',') | |
472 | p++; | |
473 | if (*p != ',') | |
474 | goto syntaxerr; | |
475 | *p++ = '\0'; | |
476 | maint = parse(p, (ADDRESS *) NULL, 1); | |
477 | if (maint == NULL) | |
478 | syserr("Illegal list maintainer for list %s", al.q_user); | |
479 | else if (CurEnv->e_returnto == &CurEnv->e_from) | |
480 | { | |
481 | CurEnv->e_returnto = maint; | |
482 | MailBack++; | |
483 | } | |
484 | } | |
485 | ||
cdb17311 | 486 | rhs = p; |
cdb17311 EA |
487 | for (;;) |
488 | { | |
489 | register char c; | |
d916f0ca | 490 | |
1e963db5 | 491 | if (init && CheckAliases) |
cdb17311 | 492 | { |
f4dbf345 | 493 | /* do parsing & compression of addresses */ |
3312f93c | 494 | while (*p != '\0') |
cdb17311 | 495 | { |
3312f93c EA |
496 | extern char *DelimChar; |
497 | ||
498 | while (isspace(*p) || *p == ',') | |
c49d661c | 499 | p++; |
3312f93c EA |
500 | if (*p == '\0') |
501 | break; | |
502 | if (parseaddr(p, &bl, -1, ',') == NULL) | |
503 | usrerr("%s... bad address", p); | |
504 | p = DelimChar; | |
cdb17311 | 505 | } |
cdb17311 | 506 | } |
f4dbf345 | 507 | else |
634c8ff3 | 508 | { |
34fe0a9b EA |
509 | p = &p[strlen(p)]; |
510 | if (p[-1] == '\n') | |
511 | *--p = '\0'; | |
634c8ff3 | 512 | } |
d916f0ca | 513 | |
cdb17311 | 514 | /* see if there should be a continuation line */ |
9e25d1f0 EA |
515 | c = fgetc(af); |
516 | if (!feof(af)) | |
74c5fe7c | 517 | (void) ungetc(c, af); |
9e25d1f0 | 518 | if (c != ' ' && c != '\t') |
cdb17311 EA |
519 | break; |
520 | ||
521 | /* read continuation line */ | |
cdb17311 EA |
522 | if (fgets(p, sizeof line - (p - line), af) == NULL) |
523 | break; | |
7338e3d4 | 524 | LineNumber++; |
cdb17311 | 525 | } |
74c5fe7c EA |
526 | |
527 | /* | |
528 | ** Insert alias into symbol table or DBM file | |
529 | */ | |
530 | ||
41173b8f | 531 | lhssize = strlen(lhs) + 1; |
d6b27179 EA |
532 | rhssize = strlen(rhs) + 1; |
533 | ||
f4dbf345 EA |
534 | # ifdef DBM |
535 | if (init) | |
536 | { | |
537 | DATUM key, content; | |
538 | ||
d6b27179 | 539 | key.dsize = lhssize; |
f4dbf345 | 540 | key.dptr = al.q_user; |
d6b27179 | 541 | content.dsize = rhssize; |
f4dbf345 EA |
542 | content.dptr = rhs; |
543 | store(key, content); | |
544 | } | |
545 | else | |
546 | # endif DBM | |
547 | { | |
548 | s = stab(al.q_user, ST_ALIAS, ST_ENTER); | |
549 | s->s_alias = newstr(rhs); | |
550 | } | |
d6b27179 EA |
551 | |
552 | /* statistics */ | |
553 | naliases++; | |
554 | bytes += lhssize + rhssize; | |
555 | if (rhssize > longest) | |
556 | longest = rhssize; | |
d916f0ca | 557 | } |
e6e345fa EA |
558 | |
559 | # ifdef DBM | |
560 | if (init) | |
561 | { | |
562 | /* add the distinquished alias "@" */ | |
563 | DATUM key; | |
564 | ||
565 | key.dsize = 2; | |
566 | key.dptr = "@"; | |
567 | store(key, key); | |
568 | ||
569 | /* restore the old signal */ | |
570 | (void) signal(SIGINT, oldsigint); | |
571 | } | |
572 | # endif DBM | |
573 | ||
574 | /* closing the alias file drops the lock */ | |
cdb17311 | 575 | (void) fclose(af); |
2654b031 | 576 | CurEnv->e_to = NULL; |
7338e3d4 | 577 | FileName = NULL; |
91f69adf | 578 | message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", |
d6b27179 | 579 | naliases, longest, bytes); |
2e3062fe EA |
580 | # ifdef LOG |
581 | if (LogLevel >= 8) | |
582 | syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", | |
583 | naliases, longest, bytes); | |
584 | # endif LOG | |
b3cbe40f EA |
585 | } |
586 | \f/* | |
587 | ** FORWARD -- Try to forward mail | |
588 | ** | |
589 | ** This is similar but not identical to aliasing. | |
590 | ** | |
b3cbe40f | 591 | ** Parameters: |
74c5fe7c EA |
592 | ** user -- the name of the user who's mail we would like |
593 | ** to forward to. It must have been verified -- | |
594 | ** i.e., the q_home field must have been filled | |
595 | ** in. | |
d4f42161 EA |
596 | ** sendq -- a pointer to the head of the send queue to |
597 | ** put this user's aliases in. | |
b3cbe40f EA |
598 | ** |
599 | ** Returns: | |
cdb17311 | 600 | ** none. |
b3cbe40f EA |
601 | ** |
602 | ** Side Effects: | |
9e3c0a28 | 603 | ** New names are added to send queues. |
b3cbe40f EA |
604 | */ |
605 | ||
d4f42161 | 606 | forward(user, sendq) |
a530c75f | 607 | ADDRESS *user; |
d4f42161 | 608 | ADDRESS **sendq; |
b3cbe40f | 609 | { |
4bb4503e | 610 | char buf[60]; |
f6a0cc15 | 611 | extern bool safefile(); |
56678245 | 612 | |
cdb17311 | 613 | # ifdef DEBUG |
9678c96d | 614 | if (tTd(27, 1)) |
cdb17311 EA |
615 | printf("forward(%s)\n", user->q_paddr); |
616 | # endif DEBUG | |
617 | ||
179c1218 | 618 | if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) |
cdb17311 | 619 | return; |
74c5fe7c EA |
620 | # ifdef DEBUG |
621 | if (user->q_home == NULL) | |
622 | syserr("forward: no home"); | |
623 | # endif DEBUG | |
56678245 | 624 | |
56678245 | 625 | /* good address -- look for .forward file in home */ |
7338e3d4 | 626 | define('z', user->q_home, CurEnv); |
a73ae8ac | 627 | expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv); |
f6a0cc15 | 628 | if (!safefile(buf, user->q_uid, S_IREAD)) |
cdb17311 | 629 | return; |
56678245 EA |
630 | |
631 | /* we do have an address to forward to -- do it */ | |
d4f42161 | 632 | include(buf, "forwarding", user, sendq); |
b3cbe40f | 633 | } |
41173b8f EA |
634 | \f/* |
635 | ** MAPHOST -- given a host description, produce a mapping. | |
636 | ** | |
637 | ** This is done by looking up the name in the alias file, | |
638 | ** preceeded by an "@". This can be used for UUCP mapping. | |
639 | ** For example, a call with {blia, ., UUCP} as arguments | |
640 | ** might return {ucsfcgl, !, blia, ., UUCP} as the result. | |
641 | ** | |
642 | ** We first break the input into three parts -- before the | |
643 | ** lookup, the lookup itself, and after the lookup. We | |
644 | ** then do the lookup, concatenate them together, and rescan | |
645 | ** the result. | |
646 | ** | |
647 | ** Parameters: | |
648 | ** pvp -- the parameter vector to map. | |
649 | ** | |
650 | ** Returns: | |
651 | ** The result of the mapping. If nothing found, it | |
652 | ** should just concatenate the three parts together and | |
653 | ** return that. | |
654 | ** | |
655 | ** Side Effects: | |
656 | ** none. | |
657 | */ | |
658 | ||
659 | char ** | |
660 | maphost(pvp) | |
661 | char **pvp; | |
662 | { | |
663 | register char **avp; | |
664 | register char **bvp; | |
665 | char *p; | |
666 | char buf1[MAXNAME]; | |
667 | char buf2[MAXNAME]; | |
668 | char buf3[MAXNAME]; | |
669 | extern char **prescan(); | |
670 | ||
671 | /* | |
672 | ** Extract the three parts of the input as strings. | |
673 | */ | |
674 | ||
675 | /* find the part before the lookup */ | |
676 | for (bvp = pvp; *bvp != NULL && **bvp != MATCHLOOKUP; bvp++) | |
677 | continue; | |
678 | if (*bvp == NULL) | |
679 | return (pvp); | |
680 | p = *bvp; | |
681 | *bvp = NULL; | |
682 | cataddr(pvp, buf1, sizeof buf1); | |
683 | *bvp++ = p; | |
684 | ||
685 | /* find the rest of the lookup */ | |
686 | for (avp = bvp; *pvp != NULL && **bvp != MATCHELOOKUP; bvp++) | |
687 | continue; | |
688 | if (*bvp == NULL) | |
689 | return (pvp); | |
690 | p = *bvp; | |
691 | *bvp = NULL; | |
692 | cataddr(avp, buf2, sizeof buf2); | |
693 | *bvp++ = p; | |
694 | ||
695 | /* save the part after the lookup */ | |
696 | cataddr(bvp, buf3, sizeof buf3); | |
697 | ||
698 | /* | |
699 | ** Now look up the middle part. | |
700 | */ | |
701 | ||
702 | p = aliaslookup(buf2); | |
703 | if (p != NULL) | |
704 | strcpy(buf2, p); | |
705 | ||
706 | /* | |
707 | ** Put the three parts back together and break into tokens. | |
708 | */ | |
709 | ||
710 | strcat(buf1, buf2); | |
711 | strcat(buf1, buf3); | |
712 | avp = prescan(buf1, '\0'); | |
713 | ||
714 | /* return this mapping */ | |
715 | return (avp); | |
716 | } |