parms.c revision 128073
1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sbin/routed/parms.c 128073 2004-04-09 19:58:40Z markm $
30 */
31
32#include "defs.h"
33#include "pathnames.h"
34#include <sys/stat.h>
35
36#ifdef __NetBSD__
37__RCSID("$NetBSD$");
38#elif defined(__FreeBSD__)
39__RCSID("$FreeBSD: head/sbin/routed/parms.c 128073 2004-04-09 19:58:40Z markm $");
40#else
41__RCSID("$Revision: 2.26 $");
42#ident "$Revision: 2.26 $"
43#endif
44#ident "$FreeBSD: head/sbin/routed/parms.c 128073 2004-04-09 19:58:40Z markm $"
45
46
47struct parm *parms;
48struct intnet *intnets;
49struct r1net *r1nets;
50struct tgate *tgates;
51
52
53/* use configured parameters
54 */
55void
56get_parms(struct interface *ifp)
57{
58	static int warned_auth_in, warned_auth_out;
59	struct parm *parmp;
60	int i, num_passwds = 0;
61
62	/* get all relevant parameters
63	 */
64	for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
65		if (parmp->parm_name[0] == '\0'
66		    || !strcmp(ifp->int_name, parmp->parm_name)
67		    || (parmp->parm_name[0] == '\n'
68			&& on_net(ifp->int_addr,
69				  parmp->parm_net, parmp->parm_mask))) {
70
71			/* This group of parameters is relevant,
72			 * so get its settings
73			 */
74			ifp->int_state |= parmp->parm_int_state;
75			for (i = 0; i < MAX_AUTH_KEYS; i++) {
76				if (parmp->parm_auth[0].type == RIP_AUTH_NONE
77				    || num_passwds >= MAX_AUTH_KEYS)
78					break;
79				memcpy(&ifp->int_auth[num_passwds++],
80				       &parmp->parm_auth[i],
81				       sizeof(ifp->int_auth[0]));
82			}
83			if (parmp->parm_rdisc_pref != 0)
84				ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
85			if (parmp->parm_rdisc_int != 0)
86				ifp->int_rdisc_int = parmp->parm_rdisc_int;
87			if (parmp->parm_adj_inmetric != 0)
88			    ifp->int_adj_inmetric = parmp->parm_adj_inmetric;
89			if (parmp->parm_adj_outmetric != 0)
90			    ifp->int_adj_outmetric = parmp->parm_adj_outmetric;
91		}
92	}
93
94	/* Set general defaults.
95	 *
96	 * Default poor-man's router discovery to a metric that will
97	 * be heard by old versions of `routed`.  They ignored received
98	 * routes with metric 15.
99	 */
100	if ((ifp->int_state & IS_PM_RDISC)
101	    && ifp->int_d_metric == 0)
102		ifp->int_d_metric = FAKE_METRIC;
103
104	if (ifp->int_rdisc_int == 0)
105		ifp->int_rdisc_int = DefMaxAdvertiseInterval;
106
107	if (!(ifp->int_if_flags & IFF_MULTICAST)
108	    && !(ifp->int_state & IS_REMOTE))
109		ifp->int_state |= IS_BCAST_RDISC;
110
111	if (ifp->int_if_flags & IFF_POINTOPOINT) {
112		ifp->int_state |= IS_BCAST_RDISC;
113		/* By default, point-to-point links should be passive
114		 * about router-discovery for the sake of demand-dialing.
115		 */
116		if (0 == (ifp->int_state & GROUP_IS_SOL_OUT))
117			ifp->int_state |= IS_NO_SOL_OUT;
118		if (0 == (ifp->int_state & GROUP_IS_ADV_OUT))
119			ifp->int_state |= IS_NO_ADV_OUT;
120	}
121
122	if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE)))
123		ifp->int_state |= IS_NO_RDISC;
124	if (ifp->int_state & IS_PASSIVE)
125		ifp->int_state |= IS_NO_RIP;
126
127	if (!IS_RIP_IN_OFF(ifp->int_state)
128	    && ifp->int_auth[0].type != RIP_AUTH_NONE
129	    && !(ifp->int_state & IS_NO_RIPV1_IN)
130	    && !warned_auth_in) {
131		msglog("Warning: RIPv1 input via %s"
132		       " will be accepted without authentication",
133		       ifp->int_name);
134		warned_auth_in = 1;
135	}
136	if (!IS_RIP_OUT_OFF(ifp->int_state)
137	    && ifp->int_auth[0].type != RIP_AUTH_NONE
138	    && !(ifp->int_state & IS_NO_RIPV1_OUT)) {
139		if (!warned_auth_out) {
140			msglog("Warning: RIPv1 output via %s"
141			       " will be sent without authentication",
142			       ifp->int_name);
143			warned_auth_out = 1;
144		}
145	}
146}
147
148
149/* Read a list of gateways from /etc/gateways and add them to our tables.
150 *
151 * This file contains a list of "remote" gateways.  That is usually
152 * a gateway which we cannot immediately determine if it is present or
153 * not as we can do for those provided by directly connected hardware.
154 *
155 * If a gateway is marked "passive" in the file, then we assume it
156 * does not understand RIP and assume it is always present.  Those
157 * not marked passive are treated as if they were directly connected
158 * and assumed to be broken if they do not send us advertisements.
159 * All remote interfaces are added to our list, and those not marked
160 * passive are sent routing updates.
161 *
162 * A passive interface can also be local, hardware interface exempt
163 * from RIP.
164 */
165void
166gwkludge(void)
167{
168	FILE *fp;
169	char *p, *lptr;
170	const char *cp;
171	char lbuf[200], net_host[5], dname[64+1+64+1];
172	char gname[GNAME_LEN+1], qual[9];
173	struct interface *ifp;
174	naddr dst, netmask, gate;
175	int metric, n, lnum;
176	struct stat sb;
177	u_int state;
178	const char *type;
179
180
181	fp = fopen(_PATH_GATEWAYS, "r");
182	if (fp == 0)
183		return;
184
185	if (0 > fstat(fileno(fp), &sb)) {
186		msglog("could not stat() "_PATH_GATEWAYS);
187		(void)fclose(fp);
188		return;
189	}
190
191	for (lnum = 1; ; lnum++) {
192		if (0 == fgets(lbuf, sizeof(lbuf), fp))
193			break;
194		lptr = lbuf;
195		while (*lptr == ' ')
196			lptr++;
197		p = lptr+strlen(lptr)-1;
198		while (*p == '\n'
199		       || (*p == ' ' && (p == lptr+1 || *(p-1) != '\\')))
200			*p-- = '\0';
201		if (*lptr == '\0'	/* ignore null and comment lines */
202		    || *lptr == '#')
203			continue;
204
205		/* notice newfangled parameter lines
206		 */
207		if (strncasecmp("net", lptr, 3)
208		    && strncasecmp("host", lptr, 4)) {
209			cp = parse_parms(lptr,
210					 (sb.st_uid == 0
211					  && !(sb.st_mode&(S_IRWXG|S_IRWXO))));
212			if (cp != 0)
213				msglog("%s in line %d of "_PATH_GATEWAYS,
214				       cp, lnum);
215			continue;
216		}
217
218/*  {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
219		qual[0] = '\0';
220		/* the '64' here must be GNAME_LEN */
221		n = sscanf(lptr, "%4s %129[^ \t] gateway"
222			   " %64[^ / \t] metric %u %8s\n",
223			   net_host, dname, gname, &metric, qual);
224		if (n != 4 && n != 5) {
225			msglog("bad "_PATH_GATEWAYS" entry \"%s\"; %d values",
226			       lptr, n);
227			continue;
228		}
229		if (metric >= HOPCNT_INFINITY) {
230			msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"",
231			       lptr);
232			continue;
233		}
234		if (!strcasecmp(net_host, "host")) {
235			if (!gethost(dname, &dst)) {
236				msglog("bad host \"%s\" in "_PATH_GATEWAYS
237				       " entry \"%s\"", dname, lptr);
238				continue;
239			}
240			netmask = HOST_MASK;
241		} else if (!strcasecmp(net_host, "net")) {
242			if (!getnet(dname, &dst, &netmask)) {
243				msglog("bad net \"%s\" in "_PATH_GATEWAYS
244				       " entry \"%s\"", dname, lptr);
245				continue;
246			}
247			if (dst == RIP_DEFAULT) {
248				msglog("bad net \"%s\" in "_PATH_GATEWAYS
249				       " entry \"%s\"--cannot be default",
250				       dname, lptr);
251				continue;
252			}
253			/* Turn network # into IP address. */
254			dst = htonl(dst);
255		} else {
256			msglog("bad \"%s\" in "_PATH_GATEWAYS
257			       " entry \"%s\"", net_host, lptr);
258			continue;
259		}
260
261		if (!gethost(gname, &gate)) {
262			msglog("bad gateway \"%s\" in "_PATH_GATEWAYS
263			       " entry \"%s\"", gname, lptr);
264			continue;
265		}
266
267		if (!strcasecmp(qual, type = "passive")) {
268			/* Passive entries are not placed in our tables,
269			 * only the kernel's, so we don't copy all of the
270			 * external routing information within a net.
271			 * Internal machines should use the default
272			 * route to a suitable gateway (like us).
273			 */
274			state = IS_REMOTE | IS_PASSIVE;
275			if (metric == 0)
276				metric = 1;
277
278		} else if (!strcasecmp(qual, type = "external")) {
279			/* External entries are handled by other means
280			 * such as EGP, and are placed only in the daemon
281			 * tables to prevent overriding them with something
282			 * else.
283			 */
284			strcpy(qual,"external");
285			state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
286			if (metric == 0)
287				metric = 1;
288
289		} else if (!strcasecmp(qual, "active")
290			   || qual[0] == '\0') {
291			if (metric != 0) {
292				/* Entries that are neither "passive" nor
293				 * "external" are "remote" and must behave
294				 * like physical interfaces.  If they are not
295				 * heard from regularly, they are deleted.
296				 */
297				state = IS_REMOTE;
298				type = "remote";
299			} else {
300				/* "remote" entries with a metric of 0
301				 * are aliases for our own interfaces
302				 */
303				state = IS_REMOTE | IS_PASSIVE | IS_ALIAS;
304				type = "alias";
305			}
306
307		} else {
308			msglog("bad "_PATH_GATEWAYS" entry \"%s\";"
309			       " unknown type %s", lptr, qual);
310			continue;
311		}
312
313		if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
314			state |= IS_NO_RDISC;
315		if (state & IS_PASSIVE)
316			state |= IS_NO_RIP;
317
318		ifp = check_dup(gate,dst,netmask,state);
319		if (ifp != 0) {
320			msglog("duplicate "_PATH_GATEWAYS" entry \"%s\"",lptr);
321			continue;
322		}
323
324		ifp = (struct interface *)rtmalloc(sizeof(*ifp), "gwkludge()");
325		memset(ifp, 0, sizeof(*ifp));
326
327		ifp->int_state = state;
328		if (netmask == HOST_MASK)
329			ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP;
330		else
331			ifp->int_if_flags = IFF_UP;
332		ifp->int_act_time = NEVER;
333		ifp->int_addr = gate;
334		ifp->int_dstaddr = dst;
335		ifp->int_mask = netmask;
336		ifp->int_ripv1_mask = netmask;
337		ifp->int_std_mask = std_mask(gate);
338		ifp->int_net = ntohl(dst);
339		ifp->int_std_net = ifp->int_net & ifp->int_std_mask;
340		ifp->int_std_addr = htonl(ifp->int_std_net);
341		ifp->int_metric = metric;
342		if (!(state & IS_EXTERNAL)
343		    && ifp->int_mask != ifp->int_std_mask)
344			ifp->int_state |= IS_SUBNET;
345		(void)sprintf(ifp->int_name, "%s(%s)", type, gname);
346		ifp->int_index = -1;
347
348		if_link(ifp);
349	}
350
351	/* After all of the parameter lines have been read,
352	 * apply them to any remote interfaces.
353	 */
354	for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
355		get_parms(ifp);
356
357		tot_interfaces++;
358		if (!IS_RIP_OFF(ifp->int_state))
359			rip_interfaces++;
360
361		trace_if("Add", ifp);
362	}
363
364	(void)fclose(fp);
365}
366
367
368/* like strtok(), but honoring backslash and not changing the source string
369 */
370static int				/* 0=ok, -1=bad */
371parse_quote(char **linep,		/* look here */
372	    const char *delims,		/* for these delimiters */
373	    char *delimp,		/* 0 or put found delimiter here */
374	    char *buf,			/* copy token to here */
375	    int	lim)			/* at most this many bytes */
376{
377	char c = '\0', *pc;
378	const char *p;
379
380
381	pc = *linep;
382	if (*pc == '\0')
383		return -1;
384
385	while (lim != 0) {
386		c = *pc++;
387		if (c == '\0')
388			break;
389
390		if (c == '\\' && *pc != '\0') {
391			if ((c = *pc++) == 'n') {
392				c = '\n';
393			} else if (c == 'r') {
394				c = '\r';
395			} else if (c == 't') {
396				c = '\t';
397			} else if (c == 'b') {
398				c = '\b';
399			} else if (c >= '0' && c <= '7') {
400				c -= '0';
401				if (*pc >= '0' && *pc <= '7') {
402					c = (c<<3)+(*pc++ - '0');
403					if (*pc >= '0' && *pc <= '7')
404					    c = (c<<3)+(*pc++ - '0');
405				}
406			}
407
408		} else {
409			for (p = delims; *p != '\0'; ++p) {
410				if (*p == c)
411					goto exit;
412			}
413		}
414
415		*buf++ = c;
416		--lim;
417	}
418exit:
419	if (lim == 0)
420		return -1;
421
422	*buf = '\0';			/* terminate copy of token */
423	if (delimp != 0)
424		*delimp = c;		/* return delimiter */
425	*linep = pc-1;			/* say where we ended */
426	return 0;
427}
428
429
430/* Parse password timestamp
431 */
432static char *
433parse_ts(time_t *tp,
434	 char **valp,
435	 char *val0,
436	 char *delimp,
437	 char *buf,
438	 u_int bufsize)
439{
440	struct tm tm;
441#if defined(sgi) || defined(__NetBSD__)
442	char *ptr;
443#endif
444
445	if (0 > parse_quote(valp, "| ,\n\r", delimp,
446			    buf,bufsize)
447	    || buf[bufsize-1] != '\0'
448	    || buf[bufsize-2] != '\0') {
449		sprintf(buf,"bad timestamp %.25s", val0);
450		return buf;
451	}
452	strcat(buf,"\n");
453	memset(&tm, 0, sizeof(tm));
454#if defined(sgi) || defined(__NetBSD__)
455	ptr = strptime(buf, "%y/%m/%d@%H:%M\n", &tm);
456	if (ptr == NULL || *ptr != '\0') {
457		sprintf(buf,"bad timestamp %.25s", val0);
458		return buf;
459	}
460#else
461	if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n",
462			&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
463			&tm.tm_hour, &tm.tm_min)
464	    || tm.tm_mon < 1 || tm.tm_mon > 12
465	    || tm.tm_mday < 1 || tm.tm_mday > 31) {
466		sprintf(buf,"bad timestamp %.25s", val0);
467		return buf;
468	}
469	tm.tm_mon--;
470	if (tm.tm_year <= 37)		/* assume small years are in the */
471		tm.tm_year += 100;	/* 3rd millenium */
472#endif
473
474	if ((*tp = mktime(&tm)) == -1) {
475		sprintf(buf,"bad timestamp %.25s", val0);
476		return buf;
477	}
478
479	return 0;
480}
481
482
483/* Get a password, key ID, and expiration date in the format
484 *	passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min
485 */
486static const char *			/* 0 or error message */
487get_passwd(char *tgt,
488	   char *val,
489	   struct parm *parmp,
490	   u_int16_t type,
491	   int safe)			/* 1=from secure file */
492{
493	static char buf[80];
494	char *val0, *p, delim;
495	struct auth k, *ap, *ap2;
496	int i;
497	u_long l;
498
499
500	if (!safe)
501		return "ignore unsafe password";
502
503	for (ap = parmp->parm_auth, i = 0;
504	     ap->type != RIP_AUTH_NONE; i++, ap++) {
505		if (i >= MAX_AUTH_KEYS)
506			return "too many passwords";
507	}
508
509	memset(&k, 0, sizeof(k));
510	k.type = type;
511	k.end = -1-DAY;
512
513	val0 = val;
514	if (0 > parse_quote(&val, "| ,\n\r", &delim,
515			    (char *)k.key, sizeof(k.key)))
516		return tgt;
517
518	if (delim != '|') {
519		if (type == RIP_AUTH_MD5)
520			return "missing Keyid";
521	} else {
522		val0 = ++val;
523		buf[sizeof(buf)-1] = '\0';
524		if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf))
525		    || buf[sizeof(buf)-1] != '\0'
526		    || (l = strtoul(buf,&p,0)) > 255
527		    || *p != '\0') {
528			sprintf(buf,"bad KeyID \"%.20s\"", val0);
529			return buf;
530		}
531		for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) {
532			if (ap2->keyid == l) {
533				sprintf(buf,"duplicate KeyID \"%.20s\"", val0);
534				return buf;
535			}
536		}
537		k.keyid = (int)l;
538
539		if (delim == '|') {
540			val0 = ++val;
541			if (0 != (p = parse_ts(&k.start,&val,val0,&delim,
542					       buf,sizeof(buf))))
543				return p;
544			if (delim != '|')
545				return "missing second timestamp";
546			val0 = ++val;
547			if (0 != (p = parse_ts(&k.end,&val,val0,&delim,
548					       buf,sizeof(buf))))
549				return p;
550			if ((u_long)k.start > (u_long)k.end) {
551				sprintf(buf,"out of order timestamp %.30s",
552					val0);
553				return buf;
554			}
555		}
556	}
557	if (delim != '\0')
558		return tgt;
559
560	memmove(ap, &k, sizeof(*ap));
561	return 0;
562}
563
564
565static const char *
566bad_str(const char *estr)
567{
568	static char buf[100+8];
569
570	sprintf(buf, "bad \"%.100s\"", estr);
571	return buf;
572}
573
574
575/* Parse a set of parameters for an interface.
576 */
577const char *					/* 0 or error message */
578parse_parms(char *line,
579	    int safe)			/* 1=from secure file */
580{
581#define PARS(str) (!strcasecmp(tgt, str))
582#define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str)))
583#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break;	\
584	parm.parm_int_state |= (b);}
585	struct parm parm;
586	struct intnet *intnetp;
587	struct r1net *r1netp;
588	struct tgate *tg;
589	naddr addr, mask;
590	char delim, *val0 = 0, *tgt, *val, *p;
591	const char *msg;
592	char buf[BUFSIZ], buf2[BUFSIZ];
593	int i;
594
595
596	/* "subnet=x.y.z.u/mask[,metric]" must be alone on the line */
597	if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1)
598	    && *(val = &line[sizeof("subnet=")-1]) != '\0') {
599		if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf)))
600			return bad_str(line);
601		intnetp = (struct intnet*)rtmalloc(sizeof(*intnetp),
602						   "parse_parms subnet");
603		intnetp->intnet_metric = 1;
604		if (delim == ',') {
605			intnetp->intnet_metric = (int)strtol(val+1,&p,0);
606			if (*p != '\0'
607			    || intnetp->intnet_metric <= 0
608			    || intnetp->intnet_metric >= HOPCNT_INFINITY)
609				return bad_str(line);
610		}
611		if (!getnet(buf, &intnetp->intnet_addr, &intnetp->intnet_mask)
612		    || intnetp->intnet_mask == HOST_MASK
613		    || intnetp->intnet_addr == RIP_DEFAULT) {
614			free(intnetp);
615			return bad_str(line);
616		}
617		intnetp->intnet_addr = htonl(intnetp->intnet_addr);
618		intnetp->intnet_next = intnets;
619		intnets = intnetp;
620		return 0;
621	}
622
623	/* "ripv1_mask=x.y.z.u/mask1,mask2" must be alone on the line.
624	 * This requires that x.y.z.u/mask1 be considered a subnet of
625	 * x.y.z.u/mask2, as if x.y.z.u/mask2 were a class-full network.
626	 */
627	if (!strncasecmp(line, "ripv1_mask=", sizeof("ripv1_mask=")-1)
628	    && *(val = &line[sizeof("ripv1_mask=")-1]) != '\0') {
629		if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf))
630		    || delim == '\0')
631			return bad_str(line);
632		if ((i = (int)strtol(val+1, &p, 0)) <= 0
633		    || i > 32 || *p != '\0')
634			return bad_str(line);
635		r1netp = (struct r1net *)rtmalloc(sizeof(*r1netp),
636						  "parse_parms ripv1_mask");
637		r1netp->r1net_mask = HOST_MASK << (32-i);
638		if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match)
639		    || r1netp->r1net_net == RIP_DEFAULT
640		    || r1netp->r1net_mask > r1netp->r1net_match) {
641			free(r1netp);
642			return bad_str(line);
643		}
644		r1netp->r1net_next = r1nets;
645		r1nets = r1netp;
646		return 0;
647	}
648
649	memset(&parm, 0, sizeof(parm));
650
651	for (;;) {
652		tgt = line + strspn(line, " ,\n\r");
653		if (*tgt == '\0' || *tgt == '#')
654			break;
655		line = tgt+strcspn(tgt, "= #,\n\r");
656		delim = *line;
657		if (delim == '=') {
658			val0 = ++line;
659			if (0 > parse_quote(&line, " #,\n\r",&delim,
660					    buf,sizeof(buf)))
661				return bad_str(tgt);
662		}
663		if (delim != '\0') {
664			for (;;) {
665				*line = '\0';
666				if (delim == '#')
667					break;
668				++line;
669				if (delim != ' '
670				    || (delim = *line) != ' ')
671					break;
672			}
673		}
674
675		if (PARSEQ("if")) {
676			if (parm.parm_name[0] != '\0'
677			    || strlen(buf) > IF_NAME_LEN)
678				return bad_str(tgt);
679			strcpy(parm.parm_name, buf);
680
681		} else if (PARSEQ("addr")) {
682			/* This is a bad idea, because the address based
683			 * sets of parameters cannot be checked for
684			 * consistency with the interface name parameters.
685			 * The parm_net stuff is needed to allow several
686			 * -F settings.
687			 */
688			if (!getnet(val0, &addr, &mask)
689			    || parm.parm_name[0] != '\0')
690				return bad_str(tgt);
691			parm.parm_net = addr;
692			parm.parm_mask = mask;
693			parm.parm_name[0] = '\n';
694
695		} else if (PARSEQ("passwd")) {
696			/* since cleartext passwords are so weak allow
697			 * them anywhere
698			 */
699			msg = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1);
700			if (msg) {
701				*val0 = '\0';
702				return bad_str(msg);
703			}
704
705		} else if (PARSEQ("md5_passwd")) {
706			msg = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe);
707			if (msg) {
708				*val0 = '\0';
709				return bad_str(msg);
710			}
711
712		} else if (PARS("no_ag")) {
713			parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
714
715		} else if (PARS("no_super_ag")) {
716			parm.parm_int_state |= IS_NO_SUPER_AG;
717
718		} else if (PARS("no_rip_out")) {
719			parm.parm_int_state |= IS_NO_RIP_OUT;
720
721		} else if (PARS("no_ripv1_in")) {
722			parm.parm_int_state |= IS_NO_RIPV1_IN;
723
724		} else if (PARS("no_ripv2_in")) {
725			parm.parm_int_state |= IS_NO_RIPV2_IN;
726
727		} else if (PARS("ripv2_out")) {
728			if (parm.parm_int_state & IS_NO_RIPV2_OUT)
729				return bad_str(tgt);
730			parm.parm_int_state |= IS_NO_RIPV1_OUT;
731
732		} else if (PARS("ripv2")) {
733			if ((parm.parm_int_state & IS_NO_RIPV2_OUT)
734			    || (parm.parm_int_state & IS_NO_RIPV2_IN))
735				return bad_str(tgt);
736			parm.parm_int_state |= (IS_NO_RIPV1_IN
737						| IS_NO_RIPV1_OUT);
738
739		} else if (PARS("no_rip")) {
740			CKF(IS_PM_RDISC, IS_NO_RIP);
741
742		} else if (PARS("no_rip_mcast")) {
743			parm.parm_int_state |= IS_NO_RIP_MCAST;
744
745		} else if (PARS("no_rdisc")) {
746			CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
747
748		} else if (PARS("no_solicit")) {
749			CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT);
750
751		} else if (PARS("send_solicit")) {
752			CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT);
753
754		} else if (PARS("no_rdisc_adv")) {
755			CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT);
756
757		} else if (PARS("rdisc_adv")) {
758			CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT);
759
760		} else if (PARS("bcast_rdisc")) {
761			parm.parm_int_state |= IS_BCAST_RDISC;
762
763		} else if (PARS("passive")) {
764			CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
765			parm.parm_int_state |= IS_NO_RIP | IS_PASSIVE;
766
767		} else if (PARSEQ("rdisc_pref")) {
768			if (parm.parm_rdisc_pref != 0
769			    || (parm.parm_rdisc_pref = (int)strtol(buf,&p,0),
770				*p != '\0'))
771				return bad_str(tgt);
772
773		} else if (PARS("pm_rdisc")) {
774			if (IS_RIP_OUT_OFF(parm.parm_int_state))
775				return bad_str(tgt);
776			parm.parm_int_state |= IS_PM_RDISC;
777
778		} else if (PARSEQ("rdisc_interval")) {
779			if (parm.parm_rdisc_int != 0
780			    || (parm.parm_rdisc_int = (int)strtoul(buf,&p,0),
781				*p != '\0')
782			    || parm.parm_rdisc_int < MinMaxAdvertiseInterval
783			    || parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
784				return bad_str(tgt);
785
786		} else if (PARSEQ("fake_default")) {
787			if (parm.parm_d_metric != 0
788			    || IS_RIP_OUT_OFF(parm.parm_int_state)
789			    || (i = strtoul(buf,&p,0), *p != '\0')
790			    || i > HOPCNT_INFINITY-1)
791				return bad_str(tgt);
792			parm.parm_d_metric = i;
793
794		} else if (PARSEQ("adj_inmetric")) {
795			if (parm.parm_adj_inmetric != 0
796			    || (i = strtoul(buf,&p,0), *p != '\0')
797			    || i > HOPCNT_INFINITY-1)
798				return bad_str(tgt);
799			parm.parm_adj_inmetric = i;
800
801		} else if (PARSEQ("adj_outmetric")) {
802			if (parm.parm_adj_outmetric != 0
803			    || (i = strtoul(buf,&p,0), *p != '\0')
804			    || i > HOPCNT_INFINITY-1)
805				return bad_str(tgt);
806			parm.parm_adj_outmetric = i;
807
808		} else if (PARSEQ("trust_gateway")) {
809			/* look for trust_gateway=x.y.z|net/mask|...) */
810			p = buf;
811			if (0 > parse_quote(&p, "|", &delim,
812					    buf2, sizeof(buf2))
813			    || !gethost(buf2,&addr))
814				return bad_str(tgt);
815			tg = (struct tgate *)rtmalloc(sizeof(*tg),
816						      "parse_parms"
817						      "trust_gateway");
818			memset(tg, 0, sizeof(*tg));
819			tg->tgate_addr = addr;
820			i = 0;
821			/* The default is to trust all routes. */
822			while (delim == '|') {
823				p++;
824				if (i >= MAX_TGATE_NETS
825				    || 0 > parse_quote(&p, "|", &delim,
826						       buf2, sizeof(buf2))
827				    || !getnet(buf2, &tg->tgate_nets[i].net,
828					       &tg->tgate_nets[i].mask)
829				    || tg->tgate_nets[i].net == RIP_DEFAULT
830				    || tg->tgate_nets[i].mask == 0)
831					return bad_str(tgt);
832				i++;
833			}
834			tg->tgate_next = tgates;
835			tgates = tg;
836			parm.parm_int_state |= IS_DISTRUST;
837
838		} else if (PARS("redirect_ok")) {
839			parm.parm_int_state |= IS_REDIRECT_OK;
840
841		} else {
842			return bad_str(tgt);	/* error */
843		}
844	}
845
846	return check_parms(&parm);
847#undef PARS
848#undef PARSEQ
849}
850
851
852/* check for duplicate parameter specifications */
853const char *				/* 0 or error message */
854check_parms(struct parm *new)
855{
856	struct parm *parmp, **parmpp;
857	int i, num_passwds;
858
859	/* set implicit values
860	 */
861	if (new->parm_int_state & IS_NO_ADV_IN)
862		new->parm_int_state |= IS_NO_SOL_OUT;
863	if (new->parm_int_state & IS_NO_SOL_OUT)
864		new->parm_int_state |= IS_NO_ADV_IN;
865
866	for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
867		if (new->parm_auth[i].type != RIP_AUTH_NONE)
868			num_passwds++;
869	}
870
871	/* compare with existing sets of parameters
872	 */
873	for (parmpp = &parms;
874	     (parmp = *parmpp) != 0;
875	     parmpp = &parmp->parm_next) {
876		if (strcmp(new->parm_name, parmp->parm_name))
877			continue;
878		if (!on_net(htonl(parmp->parm_net),
879			    new->parm_net, new->parm_mask)
880		    && !on_net(htonl(new->parm_net),
881			       parmp->parm_net, parmp->parm_mask))
882			continue;
883
884		for (i = 0; i < MAX_AUTH_KEYS; i++) {
885			if (parmp->parm_auth[i].type != RIP_AUTH_NONE)
886				num_passwds++;
887		}
888		if (num_passwds > MAX_AUTH_KEYS)
889			return "too many conflicting passwords";
890
891		if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT)
892		     && 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT)
893		     && 0 != ((new->parm_int_state ^ parmp->parm_int_state)
894			      && GROUP_IS_SOL_OUT))
895		    || (0 != (new->parm_int_state & GROUP_IS_ADV_OUT)
896			&& 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT)
897			&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
898				 && GROUP_IS_ADV_OUT))
899		    || (new->parm_rdisc_pref != 0
900			&& parmp->parm_rdisc_pref != 0
901			&& new->parm_rdisc_pref != parmp->parm_rdisc_pref)
902		    || (new->parm_rdisc_int != 0
903			&& parmp->parm_rdisc_int != 0
904			&& new->parm_rdisc_int != parmp->parm_rdisc_int)) {
905			return ("conflicting, duplicate router discovery"
906				" parameters");
907
908		}
909
910		if (new->parm_d_metric != 0
911		     && parmp->parm_d_metric != 0
912		     && new->parm_d_metric != parmp->parm_d_metric) {
913			return ("conflicting, duplicate poor man's router"
914				" discovery or fake default metric");
915		}
916
917		if (new->parm_adj_inmetric != 0
918		    && parmp->parm_adj_inmetric != 0
919		    && new->parm_adj_inmetric != parmp->parm_adj_inmetric) {
920			return ("conflicting interface input "
921				"metric adjustments");
922		}
923
924		if (new->parm_adj_outmetric != 0
925		    && parmp->parm_adj_outmetric != 0
926		    && new->parm_adj_outmetric != parmp->parm_adj_outmetric) {
927			return ("conflicting interface output "
928				"metric adjustments");
929		}
930	}
931
932	/* link new entry on the list so that when the entries are scanned,
933	 * they affect the result in the order the operator specified.
934	 */
935	parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms");
936	memcpy(parmp, new, sizeof(*parmp));
937	*parmpp = parmp;
938
939	return 0;
940}
941
942
943/* get a network number as a name or a number, with an optional "/xx"
944 * netmask.
945 */
946int					/* 0=bad */
947getnet(char *name,
948       naddr *netp,			/* network in host byte order */
949       naddr *maskp)			/* masks are always in host order */
950{
951	int i;
952	struct netent *np;
953	naddr mask;			/* in host byte order */
954	struct in_addr in;		/* a network and so host byte order */
955	char hname[MAXHOSTNAMELEN+1];
956	char *mname, *p;
957
958
959	/* Detect and separate "1.2.3.4/24"
960	 */
961	if (0 != (mname = strrchr(name,'/'))) {
962		i = (int)(mname - name);
963		if (i > (int)sizeof(hname)-1)	/* name too long */
964			return 0;
965		memmove(hname, name, i);
966		hname[i] = '\0';
967		mname++;
968		name = hname;
969	}
970
971	np = getnetbyname(name);
972	if (np != 0) {
973		in.s_addr = (naddr)np->n_net;
974		if (0 == (in.s_addr & 0xff000000))
975			in.s_addr <<= 8;
976		if (0 == (in.s_addr & 0xff000000))
977			in.s_addr <<= 8;
978		if (0 == (in.s_addr & 0xff000000))
979			in.s_addr <<= 8;
980	} else if (inet_aton(name, &in) == 1) {
981		in.s_addr = ntohl(in.s_addr);
982	} else if (!mname && !strcasecmp(name,"default")) {
983		in.s_addr = RIP_DEFAULT;
984	} else {
985		return 0;
986	}
987
988	if (!mname) {
989		/* we cannot use the interfaces here because we have not
990		 * looked at them yet.
991		 */
992		mask = std_mask(htonl(in.s_addr));
993		if ((~mask & in.s_addr) != 0)
994			mask = HOST_MASK;
995	} else {
996		mask = (naddr)strtoul(mname, &p, 0);
997		if (*p != '\0' || mask > 32)
998			return 0;
999		if (mask != 0)
1000			mask = HOST_MASK << (32-mask);
1001	}
1002
1003	/* must have mask of 0 with default */
1004	if (mask != 0 && in.s_addr == RIP_DEFAULT)
1005		return 0;
1006	/* no host bits allowed in a network number */
1007	if ((~mask & in.s_addr) != 0)
1008		return 0;
1009	/* require non-zero network number */
1010	if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT)
1011		return 0;
1012	if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT)
1013		return 0;
1014	if (in.s_addr>>24 == 0xff)
1015		return 0;
1016
1017	*netp = in.s_addr;
1018	*maskp = mask;
1019	return 1;
1020}
1021
1022
1023int					/* 0=bad */
1024gethost(char *name,
1025	naddr *addrp)
1026{
1027	struct hostent *hp;
1028	struct in_addr in;
1029
1030
1031	/* Try for a number first, even in IRIX where gethostbyname()
1032	 * is smart.  This avoids hitting the name server which
1033	 * might be sick because routing is.
1034	 */
1035	if (inet_aton(name, &in) == 1) {
1036		/* get a good number, but check that it it makes some
1037		 * sense.
1038		 */
1039		if (ntohl(in.s_addr)>>24 == 0
1040		    || ntohl(in.s_addr)>>24 == 0xff)
1041			return 0;
1042		*addrp = in.s_addr;
1043		return 1;
1044	}
1045
1046	hp = gethostbyname(name);
1047	if (hp) {
1048		memcpy(addrp, hp->h_addr, sizeof(*addrp));
1049		return 1;
1050	}
1051
1052	return 0;
1053}
1054