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