|
|
1.1 root 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:
11: # include <pwd.h>
12: # include <sys/types.h>
13: # include <sys/stat.h>
14: # include <signal.h>
15: # include <errno.h>
16: # include "sendmail.h"
17: # ifdef FLOCK
18: # include <sys/file.h>
19: # endif FLOCK
20:
21: #ifndef lint
22: # ifdef DBM
23: static char SccsId[] = "@(#)alias.c 5.13 (Berkeley) 4/17/86 (with DBM)";
24: # else DBM
25: static char SccsId[] = "@(#)alias.c 5.13 (Berkeley) 4/17/86 (without DBM)";
26: # endif DBM
27: #endif not lint
28:
29:
30: /*
31: ** ALIAS -- Compute aliases.
32: **
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.
36: **
37: ** Parameters:
38: ** a -- address to alias.
39: ** sendq -- a pointer to the head of the send queue
40: ** to put the aliases in.
41: **
42: ** Returns:
43: ** none
44: **
45: ** Side Effects:
46: ** Aliases found are expanded.
47: **
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.
55: */
56:
57:
58: #ifdef DBM
59: typedef struct
60: {
61: char *dptr;
62: int dsize;
63: } DATUM;
64: extern DATUM fetch();
65: #endif DBM
66:
67: alias(a, sendq)
68: register ADDRESS *a;
69: ADDRESS **sendq;
70: {
71: register char *p;
72: extern char *aliaslookup();
73:
74: # ifdef DEBUG
75: if (tTd(27, 1))
76: printf("alias(%s)\n", a->q_paddr);
77: # endif
78:
79: /* don't realias already aliased names */
80: if (bitset(QDONTSEND, a->q_flags))
81: return;
82:
83: CurEnv->e_to = a->q_paddr;
84:
85: /*
86: ** Look up this name
87: */
88:
89: if (NoAlias)
90: p = NULL;
91: else
92: p = aliaslookup(a->q_user);
93: if (p == NULL)
94: return;
95:
96: /*
97: ** Match on Alias.
98: ** Deliver to the target list.
99: */
100:
101: # ifdef DEBUG
102: if (tTd(27, 1))
103: printf("%s (%s, %s) aliased to %s\n",
104: a->q_paddr, a->q_host, a->q_user, p);
105: # endif
106: message(Arpa_Info, "aliased to %s", p);
107: AliasLevel++;
108: sendtolist(p, a, sendq);
109: AliasLevel--;
110: }
111: /*
112: ** ALIASLOOKUP -- look up a name in the alias file.
113: **
114: ** Parameters:
115: ** name -- the name to look up.
116: **
117: ** Returns:
118: ** the value of name.
119: ** NULL if unknown.
120: **
121: ** Side Effects:
122: ** none.
123: **
124: ** Warnings:
125: ** The return value will be trashed across calls.
126: */
127:
128: char *
129: aliaslookup(name)
130: char *name;
131: {
132: # ifdef DBM
133: DATUM rhs, lhs;
134:
135: /* create a key for fetch */
136: lhs.dptr = name;
137: lhs.dsize = strlen(name) + 1;
138: rhs = fetch(lhs);
139: return (rhs.dptr);
140: # else DBM
141: register STAB *s;
142:
143: s = stab(name, ST_ALIAS, ST_FIND);
144: if (s == NULL)
145: return (NULL);
146: return (s->s_alias);
147: # endif DBM
148: }
149: /*
150: ** INITALIASES -- initialize for aliasing
151: **
152: ** Very different depending on whether we are running DBM or not.
153: **
154: ** Parameters:
155: ** aliasfile -- location of aliases.
156: ** init -- if set and if DBM, initialize the DBM files.
157: **
158: ** Returns:
159: ** none.
160: **
161: ** Side Effects:
162: ** initializes aliases:
163: ** if DBM: opens the database.
164: ** if ~DBM: reads the aliases into the symbol table.
165: */
166:
167: # define DBMMODE 0666
168:
169: initaliases(aliasfile, init)
170: char *aliasfile;
171: bool init;
172: {
173: #ifdef DBM
174: int atcnt;
175: time_t modtime;
176: bool automatic = FALSE;
177: char buf[MAXNAME];
178: #endif DBM
179: struct stat stb;
180: static bool initialized = FALSE;
181:
182: if (initialized)
183: return;
184: initialized = TRUE;
185:
186: if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
187: {
188: if (aliasfile != NULL && init)
189: syserr("Cannot open %s", aliasfile);
190: NoAlias = TRUE;
191: errno = 0;
192: return;
193: }
194:
195: # ifdef DBM
196: /*
197: ** Check to see that the alias file is complete.
198: ** If not, we will assume that someone died, and it is up
199: ** to us to rebuild it.
200: */
201:
202: if (!init)
203: dbminit(aliasfile);
204: atcnt = SafeAlias * 2;
205: if (atcnt > 0)
206: {
207: while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
208: {
209: /*
210: ** Reinitialize alias file in case the new
211: ** one is mv'ed in instead of cp'ed in.
212: **
213: ** Only works with new DBM -- old one will
214: ** just consume file descriptors forever.
215: ** If you have a dbmclose() it can be
216: ** added before the sleep(30).
217: */
218:
219: sleep(30);
220: # ifdef NDBM
221: dbminit(aliasfile);
222: # endif NDBM
223: }
224: }
225: else
226: atcnt = 1;
227:
228: /*
229: ** See if the DBM version of the file is out of date with
230: ** the text version. If so, go into 'init' mode automatically.
231: ** This only happens if our effective userid owns the DBM
232: ** version or if the mode of the database is 666 -- this
233: ** is an attempt to avoid protection problems. Note the
234: ** unpalatable hack to see if the stat succeeded.
235: */
236:
237: modtime = stb.st_mtime;
238: (void) strcpy(buf, aliasfile);
239: (void) strcat(buf, ".pag");
240: stb.st_ino = 0;
241: if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
242: {
243: errno = 0;
244: if (AutoRebuild && stb.st_ino != 0 &&
245: ((stb.st_mode & 0777) == 0666 || 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: int (*oldsigint)();
317: ADDRESS al, bl;
318: register STAB *s;
319: char line[BUFSIZ];
320:
321: if ((af = fopen(aliasfile, "r")) == NULL)
322: {
323: # ifdef DEBUG
324: if (tTd(27, 1))
325: printf("Can't open %s\n", aliasfile);
326: # endif
327: errno = 0;
328: NoAlias++;
329: return;
330: }
331:
332: # ifdef DBM
333: # ifdef FLOCK
334: /* see if someone else is rebuilding the alias file already */
335: if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
336: {
337: /* yes, they are -- wait until done and then return */
338: message(Arpa_Info, "Alias file is already being rebuilt");
339: if (OpMode != MD_INITALIAS)
340: {
341: /* wait for other rebuild to complete */
342: (void) flock(fileno(af), LOCK_EX);
343: }
344: (void) fclose(af);
345: errno = 0;
346: return;
347: }
348: # endif FLOCK
349: # endif DBM
350:
351: /*
352: ** If initializing, create the new DBM files.
353: */
354:
355: if (init)
356: {
357: oldsigint = signal(SIGINT, SIG_IGN);
358: (void) strcpy(line, aliasfile);
359: (void) strcat(line, ".dir");
360: if (close(creat(line, DBMMODE)) < 0)
361: {
362: syserr("cannot make %s", line);
363: (void) signal(SIGINT, oldsigint);
364: return;
365: }
366: (void) strcpy(line, aliasfile);
367: (void) strcat(line, ".pag");
368: if (close(creat(line, DBMMODE)) < 0)
369: {
370: syserr("cannot make %s", line);
371: (void) signal(SIGINT, oldsigint);
372: return;
373: }
374: dbminit(aliasfile);
375: }
376:
377: /*
378: ** Read and interpret lines
379: */
380:
381: FileName = aliasfile;
382: LineNumber = 0;
383: naliases = bytes = longest = 0;
384: skipping = FALSE;
385: while (fgets(line, sizeof (line), af) != NULL)
386: {
387: int lhssize, rhssize;
388:
389: LineNumber++;
390: p = index(line, '\n');
391: if (p != NULL)
392: *p = '\0';
393: switch (line[0])
394: {
395: case '#':
396: case '\0':
397: skipping = FALSE;
398: continue;
399:
400: case ' ':
401: case '\t':
402: if (!skipping)
403: syserr("Non-continuation line starts with space");
404: skipping = TRUE;
405: continue;
406: }
407: skipping = FALSE;
408:
409: /*
410: ** Process the LHS
411: ** Find the final colon, and parse the address.
412: ** It should resolve to a local name -- this will
413: ** be checked later (we want to optionally do
414: ** parsing of the RHS first to maximize error
415: ** detection).
416: */
417:
418: for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
419: continue;
420: if (*p++ != ':')
421: {
422: syserr("missing colon");
423: continue;
424: }
425: if (parseaddr(line, &al, 1, ':') == NULL)
426: {
427: syserr("illegal alias name");
428: continue;
429: }
430: loweraddr(&al);
431:
432: /*
433: ** Process the RHS.
434: ** 'al' is the internal form of the LHS address.
435: ** 'p' points to the text of the RHS.
436: */
437:
438: rhs = p;
439: for (;;)
440: {
441: register char c;
442:
443: if (init && CheckAliases)
444: {
445: /* do parsing & compression of addresses */
446: while (*p != '\0')
447: {
448: extern char *DelimChar;
449:
450: while (isspace(*p) || *p == ',')
451: p++;
452: if (*p == '\0')
453: break;
454: if (parseaddr(p, &bl, -1, ',') == NULL)
455: usrerr("%s... bad address", p);
456: p = DelimChar;
457: }
458: }
459: else
460: {
461: p = &p[strlen(p)];
462: if (p[-1] == '\n')
463: *--p = '\0';
464: }
465:
466: /* see if there should be a continuation line */
467: c = fgetc(af);
468: if (!feof(af))
469: (void) ungetc(c, af);
470: if (c != ' ' && c != '\t')
471: break;
472:
473: /* read continuation line */
474: if (fgets(p, sizeof line - (p - line), af) == NULL)
475: break;
476: LineNumber++;
477: }
478: if (al.q_mailer != LocalMailer)
479: {
480: syserr("cannot alias non-local names");
481: continue;
482: }
483:
484: /*
485: ** Insert alias into symbol table or DBM file
486: */
487:
488: lhssize = strlen(al.q_user) + 1;
489: rhssize = strlen(rhs) + 1;
490:
491: # ifdef DBM
492: if (init)
493: {
494: DATUM key, content;
495:
496: key.dsize = lhssize;
497: key.dptr = al.q_user;
498: content.dsize = rhssize;
499: content.dptr = rhs;
500: store(key, content);
501: }
502: else
503: # endif DBM
504: {
505: s = stab(al.q_user, ST_ALIAS, ST_ENTER);
506: s->s_alias = newstr(rhs);
507: }
508:
509: /* statistics */
510: naliases++;
511: bytes += lhssize + rhssize;
512: if (rhssize > longest)
513: longest = rhssize;
514: }
515:
516: # ifdef DBM
517: if (init)
518: {
519: /* add the distinquished alias "@" */
520: DATUM key;
521:
522: key.dsize = 2;
523: key.dptr = "@";
524: store(key, key);
525:
526: /* restore the old signal */
527: (void) signal(SIGINT, oldsigint);
528: }
529: # endif DBM
530:
531: /* closing the alias file drops the lock */
532: (void) fclose(af);
533: CurEnv->e_to = NULL;
534: FileName = NULL;
535: message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
536: naliases, longest, bytes);
537: # ifdef LOG
538: if (LogLevel >= 8)
539: syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
540: naliases, longest, bytes);
541: # endif LOG
542: }
543: /*
544: ** FORWARD -- Try to forward mail
545: **
546: ** This is similar but not identical to aliasing.
547: **
548: ** Parameters:
549: ** user -- the name of the user who's mail we would like
550: ** to forward to. It must have been verified --
551: ** i.e., the q_home field must have been filled
552: ** in.
553: ** sendq -- a pointer to the head of the send queue to
554: ** put this user's aliases in.
555: **
556: ** Returns:
557: ** none.
558: **
559: ** Side Effects:
560: ** New names are added to send queues.
561: */
562:
563: forward(user, sendq)
564: ADDRESS *user;
565: ADDRESS **sendq;
566: {
567: char buf[60];
568: extern bool safefile();
569:
570: # ifdef DEBUG
571: if (tTd(27, 1))
572: printf("forward(%s)\n", user->q_paddr);
573: # endif DEBUG
574:
575: if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
576: return;
577: # ifdef DEBUG
578: if (user->q_home == NULL)
579: syserr("forward: no home");
580: # endif DEBUG
581:
582: /* good address -- look for .forward file in home */
583: define('z', user->q_home, CurEnv);
584: expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
585: if (!safefile(buf, user->q_uid, S_IREAD))
586: return;
587:
588: /* we do have an address to forward to -- do it */
589: include(buf, "forwarding", user, sendq);
590: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.