1 # include <stdio.h>
2 # include <ctype.h>
3 # include <pwd.h>
4 # include "sendmail.h"
5 
6 # ifdef DBM
7 static char SccsId[] = "@(#)alias.c	3.14	08/18/81	(with DBM)";
8 # else DBM
9 static char SccsId[] = "@(#)alias.c	3.14	08/18/81	(without DBM)";
10 # endif DBM
11 
12 /*
13 **  ALIAS -- Compute aliases.
14 **
15 **	Scans the file /usr/lib/aliases for a set of aliases.
16 **	If found, it arranges to deliver to them.  Uses libdbm
17 **	database if -DDBM.
18 **
19 **	Parameters:
20 **		a -- address to alias.
21 **
22 **	Returns:
23 **		none
24 **
25 **	Side Effects:
26 **		Aliases found are expanded.
27 **
28 **	Files:
29 **		/usr/lib/aliases -- the mail aliases.  The format is
30 **			a series of lines of the form:
31 **				alias:name1,name2,name3,...
32 **			where 'alias' expands to all of
33 **			'name[i]'.  Continuations begin with
34 **			space or tab.
35 **		/usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version
36 **			of alias file.  Keys are aliases, datums
37 **			(data?) are name1,name2, ...
38 **
39 **	Notes:
40 **		If NoAlias (the "-n" flag) is set, no aliasing is
41 **			done.
42 **
43 **	Deficiencies:
44 **		It should complain about names that are aliased to
45 **			nothing.
46 **		It is unsophisticated about line overflows.
47 */
48 
49 
50 #ifdef DBM
51 typedef struct
52 {
53 	char	*dptr;
54 	int	dsize;
55 } DATUM;
56 DATUM lhs, rhs;
57 extern DATUM fetch();
58 #endif DBM
59 
60 alias(a)
61 	register ADDRESS *a;
62 {
63 	register char *p;
64 # ifndef DBM
65 	register STAB *s;
66 # endif DBM
67 
68 	if (NoAlias)
69 		return;
70 # ifdef DEBUG
71 	if (Debug)
72 		printf("alias(%s)\n", a->q_paddr);
73 # endif
74 
75 	/* don't realias already aliased names */
76 	if (bitset(QDONTSEND, a->q_flags))
77 		return;
78 
79 	To = a->q_paddr;
80 
81 # ifdef DBM
82 	/* create a key for fetch */
83 	lhs.dptr = a->q_user;
84 	lhs.dsize = strlen(a->q_user) + 1;
85 	rhs = fetch(lhs);
86 
87 	/* find this alias? */
88 	p = rhs.dptr;
89 	if (p == NULL)
90 		return;
91 # else DBM
92 	s = stab(a->q_user, ST_ALIAS, ST_FIND);
93 	if (s == NULL)
94 		return;
95 	p = s->s_alias;
96 # endif DBM
97 
98 	/*
99 	**  Match on Alias.
100 	**	Deliver to the target list.
101 	*/
102 
103 # ifdef DEBUG
104 	if (Debug)
105 		printf("%s (%s, %s) aliased to %s\n",
106 		    a->q_paddr, a->q_host, a->q_user, p);
107 # endif
108 	if (Verbose)
109 		message(Arpa_Info, "aliased to %s", p);
110 	a->q_flags |= QDONTSEND;
111 	AliasLevel++;
112 	sendto(p, 1);
113 	AliasLevel--;
114 }
115 /*
116 **  INITALIASES -- initialize for aliasing
117 **
118 **	Very different depending on whether we are running DBM or not.
119 **
120 **	Parameters:
121 **		aliasfile -- location of aliases.
122 **		init -- if set and if DBM, initialize the DBM files.
123 **
124 **	Returns:
125 **		none.
126 **
127 **	Side Effects:
128 **		initializes aliases:
129 **		if DBM:  opens the database.
130 **		if ~DBM: reads the aliases into the symbol table.
131 */
132 
133 # define DBMMODE	0666
134 
135 initaliases(aliasfile, init)
136 	char *aliasfile;
137 	bool init;
138 {
139 # ifdef DBM
140 	if (init)
141 	{
142 		char buf[MAXNAME];
143 
144 		(void) strcpy(buf, aliasfile);
145 		(void) strcat(buf, ".dir");
146 		if (close(creat(buf, DBMMODE)) < 0)
147 		{
148 			syserr("cannot make %s", buf);
149 			return;
150 		}
151 		(void) strcpy(buf, aliasfile);
152 		(void) strcat(buf, ".pag");
153 		if (close(creat(buf, DBMMODE)) < 0)
154 		{
155 			syserr("cannot make %s", buf);
156 			return;
157 		}
158 	}
159 	dbminit(aliasfile);
160 	if (init)
161 		readaliases(aliasfile, TRUE);
162 # else DBM
163 	readaliases(aliasfile, init);
164 # endif DBM
165 }
166 /*
167 **  READALIASES -- read and process the alias file.
168 **
169 **	This routine implements the part of initaliases that occurs
170 **	when we are not going to use the DBM stuff.
171 **
172 **	Parameters:
173 **		aliasfile -- the pathname of the alias file master.
174 **		init -- if set, initialize the DBM stuff.
175 **
176 **	Returns:
177 **		none.
178 **
179 **	Side Effects:
180 **		Reads aliasfile into the symbol table.
181 **		Optionally, builds the .dir & .pag files.
182 */
183 
184 static
185 readaliases(aliasfile, init)
186 	char *aliasfile;
187 	bool init;
188 {
189 	char line[BUFSIZ];
190 	register char *p;
191 	char *p2;
192 	char *rhs;
193 	bool skipping;
194 	ADDRESS al, bl;
195 	FILE *af;
196 	int lineno;
197 	register STAB *s;
198 
199 	if ((af = fopen(aliasfile, "r")) == NULL)
200 	{
201 # ifdef DEBUG
202 		if (Debug)
203 			printf("Can't open %s\n", aliasfile);
204 # endif
205 		errno = 0;
206 		NoAlias++;
207 		return;
208 	}
209 	/* read and interpret lines */
210 	lineno = 0;
211 	skipping = FALSE;
212 	while (fgets(line, sizeof (line), af) != NULL)
213 	{
214 		lineno++;
215 		switch (line[0])
216 		{
217 		  case '#':
218 		  case '\n':
219 		  case '\0':
220 			skipping = FALSE;
221 			continue;
222 
223 		  case ' ':
224 		  case '\t':
225 			if (!skipping)
226 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
227 			skipping = TRUE;
228 			continue;
229 		}
230 		skipping = FALSE;
231 
232 		/* process the LHS */
233 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
234 			continue;
235 		if (*p == '\0' || *p == '\n')
236 		{
237 		 syntaxerr:
238 			syserr("aliases: %d: missing colon", lineno);
239 			continue;
240 		}
241 		*p++ = '\0';
242 		if (parse(line, &al, 1) == NULL)
243 		{
244 			*--p = ':';
245 			goto syntaxerr;
246 		}
247 		rhs = p;
248 		for (;;)
249 		{
250 			register char c;
251 
252 			if (init)
253 			{
254 				/* do parsing & compression of addresses */
255 				c = *p;
256 				while (c != '\0')
257 				{
258 					p2 = p;
259 					while (*p != '\n' && *p != ',' && *p != '\0')
260 						p++;
261 					c = *p;
262 					*p++ = '\0';
263 					if (*p2 == '\0')
264 					{
265 						p[-1] = c;
266 						continue;
267 					}
268 					parse(p2, &bl, -1);
269 					p[-1] = c;
270 					while (isspace(*p))
271 						p++;
272 				}
273 			}
274 			else
275 				p = &p[strlen(p)];
276 
277 			/* see if there should be a continuation line */
278 			c = fgetc(af);
279 			if (!feof(af))
280 				ungetc(c, af);
281 			if (c != ' ' && c != '\t')
282 				break;
283 
284 			/* read continuation line */
285 			p--;
286 			if (fgets(p, sizeof line - (p - line), af) == NULL)
287 				break;
288 			lineno++;
289 		}
290 		if (al.q_mailer != M_LOCAL)
291 		{
292 			syserr("aliases: %d: cannot alias non-local names", lineno);
293 			continue;
294 		}
295 # ifdef DBM
296 		if (init)
297 		{
298 			DATUM key, content;
299 
300 			key.dsize = strlen(al.q_user) + 1;
301 			key.dptr = al.q_user;
302 			content.dsize = strlen(rhs) + 1;
303 			content.dptr = rhs;
304 			store(key, content);
305 		}
306 		else
307 # endif DBM
308 		{
309 			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
310 			s->s_alias = newstr(rhs);
311 		}
312 	}
313 	(void) fclose(af);
314 }
315 /*
316 **  FORWARD -- Try to forward mail
317 **
318 **	This is similar but not identical to aliasing.
319 **
320 **	Parameters:
321 **		user -- the name of the user who's mail we
322 **			would like to forward to.
323 **
324 **	Returns:
325 **		none.
326 **
327 **	Side Effects:
328 **		New names are added to send queues.
329 **		Sets the QDONTSEND bit in addresses that are forwarded.
330 */
331 
332 forward(user)
333 	ADDRESS *user;
334 {
335 	char buf[60];
336 	register FILE *fp;
337 	register char *p;
338 
339 # ifdef DEBUG
340 	if (Debug)
341 		printf("forward(%s)\n", user->q_paddr);
342 # endif DEBUG
343 
344 	if (user->q_mailer != M_LOCAL || bitset(QBADADDR, user->q_flags))
345 		return;
346 
347 	/* good address -- look for .forward file in home */
348 	define('z', user->q_home);
349 	(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
350 	fp = fopen(buf, "r");
351 	if (fp == NULL)
352 		return;
353 
354 	/* we do have an address to forward to -- do it */
355 	user->q_flags |= QDONTSEND;
356 	(void) fgets(buf, sizeof buf, fp);
357 	if ((p = index(buf, '\n')) != NULL)
358 		*p = '\0';
359 	(void) fclose(fp);
360 	if (buf[0] == '\0')
361 		return;
362 	if (Verbose)
363 		message(Arpa_Info, "forwarded to %s", buf);
364 	AliasLevel++;
365 	sendto(buf, 1);
366 	AliasLevel--;
367 	return;
368 }
369