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