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.12	08/10/81	(with DBM)";
8 # else DBM
9 static char SccsId[] = "@(#)alias.c	3.12	08/10/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("050", "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 **
123 **	Returns:
124 **		none.
125 **
126 **	Side Effects:
127 **		initializes aliases:
128 **		if DBM:  opens the database.
129 **		if ~DBM: reads the aliases into the symbol table.
130 */
131 
132 initaliases(aliasfile)
133 	char *aliasfile;
134 {
135 # ifdef DBM
136 	dbminit(aliasfile);
137 # else DBM
138 	char line[BUFSIZ];
139 	register char *p;
140 	char *p2;
141 	char *rhs;
142 	bool skipping;
143 	ADDRESS al, bl;
144 	FILE *af;
145 	int lineno;
146 	register STAB *s;
147 
148 	if ((af = fopen(aliasfile, "r")) == NULL)
149 	{
150 # ifdef DEBUG
151 		if (Debug)
152 			printf("Can't open %s\n", aliasfile);
153 # endif
154 		errno = 0;
155 		NoAlias++;
156 		return;
157 	}
158 	/* read and interpret lines */
159 	lineno = 0;
160 	skipping = FALSE;
161 	while (fgets(line, sizeof (line), af) != NULL)
162 	{
163 		lineno++;
164 		switch (line[0])
165 		{
166 		  case '#':
167 		  case '\n':
168 		  case '\0':
169 			skipping = FALSE;
170 			continue;
171 
172 		  case ' ':
173 		  case '\t':
174 			if (!skipping)
175 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
176 			skipping = TRUE;
177 			continue;
178 		}
179 		skipping = FALSE;
180 
181 		/* process the LHS */
182 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
183 			continue;
184 		if (*p == '\0' || *p == '\n')
185 		{
186 		 syntaxerr:
187 			syserr("aliases: %d: missing colon", lineno);
188 			continue;
189 		}
190 		*p++ = '\0';
191 		if (parse(line, &al, 1) == NULL)
192 		{
193 			*--p = ':';
194 			goto syntaxerr;
195 		}
196 		rhs = p;
197 		for (;;)
198 		{
199 			register char c;
200 
201 # ifdef SECURE
202 			/* do parsing & compression of addresses */
203 			c = *p;
204 			while (c != '\0')
205 			{
206 				p2 = p;
207 				while (*p != '\n' && *p != ',' && *p != '\0')
208 					p++;
209 				c = *p;
210 				*p++ = '\0';
211 				if (*p2 == '\0')
212 				{
213 					p[-1] = c;
214 					continue;
215 				}
216 				parse(p2, &bl, -1);
217 				p[-1] = c;
218 				while (isspace(*p))
219 					p++;
220 			}
221 # else SECURE
222 			p = &p[strlen(p)];
223 # endif SECURE
224 
225 			/* see if there should be a continuation line */
226 			c = fgetc(af);
227 			if (!feof(af))
228 				ungetc(c, af);
229 			if (c != ' ' && c != '\t')
230 				break;
231 
232 			/* read continuation line */
233 			p--;
234 			if (fgets(p, sizeof line - (p - line), af) == NULL)
235 				break;
236 			lineno++;
237 		}
238 		if (al.q_mailer != M_LOCAL)
239 		{
240 			syserr("aliases: %d: cannot alias non-local names", lineno);
241 			continue;
242 		}
243 		s = stab(al.q_user, ST_ALIAS, ST_ENTER);
244 		s->s_alias = newstr(rhs);
245 	}
246 	(void) fclose(af);
247 # endif DBM
248 }
249 /*
250 **  FORWARD -- Try to forward mail
251 **
252 **	This is similar but not identical to aliasing.
253 **
254 **	Parameters:
255 **		user -- the name of the user who's mail we
256 **			would like to forward to.
257 **
258 **	Returns:
259 **		none.
260 **
261 **	Side Effects:
262 **		New names are added to send queues.
263 **		Sets the QDONTSEND bit in addresses that are forwarded.
264 */
265 
266 forward(user)
267 	ADDRESS *user;
268 {
269 	char buf[60];
270 	register FILE *fp;
271 	register char *p;
272 
273 # ifdef DEBUG
274 	if (Debug)
275 		printf("forward(%s)\n", user->q_paddr);
276 # endif DEBUG
277 
278 	if (user->q_mailer != M_LOCAL || bitset(QBADADDR, user->q_flags))
279 		return;
280 
281 	/* good address -- look for .forward file in home */
282 	define('z', user->q_home);
283 	(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
284 	fp = fopen(buf, "r");
285 	if (fp == NULL)
286 		return;
287 
288 	/* we do have an address to forward to -- do it */
289 	user->q_flags |= QDONTSEND;
290 	(void) fgets(buf, sizeof buf, fp);
291 	if ((p = index(buf, '\n')) != NULL)
292 		*p = '\0';
293 	(void) fclose(fp);
294 	if (buf[0] == '\0')
295 		return;
296 	if (Verbose)
297 		message("050", "forwarded to %s", buf);
298 	AliasLevel++;
299 	sendto(buf, 1);
300 	AliasLevel--;
301 	return;
302 }
303