parms.c revision 37908
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#ifndef lint
35#if 0
36static char sccsid[] = "@(#)if.c	8.1 (Berkeley) 6/5/93";
37#endif
38static const char rcsid[] =
39	"$Id$";
40#endif /* not lint */
41
42#include "defs.h"
43#include "pathnames.h"
44#include <sys/stat.h>
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 *)rtmalloc(sizeof(*ifp), "gwkludge");
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=")-1]) != '\0') {
561		intnetp = (struct intnet*)
562				rtmalloc(sizeof(*intnetp), "parse_parms");
563		intnetp->intnet_metric = 1;
564		if ((p = strrchr(val,','))) {
565			*p++ = '\0';
566			intnetp->intnet_metric = (int)strtol(p,&p,0);
567			if (*p != '\0'
568			    || intnetp->intnet_metric <= 0
569			    || intnetp->intnet_metric >= HOPCNT_INFINITY)
570				return line;
571		}
572		if (!getnet(val, &intnetp->intnet_addr, &intnetp->intnet_mask)
573		    || intnetp->intnet_mask == HOST_MASK
574		    || intnetp->intnet_addr == RIP_DEFAULT) {
575			free(intnetp);
576			return line;
577		}
578		HTONL(intnetp->intnet_addr);
579		intnetp->intnet_next = intnets;
580		intnets = intnetp;
581		return 0;
582	}
583
584	bzero(&parm, sizeof(parm));
585
586	tgt = "null";
587	for (;;) {
588		tgt = line + strspn(line, " ,\n\r");
589		if (*tgt == '\0')
590			break;
591
592		line += strcspn(tgt, "= ,\n\r");
593		delim = *line;
594		if (delim == '=') {
595			val0 = ++line;
596			if (0 > parse_quote(&line," ,\n\r",&delim,
597					    buf,sizeof(buf)))
598				return tgt;
599		}
600		if (delim != '\0')
601			*line++ = '\0';
602
603		if (PARSEQ("if")) {
604			if (parm.parm_name[0] != '\0'
605			    || strlen(buf) > IFNAMSIZ)
606				return tgt;
607			strcpy(parm.parm_name, buf);
608
609		} else if (PARSEQ("addr")) {
610			/* This is a bad idea, because the address based
611			 * sets of parameters cannot be checked for
612			 * consistency with the interface name parameters.
613			 * The parm_net stuff is needed to allow several
614			 * -F settings.
615			 */
616			if (!getnet(val0, &addr, &mask)
617			    || parm.parm_name[0] != '\0')
618				return tgt;
619			parm.parm_net = addr;
620			parm.parm_mask = mask;
621			parm.parm_name[0] = '\n';
622
623		} else if (PARSEQ("passwd")) {
624			/* since cleartext passwords are so weak allow
625			 * them anywhere
626			 */
627			tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1);
628			if (tgt) {
629				*val0 = '\0';
630				return tgt;
631			}
632
633		} else if (PARSEQ("md5_passwd")) {
634			tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe);
635			if (tgt) {
636				*val0 = '\0';
637				return tgt;
638			}
639
640		} else if (PARS("no_ag")) {
641			parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
642
643		} else if (PARS("no_super_ag")) {
644			parm.parm_int_state |= IS_NO_SUPER_AG;
645
646		} else if (PARS("no_ripv1_in")) {
647			parm.parm_int_state |= IS_NO_RIPV1_IN;
648
649		} else if (PARS("no_ripv2_in")) {
650			parm.parm_int_state |= IS_NO_RIPV2_IN;
651
652		} else if (PARS("ripv2_out")) {
653			if (parm.parm_int_state & IS_NO_RIPV2_OUT)
654				return tgt;
655			parm.parm_int_state |= IS_NO_RIPV1_OUT;
656
657		} else if (PARS("ripv2")) {
658			if ((parm.parm_int_state & IS_NO_RIPV2_OUT)
659			    || (parm.parm_int_state & IS_NO_RIPV2_IN))
660				return tgt;
661			parm.parm_int_state |= (IS_NO_RIPV1_IN
662						| IS_NO_RIPV1_OUT);
663
664		} else if (PARS("no_rip")) {
665			CKF(IS_PM_RDISC, IS_NO_RIP);
666
667		} else if (PARS("no_rdisc")) {
668			CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
669
670		} else if (PARS("no_solicit")) {
671			CKF(GROUP_IS_SOL, IS_NO_SOL_OUT);
672
673		} else if (PARS("send_solicit")) {
674			CKF(GROUP_IS_SOL, IS_SOL_OUT);
675
676		} else if (PARS("no_rdisc_adv")) {
677			CKF(GROUP_IS_ADV, IS_NO_ADV_OUT);
678
679		} else if (PARS("rdisc_adv")) {
680			CKF(GROUP_IS_ADV, IS_ADV_OUT);
681
682		} else if (PARS("bcast_rdisc")) {
683			parm.parm_int_state |= IS_BCAST_RDISC;
684
685		} else if (PARS("passive")) {
686			CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
687			parm.parm_int_state |= IS_NO_RIP;
688
689		} else if (PARSEQ("rdisc_pref")) {
690			if (parm.parm_rdisc_pref != 0
691			    || (parm.parm_rdisc_pref = (int)strtoul(buf, &p,0),
692				*p != '\0'))
693				return tgt;
694
695		} else if (PARS("pm_rdisc")) {
696			if (IS_RIP_OUT_OFF(parm.parm_int_state))
697				return tgt;
698			parm.parm_int_state |= IS_PM_RDISC;
699
700		} else if (PARSEQ("rdisc_interval")) {
701			if (parm.parm_rdisc_int != 0
702			    || (parm.parm_rdisc_int = (int)strtoul(buf,&p,0),
703				*p != '\0')
704			    || parm.parm_rdisc_int < MinMaxAdvertiseInterval
705			    || parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
706				return tgt;
707
708		} else if (PARSEQ("fake_default")) {
709			if (parm.parm_d_metric != 0
710			    || IS_RIP_OUT_OFF(parm.parm_int_state)
711			    || (parm.parm_d_metric = (int)strtoul(buf,&p,0),
712				*p != '\0')
713			    || parm.parm_d_metric > HOPCNT_INFINITY-1)
714				return tgt;
715
716		} else if (PARSEQ("trust_gateway")) {
717			if (!gethost(buf,&addr))
718				return tgt;
719			tg = (struct tgate *)
720					rtmalloc(sizeof(*tg), "parse_parms");
721			tg->tgate_next = tgates;
722			tg->tgate_addr = addr;
723			tgates = tg;
724			parm.parm_int_state |= IS_DISTRUST;
725
726		} else if (PARS("redirect_ok")) {
727			parm.parm_int_state |= IS_REDIRECT_OK;
728
729		} else {
730			return tgt;	/* error */
731		}
732	}
733
734	return check_parms(&parm);
735#undef PARS
736#undef PARSEQ
737}
738
739
740/* check for duplicate parameter specifications */
741char *					/* 0 or error message */
742check_parms(struct parm *new)
743{
744	struct parm *parmp, **parmpp;
745	int i, num_passwds;
746
747	/* set implicit values
748	 */
749	if (new->parm_int_state & IS_NO_ADV_IN)
750		new->parm_int_state |= IS_NO_SOL_OUT;
751
752	for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
753		if (new->parm_auth[i].type != RIP_AUTH_NONE)
754			num_passwds++;
755	}
756
757	/* compare with existing sets of parameters
758	 */
759	for (parmpp = &parms;
760	     (parmp = *parmpp) != 0;
761	     parmpp = &parmp->parm_next) {
762		if (strcmp(new->parm_name, parmp->parm_name))
763			continue;
764		if (!on_net(htonl(parmp->parm_net),
765			    new->parm_net, new->parm_mask)
766		    && !on_net(htonl(new->parm_net),
767			       parmp->parm_net, parmp->parm_mask))
768			continue;
769
770		for (i = 0; i < MAX_AUTH_KEYS; i++) {
771			if (parmp->parm_auth[i].type != RIP_AUTH_NONE)
772				num_passwds++;
773		}
774		if (num_passwds > MAX_AUTH_KEYS)
775			return "too many conflicting passwords";
776
777		if ((0 != (new->parm_int_state & GROUP_IS_SOL)
778		     && 0 != (parmp->parm_int_state & GROUP_IS_SOL)
779		     && 0 != ((new->parm_int_state ^ parmp->parm_int_state)
780			      && GROUP_IS_SOL))
781		    || (0 != (new->parm_int_state & GROUP_IS_ADV)
782			&& 0 != (parmp->parm_int_state & GROUP_IS_ADV)
783			&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
784				 && GROUP_IS_ADV))
785		    || (new->parm_rdisc_pref != 0
786			&& parmp->parm_rdisc_pref != 0
787			&& new->parm_rdisc_pref != parmp->parm_rdisc_pref)
788		    || (new->parm_rdisc_int != 0
789			&& parmp->parm_rdisc_int != 0
790			&& new->parm_rdisc_int != parmp->parm_rdisc_int)) {
791			return ("conflicting, duplicate router discovery"
792				" parameters");
793
794		}
795
796		if (new->parm_d_metric != 0
797		     && parmp->parm_d_metric != 0
798		     && new->parm_d_metric != parmp->parm_d_metric) {
799			return ("conflicting, duplicate poor man's router"
800				" discovery or fake default metric");
801		}
802	}
803
804	/* link new entry on the so that when the entries are scanned,
805	 * they affect the result in the order the operator specified.
806	 */
807	parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms");
808	bcopy(new, parmp, sizeof(*parmp));
809	*parmpp = parmp;
810
811	return 0;
812}
813
814
815/* get a network number as a name or a number, with an optional "/xx"
816 * netmask.
817 */
818int					/* 0=bad */
819getnet(char *name,
820       naddr *netp,			/* a network so host byte order */
821       naddr *maskp)			/* masks are always in host order */
822{
823	int i;
824	struct netent *np;
825	naddr mask;			/* in host byte order */
826	struct in_addr in;		/* a network and so host byte order */
827	char hname[MAXHOSTNAMELEN+1];
828	char *mname, *p;
829
830
831	/* Detect and separate "1.2.3.4/24"
832	 */
833	if (0 != (mname = rindex(name,'/'))) {
834		i = (int)(mname - name);
835		if (i > sizeof(hname)-1)	/* name too long */
836			return 0;
837		bcopy(name, hname, i);
838		hname[i] = '\0';
839		mname++;
840		name = hname;
841	}
842
843	np = getnetbyname(name);
844	if (np != 0) {
845		in.s_addr = (naddr)np->n_net;
846	} else if (inet_aton(name, &in) == 1) {
847		NTOHL(in.s_addr);
848	} else if (!mname && !strcasecmp(name,"default")) {
849		in.s_addr = RIP_DEFAULT;
850	} else {
851		return 0;
852	}
853
854	if (!mname) {
855		/* we cannot use the interfaces here because we have not
856		 * looked at them yet.
857		 */
858		mask = std_mask(htonl(in.s_addr));
859		if ((~mask & in.s_addr) != 0)
860			mask = HOST_MASK;
861	} else {
862		mask = (naddr)strtoul(mname, &p, 0);
863		if (*p != '\0' || mask > 32)
864			return 0;
865		mask = HOST_MASK << (32-mask);
866	}
867
868	/* must have mask of 0 with default */
869	if (mask != 0 && in.s_addr == RIP_DEFAULT)
870		return 0;
871	/* no host bits allowed in a network number */
872	if ((~mask & in.s_addr) != 0)
873		return 0;
874	/* require non-zero network number */
875	if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT)
876		return 0;
877	if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT)
878		return 0;
879	if (in.s_addr>>24 == 0xff)
880		return 0;
881
882	*netp = in.s_addr;
883	*maskp = mask;
884	return 1;
885}
886
887
888int					/* 0=bad */
889gethost(char *name,
890	naddr *addrp)
891{
892	struct hostent *hp;
893	struct in_addr in;
894
895
896	/* Try for a number first, even in IRIX where gethostbyname()
897	 * is smart.  This avoids hitting the name server which
898	 * might be sick because routing is.
899	 */
900	if (inet_aton(name, &in) == 1) {
901		/* get a good number, but check that it it makes some
902		 * sense.
903		 */
904		if (ntohl(in.s_addr)>>24 == 0
905		    || ntohl(in.s_addr)>>24 == 0xff)
906			return 0;
907		*addrp = in.s_addr;
908		return 1;
909	}
910
911	hp = gethostbyname(name);
912	if (hp) {
913		bcopy(hp->h_addr, addrp, sizeof(*addrp));
914		return 1;
915	}
916
917	return 0;
918}
919