1 # include "sendmail.h"
2 
3 static char SccsId[] = "@(#)readcf.c	3.12	08/23/81";
4 
5 /*
6 **  READCF -- read control file.
7 **
8 **	This routine reads the control file and builds the internal
9 **	form.
10 **
11 **	Parameters:
12 **		cfname -- control file name.
13 **		safe -- set if this is a system configuration file.
14 **			Non-system configuration files can not do
15 **			certain things (e.g., leave the SUID bit on
16 **			when executing mailers).
17 **
18 **	Returns:
19 **		none.
20 **
21 **	Side Effects:
22 **		Builds several internal tables.
23 */
24 
25 struct rewrite	*RewriteRules[10];
26 
27 
28 readcf(cfname, safe)
29 	char *cfname;
30 	bool safe;
31 {
32 	FILE *cf;
33 	char buf[MAXLINE];
34 	register char *p;
35 	struct rewrite *rwp = NULL;
36 	extern char **prescan();
37 	extern char **copyplist();
38 	int class;
39 	int ruleset = 0;
40 
41 	cf = fopen(cfname, "r");
42 	if (cf == NULL)
43 	{
44 		syserr("cannot open %s", cfname);
45 		exit(EX_OSFILE);
46 	}
47 
48 	while (fgets(buf, sizeof buf, cf) != NULL)
49 	{
50 		p = rindex(buf, '\n');
51 		if (p != NULL)
52 			*p = '\0';
53 
54 		switch (buf[0])
55 		{
56 		  case '\n':
57 		  case '\0':
58 		  case ' ':
59 		  case '\t':
60 		  case '#':		/* comment */
61 			break;
62 
63 		  case 'R':		/* rewriting rule */
64 			for (p = &buf[1]; *p != '\0' && *p != '\t'; p++)
65 				continue;
66 
67 			if (*p == '\0')
68 				syserr("invalid rewrite line \"%s\"", buf);
69 			else
70 			{
71 				if (rwp == NULL)
72 				{
73 					RewriteRules[ruleset] = rwp =
74 						(struct rewrite *) xalloc(sizeof *rwp);
75 				}
76 				else
77 				{
78 					rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
79 					rwp = rwp->r_next;
80 				}
81 				rwp->r_next = NULL;
82 
83 				rwp->r_lhs = prescan(&buf[1], '\t');
84 				if (rwp->r_lhs != NULL)
85 					rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
86 				while (*p == '\t')
87 					p++;
88 				rwp->r_rhs = prescan(p, '\t');
89 				if (rwp->r_rhs != NULL)
90 					rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
91 			}
92 			break;
93 
94 		  case 'S':		/* select rewriting set */
95 			ruleset = atoi(&buf[1]);
96 			rwp = NULL;
97 			break;
98 
99 		  case 'D':		/* macro definition */
100 			define(buf[1], newstr(&buf[2]));
101 			break;
102 
103 		  case 'H':		/* required header line */
104 			(void) chompheader(&buf[1], TRUE);
105 			break;
106 
107 		  case 'C':		/* word class */
108 			class = buf[1];
109 			if (!isalpha(class))
110 				goto badline;
111 			if (isupper(class))
112 				class -= 'A';
113 			else
114 				class -= 'a';
115 
116 			/* scan the list of words and set class 'i' for all */
117 			for (p = &buf[2]; *p != '\0'; )
118 			{
119 				register char *wd;
120 				char delim;
121 				register STAB *s;
122 
123 				while (*p != '\0' && isspace(*p))
124 					p++;
125 				wd = p;
126 				while (*p != '\0' && !isspace(*p))
127 					p++;
128 				delim = *p;
129 				*p = '\0';
130 				if (wd[0] != '\0')
131 				{
132 					s = stab(wd, ST_CLASS, ST_ENTER);
133 					s->s_class |= 1 << class;
134 				}
135 				*p = delim;
136 			}
137 			break;
138 
139 		  case 'M':		/* define mailer */
140 			makemailer(&buf[1], safe);
141 			break;
142 
143 		  default:
144 		  badline:
145 			syserr("unknown control line \"%s\"", buf);
146 		}
147 	}
148 }
149 /*
150 **  MAKEMAILER -- define a new mailer.
151 **
152 **	Parameters:
153 **		line -- description of mailer.  This is in tokens
154 **			separated by white space.  The fields are:
155 **			* the name of the mailer, as refered to
156 **			  in the rewriting rules.
157 **			* the pathname of the program to fork to
158 **			  execute it.
159 **			* the options needed by this program.
160 **			* the macro string needed to translate
161 **			  a local "from" name to one that can be
162 **			  returned to this machine.
163 **			* the argument vector (a series of parameters).
164 **		safe -- set if this is a safe configuration file.
165 **
166 **	Returns:
167 **		none.
168 **
169 **	Side Effects:
170 **		enters the mailer into the mailer table.
171 */
172 
173 # define SETWORD \
174 		{ \
175 			while (*p != '\0' && isspace(*p)) \
176 				p++; \
177 			q = p; \
178 			while (*p != '\0' && !isspace(*p)) \
179 				p++; \
180 			if (*p != '\0') \
181 				*p++ = '\0'; \
182 		}
183 
184 makemailer(line, safe)
185 	char *line;
186 	bool safe;
187 {
188 	register char *p;
189 	register char *q;
190 	char *mname;
191 	char *mpath;
192 	int mopts;
193 	char *mfrom;
194 	register struct mailer *m;
195 	char *margv[MAXPV + 1];
196 	register int i;
197 	extern int NextMailer;
198 
199 	if (NextMailer >= MAXMAILERS)
200 	{
201 		syserr("Too many mailers defined");
202 		return;
203 	}
204 
205 	/* collect initial information */
206 	p = line;
207 	SETWORD;
208 	mname = q;
209 	SETWORD;
210 	mpath = q;
211 	SETWORD;
212 	mopts = crackopts(q);
213 	if (!safe)
214 		mopts &= ~M_RESTR;
215 	SETWORD;
216 	mfrom = q;
217 
218 	if (*p == '\0')
219 	{
220 		syserr("invalid M line in configuration file");
221 		return;
222 	}
223 
224 	/* allocate a mailer */
225 	m = (struct mailer *) xalloc(sizeof *m);
226 	m->m_name = newstr(mname);
227 	m->m_mailer = newstr(mpath);
228 	m->m_flags = mopts;
229 	m->m_from = newstr(mfrom);
230 	m->m_badstat = EX_UNAVAILABLE;
231 	m->m_sendq = NULL;
232 	Mailer[NextMailer++] = m;
233 
234 	/* collect the argument vector */
235 	for (i = 0; i < MAXPV - 1 && *p != '\0'; i++)
236 	{
237 		SETWORD;
238 		margv[i] = newstr(q);
239 	}
240 	margv[i++] = NULL;
241 
242 	/* save the argv */
243 	m->m_argv = (char **) xalloc(sizeof margv[0] * i);
244 	bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i);
245 }
246 /*
247 **  PRINTRULES -- print rewrite rules (for debugging)
248 **
249 **	Parameters:
250 **		none.
251 **
252 **	Returns:
253 **		none.
254 **
255 **	Side Effects:
256 **		prints rewrite rules.
257 */
258 
259 printrules()
260 {
261 	register struct rewrite *rwp;
262 	register int ruleset;
263 
264 	for (ruleset = 0; ruleset < 10; ruleset++)
265 	{
266 		if (RewriteRules[ruleset] == NULL)
267 			continue;
268 		printf("\n----Rule Set %d:\n", ruleset);
269 
270 		for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
271 		{
272 			register char **av;
273 
274 			printf("\n");
275 			for (av = rwp->r_lhs; *av != NULL; av++)
276 			{
277 				xputs(*av);
278 				putchar('_');
279 			}
280 			printf("\n\t");
281 			for (av = rwp->r_rhs; *av != NULL; av++)
282 			{
283 				xputs(*av);
284 				putchar('_');
285 			}
286 			printf("\n");
287 		}
288 	}
289 }
290 /*
291 **  CRACKOPTS -- crack mailer options
292 **
293 **	These options modify the functioning of the mailer
294 **	from the configuration table.
295 **
296 **	Parameters:
297 **		p -- pointer to vector of options.
298 **
299 **	Returns:
300 **		option list in binary.
301 **
302 **	Side Effects:
303 **		none.
304 */
305 
306 struct optlist
307 {
308 	char	opt_name;	/* external name of option */
309 	int	opt_value;	/* internal name of option */
310 };
311 struct optlist	OptList[] =
312 {
313 	'f',	M_FOPT,
314 	'r',	M_ROPT,
315 	'q',	M_QUIET,
316 	'S',	M_RESTR,
317 	'n',	M_NHDR,
318 	'l',	M_LOCAL,
319 	's',	M_STRIPQ,
320 	'm',	M_MUSER,
321 	'F',	M_NEEDFROM,
322 	'D',	M_NEEDDATE,
323 	'M',	M_MSGID,
324 	'u',	M_USR_UPPER,
325 	'h',	M_HST_UPPER,
326 	'x',	M_FULLNAME,
327 	'A',	M_ARPAFMT,
328 	0,	0
329 };
330 
331 crackopts(p)
332 	register char *p;
333 {
334 	register struct optlist *o;
335 	register int opts = 0;
336 
337 	while (*p != '\0')
338 	{
339 		for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++)
340 			continue;
341 		if (o->opt_name == '\0')
342 			syserr("bad mailer option %c", *p);
343 		opts |= o->opt_value;
344 		p++;
345 	}
346 	return (opts);
347 }
348