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