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