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