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