]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/zip.c
Remove bdb env on exit
[netatalk.git] / etc / atalkd / zip.c
1 /*
2  * $Id: zip.c,v 1.15 2009-12-13 00:31:50 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 <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <sys/param.h>
16 #include <sys/types.h>
17 #include <atalk/logger.h>
18 #include <sys/socket.h>
19 #include <sys/ioctl.h>
20 #include <sys/time.h>
21 #ifdef TRU64
22 #include <sys/mbuf.h>
23 #include <net/route.h>
24 #endif /* TRU64 */
25 #include <net/if.h>
26 #include <net/route.h>
27 #include <netatalk/endian.h>
28 #include <netatalk/at.h>
29
30 #ifdef __svr4__
31 #include <sys/sockio.h>
32 #endif /* __svr4__ */
33
34 #include <atalk/ddp.h>
35 #include <atalk/zip.h>
36 #include <atalk/atp.h>
37 #include <atalk/util.h>
38
39 #include "atserv.h"
40 #include "interface.h"
41 #include "gate.h"
42 #include "zip.h"
43 #include "rtmp.h"
44 #include "list.h"
45 #include "multicast.h"
46 #include "main.h"
47
48 struct ziptab   *ziptab = NULL, *ziplast = NULL;
49
50
51 static int zonecheck(struct rtmptab *rtmp, struct interface *iface)
52 {
53     struct list         *l;
54     struct ziptab       *czt, *zt;
55     int                 cztcnt, ztcnt;
56
57     if (( iface->i_flags & IFACE_SEED ) == 0 ) {
58         return( 0 );
59     }
60
61     for ( cztcnt = 0, czt = iface->i_czt; czt; czt = czt->zt_next, cztcnt++ ) {
62         for ( l = rtmp->rt_zt; l; l = l->l_next ) {
63             zt = (struct ziptab *)l->l_data;
64             if ( czt->zt_len == zt->zt_len &&
65                     !strndiacasecmp( czt->zt_name, zt->zt_name, czt->zt_len )) {
66                 break;
67             }
68         }
69         if ( l == NULL ) {
70             LOG(log_error, logtype_atalkd, "zonecheck: %.*s not in zone list", czt->zt_len,
71                     czt->zt_name );
72             return( -1 );       /* configured zone not found in net zones */
73         }
74     }
75
76     for ( ztcnt = 0, l = rtmp->rt_zt; l; l = l->l_next, ztcnt++ )
77         ;
78
79     if ( cztcnt != ztcnt ) {
80         LOG(log_error, logtype_atalkd, "zonecheck: %d configured zones, %d zones found",
81                 cztcnt, ztcnt );
82         return( -1 );           /* more net zones than configured zones */
83     }
84
85     return( 0 );
86 }
87
88
89 int zip_packet(struct atport *ap,struct sockaddr_at *from, char *data, int len)
90 {
91     struct ziphdr       zh;
92     struct atphdr       ah;
93     struct interface    *iface;
94     struct gate         *gate;
95     struct rtmptab      *rtmp = NULL;
96     struct list         *l;
97     struct ziptab       *zt;
98     u_short             firstnet, lastnet, index, nz;
99     char                *end, zname[ 32 ], packet[ ATP_BUFSIZ ], *nzones, *lastflag;
100     char                *reply, *rend, *ziphdr;
101     int                 zlen, n, zipop, rcnt, qcnt, zcnt, zsz;
102     extern int          stabletimer;
103
104     end = data + len;
105
106     if ( data >= end ) {
107         LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
108         return 1;
109     }
110
111     /* get interface */
112     iface = ap->ap_iface;
113
114     switch( *data++ ) {
115     case DDPTYPE_ZIP :
116         if ( data + sizeof( struct ziphdr ) > end ) {
117             LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
118             return 1;
119         }
120         memcpy( &zh, data, sizeof( struct ziphdr ));
121         data += sizeof( struct ziphdr );
122
123         switch ( zh.zh_op ) {
124         case ZIPOP_QUERY :
125             /* set up reply */
126             reply = packet;
127             rend = packet + sizeof( packet );
128             *reply++ = DDPTYPE_ZIP;
129             ziphdr = reply;
130             reply += 2;
131             rcnt = 0;
132
133             qcnt = zh.zh_count;
134
135             while ( data + sizeof( u_short ) <= end && qcnt-- > 0 ) {
136                 memcpy( &firstnet, data, sizeof( u_short ));
137                 data += sizeof( u_short );
138
139                 /*
140                  * Look for the given network number (firstnet).
141                  * Perhaps we could do better than brute force?
142                  */
143                 for ( iface = interfaces; iface; iface = iface->i_next ) {
144                     for ( rtmp = iface->i_rt; rtmp; rtmp = rtmp->rt_inext ) {
145                         if ( firstnet == rtmp->rt_firstnet ) {
146                             break;
147                         }
148                     }
149                     if ( rtmp ) {
150                         break;
151                     }
152                 }
153                 if ( rtmp == NULL ) {
154                     continue;
155                 }
156
157                 /*
158                  * Count the number of zones in this list, and the
159                  * number of byte it will consume in a reply.
160                  */
161                 for ( zsz = 0, zcnt = 0, l = rtmp->rt_zt; l; l = l->l_next ) {
162                     zcnt++;
163                     zt = (struct ziptab *)l->l_data;
164                     zsz += sizeof( u_short ) + 1 + zt->zt_len;
165                 }
166
167                 /*
168                  * We might send this list in the current reply, as the
169                  * first thing in the next reply, or as an extended packet.
170                  */
171                 if ( reply + zsz > rend ) {
172                     if ( rcnt > 0 ) {
173                         zh.zh_op = ZIPOP_REPLY;
174                         zh.zh_cnt = rcnt;
175                         memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
176                         if ( sendto( ap->ap_fd, packet, reply - packet, 0,
177                                 (struct sockaddr *)from,
178                                 sizeof( struct sockaddr_at )) < 0 ) {
179                             LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
180                                     strerror(errno) );
181                         }
182
183                         reply = packet + 3;
184                         rcnt = 0;
185                     }
186
187                     if ( reply + zsz > rend ) {
188                         /* ereply */
189                         for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
190                             zt = (struct ziptab *)l->l_data;
191                             if ( reply + sizeof( u_short ) + 1 + zt->zt_len >
192                                     rend ) {
193                                 zh.zh_op = ZIPOP_EREPLY;
194                                 zh.zh_cnt = zcnt;
195                                 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
196                                 if ( sendto( ap->ap_fd, packet, reply - packet,
197                                         0, (struct sockaddr *)from,
198                                         sizeof( struct sockaddr_at )) < 0 ) {
199                                     LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
200                                             strerror(errno) );
201                                 }
202
203                                 reply = packet + 3;
204                                 rcnt = 0;
205                             }
206
207                             memcpy( reply, &firstnet, sizeof( u_short ));
208                             reply += sizeof( u_short );
209                             *reply++ = zt->zt_len;
210                             memcpy( reply, zt->zt_name, zt->zt_len );
211                             reply += zt->zt_len;
212                         }
213
214                         if ( rcnt > 0 ) {
215                             zh.zh_op = ZIPOP_EREPLY;
216                             zh.zh_cnt = zcnt;
217                             memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
218                             if ( sendto( ap->ap_fd, packet, reply - packet, 0,
219                                     (struct sockaddr *)from,
220                                     sizeof( struct sockaddr_at )) < 0 ) {
221                                 LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
222                                         strerror(errno) );
223                             }
224
225                             reply = packet + 3;
226                             rcnt = 0;
227                         }
228                         continue;
229                     }
230                 }
231
232                 for ( l = rtmp->rt_zt; l; l = l->l_next, rcnt++ ) {
233                     zt = (struct ziptab *)l->l_data;
234                     memcpy( reply, &firstnet, sizeof( u_short ));
235                     reply += sizeof( u_short );
236                     *reply++ = zt->zt_len;
237                     memcpy( reply, zt->zt_name, zt->zt_len );
238                     reply += zt->zt_len;
239                 }
240             }
241
242             if ( rcnt > 0 ) {
243                 zh.zh_op = ZIPOP_REPLY;
244                 zh.zh_cnt = rcnt;
245                 memcpy( ziphdr, &zh, sizeof( struct ziphdr ));
246                 if ( sendto( ap->ap_fd, packet, reply - packet, 0,
247                         (struct sockaddr *)from,
248                         sizeof( struct sockaddr_at )) < 0 ) {
249                     LOG(log_error, logtype_atalkd, "zip reply sendto: %s",
250                             strerror(errno) );
251                 }
252             }
253             break;
254
255         case ZIPOP_REPLY :
256             for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
257                 if (( from->sat_addr.s_net == 0 ||
258                         gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
259                         gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
260                     break;
261                 }
262             }
263             if ( gate == NULL ) {
264                 LOG(log_info, logtype_atalkd, "zip reply from non-gateway %u.%u", 
265                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
266                 return 1;
267             }
268
269             rtmp = NULL;
270
271             do {
272                 if ( data + sizeof( u_short ) + 1 > end ) {     /* + strlen */
273                     LOG(log_info, logtype_atalkd, "zip reply short (%d)", len );
274                     return 1;
275                 }
276                 memcpy( &firstnet, data, sizeof( u_short ));
277                 data += sizeof( u_short );
278
279                 if ( rtmp && rtmp->rt_firstnet != firstnet ) {
280                     /* XXX */
281                     if ( rtmp->rt_gate == NULL &&
282                             zonecheck( rtmp, gate->g_iface ) != 0 ) {
283                         LOG(log_error, logtype_atalkd, "zip_packet seed zonelist mismatch" );
284                         return -1;
285                     }
286                     rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
287                 }
288
289                 /* Check if this is the interface's route. */
290                 if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
291                     rtmp = gate->g_iface->i_rt;
292                 } else {
293                     for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
294                         if ( rtmp->rt_firstnet == firstnet ) {
295                             break;
296                         }
297                     }
298
299                     /*
300                      * Update head to this rtmp entry.
301                      */
302                     if ( rtmp != NULL && gate->g_rt != rtmp ) {
303                         gate->g_rt->rt_prev->rt_next = gate->g_rt;
304                         gate->g_rt = rtmp;
305                         rtmp->rt_prev->rt_next = NULL;
306                     }
307                 }
308
309                 zlen = *data++;
310                 if ( zlen > 32 || zlen <= 0 ) {
311                     LOG(log_info, logtype_atalkd, "zip reply bad packet" );
312                     return 1;
313                 }
314                 if ( data + zlen > end ) {
315                     LOG(log_info, logtype_atalkd, "zip reply short (%d)", len );
316                     return 1;
317                 }
318                 memcpy( zname, data, zlen );
319                 data += zlen;
320
321                 /*
322                  * We won't find any rtmp entry if the gateway is no longer
323                  * telling us about the entry.
324                  */
325                 if ( rtmp == NULL ) {
326                     LOG(log_info, logtype_atalkd, "zip skip reply %u from %u.%u (no rtmp)",
327                             ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
328                             from->sat_addr.s_node );
329                 /*
330                  * Check if the route is still in use (the iprev check is
331                  * no good if rtmp is the interface's route).
332                  */
333                 } else if ( rtmp->rt_iprev == NULL && rtmp->rt_prev != NULL ) {
334                     LOG(log_info, logtype_atalkd,
335                             "zip skip reply %u-%u from %u.%u (rtmp not in use)",
336                             ntohs( rtmp->rt_firstnet ),
337                             ntohs( rtmp->rt_lastnet ),
338                             ntohs( from->sat_addr.s_net ),
339                             from->sat_addr.s_node );
340                 /*
341                  * Check if we've got an outstanding query for this route.
342                  * We will often get this, since we ask every router on a
343                  * net to verify our interface's zone(s).
344                  */
345                 } else if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
346                     LOG(log_info, logtype_atalkd,
347                             "zip skip reply %u-%u from %u.%u (no query)",
348                             ntohs( rtmp->rt_firstnet ),
349                             ntohs( rtmp->rt_lastnet ),
350                             ntohs( from->sat_addr.s_net ),
351                             from->sat_addr.s_node );
352                 } else {
353                     if (addzone( rtmp, zlen, zname ) < 0) {
354                         LOG(log_error, logtype_atalkd, "zip_packet: addzone");
355                         return -1;
356                     }
357                     rtmp->rt_flags |= RTMPTAB_HASZONES;
358                 }
359             } while ( data < end );
360
361             if ( rtmp && rtmp->rt_flags & RTMPTAB_HASZONES ) {
362                 /* XXX */
363                 if ( rtmp->rt_gate == NULL &&
364                         zonecheck( rtmp, gate->g_iface ) != 0 ) {
365                     LOG(log_error, logtype_atalkd, "zip_packet seed zonelist mismatch" );
366                     return -1;
367                 }
368                 rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
369             }
370             break;
371
372         case ZIPOP_EREPLY :
373             for ( gate = iface->i_gate; gate; gate = gate->g_next ) {
374                 if (( from->sat_addr.s_net == 0 ||
375                         gate->g_sat.sat_addr.s_net == from->sat_addr.s_net ) &&
376                         gate->g_sat.sat_addr.s_node == from->sat_addr.s_node ) {
377                     break;
378                 }
379             }
380             if ( gate == NULL ) {
381                 LOG(log_info, logtype_atalkd, "zip ereply from non-gateway %u.%u", 
382                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
383                 return 1;
384             }
385
386             /*
387              * Note that we're not advancing "data" here.  We do that
388              * at the top of the do-while loop, below.
389              */
390             if ( data + sizeof( u_short ) + 1 > end ) { /* + strlen */
391                 LOG(log_info, logtype_atalkd, "zip ereply short (%d)", len );
392                 return 1;
393             }
394             memcpy( &firstnet, data, sizeof( u_short ));
395
396             /* Check if this is the interface's route. */
397             if ( firstnet == gate->g_iface->i_rt->rt_firstnet ) {
398                 rtmp = gate->g_iface->i_rt;
399             } else {
400                 for ( rtmp = gate->g_rt; rtmp; rtmp = rtmp->rt_next ) {
401                     if ( rtmp->rt_firstnet == firstnet ) {
402                         break;
403                     }
404                 }
405                 if ( rtmp == NULL ) {
406                     LOG(log_info, logtype_atalkd, "zip ereply %u from %u.%u (no rtmp)",
407                             ntohs( firstnet ), ntohs( from->sat_addr.s_net ),
408                             from->sat_addr.s_node );
409                     return 1;
410                 }
411                 if ( rtmp->rt_iprev == NULL ) {
412                     LOG(log_info, logtype_atalkd,
413                             "zip ereply %u-%u from %u.%u (rtmp not in use)",
414                             ntohs( rtmp->rt_firstnet ),
415                             ntohs( rtmp->rt_lastnet ),
416                             ntohs( from->sat_addr.s_net ),
417                             from->sat_addr.s_node );
418                 }
419
420                 /* update head to *next* rtmp entry */
421                 if ( rtmp->rt_next != NULL ) {
422                     gate->g_rt->rt_prev->rt_next = gate->g_rt;
423                     gate->g_rt = rtmp->rt_next;
424                     rtmp->rt_next = NULL;
425                 }
426             }
427
428             if (( rtmp->rt_flags & RTMPTAB_ZIPQUERY ) == 0 ) {
429                 LOG(log_info, logtype_atalkd, "zip ereply %u-%u from %u.%u (no query)",
430                         ntohs( rtmp->rt_firstnet ),
431                         ntohs( rtmp->rt_lastnet ),
432                         ntohs( from->sat_addr.s_net ),
433                         from->sat_addr.s_node );
434                 return 0;
435             }
436
437             do {
438                 /*
439                  * We copy out firstnet, twice (see above).  Not
440                  * a big deal, and it makes the end condition cleaner.
441                  */
442                 if ( data + sizeof( u_short ) + 1 > end ) {     /* + strlen */
443                     LOG(log_info, logtype_atalkd, "zip ereply short (%d)", len );
444                     return 1;
445                 }
446                 memcpy( &firstnet, data, sizeof( u_short ));
447                 data += sizeof( u_short );
448
449                 /* check route */
450                 if ( firstnet != rtmp->rt_firstnet ) {
451                     LOG(log_info, logtype_atalkd, "zip ereply with multiple nets" );
452                     return 1;
453                 }
454
455                 zlen = *data++;
456                 if ( zlen > 32 || zlen <= 0 ) {
457                     LOG(log_info, logtype_atalkd, "zip ereply bad zone length (%d)", zlen );
458                     return 1;
459                 }
460                 if ( data + zlen > end ) {
461                     LOG(log_info, logtype_atalkd, "zip ereply short (%d)", len );
462                     return 1;
463                 }
464                 memcpy( zname, data, zlen );
465                 data += zlen;
466                 if (addzone( rtmp, zlen, zname ) < 0) {
467                     LOG(log_error, logtype_atalkd, "zip_packet: addzone");
468                     return -1;
469                 }
470             } while ( data < end );
471
472             if ( rtmp ) {
473                 /*
474                  * Count zones for rtmptab entry.
475                  */
476                 for ( n = 0, l = rtmp->rt_zt; l; l = l->l_next, n++ )
477                     ;
478                 if ( n == zh.zh_count ) {
479                     rtmp->rt_flags |= RTMPTAB_HASZONES;
480                     /* XXX */
481                     if ( rtmp->rt_gate == NULL &&
482                             zonecheck( rtmp, gate->g_iface ) != 0 ) {
483                         LOG(log_error, logtype_atalkd, "zip_packet seed zonelist mismatch" );
484                         return -1;
485                     }
486                     rtmp->rt_flags &= ~RTMPTAB_ZIPQUERY;
487                 }
488             }
489             break;
490
491         case ZIPOP_GNI :
492             /*
493              * Don't answer with bogus information.
494              */
495             if (((iface->i_flags & IFACE_ISROUTER) == 0) ||
496                 iface->i_rt->rt_zt == NULL ||
497                 ( iface->i_flags & IFACE_CONFIG ) == 0 ) {
498                 return 0;
499             }
500
501             if ( zh.zh_zero != 0 || data + 2 * sizeof( u_short ) > end ) {
502                 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
503                 return 1;
504             }
505
506             memcpy( &firstnet, data, sizeof( u_short ));
507             data += sizeof( u_short );
508             memcpy( &lastnet, data, sizeof( u_short ));
509             data += sizeof( u_short );
510             if ( firstnet != 0 || lastnet != 0 || data >= end ) {
511                 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
512                 return 1;
513             }
514
515             zlen = *data++;
516             if ( zlen < 0 || zlen > 32 ) {
517                 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
518                 return 1;
519             }
520             memcpy( zname, data, zlen );
521
522             data = packet;
523             end = data + sizeof( packet );
524             zh.zh_op = ZIPOP_GNIREPLY;
525             zh.zh_flags = 0;
526
527             /*
528              * Skip to the nets.  Fill in header when we're done.
529              */
530             data += 1 + sizeof( struct ziphdr );
531             memcpy( data, &iface->i_rt->rt_firstnet, sizeof( u_short ));
532             data += sizeof( u_short );
533             memcpy( data, &iface->i_rt->rt_lastnet, sizeof( u_short ));
534             data += sizeof( u_short );
535
536             *data++ = zlen;
537             memcpy( data, zname, zlen );
538             data += zlen;
539
540             /*
541              * Check if the given zone is valid.  If it's valid, just fill in
542              * the multicast address.  If it's not, fill the multicast address
543              * in with the default zone and return the default zone.
544              */
545             for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
546                 zt = (struct ziptab *)l->l_data;
547                 if ( zt->zt_len == zlen &&
548                         strndiacasecmp( zname, zt->zt_name, zlen ) == 0 ) {
549                     break;
550                 }
551             }
552             if ( l == NULL ) {
553                 zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
554                 zh.zh_flags |= ZIPGNI_INVALID;
555             }
556
557             for ( n = 0, l = iface->i_rt->rt_zt; l; l = l->l_next, n++ )
558                 ;
559             if ( n == 1 ) {
560                 zh.zh_flags |= ZIPGNI_ONEZONE;
561             }
562
563             /* multicast */
564             *data++ = 6;        /* sizeof ??? */
565             if (zone_bcast(zt) < 0) {
566               LOG(log_error, logtype_atalkd, "zip_packet: zone_bcast");
567               return -1;
568             }
569             memcpy(data, zt->zt_bcast, 6);
570             data += 6;
571
572             /*
573              * Add default zone.
574              */
575             if ( zh.zh_flags & ZIPGNI_INVALID ) {
576                 *data++ = zt->zt_len;
577                 memcpy( data, zt->zt_name, zt->zt_len );
578                 data += zt->zt_len;
579             }
580
581             /* fill in header */
582             *packet = DDPTYPE_ZIP;
583             memcpy( packet + 1, &zh, sizeof( struct ziphdr ));
584
585             /*
586              * If the address we received this request from isn't correct
587              * for the net we received it on, send a broadcast.
588              */
589             if ( ntohs( from->sat_addr.s_net ) <
590                     ntohs( iface->i_rt->rt_firstnet ) ||
591                     ntohs( from->sat_addr.s_net ) >
592                     ntohs( iface->i_rt->rt_lastnet )) {
593                 from->sat_addr.s_net = 0;
594                 from->sat_addr.s_node = ATADDR_BCAST;
595             }
596
597             if ( sendto( ap->ap_fd, packet, data - packet, 0,
598                     (struct sockaddr *)from,
599                     sizeof( struct sockaddr_at )) < 0 ) {
600                 LOG(log_error, logtype_atalkd, "zip gni sendto %u.%u: %s",
601                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
602                         strerror(errno) );
603                 return 1;
604             }
605             break;
606
607         case ZIPOP_GNIREPLY :
608             /*
609              * Ignore ZIP GNIReplys which are either late or unsolicited.
610              */
611             LOG(log_debug, logtype_atalkd, "zip gnireply from %u.%u (%s %x)",
612                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
613                     iface->i_name, iface->i_flags );
614
615             if (( iface->i_flags & ( IFACE_CONFIG|IFACE_PHASE1 )) ||
616                     ( iface->i_flags & IFACE_ADDR ) == 0 ) {
617                 LOG(log_debug, logtype_atalkd, "zip ignoring gnireply" );
618                 return 1;
619             }
620
621             if ( data + 2 * sizeof( u_short ) > end ) {
622                 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
623                 return 1;
624             }
625             memcpy( &firstnet, data, sizeof( u_short ));
626             data += sizeof( u_short );
627             memcpy( &lastnet, data, sizeof( u_short ));
628             data += sizeof( u_short );
629
630             /*
631              * We never ask for a zone, so we can get back what the
632              * default zone is.
633              */
634             if ( data >= end || data + *data > end ) {
635                 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
636                 return 1;
637             }
638             if ( *data++ != 0 ) {
639                 LOG(log_info, logtype_atalkd, "zip_packet unsolicited zone" );
640                 return 1;
641             }
642
643             /* skip multicast (should really check it) */
644             if ( data >= end || data + *data > end ) {
645                 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
646                 return 1;
647             }
648             data += *data + 1;
649
650             if ( data >= end || data + *data > end ) {
651                 LOG(log_info, logtype_atalkd, "zip_packet malformed packet" );
652                 return 1;
653             }
654
655             /*
656              * First, if we're not seed, we always get our zone information
657              * from the net -- we don't even save what was in the file.
658              * Second, if we are seed, we keep our zone list in the
659              * interface structure, not in the zone table.  This allows us
660              * to check that the net is giving us good zones.
661              */
662             if ( (iface->i_flags & IFACE_SEED) && iface->i_czt) {
663                 if ( iface->i_czt->zt_len != *data ||
664                         strndiacasecmp( iface->i_czt->zt_name,
665                         data + 1, *data ) != 0 ) {
666                     LOG(log_error, logtype_atalkd, "default zone mismatch on %s",
667                             iface->i_name );
668                     LOG(log_error, logtype_atalkd, "%.*s != %.*s",
669                             iface->i_czt->zt_len, iface->i_czt->zt_name,
670                             *data, data + 1 );
671                     LOG(log_error, logtype_atalkd, "Seed error! Exiting!" );
672                     return -1;
673                 }
674             }
675
676             if (addzone( iface->i_rt, *data, data + 1 ) < 0) {
677                 LOG(log_error, logtype_atalkd, "zip_packet: addzone");
678                 return -1;
679             }
680             
681             /*
682              * The netrange we received from the router doesn't match the
683              * range we have locally. This is not a problem, unless we
684              * have seed information.
685              */
686             if ( firstnet != iface->i_rt->rt_firstnet ||
687                     lastnet != iface->i_rt->rt_lastnet ) {
688                 if ( iface->i_flags & IFACE_SEED ) {
689                     LOG(log_error, logtype_atalkd, "netrange mismatch on %s",
690                             iface->i_name );
691                     LOG(log_error, logtype_atalkd, "%u-%u != %u-%u",
692                             ntohs( firstnet ), ntohs( lastnet ),
693                             ntohs( iface->i_rt->rt_firstnet ),
694                             ntohs( iface->i_rt->rt_lastnet ));
695                     LOG(log_error, logtype_atalkd, "Seed error! Exiting!" );
696                     return -1;
697                 }
698
699
700                 /*
701                  * It is possible that we will corrupt our route database
702                  * by just forcing this change.  A better solution would
703                  * be to search all of our current routes, looking for
704                  * this new route, and delete any old versions.  Also, we
705                  * would call rtmp_delete() on the old net range, in case
706                  * there is some other net which actually had that range.  XXX
707                  */
708                 iface->i_rt->rt_firstnet = firstnet;
709                 iface->i_rt->rt_lastnet = lastnet;
710
711                 if ( ntohs( iface->i_addr.sat_addr.s_net ) <
712                         ntohs( firstnet ) ||
713                         ntohs( iface->i_addr.sat_addr.s_net ) >
714                         ntohs( lastnet )) {
715                     iface->i_addr.sat_addr.s_net = 0;   /* ATADDR_ANYNET? */
716                 }
717                 setaddr( iface, IFACE_PHASE2, iface->i_addr.sat_addr.s_net,
718                         iface->i_addr.sat_addr.s_node, firstnet, lastnet );
719                 stabletimer = UNSTABLE;
720             }
721
722             /* add addr to loopback route */
723             if ( looproute( iface, RTMP_ADD )) { /* -1 or 1 */
724                 LOG(log_error, logtype_atalkd,
725                         "zip_packet: can't route %u.%u to loopback: %s",
726                         ntohs( iface->i_addr.sat_addr.s_net ),
727                         iface->i_addr.sat_addr.s_node,
728                         strerror(errno) );
729                 return -1;
730             }
731
732             LOG(log_info, logtype_atalkd, "zip_packet configured %s from %u.%u",
733                     iface->i_name, ntohs( from->sat_addr.s_net ),
734                     from->sat_addr.s_node );
735             iface->i_flags |= IFACE_CONFIG;
736             if ( iface == ciface ) {
737                 ciface = ciface->i_next;
738                 bootaddr( ciface );
739             }
740             break;
741
742         case ZIPOP_NOTIFY :
743 #ifdef DEBUG
744             printf( "zip notify from %u.%u\n", ntohs( from->sat_addr.s_net ),
745                     from->sat_addr.s_node );
746 #endif /* DEBUG */
747             break;
748
749         default :
750             LOG(log_info, logtype_atalkd, "zip_packet bad zip op from %u.%u",
751                     ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
752         }
753         break;
754
755     case DDPTYPE_ATP :
756         if ( data + sizeof( struct atphdr ) > end ) {
757             LOG(log_info, logtype_atalkd, "zip atp malformed packet" );
758             return 1;
759         }
760         memcpy( &ah, data, sizeof( struct atphdr ));
761         data += sizeof( struct atphdr );
762         if ( ah.atphd_ctrlinfo != ATP_TREQ ) {
763             LOG(log_info, logtype_atalkd, "zip atp bad control" );
764             return 1;
765         }
766         ah.atphd_ctrlinfo = ATP_TRESP | ATP_EOM;
767         if ( ah.atphd_bitmap != 1 ) {
768             LOG(log_error, logtype_atalkd, "zip atp bad bitmap" );
769             return 1;
770         }
771         ah.atphd_bitmap = 0;
772
773         zipop = *data++;
774         data++;
775         memcpy( &index, data, sizeof( u_short ));
776         data += sizeof( u_short );
777         index = ntohs( index );
778         if ( data != end ) {
779             LOG(log_info, logtype_atalkd, "zip atp malformed packet" );
780             return 1;
781         }
782
783         data = packet;
784         end = data + sizeof( packet );
785         *data++ = DDPTYPE_ATP;
786         memcpy( data, &ah, sizeof( struct atphdr ));
787         data += sizeof( struct atphdr );
788         lastflag = data++;              /* mark and space for last flag */
789         *data++ = 0;
790         nzones = data;                  /* mark and space for zone count */
791         data += sizeof( u_short );
792
793         switch ( zipop ) {
794         case ZIPOP_GETMYZONE :
795             if ( index != 0 ) {
796                 LOG(log_info, logtype_atalkd, "zip atp gmz bad index" );
797                 return 1;
798             }
799
800             if ( iface->i_flags & IFACE_LOOPBACK ) {
801                 iface = interfaces->i_next;     /* first interface */
802             } else if ( ntohs( iface->i_rt->rt_firstnet ) >
803                     ntohs( from->sat_addr.s_net ) ||
804                     ntohs( iface->i_rt->rt_lastnet ) <
805                     ntohs( from->sat_addr.s_net )) {
806                 return 0;
807             }
808
809             if ( iface->i_rt->rt_zt == NULL ) {
810                 return 0;
811             }
812             zt = (struct ziptab *)iface->i_rt->rt_zt->l_data;
813             if ( data + 1 + zt->zt_len > end ) {
814                 LOG(log_info, logtype_atalkd, "zip atp gmz reply too long" );
815                 return 1;
816             }
817             *data++ = zt->zt_len;
818             memcpy( data, zt->zt_name, zt->zt_len );
819             data += zt->zt_len;
820
821             *lastflag = 0;
822             nz = 1;
823             break;
824
825         case ZIPOP_GETZONELIST :
826             for ( zt = ziptab; zt && ( index > 1 ); zt = zt->zt_next, index-- )
827                 ;
828             for ( nz = 0; zt; zt = zt->zt_next, nz++ ) {
829                 if ( data + 1 + zt->zt_len > end ) {
830                     break;
831                 }
832                 *data++ = zt->zt_len;
833                 memcpy( data, zt->zt_name, zt->zt_len );
834                 data += zt->zt_len;
835             }
836
837             *lastflag = ( zt == NULL );         /* Too clever? */
838             break;
839
840         case ZIPOP_GETLOCALZONES :
841             if ( iface->i_flags & IFACE_LOOPBACK ) {
842                 iface = interfaces->i_next;     /* first interface */
843             } else if ( ntohs( iface->i_rt->rt_firstnet ) >
844                     ntohs( from->sat_addr.s_net ) ||
845                     ntohs( iface->i_rt->rt_lastnet ) <
846                     ntohs( from->sat_addr.s_net )) {
847                 return 0;
848             }
849
850             for ( l = iface->i_rt->rt_zt; l && ( index > 1 );
851                     l = l->l_next, index-- )
852                 ;
853             for ( nz = 0; l; l = l->l_next, nz++ ) {
854                 zt = (struct ziptab *)l->l_data;
855                 if ( data + 1 + zt->zt_len > end ) {
856                     break;
857                 }
858                 *data++ = zt->zt_len;
859                 memcpy( data, zt->zt_name, zt->zt_len );
860                 data += zt->zt_len;
861             }
862
863             *lastflag = ( l == NULL );
864             break;
865
866         default :
867             LOG(log_info, logtype_atalkd, "zip atp bad option" );
868             return 1;
869         }
870
871         /* send reply */
872         if ( nz > 0 ) {
873             nz = htons( nz );
874             memcpy( nzones, &nz, sizeof( u_short ));
875             if ( sendto( ap->ap_fd, packet, data - packet, 0,
876                     (struct sockaddr *)from,
877                     sizeof( struct sockaddr_at )) < 0 ) {
878                 LOG(log_error, logtype_atalkd, "zip atp sendto %u.%u: %s",
879                         ntohs( from->sat_addr.s_net ), from->sat_addr.s_node,
880                         strerror(errno) );
881                 return 1;
882             }
883         }
884         break;
885
886     default :
887         LOG(log_info, logtype_atalkd, "zip_packet bad ddp type from %u.%u",
888                 ntohs( from->sat_addr.s_net ), from->sat_addr.s_node );
889         return 1;
890     }
891
892     return 0;
893 }
894
895 int zip_getnetinfo(struct interface *iface)
896 {
897     struct atport       *ap;
898     struct ziphdr       zh;
899     struct sockaddr_at  sat;
900     char                *data, packet[ 40 ];
901     u_short             net;
902
903     LOG(log_info, logtype_atalkd, "zip_getnetinfo for %s", iface->i_name );
904
905     for ( ap = iface->i_ports; ap; ap = ap->ap_next ) {
906         if ( ap->ap_packet == zip_packet ) {
907             break;
908         }
909     }
910     if ( ap == NULL ) {
911         LOG(log_error, logtype_atalkd, "zip_getnetinfo can't find zip socket!" );
912         return -1;
913     }
914
915     data = packet;
916
917     *data++ = DDPTYPE_ZIP;
918
919     zh.zh_op = ZIPOP_GNI;
920     zh.zh_zero = 0;
921     memcpy( data, &zh, sizeof( struct ziphdr ));
922     data += sizeof( struct ziphdr );
923     net = 0;
924     memcpy( data, &net, sizeof( u_short ));
925     data += sizeof( u_short );
926     memcpy( data, &net, sizeof( u_short ));
927     data += sizeof( u_short );
928
929     /*
930      * Set our requesting zone to NULL, so the response will contain
931      * the default zone.
932      */
933     *data++ = 0;
934
935 #ifdef BSD4_4
936     sat.sat_len = sizeof( struct sockaddr_at );
937 #endif /* BSD4_4 */
938     sat.sat_family = AF_APPLETALK;
939     sat.sat_addr.s_net = 0;
940     sat.sat_addr.s_node = ATADDR_BCAST;
941     sat.sat_port = ap->ap_port;
942
943     if ( sendto( ap->ap_fd, packet, data - packet, 0, (struct sockaddr *)&sat,
944             sizeof( struct sockaddr_at )) < 0 ) {
945         LOG(log_error, logtype_atalkd, "zip_getnetinfo sendto: %s", strerror(errno) );
946         return -1;
947     }
948     return 0;
949 }
950
951 struct ziptab *newzt(const int len, const char *name)
952 {
953     struct ziptab       *zt;
954
955     if (( zt = (struct ziptab *)calloc(1, sizeof( struct ziptab ))) == NULL ) {
956         return( NULL );
957     }
958
959     zt->zt_len = len;
960     if (( zt->zt_name = (char *)malloc( len )) == NULL ) {
961         free(zt);
962         return( NULL );
963     }
964
965     memcpy( zt->zt_name, name, len );
966     return( zt );
967 }
968
969
970 /*
971  * Insert at the end.  Return 1 if a mapping already exists, 0 otherwise.
972  * -1 on error.
973  */
974 static int add_list(struct list **head, void *data)
975 {
976     struct list *l, *l2;
977
978     for ( l = *head; l; l = l->l_next ) {
979         if ( l->l_data == data ) {
980             return( 1 );
981         }
982     }
983     if (( l = (struct list *)malloc( sizeof( struct list ))) == NULL ) {
984         LOG(log_error, logtype_atalkd, "add_list malloc: %s", strerror(errno) );
985         return -1;
986     }
987
988     l->l_data = data;
989     l->l_next = NULL;
990     if ( *head == NULL ) {
991         l->l_prev = NULL;
992         *head = l;
993     } else {
994         /* find end of list */
995         for ( l2 = *head; l2->l_next; l2 = l2->l_next )
996             ;
997         l->l_prev = l2;
998         l2->l_next = l;
999     }
1000     return( 0 );
1001 }
1002
1003 int addzone(struct rtmptab *rt, int len, char *zone)
1004 {
1005     struct ziptab       *zt;
1006     int                 cc, exists = 0;
1007
1008     for ( zt = ziptab; zt; zt = zt->zt_next ) {
1009         if ( zt->zt_len == len &&
1010                 strndiacasecmp( zt->zt_name, zone, len ) == 0 ) {
1011             break;
1012         }
1013     }
1014     if ( zt == NULL ) {
1015         if (( zt = newzt( len, zone )) == NULL ) {
1016             LOG(log_error, logtype_atalkd, "addzone newzt: %s", strerror(errno) );
1017             return -1;
1018         }
1019         if ( ziptab == NULL ) {
1020             zt->zt_prev = NULL;
1021             ziptab = zt;
1022         } else {
1023             zt->zt_prev = ziplast;
1024             ziplast->zt_next = zt;
1025         }
1026         ziplast = zt;
1027     }
1028
1029     if ((cc = add_list( &zt->zt_rt, rt )) < 0) 
1030       return -1;
1031
1032     if (cc)
1033       exists++;
1034
1035     if ((cc = add_list( &rt->rt_zt, zt )) < 0 )
1036       return -1;
1037
1038     if (cc) {
1039         if ( !exists ) {
1040             LOG(log_error, logtype_atalkd, "addzone corrupted route/zone mapping" );
1041             return -1;
1042         }
1043         /*
1044          * We get the repeat for local nets which have zone information
1045          * already: we ask anyway, just to make sure.
1046          */
1047         
1048         return 0;
1049     }
1050     if ( exists ) {
1051         LOG(log_error, logtype_atalkd, "addzone corrupted zone/route mapping" );
1052         return -1;
1053     }
1054     return 0;
1055 }