118316Swollman/*
218316Swollman * Copyright (c) 1983, 1993
318316Swollman *	The Regents of the University of California.  All rights reserved.
418316Swollman *
518316Swollman * Redistribution and use in source and binary forms, with or without
618316Swollman * modification, are permitted provided that the following conditions
718316Swollman * are met:
818316Swollman * 1. Redistributions of source code must retain the above copyright
918316Swollman *    notice, this list of conditions and the following disclaimer.
1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright
1118316Swollman *    notice, this list of conditions and the following disclaimer in the
1218316Swollman *    documentation and/or other materials provided with the distribution.
1318316Swollman * 4. Neither the name of the University nor the names of its contributors
1418316Swollman *    may be used to endorse or promote products derived from this software
1518316Swollman *    without specific prior written permission.
1618316Swollman *
1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2018316Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2718316Swollman * SUCH DAMAGE.
2846303Smarkm *
2950476Speter * $FreeBSD$
3018316Swollman */
3118316Swollman
3218316Swollman#include "defs.h"
3318316Swollman#include "pathnames.h"
3420339Swollman#include <sys/stat.h>
3518316Swollman
36126250Sbms#ifdef __NetBSD__
3746303Smarkm__RCSID("$NetBSD$");
38126250Sbms#elif defined(__FreeBSD__)
39126250Sbms__RCSID("$FreeBSD$");
40126250Sbms#else
41126250Sbms__RCSID("$Revision: 2.26 $");
42126250Sbms#ident "$Revision: 2.26 $"
4346303Smarkm#endif
4446303Smarkm
4546303Smarkm
46190715Sphkstatic struct parm *parms;
4718316Swollmanstruct intnet *intnets;
4846303Smarkmstruct r1net *r1nets;
4919880Swollmanstruct tgate *tgates;
5018316Swollman
5118316Swollman
5218316Swollman/* use configured parameters
5318316Swollman */
5418316Swollmanvoid
5518316Swollmanget_parms(struct interface *ifp)
5618316Swollman{
5746303Smarkm	static int warned_auth_in, warned_auth_out;
5818316Swollman	struct parm *parmp;
5920339Swollman	int i, num_passwds = 0;
6018316Swollman
6118316Swollman	/* get all relevant parameters
6218316Swollman	 */
6318316Swollman	for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
6419880Swollman		if (parmp->parm_name[0] == '\0'
6519880Swollman		    || !strcmp(ifp->int_name, parmp->parm_name)
6619880Swollman		    || (parmp->parm_name[0] == '\n'
6719880Swollman			&& on_net(ifp->int_addr,
6819880Swollman				  parmp->parm_net, parmp->parm_mask))) {
6919880Swollman
7019880Swollman			/* This group of parameters is relevant,
7118316Swollman			 * so get its settings
7218316Swollman			 */
7318316Swollman			ifp->int_state |= parmp->parm_int_state;
7420339Swollman			for (i = 0; i < MAX_AUTH_KEYS; i++) {
7520339Swollman				if (parmp->parm_auth[0].type == RIP_AUTH_NONE
7620339Swollman				    || num_passwds >= MAX_AUTH_KEYS)
7720339Swollman					break;
7846303Smarkm				memcpy(&ifp->int_auth[num_passwds++],
7946303Smarkm				       &parmp->parm_auth[i],
8046303Smarkm				       sizeof(ifp->int_auth[0]));
8120339Swollman			}
8218316Swollman			if (parmp->parm_rdisc_pref != 0)
8318316Swollman				ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
8418316Swollman			if (parmp->parm_rdisc_int != 0)
8518316Swollman				ifp->int_rdisc_int = parmp->parm_rdisc_int;
86126250Sbms			if (parmp->parm_adj_inmetric != 0)
87126250Sbms			    ifp->int_adj_inmetric = parmp->parm_adj_inmetric;
88126250Sbms			if (parmp->parm_adj_outmetric != 0)
89126250Sbms			    ifp->int_adj_outmetric = parmp->parm_adj_outmetric;
9019880Swollman		}
9118316Swollman	}
9219880Swollman
9319880Swollman	/* Set general defaults.
9419880Swollman	 *
9519880Swollman	 * Default poor-man's router discovery to a metric that will
9619880Swollman	 * be heard by old versions of `routed`.  They ignored received
9719880Swollman	 * routes with metric 15.
9818316Swollman	 */
9918316Swollman	if ((ifp->int_state & IS_PM_RDISC)
10018316Swollman	    && ifp->int_d_metric == 0)
10119880Swollman		ifp->int_d_metric = FAKE_METRIC;
10218316Swollman
10318316Swollman	if (ifp->int_rdisc_int == 0)
10418316Swollman		ifp->int_rdisc_int = DefMaxAdvertiseInterval;
10518316Swollman
10618316Swollman	if (!(ifp->int_if_flags & IFF_MULTICAST)
10719880Swollman	    && !(ifp->int_state & IS_REMOTE))
10818316Swollman		ifp->int_state |= IS_BCAST_RDISC;
10918316Swollman
11018316Swollman	if (ifp->int_if_flags & IFF_POINTOPOINT) {
11118316Swollman		ifp->int_state |= IS_BCAST_RDISC;
11218316Swollman		/* By default, point-to-point links should be passive
11318316Swollman		 * about router-discovery for the sake of demand-dialing.
11418316Swollman		 */
11546303Smarkm		if (0 == (ifp->int_state & GROUP_IS_SOL_OUT))
11618316Swollman			ifp->int_state |= IS_NO_SOL_OUT;
11746303Smarkm		if (0 == (ifp->int_state & GROUP_IS_ADV_OUT))
11818316Swollman			ifp->int_state |= IS_NO_ADV_OUT;
11918316Swollman	}
12018316Swollman
12118316Swollman	if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE)))
12218316Swollman		ifp->int_state |= IS_NO_RDISC;
12318316Swollman	if (ifp->int_state & IS_PASSIVE)
12419880Swollman		ifp->int_state |= IS_NO_RIP;
12519880Swollman
12619880Swollman	if (!IS_RIP_IN_OFF(ifp->int_state)
12720339Swollman	    && ifp->int_auth[0].type != RIP_AUTH_NONE
12819880Swollman	    && !(ifp->int_state & IS_NO_RIPV1_IN)
12919880Swollman	    && !warned_auth_in) {
13019880Swollman		msglog("Warning: RIPv1 input via %s"
13119880Swollman		       " will be accepted without authentication",
13219880Swollman		       ifp->int_name);
13319880Swollman		warned_auth_in = 1;
13419880Swollman	}
13519880Swollman	if (!IS_RIP_OUT_OFF(ifp->int_state)
13620339Swollman	    && ifp->int_auth[0].type != RIP_AUTH_NONE
13720339Swollman	    && !(ifp->int_state & IS_NO_RIPV1_OUT)) {
13820339Swollman		if (!warned_auth_out) {
13920339Swollman			msglog("Warning: RIPv1 output via %s"
14020339Swollman			       " will be sent without authentication",
14120339Swollman			       ifp->int_name);
14220339Swollman			warned_auth_out = 1;
14320339Swollman		}
14419880Swollman	}
14518316Swollman}
14618316Swollman
14718316Swollman
14818316Swollman/* Read a list of gateways from /etc/gateways and add them to our tables.
14918316Swollman *
15018316Swollman * This file contains a list of "remote" gateways.  That is usually
15118316Swollman * a gateway which we cannot immediately determine if it is present or
15218316Swollman * not as we can do for those provided by directly connected hardware.
15318316Swollman *
15418316Swollman * If a gateway is marked "passive" in the file, then we assume it
15518316Swollman * does not understand RIP and assume it is always present.  Those
15618316Swollman * not marked passive are treated as if they were directly connected
15718316Swollman * and assumed to be broken if they do not send us advertisements.
15818316Swollman * All remote interfaces are added to our list, and those not marked
15918316Swollman * passive are sent routing updates.
16018316Swollman *
16118316Swollman * A passive interface can also be local, hardware interface exempt
16218316Swollman * from RIP.
16318316Swollman */
16418316Swollmanvoid
16518316Swollmangwkludge(void)
16618316Swollman{
16718316Swollman	FILE *fp;
16818316Swollman	char *p, *lptr;
16946303Smarkm	const char *cp;
17046303Smarkm	char lbuf[200], net_host[5], dname[64+1+64+1];
17146303Smarkm	char gname[GNAME_LEN+1], qual[9];
17218316Swollman	struct interface *ifp;
17318316Swollman	naddr dst, netmask, gate;
17446303Smarkm	int metric, n, lnum;
17520339Swollman	struct stat sb;
17618316Swollman	u_int state;
17746303Smarkm	const char *type;
17818316Swollman
17918316Swollman
18018316Swollman	fp = fopen(_PATH_GATEWAYS, "r");
18118316Swollman	if (fp == 0)
18218316Swollman		return;
18318316Swollman
18420339Swollman	if (0 > fstat(fileno(fp), &sb)) {
18520339Swollman		msglog("could not stat() "_PATH_GATEWAYS);
18620339Swollman		(void)fclose(fp);
18720339Swollman		return;
18820339Swollman	}
18920339Swollman
19046303Smarkm	for (lnum = 1; ; lnum++) {
191230045Skevlo		if (fgets(lbuf, sizeof(lbuf), fp) == NULL)
19218316Swollman			break;
19318316Swollman		lptr = lbuf;
19418316Swollman		while (*lptr == ' ')
19518316Swollman			lptr++;
19646303Smarkm		p = lptr+strlen(lptr)-1;
19746303Smarkm		while (*p == '\n'
19846303Smarkm		       || (*p == ' ' && (p == lptr+1 || *(p-1) != '\\')))
19946303Smarkm			*p-- = '\0';
20046303Smarkm		if (*lptr == '\0'	/* ignore null and comment lines */
20118316Swollman		    || *lptr == '#')
20218316Swollman			continue;
20318316Swollman
20418316Swollman		/* notice newfangled parameter lines
20518316Swollman		 */
20618316Swollman		if (strncasecmp("net", lptr, 3)
20718316Swollman		    && strncasecmp("host", lptr, 4)) {
20846303Smarkm			cp = parse_parms(lptr,
20946303Smarkm					 (sb.st_uid == 0
21046303Smarkm					  && !(sb.st_mode&(S_IRWXG|S_IRWXO))));
21146303Smarkm			if (cp != 0)
21246303Smarkm				msglog("%s in line %d of "_PATH_GATEWAYS,
21346303Smarkm				       cp, lnum);
21418316Swollman			continue;
21518316Swollman		}
21618316Swollman
21718316Swollman/*  {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
21819880Swollman		qual[0] = '\0';
21946303Smarkm		/* the '64' here must be GNAME_LEN */
22018316Swollman		n = sscanf(lptr, "%4s %129[^ \t] gateway"
22119880Swollman			   " %64[^ / \t] metric %u %8s\n",
22218316Swollman			   net_host, dname, gname, &metric, qual);
22319880Swollman		if (n != 4 && n != 5) {
22419880Swollman			msglog("bad "_PATH_GATEWAYS" entry \"%s\"; %d values",
22519880Swollman			       lptr, n);
22618316Swollman			continue;
22718316Swollman		}
22819880Swollman		if (metric >= HOPCNT_INFINITY) {
22918316Swollman			msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"",
23018316Swollman			       lptr);
23118316Swollman			continue;
23218316Swollman		}
23319880Swollman		if (!strcasecmp(net_host, "host")) {
23418316Swollman			if (!gethost(dname, &dst)) {
23518316Swollman				msglog("bad host \"%s\" in "_PATH_GATEWAYS
23618316Swollman				       " entry \"%s\"", dname, lptr);
23718316Swollman				continue;
23818316Swollman			}
23918316Swollman			netmask = HOST_MASK;
24019880Swollman		} else if (!strcasecmp(net_host, "net")) {
24118316Swollman			if (!getnet(dname, &dst, &netmask)) {
24218316Swollman				msglog("bad net \"%s\" in "_PATH_GATEWAYS
24318316Swollman				       " entry \"%s\"", dname, lptr);
24418316Swollman				continue;
24518316Swollman			}
24646303Smarkm			if (dst == RIP_DEFAULT) {
24746303Smarkm				msglog("bad net \"%s\" in "_PATH_GATEWAYS
24846303Smarkm				       " entry \"%s\"--cannot be default",
24946303Smarkm				       dname, lptr);
25046303Smarkm				continue;
25146303Smarkm			}
25290868Smike			/* Turn network # into IP address. */
25390868Smike			dst = htonl(dst);
25418316Swollman		} else {
25518316Swollman			msglog("bad \"%s\" in "_PATH_GATEWAYS
25646303Smarkm			       " entry \"%s\"", net_host, lptr);
25718316Swollman			continue;
25818316Swollman		}
25918316Swollman
26018316Swollman		if (!gethost(gname, &gate)) {
26118316Swollman			msglog("bad gateway \"%s\" in "_PATH_GATEWAYS
26218316Swollman			       " entry \"%s\"", gname, lptr);
26318316Swollman			continue;
26418316Swollman		}
26518316Swollman
26619880Swollman		if (!strcasecmp(qual, type = "passive")) {
26718316Swollman			/* Passive entries are not placed in our tables,
26818316Swollman			 * only the kernel's, so we don't copy all of the
26918316Swollman			 * external routing information within a net.
27018316Swollman			 * Internal machines should use the default
27118316Swollman			 * route to a suitable gateway (like us).
27218316Swollman			 */
27318316Swollman			state = IS_REMOTE | IS_PASSIVE;
27418316Swollman			if (metric == 0)
27518316Swollman				metric = 1;
27618316Swollman
27719880Swollman		} else if (!strcasecmp(qual, type = "external")) {
27818316Swollman			/* External entries are handled by other means
27918316Swollman			 * such as EGP, and are placed only in the daemon
28018316Swollman			 * tables to prevent overriding them with something
28118316Swollman			 * else.
28218316Swollman			 */
28319880Swollman			strcpy(qual,"external");
28418316Swollman			state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
28518316Swollman			if (metric == 0)
28618316Swollman				metric = 1;
28718316Swollman
28819880Swollman		} else if (!strcasecmp(qual, "active")
28919880Swollman			   || qual[0] == '\0') {
29018316Swollman			if (metric != 0) {
29118316Swollman				/* Entries that are neither "passive" nor
29218316Swollman				 * "external" are "remote" and must behave
29318316Swollman				 * like physical interfaces.  If they are not
29418316Swollman				 * heard from regularly, they are deleted.
29518316Swollman				 */
29618316Swollman				state = IS_REMOTE;
29718316Swollman				type = "remote";
29818316Swollman			} else {
29918316Swollman				/* "remote" entries with a metric of 0
30018316Swollman				 * are aliases for our own interfaces
30118316Swollman				 */
30219880Swollman				state = IS_REMOTE | IS_PASSIVE | IS_ALIAS;
30318316Swollman				type = "alias";
30418316Swollman			}
30518316Swollman
30618316Swollman		} else {
30719880Swollman			msglog("bad "_PATH_GATEWAYS" entry \"%s\";"
30819880Swollman			       " unknown type %s", lptr, qual);
30918316Swollman			continue;
31018316Swollman		}
31118316Swollman
31218316Swollman		if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
31318316Swollman			state |= IS_NO_RDISC;
31418316Swollman		if (state & IS_PASSIVE)
31519880Swollman			state |= IS_NO_RIP;
31618316Swollman
317126250Sbms		ifp = check_dup(gate,dst,netmask,state);
31818316Swollman		if (ifp != 0) {
31919880Swollman			msglog("duplicate "_PATH_GATEWAYS" entry \"%s\"",lptr);
32018316Swollman			continue;
32118316Swollman		}
32218316Swollman
32346303Smarkm		ifp = (struct interface *)rtmalloc(sizeof(*ifp), "gwkludge()");
32446303Smarkm		memset(ifp, 0, sizeof(*ifp));
32518316Swollman
32618316Swollman		ifp->int_state = state;
32718316Swollman		if (netmask == HOST_MASK)
32846303Smarkm			ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP;
32919880Swollman		else
33046303Smarkm			ifp->int_if_flags = IFF_UP;
33119880Swollman		ifp->int_act_time = NEVER;
33219880Swollman		ifp->int_addr = gate;
33318316Swollman		ifp->int_dstaddr = dst;
33419880Swollman		ifp->int_mask = netmask;
33519880Swollman		ifp->int_ripv1_mask = netmask;
33619880Swollman		ifp->int_std_mask = std_mask(gate);
33719880Swollman		ifp->int_net = ntohl(dst);
33819880Swollman		ifp->int_std_net = ifp->int_net & ifp->int_std_mask;
33919880Swollman		ifp->int_std_addr = htonl(ifp->int_std_net);
34018316Swollman		ifp->int_metric = metric;
34119880Swollman		if (!(state & IS_EXTERNAL)
34219880Swollman		    && ifp->int_mask != ifp->int_std_mask)
34319880Swollman			ifp->int_state |= IS_SUBNET;
34419880Swollman		(void)sprintf(ifp->int_name, "%s(%s)", type, gname);
34518316Swollman		ifp->int_index = -1;
34618316Swollman
34719880Swollman		if_link(ifp);
34819880Swollman	}
34919880Swollman
35019880Swollman	/* After all of the parameter lines have been read,
35119880Swollman	 * apply them to any remote interfaces.
35219880Swollman	 */
353190711Sphk	LIST_FOREACH(ifp, &ifnet, int_list) {
35418316Swollman		get_parms(ifp);
35518316Swollman
35619880Swollman		tot_interfaces++;
35719880Swollman		if (!IS_RIP_OFF(ifp->int_state))
35819880Swollman			rip_interfaces++;
35919880Swollman
36018316Swollman		trace_if("Add", ifp);
36118316Swollman	}
36220339Swollman
36320339Swollman	(void)fclose(fp);
36418316Swollman}
36518316Swollman
36618316Swollman
36746303Smarkm/* like strtok(), but honoring backslash and not changing the source string
36818316Swollman */
36920339Swollmanstatic int				/* 0=ok, -1=bad */
37046303Smarkmparse_quote(char **linep,		/* look here */
37146303Smarkm	    const char *delims,		/* for these delimiters */
37246303Smarkm	    char *delimp,		/* 0 or put found delimiter here */
37346303Smarkm	    char *buf,			/* copy token to here */
37446303Smarkm	    int	lim)			/* at most this many bytes */
37519880Swollman{
37646303Smarkm	char c = '\0', *pc;
37746303Smarkm	const char *p;
37819880Swollman
37919880Swollman
38019880Swollman	pc = *linep;
38119880Swollman	if (*pc == '\0')
38219880Swollman		return -1;
38319880Swollman
38420339Swollman	while (lim != 0) {
38519880Swollman		c = *pc++;
38619880Swollman		if (c == '\0')
38719880Swollman			break;
38819880Swollman
38937815Sphk		if (c == '\\' && *pc != '\0') {
39019880Swollman			if ((c = *pc++) == 'n') {
39119880Swollman				c = '\n';
39219880Swollman			} else if (c == 'r') {
39319880Swollman				c = '\r';
39419880Swollman			} else if (c == 't') {
39519880Swollman				c = '\t';
39619880Swollman			} else if (c == 'b') {
39719880Swollman				c = '\b';
39819880Swollman			} else if (c >= '0' && c <= '7') {
39919880Swollman				c -= '0';
40019880Swollman				if (*pc >= '0' && *pc <= '7') {
40119880Swollman					c = (c<<3)+(*pc++ - '0');
40219880Swollman					if (*pc >= '0' && *pc <= '7')
40319880Swollman					    c = (c<<3)+(*pc++ - '0');
40419880Swollman				}
40519880Swollman			}
40619880Swollman
40719880Swollman		} else {
40819880Swollman			for (p = delims; *p != '\0'; ++p) {
40919880Swollman				if (*p == c)
41019880Swollman					goto exit;
41119880Swollman			}
41219880Swollman		}
41319880Swollman
41419880Swollman		*buf++ = c;
41519880Swollman		--lim;
41619880Swollman	}
41719880Swollmanexit:
41820339Swollman	if (lim == 0)
41920339Swollman		return -1;
42020339Swollman
42146303Smarkm	*buf = '\0';			/* terminate copy of token */
42219880Swollman	if (delimp != 0)
42346303Smarkm		*delimp = c;		/* return delimiter */
42446303Smarkm	*linep = pc-1;			/* say where we ended */
42519880Swollman	return 0;
42619880Swollman}
42719880Swollman
42819880Swollman
42919880Swollman/* Parse password timestamp
43019880Swollman */
43119880Swollmanstatic char *
43219880Swollmanparse_ts(time_t *tp,
43319880Swollman	 char **valp,
43419880Swollman	 char *val0,
43519880Swollman	 char *delimp,
43619880Swollman	 char *buf,
43719880Swollman	 u_int bufsize)
43819880Swollman{
43919880Swollman	struct tm tm;
44046303Smarkm	char *ptr;
44119880Swollman
44219880Swollman	if (0 > parse_quote(valp, "| ,\n\r", delimp,
44319880Swollman			    buf,bufsize)
44419880Swollman	    || buf[bufsize-1] != '\0'
44519880Swollman	    || buf[bufsize-2] != '\0') {
44620339Swollman		sprintf(buf,"bad timestamp %.25s", val0);
44719880Swollman		return buf;
44819880Swollman	}
44919880Swollman	strcat(buf,"\n");
45046303Smarkm	memset(&tm, 0, sizeof(tm));
45146303Smarkm	ptr = strptime(buf, "%y/%m/%d@%H:%M\n", &tm);
45246303Smarkm	if (ptr == NULL || *ptr != '\0') {
45346303Smarkm		sprintf(buf,"bad timestamp %.25s", val0);
45446303Smarkm		return buf;
45546303Smarkm	}
45619880Swollman
45719880Swollman	if ((*tp = mktime(&tm)) == -1) {
45820339Swollman		sprintf(buf,"bad timestamp %.25s", val0);
45919880Swollman		return buf;
46019880Swollman	}
46119880Swollman
46219880Swollman	return 0;
46319880Swollman}
46419880Swollman
46519880Swollman
46620339Swollman/* Get a password, key ID, and expiration date in the format
46720339Swollman *	passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min
46819880Swollman */
46946303Smarkmstatic const char *			/* 0 or error message */
47020339Swollmanget_passwd(char *tgt,
47120339Swollman	   char *val,
47220339Swollman	   struct parm *parmp,
47346303Smarkm	   u_int16_t type,
47420339Swollman	   int safe)			/* 1=from secure file */
47519880Swollman{
47619880Swollman	static char buf[80];
47719880Swollman	char *val0, *p, delim;
47820339Swollman	struct auth k, *ap, *ap2;
47919880Swollman	int i;
48019880Swollman	u_long l;
48119880Swollman
482190718Sphk	assert(val != NULL);
48320339Swollman	if (!safe)
48446303Smarkm		return "ignore unsafe password";
48519880Swollman
48620339Swollman	for (ap = parmp->parm_auth, i = 0;
48720339Swollman	     ap->type != RIP_AUTH_NONE; i++, ap++) {
48820339Swollman		if (i >= MAX_AUTH_KEYS)
48920339Swollman			return "too many passwords";
49020339Swollman	}
49119880Swollman
49246303Smarkm	memset(&k, 0, sizeof(k));
49320339Swollman	k.type = type;
49420339Swollman	k.end = -1-DAY;
49519880Swollman
49620339Swollman	val0 = val;
49720339Swollman	if (0 > parse_quote(&val, "| ,\n\r", &delim,
49820339Swollman			    (char *)k.key, sizeof(k.key)))
49920339Swollman		return tgt;
50019880Swollman
50120339Swollman	if (delim != '|') {
50220339Swollman		if (type == RIP_AUTH_MD5)
50320339Swollman			return "missing Keyid";
50420339Swollman	} else {
50519880Swollman		val0 = ++val;
50620339Swollman		buf[sizeof(buf)-1] = '\0';
50719880Swollman		if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf))
50819880Swollman		    || buf[sizeof(buf)-1] != '\0'
50919880Swollman		    || (l = strtoul(buf,&p,0)) > 255
51019880Swollman		    || *p != '\0') {
51120339Swollman			sprintf(buf,"bad KeyID \"%.20s\"", val0);
51219880Swollman			return buf;
51319880Swollman		}
51420339Swollman		for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) {
51520339Swollman			if (ap2->keyid == l) {
51619880Swollman				sprintf(buf,"duplicate KeyID \"%.20s\"", val0);
51719880Swollman				return buf;
51819880Swollman			}
51919880Swollman		}
52020339Swollman		k.keyid = (int)l;
52119880Swollman
52220339Swollman		if (delim == '|') {
52320339Swollman			val0 = ++val;
52420339Swollman			if (0 != (p = parse_ts(&k.start,&val,val0,&delim,
52520339Swollman					       buf,sizeof(buf))))
52620339Swollman				return p;
52720339Swollman			if (delim != '|')
52820339Swollman				return "missing second timestamp";
52920339Swollman			val0 = ++val;
53020339Swollman			if (0 != (p = parse_ts(&k.end,&val,val0,&delim,
53120339Swollman					       buf,sizeof(buf))))
53220339Swollman				return p;
53320339Swollman			if ((u_long)k.start > (u_long)k.end) {
53420339Swollman				sprintf(buf,"out of order timestamp %.30s",
53520339Swollman					val0);
53620339Swollman				return buf;
53720339Swollman			}
53819880Swollman		}
53919880Swollman	}
54020339Swollman	if (delim != '\0')
54120339Swollman		return tgt;
54219880Swollman
54346303Smarkm	memmove(ap, &k, sizeof(*ap));
54420339Swollman	return 0;
54519880Swollman}
54619880Swollman
54719880Swollman
54846303Smarkmstatic const char *
54946303Smarkmbad_str(const char *estr)
55046303Smarkm{
55146303Smarkm	static char buf[100+8];
55246303Smarkm
55346303Smarkm	sprintf(buf, "bad \"%.100s\"", estr);
55446303Smarkm	return buf;
55546303Smarkm}
55646303Smarkm
55746303Smarkm
55819880Swollman/* Parse a set of parameters for an interface.
55919880Swollman */
56046303Smarkmconst char *					/* 0 or error message */
56120339Swollmanparse_parms(char *line,
56220339Swollman	    int safe)			/* 1=from secure file */
56318316Swollman{
56419880Swollman#define PARS(str) (!strcasecmp(tgt, str))
56519880Swollman#define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str)))
56618316Swollman#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break;	\
56718316Swollman	parm.parm_int_state |= (b);}
56818316Swollman	struct parm parm;
56918316Swollman	struct intnet *intnetp;
57046303Smarkm	struct r1net *r1netp;
57119880Swollman	struct tgate *tg;
57219880Swollman	naddr addr, mask;
57346303Smarkm	char delim, *val0 = 0, *tgt, *val, *p;
57446303Smarkm	const char *msg;
57546303Smarkm	char buf[BUFSIZ], buf2[BUFSIZ];
57646303Smarkm	int i;
57718316Swollman
57818316Swollman
57946303Smarkm	/* "subnet=x.y.z.u/mask[,metric]" must be alone on the line */
58019880Swollman	if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1)
58135306Sphk	    && *(val = &line[sizeof("subnet=")-1]) != '\0') {
58246303Smarkm		if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf)))
58346303Smarkm			return bad_str(line);
58446303Smarkm		intnetp = (struct intnet*)rtmalloc(sizeof(*intnetp),
58546303Smarkm						   "parse_parms subnet");
58618316Swollman		intnetp->intnet_metric = 1;
58746303Smarkm		if (delim == ',') {
58846303Smarkm			intnetp->intnet_metric = (int)strtol(val+1,&p,0);
58918316Swollman			if (*p != '\0'
59018316Swollman			    || intnetp->intnet_metric <= 0
59118316Swollman			    || intnetp->intnet_metric >= HOPCNT_INFINITY)
59246303Smarkm				return bad_str(line);
59318316Swollman		}
59446303Smarkm		if (!getnet(buf, &intnetp->intnet_addr, &intnetp->intnet_mask)
59518316Swollman		    || intnetp->intnet_mask == HOST_MASK
59618316Swollman		    || intnetp->intnet_addr == RIP_DEFAULT) {
59718316Swollman			free(intnetp);
59846303Smarkm			return bad_str(line);
59918316Swollman		}
60090868Smike		intnetp->intnet_addr = htonl(intnetp->intnet_addr);
60118316Swollman		intnetp->intnet_next = intnets;
60218316Swollman		intnets = intnetp;
60318316Swollman		return 0;
60418316Swollman	}
60518316Swollman
60646303Smarkm	/* "ripv1_mask=x.y.z.u/mask1,mask2" must be alone on the line.
60746303Smarkm	 * This requires that x.y.z.u/mask1 be considered a subnet of
60846303Smarkm	 * x.y.z.u/mask2, as if x.y.z.u/mask2 were a class-full network.
60946303Smarkm	 */
61046303Smarkm	if (!strncasecmp(line, "ripv1_mask=", sizeof("ripv1_mask=")-1)
61146303Smarkm	    && *(val = &line[sizeof("ripv1_mask=")-1]) != '\0') {
61246303Smarkm		if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf))
61346303Smarkm		    || delim == '\0')
61446303Smarkm			return bad_str(line);
61546303Smarkm		if ((i = (int)strtol(val+1, &p, 0)) <= 0
61646303Smarkm		    || i > 32 || *p != '\0')
61746303Smarkm			return bad_str(line);
61846303Smarkm		r1netp = (struct r1net *)rtmalloc(sizeof(*r1netp),
61946303Smarkm						  "parse_parms ripv1_mask");
62046303Smarkm		r1netp->r1net_mask = HOST_MASK << (32-i);
62146303Smarkm		if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match)
62246303Smarkm		    || r1netp->r1net_net == RIP_DEFAULT
62346303Smarkm		    || r1netp->r1net_mask > r1netp->r1net_match) {
62446303Smarkm			free(r1netp);
62546303Smarkm			return bad_str(line);
62646303Smarkm		}
62746303Smarkm		r1netp->r1net_next = r1nets;
62846303Smarkm		r1nets = r1netp;
62946303Smarkm		return 0;
63046303Smarkm	}
63118316Swollman
63246303Smarkm	memset(&parm, 0, sizeof(parm));
63346303Smarkm
63419880Swollman	for (;;) {
63519880Swollman		tgt = line + strspn(line, " ,\n\r");
63646303Smarkm		if (*tgt == '\0' || *tgt == '#')
63719880Swollman			break;
63846303Smarkm		line = tgt+strcspn(tgt, "= #,\n\r");
63919880Swollman		delim = *line;
64019880Swollman		if (delim == '=') {
64119880Swollman			val0 = ++line;
64246303Smarkm			if (0 > parse_quote(&line, " #,\n\r",&delim,
64319880Swollman					    buf,sizeof(buf)))
64446303Smarkm				return bad_str(tgt);
645190718Sphk		} else {
646190718Sphk			val0 = NULL;
64719880Swollman		}
64846303Smarkm		if (delim != '\0') {
64946303Smarkm			for (;;) {
65046303Smarkm				*line = '\0';
65146303Smarkm				if (delim == '#')
65246303Smarkm					break;
65346303Smarkm				++line;
65446303Smarkm				if (delim != ' '
65546303Smarkm				    || (delim = *line) != ' ')
65646303Smarkm					break;
65746303Smarkm			}
65846303Smarkm		}
65919880Swollman
66019880Swollman		if (PARSEQ("if")) {
66118316Swollman			if (parm.parm_name[0] != '\0'
66246303Smarkm			    || strlen(buf) > IF_NAME_LEN)
66346303Smarkm				return bad_str(tgt);
66419880Swollman			strcpy(parm.parm_name, buf);
66518316Swollman
66619880Swollman		} else if (PARSEQ("addr")) {
66719880Swollman			/* This is a bad idea, because the address based
66819880Swollman			 * sets of parameters cannot be checked for
66919880Swollman			 * consistency with the interface name parameters.
67019880Swollman			 * The parm_net stuff is needed to allow several
67119880Swollman			 * -F settings.
67219880Swollman			 */
67320339Swollman			if (!getnet(val0, &addr, &mask)
67419880Swollman			    || parm.parm_name[0] != '\0')
67546303Smarkm				return bad_str(tgt);
67619880Swollman			parm.parm_net = addr;
67719880Swollman			parm.parm_mask = mask;
67819880Swollman			parm.parm_name[0] = '\n';
67918316Swollman
68019880Swollman		} else if (PARSEQ("passwd")) {
68120339Swollman			/* since cleartext passwords are so weak allow
68220339Swollman			 * them anywhere
68320339Swollman			 */
68446303Smarkm			msg = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1);
68546303Smarkm			if (msg) {
68620339Swollman				*val0 = '\0';
68746303Smarkm				return bad_str(msg);
68820339Swollman			}
68919880Swollman
69019880Swollman		} else if (PARSEQ("md5_passwd")) {
69146303Smarkm			msg = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe);
69246303Smarkm			if (msg) {
69320339Swollman				*val0 = '\0';
69446303Smarkm				return bad_str(msg);
69520339Swollman			}
69619880Swollman
69718316Swollman		} else if (PARS("no_ag")) {
69818316Swollman			parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
69918316Swollman
70018316Swollman		} else if (PARS("no_super_ag")) {
70118316Swollman			parm.parm_int_state |= IS_NO_SUPER_AG;
70218316Swollman
70394125Sasmodai		} else if (PARS("no_rip_out")) {
70494125Sasmodai			parm.parm_int_state |= IS_NO_RIP_OUT;
70594125Sasmodai
70618316Swollman		} else if (PARS("no_ripv1_in")) {
70718316Swollman			parm.parm_int_state |= IS_NO_RIPV1_IN;
70818316Swollman
70918316Swollman		} else if (PARS("no_ripv2_in")) {
71018316Swollman			parm.parm_int_state |= IS_NO_RIPV2_IN;
71118316Swollman
71218316Swollman		} else if (PARS("ripv2_out")) {
71318316Swollman			if (parm.parm_int_state & IS_NO_RIPV2_OUT)
71446303Smarkm				return bad_str(tgt);
71518316Swollman			parm.parm_int_state |= IS_NO_RIPV1_OUT;
71618316Swollman
71719880Swollman		} else if (PARS("ripv2")) {
71819880Swollman			if ((parm.parm_int_state & IS_NO_RIPV2_OUT)
71919880Swollman			    || (parm.parm_int_state & IS_NO_RIPV2_IN))
72046303Smarkm				return bad_str(tgt);
72119880Swollman			parm.parm_int_state |= (IS_NO_RIPV1_IN
72219880Swollman						| IS_NO_RIPV1_OUT);
72319880Swollman
72418316Swollman		} else if (PARS("no_rip")) {
72519880Swollman			CKF(IS_PM_RDISC, IS_NO_RIP);
72618316Swollman
72746303Smarkm		} else if (PARS("no_rip_mcast")) {
72846303Smarkm			parm.parm_int_state |= IS_NO_RIP_MCAST;
72946303Smarkm
73018316Swollman		} else if (PARS("no_rdisc")) {
73146303Smarkm			CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
73218316Swollman
73318316Swollman		} else if (PARS("no_solicit")) {
73446303Smarkm			CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT);
73518316Swollman
73618316Swollman		} else if (PARS("send_solicit")) {
73746303Smarkm			CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT);
73818316Swollman
73918316Swollman		} else if (PARS("no_rdisc_adv")) {
74046303Smarkm			CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT);
74118316Swollman
74218316Swollman		} else if (PARS("rdisc_adv")) {
74346303Smarkm			CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT);
74418316Swollman
74518316Swollman		} else if (PARS("bcast_rdisc")) {
74618316Swollman			parm.parm_int_state |= IS_BCAST_RDISC;
74718316Swollman
74818316Swollman		} else if (PARS("passive")) {
74946303Smarkm			CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
750126250Sbms			parm.parm_int_state |= IS_NO_RIP | IS_PASSIVE;
75118316Swollman
75219880Swollman		} else if (PARSEQ("rdisc_pref")) {
75318316Swollman			if (parm.parm_rdisc_pref != 0
75446303Smarkm			    || (parm.parm_rdisc_pref = (int)strtol(buf,&p,0),
75518316Swollman				*p != '\0'))
75646303Smarkm				return bad_str(tgt);
75718316Swollman
75818316Swollman		} else if (PARS("pm_rdisc")) {
75919880Swollman			if (IS_RIP_OUT_OFF(parm.parm_int_state))
76046303Smarkm				return bad_str(tgt);
76118316Swollman			parm.parm_int_state |= IS_PM_RDISC;
76218316Swollman
76319880Swollman		} else if (PARSEQ("rdisc_interval")) {
76418316Swollman			if (parm.parm_rdisc_int != 0
76519880Swollman			    || (parm.parm_rdisc_int = (int)strtoul(buf,&p,0),
76618316Swollman				*p != '\0')
76718316Swollman			    || parm.parm_rdisc_int < MinMaxAdvertiseInterval
76818316Swollman			    || parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
76946303Smarkm				return bad_str(tgt);
77018316Swollman
77119880Swollman		} else if (PARSEQ("fake_default")) {
77218316Swollman			if (parm.parm_d_metric != 0
77319880Swollman			    || IS_RIP_OUT_OFF(parm.parm_int_state)
774126250Sbms			    || (i = strtoul(buf,&p,0), *p != '\0')
775126250Sbms			    || i > HOPCNT_INFINITY-1)
77646303Smarkm				return bad_str(tgt);
777126250Sbms			parm.parm_d_metric = i;
77818316Swollman
779126250Sbms		} else if (PARSEQ("adj_inmetric")) {
780126250Sbms			if (parm.parm_adj_inmetric != 0
781126250Sbms			    || (i = strtoul(buf,&p,0), *p != '\0')
782126250Sbms			    || i > HOPCNT_INFINITY-1)
783126250Sbms				return bad_str(tgt);
784126250Sbms			parm.parm_adj_inmetric = i;
785126250Sbms
786126250Sbms		} else if (PARSEQ("adj_outmetric")) {
787126250Sbms			if (parm.parm_adj_outmetric != 0
788126250Sbms			    || (i = strtoul(buf,&p,0), *p != '\0')
789126250Sbms			    || i > HOPCNT_INFINITY-1)
790126250Sbms				return bad_str(tgt);
791126250Sbms			parm.parm_adj_outmetric = i;
792126250Sbms
79319880Swollman		} else if (PARSEQ("trust_gateway")) {
79446303Smarkm			/* look for trust_gateway=x.y.z|net/mask|...) */
79546303Smarkm			p = buf;
79646303Smarkm			if (0 > parse_quote(&p, "|", &delim,
79746303Smarkm					    buf2, sizeof(buf2))
79846303Smarkm			    || !gethost(buf2,&addr))
79946303Smarkm				return bad_str(tgt);
80046303Smarkm			tg = (struct tgate *)rtmalloc(sizeof(*tg),
80146303Smarkm						      "parse_parms"
80246303Smarkm						      "trust_gateway");
80346303Smarkm			memset(tg, 0, sizeof(*tg));
80446303Smarkm			tg->tgate_addr = addr;
80546303Smarkm			i = 0;
80646303Smarkm			/* The default is to trust all routes. */
80746303Smarkm			while (delim == '|') {
80846303Smarkm				p++;
80946303Smarkm				if (i >= MAX_TGATE_NETS
81046303Smarkm				    || 0 > parse_quote(&p, "|", &delim,
81146303Smarkm						       buf2, sizeof(buf2))
81246303Smarkm				    || !getnet(buf2, &tg->tgate_nets[i].net,
81346303Smarkm					       &tg->tgate_nets[i].mask)
81446303Smarkm				    || tg->tgate_nets[i].net == RIP_DEFAULT
81546303Smarkm				    || tg->tgate_nets[i].mask == 0)
81646303Smarkm					return bad_str(tgt);
81746303Smarkm				i++;
81846303Smarkm			}
81919880Swollman			tg->tgate_next = tgates;
82019880Swollman			tgates = tg;
82119880Swollman			parm.parm_int_state |= IS_DISTRUST;
82219880Swollman
82320339Swollman		} else if (PARS("redirect_ok")) {
82420339Swollman			parm.parm_int_state |= IS_REDIRECT_OK;
82520339Swollman
82618316Swollman		} else {
82746303Smarkm			return bad_str(tgt);	/* error */
82818316Swollman		}
82918316Swollman	}
83018316Swollman
83118316Swollman	return check_parms(&parm);
83218316Swollman#undef PARS
83319880Swollman#undef PARSEQ
83418316Swollman}
83518316Swollman
83618316Swollman
83718316Swollman/* check for duplicate parameter specifications */
83846303Smarkmconst char *				/* 0 or error message */
83918316Swollmancheck_parms(struct parm *new)
84018316Swollman{
84120339Swollman	struct parm *parmp, **parmpp;
84220339Swollman	int i, num_passwds;
84318316Swollman
84418316Swollman	/* set implicit values
84518316Swollman	 */
84618316Swollman	if (new->parm_int_state & IS_NO_ADV_IN)
84718316Swollman		new->parm_int_state |= IS_NO_SOL_OUT;
84846303Smarkm	if (new->parm_int_state & IS_NO_SOL_OUT)
84946303Smarkm		new->parm_int_state |= IS_NO_ADV_IN;
85018316Swollman
85120339Swollman	for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
85220339Swollman		if (new->parm_auth[i].type != RIP_AUTH_NONE)
85320339Swollman			num_passwds++;
85420339Swollman	}
85520339Swollman
85618316Swollman	/* compare with existing sets of parameters
85718316Swollman	 */
85820339Swollman	for (parmpp = &parms;
85920339Swollman	     (parmp = *parmpp) != 0;
86020339Swollman	     parmpp = &parmp->parm_next) {
86118316Swollman		if (strcmp(new->parm_name, parmp->parm_name))
86218316Swollman			continue;
86319880Swollman		if (!on_net(htonl(parmp->parm_net),
86419880Swollman			    new->parm_net, new->parm_mask)
86519880Swollman		    && !on_net(htonl(new->parm_net),
86619880Swollman			       parmp->parm_net, parmp->parm_mask))
86718316Swollman			continue;
86818316Swollman
86920339Swollman		for (i = 0; i < MAX_AUTH_KEYS; i++) {
87020339Swollman			if (parmp->parm_auth[i].type != RIP_AUTH_NONE)
87120339Swollman				num_passwds++;
87219880Swollman		}
87320339Swollman		if (num_passwds > MAX_AUTH_KEYS)
87420339Swollman			return "too many conflicting passwords";
87519880Swollman
87646303Smarkm		if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT)
87746303Smarkm		     && 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT)
87819880Swollman		     && 0 != ((new->parm_int_state ^ parmp->parm_int_state)
879215702Sbrucec			      & GROUP_IS_SOL_OUT))
88046303Smarkm		    || (0 != (new->parm_int_state & GROUP_IS_ADV_OUT)
88146303Smarkm			&& 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT)
88218316Swollman			&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
883215702Sbrucec				 & GROUP_IS_ADV_OUT))
88418316Swollman		    || (new->parm_rdisc_pref != 0
88518316Swollman			&& parmp->parm_rdisc_pref != 0
88618316Swollman			&& new->parm_rdisc_pref != parmp->parm_rdisc_pref)
88718316Swollman		    || (new->parm_rdisc_int != 0
88818316Swollman			&& parmp->parm_rdisc_int != 0
88919880Swollman			&& new->parm_rdisc_int != parmp->parm_rdisc_int)) {
89019880Swollman			return ("conflicting, duplicate router discovery"
89119880Swollman				" parameters");
89219880Swollman
89319880Swollman		}
89419880Swollman
89519880Swollman		if (new->parm_d_metric != 0
89619880Swollman		     && parmp->parm_d_metric != 0
89719880Swollman		     && new->parm_d_metric != parmp->parm_d_metric) {
89819880Swollman			return ("conflicting, duplicate poor man's router"
89919880Swollman				" discovery or fake default metric");
90019880Swollman		}
901126250Sbms
902126250Sbms		if (new->parm_adj_inmetric != 0
903126250Sbms		    && parmp->parm_adj_inmetric != 0
904126250Sbms		    && new->parm_adj_inmetric != parmp->parm_adj_inmetric) {
905126250Sbms			return ("conflicting interface input "
906126250Sbms				"metric adjustments");
907126250Sbms		}
908126250Sbms
909126250Sbms		if (new->parm_adj_outmetric != 0
910126250Sbms		    && parmp->parm_adj_outmetric != 0
911126250Sbms		    && new->parm_adj_outmetric != parmp->parm_adj_outmetric) {
912126250Sbms			return ("conflicting interface output "
913126250Sbms				"metric adjustments");
914126250Sbms		}
91518316Swollman	}
91618316Swollman
917126250Sbms	/* link new entry on the list so that when the entries are scanned,
91820339Swollman	 * they affect the result in the order the operator specified.
91920339Swollman	 */
92037908Scharnier	parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms");
92146303Smarkm	memcpy(parmp, new, sizeof(*parmp));
92220339Swollman	*parmpp = parmp;
92318316Swollman
92418316Swollman	return 0;
92518316Swollman}
92618316Swollman
92718316Swollman
92818316Swollman/* get a network number as a name or a number, with an optional "/xx"
92918316Swollman * netmask.
93018316Swollman */
93118316Swollmanint					/* 0=bad */
93218316Swollmangetnet(char *name,
93346303Smarkm       naddr *netp,			/* network in host byte order */
93420339Swollman       naddr *maskp)			/* masks are always in host order */
93518316Swollman{
93618316Swollman	int i;
93718316Swollman	struct netent *np;
93820339Swollman	naddr mask;			/* in host byte order */
93920339Swollman	struct in_addr in;		/* a network and so host byte order */
94018316Swollman	char hname[MAXHOSTNAMELEN+1];
94118316Swollman	char *mname, *p;
94218316Swollman
94318316Swollman
94418316Swollman	/* Detect and separate "1.2.3.4/24"
94518316Swollman	 */
94646303Smarkm	if (0 != (mname = strrchr(name,'/'))) {
94718316Swollman		i = (int)(mname - name);
94846303Smarkm		if (i > (int)sizeof(hname)-1)	/* name too long */
94918316Swollman			return 0;
95046303Smarkm		memmove(hname, name, i);
95118316Swollman		hname[i] = '\0';
95218316Swollman		mname++;
95318316Swollman		name = hname;
95418316Swollman	}
95518316Swollman
95618316Swollman	np = getnetbyname(name);
95718316Swollman	if (np != 0) {
95818316Swollman		in.s_addr = (naddr)np->n_net;
95946303Smarkm		if (0 == (in.s_addr & 0xff000000))
96046303Smarkm			in.s_addr <<= 8;
96146303Smarkm		if (0 == (in.s_addr & 0xff000000))
96246303Smarkm			in.s_addr <<= 8;
96346303Smarkm		if (0 == (in.s_addr & 0xff000000))
96446303Smarkm			in.s_addr <<= 8;
96518316Swollman	} else if (inet_aton(name, &in) == 1) {
96690868Smike		in.s_addr = ntohl(in.s_addr);
96719880Swollman	} else if (!mname && !strcasecmp(name,"default")) {
96819880Swollman		in.s_addr = RIP_DEFAULT;
96918316Swollman	} else {
97018316Swollman		return 0;
97118316Swollman	}
97218316Swollman
97319880Swollman	if (!mname) {
97418316Swollman		/* we cannot use the interfaces here because we have not
97518316Swollman		 * looked at them yet.
97618316Swollman		 */
97720339Swollman		mask = std_mask(htonl(in.s_addr));
97819880Swollman		if ((~mask & in.s_addr) != 0)
97918316Swollman			mask = HOST_MASK;
98018316Swollman	} else {
98118316Swollman		mask = (naddr)strtoul(mname, &p, 0);
98218316Swollman		if (*p != '\0' || mask > 32)
98318316Swollman			return 0;
98446303Smarkm		if (mask != 0)
98546303Smarkm			mask = HOST_MASK << (32-mask);
98618316Swollman	}
98719880Swollman
98819880Swollman	/* must have mask of 0 with default */
98918316Swollman	if (mask != 0 && in.s_addr == RIP_DEFAULT)
99018316Swollman		return 0;
99119880Swollman	/* no host bits allowed in a network number */
99219880Swollman	if ((~mask & in.s_addr) != 0)
99318316Swollman		return 0;
99419880Swollman	/* require non-zero network number */
99519880Swollman	if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT)
99619880Swollman		return 0;
99719880Swollman	if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT)
99819880Swollman		return 0;
99919880Swollman	if (in.s_addr>>24 == 0xff)
100019880Swollman		return 0;
100118316Swollman
100219880Swollman	*netp = in.s_addr;
100318316Swollman	*maskp = mask;
100418316Swollman	return 1;
100518316Swollman}
100618316Swollman
100718316Swollman
100818316Swollmanint					/* 0=bad */
100918316Swollmangethost(char *name,
101018316Swollman	naddr *addrp)
101118316Swollman{
101218316Swollman	struct hostent *hp;
101318316Swollman	struct in_addr in;
101418316Swollman
101518316Swollman
101618316Swollman	/* Try for a number first, even in IRIX where gethostbyname()
101718316Swollman	 * is smart.  This avoids hitting the name server which
101818316Swollman	 * might be sick because routing is.
101918316Swollman	 */
102018316Swollman	if (inet_aton(name, &in) == 1) {
102119880Swollman		/* get a good number, but check that it it makes some
102219880Swollman		 * sense.
102319880Swollman		 */
102419880Swollman		if (ntohl(in.s_addr)>>24 == 0
102519880Swollman		    || ntohl(in.s_addr)>>24 == 0xff)
102619880Swollman			return 0;
102718316Swollman		*addrp = in.s_addr;
102818316Swollman		return 1;
102918316Swollman	}
103018316Swollman
103118316Swollman	hp = gethostbyname(name);
103218316Swollman	if (hp) {
103346303Smarkm		memcpy(addrp, hp->h_addr, sizeof(*addrp));
103418316Swollman		return 1;
103518316Swollman	}
103618316Swollman
103718316Swollman	return 0;
103818316Swollman}
1039