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