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