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