]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/bdump.c
r4280@bucket (orig r270): kcr | 2008-01-21 14:12:44 -0500
[1ts-debian.git] / zephyr / server / bdump.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains functions for dumping server state between servers.
3  *
4  *      Created by:     John T. Kohl
5  *
6  *      $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/bdump.c,v $
7  *      $Id$
8  *      $Author$
9  *
10  *      Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology.
11  *      For copying and distribution information, see the file
12  *      "mit-copyright.h". 
13  */
14
15 #include <zephyr/mit-copyright.h>
16 #include "zserver.h"
17 #include <sys/socket.h>
18 #include <com_err.h>
19
20 #ifndef lint
21 static const char rcsid_bdump_c[] = "$Id$";
22 #endif /* lint */
23
24 /*
25  * External functions are:
26  *
27  * void bdump_offer(who)
28  *      strut sockaddr_in *who;
29  *
30  * void bdump_send()
31  *
32  * void bdump_get(notice, auth, who, server)
33  *      ZNotice_t *notice;
34  *      int auth;
35  *      struct sockaddr_in *who;
36  *      Server *server;
37  *
38  * Code_t bdump_send_list_tcp(kind, port, class, inst, opcode,
39  *                          sender, recip, lyst, num)
40  *      ZNotice_Kind_t kind;
41  *      u_short port;
42  *      char *class, *inst, *opcode, *sender, *recip;
43  *      char *lyst[];
44  *      int num;
45  */
46
47 #if defined(HAVE_KRB5) && 0
48 int krb5_init_keyblock(krb5_context context,
49         krb5_enctype type,
50         size_t size,
51         krb5_keyblock **akey)
52 {
53 krb5_error_code ret;
54 size_t len;
55 krb5_keyblock *key;
56
57 *akey=NULL;
58 key=malloc(sizeof(*key));
59 memset(key, 0, sizeof(*key));
60 ret = krb5_enctype_keysize(context, type, &len);
61 if (ret)
62 return ret;
63
64 if (len != size) {
65 krb5_set_error_string(context, "Encryption key %d is %lu bytes "
66 "long, %lu was passed in",
67 type, (unsigned long)len, (unsigned long)size);
68 return KRB5_PROG_ETYPE_NOSUPP;
69 }
70
71 ret = krb5_data_alloc(&key->keyvalue, len);
72 if(ret) {
73 krb5_set_error_string(context, "malloc failed: %lu",
74 (unsigned long)len);
75 return ret;
76 }
77 key->keytype = type;
78 *akey=key;
79 return 0;
80 }
81 #endif
82
83
84 static void close_bdump(void* arg);
85 static Code_t bdump_send_loop(Server *server);
86 static Code_t bdump_recv_loop(Server *server);
87 static void bdump_get_v12(ZNotice_t *, int, struct sockaddr_in *,
88                                Server *);
89 static Code_t get_packet(void *packet, int len, int *retlen);
90 static Code_t extract_sin(ZNotice_t *notice, struct sockaddr_in *target);
91 static Code_t send_done(void);
92 static Code_t send_list(ZNotice_Kind_t kind, int port, char *class_name,
93                              char *inst, char *opcode, char *sender,
94                              char *recip, char **lyst, int num);
95 static Code_t send_normal_tcp(ZNotice_Kind_t kind, int port,
96                                    char *class_name,
97                                    char *inst, char *opcode, char *sender,
98                                    char *recip, char *message, int len);
99 static int net_read(FILE *f, char *buf, int len);
100 static int net_write(FILE *f, char *buf, int len);
101 static int setup_file_pointers(void);
102 static void shutdown_file_pointers(void);
103 static void cleanup(Server *server);
104
105 #ifdef HAVE_KRB5
106 static long ticket5_time;
107 #define TKT5LIFETIME 8*60*60
108 #define tkt5_lifetime(val) (val)
109 #endif
110
111 #ifdef HAVE_KRB4
112 static long ticket_time;
113
114 #define TKTLIFETIME     120
115 #define tkt_lifetime(val) ((long) val * 5L * 60L)
116
117 extern C_Block  serv_key;
118 extern Sched    serv_ksched;
119 #endif /* HAVE_KRB4 */
120
121 static Timer *bdump_timer;
122 static int live_socket = -1;
123 static FILE *input, *output;
124 static struct sockaddr_in bdump_sin;
125 #ifdef HAVE_KRB5
126 static krb5_auth_context bdump_ac;
127 #endif
128 #ifdef notdef
129 static int cancel_outgoing_dump;
130 #endif
131
132 int bdumping;
133 int bdump_concurrent;
134 extern char *bdump_version;
135 extern int bdump_auth_proto;
136
137 /*
138  * Functions for performing a brain dump between servers.
139  */
140
141 /*
142  * offer the brain dump to another server
143  */
144
145 void
146 bdump_offer(struct sockaddr_in *who)
147 {
148     Code_t retval;
149     char buf[512], *addr, *lyst[2];
150 #ifndef HAVE_KRB4
151     int bdump_port = IPPORT_RESERVED - 1;
152 #endif /* !HAVE_KRB4 */
153 #if 1
154     zdbug((LOG_DEBUG, "bdump_offer"));
155 #endif
156 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
157     /* 
158      * when using kerberos server-server authentication, we can
159      * use any random local address 
160      */
161     bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
162     if (bdump_socket < 0) {
163         syslog(LOG_ERR,"bdump_offer: socket: %m");
164         bdump_socket = -1;
165         return;
166     }
167     memset(&bdump_sin, 0, sizeof(bdump_sin));
168     /* a port field of 0 makes the UNIX
169      * kernel choose an appropriate port/address pair */
170  
171     bdump_sin.sin_port = 0;
172     bdump_sin.sin_addr = my_addr;
173     bdump_sin.sin_family = AF_INET;
174     retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
175                   sizeof(bdump_sin));
176     if (retval < 0) {
177         syslog(LOG_ERR, "bdump_offer: bind: %m");
178         close(bdump_socket);
179         bdump_socket = -1;
180         return;
181     }
182     if (!bdump_sin.sin_port) {
183         unsigned int len = sizeof(bdump_sin);
184
185         if (getsockname(bdump_socket,
186                         (struct sockaddr *) &bdump_sin, &len) < 0) {
187             syslog(LOG_ERR, "bdump_offer: getsockname: %m");
188             close(bdump_socket);
189             bdump_socket = -1;
190             return;
191         }
192     }
193 #else  /* !HAVE_KRB4 */
194     /*
195      * when not using HAVE_KRB4, we can't use any old port, we use
196      * Internet reserved ports instead (rresvport)
197      */
198     bdump_socket = rresvport(&bdump_port);
199     if (bdump_socket < 0) {
200         syslog(LOG_ERR,"bdump_offer: socket: %m");
201         bdump_socket = -1;
202         return;
203     }
204     memset(&bdump_sin, 0, sizeof(bdump_sin));
205     bdump_sin.sin_port = htons((unsigned short) bdump_port);
206     bdump_sin.sin_addr = my_addr;
207     bdump_sin.sin_family = AF_INET;
208 #endif                          /* HAVE_KRB4 */
209
210     listen(bdump_socket, 1);
211  
212     bdump_timer = timer_set_rel(20L, close_bdump, NULL);
213     FD_SET(bdump_socket, &interesting);
214     nfds = max(bdump_socket, srv_socket) + 1;
215
216     addr = inet_ntoa(bdump_sin.sin_addr);
217     sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
218     lyst[0] = addr;
219     lyst[1] = buf;
220  
221     retval = ZSetDestAddr(who);
222     if (retval != ZERR_NONE) {
223         syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
224                error_message(retval));
225         return;
226     }
227  
228     /* myname is the hostname */
229     /* the class instance is the version number, here it is */
230     /* bdump_version, which is set in main */
231     send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
232               ADMIN_BDUMP, myname, "", lyst, 2);
233         
234 #if 1
235     zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
236            inet_ntoa(bdump_sin.sin_addr),
237            ntohs(bdump_sin.sin_port)));
238 #endif
239     return;
240 }
241
242 /*
243  * Accept a connection, and send the brain dump to the other server
244  */
245
246 void
247 bdump_send(void)
248 {
249     struct sockaddr_in from;
250     Server *server;
251     Code_t retval;
252     unsigned int fromlen = sizeof(from);
253     int on = 1;
254 #ifdef _POSIX_VERSION
255     struct sigaction action;
256 #endif
257 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
258     char *data = NULL;
259     int len = 0;
260     int proto = 0;
261 #endif
262 #ifdef HAVE_KRB4
263     KTEXT_ST ticket;
264     AUTH_DAT kdata;
265     /* may be moved into kstuff.c */
266     char instance [INST_SZ];
267 #endif
268 #ifdef HAVE_KRB5
269     /* may be moved into kstuff.c */
270     krb5_principal principal;
271     krb5_data k5data;
272     krb5_keytab kt;
273 #endif
274 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
275     unsigned short fromport;
276 #endif /* HAVE_KRB4 */
277  
278 #if 1
279     zdbug((LOG_DEBUG, "bdump_send"));
280 #endif
281     /* accept the connection, and send the brain dump */
282     live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
283     if (live_socket < 0) {
284         syslog(LOG_ERR,"bdump_send: accept: %m");
285         return;
286     }
287     if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
288                    sizeof(on)) < 0)
289         syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
290  
291 #ifndef HAVE_KRB4
292     fromport = ntohs(from.sin_port);
293 #endif
294  
295 #ifdef _POSIX_VERSION
296     sigemptyset(&action.sa_mask);
297     action.sa_flags = 0;
298     action.sa_handler = SIG_IGN;
299     sigaction(SIGPIPE, &action, NULL);
300
301 #else
302     signal(SIGPIPE, SIG_IGN);   /* so we can detect failures */
303 #endif
304  
305     from.sin_port = srv_addr.sin_port; /* we don't care what port
306                                         * it came from, and we need to
307                                         * fake out server_which_server() */
308     server = server_which_server(&from);
309     if (!server) {
310         syslog(LOG_ERR, "bdump_send: unknown server?");
311         server = limbo_server;
312     }
313 #if 1
314     zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
315            inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
316 #endif
317
318     bdumping = 1;
319     server->dumping = 1;
320
321     if (bdump_socket >= 0) {
322         /* shut down the listening socket and the timer. */
323         FD_CLR(bdump_socket, &interesting);
324         close(bdump_socket);
325         nfds = srv_socket + 1;
326         bdump_socket = -1;
327         timer_reset(bdump_timer);
328     }
329
330     /* Now begin the brain dump. */
331 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
332     retval = ReadKerberosData(live_socket, &len, &data, &proto);
333
334     if (retval != 0) {
335         syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
336                krb_get_err_text(retval));
337         cleanup(server);
338         return;
339     }
340
341     syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
342
343     if (get_tgt()) {
344         syslog(LOG_ERR, "bdump_send: get_tgt failed");
345         cleanup(server);
346         return;
347     }
348  
349     switch(proto) {
350 #ifdef HAVE_KRB5
351     case 5:
352         /* "server" side */
353         retval = krb5_build_principal(Z_krb5_ctx, &principal, 
354                                       strlen(ZGetRealm()),
355                                       ZGetRealm(),
356                                       SERVER_KRB5_SERVICE, SERVER_INSTANCE,
357                                       0); 
358         if (retval) {
359             syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
360             cleanup(server);
361             return;
362         }
363         
364
365         retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
366         if (retval) {
367             syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
368             cleanup(server);
369             return;
370         }
371
372         retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
373         if (retval) {
374             syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
375             cleanup(server);
376             return;
377         }
378
379         retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
380                                        KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
381         if (retval) {
382             syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
383             cleanup(server);
384             return;
385         }
386
387         /* Get the "client" krb_ap_req */
388
389         memset((char *)&k5data, 0, sizeof(krb5_data));
390         k5data.length = len;
391         k5data.data = data;
392         if (retval) {
393              syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
394                     error_message(retval)); 
395              cleanup(server);
396              return;
397         }
398
399         /* resolve keytab */
400         retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
401         if (retval) {
402             syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s", 
403                    error_message(retval));
404             krb5_kt_close(Z_krb5_ctx, kt);
405             cleanup(server);
406             return;
407         }
408
409         retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
410         krb5_free_principal(Z_krb5_ctx, principal);
411         krb5_kt_close(Z_krb5_ctx, kt);
412         free(k5data.data);
413         memset((char *)&k5data, 0, sizeof(krb5_data));
414         if (retval) {
415              syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
416                     error_message(retval));
417              cleanup(server);
418              return;
419         }
420
421         /* Now send back our auth packet */
422
423         retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
424         if (retval) {
425             syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
426             cleanup(server);
427             return;
428         }
429         retval = SendKrb5Data(live_socket, &k5data);
430         if (retval) {
431              syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
432                     error_message(retval));
433              krb5_free_data_contents(Z_krb5_ctx, &k5data);
434              cleanup(server);
435              return;
436         }    
437         krb5_free_data_contents(Z_krb5_ctx, &k5data);
438         break;
439 #endif  /* HAVE_KRB5 */  
440 #ifdef HAVE_KRB4
441     case 4:
442         /* here to krb_rd_req from GetKerberosData candidate for refactoring
443            back into kstuff.c */
444         (void) strcpy(instance, "*");           /* let Kerberos fill it in */
445
446         ticket.length = len;
447         memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
448         retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
449                             from.sin_addr.s_addr, &kdata, srvtab_file);
450         /*
451         retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
452                                  SERVER_SERVICE, srvtab_file);
453         */
454         if (retval != KSUCCESS) {
455             syslog(LOG_ERR, "bdump_send: getkdata: %s",
456                    krb_get_err_text(retval));
457             cleanup(server);
458             return;
459         }
460         if (strcmp(kdata.pname, SERVER_SERVICE) ||
461             strcmp(kdata.pinst, SERVER_INSTANCE) ||
462             strcmp(kdata.prealm, ZGetRealm())) {
463             syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
464                    kdata.pname, kdata.pinst, kdata.prealm);
465             cleanup(server);
466             return;
467         }
468         /* authenticate back */
469         retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
470                                   SERVER_INSTANCE);
471         if (retval != 0) {
472             syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
473                    error_message (retval));
474             cleanup(server);
475             return;
476         }
477         break;
478 #endif /* HAVE_KRB4 */
479     }
480 #else /* HAVE_KRB4 || HAVE_KRB5 */
481     if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
482         syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
483         cleanup(server);
484         return;
485     }
486 #endif /* HAVE_KRB4 || HAVE_KRB5 */
487     retval = setup_file_pointers();
488     if (retval != 0) {
489         syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
490                 error_message(retval));
491         cleanup(server);
492         return;
493     }
494     retval = bdump_send_loop(server);
495     if (retval != ZERR_NONE) {
496         syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
497                error_message(retval));
498         cleanup(server);
499         return;
500     }
501     retval = bdump_recv_loop(server);
502     if (retval != ZERR_NONE) {
503         syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
504                error_message(retval));
505         cleanup(server);
506         return;
507     }
508 #if 1
509     zdbug((LOG_DEBUG, "bdump_send: finished"));
510 #endif
511     if (server != limbo_server) {
512         /* set this guy to be up, and schedule a hello */
513         server->state = SERV_UP;
514         timer_reset(server->timer);
515         server->timer = timer_set_rel(0L, server_timo, server);
516     }
517 #if 0
518     zdbug((LOG_DEBUG,"cleanup sbd"));
519 #endif
520     shutdown_file_pointers();
521
522 #ifdef _POSIX_VERSION
523     action.sa_handler = SIG_DFL;
524     sigaction(SIGPIPE, &action, NULL);
525 #else
526     signal(SIGPIPE, SIG_DFL);
527 #endif
528     bdumping = 0;
529     server->dumping = 0;
530     /* Now that we are finished dumping, send all the queued packets */
531     server_send_queue(server);
532     return;
533 }
534
535 /*ARGSUSED*/
536 static void
537 bdump_get_v12 (ZNotice_t *notice,
538                int auth,
539                struct sockaddr_in *who,
540                Server *server)
541 {
542     struct sockaddr_in from;
543     Code_t retval;
544     int on = 1;
545 #ifdef _POSIX_VERSION
546     struct sigaction action;
547 #endif
548 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
549 #ifdef HAVE_KRB5
550     krb5_creds creds;
551     krb5_creds *credsp;
552     krb5_principal principal;
553     krb5_data data;
554     krb5_ap_rep_enc_part *rep;
555 #endif
556 #ifdef HAVE_KRB4
557     KTEXT_ST ticket;
558     AUTH_DAT kdata;
559 #endif
560 #else  /* !HAVE_KRB4 && !HAVE_KRB5 */
561     int reserved_port = IPPORT_RESERVED - 1;
562 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
563     
564     bdumping = 1;
565     server->dumping = 1;
566  
567 #ifdef _POSIX_VERSION
568     action.sa_flags = 0;
569     sigemptyset(&action.sa_mask);
570     action.sa_handler = SIG_IGN;
571     sigaction(SIGPIPE, &action, NULL);
572 #else
573     signal(SIGPIPE, SIG_IGN);   /* so we can detect problems */
574 #endif /* _POSIX_VRESION */
575  
576     if (bdump_socket >= 0) {
577         /* We cannot go get a brain dump when someone may
578            potentially be connecting to us (if that other
579            server is the server to whom we are connecting,
580            we will deadlock. so we shut down the listening
581            socket and the timer. */
582         FD_CLR(bdump_socket, &interesting);
583         close(bdump_socket);
584         nfds = srv_socket+1;
585         bdump_socket = -1;
586         timer_reset(bdump_timer);
587     }
588
589     retval = extract_sin(notice, &from);
590     if (retval != ZERR_NONE) {
591         syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
592 #ifdef _POSIX_VERSION
593         action.sa_handler = SIG_DFL;
594         sigaction(SIGPIPE, &action, NULL);
595 #else
596         signal(SIGPIPE, SIG_DFL);
597 #endif
598         bdumping = 0;
599         server->dumping = 0;
600         return;
601     }
602 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
603     if (ntohs(from.sin_port) > IPPORT_RESERVED ||
604         ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
605         syslog(LOG_ERR, "bdump_get: port not reserved: %d",
606                ntohs(from.sin_port));
607         cleanup(server);
608         return;
609     }
610     live_socket = rresvport(&reserved_port);
611 #else  /* !HAVE_KRB4 && !HAVE_KRB5 */
612     live_socket = socket(AF_INET, SOCK_STREAM, 0);
613 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
614     if (live_socket < 0) {
615         syslog(LOG_ERR, "bdump_get: socket: %m");
616         cleanup(server);
617         return;
618     }
619     if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
620         syslog(LOG_ERR, "bdump_get: connect: %m");
621         cleanup(server);
622         return;
623     }
624     if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
625                    sizeof(on)) < 0)
626         syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
627 #if 1
628     zdbug((LOG_DEBUG, "bdump_get: connected"));
629 #endif
630  
631     /* Now begin the brain dump. */
632 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
633     if (get_tgt()) {
634         syslog(LOG_ERR, "bdump_get: get_tgt failed"); 
635         cleanup(server);
636         return;
637     }
638     switch(bdump_auth_proto) {
639 #ifdef HAVE_KRB5
640     case 5: /* "client" side */
641         memset((char *)&creds, 0, sizeof(creds));
642
643         retval = krb5_build_principal(Z_krb5_ctx, &principal, 
644                                       strlen(ZGetRealm()),
645                                       ZGetRealm(),
646                                       SERVER_KRB5_SERVICE, SERVER_INSTANCE,
647                                       0); 
648         if (retval) {
649             syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
650             cleanup(server);
651             return;
652         }
653
654         retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
655         if (retval) {
656             syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
657             krb5_free_principal(Z_krb5_ctx, principal);
658             cleanup(server);
659             return;
660         }
661         
662         retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
663         krb5_free_principal(Z_krb5_ctx, principal);
664         if (retval) {
665             syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
666             krb5_free_cred_contents(Z_krb5_ctx, &creds);
667             cleanup(server);
668             return;
669         }
670
671         retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
672                                       &creds, &credsp);
673         krb5_free_cred_contents(Z_krb5_ctx, &creds);
674         if (retval) {
675             syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
676             cleanup(server);
677             return;
678         }
679
680         retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
681         if (retval) {
682             syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
683             krb5_free_creds(Z_krb5_ctx, credsp);
684             cleanup(server);
685             return;
686         }
687
688         retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
689         if (retval) {
690             syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
691             krb5_free_creds(Z_krb5_ctx, credsp);
692             cleanup(server);
693             return;
694         }
695
696         retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
697                 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
698         if (retval) {
699             syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
700             krb5_free_creds(Z_krb5_ctx, credsp);
701             cleanup(server);
702             return;
703         }
704
705         memset((char *)&data, 0, sizeof(krb5_data));
706         retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
707                                  NULL, credsp, &data);
708         if (retval) {
709             syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
710             krb5_free_creds(Z_krb5_ctx, credsp);
711             cleanup(server);
712             return;
713         }
714         retval = SendKrb5Data(live_socket, &data);
715         krb5_free_creds(Z_krb5_ctx, credsp);
716         if (retval) {
717              syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
718                     error_message(retval));
719              krb5_free_data_contents(Z_krb5_ctx, &data);
720              cleanup(server);
721              return;
722         }    
723         krb5_free_data_contents(Z_krb5_ctx, &data);
724         memset((char *)&data, 0, sizeof(krb5_data));
725         retval = GetKrb5Data(live_socket, &data);
726         if (retval) {
727              syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
728                     error_message(retval));
729              cleanup(server);
730              return;
731         }    
732         retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
733         free(data.data);
734         memset((char *)&data, 0, sizeof(krb5_data));
735         if (retval) {
736              syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
737                     error_message(retval));
738              cleanup(server);
739              return;
740         }    
741         break;
742 #endif
743 #ifdef HAVE_KRB4
744     case 4:
745         /* send an authenticator */
746         retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
747                                   SERVER_INSTANCE);
748         if (retval != 0) {
749             syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
750             cleanup(server);
751             return;
752         }
753         zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
754         
755         /* get his authenticator */
756         retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
757                                  SERVER_SERVICE, srvtab_file);
758         if (retval != KSUCCESS) {
759             syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
760             cleanup(server);
761             return;
762         }
763
764         if (strcmp(kdata.pname, SERVER_SERVICE) ||
765             strcmp(kdata.pinst, SERVER_INSTANCE) ||
766             strcmp(kdata.prealm, ZGetRealm())) {
767             syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
768                    kdata.pname, kdata.pinst,kdata.prealm);
769             cleanup(server);
770             return;
771         }
772         break;
773 #endif /* HAVE_KRB4 */
774     }
775 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */   
776     retval = setup_file_pointers();
777     if (retval != 0) {
778         syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
779                error_message (retval));
780         cleanup(server);
781         return;
782     }
783     retval = bdump_recv_loop(server);
784     if (retval != ZERR_NONE) {
785         syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
786                error_message(retval));
787         cleanup(server);
788         return;
789     }
790     zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
791     retval = bdump_send_loop(server);
792     if (retval != ZERR_NONE) {
793         syslog(LOG_WARNING, "bdump_send_loop failed: %s",
794                error_message(retval));
795         cleanup(server);
796         return;
797     }
798 #if 1
799     zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
800 #endif
801     /* set this guy to be up, and schedule a hello */
802     server->state = SERV_UP;
803     timer_reset(server->timer);
804     server->timer = timer_set_rel(0L, server_timo, server);
805
806 #if 1
807     zdbug((LOG_DEBUG,"cleanup gbd"));
808 #endif
809     shutdown_file_pointers();
810 #ifdef _POSIX_VERSION
811     action.sa_handler = SIG_DFL;
812     sigaction(SIGPIPE, &action, NULL);
813 #else
814     signal(SIGPIPE, SIG_DFL);
815 #endif
816     bdumping = 0;
817     server->dumping = 0;
818     /* Now that we are finished dumping, send all the queued packets */
819     server_send_queue(server);
820
821     return;
822 }
823
824 void
825 bdump_get(ZNotice_t *notice,
826           int auth,
827           struct sockaddr_in *who,
828           Server *server)
829 {
830     void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *);
831
832     proc = NULL;
833
834 #if 1
835     if (zdebug) {
836         syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
837                notice->z_class_inst, inet_ntoa(who->sin_addr));
838     }
839 #endif
840     if (strcmp (notice->z_class_inst, "1.2") == 0)
841         proc = bdump_get_v12;
842
843     if (proc) {
844         (*proc)(notice, auth, who, server);
845     } else {
846         syslog(LOG_WARNING,
847                "bdump_get: Incompatible bdump version '%s' from %s",
848                notice->z_class_inst,
849                inet_ntoa(who->sin_addr));
850     }
851 }
852
853 /*
854  * Send a list off as the specified notice
855  */
856
857 Code_t
858 bdump_send_list_tcp(ZNotice_Kind_t kind,
859                     struct sockaddr_in *addr,
860                     char *class_name,
861                     char *inst,
862                     char *opcode,
863                     char *sender,
864                     char *recip,
865                     char **lyst,
866                     int num)
867 {
868     ZNotice_t notice;
869     char *pack, addrbuf[100];
870     int packlen, count;
871     Code_t retval;
872     u_short length;
873
874     memset (&notice, 0, sizeof(notice));
875  
876     retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
877                         (unsigned char *) &addr->sin_addr,
878                         sizeof(struct in_addr));
879     if (retval != ZERR_NONE)
880         return retval;
881     notice.z_kind = kind;
882  
883     notice.z_port = addr->sin_port;
884     notice.z_class = class_name;
885     notice.z_class_inst = inst;
886     notice.z_opcode = opcode;
887     notice.z_sender = sender;
888     notice.z_recipient = recip;
889     notice.z_default_format = "";
890     notice.z_num_other_fields = 1;
891     notice.z_other_fields[0] = addrbuf;
892  
893     retval = ZFormatNoticeList(&notice, lyst, num, &pack, &packlen, ZNOAUTH);
894     if (retval != ZERR_NONE)
895         return retval;
896
897 #ifdef HAVE_KRB5
898     if (bdump_ac) {
899         krb5_data indata, outmsg;
900         indata.length=packlen;
901         indata.data=pack;
902         memset(&outmsg, 0, sizeof(krb5_data));
903         retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
904         if (retval != ZERR_NONE)
905             return retval;
906         if (outmsg.length > Z_MAXPKTLEN) {
907             syslog(LOG_ERR, "bsl: encrypted packet is too large");
908             return ZERR_PKTLEN;
909         }
910         packlen = outmsg.length;
911         free(pack);
912         pack=malloc(packlen);
913         if (!pack)
914             return ENOMEM;
915         memcpy(pack, outmsg.data, packlen);
916         krb5_free_data_contents(Z_krb5_ctx, &outmsg);
917     }
918 #endif
919
920     length = htons((u_short) packlen);
921  
922     count = net_write(output, (char *) &length, sizeof(length));
923     if (count != sizeof(length)) {
924         if (count < 0) {
925             free(pack);
926             return(errno);
927         } else {
928             syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
929                    sizeof(length), count);
930             free(pack);
931             return(ZSRV_PKSHORT);
932         }
933     }
934  
935     count = net_write(output, pack, packlen);
936     if (count != packlen) {
937         if (count < 0) {
938             free(pack);
939             return(errno);
940         } else {
941             syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
942                    packlen, count);
943             free(pack);
944             return(ZSRV_PKSHORT);
945         }
946     }
947     free(pack);
948     return(ZERR_NONE);
949 }
950
951 static void
952 shutdown_file_pointers(void)
953 {
954     if (input) {
955         fclose(input);
956         input = 0;
957     }
958     if (output) {
959         fclose(output);
960         output = 0;
961     }
962     if (live_socket >= 0) {
963         close(live_socket);
964         live_socket = -1;
965 #ifdef HAVE_KRB5
966         if (bdump_ac)
967                 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
968         bdump_ac = NULL;
969 #endif
970     }
971 }
972
973 static void
974 cleanup(Server *server)
975 {
976 #ifdef _POSIX_VERSION
977     struct sigaction action;
978 #endif
979
980 #if 1
981     zdbug((LOG_DEBUG, "bdump cleanup"));
982 #endif
983     if (server != limbo_server) {
984         server->state = SERV_DEAD;
985         timer_reset(server->timer);
986         server->timer = timer_set_rel(0L, server_timo, server);
987     }
988     shutdown_file_pointers ();
989 #ifdef _POSIX_VERSION
990     action.sa_flags = 0;
991     sigemptyset(&action.sa_mask);
992     action.sa_handler = SIG_DFL;
993     sigaction(SIGPIPE,&action, NULL);
994 #else
995     signal(SIGPIPE, SIG_DFL);
996 #endif /* _POSIX_VERSION */
997     bdumping = 0;
998     server->dumping = 0;
999 }
1000
1001 #ifdef HAVE_KRB4
1002 int
1003 get_tgt(void)
1004 {
1005     /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
1006      * at least INST_SZ bytes long. */
1007     static char buf[INST_SZ + 1] = SERVER_INSTANCE;
1008     int retval = 0;
1009     
1010     /* have they expired ? */
1011     if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1012         /* +15 for leeway */
1013 #if 0
1014         zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1015                NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1016 #endif
1017         dest_tkt();
1018
1019         retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
1020                                     "krbtgt", ZGetRealm(),
1021                                     TKTLIFETIME, srvtab_file);
1022         if (retval != KSUCCESS) {
1023             syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1024                    krb_get_err_text(retval));
1025             ticket_time = 0;
1026             return(1);
1027         } else {
1028             ticket_time = NOW;
1029         }
1030
1031         retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1032                                   ZGetRealm(), 0 /*kvno*/,
1033                                   srvtab_file, (char *)serv_key);
1034         if (retval != KSUCCESS) {
1035             syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1036                    krb_get_err_text(retval));
1037             return 1;
1038         }
1039         des_key_sched(serv_key, serv_ksched.s);
1040     }
1041 #ifdef HAVE_KRB5        
1042     /* XXX */
1043     if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1044         krb5_keytab kt;
1045         krb5_get_init_creds_opt opt;
1046         krb5_creds cred;
1047         krb5_principal principal;
1048
1049         memset(&cred, 0, sizeof(cred));
1050
1051         retval = krb5_build_principal(Z_krb5_ctx, &principal, 
1052                                       strlen(ZGetRealm()),
1053                                       ZGetRealm(),
1054                                       SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1055                                       0); 
1056         if (retval) {
1057           krb5_free_principal(Z_krb5_ctx, principal);
1058           return(1);
1059         }
1060
1061         krb5_get_init_creds_opt_init (&opt);
1062         krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1063
1064         retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1065         if (retval) return(1);
1066         
1067         retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1068                                              &cred,
1069                                              principal,
1070                                              kt,
1071                                              0,
1072                                              NULL,
1073                                              &opt);
1074         krb5_free_principal(Z_krb5_ctx, principal);
1075         krb5_kt_close(Z_krb5_ctx, kt);
1076         if (retval) return(1);
1077
1078         retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1079         if (retval) return(1);
1080     
1081         retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1082         if (retval) return(1);
1083
1084         ticket5_time = NOW;
1085
1086         krb5_free_cred_contents (Z_krb5_ctx, &cred);
1087     }
1088 #endif
1089     return(0);
1090 }
1091 #endif /* HAVE_KRB4 */
1092
1093 /*
1094  * The braindump offer wasn't taken, so we retract it.
1095  */
1096  
1097 /*ARGSUSED*/
1098 static void
1099 close_bdump(void *arg)
1100 {
1101     if (bdump_socket >= 0) {
1102         FD_CLR(bdump_socket, &interesting);
1103         close(bdump_socket);
1104         nfds = srv_socket + 1;
1105         bdump_socket = -1;
1106 #if 1
1107         zdbug((LOG_DEBUG, "bdump not used"));
1108 #endif
1109     } else {
1110 #if 1
1111         zdbug((LOG_DEBUG, "bdump not open"));
1112 #endif
1113     }
1114     return;
1115 }
1116  
1117 /*
1118  * Start receiving instruction notices from the brain dump socket
1119  */
1120  
1121 static Code_t
1122 bdump_recv_loop(Server *server)
1123 {
1124     ZNotice_t notice;
1125     ZPacket_t packet;
1126     int len;
1127     Code_t retval;
1128     Client *client = NULL;
1129     struct sockaddr_in who;
1130 #ifdef HAVE_KRB5
1131     unsigned char buf[512];
1132     int blen;
1133 #endif
1134 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)    
1135     char *cp;
1136 #endif
1137 #ifdef HAVE_KRB4
1138     C_Block cblock;
1139 #endif /* HAVE_KRB4 */
1140     ZRealm *realm = NULL;
1141  
1142 #if 1
1143     zdbug((LOG_DEBUG, "bdump recv loop"));
1144 #endif
1145         
1146     /* do the inverse of bdump_send_loop, registering stuff on the fly */
1147     while (1) {
1148         if (packets_waiting()) {
1149             /* A non-braindump packet is waiting; handle it. */
1150             bdumping = 0;
1151             bdump_concurrent = 1;
1152             handle_packet();
1153             bdump_concurrent = 0;
1154             bdumping = 1;
1155         }
1156         len = sizeof(packet);
1157         retval = get_packet(packet, len, &len);
1158         if (retval != ZERR_NONE) {
1159             syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1160             return retval;
1161         }
1162
1163 #if HAVE_KRB5
1164         if (bdump_ac) {
1165             krb5_data in, out;
1166             in.length = len;
1167             in.data = packet;
1168             memset(&out, 0, sizeof(krb5_data));
1169             retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1170             if (retval != ZERR_NONE) {
1171                 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1172                 return retval;
1173             }
1174             memcpy(packet, out.data, out.length);
1175             len = out.length;
1176             krb5_free_data_contents(Z_krb5_ctx, &out);
1177         }
1178 #endif
1179
1180         retval = ZParseNotice(packet, len, &notice);
1181         if (retval != ZERR_NONE) {
1182             syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1183             return retval;
1184         }
1185 #if defined (DEBUG)
1186         if (zdebug) {
1187             syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1188                     ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1189                     notice.z_class_inst, notice.z_opcode, notice.z_sender,
1190                     notice.z_recipient);
1191         }
1192 #endif /* DEBUG */
1193         if (notice.z_num_other_fields >= 1) {
1194             retval = ZReadAscii(notice.z_other_fields[0],
1195                                 strlen(notice.z_other_fields[0]),
1196                                 (unsigned char *) &who.sin_addr,
1197                                 sizeof(struct in_addr));
1198             if (retval != ZERR_NONE) {
1199                 syslog(LOG_ERR, "brl zreadascii failed: %s",
1200                        error_message(retval));
1201                 return retval;
1202             }
1203         } else {
1204             who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
1205         }
1206         who.sin_family = AF_INET;
1207         who.sin_port = notice.z_port;
1208
1209         if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1210             /* end of brain dump */
1211             return ZERR_NONE;
1212         } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
1213             /* get a realm from the message */
1214             realm = realm_get_realm_by_name(notice.z_message);
1215             if (!realm) {
1216                 syslog(LOG_ERR, "brl newrlm failed: no realm %s", 
1217                        notice.z_message);
1218             }
1219         } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1220             /* 1 = tell it we are authentic */
1221             retval = ulogin_dispatch(&notice, 1, &who, server);
1222             if (retval != ZERR_NONE) {
1223                 syslog(LOG_ERR, "brl ul_disp failed: %s",
1224                        error_message(retval));
1225                 return retval;
1226             }
1227         } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1228             /* a new client */
1229             notice.z_port = htons((u_short) atoi(notice.z_message));
1230             retval = client_register(&notice, &who.sin_addr, &client, 0);
1231             if (retval != ZERR_NONE) {
1232                 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
1233                 return retval;
1234             }
1235 #ifdef HAVE_KRB5
1236             client->session_keyblock = NULL;
1237             if (*notice.z_class_inst) {
1238                 /* check out this session key I found */
1239                 cp = notice.z_message + strlen(notice.z_message) + 1;
1240                 if (*cp == '0') {
1241                     /* ****ing netascii; this is an encrypted DES keyblock
1242                        XXX this code should be conditionalized for server
1243                        transitions   */
1244                     retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1245                                                 sizeof(C_Block),
1246                                                 &client->session_keyblock);
1247                     if (retval) {
1248                         syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1249                                error_message(retval));
1250                         return retval;
1251                     }
1252                     retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1253                     if (retval != ZERR_NONE) {
1254                         syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1255                                error_message(retval), cp);
1256                     } else {
1257                         des_ecb_encrypt((C_Block *)cblock, (C_Block *)Z_keydata(client->session_keyblock),
1258                                         serv_ksched.s, DES_DECRYPT);
1259                     }
1260                 } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
1261                     retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen);
1262                     if (retval != ZERR_NONE) {
1263                         syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1264                                error_message(retval), cp);
1265                     } else {
1266                         retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1267                                                     ntohl(*(krb5_enctype *)&buf[0]),
1268                                                     ntohl(*(u_int32_t *)&buf[4]),
1269                                                     &client->session_keyblock);
1270                         if (retval) {
1271                             syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1272                                    error_message(retval));
1273                             return retval;
1274                         }
1275                         memcpy(Z_keydata(client->session_keyblock), &buf[8],
1276                                Z_keylen(client->session_keyblock));
1277                     }
1278                 }
1279             }
1280 #else
1281 #ifdef HAVE_KRB4
1282             memset(client->session_key, 0, sizeof(C_Block));
1283             if (*notice.z_class_inst) {
1284                 /* a C_Block is there */
1285                 cp = notice.z_message + strlen(notice.z_message) + 1;
1286                 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1287                 if (retval != ZERR_NONE) {
1288                     syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1289                            error_message(retval), cp);
1290                 } else {
1291                     des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1292                                     DES_DECRYPT);
1293                 }
1294             }
1295 #endif /* HAVE_KRB4 */
1296 #endif
1297         } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) { 
1298             /* a subscription packet */
1299             if (!client) {
1300                 syslog(LOG_ERR, "brl no client");
1301                 return ZSRV_NOCLT;
1302             }
1303             retval = subscr_subscribe(client, &notice, server);
1304             if (retval != ZERR_NONE) {
1305                 syslog(LOG_WARNING, "brl subscr failed: %s",
1306                        error_message(retval));
1307                 return retval;
1308             }
1309         } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1310             /* add a subscription for a realm */
1311             if (realm) {
1312                 retval = subscr_realm(realm, &notice);
1313                 if (retval != ZERR_NONE) {
1314                     syslog(LOG_WARNING, "brl subscr failed: %s",
1315                            error_message(retval));
1316                     return retval;
1317                 }
1318             } /* else */
1319                  /* Other side tried to send us subs for a realm we didn't
1320                     know about, and so we drop them silently */
1321         
1322         } else {
1323             syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1324             return ZSRV_UNKNOWNOPCODE;
1325         }
1326     }
1327 }
1328
1329 /*
1330  * Send all the state to the peer.
1331  */
1332
1333 static Code_t
1334 bdump_send_loop(Server *server)
1335 {
1336     Code_t retval;
1337
1338 #if 1
1339     zdbug((LOG_DEBUG, "bdump send loop"));
1340 #endif
1341
1342     retval = uloc_send_locations();
1343     if (retval != ZERR_NONE)
1344         return retval;
1345     retval = client_send_clients();
1346     if (retval != ZERR_NONE)
1347         return retval;
1348     retval = realm_send_realms();
1349     if (retval != ZERR_NONE)
1350         return retval;
1351     return send_done();
1352 }
1353
1354 /*
1355  * Send a sync indicating end of this host
1356  */
1357
1358 static Code_t
1359 send_done(void)
1360 {
1361     Code_t retval;
1362  
1363 #if 1
1364     zdbug((LOG_DEBUG, "send_done"));
1365 #endif
1366     retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1367                              "", ADMIN_DONE, myname, "", NULL, 0);
1368     return retval;
1369 }
1370
1371
1372 /*
1373  * Send a list off as the specified notice
1374  */
1375
1376 static Code_t
1377 send_list(ZNotice_Kind_t kind,
1378           int port,
1379           char *class_name,
1380           char *inst,
1381           char *opcode,
1382           char *sender,
1383           char *recip,
1384           char **lyst,
1385           int num)
1386 {
1387     ZNotice_t notice;
1388     char *pack;
1389     int packlen;
1390     Code_t retval;
1391  
1392     memset (&notice, 0, sizeof(notice));
1393
1394     notice.z_kind = kind;
1395     notice.z_port = port;
1396     notice.z_class = class_name;
1397     notice.z_class_inst = inst;
1398     notice.z_opcode = opcode;
1399     notice.z_sender = sender;
1400     notice.z_recipient = recip;
1401     notice.z_default_format = "";
1402     notice.z_num_other_fields = 0;
1403         
1404     retval = ZFormatNoticeList(&notice, lyst, num, &pack, &packlen, ZNOAUTH);
1405     if (retval != ZERR_NONE) {
1406         syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1407         return retval;
1408     }
1409         
1410     retval = ZSendPacket(pack, packlen, 0);
1411     if (retval != ZERR_NONE)
1412         syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1413     free(pack);
1414     return retval;
1415 }
1416
1417 /*
1418  * Send a message off as the specified notice, via TCP
1419  */
1420
1421 static Code_t
1422 send_normal_tcp(ZNotice_Kind_t kind,
1423                 int port,
1424                 char *class_name,
1425                 char *inst,
1426                 char *opcode,
1427                 char *sender,
1428                 char *recip,
1429                 char *message,
1430                 int len)
1431 {
1432     ZNotice_t notice;
1433     char *pack;
1434     int packlen, count;
1435     Code_t retval;
1436     u_short length;
1437  
1438     memset (&notice, 0, sizeof(notice));
1439
1440     notice.z_kind = kind;
1441     notice.z_port = port;
1442     notice.z_class = class_name;
1443     notice.z_class_inst = inst;
1444     notice.z_opcode = opcode;
1445     notice.z_sender = sender;
1446     notice.z_recipient = recip;
1447     notice.z_default_format = "";
1448     notice.z_message = message;
1449     notice.z_message_len = len;
1450     notice.z_num_other_fields = 0;
1451  
1452     retval = ZFormatNotice(&notice, &pack, &packlen, ZNOAUTH);
1453     if (retval != ZERR_NONE) {
1454         syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1455         return retval;
1456     }
1457  
1458 #ifdef HAVE_KRB5
1459     if (bdump_ac) {
1460         krb5_data indata, outmsg;
1461         indata.length=packlen;
1462         indata.data=pack;
1463         memset(&outmsg, 0, sizeof(krb5_data));
1464         retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1465         if (retval != ZERR_NONE)
1466             return retval;
1467         if (outmsg.length > Z_MAXPKTLEN) {
1468             syslog(LOG_ERR, "sn: encrypted packet is too large");
1469             return ZERR_PKTLEN;
1470         }
1471         packlen = outmsg.length;
1472         free(pack);
1473         pack=malloc(packlen);
1474         if (!pack)
1475             return ENOMEM;
1476         memcpy(pack, outmsg.data, packlen);
1477         krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1478     }
1479 #endif
1480
1481     length = htons((u_short) packlen);
1482  
1483     count = net_write(output, (char *) &length, sizeof(length));
1484     if (count != sizeof(length)) {
1485         if (count < 0) {
1486             syslog(LOG_WARNING, "snt xmit/len: %m");
1487             free(pack);
1488             return errno;
1489         } else {
1490             syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1491             free(pack);
1492             return ZSRV_LEN;
1493         }
1494     }
1495     count = net_write(output, pack, packlen);
1496     if (count != packlen) {
1497         if (count < 0) {
1498             syslog(LOG_WARNING, "snt xmit: %m");
1499             free(pack);
1500             return errno;
1501         } else {
1502             syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1503             free(pack);
1504             return ZSRV_LEN;
1505         }
1506     }
1507     free(pack);
1508     return ZERR_NONE;
1509 }
1510
1511 /*
1512  * get a packet from the TCP socket
1513  * return 0 if successful, error code else
1514  */
1515
1516 static Code_t
1517 get_packet(void *packet, int len, int *retlen)
1518 {
1519     u_short length;
1520     int result;
1521  
1522     result = net_read(input, (char *) &length, sizeof(u_short));
1523     if (result < sizeof(short)) {
1524         if (result < 0) {
1525             return errno;
1526         } else {
1527             syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1528                    sizeof(short));
1529             return ZSRV_LEN;
1530         }
1531     }
1532         
1533     length = ntohs(length);
1534     if (len < length)
1535         return ZSRV_BUFSHORT;
1536     result = net_read(input, packet, (int) length);
1537     if (result < length) {
1538         if (result < 0) {
1539             return errno;
1540         } else {
1541             syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1542             return ZSRV_LEN;
1543         }
1544     }
1545     *retlen = length;
1546     return ZERR_NONE;
1547 }
1548
1549 static Code_t
1550 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1551 {
1552     char *cp = notice->z_message;
1553     char *buf;
1554
1555     buf = cp;
1556     if (!notice->z_message_len || *buf == '\0') {
1557 #if 0
1558         zdbug((LOG_DEBUG,"no addr"));
1559 #endif
1560         return ZSRV_PKSHORT;
1561     }
1562     target->sin_addr.s_addr = inet_addr(cp);
1563  
1564     cp += (strlen(cp) + 1);     /* past the null */
1565     if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1566 #if 0
1567         zdbug((LOG_DEBUG, "no port"));
1568 #endif
1569         return(ZSRV_PKSHORT);
1570     }
1571     target->sin_port = htons((u_short) atoi(cp));
1572     target->sin_family = AF_INET;
1573     return ZERR_NONE;
1574 }
1575
1576 static int
1577 net_read(FILE *f, char *buf, int len)
1578 {
1579     int cc, len2 = 0;
1580  
1581     fflush (output);
1582     do {
1583         errno = 0;
1584         cc = fread(buf, 1, len, f);
1585         if (cc == 0)
1586           {
1587             if (feof(f))
1588               return len2;
1589             if (errno == 0)
1590               errno = EIO;
1591             return -1;
1592           }
1593         buf += cc;
1594         len2 += cc;
1595         len -= cc;
1596     } while (len > 0);
1597     return len2;
1598 }
1599
1600 static int
1601 net_write(FILE *f, char *buf, int len)
1602 {
1603     int cc;
1604     int wrlen = len;
1605     do {
1606         cc = fwrite (buf, 1, wrlen, f);
1607         if (cc == 0)
1608             return -1;
1609         buf += cc;
1610         wrlen -= cc;
1611     } while (wrlen > 0);
1612     return len;
1613 }
1614
1615 static int
1616 setup_file_pointers (void)
1617 {
1618     int fd;
1619
1620     input = fdopen (live_socket, "r");
1621     if (!input)
1622         return errno;
1623
1624     fd = dup (live_socket);
1625     if (fd < 0)
1626         return errno;
1627     output = fdopen (fd, "w");
1628     if (!output)
1629         return errno;
1630
1631     return 0;
1632 }