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