1 # include <stdio.h>
2 # include <ctype.h>
3 # include <pwd.h>
4 # include "sendmail.h"
5 
6 static char SccsId[] = "@(#)alias.c	3.5	08/08/81";
7 
8 /*
9 **  ALIAS -- Compute aliases.
10 **
11 **	Scans the file ALIASFILE for a set of aliases.
12 **	If found, it arranges to deliver to them.  Uses libdbm
13 **	database if -DDBM.
14 **
15 **	Parameters:
16 **		none
17 **
18 **	Returns:
19 **		none
20 **
21 **	Side Effects:
22 **		Aliases found are expanded.
23 **
24 **	Defined Constants:
25 **		MAXRCRSN -- the maximum recursion depth.
26 **
27 **	Files:
28 **		ALIASFILE -- the mail aliases.  The format is
29 **			a series of lines of the form:
30 **				alias:name1,name2,name3,...
31 **			where 'alias' expands to all of
32 **			'name[i]'.  Continuations begin with
33 **			space or tab.
34 **		ALIASFILE.pag, ALIASFILE.dir: libdbm version
35 **			of alias file.  Keys are aliases, datums
36 **			(data?) are name1,name2, ...
37 **
38 **	Notes:
39 **		If NoAlias (the "-n" flag) is set, no aliasing is
40 **			done.
41 **
42 **	Deficiencies:
43 **		It should complain about names that are aliased to
44 **			nothing.
45 **		It is unsophisticated about line overflows.
46 */
47 
48 
49 # define MAXRCRSN	10
50 
51 #ifdef DBM
52 typedef struct
53 {
54 	char	*dptr;
55 	int dsize;
56 } datum;
57 datum lhs, rhs;
58 extern datum fetch();
59 #endif DBM
60 
61 alias()
62 {
63 	register ADDRESS *q;
64 	ADDRESS *q2;
65 	FILE *af;
66 	char line[MAXLINE+1];
67 	register char *p;
68 	extern int errno;
69 	bool didalias;
70 	bool gotmatch;
71 	auto ADDRESS al;
72 	extern bool sameaddr();
73 	extern ADDRESS *parse();
74 	int mno;
75 
76 	if (NoAlias)
77 		return;
78 # ifdef DEBUG
79 	if (Debug)
80 		printf("--- alias ---\n");
81 # endif
82 
83 	/* open alias file if not already open */
84 #ifndef DBM
85 # ifdef DEBUG
86 	if (Debug && (af = fopen("mailaliases", "r")) != NULL)
87 		printf(" [using local alias file]\n");
88 	else
89 # endif
90 	if ((af = fopen(ALIASFILE, "r")) == NULL)
91 	{
92 # ifdef DEBUG
93 		if (Debug)
94 			printf("Can't open %s\n", ALIASFILE);
95 # endif
96 		errno = 0;
97 		return;
98 	}
99 #else DBM
100 	dbminit(ALIASFILE);
101 #endif DBM
102 
103 #ifndef DBM
104 	/*
105 	**  Scan alias file.
106 	**	If we find any user that any line matches any user, we
107 	**	will send to the line rather than to the user.
108 	**
109 	**	We pass through the file several times.  Didalias tells
110 	**	us if we took some alias on this pass through the file;
111 	**	when it goes false at the top of the loop we don't have
112 	**	to scan any more.  Gotmatch tells the same thing, but
113 	**	on a line-by-line basis; it is used for processing
114 	**	continuation lines.
115 	*/
116 
117 	do
118 	{
119 		didalias = FALSE;
120 		gotmatch = FALSE;
121 		rewind(af);
122 		while (fgets(line, sizeof line, af) != NULL)
123 		{
124 			/* comments begin with `#' */
125 			if (line[0] == '#')
126 				continue;
127 
128 			/* check for continuation lines */
129 			if (isspace(line[0]))
130 			{
131 				if (gotmatch)
132 				{
133 					sendto(line, 1);
134 				}
135 				continue;
136 			}
137 			gotmatch = FALSE;
138 
139 			/*
140 			**  Check to see if this pseudonym exists.
141 			**	Turn the alias into canonical form.
142 			**	Then scan the send queue until you
143 			**	do (or do not) find that address.
144 			*/
145 
146 			/*  Get a canonical form for the alias. */
147 			for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
148 				continue;
149 			if (*p == '\0' || *p == '\n')
150 			{
151 			 syntaxerr:
152 				syserr("Bad alias line `%s'", line);
153 				continue;
154 			}
155 			*p++ = '\0';
156 			if (parse(line, &al, -1) == NULL)
157 			{
158 				*--p = ':';
159 				goto syntaxerr;
160 			}
161 
162 			/* if already queued up, don't realias */
163 			for (q = Mailer[al.q_mailer]->m_sendq; q != NULL; q = q->q_next)
164 			{
165 				if (sameaddr(&al, q, TRUE))
166 					break;
167 			}
168 			if (q == NULL || bitset(QDONTSEND, q->q_flags))
169 				continue;
170 
171 			/*
172 			**  Match on Alias.
173 			**	Deliver to the target list.
174 			**	Remove the alias from the send queue
175 			**	  and put it on the Alias queue.
176 			*/
177 
178 # ifdef DEBUG
179 			if (Debug)
180 				printf("%s (%s, %s) aliased to %s (%s,%s,%s)\n",
181 				    q->q_paddr, q->q_host, q->q_user,
182 				    p, al.q_paddr, al.q_host, al.q_user);
183 # endif
184 			if (Verbose)
185 				message("050", "aliased to %s", p);
186 			q->q_flags |= QDONTSEND;
187 			didalias++;
188 			gotmatch++;
189 			sendto(p, 1);
190 		}
191 	} while (didalias);
192 	fclose(af);
193 #else DBM
194 	/*
195 	**  Scan send queues
196 	**	We only have to do this once, since anything we alias
197 	**	to is being put at the end of the queue we are
198 	**	scanning.
199 	*/
200 
201 	for (mno = 0; Mailer[mno] != NULL; mno++)
202 	{
203 		for (q = Mailer[mno]->m_sendq; q != NULL; q = q->q_next)
204 		{
205 			To = q->q_paddr;
206 
207 			/* don't realias already aliased names */
208 			if (bitset(QDONTSEND, q->q_flags))
209 				continue;
210 
211 			/* only alias local users */
212 			if (q->q_mailer != 0)
213 				continue;
214 
215 			/* create a key for fetch */
216 			lhs.dptr = q->q_user;
217 			lhs.dsize = strlen(q->q_user) + 1;
218 			rhs = fetch(lhs);
219 
220 			/* find this alias? */
221 			p = rhs.dptr;
222 			if (p == NULL)
223 				continue;
224 
225 			/*
226 			**  Match on Alias.
227 			**	Deliver to the target list.
228 			**	Remove the alias from the send queue
229 			**	  and put it on the Alias queue.
230 			*/
231 
232 # ifdef DEBUG
233 			if (Debug)
234 				printf("%s (%s, %s) aliased to %s\n",
235 				    q->q_paddr, q->q_host, q->q_user, p);
236 # endif
237 			if (Verbose)
238 				message("050", "aliased to %s", p);
239 			q->q_flags |= QDONTSEND;
240 			sendto(p, 1);
241 		}
242 	}
243 #endif DBM
244 }
245 /*
246 **  FORWARD -- Try to forward mail
247 **
248 **	This is similar but not identical to aliasing.
249 **
250 **	Currently it is undefined, until the protocol for userinfo
251 **	databases is finalized.
252 **
253 **	Parameters:
254 **		user -- the name of the user who's mail we
255 **			would like to forward to.
256 **
257 **	Returns:
258 **		TRUE -- we have forwarded it somewhere.
259 **		FALSE -- not forwarded; go ahead & deliver.
260 **
261 **	Side Effects:
262 **		New names are added to send queues.
263 */
264 
265 bool
266 forward(user)
267 	ADDRESS *user;
268 {
269 	return (FALSE);
270 }
271