parms.c revision 94125
1186681Sed/* 2186681Sed * Copyright (c) 1983, 1993 3186681Sed * The Regents of the University of California. All rights reserved. 4186681Sed * 5186681Sed * Redistribution and use in source and binary forms, with or without 6186681Sed * modification, are permitted provided that the following conditions 7186681Sed * are met: 8186681Sed * 1. Redistributions of source code must retain the above copyright 9186681Sed * notice, this list of conditions and the following disclaimer. 10186681Sed * 2. Redistributions in binary form must reproduce the above copyright 11186681Sed * notice, this list of conditions and the following disclaimer in the 12186681Sed * documentation and/or other materials provided with the distribution. 13186681Sed * 3. All advertising materials mentioning features or use of this software 14186681Sed * must display the following acknowledgment: 15186681Sed * This product includes software developed by the University of 16186681Sed * California, Berkeley and its contributors. 17186681Sed * 4. Neither the name of the University nor the names of its contributors 18186681Sed * may be used to endorse or promote products derived from this software 19186681Sed * without specific prior written permission. 20186681Sed * 21186681Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22186681Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23186681Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24186681Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25186681Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26186681Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27186681Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28186681Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29186681Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30186681Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31186681Sed * SUCH DAMAGE. 32186681Sed * 33187469Sed * $FreeBSD: head/sbin/routed/parms.c 94125 2002-04-07 17:01:20Z asmodai $ 34186681Sed */ 35186681Sed 36186681Sed#include "defs.h" 37186681Sed#include "pathnames.h" 38186681Sed#include <sys/stat.h> 39186681Sed 40186681Sed#if !defined(sgi) && !defined(__NetBSD__) 41186681Sedstatic char sccsid[] __attribute__((unused)) = "@(#)if.c 8.1 (Berkeley) 6/5/93"; 42186681Sed#elif defined(__NetBSD__) 43186681Sed__RCSID("$NetBSD$"); 44186681Sed#endif 45186681Sed#ident "$FreeBSD: head/sbin/routed/parms.c 94125 2002-04-07 17:01:20Z asmodai $" 46186681Sed 47186681Sed 48186681Sedstruct parm *parms; 49186681Sedstruct intnet *intnets; 50186681Sedstruct r1net *r1nets; 51186681Sedstruct tgate *tgates; 52186681Sed 53186681Sed 54186681Sed/* use configured parameters 55186681Sed */ 56186681Sedvoid 57186681Sedget_parms(struct interface *ifp) 58186681Sed{ 59186681Sed static int warned_auth_in, warned_auth_out; 60186681Sed struct parm *parmp; 61186681Sed int i, num_passwds = 0; 62186681Sed 63186681Sed /* get all relevant parameters 64186681Sed */ 65186681Sed for (parmp = parms; parmp != 0; parmp = parmp->parm_next) { 66186681Sed if (parmp->parm_name[0] == '\0' 67186681Sed || !strcmp(ifp->int_name, parmp->parm_name) 68186681Sed || (parmp->parm_name[0] == '\n' 69186681Sed && on_net(ifp->int_addr, 70186681Sed parmp->parm_net, parmp->parm_mask))) { 71186681Sed 72186681Sed /* This group of parameters is relevant, 73186681Sed * so get its settings 74186681Sed */ 75186681Sed ifp->int_state |= parmp->parm_int_state; 76186681Sed for (i = 0; i < MAX_AUTH_KEYS; i++) { 77186681Sed if (parmp->parm_auth[0].type == RIP_AUTH_NONE 78186681Sed || num_passwds >= MAX_AUTH_KEYS) 79186681Sed break; 80186681Sed memcpy(&ifp->int_auth[num_passwds++], 81186681Sed &parmp->parm_auth[i], 82186681Sed sizeof(ifp->int_auth[0])); 83186681Sed } 84186681Sed if (parmp->parm_rdisc_pref != 0) 85186681Sed ifp->int_rdisc_pref = parmp->parm_rdisc_pref; 86186681Sed if (parmp->parm_rdisc_int != 0) 87186681Sed ifp->int_rdisc_int = parmp->parm_rdisc_int; 88186681Sed if (parmp->parm_d_metric != 0) 89186681Sed ifp->int_d_metric = parmp->parm_d_metric; 90186681Sed } 91186681Sed } 92186681Sed 93186681Sed /* Set general defaults. 94186681Sed * 95186681Sed * Default poor-man's router discovery to a metric that will 96186681Sed * be heard by old versions of `routed`. They ignored received 97186681Sed * routes with metric 15. 98186681Sed */ 99186681Sed if ((ifp->int_state & IS_PM_RDISC) 100186681Sed && ifp->int_d_metric == 0) 101186681Sed ifp->int_d_metric = FAKE_METRIC; 102186681Sed 103186681Sed if (ifp->int_rdisc_int == 0) 104186681Sed ifp->int_rdisc_int = DefMaxAdvertiseInterval; 105186681Sed 106186681Sed if (!(ifp->int_if_flags & IFF_MULTICAST) 107186681Sed && !(ifp->int_state & IS_REMOTE)) 108186681Sed ifp->int_state |= IS_BCAST_RDISC; 109186681Sed 110186681Sed if (ifp->int_if_flags & IFF_POINTOPOINT) { 111186681Sed ifp->int_state |= IS_BCAST_RDISC; 112186681Sed /* By default, point-to-point links should be passive 113186681Sed * about router-discovery for the sake of demand-dialing. 114186681Sed */ 115186681Sed if (0 == (ifp->int_state & GROUP_IS_SOL_OUT)) 116186681Sed ifp->int_state |= IS_NO_SOL_OUT; 117186681Sed if (0 == (ifp->int_state & GROUP_IS_ADV_OUT)) 118186681Sed ifp->int_state |= IS_NO_ADV_OUT; 119186681Sed } 120186681Sed 121186681Sed if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE))) 122186681Sed ifp->int_state |= IS_NO_RDISC; 123186681Sed if (ifp->int_state & IS_PASSIVE) 124186681Sed ifp->int_state |= IS_NO_RIP; 125186681Sed 126186681Sed if (!IS_RIP_IN_OFF(ifp->int_state) 127186681Sed && ifp->int_auth[0].type != RIP_AUTH_NONE 128186681Sed && !(ifp->int_state & IS_NO_RIPV1_IN) 129186681Sed && !warned_auth_in) { 130186681Sed msglog("Warning: RIPv1 input via %s" 131186681Sed " will be accepted without authentication", 132186681Sed ifp->int_name); 133186681Sed warned_auth_in = 1; 134186681Sed } 135186681Sed if (!IS_RIP_OUT_OFF(ifp->int_state) 136186681Sed && ifp->int_auth[0].type != RIP_AUTH_NONE 137186681Sed && !(ifp->int_state & IS_NO_RIPV1_OUT)) { 138186681Sed if (!warned_auth_out) { 139186681Sed msglog("Warning: RIPv1 output via %s" 140186681Sed " will be sent without authentication", 141186681Sed ifp->int_name); 142186681Sed warned_auth_out = 1; 143186681Sed } 144186681Sed } 145186681Sed} 146186681Sed 147186681Sed 148186681Sed/* Read a list of gateways from /etc/gateways and add them to our tables. 149186681Sed * 150186681Sed * This file contains a list of "remote" gateways. That is usually 151186681Sed * a gateway which we cannot immediately determine if it is present or 152186681Sed * not as we can do for those provided by directly connected hardware. 153186681Sed * 154186681Sed * If a gateway is marked "passive" in the file, then we assume it 155186681Sed * does not understand RIP and assume it is always present. Those 156186681Sed * not marked passive are treated as if they were directly connected 157186681Sed * and assumed to be broken if they do not send us advertisements. 158186681Sed * All remote interfaces are added to our list, and those not marked 159186681Sed * passive are sent routing updates. 160186681Sed * 161186681Sed * A passive interface can also be local, hardware interface exempt 162186681Sed * from RIP. 163186681Sed */ 164186681Sedvoid 165186681Sedgwkludge(void) 166186681Sed{ 167186681Sed FILE *fp; 168186681Sed char *p, *lptr; 169186681Sed const char *cp; 170186681Sed char lbuf[200], net_host[5], dname[64+1+64+1]; 171186681Sed char gname[GNAME_LEN+1], qual[9]; 172186681Sed struct interface *ifp; 173186681Sed naddr dst, netmask, gate; 174186681Sed int metric, n, lnum; 175186681Sed struct stat sb; 176186681Sed u_int state; 177186681Sed const char *type; 178186681Sed 179186681Sed 180186681Sed fp = fopen(_PATH_GATEWAYS, "r"); 181186681Sed if (fp == 0) 182186681Sed return; 183186681Sed 184186681Sed if (0 > fstat(fileno(fp), &sb)) { 185186681Sed msglog("could not stat() "_PATH_GATEWAYS); 186186681Sed (void)fclose(fp); 187186681Sed return; 188186681Sed } 189186681Sed 190186681Sed for (lnum = 1; ; lnum++) { 191186681Sed if (0 == fgets(lbuf, sizeof(lbuf), fp)) 192186681Sed break; 193186681Sed lptr = lbuf; 194186681Sed while (*lptr == ' ') 195186681Sed lptr++; 196186681Sed p = lptr+strlen(lptr)-1; 197186681Sed while (*p == '\n' 198186681Sed || (*p == ' ' && (p == lptr+1 || *(p-1) != '\\'))) 199186681Sed *p-- = '\0'; 200186681Sed if (*lptr == '\0' /* ignore null and comment lines */ 201186681Sed || *lptr == '#') 202187367Sed continue; 203187367Sed 204187367Sed /* notice newfangled parameter lines 205187367Sed */ 206187367Sed if (strncasecmp("net", lptr, 3) 207187367Sed && strncasecmp("host", lptr, 4)) { 208187367Sed cp = parse_parms(lptr, 209186753Sed (sb.st_uid == 0 210186753Sed && !(sb.st_mode&(S_IRWXG|S_IRWXO)))); 211186753Sed if (cp != 0) 212186753Sed msglog("%s in line %d of "_PATH_GATEWAYS, 213186753Sed cp, lnum); 214186753Sed continue; 215186753Sed } 216186753Sed 217187367Sed/* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */ 218186681Sed qual[0] = '\0'; 219186681Sed /* the '64' here must be GNAME_LEN */ 220186681Sed n = sscanf(lptr, "%4s %129[^ \t] gateway" 221186681Sed " %64[^ / \t] metric %u %8s\n", 222186681Sed net_host, dname, gname, &metric, qual); 223186681Sed if (n != 4 && n != 5) { 224186681Sed msglog("bad "_PATH_GATEWAYS" entry \"%s\"; %d values", 225186681Sed lptr, n); 226186681Sed continue; 227186681Sed } 228186681Sed if (metric >= HOPCNT_INFINITY) { 229186681Sed msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"", 230186681Sed lptr); 231186681Sed continue; 232186681Sed } 233186681Sed if (!strcasecmp(net_host, "host")) { 234186681Sed if (!gethost(dname, &dst)) { 235186681Sed msglog("bad host \"%s\" in "_PATH_GATEWAYS 236186681Sed " entry \"%s\"", dname, lptr); 237186681Sed continue; 238186681Sed } 239186681Sed netmask = HOST_MASK; 240186681Sed } else if (!strcasecmp(net_host, "net")) { 241186681Sed if (!getnet(dname, &dst, &netmask)) { 242186681Sed msglog("bad net \"%s\" in "_PATH_GATEWAYS 243186681Sed " entry \"%s\"", dname, lptr); 244186681Sed continue; 245186681Sed } 246186681Sed if (dst == RIP_DEFAULT) { 247186681Sed msglog("bad net \"%s\" in "_PATH_GATEWAYS 248186681Sed " entry \"%s\"--cannot be default", 249186681Sed dname, lptr); 250186681Sed continue; 251186681Sed } 252186681Sed /* Turn network # into IP address. */ 253186681Sed dst = htonl(dst); 254186681Sed } else { 255186681Sed msglog("bad \"%s\" in "_PATH_GATEWAYS 256186681Sed " entry \"%s\"", net_host, lptr); 257186681Sed continue; 258186681Sed } 259186681Sed 260186681Sed if (!gethost(gname, &gate)) { 261186681Sed msglog("bad gateway \"%s\" in "_PATH_GATEWAYS 262186681Sed " entry \"%s\"", gname, lptr); 263186681Sed continue; 264186681Sed } 265186729Sed 266186729Sed if (!strcasecmp(qual, type = "passive")) { 267186681Sed /* Passive entries are not placed in our tables, 268186681Sed * only the kernel's, so we don't copy all of the 269186681Sed * external routing information within a net. 270186681Sed * Internal machines should use the default 271186681Sed * route to a suitable gateway (like us). 272186681Sed */ 273186681Sed state = IS_REMOTE | IS_PASSIVE; 274186681Sed if (metric == 0) 275186681Sed metric = 1; 276186681Sed 277186681Sed } else if (!strcasecmp(qual, type = "external")) { 278186681Sed /* External entries are handled by other means 279186681Sed * such as EGP, and are placed only in the daemon 280186681Sed * tables to prevent overriding them with something 281186681Sed * else. 282186681Sed */ 283186681Sed strcpy(qual,"external"); 284186681Sed state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL; 285186681Sed if (metric == 0) 286186681Sed metric = 1; 287186681Sed 288186681Sed } else if (!strcasecmp(qual, "active") 289186681Sed || qual[0] == '\0') { 290186681Sed if (metric != 0) { 291186681Sed /* Entries that are neither "passive" nor 292186681Sed * "external" are "remote" and must behave 293186681Sed * like physical interfaces. If they are not 294186681Sed * heard from regularly, they are deleted. 295186681Sed */ 296186681Sed state = IS_REMOTE; 297186681Sed type = "remote"; 298186681Sed } else { 299186681Sed /* "remote" entries with a metric of 0 300186681Sed * are aliases for our own interfaces 301186681Sed */ 302186681Sed state = IS_REMOTE | IS_PASSIVE | IS_ALIAS; 303186681Sed type = "alias"; 304186681Sed } 305186681Sed 306186681Sed } else { 307186681Sed msglog("bad "_PATH_GATEWAYS" entry \"%s\";" 308186729Sed " unknown type %s", lptr, qual); 309186729Sed continue; 310186681Sed } 311186681Sed 312186681Sed if (0 != (state & (IS_PASSIVE | IS_REMOTE))) 313186681Sed state |= IS_NO_RDISC; 314186681Sed if (state & IS_PASSIVE) 315186681Sed state |= IS_NO_RIP; 316186681Sed 317186681Sed ifp = check_dup(gate,dst,netmask,0); 318186681Sed if (ifp != 0) { 319186681Sed msglog("duplicate "_PATH_GATEWAYS" entry \"%s\"",lptr); 320186681Sed continue; 321186681Sed } 322186681Sed 323186681Sed ifp = (struct interface *)rtmalloc(sizeof(*ifp), "gwkludge()"); 324186681Sed memset(ifp, 0, sizeof(*ifp)); 325186681Sed 326186681Sed ifp->int_state = state; 327186681Sed if (netmask == HOST_MASK) 328186681Sed ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP; 329186681Sed else 330186681Sed ifp->int_if_flags = IFF_UP; 331186681Sed ifp->int_act_time = NEVER; 332186681Sed ifp->int_addr = gate; 333186681Sed ifp->int_dstaddr = dst; 334186681Sed ifp->int_mask = netmask; 335186681Sed ifp->int_ripv1_mask = netmask; 336186681Sed ifp->int_std_mask = std_mask(gate); 337186681Sed ifp->int_net = ntohl(dst); 338186681Sed ifp->int_std_net = ifp->int_net & ifp->int_std_mask; 339186681Sed ifp->int_std_addr = htonl(ifp->int_std_net); 340186681Sed ifp->int_metric = metric; 341186681Sed if (!(state & IS_EXTERNAL) 342186681Sed && ifp->int_mask != ifp->int_std_mask) 343186681Sed ifp->int_state |= IS_SUBNET; 344186681Sed (void)sprintf(ifp->int_name, "%s(%s)", type, gname); 345186681Sed ifp->int_index = -1; 346186681Sed 347186681Sed if_link(ifp); 348186681Sed } 349186681Sed 350186681Sed /* After all of the parameter lines have been read, 351186681Sed * apply them to any remote interfaces. 352186681Sed */ 353186681Sed for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 354186681Sed get_parms(ifp); 355186681Sed 356186681Sed tot_interfaces++; 357186681Sed if (!IS_RIP_OFF(ifp->int_state)) 358186681Sed rip_interfaces++; 359186681Sed 360186681Sed trace_if("Add", ifp); 361186681Sed } 362186681Sed 363186681Sed (void)fclose(fp); 364186681Sed} 365186681Sed 366186681Sed 367186681Sed/* like strtok(), but honoring backslash and not changing the source string 368186681Sed */ 369186681Sedstatic int /* 0=ok, -1=bad */ 370186681Sedparse_quote(char **linep, /* look here */ 371186681Sed const char *delims, /* for these delimiters */ 372186681Sed char *delimp, /* 0 or put found delimiter here */ 373186681Sed char *buf, /* copy token to here */ 374186681Sed int lim) /* at most this many bytes */ 375186681Sed{ 376186681Sed char c = '\0', *pc; 377186681Sed const char *p; 378186681Sed 379186681Sed 380186681Sed pc = *linep; 381186681Sed if (*pc == '\0') 382186681Sed return -1; 383186681Sed 384186681Sed while (lim != 0) { 385186681Sed c = *pc++; 386186681Sed if (c == '\0') 387186681Sed break; 388186681Sed 389186681Sed if (c == '\\' && *pc != '\0') { 390186681Sed if ((c = *pc++) == 'n') { 391186681Sed c = '\n'; 392186681Sed } else if (c == 'r') { 393186681Sed c = '\r'; 394186681Sed } else if (c == 't') { 395186681Sed c = '\t'; 396186681Sed } else if (c == 'b') { 397186681Sed c = '\b'; 398186681Sed } else if (c >= '0' && c <= '7') { 399186681Sed c -= '0'; 400186681Sed if (*pc >= '0' && *pc <= '7') { 401186681Sed c = (c<<3)+(*pc++ - '0'); 402186681Sed if (*pc >= '0' && *pc <= '7') 403186681Sed c = (c<<3)+(*pc++ - '0'); 404186681Sed } 405186681Sed } 406186681Sed 407186681Sed } else { 408186681Sed for (p = delims; *p != '\0'; ++p) { 409186681Sed if (*p == c) 410186681Sed goto exit; 411186681Sed } 412186681Sed } 413186681Sed 414186681Sed *buf++ = c; 415186681Sed --lim; 416186681Sed } 417186681Sedexit: 418186681Sed if (lim == 0) 419186681Sed return -1; 420186681Sed 421186681Sed *buf = '\0'; /* terminate copy of token */ 422186681Sed if (delimp != 0) 423186681Sed *delimp = c; /* return delimiter */ 424186681Sed *linep = pc-1; /* say where we ended */ 425186681Sed return 0; 426186681Sed} 427186681Sed 428186681Sed 429186681Sed/* Parse password timestamp 430186681Sed */ 431186681Sedstatic char * 432186681Sedparse_ts(time_t *tp, 433186681Sed char **valp, 434186681Sed char *val0, 435186681Sed char *delimp, 436186681Sed char *buf, 437186681Sed u_int bufsize) 438186681Sed{ 439186681Sed struct tm tm; 440186681Sed#if defined(sgi) || defined(__NetBSD__) 441186681Sed char *ptr; 442186681Sed#endif 443186681Sed 444186681Sed if (0 > parse_quote(valp, "| ,\n\r", delimp, 445186681Sed buf,bufsize) 446186681Sed || buf[bufsize-1] != '\0' 447186681Sed || buf[bufsize-2] != '\0') { 448186681Sed sprintf(buf,"bad timestamp %.25s", val0); 449186681Sed return buf; 450186681Sed } 451186681Sed strcat(buf,"\n"); 452186681Sed memset(&tm, 0, sizeof(tm)); 453186681Sed#if defined(sgi) || defined(__NetBSD__) 454186681Sed ptr = strptime(buf, "%y/%m/%d@%H:%M\n", &tm); 455186681Sed if (ptr == NULL || *ptr != '\0') { 456186681Sed sprintf(buf,"bad timestamp %.25s", val0); 457186681Sed return buf; 458186681Sed } 459186681Sed#else 460186681Sed if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n", 461186681Sed &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 462186681Sed &tm.tm_hour, &tm.tm_min) 463186681Sed || tm.tm_mon < 1 || tm.tm_mon > 12 464186681Sed || tm.tm_mday < 1 || tm.tm_mday > 31) { 465186681Sed sprintf(buf,"bad timestamp %.25s", val0); 466186681Sed return buf; 467186681Sed } 468186681Sed tm.tm_mon--; 469186681Sed if (tm.tm_year <= 37) /* assume small years are in the */ 470186681Sed tm.tm_year += 100; /* 3rd millenium */ 471186681Sed#endif 472186681Sed 473186681Sed if ((*tp = mktime(&tm)) == -1) { 474186681Sed sprintf(buf,"bad timestamp %.25s", val0); 475186681Sed return buf; 476186681Sed } 477186681Sed 478186681Sed return 0; 479186681Sed} 480186681Sed 481186681Sed 482186681Sed/* Get a password, key ID, and expiration date in the format 483186681Sed * passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min 484186681Sed */ 485186681Sedstatic const char * /* 0 or error message */ 486186681Sedget_passwd(char *tgt, 487186681Sed char *val, 488186681Sed struct parm *parmp, 489186681Sed u_int16_t type, 490186681Sed int safe) /* 1=from secure file */ 491186681Sed{ 492186681Sed static char buf[80]; 493186681Sed char *val0, *p, delim; 494186681Sed struct auth k, *ap, *ap2; 495186681Sed int i; 496186681Sed u_long l; 497186681Sed 498186681Sed 499186681Sed if (!safe) 500186681Sed return "ignore unsafe password"; 501186681Sed 502186681Sed for (ap = parmp->parm_auth, i = 0; 503186681Sed ap->type != RIP_AUTH_NONE; i++, ap++) { 504186681Sed if (i >= MAX_AUTH_KEYS) 505186681Sed return "too many passwords"; 506186681Sed } 507186681Sed 508186681Sed memset(&k, 0, sizeof(k)); 509186681Sed k.type = type; 510186681Sed k.end = -1-DAY; 511186681Sed 512186681Sed val0 = val; 513186681Sed if (0 > parse_quote(&val, "| ,\n\r", &delim, 514186681Sed (char *)k.key, sizeof(k.key))) 515186681Sed return tgt; 516186681Sed 517186681Sed if (delim != '|') { 518186681Sed if (type == RIP_AUTH_MD5) 519186681Sed return "missing Keyid"; 520186681Sed } else { 521186681Sed val0 = ++val; 522186681Sed buf[sizeof(buf)-1] = '\0'; 523186681Sed if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf)) 524186681Sed || buf[sizeof(buf)-1] != '\0' 525186681Sed || (l = strtoul(buf,&p,0)) > 255 526186681Sed || *p != '\0') { 527186681Sed sprintf(buf,"bad KeyID \"%.20s\"", val0); 528186681Sed return buf; 529186681Sed } 530186681Sed for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) { 531186681Sed if (ap2->keyid == l) { 532187469Sed sprintf(buf,"duplicate KeyID \"%.20s\"", val0); 533187469Sed return buf; 534187469Sed } 535187469Sed } 536187469Sed k.keyid = (int)l; 537187469Sed 538187469Sed if (delim == '|') { 539187469Sed val0 = ++val; 540187469Sed if (0 != (p = parse_ts(&k.start,&val,val0,&delim, 541187469Sed buf,sizeof(buf)))) 542187469Sed return p; 543187469Sed if (delim != '|') 544187469Sed return "missing second timestamp"; 545187469Sed val0 = ++val; 546187469Sed if (0 != (p = parse_ts(&k.end,&val,val0,&delim, 547187469Sed buf,sizeof(buf)))) 548187469Sed return p; 549187469Sed if ((u_long)k.start > (u_long)k.end) { 550187469Sed sprintf(buf,"out of order timestamp %.30s", 551187469Sed val0); 552187469Sed return buf; 553187469Sed } 554187469Sed } 555187469Sed } 556187469Sed if (delim != '\0') 557187469Sed return tgt; 558187469Sed 559187469Sed memmove(ap, &k, sizeof(*ap)); 560187469Sed return 0; 561187469Sed} 562187469Sed 563187469Sed 564187469Sedstatic const char * 565187469Sedbad_str(const char *estr) 566187469Sed{ 567187469Sed static char buf[100+8]; 568187469Sed 569187469Sed sprintf(buf, "bad \"%.100s\"", estr); 570187469Sed return buf; 571187469Sed} 572187469Sed 573187469Sed 574186681Sed/* Parse a set of parameters for an interface. 575186681Sed */ 576186681Sedconst char * /* 0 or error message */ 577186681Sedparse_parms(char *line, 578186681Sed int safe) /* 1=from secure file */ 579186681Sed{ 580186681Sed#define PARS(str) (!strcasecmp(tgt, str)) 581186681Sed#define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str))) 582186681Sed#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \ 583186681Sed parm.parm_int_state |= (b);} 584186681Sed struct parm parm; 585186681Sed struct intnet *intnetp; 586186681Sed struct r1net *r1netp; 587186681Sed struct tgate *tg; 588187367Sed naddr addr, mask; 589186681Sed char delim, *val0 = 0, *tgt, *val, *p; 590186681Sed const char *msg; 591186681Sed char buf[BUFSIZ], buf2[BUFSIZ]; 592186681Sed int i; 593186681Sed 594186681Sed 595186681Sed /* "subnet=x.y.z.u/mask[,metric]" must be alone on the line */ 596186681Sed if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1) 597186681Sed && *(val = &line[sizeof("subnet=")-1]) != '\0') { 598186681Sed if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf))) 599187367Sed return bad_str(line); 600187367Sed intnetp = (struct intnet*)rtmalloc(sizeof(*intnetp), 601187367Sed "parse_parms subnet"); 602187367Sed intnetp->intnet_metric = 1; 603186681Sed if (delim == ',') { 604186681Sed intnetp->intnet_metric = (int)strtol(val+1,&p,0); 605186681Sed if (*p != '\0' 606186681Sed || intnetp->intnet_metric <= 0 607186681Sed || intnetp->intnet_metric >= HOPCNT_INFINITY) 608186681Sed return bad_str(line); 609186681Sed } 610186681Sed if (!getnet(buf, &intnetp->intnet_addr, &intnetp->intnet_mask) 611186681Sed || intnetp->intnet_mask == HOST_MASK 612186681Sed || intnetp->intnet_addr == RIP_DEFAULT) { 613186681Sed free(intnetp); 614186681Sed return bad_str(line); 615186681Sed } 616186681Sed intnetp->intnet_addr = htonl(intnetp->intnet_addr); 617186681Sed intnetp->intnet_next = intnets; 618186681Sed intnets = intnetp; 619186681Sed return 0; 620186681Sed } 621186681Sed 622186681Sed /* "ripv1_mask=x.y.z.u/mask1,mask2" must be alone on the line. 623186681Sed * This requires that x.y.z.u/mask1 be considered a subnet of 624186681Sed * x.y.z.u/mask2, as if x.y.z.u/mask2 were a class-full network. 625186681Sed */ 626186681Sed if (!strncasecmp(line, "ripv1_mask=", sizeof("ripv1_mask=")-1) 627186681Sed && *(val = &line[sizeof("ripv1_mask=")-1]) != '\0') { 628186681Sed if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf)) 629186681Sed || delim == '\0') 630186681Sed return bad_str(line); 631186681Sed if ((i = (int)strtol(val+1, &p, 0)) <= 0 632186681Sed || i > 32 || *p != '\0') 633186681Sed return bad_str(line); 634186681Sed r1netp = (struct r1net *)rtmalloc(sizeof(*r1netp), 635186681Sed "parse_parms ripv1_mask"); 636186681Sed r1netp->r1net_mask = HOST_MASK << (32-i); 637186681Sed if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match) 638186681Sed || r1netp->r1net_net == RIP_DEFAULT 639186681Sed || r1netp->r1net_mask > r1netp->r1net_match) { 640186681Sed free(r1netp); 641186681Sed return bad_str(line); 642186681Sed } 643186681Sed r1netp->r1net_next = r1nets; 644186681Sed r1nets = r1netp; 645186681Sed return 0; 646186681Sed } 647186681Sed 648186681Sed memset(&parm, 0, sizeof(parm)); 649186681Sed 650186681Sed for (;;) { 651186681Sed tgt = line + strspn(line, " ,\n\r"); 652186681Sed if (*tgt == '\0' || *tgt == '#') 653186681Sed break; 654186681Sed line = tgt+strcspn(tgt, "= #,\n\r"); 655186681Sed delim = *line; 656186681Sed if (delim == '=') { 657186681Sed val0 = ++line; 658186681Sed if (0 > parse_quote(&line, " #,\n\r",&delim, 659186681Sed buf,sizeof(buf))) 660186681Sed return bad_str(tgt); 661186681Sed } 662186681Sed if (delim != '\0') { 663186681Sed for (;;) { 664186681Sed *line = '\0'; 665186681Sed if (delim == '#') 666186681Sed break; 667186681Sed ++line; 668186681Sed if (delim != ' ' 669186681Sed || (delim = *line) != ' ') 670186681Sed break; 671186681Sed } 672186681Sed } 673186681Sed 674186681Sed if (PARSEQ("if")) { 675186681Sed if (parm.parm_name[0] != '\0' 676186681Sed || strlen(buf) > IF_NAME_LEN) 677186681Sed return bad_str(tgt); 678186681Sed strcpy(parm.parm_name, buf); 679186681Sed 680186681Sed } else if (PARSEQ("addr")) { 681186681Sed /* This is a bad idea, because the address based 682186681Sed * sets of parameters cannot be checked for 683186681Sed * consistency with the interface name parameters. 684186681Sed * The parm_net stuff is needed to allow several 685186681Sed * -F settings. 686186681Sed */ 687186681Sed if (!getnet(val0, &addr, &mask) 688186681Sed || parm.parm_name[0] != '\0') 689186681Sed return bad_str(tgt); 690186681Sed parm.parm_net = addr; 691186681Sed parm.parm_mask = mask; 692186681Sed parm.parm_name[0] = '\n'; 693186681Sed 694186681Sed } else if (PARSEQ("passwd")) { 695186681Sed /* since cleartext passwords are so weak allow 696186681Sed * them anywhere 697186681Sed */ 698186681Sed msg = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1); 699186681Sed if (msg) { 700186681Sed *val0 = '\0'; 701186681Sed return bad_str(msg); 702186681Sed } 703186681Sed 704186681Sed } else if (PARSEQ("md5_passwd")) { 705186681Sed msg = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe); 706186681Sed if (msg) { 707186681Sed *val0 = '\0'; 708186798Sed return bad_str(msg); 709186798Sed } 710187367Sed 711187367Sed } else if (PARS("no_ag")) { 712187367Sed parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG); 713187367Sed 714186798Sed } else if (PARS("no_super_ag")) { 715186798Sed parm.parm_int_state |= IS_NO_SUPER_AG; 716186798Sed 717186798Sed } else if (PARS("no_rip_out")) { 718186798Sed parm.parm_int_state |= IS_NO_RIP_OUT; 719186798Sed 720186798Sed } else if (PARS("no_ripv1_in")) { 721186798Sed parm.parm_int_state |= IS_NO_RIPV1_IN; 722187367Sed 723186798Sed } else if (PARS("no_ripv2_in")) { 724186798Sed parm.parm_int_state |= IS_NO_RIPV2_IN; 725186798Sed 726186681Sed } else if (PARS("ripv2_out")) { 727186681Sed if (parm.parm_int_state & IS_NO_RIPV2_OUT) 728186681Sed return bad_str(tgt); 729186681Sed parm.parm_int_state |= IS_NO_RIPV1_OUT; 730186681Sed 731186681Sed } else if (PARS("ripv2")) { 732186681Sed if ((parm.parm_int_state & IS_NO_RIPV2_OUT) 733186681Sed || (parm.parm_int_state & IS_NO_RIPV2_IN)) 734186681Sed return bad_str(tgt); 735186681Sed parm.parm_int_state |= (IS_NO_RIPV1_IN 736186681Sed | IS_NO_RIPV1_OUT); 737186681Sed 738186681Sed } else if (PARS("no_rip")) { 739186681Sed CKF(IS_PM_RDISC, IS_NO_RIP); 740186681Sed 741186681Sed } else if (PARS("no_rip_mcast")) { 742186681Sed parm.parm_int_state |= IS_NO_RIP_MCAST; 743186681Sed 744186681Sed } else if (PARS("no_rdisc")) { 745186681Sed CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC); 746186681Sed 747186681Sed } else if (PARS("no_solicit")) { 748186681Sed CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT); 749186681Sed 750186681Sed } else if (PARS("send_solicit")) { 751186681Sed CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT); 752186681Sed 753186681Sed } else if (PARS("no_rdisc_adv")) { 754186681Sed CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT); 755186681Sed 756186681Sed } else if (PARS("rdisc_adv")) { 757186681Sed CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT); 758186681Sed 759186681Sed } else if (PARS("bcast_rdisc")) { 760186681Sed parm.parm_int_state |= IS_BCAST_RDISC; 761186681Sed 762186681Sed } else if (PARS("passive")) { 763186681Sed CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC); 764186681Sed parm.parm_int_state |= IS_NO_RIP| IS_PASSIVE; 765186681Sed 766186681Sed } else if (PARSEQ("rdisc_pref")) { 767186681Sed if (parm.parm_rdisc_pref != 0 768186681Sed || (parm.parm_rdisc_pref = (int)strtol(buf,&p,0), 769186681Sed *p != '\0')) 770186681Sed return bad_str(tgt); 771186681Sed 772186681Sed } else if (PARS("pm_rdisc")) { 773186681Sed if (IS_RIP_OUT_OFF(parm.parm_int_state)) 774186681Sed return bad_str(tgt); 775186681Sed parm.parm_int_state |= IS_PM_RDISC; 776186681Sed 777186681Sed } else if (PARSEQ("rdisc_interval")) { 778186681Sed if (parm.parm_rdisc_int != 0 779186681Sed || (parm.parm_rdisc_int = (int)strtoul(buf,&p,0), 780186681Sed *p != '\0') 781186681Sed || parm.parm_rdisc_int < MinMaxAdvertiseInterval 782186681Sed || parm.parm_rdisc_int > MaxMaxAdvertiseInterval) 783186681Sed return bad_str(tgt); 784186681Sed 785186681Sed } else if (PARSEQ("fake_default")) { 786187469Sed if (parm.parm_d_metric != 0 787187469Sed || IS_RIP_OUT_OFF(parm.parm_int_state) 788186681Sed || (parm.parm_d_metric = (int)strtoul(buf,&p,0), 789186681Sed *p != '\0') 790186681Sed || parm.parm_d_metric > HOPCNT_INFINITY-1) 791186681Sed return bad_str(tgt); 792186681Sed 793186681Sed } else if (PARSEQ("trust_gateway")) { 794187367Sed /* look for trust_gateway=x.y.z|net/mask|...) */ 795186681Sed p = buf; 796186681Sed if (0 > parse_quote(&p, "|", &delim, 797186681Sed buf2, sizeof(buf2)) 798186681Sed || !gethost(buf2,&addr)) 799186681Sed return bad_str(tgt); 800186681Sed tg = (struct tgate *)rtmalloc(sizeof(*tg), 801186681Sed "parse_parms" 802186681Sed "trust_gateway"); 803186681Sed memset(tg, 0, sizeof(*tg)); 804186681Sed tg->tgate_addr = addr; 805186681Sed i = 0; 806186681Sed /* The default is to trust all routes. */ 807186681Sed while (delim == '|') { 808186681Sed p++; 809186681Sed if (i >= MAX_TGATE_NETS 810186681Sed || 0 > parse_quote(&p, "|", &delim, 811186681Sed buf2, sizeof(buf2)) 812186681Sed || !getnet(buf2, &tg->tgate_nets[i].net, 813186681Sed &tg->tgate_nets[i].mask) 814186681Sed || tg->tgate_nets[i].net == RIP_DEFAULT 815186681Sed || tg->tgate_nets[i].mask == 0) 816186681Sed return bad_str(tgt); 817186681Sed i++; 818186681Sed } 819186681Sed tg->tgate_next = tgates; 820186681Sed tgates = tg; 821186681Sed parm.parm_int_state |= IS_DISTRUST; 822186681Sed 823186681Sed } else if (PARS("redirect_ok")) { 824186681Sed parm.parm_int_state |= IS_REDIRECT_OK; 825186681Sed 826186681Sed } else { 827186681Sed return bad_str(tgt); /* error */ 828186681Sed } 829186681Sed } 830186681Sed 831186681Sed return check_parms(&parm); 832186681Sed#undef PARS 833186681Sed#undef PARSEQ 834186681Sed} 835186681Sed 836186681Sed 837186681Sed/* check for duplicate parameter specifications */ 838186681Sedconst char * /* 0 or error message */ 839187367Sedcheck_parms(struct parm *new) 840187367Sed{ 841187367Sed struct parm *parmp, **parmpp; 842186681Sed int i, num_passwds; 843187367Sed 844187367Sed /* set implicit values 845187367Sed */ 846187367Sed if (new->parm_int_state & IS_NO_ADV_IN) 847187367Sed new->parm_int_state |= IS_NO_SOL_OUT; 848187367Sed if (new->parm_int_state & IS_NO_SOL_OUT) 849187367Sed new->parm_int_state |= IS_NO_ADV_IN; 850187367Sed 851187367Sed for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) { 852187367Sed if (new->parm_auth[i].type != RIP_AUTH_NONE) 853187367Sed num_passwds++; 854187367Sed } 855187367Sed 856186681Sed /* compare with existing sets of parameters 857186681Sed */ 858186681Sed for (parmpp = &parms; 859186681Sed (parmp = *parmpp) != 0; 860186681Sed parmpp = &parmp->parm_next) { 861186681Sed if (strcmp(new->parm_name, parmp->parm_name)) 862186681Sed continue; 863186681Sed if (!on_net(htonl(parmp->parm_net), 864186681Sed new->parm_net, new->parm_mask) 865186681Sed && !on_net(htonl(new->parm_net), 866186681Sed parmp->parm_net, parmp->parm_mask)) 867186681Sed continue; 868186681Sed 869186681Sed for (i = 0; i < MAX_AUTH_KEYS; i++) { 870186681Sed if (parmp->parm_auth[i].type != RIP_AUTH_NONE) 871186681Sed num_passwds++; 872186681Sed } 873186681Sed if (num_passwds > MAX_AUTH_KEYS) 874186681Sed return "too many conflicting passwords"; 875186681Sed 876186681Sed if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT) 877186681Sed && 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT) 878186681Sed && 0 != ((new->parm_int_state ^ parmp->parm_int_state) 879186681Sed && GROUP_IS_SOL_OUT)) 880186681Sed || (0 != (new->parm_int_state & GROUP_IS_ADV_OUT) 881186681Sed && 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT) 882186681Sed && 0 != ((new->parm_int_state ^ parmp->parm_int_state) 883186681Sed && GROUP_IS_ADV_OUT)) 884186681Sed || (new->parm_rdisc_pref != 0 885186681Sed && parmp->parm_rdisc_pref != 0 886186681Sed && new->parm_rdisc_pref != parmp->parm_rdisc_pref) 887186681Sed || (new->parm_rdisc_int != 0 888186681Sed && parmp->parm_rdisc_int != 0 889186681Sed && new->parm_rdisc_int != parmp->parm_rdisc_int)) { 890186681Sed return ("conflicting, duplicate router discovery" 891186681Sed " parameters"); 892186681Sed 893186681Sed } 894186681Sed 895186681Sed if (new->parm_d_metric != 0 896186681Sed && parmp->parm_d_metric != 0 897186681Sed && new->parm_d_metric != parmp->parm_d_metric) { 898186681Sed return ("conflicting, duplicate poor man's router" 899186681Sed " discovery or fake default metric"); 900186681Sed } 901186681Sed } 902186681Sed 903186681Sed /* link new entry on the so that when the entries are scanned, 904186681Sed * they affect the result in the order the operator specified. 905186681Sed */ 906186681Sed parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms"); 907186681Sed memcpy(parmp, new, sizeof(*parmp)); 908186681Sed *parmpp = parmp; 909186681Sed 910186681Sed return 0; 911186681Sed} 912186681Sed 913186681Sed 914186681Sed/* get a network number as a name or a number, with an optional "/xx" 915186681Sed * netmask. 916186681Sed */ 917186681Sedint /* 0=bad */ 918186681Sedgetnet(char *name, 919186681Sed naddr *netp, /* network in host byte order */ 920186681Sed naddr *maskp) /* masks are always in host order */ 921186681Sed{ 922186681Sed int i; 923186681Sed struct netent *np; 924186681Sed naddr mask; /* in host byte order */ 925187469Sed struct in_addr in; /* a network and so host byte order */ 926186681Sed char hname[MAXHOSTNAMELEN+1]; 927186681Sed char *mname, *p; 928186681Sed 929187469Sed 930187469Sed /* Detect and separate "1.2.3.4/24" 931187469Sed */ 932187469Sed if (0 != (mname = strrchr(name,'/'))) { 933187469Sed i = (int)(mname - name); 934186681Sed if (i > (int)sizeof(hname)-1) /* name too long */ 935186681Sed return 0; 936186681Sed memmove(hname, name, i); 937186681Sed hname[i] = '\0'; 938186681Sed mname++; 939186681Sed name = hname; 940186681Sed } 941186681Sed 942186681Sed np = getnetbyname(name); 943186753Sed if (np != 0) { 944186681Sed in.s_addr = (naddr)np->n_net; 945186681Sed if (0 == (in.s_addr & 0xff000000)) 946186681Sed in.s_addr <<= 8; 947186681Sed if (0 == (in.s_addr & 0xff000000)) 948186681Sed in.s_addr <<= 8; 949186681Sed if (0 == (in.s_addr & 0xff000000)) 950186681Sed in.s_addr <<= 8; 951186681Sed } else if (inet_aton(name, &in) == 1) { 952186681Sed in.s_addr = ntohl(in.s_addr); 953186681Sed } else if (!mname && !strcasecmp(name,"default")) { 954187469Sed in.s_addr = RIP_DEFAULT; 955186681Sed } else { 956186681Sed return 0; 957186681Sed } 958186681Sed 959186681Sed if (!mname) { 960186681Sed /* we cannot use the interfaces here because we have not 961186681Sed * looked at them yet. 962186681Sed */ 963186681Sed mask = std_mask(htonl(in.s_addr)); 964186681Sed if ((~mask & in.s_addr) != 0) 965186681Sed mask = HOST_MASK; 966186681Sed } else { 967186681Sed mask = (naddr)strtoul(mname, &p, 0); 968186681Sed if (*p != '\0' || mask > 32) 969186681Sed return 0; 970186681Sed if (mask != 0) 971186681Sed mask = HOST_MASK << (32-mask); 972186681Sed } 973186681Sed 974186681Sed /* must have mask of 0 with default */ 975186681Sed if (mask != 0 && in.s_addr == RIP_DEFAULT) 976186681Sed return 0; 977187469Sed /* no host bits allowed in a network number */ 978186681Sed if ((~mask & in.s_addr) != 0) 979186681Sed return 0; 980186681Sed /* require non-zero network number */ 981186681Sed if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT) 982186681Sed return 0; 983186681Sed if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT) 984186681Sed return 0; 985186681Sed if (in.s_addr>>24 == 0xff) 986186681Sed return 0; 987186681Sed 988186681Sed *netp = in.s_addr; 989186681Sed *maskp = mask; 990186681Sed return 1; 991186681Sed} 992186681Sed 993186681Sed 994186681Sedint /* 0=bad */ 995186681Sedgethost(char *name, 996186681Sed naddr *addrp) 997186681Sed{ 998186681Sed struct hostent *hp; 999186681Sed struct in_addr in; 1000186681Sed 1001186681Sed 1002186681Sed /* Try for a number first, even in IRIX where gethostbyname() 1003186681Sed * is smart. This avoids hitting the name server which 1004186681Sed * might be sick because routing is. 1005186681Sed */ 1006186681Sed if (inet_aton(name, &in) == 1) { 1007186681Sed /* get a good number, but check that it it makes some 1008186681Sed * sense. 1009186681Sed */ 1010186681Sed if (ntohl(in.s_addr)>>24 == 0 1011186681Sed || ntohl(in.s_addr)>>24 == 0xff) 1012186681Sed return 0; 1013186681Sed *addrp = in.s_addr; 1014186681Sed return 1; 1015186681Sed } 1016186681Sed 1017186681Sed hp = gethostbyname(name); 1018186681Sed if (hp) { 1019186681Sed memcpy(addrp, hp->h_addr, sizeof(*addrp)); 1020186681Sed return 1; 1021186681Sed } 1022186681Sed 1023186681Sed return 0; 1024186681Sed} 1025186681Sed