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