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