parms.c revision 1.1.1.4 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 acknowledgement:
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(lint) && !defined(sgi) && !defined(__NetBSD__)
35 static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
36 #elif defined(__NetBSD__)
37 static char rcsid[] = "$NetBSD: parms.c,v 1.1.1.4 1998/06/02 17:41:26 thorpej Exp $";
38 #endif
39 #ident "$Revision: 1.1.1.4 $"
40
41 #include "defs.h"
42 #include "pathnames.h"
43 #include <sys/stat.h>
44
45
46 struct parm *parms;
47 struct intnet *intnets;
48 struct r1net *r1nets;
49 struct tgate *tgates;
50
51
52 /* use configured parameters
53 */
54 void
55 get_parms(struct interface *ifp)
56 {
57 static warned_auth_in, warned_auth_out;
58 struct parm *parmp;
59 int i, num_passwds = 0;
60
61 /* get all relevant parameters
62 */
63 for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
64 if (parmp->parm_name[0] == '\0'
65 || !strcmp(ifp->int_name, parmp->parm_name)
66 || (parmp->parm_name[0] == '\n'
67 && on_net(ifp->int_addr,
68 parmp->parm_net, parmp->parm_mask))) {
69
70 /* This group of parameters is relevant,
71 * so get its settings
72 */
73 ifp->int_state |= parmp->parm_int_state;
74 for (i = 0; i < MAX_AUTH_KEYS; i++) {
75 if (parmp->parm_auth[0].type == RIP_AUTH_NONE
76 || num_passwds >= MAX_AUTH_KEYS)
77 break;
78 bcopy(&parmp->parm_auth[i],
79 &ifp->int_auth[num_passwds++],
80 sizeof(ifp->int_auth[0]));
81 }
82 if (parmp->parm_rdisc_pref != 0)
83 ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
84 if (parmp->parm_rdisc_int != 0)
85 ifp->int_rdisc_int = parmp->parm_rdisc_int;
86 if (parmp->parm_d_metric != 0)
87 ifp->int_d_metric = parmp->parm_d_metric;
88 }
89 }
90
91 /* Set general defaults.
92 *
93 * Default poor-man's router discovery to a metric that will
94 * be heard by old versions of `routed`. They ignored received
95 * routes with metric 15.
96 */
97 if ((ifp->int_state & IS_PM_RDISC)
98 && ifp->int_d_metric == 0)
99 ifp->int_d_metric = FAKE_METRIC;
100
101 if (ifp->int_rdisc_int == 0)
102 ifp->int_rdisc_int = DefMaxAdvertiseInterval;
103
104 if (!(ifp->int_if_flags & IFF_MULTICAST)
105 && !(ifp->int_state & IS_REMOTE))
106 ifp->int_state |= IS_BCAST_RDISC;
107
108 if (ifp->int_if_flags & IFF_POINTOPOINT) {
109 ifp->int_state |= IS_BCAST_RDISC;
110 /* By default, point-to-point links should be passive
111 * about router-discovery for the sake of demand-dialing.
112 */
113 if (0 == (ifp->int_state & GROUP_IS_SOL_OUT))
114 ifp->int_state |= IS_NO_SOL_OUT;
115 if (0 == (ifp->int_state & GROUP_IS_ADV_OUT))
116 ifp->int_state |= IS_NO_ADV_OUT;
117 }
118
119 if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE)))
120 ifp->int_state |= IS_NO_RDISC;
121 if (ifp->int_state & IS_PASSIVE)
122 ifp->int_state |= IS_NO_RIP;
123
124 if (!IS_RIP_IN_OFF(ifp->int_state)
125 && ifp->int_auth[0].type != RIP_AUTH_NONE
126 && !(ifp->int_state & IS_NO_RIPV1_IN)
127 && !warned_auth_in) {
128 msglog("Warning: RIPv1 input via %s"
129 " will be accepted without authentication",
130 ifp->int_name);
131 warned_auth_in = 1;
132 }
133 if (!IS_RIP_OUT_OFF(ifp->int_state)
134 && ifp->int_auth[0].type != RIP_AUTH_NONE
135 && !(ifp->int_state & IS_NO_RIPV1_OUT)) {
136 if (!warned_auth_out) {
137 msglog("Warning: RIPv1 output via %s"
138 " will be sent without authentication",
139 ifp->int_name);
140 warned_auth_out = 1;
141 }
142 }
143 }
144
145
146 /* Read a list of gateways from /etc/gateways and add them to our tables.
147 *
148 * This file contains a list of "remote" gateways. That is usually
149 * a gateway which we cannot immediately determine if it is present or
150 * not as we can do for those provided by directly connected hardware.
151 *
152 * If a gateway is marked "passive" in the file, then we assume it
153 * does not understand RIP and assume it is always present. Those
154 * not marked passive are treated as if they were directly connected
155 * and assumed to be broken if they do not send us advertisements.
156 * All remote interfaces are added to our list, and those not marked
157 * passive are sent routing updates.
158 *
159 * A passive interface can also be local, hardware interface exempt
160 * from RIP.
161 */
162 void
163 gwkludge(void)
164 {
165 FILE *fp;
166 char *p, *lptr;
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 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)-1, 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 p = parse_parms(lptr,
206 (sb.st_uid == 0
207 && !(sb.st_mode&(S_IRWXG|S_IRWXO))));
208 if (p != 0)
209 msglog("%s in line %d of "_PATH_GATEWAYS,
210 p, 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\"", 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 bzero(ifp, 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 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, *pc, *p;
373
374
375 pc = *linep;
376 if (*pc == '\0')
377 return -1;
378
379 while (lim != 0) {
380 c = *pc++;
381 if (c == '\0')
382 break;
383
384 if (c == '\\' && pc != '\0') {
385 if ((c = *pc++) == 'n') {
386 c = '\n';
387 } else if (c == 'r') {
388 c = '\r';
389 } else if (c == 't') {
390 c = '\t';
391 } else if (c == 'b') {
392 c = '\b';
393 } else if (c >= '0' && c <= '7') {
394 c -= '0';
395 if (*pc >= '0' && *pc <= '7') {
396 c = (c<<3)+(*pc++ - '0');
397 if (*pc >= '0' && *pc <= '7')
398 c = (c<<3)+(*pc++ - '0');
399 }
400 }
401
402 } else {
403 for (p = delims; *p != '\0'; ++p) {
404 if (*p == c)
405 goto exit;
406 }
407 }
408
409 *buf++ = c;
410 --lim;
411 }
412 exit:
413 if (lim == 0)
414 return -1;
415
416 *buf = '\0'; /* terminate copy of token */
417 if (delimp != 0)
418 *delimp = c; /* return delimiter */
419 *linep = pc-1; /* say where we ended */
420 return 0;
421 }
422
423
424 /* Parse password timestamp
425 */
426 static char *
427 parse_ts(time_t *tp,
428 char **valp,
429 char *val0,
430 char *delimp,
431 char *buf,
432 u_int bufsize)
433 {
434 struct tm tm;
435
436 if (0 > parse_quote(valp, "| ,\n\r", delimp,
437 buf,bufsize)
438 || buf[bufsize-1] != '\0'
439 || buf[bufsize-2] != '\0') {
440 sprintf(buf,"bad timestamp %.25s", val0);
441 return buf;
442 }
443 strcat(buf,"\n");
444 bzero(&tm, sizeof(tm));
445 if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n",
446 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
447 &tm.tm_hour, &tm.tm_min)) {
448 sprintf(buf,"bad timestamp %.25s", val0);
449 return buf;
450 }
451 if (tm.tm_year <= 37)
452 tm.tm_year += 100;
453
454 if ((*tp = mktime(&tm)) == -1) {
455 sprintf(buf,"bad timestamp %.25s", val0);
456 return buf;
457 }
458
459 return 0;
460 }
461
462
463 /* Get a password, key ID, and expiration date in the format
464 * passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min
465 */
466 static char * /* 0 or error message */
467 get_passwd(char *tgt,
468 char *val,
469 struct parm *parmp,
470 u_char type,
471 int safe) /* 1=from secure file */
472 {
473 static char buf[80];
474 char *val0, *p, delim;
475 struct auth k, *ap, *ap2;
476 int i;
477 u_long l;
478
479
480 if (!safe)
481 return "ignore unsafe password";
482
483 for (ap = parmp->parm_auth, i = 0;
484 ap->type != RIP_AUTH_NONE; i++, ap++) {
485 if (i >= MAX_AUTH_KEYS)
486 return "too many passwords";
487 }
488
489 bzero(&k, sizeof(k));
490 k.type = type;
491 k.end = -1-DAY;
492
493 val0 = val;
494 if (0 > parse_quote(&val, "| ,\n\r", &delim,
495 (char *)k.key, sizeof(k.key)))
496 return tgt;
497
498 if (delim != '|') {
499 if (type == RIP_AUTH_MD5)
500 return "missing Keyid";
501 } else {
502 val0 = ++val;
503 buf[sizeof(buf)-1] = '\0';
504 if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf))
505 || buf[sizeof(buf)-1] != '\0'
506 || (l = strtoul(buf,&p,0)) > 255
507 || *p != '\0') {
508 sprintf(buf,"bad KeyID \"%.20s\"", val0);
509 return buf;
510 }
511 for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) {
512 if (ap2->keyid == l) {
513 sprintf(buf,"duplicate KeyID \"%.20s\"", val0);
514 return buf;
515 }
516 }
517 k.keyid = (int)l;
518
519 if (delim == '|') {
520 val0 = ++val;
521 if (0 != (p = parse_ts(&k.start,&val,val0,&delim,
522 buf,sizeof(buf))))
523 return p;
524 if (delim != '|')
525 return "missing second timestamp";
526 val0 = ++val;
527 if (0 != (p = parse_ts(&k.end,&val,val0,&delim,
528 buf,sizeof(buf))))
529 return p;
530 if ((u_long)k.start > (u_long)k.end) {
531 sprintf(buf,"out of order timestamp %.30s",
532 val0);
533 return buf;
534 }
535 }
536 }
537 if (delim != '\0')
538 return tgt;
539
540 bcopy(&k, ap, sizeof(*ap));
541 return 0;
542 }
543
544
545 static char *
546 bad_str(char *estr)
547 {
548 static char buf[100+8];
549
550 sprintf(buf, "bad \"%.100s\"", estr);
551 return buf;
552 }
553
554
555 /* Parse a set of parameters for an interface.
556 */
557 char * /* 0 or error message */
558 parse_parms(char *line,
559 int safe) /* 1=from secure file */
560 {
561 #define PARS(str) (!strcasecmp(tgt, str))
562 #define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str)))
563 #define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \
564 parm.parm_int_state |= (b);}
565 struct parm parm;
566 struct intnet *intnetp;
567 struct r1net *r1netp;
568 struct tgate *tg;
569 naddr addr, mask;
570 char delim, *val0, *tgt, *val, *p;
571 char buf[BUFSIZ], buf2[BUFSIZ];
572 int i;
573
574
575 /* "subnet=x.y.z.u/mask[,metric]" must be alone on the line */
576 if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1)
577 && *(val = &line[sizeof("subnet=")-1]) != '\0') {
578 if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf)))
579 return bad_str(line);
580 intnetp = (struct intnet*)rtmalloc(sizeof(*intnetp),
581 "parse_parms subnet");
582 intnetp->intnet_metric = 1;
583 if (delim == ',') {
584 intnetp->intnet_metric = (int)strtol(val+1,&p,0);
585 if (*p != '\0'
586 || intnetp->intnet_metric <= 0
587 || intnetp->intnet_metric >= HOPCNT_INFINITY)
588 return bad_str(line);
589 }
590 if (!getnet(buf, &intnetp->intnet_addr, &intnetp->intnet_mask)
591 || intnetp->intnet_mask == HOST_MASK
592 || intnetp->intnet_addr == RIP_DEFAULT) {
593 free(intnetp);
594 return bad_str(line);
595 }
596 HTONL(intnetp->intnet_addr);
597 intnetp->intnet_next = intnets;
598 intnets = intnetp;
599 return 0;
600 }
601
602 /* "ripv1_mask=x.y.z.u/mask,mask" must be alone on the line */
603 if (!strncasecmp(line, "ripv1_mask=", sizeof("ripv1_mask=")-1)
604 && *(val = &line[sizeof("ripv1_mask=")-1]) != '\0') {
605 if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf))
606 || delim == '\0')
607 return bad_str(line);
608 if ((i = (int)strtol(val+1, &p, 0)) <= 0
609 || i > 32 || *p != '\0')
610 return bad_str(line);
611 r1netp = (struct r1net *)rtmalloc(sizeof(*r1netp),
612 "parse_parms ripv1_mask");
613 r1netp->r1net_mask = HOST_MASK << (32-i);
614 if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match)
615 || r1netp->r1net_net == RIP_DEFAULT
616 || r1netp->r1net_mask < r1netp->r1net_match) {
617 free(r1netp);
618 return bad_str(line);
619 }
620 r1netp->r1net_next = r1nets;
621 r1nets = r1netp;
622 return 0;
623 }
624
625 bzero(&parm, sizeof(parm));
626
627 tgt = "null";
628 for (;;) {
629 tgt = line + strspn(line, " ,\n\r");
630 if (*tgt == '\0' || *tgt == '#')
631 break;
632 line = tgt+strcspn(tgt, "= #,\n\r");
633 delim = *line;
634 if (delim == '=') {
635 val0 = ++line;
636 if (0 > parse_quote(&line, " #,\n\r",&delim,
637 buf,sizeof(buf)))
638 return bad_str(tgt);
639 }
640 if (delim != '\0') {
641 for (;;) {
642 *line = '\0';
643 if (delim == '#')
644 break;
645 ++line;
646 if (delim != ' '
647 || (delim = *line) != ' ')
648 break;
649 }
650 }
651
652 if (PARSEQ("if")) {
653 if (parm.parm_name[0] != '\0'
654 || strlen(buf) > IF_NAME_LEN)
655 return bad_str(tgt);
656 strcpy(parm.parm_name, buf);
657
658 } else if (PARSEQ("addr")) {
659 /* This is a bad idea, because the address based
660 * sets of parameters cannot be checked for
661 * consistency with the interface name parameters.
662 * The parm_net stuff is needed to allow several
663 * -F settings.
664 */
665 if (!getnet(val0, &addr, &mask)
666 || parm.parm_name[0] != '\0')
667 return bad_str(tgt);
668 parm.parm_net = addr;
669 parm.parm_mask = mask;
670 parm.parm_name[0] = '\n';
671
672 } else if (PARSEQ("passwd")) {
673 /* since cleartext passwords are so weak allow
674 * them anywhere
675 */
676 tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1);
677 if (tgt) {
678 *val0 = '\0';
679 return bad_str(tgt);
680 }
681
682 } else if (PARSEQ("md5_passwd")) {
683 tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe);
684 if (tgt) {
685 *val0 = '\0';
686 return bad_str(tgt);
687 }
688
689 } else if (PARS("no_ag")) {
690 parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
691
692 } else if (PARS("no_super_ag")) {
693 parm.parm_int_state |= IS_NO_SUPER_AG;
694
695 } else if (PARS("no_ripv1_in")) {
696 parm.parm_int_state |= IS_NO_RIPV1_IN;
697
698 } else if (PARS("no_ripv2_in")) {
699 parm.parm_int_state |= IS_NO_RIPV2_IN;
700
701 } else if (PARS("ripv2_out")) {
702 if (parm.parm_int_state & IS_NO_RIPV2_OUT)
703 return bad_str(tgt);
704 parm.parm_int_state |= IS_NO_RIPV1_OUT;
705
706 } else if (PARS("ripv2")) {
707 if ((parm.parm_int_state & IS_NO_RIPV2_OUT)
708 || (parm.parm_int_state & IS_NO_RIPV2_IN))
709 return bad_str(tgt);
710 parm.parm_int_state |= (IS_NO_RIPV1_IN
711 | IS_NO_RIPV1_OUT);
712
713 } else if (PARS("no_rip")) {
714 CKF(IS_PM_RDISC, IS_NO_RIP);
715
716 } else if (PARS("no_rip_mcast")) {
717 parm.parm_int_state |= IS_NO_RIP_MCAST;
718
719 } else if (PARS("no_rdisc")) {
720 CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
721
722 } else if (PARS("no_solicit")) {
723 CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT);
724
725 } else if (PARS("send_solicit")) {
726 CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT);
727
728 } else if (PARS("no_rdisc_adv")) {
729 CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT);
730
731 } else if (PARS("rdisc_adv")) {
732 CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT);
733
734 } else if (PARS("bcast_rdisc")) {
735 parm.parm_int_state |= IS_BCAST_RDISC;
736
737 } else if (PARS("passive")) {
738 CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
739 parm.parm_int_state |= IS_NO_RIP;
740
741 } else if (PARSEQ("rdisc_pref")) {
742 if (parm.parm_rdisc_pref != 0
743 || (parm.parm_rdisc_pref = (int)strtol(buf,&p,0),
744 *p != '\0'))
745 return bad_str(tgt);
746
747 } else if (PARS("pm_rdisc")) {
748 if (IS_RIP_OUT_OFF(parm.parm_int_state))
749 return bad_str(tgt);
750 parm.parm_int_state |= IS_PM_RDISC;
751
752 } else if (PARSEQ("rdisc_interval")) {
753 if (parm.parm_rdisc_int != 0
754 || (parm.parm_rdisc_int = (int)strtoul(buf,&p,0),
755 *p != '\0')
756 || parm.parm_rdisc_int < MinMaxAdvertiseInterval
757 || parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
758 return bad_str(tgt);
759
760 } else if (PARSEQ("fake_default")) {
761 if (parm.parm_d_metric != 0
762 || IS_RIP_OUT_OFF(parm.parm_int_state)
763 || (parm.parm_d_metric = (int)strtoul(buf,&p,0),
764 *p != '\0')
765 || parm.parm_d_metric > HOPCNT_INFINITY-1)
766 return bad_str(tgt);
767
768 } else if (PARSEQ("trust_gateway")) {
769 /* look for trust_gateway=x.y.z|net/mask|...) */
770 p = buf;
771 if (0 > parse_quote(&p, "|", &delim,
772 buf2, sizeof(buf2))
773 || !gethost(buf2,&addr))
774 return bad_str(tgt);
775 tg = (struct tgate *)rtmalloc(sizeof(*tg),
776 "parse_parms"
777 "trust_gateway");
778 bzero(tg, sizeof(*tg));
779 tg->tgate_addr = addr;
780 i = 0;
781 /* The default is to trust all routes. */
782 while (delim == '|') {
783 p++;
784 if (i >= MAX_TGATE_NETS
785 || 0 > parse_quote(&p, "|", &delim,
786 buf2, sizeof(buf2))
787 || !getnet(buf2, &tg->tgate_nets[i].net,
788 &tg->tgate_nets[i].mask)
789 || tg->tgate_nets[i].net == RIP_DEFAULT
790 || tg->tgate_nets[i].mask == 0)
791 return bad_str(tgt);
792 i++;
793 }
794 tg->tgate_next = tgates;
795 tgates = tg;
796 parm.parm_int_state |= IS_DISTRUST;
797
798 } else if (PARS("redirect_ok")) {
799 parm.parm_int_state |= IS_REDIRECT_OK;
800
801 } else {
802 return bad_str(tgt); /* error */
803 }
804 }
805
806 return check_parms(&parm);
807 #undef PARS
808 #undef PARSEQ
809 }
810
811
812 /* check for duplicate parameter specifications */
813 char * /* 0 or error message */
814 check_parms(struct parm *new)
815 {
816 struct parm *parmp, **parmpp;
817 int i, num_passwds;
818
819 /* set implicit values
820 */
821 if (new->parm_int_state & IS_NO_ADV_IN)
822 new->parm_int_state |= IS_NO_SOL_OUT;
823 if (new->parm_int_state & IS_NO_SOL_OUT)
824 new->parm_int_state |= IS_NO_ADV_IN;
825
826 for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
827 if (new->parm_auth[i].type != RIP_AUTH_NONE)
828 num_passwds++;
829 }
830
831 /* compare with existing sets of parameters
832 */
833 for (parmpp = &parms;
834 (parmp = *parmpp) != 0;
835 parmpp = &parmp->parm_next) {
836 if (strcmp(new->parm_name, parmp->parm_name))
837 continue;
838 if (!on_net(htonl(parmp->parm_net),
839 new->parm_net, new->parm_mask)
840 && !on_net(htonl(new->parm_net),
841 parmp->parm_net, parmp->parm_mask))
842 continue;
843
844 for (i = 0; i < MAX_AUTH_KEYS; i++) {
845 if (parmp->parm_auth[i].type != RIP_AUTH_NONE)
846 num_passwds++;
847 }
848 if (num_passwds > MAX_AUTH_KEYS)
849 return "too many conflicting passwords";
850
851 if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT)
852 && 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT)
853 && 0 != ((new->parm_int_state ^ parmp->parm_int_state)
854 && GROUP_IS_SOL_OUT))
855 || (0 != (new->parm_int_state & GROUP_IS_ADV_OUT)
856 && 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT)
857 && 0 != ((new->parm_int_state ^ parmp->parm_int_state)
858 && GROUP_IS_ADV_OUT))
859 || (new->parm_rdisc_pref != 0
860 && parmp->parm_rdisc_pref != 0
861 && new->parm_rdisc_pref != parmp->parm_rdisc_pref)
862 || (new->parm_rdisc_int != 0
863 && parmp->parm_rdisc_int != 0
864 && new->parm_rdisc_int != parmp->parm_rdisc_int)) {
865 return ("conflicting, duplicate router discovery"
866 " parameters");
867
868 }
869
870 if (new->parm_d_metric != 0
871 && parmp->parm_d_metric != 0
872 && new->parm_d_metric != parmp->parm_d_metric) {
873 return ("conflicting, duplicate poor man's router"
874 " discovery or fake default metric");
875 }
876 }
877
878 /* link new entry on the so that when the entries are scanned,
879 * they affect the result in the order the operator specified.
880 */
881 parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms");
882 bcopy(new, parmp, sizeof(*parmp));
883 *parmpp = parmp;
884
885 return 0;
886 }
887
888
889 /* get a network number as a name or a number, with an optional "/xx"
890 * netmask.
891 */
892 int /* 0=bad */
893 getnet(char *name,
894 naddr *netp, /* network in host byte order */
895 naddr *maskp) /* masks are always in host order */
896 {
897 int i;
898 struct netent *np;
899 naddr mask; /* in host byte order */
900 struct in_addr in; /* a network and so host byte order */
901 char hname[MAXHOSTNAMELEN+1];
902 char *mname, *p;
903
904
905 /* Detect and separate "1.2.3.4/24"
906 */
907 if (0 != (mname = rindex(name,'/'))) {
908 i = (int)(mname - name);
909 if (i > sizeof(hname)-1) /* name too long */
910 return 0;
911 bcopy(name, hname, i);
912 hname[i] = '\0';
913 mname++;
914 name = hname;
915 }
916
917 np = getnetbyname(name);
918 if (np != 0) {
919 in.s_addr = (naddr)np->n_net;
920 if (0 == (in.s_addr & 0xff000000))
921 in.s_addr <<= 8;
922 if (0 == (in.s_addr & 0xff000000))
923 in.s_addr <<= 8;
924 if (0 == (in.s_addr & 0xff000000))
925 in.s_addr <<= 8;
926 } else if (inet_aton(name, &in) == 1) {
927 NTOHL(in.s_addr);
928 } else if (!mname && !strcasecmp(name,"default")) {
929 in.s_addr = RIP_DEFAULT;
930 } else {
931 return 0;
932 }
933
934 if (!mname) {
935 /* we cannot use the interfaces here because we have not
936 * looked at them yet.
937 */
938 mask = std_mask(htonl(in.s_addr));
939 if ((~mask & in.s_addr) != 0)
940 mask = HOST_MASK;
941 } else {
942 mask = (naddr)strtoul(mname, &p, 0);
943 if (*p != '\0' || mask > 32)
944 return 0;
945 mask = HOST_MASK << (32-mask);
946 }
947
948 /* must have mask of 0 with default */
949 if (mask != 0 && in.s_addr == RIP_DEFAULT)
950 return 0;
951 /* no host bits allowed in a network number */
952 if ((~mask & in.s_addr) != 0)
953 return 0;
954 /* require non-zero network number */
955 if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT)
956 return 0;
957 if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT)
958 return 0;
959 if (in.s_addr>>24 == 0xff)
960 return 0;
961
962 *netp = in.s_addr;
963 *maskp = mask;
964 return 1;
965 }
966
967
968 int /* 0=bad */
969 gethost(char *name,
970 naddr *addrp)
971 {
972 struct hostent *hp;
973 struct in_addr in;
974
975
976 /* Try for a number first, even in IRIX where gethostbyname()
977 * is smart. This avoids hitting the name server which
978 * might be sick because routing is.
979 */
980 if (inet_aton(name, &in) == 1) {
981 /* get a good number, but check that it it makes some
982 * sense.
983 */
984 if (ntohl(in.s_addr)>>24 == 0
985 || ntohl(in.s_addr)>>24 == 0xff)
986 return 0;
987 *addrp = in.s_addr;
988 return 1;
989 }
990
991 hp = gethostbyname(name);
992 if (hp) {
993 bcopy(hp->h_addr, addrp, sizeof(*addrp));
994 return 1;
995 }
996
997 return 0;
998 }
999