|
|
1.1 root 1: # include <pwd.h>
2: # include <sys/types.h>
3: # include <sys/stat.h>
4: # include <signal.h>
5: # include "sendmail.h"
6:
7: # ifdef DBM
8: SCCSID(@(#)alias.c 4.1 7/25/83 (with DBM));
9: # else DBM
10: SCCSID(@(#)alias.c 4.1 7/25/83 (without DBM));
11: # endif DBM
12:
13: /*
14: ** ALIAS -- Compute aliases.
15: **
16: ** Scans the alias file for an alias for the given address.
17: ** If found, it arranges to deliver to the alias list instead.
18: ** Uses libdbm database if -DDBM.
19: **
20: ** Parameters:
21: ** a -- address to alias.
22: ** sendq -- a pointer to the head of the send queue
23: ** to put the aliases in.
24: **
25: ** Returns:
26: ** none
27: **
28: ** Side Effects:
29: ** Aliases found are expanded.
30: **
31: ** Notes:
32: ** If NoAlias (the "-n" flag) is set, no aliasing is
33: ** done.
34: **
35: ** Deficiencies:
36: ** It should complain about names that are aliased to
37: ** nothing.
38: */
39:
40:
41: #ifdef DBM
42: typedef struct
43: {
44: char *dptr;
45: int dsize;
46: } DATUM;
47: extern DATUM fetch();
48: #endif DBM
49:
50: alias(a, sendq)
51: register ADDRESS *a;
52: ADDRESS **sendq;
53: {
54: register char *p;
55: extern char *aliaslookup();
56:
57: if (NoAlias)
58: return;
59: # ifdef DEBUG
60: if (tTd(27, 1))
61: printf("alias(%s)\n", a->q_paddr);
62: # endif
63:
64: /* don't realias already aliased names */
65: if (bitset(QDONTSEND, a->q_flags))
66: return;
67:
68: CurEnv->e_to = a->q_paddr;
69:
70: /*
71: ** Look up this name
72: */
73:
74: p = aliaslookup(a->q_user);
75: if (p == NULL)
76: return;
77:
78: /*
79: ** Match on Alias.
80: ** Deliver to the target list.
81: */
82:
83: # ifdef DEBUG
84: if (tTd(27, 1))
85: printf("%s (%s, %s) aliased to %s\n",
86: a->q_paddr, a->q_host, a->q_user, p);
87: # endif
88: message(Arpa_Info, "aliased to %s", p);
89: AliasLevel++;
90: sendtolist(p, a, sendq);
91: AliasLevel--;
92: }
93: /*
94: ** ALIASLOOKUP -- look up a name in the alias file.
95: **
96: ** Parameters:
97: ** name -- the name to look up.
98: **
99: ** Returns:
100: ** the value of name.
101: ** NULL if unknown.
102: **
103: ** Side Effects:
104: ** none.
105: **
106: ** Warnings:
107: ** The return value will be trashed across calls.
108: */
109:
110: char *
111: aliaslookup(name)
112: char *name;
113: {
114: # ifdef DBM
115: DATUM rhs, lhs;
116:
117: /* create a key for fetch */
118: lhs.dptr = name;
119: lhs.dsize = strlen(name) + 1;
120: rhs = fetch(lhs);
121: return (rhs.dptr);
122: # else DBM
123: register STAB *s;
124:
125: s = stab(name, ST_ALIAS, ST_FIND);
126: if (s == NULL)
127: return (NULL);
128: return (s->s_alias);
129: # endif DBM
130: }
131: /*
132: ** INITALIASES -- initialize for aliasing
133: **
134: ** Very different depending on whether we are running DBM or not.
135: **
136: ** Parameters:
137: ** aliasfile -- location of aliases.
138: ** init -- if set and if DBM, initialize the DBM files.
139: **
140: ** Returns:
141: ** none.
142: **
143: ** Side Effects:
144: ** initializes aliases:
145: ** if DBM: opens the database.
146: ** if ~DBM: reads the aliases into the symbol table.
147: */
148:
149: # define DBMMODE 0666
150:
151: initaliases(aliasfile, init)
152: char *aliasfile;
153: bool init;
154: {
155: #ifdef DBM
156: int atcnt;
157: char buf[MAXNAME];
158: time_t modtime;
159: int (*oldsigint)();
160: #endif DBM
161: struct stat stb;
162:
163: if (stat(aliasfile, &stb) < 0)
164: {
165: NoAlias = TRUE;
166: errno = 0;
167: return;
168: }
169:
170: # ifdef DBM
171: /*
172: ** Check to see that the alias file is complete.
173: ** If not, we will assume that someone died, and it is up
174: ** to us to rebuild it.
175: */
176:
177: dbminit(aliasfile);
178: atcnt = 10;
179: while (SafeAlias && !init && atcnt-- >= 0 && aliaslookup("@") == NULL)
180: sleep(30);
181:
182: /*
183: ** See if the DBM version of the file is out of date with
184: ** the text version. If so, go into 'init' mode automatically.
185: ** This only happens if our effective userid owns the DBM
186: ** version or if the mode of the database is 666 -- this
187: ** is an attempt to avoid protection problems. Note the
188: ** unpalatable hack to see if the stat succeeded.
189: */
190:
191: modtime = stb.st_mtime;
192: (void) strcpy(buf, aliasfile);
193: (void) strcat(buf, ".pag");
194: stb.st_ino = 0;
195: if (!init && (atcnt < 0 || stat(buf, &stb) < 0 || stb.st_mtime < modtime))
196: {
197: errno = 0;
198: if (AutoRebuild && stb.st_ino != 0 &&
199: ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid()))
200: {
201: init = TRUE;
202: message(Arpa_Info, "rebuilding alias database");
203: }
204: else
205: {
206: bool oldverb = Verbose;
207:
208: Verbose = TRUE;
209: message(Arpa_Info, "Warning: alias database out of date");
210: Verbose = oldverb;
211: }
212: }
213:
214: /*
215: ** If initializing, create the new files.
216: ** We should lock the alias file here to prevent other
217: ** instantiations of sendmail from reading an incomplete
218: ** file -- or worse yet, doing a concurrent initialize.
219: */
220:
221: if (init)
222: {
223: oldsigint = signal(SIGINT, SIG_IGN);
224: (void) strcpy(buf, aliasfile);
225: (void) strcat(buf, ".dir");
226: if (close(creat(buf, DBMMODE)) < 0)
227: {
228: syserr("cannot make %s", buf);
229: (void) signal(SIGINT, oldsigint);
230: return;
231: }
232: (void) strcpy(buf, aliasfile);
233: (void) strcat(buf, ".pag");
234: if (close(creat(buf, DBMMODE)) < 0)
235: {
236: syserr("cannot make %s", buf);
237: (void) signal(SIGINT, oldsigint);
238: return;
239: }
240: }
241:
242: /*
243: ** If necessary, load the DBM file.
244: ** If running without DBM, load the symbol table.
245: ** After loading the DBM file, add the distinquished alias "@".
246: */
247:
248: if (init)
249: {
250: DATUM key;
251:
252: readaliases(aliasfile, TRUE);
253: key.dsize = 2;
254: key.dptr = "@";
255: store(key, key);
256: (void) signal(SIGINT, oldsigint);
257: }
258: # else DBM
259: readaliases(aliasfile, init);
260: # endif DBM
261: }
262: /*
263: ** READALIASES -- read and process the alias file.
264: **
265: ** This routine implements the part of initaliases that occurs
266: ** when we are not going to use the DBM stuff.
267: **
268: ** Parameters:
269: ** aliasfile -- the pathname of the alias file master.
270: ** init -- if set, initialize the DBM stuff.
271: **
272: ** Returns:
273: ** none.
274: **
275: ** Side Effects:
276: ** Reads aliasfile into the symbol table.
277: ** Optionally, builds the .dir & .pag files.
278: */
279:
280: static
281: readaliases(aliasfile, init)
282: char *aliasfile;
283: bool init;
284: {
285: register char *p;
286: char *p2;
287: char *rhs;
288: bool skipping;
289: int naliases, bytes, longest;
290: FILE *af;
291: ADDRESS al, bl;
292: register STAB *s;
293: char line[BUFSIZ];
294:
295: if ((af = fopen(aliasfile, "r")) == NULL)
296: {
297: # ifdef DEBUG
298: if (tTd(27, 1))
299: printf("Can't open %s\n", aliasfile);
300: # endif
301: errno = 0;
302: NoAlias++;
303: return;
304: }
305:
306: /*
307: ** Read and interpret lines
308: */
309:
310: FileName = aliasfile;
311: LineNumber = 0;
312: naliases = bytes = longest = 0;
313: skipping = FALSE;
314: while (fgets(line, sizeof (line), af) != NULL)
315: {
316: int lhssize, rhssize;
317:
318: LineNumber++;
319: switch (line[0])
320: {
321: case '#':
322: case '\n':
323: case '\0':
324: skipping = FALSE;
325: continue;
326:
327: case ' ':
328: case '\t':
329: if (!skipping)
330: syserr("Non-continuation line starts with space");
331: skipping = TRUE;
332: continue;
333: }
334: skipping = FALSE;
335:
336: /*
337: ** Process the LHS
338: ** Find the final colon, and parse the address.
339: ** It should resolve to a local name -- this will
340: ** be checked later (we want to optionally do
341: ** parsing of the RHS first to maximize error
342: ** detection).
343: */
344:
345: for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
346: continue;
347: if (*p++ != ':')
348: {
349: syserr("missing colon");
350: continue;
351: }
352: if (parseaddr(line, &al, 1, ':') == NULL)
353: {
354: syserr("illegal alias name");
355: continue;
356: }
357:
358: /*
359: ** Process the RHS.
360: ** 'al' is the internal form of the LHS address.
361: ** 'p' points to the text of the RHS.
362: */
363:
364: rhs = p;
365: for (;;)
366: {
367: register char c;
368:
369: if (init)
370: {
371: /* do parsing & compression of addresses */
372: c = *p;
373: while (c != '\0')
374: {
375: p2 = p;
376: while (*p != '\n' && *p != ',' && *p != '\0')
377: p++;
378: c = *p;
379: *p++ = '\0';
380: if (c == '\n')
381: c = '\0';
382: if (*p2 == '\0')
383: {
384: p[-1] = c;
385: continue;
386: }
387: (void) parseaddr(p2, &bl, -1, ',');
388: p[-1] = c;
389: while (isspace(*p))
390: p++;
391: }
392: }
393: else
394: p = &p[strlen(p)];
395:
396: /* see if there should be a continuation line */
397: c = fgetc(af);
398: if (!feof(af))
399: (void) ungetc(c, af);
400: if (c != ' ' && c != '\t')
401: break;
402:
403: /* read continuation line */
404: p--;
405: if (fgets(p, sizeof line - (p - line), af) == NULL)
406: break;
407: LineNumber++;
408: }
409: if (al.q_mailer != LocalMailer)
410: {
411: syserr("cannot alias non-local names");
412: continue;
413: }
414:
415: /*
416: ** Insert alias into symbol table or DBM file
417: */
418:
419: lhssize = strlen(al.q_user) + 1;
420: rhssize = strlen(rhs) + 1;
421:
422: # ifdef DBM
423: if (init)
424: {
425: DATUM key, content;
426:
427: key.dsize = lhssize;
428: key.dptr = al.q_user;
429: content.dsize = rhssize;
430: content.dptr = rhs;
431: store(key, content);
432: }
433: else
434: # endif DBM
435: {
436: s = stab(al.q_user, ST_ALIAS, ST_ENTER);
437: s->s_alias = newstr(rhs);
438: }
439:
440: /* statistics */
441: naliases++;
442: bytes += lhssize + rhssize;
443: if (rhssize > longest)
444: longest = rhssize;
445: }
446: (void) fclose(af);
447: CurEnv->e_to = NULL;
448: FileName = NULL;
449: message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
450: naliases, longest, bytes);
451: }
452: /*
453: ** FORWARD -- Try to forward mail
454: **
455: ** This is similar but not identical to aliasing.
456: **
457: ** Parameters:
458: ** user -- the name of the user who's mail we would like
459: ** to forward to. It must have been verified --
460: ** i.e., the q_home field must have been filled
461: ** in.
462: ** sendq -- a pointer to the head of the send queue to
463: ** put this user's aliases in.
464: **
465: ** Returns:
466: ** none.
467: **
468: ** Side Effects:
469: ** New names are added to send queues.
470: */
471:
472: forward(user, sendq)
473: ADDRESS *user;
474: ADDRESS **sendq;
475: {
476: char buf[60];
477: extern bool safefile();
478:
479: # ifdef DEBUG
480: if (tTd(27, 1))
481: printf("forward(%s)\n", user->q_paddr);
482: # endif DEBUG
483:
484: if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
485: return;
486: # ifdef DEBUG
487: if (user->q_home == NULL)
488: syserr("forward: no home");
489: # endif DEBUG
490:
491: /* good address -- look for .forward file in home */
492: define('z', user->q_home, CurEnv);
493: expand("$z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
494: if (!safefile(buf, user->q_uid, S_IREAD))
495: return;
496:
497: /* we do have an address to forward to -- do it */
498: include(buf, "forwarding", user, sendq);
499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.