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