Merge branch 'vendor/OPENRESOLV' with the following changes:
[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. 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
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
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 */
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 *
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 */
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 *
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 */
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 */
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 */
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 */
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 }