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