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