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