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