|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Eric P. Allman
3: * Copyright (c) 1988 Regents of the University of California.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms are permitted provided
7: * that: (1) source distributions retain this entire copyright notice and
8: * comment, and (2) distributions including binaries display the following
9: * acknowledgement: ``This product includes software developed by the
10: * University of California, Berkeley and its contributors'' in the
11: * documentation or other materials provided with the distribution and in
12: * all advertising materials mentioning features or use of this software.
13: * Neither the name of the University nor the names of its contributors may
14: * be used to endorse or promote products derived from this software without
15: * specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: */
20:
21: #ifndef lint
22: #ifdef DBM
23: static char sccsid[] = "@(#)alias.c 5.21 (Berkeley) 6/1/90 (with DBM)";
24: #else
25: static char sccsid[] = "@(#)alias.c 5.21 (Berkeley) 6/1/90 (without DBM)";
26: #endif
27: #endif /* not lint */
28:
29: # include <sys/types.h>
30: # include <sys/stat.h>
31: # include <signal.h>
32: # include <errno.h>
33: # include "sendmail.h"
34: # include <sys/file.h>
35: # include <pwd.h>
36:
37: /*
38: ** ALIAS -- Compute aliases.
39: **
40: ** Scans the alias file for an alias for the given address.
41: ** If found, it arranges to deliver to the alias list instead.
42: ** Uses libdbm database if -DDBM.
43: **
44: ** Parameters:
45: ** a -- address to alias.
46: ** sendq -- a pointer to the head of the send queue
47: ** to put the aliases in.
48: **
49: ** Returns:
50: ** none
51: **
52: ** Side Effects:
53: ** Aliases found are expanded.
54: **
55: ** Notes:
56: ** If NoAlias (the "-n" flag) is set, no aliasing is
57: ** done.
58: **
59: ** Deficiencies:
60: ** It should complain about names that are aliased to
61: ** nothing.
62: */
63:
64:
65: #ifdef DBM
66: typedef struct
67: {
68: char *dptr;
69: int dsize;
70: } DATUM;
71: extern DATUM fetch();
72: #endif DBM
73:
74: alias(a, sendq)
75: register ADDRESS *a;
76: ADDRESS **sendq;
77: {
78: register char *p;
79: extern char *aliaslookup();
80:
81: if (tTd(27, 1))
82: printf("alias(%s)\n", a->q_paddr);
83:
84: /* don't realias already aliased names */
85: if (bitset(QDONTSEND, a->q_flags))
86: return;
87:
88: CurEnv->e_to = a->q_paddr;
89:
90: /*
91: ** Look up this name
92: */
93:
94: if (NoAlias)
95: p = NULL;
96: else
97: p = aliaslookup(a->q_user);
98: if (p == NULL)
99: return;
100:
101: /*
102: ** Match on Alias.
103: ** Deliver to the target list.
104: */
105:
106: if (tTd(27, 1))
107: printf("%s (%s, %s) aliased to %s\n",
108: a->q_paddr, a->q_host, a->q_user, p);
109: message(Arpa_Info, "aliased to %s", p);
110: AliasLevel++;
111: sendtolist(p, a, sendq);
112: AliasLevel--;
113: }
114: /*
115: ** ALIASLOOKUP -- look up a name in the alias file.
116: **
117: ** Parameters:
118: ** name -- the name to look up.
119: **
120: ** Returns:
121: ** the value of name.
122: ** NULL if unknown.
123: **
124: ** Side Effects:
125: ** none.
126: **
127: ** Warnings:
128: ** The return value will be trashed across calls.
129: */
130:
131: char *
132: aliaslookup(name)
133: char *name;
134: {
135: # ifdef DBM
136: DATUM rhs, lhs;
137:
138: /* create a key for fetch */
139: lhs.dptr = name;
140: lhs.dsize = strlen(name) + 1;
141: rhs = fetch(lhs);
142: return (rhs.dptr);
143: # else DBM
144: register STAB *s;
145:
146: s = stab(name, ST_ALIAS, ST_FIND);
147: if (s == NULL)
148: return (NULL);
149: return (s->s_alias);
150: # endif DBM
151: }
152: /*
153: ** INITALIASES -- initialize for aliasing
154: **
155: ** Very different depending on whether we are running DBM or not.
156: **
157: ** Parameters:
158: ** aliasfile -- location of aliases.
159: ** init -- if set and if DBM, initialize the DBM files.
160: **
161: ** Returns:
162: ** none.
163: **
164: ** Side Effects:
165: ** initializes aliases:
166: ** if DBM: opens the database.
167: ** if ~DBM: reads the aliases into the symbol table.
168: */
169:
170: # define DBMMODE 0644
171:
172: initaliases(aliasfile, init)
173: char *aliasfile;
174: bool init;
175: {
176: #ifdef DBM
177: int atcnt;
178: time_t modtime;
179: bool automatic = FALSE;
180: char buf[MAXNAME];
181: #endif DBM
182: struct stat stb;
183: static bool initialized = FALSE;
184:
185: if (initialized)
186: return;
187: initialized = TRUE;
188:
189: if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
190: {
191: if (aliasfile != NULL && init)
192: syserr("Cannot open %s", aliasfile);
193: NoAlias = TRUE;
194: errno = 0;
195: return;
196: }
197:
198: # ifdef DBM
199: /*
200: ** Check to see that the alias file is complete.
201: ** If not, we will assume that someone died, and it is up
202: ** to us to rebuild it.
203: */
204:
205: if (!init)
206: dbminit(aliasfile);
207: atcnt = SafeAlias * 2;
208: if (atcnt > 0)
209: {
210: while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
211: {
212: /*
213: ** Reinitialize alias file in case the new
214: ** one is mv'ed in instead of cp'ed in.
215: **
216: ** Only works with new DBM -- old one will
217: ** just consume file descriptors forever.
218: ** If you have a dbmclose() it can be
219: ** added before the sleep(30).
220: */
221:
222: sleep(30);
223: # ifdef NDBM
224: dbminit(aliasfile);
225: # endif NDBM
226: }
227: }
228: else
229: atcnt = 1;
230:
231: /*
232: ** See if the DBM version of the file is out of date with
233: ** the text version. If so, go into 'init' mode automatically.
234: ** This only happens if our effective userid owns the DBM.
235: ** Note the unpalatable hack to see if the stat succeeded.
236: */
237:
238: modtime = stb.st_mtime;
239: (void) strcpy(buf, aliasfile);
240: (void) strcat(buf, ".pag");
241: stb.st_ino = 0;
242: if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
243: {
244: errno = 0;
245: if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
246: {
247: init = TRUE;
248: automatic = TRUE;
249: message(Arpa_Info, "rebuilding alias database");
250: #ifdef LOG
251: if (LogLevel >= 7)
252: syslog(LOG_INFO, "rebuilding alias database");
253: #endif LOG
254: }
255: else
256: {
257: #ifdef LOG
258: if (LogLevel >= 7)
259: syslog(LOG_INFO, "alias database out of date");
260: #endif LOG
261: message(Arpa_Info, "Warning: alias database out of date");
262: }
263: }
264:
265:
266: /*
267: ** If necessary, load the DBM file.
268: ** If running without DBM, load the symbol table.
269: */
270:
271: if (init)
272: {
273: #ifdef LOG
274: if (LogLevel >= 6)
275: {
276: extern char *username();
277:
278: syslog(LOG_NOTICE, "alias database %srebuilt by %s",
279: automatic ? "auto" : "", username());
280: }
281: #endif LOG
282: readaliases(aliasfile, TRUE);
283: }
284: # else DBM
285: readaliases(aliasfile, init);
286: # endif DBM
287: }
288: /*
289: ** READALIASES -- read and process the alias file.
290: **
291: ** This routine implements the part of initaliases that occurs
292: ** when we are not going to use the DBM stuff.
293: **
294: ** Parameters:
295: ** aliasfile -- the pathname of the alias file master.
296: ** init -- if set, initialize the DBM stuff.
297: **
298: ** Returns:
299: ** none.
300: **
301: ** Side Effects:
302: ** Reads aliasfile into the symbol table.
303: ** Optionally, builds the .dir & .pag files.
304: */
305:
306: static
307: readaliases(aliasfile, init)
308: char *aliasfile;
309: bool init;
310: {
311: register char *p;
312: char *rhs;
313: bool skipping;
314: int naliases, bytes, longest;
315: FILE *af;
316: void (*oldsigint)();
317: ADDRESS al, bl;
318: register STAB *s;
319: char line[BUFSIZ];
320:
321: if ((af = fopen(aliasfile, "r")) == NULL)
322: {
323: if (tTd(27, 1))
324: printf("Can't open %s\n", aliasfile);
325: errno = 0;
326: NoAlias++;
327: return;
328: }
329:
330: # ifdef DBM
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: }
341: (void) fclose(af);
342: errno = 0;
343: return;
344: }
345: # endif DBM
346:
347: /*
348: ** If initializing, create the new DBM files.
349: */
350:
351: if (init)
352: {
353: oldsigint = signal(SIGINT, SIG_IGN);
354: (void) strcpy(line, aliasfile);
355: (void) strcat(line, ".dir");
356: if (close(creat(line, DBMMODE)) < 0)
357: {
358: syserr("cannot make %s", line);
359: (void) signal(SIGINT, oldsigint);
360: return;
361: }
362: (void) strcpy(line, aliasfile);
363: (void) strcat(line, ".pag");
364: if (close(creat(line, DBMMODE)) < 0)
365: {
366: syserr("cannot make %s", line);
367: (void) signal(SIGINT, oldsigint);
368: return;
369: }
370: dbminit(aliasfile);
371: }
372:
373: /*
374: ** Read and interpret lines
375: */
376:
377: FileName = aliasfile;
378: LineNumber = 0;
379: naliases = bytes = longest = 0;
380: skipping = FALSE;
381: while (fgets(line, sizeof (line), af) != NULL)
382: {
383: int lhssize, rhssize;
384:
385: LineNumber++;
386: p = index(line, '\n');
387: if (p != NULL)
388: *p = '\0';
389: switch (line[0])
390: {
391: case '#':
392: case '\0':
393: skipping = FALSE;
394: continue;
395:
396: case ' ':
397: case '\t':
398: if (!skipping)
399: syserr("Non-continuation line starts with space");
400: skipping = TRUE;
401: continue;
402: }
403: skipping = FALSE;
404:
405: /*
406: ** Process the LHS
407: ** Find the final colon, and parse the address.
408: ** It should resolve to a local name -- this will
409: ** be checked later (we want to optionally do
410: ** parsing of the RHS first to maximize error
411: ** detection).
412: */
413:
414: for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
415: continue;
416: if (*p++ != ':')
417: {
418: syserr("missing colon");
419: continue;
420: }
421: if (parseaddr(line, &al, 1, ':') == NULL)
422: {
423: syserr("illegal alias name");
424: continue;
425: }
426: loweraddr(&al);
427:
428: /*
429: ** Process the RHS.
430: ** 'al' is the internal form of the LHS address.
431: ** 'p' points to the text of the RHS.
432: */
433:
434: rhs = p;
435: for (;;)
436: {
437: register char c;
438:
439: if (init && CheckAliases)
440: {
441: /* do parsing & compression of addresses */
442: while (*p != '\0')
443: {
444: extern char *DelimChar;
445:
446: while (isspace(*p) || *p == ',')
447: p++;
448: if (*p == '\0')
449: break;
450: if (parseaddr(p, &bl, -1, ',') == NULL)
451: usrerr("%s... bad address", p);
452: p = DelimChar;
453: }
454: }
455: else
456: {
457: p = &p[strlen(p)];
458: if (p[-1] == '\n')
459: *--p = '\0';
460: }
461:
462: /* see if there should be a continuation line */
463: c = fgetc(af);
464: if (!feof(af))
465: (void) ungetc(c, af);
466: if (c != ' ' && c != '\t')
467: break;
468:
469: /* read continuation line */
470: if (fgets(p, sizeof line - (p - line), af) == NULL)
471: break;
472: LineNumber++;
473: }
474: if (al.q_mailer != LocalMailer)
475: {
476: syserr("cannot alias non-local names");
477: continue;
478: }
479:
480: /*
481: ** Insert alias into symbol table or DBM file
482: */
483:
484: lhssize = strlen(al.q_user) + 1;
485: rhssize = strlen(rhs) + 1;
486:
487: # ifdef DBM
488: if (init)
489: {
490: DATUM key, content;
491:
492: key.dsize = lhssize;
493: key.dptr = al.q_user;
494: content.dsize = rhssize;
495: content.dptr = rhs;
496: store(key, content);
497: }
498: else
499: # endif DBM
500: {
501: s = stab(al.q_user, ST_ALIAS, ST_ENTER);
502: s->s_alias = newstr(rhs);
503: }
504:
505: /* statistics */
506: naliases++;
507: bytes += lhssize + rhssize;
508: if (rhssize > longest)
509: longest = rhssize;
510: }
511:
512: # ifdef DBM
513: if (init)
514: {
515: /* add the distinquished alias "@" */
516: DATUM key;
517:
518: key.dsize = 2;
519: key.dptr = "@";
520: store(key, key);
521:
522: /* restore the old signal */
523: (void) signal(SIGINT, oldsigint);
524: }
525: # endif DBM
526:
527: /* closing the alias file drops the lock */
528: (void) fclose(af);
529: CurEnv->e_to = NULL;
530: FileName = NULL;
531: message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
532: naliases, longest, bytes);
533: # ifdef LOG
534: if (LogLevel >= 8)
535: syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
536: naliases, longest, bytes);
537: # endif LOG
538: }
539: /*
540: ** FORWARD -- Try to forward mail
541: **
542: ** This is similar but not identical to aliasing.
543: **
544: ** Parameters:
545: ** user -- the name of the user who's mail we would like
546: ** to forward to. It must have been verified --
547: ** i.e., the q_home field must have been filled
548: ** in.
549: ** sendq -- a pointer to the head of the send queue to
550: ** put this user's aliases in.
551: **
552: ** Returns:
553: ** none.
554: **
555: ** Side Effects:
556: ** New names are added to send queues.
557: */
558:
559: forward(user, sendq)
560: ADDRESS *user;
561: ADDRESS **sendq;
562: {
563: char buf[60];
564: extern bool safefile();
565:
566: if (tTd(27, 1))
567: printf("forward(%s)\n", user->q_paddr);
568:
569: if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
570: return;
571: if (user->q_home == NULL)
572: syserr("forward: no home");
573:
574: /* good address -- look for .forward file in home */
575: define('z', user->q_home, CurEnv);
576: expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
577: if (!safefile(buf, user->q_uid, S_IREAD))
578: return;
579:
580: /* we do have an address to forward to -- do it */
581: include(buf, "forwarding", user, sendq);
582: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.