]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/config.c
solaris bug #1242278, #1240793, #1079670, from Andrew Morgan
[netatalk.git] / etc / atalkd / config.c
1 /*
2  * $Id: config.c,v 1.13.6.5.2.6 2008-12-03 19:17:27 didg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved. See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/socket.h>
15 #include <sys/ioctl.h>
16 #include <atalk/logger.h>
17 #include <sys/param.h>
18 #ifdef TRU64
19 #include <sys/mbuf.h>
20 #include <net/route.h>
21 #endif /* TRU64 */
22 #include <net/if.h>
23 #include <netatalk/at.h>
24 #include <netatalk/endian.h>
25 #include <atalk/paths.h>
26 #include <atalk/util.h>
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <ctype.h>
33
34 /* STDC check */
35 #if STDC_HEADERS
36 #include <string.h>
37 #else /* STDC_HEADERS */
38 #ifndef HAVE_STRCHR
39 #define strchr index
40 #define strrchr index
41 #endif /* HAVE_STRCHR */
42 char *strchr (), *strrchr ();
43 #ifndef HAVE_MEMCPY
44 #define memcpy(d,s,n) bcopy ((s), (d), (n))
45 #define memmove(d,s,n) bcopy ((s), (d), (n))
46 #endif /* ! HAVE_MEMCPY */
47 #endif /* STDC_HEADERS */
48
49 #ifdef HAVE_FCNTL_H
50 #include <fcntl.h>
51 #endif /* HAVE_FCNTL_H */
52
53 #ifdef __svr4__
54 #include <sys/sockio.h>
55 #include <sys/stropts.h>
56 #endif /* __svr4__ */
57
58 #include <atalk/unicode.h>
59 #include "interface.h"
60 #include "multicast.h"
61 #include "rtmp.h"
62 #include "zip.h"
63 #include "list.h"
64 #include "main.h"
65
66 #ifndef IFF_SLAVE /* a little backward compatibility */
67 #define IFF_SLAVE 0
68 #endif /* IFF_SLAVE */
69
70 int     router(), dontroute(), seed(), phase(), net(), addr(), zone(), noallmulti();
71
72 static const struct param {
73     char        *p_name;
74     int         (*p_func)();
75 } params[] = {
76     { "router", router },
77     { "dontroute", dontroute },
78     { "seed",   seed },
79     { "phase",  phase },
80     { "net",    net },
81     { "addr",   addr },
82     { "zone",   zone },
83     { "noallmulti", noallmulti }
84 };
85
86 #define ARGV_CHUNK_SIZE 128
87 #define MAXLINELEN 2048
88 char **parseline(const char *line)
89 {
90     const char   *p;
91     int           argc = 0;
92     char         *buffer, *tmpbuf;
93     char        **argv;
94
95     /* Ignore empty lines and lines with leading hash marks. */
96     p = line;
97     while ( isspace( *p ) ) {
98         p++;
99     }
100     if ( *p == '#' || *p == '\0' ) {
101         return NULL;
102     }
103
104     buffer = (char *) malloc( strlen( p ) + 1 );
105     if ( !buffer ) {
106         /* FIXME: error handling */
107         return NULL;
108     }
109     strcpy( buffer, p );
110     tmpbuf = buffer;
111
112     argv = (char **) malloc( ARGV_CHUNK_SIZE * sizeof( char * ) );
113     if ( !argv ) {
114         /* FIXME: error handling */
115         free( buffer );
116         return NULL;
117     }
118
119     /*
120      * This parser should be made more powerful -- it should
121      * handle various escapes, e.g. \" and \031.
122      */
123     do {
124         if ( *tmpbuf == '"' ) {
125             argv[ argc++ ] = ++tmpbuf;
126             while ( *tmpbuf != '\0' && *tmpbuf != '"' ) {
127                 tmpbuf++;
128             }
129             if ( *tmpbuf == '"' ) {
130                 /* FIXME: error handling */
131             }
132         } else {
133             argv[ argc++ ] = tmpbuf;
134             while ( *tmpbuf != '\0' && !isspace( *tmpbuf )) {
135                 tmpbuf++;
136             }
137         }
138         *tmpbuf++ = '\0';
139
140         /* Make room for a NULL pointer and our special pointer (s.b.) */
141         if ( (argc + 1) % ARGV_CHUNK_SIZE == 0 ) {
142             char **tmp;
143             tmp = (char **) realloc( argv, argc + 1 + ARGV_CHUNK_SIZE * sizeof( char * ) );
144             if ( !tmp ) {
145                 /* FIXME: error handling */
146                 free( argv );
147                 free( buffer );
148                 return NULL;
149             }
150             argv = tmp;
151         }
152
153         /* Skip white spaces. */
154         while ( isspace( *tmpbuf ) ) {
155             tmpbuf++;
156         }
157     } while ( *tmpbuf != '\0' );
158
159     argv[ argc++ ] = NULL;
160     /* We store our buffer pointer in argv, too, so we can free it later.
161      * (But don't tell anyone.)
162      */
163     argv[ argc ] = buffer;
164
165     return argv;
166 }
167
168 void freeline( char **argv )
169 {
170     char **tmp = argv;
171
172     if ( argv ) {
173         while ( *tmp ) {
174             tmp++;
175         }
176         free( *++tmp );
177         free( argv );
178     }
179 }
180
181 int writeconf( cf )
182     char        *cf;
183 {
184     struct stat         st;
185     char                *path, *p, newpath[ MAXPATHLEN ], line[ MAXLINELEN ];
186     char                **argv;
187     FILE                *conf, *newconf;
188     struct interface    *iface;
189     struct list         *l;
190     int                 mode = 0644, fd;
191     size_t              len;
192     char                *zonename;
193
194     if ( cf == NULL ) {
195         path = _PATH_ATALKDCONF;
196     } else {
197         path = cf;
198     }
199
200     /* check if old conf is writable */
201     if ( stat( path, &st ) == 0 ) {
202         if (( st.st_mode & S_IWUSR ) == 0 ) {
203             LOG(log_info, logtype_atalkd, "%s not writable, won't rewrite", path );
204             return( -1 );
205         }
206          mode = st.st_mode;
207     }
208
209     if (( p = strrchr( path, '/' )) == NULL ) {
210         strcpy( newpath, _PATH_ATALKDTMP );
211     } else {
212         sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP );
213     }
214     if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) {
215         LOG(log_error, logtype_atalkd, "%s: %s", newpath, strerror(errno) );
216         return( -1 );
217     }
218     if (( newconf = fdopen( fd, "w" )) == NULL ) {
219         LOG(log_error, logtype_atalkd, "fdreopen %s: %s", newpath, strerror(errno) );
220         return( -1 );
221     }
222
223     if (( conf = fopen( path, "r" )) == NULL && cf ) {
224         LOG(log_error, logtype_atalkd, "%s: %s", path, strerror(errno) );
225         return( -1 );
226     }
227
228     iface = interfaces->i_next;
229
230     while ( conf == NULL || fgets( line, sizeof( line ), conf ) != NULL ) {
231         if ( conf != NULL && ( argv = parseline( line )) == NULL ) {
232             if ( fputs( line, newconf ) == EOF ) {
233                 LOG(log_error, logtype_atalkd, "fputs: %s", strerror(errno) );
234                 return( -1 );
235             }
236             freeline( argv );
237             continue;
238         }
239
240         /* write real lines */
241         if ( iface ) {
242             fprintf( newconf, "%s", iface->i_name );
243             if ( iface->i_flags & IFACE_RSEED ) {
244                 fprintf( newconf, " -router" );
245             } else if ( iface->i_flags & IFACE_SEED ) {
246                 fprintf( newconf, " -seed" );
247             }
248             if ( iface->i_flags & IFACE_DONTROUTE) {
249                 fprintf( newconf, " -dontroute");
250             }
251 #ifdef linux
252             if ( !(iface->i_flags & IFACE_ALLMULTI)) {
253                 fprintf( newconf, " -noallmulti");
254             }
255 #endif
256
257             fprintf( newconf, " -phase %d",
258                     ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
259             fprintf( newconf, " -net %d", ntohs( iface->i_rt->rt_firstnet ));
260             if ( iface->i_rt->rt_lastnet != iface->i_rt->rt_firstnet ) {
261                 fprintf( newconf, "-%d", ntohs( iface->i_rt->rt_lastnet ));
262             }
263             fprintf( newconf, " -addr %u.%u",
264                     ntohs( iface->i_addr.sat_addr.s_net ),
265                     iface->i_addr.sat_addr.s_node );
266             for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
267                 /* codepage conversion */
268                 if ((size_t)(-1) == (len = convert_string_allocate(CH_MAC, CH_UNIX, 
269                                       ((struct ziptab *)l->l_data)->zt_name,
270                                       ((struct ziptab *)l->l_data)->zt_len,
271                                       &zonename)) ) {
272                     if ( NULL == 
273                       (zonename = strdup(((struct ziptab *)l->l_data)->zt_name))) {
274                         LOG(log_error, logtype_atalkd, "malloc: %s",  strerror(errno) );
275                         return( -1 );
276                     }
277                     len = ((struct ziptab *)l->l_data)->zt_len;
278                 } 
279                 fprintf( newconf, " -zone \"%.*s\"", (int)len, zonename);
280                 free(zonename);
281             }
282             fprintf( newconf, "\n" );
283
284             iface = iface->i_next;
285             if ( conf == NULL && iface == NULL ) {
286                 break;
287             }
288         }
289     }
290     if ( conf != NULL ) {
291         fclose( conf );
292     }
293     fclose( newconf );
294
295     if ( rename( newpath, path ) < 0 ) {
296         LOG(log_error, logtype_atalkd, "rename %s to %s: %s", newpath, path, strerror(errno) );
297         return( -1 );
298     }
299     return( 0 );
300 }
301
302 /*
303  * Read our config file. If it's not there, return -1. If it is there,
304  * but has syntax errors, exit. Format of the file is as follows:
305  *
306  *      interface [ -seed ] [ -phase number ] [ -net net-range ]
307  *      [ -addr net.node ] [ -zone zonename ]...
308  * e.g.
309  *      le0 -phase 1 -net 7938 -zone Argus
310  * or
311  *      le0 -phase 2 -net 8043-8044 -zone Argus -zone "Research Systems"
312  *      le0 -phase 1 -net 7938 -zone Argus
313  *
314  * Pretty much everything is optional. Anything that is unspecified is
315  * searched for on the network.  If -seed is not specified, the
316  * configuration is assumed to be soft, i.e. it can be overridden by
317  * another router. If -seed is specified, atalkd will exit if another
318  * router disagrees.  If the phase is unspecified, it defaults to phase
319  * 2 (the default can be overridden on the command line).  -addr can
320  * replace -net, if the network in question isn't a range.  The default
321  * zone for an interface is the first zone encountered for that
322  * interface.
323  */
324 int readconf( cf )
325     char                *cf;
326 {
327     struct ifreq        ifr;
328     struct interface    *iface, *niface;
329     char                line[ MAXLINELEN ], **argv, *p;
330     unsigned int        i, j;
331     int                 s, cc = 0;
332     FILE                *conf;
333
334     if ( cf == NULL ) {
335         p = _PATH_ATALKDCONF;
336     } else {
337         p = cf;
338     }
339     if (( conf = fopen( p, "r" )) == NULL ) {
340         return( -1 );
341     }
342
343 #ifndef __svr4__
344     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
345         perror( "socket" );
346         fclose(conf);
347         return -1;
348     }
349 #endif /* __svr4__ */
350
351     while ( fgets( line, sizeof( line ), conf ) != NULL ) {
352         if (( argv = parseline( line )) == NULL ) {
353             continue;
354         }
355
356 #ifndef __svr4__
357         /*
358          * Check that av[ 0 ] is a valid interface.
359          * Not possible under sysV.
360          */
361         strlcpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
362
363         /* for devices that don't support appletalk */
364         if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
365           perror(argv[0]);
366           goto read_conf_err;
367         }
368
369         if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) {
370             perror( argv[ 0 ] );
371             goto read_conf_err;
372         }
373
374         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) {
375             fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name );
376             goto read_conf_err;
377         }
378
379 #ifdef IFF_MULTICAST
380         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
381             fprintf(stderr, "%s: multicast may not work properly.\n",
382                     ifr.ifr_name);
383 #endif /* IFF_MULTICAST */
384
385         /* configure hw multicast for this interface. */
386         if (addmulti(ifr.ifr_name, NULL) < 0) {
387           perror(ifr.ifr_name);
388           fprintf(stderr, "Can't configure multicast.\n");
389           goto read_conf_err;
390         }
391
392 #endif /* __svr4__ */
393
394         if (( niface = newiface( argv[ 0 ] )) == NULL ) {
395             perror( "newiface" );
396             goto read_conf_err;
397         }
398
399         for ( i = 1; argv[ i ]; i += cc ) {
400             if ( argv[ i ][ 0 ] == '-' ) {
401                 argv[ i ]++;
402             }
403             for ( j = 0; j < sizeof( params ) / sizeof( params[ 0 ] ); j++ ) {
404                 if ( strcmp( argv[ i ], params[ j ].p_name ) == 0 ) {
405                     if ( params[ j ].p_func != NULL ) {
406                         cc = (*params[ j ].p_func)( niface, &argv[ i + 1 ] );
407                         if (cc < 0) 
408                           goto read_conf_err;
409                         break;
410                     }
411                 }
412             }
413             if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) {
414                 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] );
415                 goto read_conf_err;
416             }
417         }
418
419         for ( iface = interfaces; iface; iface = iface->i_next ) {
420             if ( strcmp( niface->i_name, iface->i_name ) == 0 &&
421                     ((( niface->i_flags & iface->i_flags &
422                     ( IFACE_PHASE1|IFACE_PHASE2 )) != 0 ) ||
423                     niface->i_flags == 0 || iface->i_flags == 0 )) {
424                 break;
425             }
426         }
427         if ( iface ) {  /* Already have this interface and phase */
428             fprintf( stderr, "%s already configured!\n", niface->i_name );
429             goto read_conf_err;
430         }
431
432 #ifdef  linux
433         /* Don't set interface to allmulti if it already is, or -noallmulti was given */
434         if ((ifr.ifr_flags & IFF_ALLMULTI))
435                 niface->i_flags |= IFACE_WASALLMULTI; 
436
437         if ((niface->i_flags & IFACE_ALLMULTI) && !(niface->i_flags & IFACE_WASALLMULTI))
438                 ifsetallmulti(ifr.ifr_name, 1);
439 #endif
440
441         if ( interfaces == NULL ) {
442             interfaces = niface;
443         } else {
444             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
445                 ;
446             iface->i_next = niface;
447         }
448         niface->i_next = NULL;
449     }
450
451 #ifndef __svr4__
452     close( s );
453 #endif /* __svr4__ */
454
455     fclose( conf );
456
457     /*
458      * Note: we've added lo0 to the interface list previously, so we must
459      * have configured more than one interface...
460      */
461     for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ )
462         ;
463     if ( cc >= IFBASE ) {
464         return( 0 );
465     } else {
466         return( -1 );
467     }
468
469 read_conf_err:
470 #ifndef __svr4__
471     close(s);
472 #endif /* __svr4__ */
473     fclose(conf);
474     return -1;
475 }
476
477 int noallmulti( iface, av )
478     struct interface    *iface;
479     char                **av _U_;
480 {
481     /* Linux specific, no effect on other platforms */
482     iface->i_flags &= !IFACE_ALLMULTI;
483
484     return (1);
485 }
486         
487 /*ARGSUSED*/
488 int router( iface, av )
489     struct interface    *iface;
490     char                **av _U_;
491 {
492     /* make sure "-router" and "-dontroute" aren't both on the same line. */
493     if (iface->i_flags & IFACE_DONTROUTE) {
494         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
495         return -1;
496     }
497
498     /*
499      * Check to be sure "-router" is before "-zone".
500      */
501     if ( iface->i_czt ) {
502         fprintf( stderr, "Must specify -router before -zone.\n");
503         return -1;
504     }
505
506     /* -router also implies -seed */
507     iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER;
508     return( 1 );
509 }
510
511 /*ARGSUSED*/
512 int dontroute( iface, av )
513     struct interface    *iface;
514     char                **av _U_;
515 {
516     /* make sure "-router" and "-dontroute" aren't both on the same line. */
517     if (iface->i_flags & IFACE_RSEED) {
518         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
519         return -1;
520     }
521
522     iface->i_flags |= IFACE_DONTROUTE;
523     return( 1 );
524 }
525
526 /*ARGSUSED*/
527 int seed( iface, av )
528     struct interface    *iface;
529     char                **av _U_;
530 {
531     /*
532      * Check to be sure "-seed" is before "-zone". we keep the old
533      * semantics of just ignoring this in a routerless world.
534      */
535     if ( iface->i_czt ) {
536         fprintf( stderr, "Must specify -seed before -zone(%s).\n",
537                  iface->i_czt->zt_name);
538         return -1;
539     }
540
541     iface->i_flags |= IFACE_SEED;
542     return( 1 );
543 }
544
545 int phase( iface, av )
546     struct interface    *iface;
547     char                **av;
548 {
549     int                 n;
550     char                *pnum;
551
552     if (( pnum = av[ 0 ] ) == NULL ) {
553         fprintf( stderr, "No phase.\n" );
554         return -1;
555     }
556
557     switch ( n = atoi( pnum )) {
558     case 1 :
559         iface->i_flags |= IFACE_PHASE1;
560         break;
561
562     case 2 :
563         iface->i_flags |= IFACE_PHASE2;
564         break;
565
566     default :
567         fprintf( stderr, "No phase %d.\n", n );
568         return -1;
569     }
570     return( 2 );
571 }
572
573 int net( iface, av )
574     struct interface    *iface;
575     char                **av;
576 {
577     char                *nrange;
578     char                *stop;
579     int                 net;
580
581     if (( nrange = av[ 0 ] ) == NULL ) {
582         fprintf( stderr, "No network.\n" );
583         return -1;
584     }
585
586     if (( stop = strchr( nrange, '-' )) != 0 ) {
587         stop++;
588     }
589     net = atoi( nrange );
590     if ( net < 0 || net >= 0xffff ) {
591         fprintf( stderr, "Bad network: %d\n", net );
592         return -1;
593     }
594
595     if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) {
596         perror( "newrt" );
597         return -1;
598     }
599
600     if ( iface->i_flags & IFACE_PHASE1 ) {
601         if ( stop != 0 ) {
602             fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
603             return -1;
604         }
605         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
606                 ntohs( iface->i_caddr.sat_addr.s_net ) != net ) {
607             fprintf( stderr, "Net-range (%u) doesn't match net %u.\n",
608                     net, ntohs( iface->i_caddr.sat_addr.s_net ));
609             return -1;
610         }
611         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
612     } else if ( iface->i_flags & IFACE_PHASE2 ) {
613         iface->i_rt->rt_firstnet = htons( net );
614         if ( stop != 0 ) {
615             net = atoi( stop );
616             if ( net < 0 || net >= 0xffff ) {
617                 fprintf( stderr, "Bad network: %d\n", net );
618                 return -1;
619             }
620         }
621         iface->i_rt->rt_lastnet = htons( net );
622         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
623                 ( ntohs( iface->i_rt->rt_firstnet ) >
624                 ntohs( iface->i_caddr.sat_addr.s_net ) ||
625                 ntohs( iface->i_rt->rt_lastnet ) <
626                 ntohs( iface->i_caddr.sat_addr.s_net ))) {
627             fprintf( stderr, "Net-range (%u-%u) doesn't contain net (%u).\n",
628                     ntohs( iface->i_rt->rt_firstnet ),
629                     ntohs( iface->i_rt->rt_lastnet ),
630                     ntohs( iface->i_caddr.sat_addr.s_net ));
631             return -1;
632         }
633         if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) {
634             iface->i_rt->rt_flags |= RTMPTAB_EXTENDED;
635         }
636     } else {
637         fprintf( stderr, "Must specify phase before networks.\n" );
638         return -1;
639     }
640     return( 2 );
641 }
642
643 int addr( iface, av )
644     struct interface    *iface;
645     char                **av;
646 {
647     if ( av[ 0 ] == NULL ) {
648         fprintf( stderr, "No address.\n" );
649         return -1;
650     }
651     if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) {
652         fprintf( stderr, "Bad address, %s\n", av[ 0 ] );
653         return -1;
654     }
655
656     if ( iface->i_rt ) {
657         if ( ntohs( iface->i_rt->rt_firstnet ) >
658                 ntohs( iface->i_caddr.sat_addr.s_net ) ||
659                 ntohs( iface->i_rt->rt_lastnet ) <
660                 ntohs( iface->i_caddr.sat_addr.s_net )) {
661             fprintf( stderr, "Net (%u) not in net-range (%u-%u).\n",
662                     ntohs( iface->i_caddr.sat_addr.s_net ),
663                     ntohs( iface->i_rt->rt_firstnet ),
664                     ntohs( iface->i_rt->rt_lastnet ));
665             return -1;
666         }
667     } else {
668         if (( iface->i_rt = newrt(iface)) == NULL ) {
669             perror( "newrt" );
670             return -1;
671         }
672         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet =
673                 iface->i_caddr.sat_addr.s_net;
674     }
675
676     return( 2 );
677 }
678
679 int zone( iface, av )
680     struct interface    *iface;
681     char                **av;
682 {
683     struct ziptab       *zt;
684     char                *zname;
685
686     if ( av[ 0 ]  == NULL ) {
687         fprintf( stderr, "No zone.\n" );
688         return -1;
689     }
690
691     /* codepage conversion */
692     if ((size_t)(-1) == convert_string_allocate(CH_UNIX, CH_MAC, av[0], strlen(av[0]), &zname)) {
693         zname = strdup(av[0]);
694     }
695
696     /*
697      * Only process "-zone" if this interface has "-seed".  We keep our
698      * list of configured zones in the interface structure.  Then we can
699      * check that the network has given us good zones.
700      */
701     if ( iface->i_flags & IFACE_SEED ) {
702         if ( iface->i_rt == NULL ) {
703             fprintf( stderr, "Must specify net-range before zones.\n" );
704             return -1;
705         }
706
707         if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
708             perror( "newzt" );
709             return -1;
710         }
711         if ( iface->i_czt == NULL ) {
712             iface->i_czt = zt;
713         } else {
714             zt->zt_next = iface->i_czt->zt_next;
715             iface->i_czt->zt_next = zt;
716         }
717     }
718     free(zname);
719
720     return( 2 );
721 }
722
723 /*
724  * Get the configuration from the kernel. Only called if there's no
725  * configuration.
726  */
727 int getifconf()
728 {
729     struct interface    *iface, *niface;
730     struct ifreq        ifr;
731     char                **start, **list;
732     int                 s;
733
734     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
735         perror( "socket" );
736         return -1;
737     }
738
739     start = list = getifacelist();
740     while (list && *list) {
741         strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
742         list++;
743
744         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
745           continue;
746
747         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
748           continue;
749
750         if ((ifr.ifr_flags & IFF_UP) == 0)
751           continue;
752
753         /* for devices that don't support appletalk */
754         if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV))
755           continue;
756
757         for ( iface = interfaces; iface; iface = iface->i_next ) {
758             if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) {
759                 break;
760             }
761         }
762         if ( iface ) {  /* Already have this interface name */
763             continue;
764         }
765
766
767 #ifdef IFF_MULTICAST
768         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
769           fprintf(stderr, "%s: multicast may not work correctly.\n",
770                   ifr.ifr_name);
771 #endif /* IFF_MULTICAST */
772
773         if (addmulti(ifr.ifr_name, NULL) < 0) {
774           fprintf(stderr, "%s: disabled.\n", ifr.ifr_name);
775           continue;
776         }
777         
778         if (( niface = newiface( ifr.ifr_name )) == NULL ) {
779             perror( "newiface" );
780             close(s);
781             freeifacelist(start);
782             return -1;
783         }
784         /*
785          * Could try to get the address from the kernel...
786          */
787
788         if ( interfaces == NULL ) {
789             interfaces = niface;
790         } else {
791             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
792                 ;
793             iface->i_next = niface;
794         }
795         niface->i_next = NULL;
796     }
797     freeifacelist(start);
798     (void)close( s );
799     return( 0 );
800 }
801
802 /*
803  * Allocate a new interface structure.  Centralized here so we can change
804  * the interface structure and have it updated nicely.
805  */
806
807 struct interface *newiface( name )
808     const char          *name;
809 {
810     struct interface    *niface;
811
812     if (( niface = (struct interface *)calloc(1, sizeof( struct interface )))
813             == NULL ) {
814         return( NULL );
815     }
816     strlcpy( niface->i_name, name, sizeof(niface->i_name));
817 #ifdef BSD4_4
818     niface->i_addr.sat_len = sizeof( struct sockaddr_at );
819 #endif /* BSD4_4 */
820     niface->i_addr.sat_family = AF_APPLETALK;
821 #ifdef BSD4_4
822     niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
823 #endif /* BSD4_4 */
824     niface->i_caddr.sat_family = AF_APPLETALK;
825 #ifdef linux
826     niface->i_flags = IFACE_ALLMULTI;
827 #endif
828     return( niface );
829 }
830
831 #ifdef __svr4__
832 int plumb()
833 {
834     struct interface    *iface;
835     char                device[ MAXPATHLEN + 1], *p, *t;
836     int                 fd, ppa;
837     int                 digits = 0;
838
839     for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
840         if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
841             continue;
842         }
843
844         strcpy( device, "/dev/" );
845         strcat( device, iface->i_name );
846         for (t = device; *t != '\0' ; ++t) {
847             if (isdigit(*t) == 0) {
848                 p = t + 1;
849             }
850             else {
851                 digits++;
852             }
853         }
854
855         if (digits == 0) {
856             LOG(log_error, logtype_atalkd, "plumb: invalid device: %s", device );
857             return -1;
858         }
859         ppa = atoi( p );
860         *p = '\0';
861
862         if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
863             LOG(log_error, logtype_atalkd, "%s: %s", device, strerror(errno) );
864             return -1;
865         }
866         if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
867             LOG(log_error, logtype_atalkd, "I_PUSH: %s", strerror(errno) );
868             close(fd);
869             return -1;
870         }
871         if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
872             LOG(log_error, logtype_atalkd, "IF_UNITSEL: %s", strerror(errno) );
873             close(fd);
874             return -1;
875         }
876
877         /* configure multicast. */
878         if (addmulti(iface->i_name, NULL) < 0) {
879           perror(iface->i_name);
880           fprintf(stderr,"Can't configure multicast.\n");
881           close(fd);
882           return -1;
883         }
884
885         LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa );
886     }
887
888     return( 0 );
889 }
890 #endif /* __svr4__ */