]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/bdump.c
fix tyop
[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,v 1.54 2001/02/27 04:43:01 zacheiss Exp $
8  *      $Author: zacheiss $
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: bdump.c,v 1.54 2001/02/27 04:43:01 zacheiss Exp $";
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 static void close_bdump __P((void* arg));
48 static Code_t bdump_send_loop __P((Server *server)),
49 bdump_ask_for __P((char *inst)),
50 bdump_recv_loop __P((Server *server));
51 static void bdump_get_v12 __P((ZNotice_t *, int, struct sockaddr_in *,
52                                Server *));
53 static Code_t get_packet __P((void *packet, int len, int *retlen));
54 static Code_t extract_sin __P((ZNotice_t *notice, struct sockaddr_in *target));
55 static Code_t send_done __P((void));
56 static Code_t send_list __P((ZNotice_Kind_t kind, int port, char *class_name,
57                              char *inst, char *opcode, char *sender,
58                              char *recip, char **lyst, int num));
59 static Code_t send_normal_tcp __P((ZNotice_Kind_t kind, int port,
60                                    char *class_name,
61                                    char *inst, char *opcode, char *sender,
62                                    char *recip, char *message, int len));
63 static int net_read __P((FILE *f, char *buf, int len));
64 static int net_write __P((FILE *f, char *buf, int len));
65 static int setup_file_pointers __P((void));
66 static void shutdown_file_pointers __P((void));
67 static void cleanup __P((Server *server));
68
69 #ifdef HAVE_KRB5
70 static long ticket5_time;
71 #define TKT5LIFETIME 8*60*60
72 #define tkt5_lifetime(val) (val)
73 #endif
74
75 #ifdef HAVE_KRB4
76 static long ticket_time;
77
78 #define TKTLIFETIME     120
79 #define tkt_lifetime(val) ((long) val * 5L * 60L)
80
81 #ifndef NOENCRYPTION
82 extern C_Block  serv_key;
83 extern Sched    serv_ksched;
84 #endif
85 #endif /* HAVE_KRB4 */
86
87 static Timer *bdump_timer;
88 static int live_socket = -1;
89 static FILE *input, *output;
90 static struct sockaddr_in bdump_sin;
91 #ifdef notdef
92 static int cancel_outgoing_dump;
93 #endif
94
95 int bdumping;
96 int bdump_concurrent;
97 extern char *bdump_version;
98
99 /*
100  * Functions for performing a brain dump between servers.
101  */
102
103 /*
104  * offer the brain dump to another server
105  */
106
107 void
108 bdump_offer(who)
109     struct sockaddr_in *who;
110 {
111     Code_t retval;
112     char buf[512], *addr, *lyst[2];
113 #ifndef HAVE_KRB4
114     int bdump_port = IPPORT_RESERVED - 1;
115 #endif /* !HAVE_KRB4 */
116 #if 1
117     zdbug((LOG_DEBUG, "bdump_offer"));
118 #endif
119 #ifdef HAVE_KRB4
120     /* 
121      * when using HAVE_KRB4 server-server authentication, we can
122      * use any random local address 
123      */
124     bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
125     if (bdump_socket < 0) {
126         syslog(LOG_ERR,"bdump_offer: socket: %m");
127         bdump_socket = -1;
128         return;
129     }
130     memset(&bdump_sin, 0, sizeof(bdump_sin));
131     /* a port field of 0 makes the UNIX
132      * kernel choose an appropriate port/address pair */
133  
134     bdump_sin.sin_port = 0;
135     bdump_sin.sin_addr = my_addr;
136     bdump_sin.sin_family = AF_INET;
137     retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
138                   sizeof(bdump_sin));
139     if (retval < 0) {
140         syslog(LOG_ERR, "bdump_offer: bind: %m");
141         close(bdump_socket);
142         bdump_socket = -1;
143         return;
144     }
145     if (!bdump_sin.sin_port) {
146         int len = sizeof(bdump_sin);
147
148         if (getsockname(bdump_socket,
149                         (struct sockaddr *) &bdump_sin, &len) < 0) {
150             syslog(LOG_ERR, "bdump_offer: getsockname: %m");
151             close(bdump_socket);
152             bdump_socket = -1;
153             return;
154         }
155     }
156 #else  /* !HAVE_KRB4 */
157     /*
158      * when not using HAVE_KRB4, we can't use any old port, we use
159      * Internet reserved ports instead (rresvport)
160      */
161     bdump_socket = rresvport(&bdump_port);
162     if (bdump_socket < 0) {
163         syslog(LOG_ERR,"bdump_offer: socket: %m");
164         bdump_socket = -1;
165         return;
166     }
167     memset(&bdump_sin, 0, sizeof(bdump_sin));
168     bdump_sin.sin_port = htons((unsigned short) bdump_port);
169     bdump_sin.sin_addr = my_addr;
170     bdump_sin.sin_family = AF_INET;
171 #endif                          /* HAVE_KRB4 */
172
173     listen(bdump_socket, 1);
174  
175     bdump_timer = timer_set_rel(20L, close_bdump, NULL);
176     FD_SET(bdump_socket, &interesting);
177     nfds = max(bdump_socket, srv_socket) + 1;
178
179     addr = inet_ntoa(bdump_sin.sin_addr);
180     sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
181     lyst[0] = addr;
182     lyst[1] = buf;
183  
184     retval = ZSetDestAddr(who);
185     if (retval != ZERR_NONE) {
186         syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
187                error_message(retval));
188         return;
189     }
190  
191     /* myname is the hostname */
192     /* the class instance is the version number, here it is */
193     /* bdump_version, which is set in main */
194     send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
195               ADMIN_BDUMP, myname, "", lyst, 2);
196         
197 #if 1
198     zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
199            inet_ntoa(bdump_sin.sin_addr),
200            ntohs(bdump_sin.sin_port)));
201 #endif
202     return;
203 }
204
205 /*
206  * Accept a connection, and send the brain dump to the other server
207  */
208
209 void
210 bdump_send()
211 {
212     struct sockaddr_in from;
213     Server *server;
214     Code_t retval;
215     int fromlen = sizeof(from);
216     int on = 1;
217 #ifdef _POSIX_VERSION
218     struct sigaction action;
219 #endif
220
221 #ifdef HAVE_KRB4
222     KTEXT_ST ticket;
223     AUTH_DAT kdata;
224 #else
225     unsigned short fromport;
226 #endif /* HAVE_KRB4 */
227  
228 #if 1
229     zdbug((LOG_DEBUG, "bdump_send"));
230 #endif
231     /* accept the connection, and send the brain dump */
232     live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
233     if (live_socket < 0) {
234         syslog(LOG_ERR,"bdump_send: accept: %m");
235         return;
236     }
237     if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
238                    sizeof(on)) < 0)
239         syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
240  
241 #ifndef HAVE_KRB4
242     fromport = ntohs(from.sin_port);
243 #endif
244  
245 #ifdef _POSIX_VERSION
246     sigemptyset(&action.sa_mask);
247     action.sa_flags = 0;
248     action.sa_handler = SIG_IGN;
249     sigaction(SIGPIPE, &action, NULL);
250
251 #else
252     signal(SIGPIPE, SIG_IGN);   /* so we can detect failures */
253 #endif
254  
255     from.sin_port = srv_addr.sin_port; /* we don't care what port
256                                         * it came from, and we need to
257                                         * fake out server_which_server() */
258     server = server_which_server(&from);
259     if (!server) {
260         syslog(LOG_ERR, "bdump_send: unknown server?");
261         server = limbo_server;
262     }
263 #if 1
264     zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
265            inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
266 #endif
267
268     bdumping = 1;
269     server->dumping = 1;
270
271     if (bdump_socket >= 0) {
272         /* shut down the listening socket and the timer. */
273         FD_CLR(bdump_socket, &interesting);
274         close(bdump_socket);
275         nfds = srv_socket + 1;
276         bdump_socket = -1;
277         timer_reset(bdump_timer);
278     }
279  
280     /* Now begin the brain dump. */
281 #ifdef HAVE_KRB5
282     { /* "server" side */
283         krb5_auth_context actx;
284         
285     }
286 #else  /* HAVE_KRB5 */  
287 #ifdef HAVE_KRB4
288     /* receive the authenticator */
289     retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
290                              SERVER_SERVICE, srvtab_file);
291     if (retval != KSUCCESS) {
292         syslog(LOG_ERR, "bdump_send: getkdata: %s",
293                krb_get_err_text(retval));
294         cleanup(server);
295         return;
296     }
297     if (get_tgt()) {
298         cleanup(server);
299         return;
300     }
301     if (strcmp(kdata.pname, SERVER_SERVICE) ||
302         strcmp(kdata.pinst, SERVER_INSTANCE) ||
303         strcmp(kdata.prealm, ZGetRealm())) {
304         syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
305                kdata.pname, kdata.pinst, kdata.prealm);
306         cleanup(server);
307         return;
308     }
309     /* authenticate back */
310     retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
311                               SERVER_INSTANCE);
312     if (retval != 0) {
313         syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
314                error_message (retval));
315         cleanup(server);
316         return;
317     }
318 #else  /* !HAVE_KRB4 */
319     if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
320         syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
321         cleanup(server);
322         return;
323     }
324 #endif /* HAVE_KRB4 */
325 #endif /* HAVE_KRB5 */    
326
327     retval = setup_file_pointers();
328     if (retval != 0) {
329         syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
330                 error_message(retval));
331         cleanup(server);
332         return;
333     }
334     retval = bdump_send_loop(server);
335     if (retval != ZERR_NONE) {
336         syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
337                error_message(retval));
338         cleanup(server);
339         return;
340     }
341     retval = bdump_recv_loop(server);
342     if (retval != ZERR_NONE) {
343         syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
344                error_message(retval));
345         cleanup(server);
346         return;
347     }
348 #if 1
349     zdbug((LOG_DEBUG, "bdump_send: finished"));
350 #endif
351     if (server != limbo_server) {
352         /* set this guy to be up, and schedule a hello */
353         server->state = SERV_UP;
354         timer_reset(server->timer);
355         server->timer = timer_set_rel(0L, server_timo, server);
356     }
357 #if 0
358     zdbug((LOG_DEBUG,"cleanup sbd"));
359 #endif
360     shutdown_file_pointers();
361
362 #ifdef _POSIX_VERSION
363     action.sa_handler = SIG_DFL;
364     sigaction(SIGPIPE, &action, NULL);
365 #else
366     signal(SIGPIPE, SIG_DFL);
367 #endif
368     bdumping = 0;
369     server->dumping = 0;
370     /* Now that we are finished dumping, send all the queued packets */
371     server_send_queue(server);
372     return;
373 }
374
375 /*ARGSUSED*/
376 static void
377 bdump_get_v12 (notice, auth, who, server)
378     ZNotice_t *notice;
379     int auth;
380     struct sockaddr_in *who;
381     Server *server;
382 {
383     struct sockaddr_in from;
384     Code_t retval;
385     int on = 1;
386 #ifdef _POSIX_VERSION
387     struct sigaction action;
388 #endif
389 #ifdef HAVE_KRB4
390     KTEXT_ST ticket;
391     AUTH_DAT kdata;
392 #else  /* !HAVE_KRB4 */
393     int reserved_port = IPPORT_RESERVED - 1;
394 #endif /* HAVE_KRB4 */
395     
396     bdumping = 1;
397     server->dumping = 1;
398  
399 #ifdef _POSIX_VERSION
400     action.sa_flags = 0;
401     sigemptyset(&action.sa_mask);
402     action.sa_handler = SIG_IGN;
403     sigaction(SIGPIPE, &action, NULL);
404 #else
405     signal(SIGPIPE, SIG_IGN);   /* so we can detect problems */
406 #endif /* _POSIX_VRESION */
407  
408     if (bdump_socket >= 0) {
409         /* We cannot go get a brain dump when someone may
410            potentially be connecting to us (if that other
411            server is the server to whom we are connecting,
412            we will deadlock. so we shut down the listening
413            socket and the timer. */
414         FD_CLR(bdump_socket, &interesting);
415         close(bdump_socket);
416         nfds = srv_socket+1;
417         bdump_socket = -1;
418         timer_reset(bdump_timer);
419     }
420
421     retval = extract_sin(notice, &from);
422     if (retval != ZERR_NONE) {
423         syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
424 #ifdef _POSIX_VERSION
425         action.sa_handler = SIG_DFL;
426         sigaction(SIGPIPE, &action, NULL);
427 #else
428         signal(SIGPIPE, SIG_DFL);
429 #endif
430         bdumping = 0;
431         server->dumping = 0;
432         return;
433     }
434 #ifndef HAVE_KRB4
435     if (ntohs(from.sin_port) > IPPORT_RESERVED ||
436         ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
437         syslog(LOG_ERR, "bdump_get: port not reserved: %d",
438                ntohs(from.sin_port));
439         cleanup(server);
440         return;
441     }
442     live_socket = rresvport(&reserved_port);
443 #else  /* !HAVE_KRB4 */
444     live_socket = socket(AF_INET, SOCK_STREAM, 0);
445 #endif /* HAVE_KRB4 */
446     if (live_socket < 0) {
447         syslog(LOG_ERR, "bdump_get: socket: %m");
448         cleanup(server);
449         return;
450     }
451     if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
452         syslog(LOG_ERR, "bdump_get: connect: %m");
453         cleanup(server);
454         return;
455     }
456     if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
457                    sizeof(on)) < 0)
458         syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
459 #if 1
460     zdbug((LOG_DEBUG, "bdump_get: connected"));
461 #endif
462  
463     /* Now begin the brain dump. */
464
465 #ifdef HAVE_KRB5
466     { /* "client" side */
467         krb5_auth_context actx;
468         krb5_creds creds;
469         krb5_creads *credsp;
470         krb5_principal principal;
471         krb5_data data;
472
473         memset((char *)&creds, 0, sizeof(creds));
474
475         retval = krb5_build_principal(Z_krb5_ctx, &principal, 
476                                       strlen(ZGetRealm()),
477                                       ZGetRealm(),
478                                       SERVER_KRB5_SERVICE, SERVER_INSTANCE,
479                                       0); 
480         if (retval) {
481             syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
482             cleanup(server);
483             return;
484         }
485
486         retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
487         if (retval) {
488             syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
489             krb5_free_principal(Z_krb5_ctx, principal);
490             cleanup(server);
491             return;
492         }
493         
494         retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
495         krb5_free_principal(Z_krb5_ctx, principal);
496         if (retval) {
497             syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
498             krb5_free_cred_contents(Z_krb5_ctx, creds);
499             cleanup(server);
500             return;
501         }
502
503         retval = krb5_get_credentials(Z_krb5_context, 0, Z_krb5_ccache,
504                                       &creds, &credsp);
505         krb5_free_cred_contents(Z_krb5_ctx, creds);
506         if (retval) {
507             syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
508             cleanup(server);
509             return;
510         }
511
512         retval = krb5_auth_con_init(Z_krb5_ctx, &actx);
513         if (retval) {
514             syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
515             krb5_free_creds(Z_krb5_ctx, credsp);
516             cleanup(server);
517             return;
518         }
519
520         memset((char *)data, 0, sizeof(krb5_data));
521         retval = krb5_mk_req_ext(Z_krb5_ctx, &actx, AP_OPTS_MUTUAL_REQUIRE|AP_OPTS_USE_SUBKEY,
522                                  NULL, credsp, &data);
523 i       if (retval) {
524             syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
525             krb5_auth_con_free(Z_krb5_ctx, actx);
526             krb5_free_creds(Z_krb5_ctx, credsp);
527             cleanup(server);
528             return;
529         }
530     }
531 #else    
532 #ifdef HAVE_KRB4
533     /* send an authenticator */
534     if (get_tgt()) {
535         cleanup(server);
536         return;
537     }
538     retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
539                               SERVER_INSTANCE);
540     if (retval != 0) {
541         syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
542         cleanup(server);
543         return;
544     }
545 #if 1
546     zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
547 #endif
548  
549     /* get his authenticator */
550     retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
551                              SERVER_SERVICE, srvtab_file);
552     if (retval != KSUCCESS) {
553         syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
554         cleanup(server);
555         return;
556     }
557
558     if (strcmp(kdata.pname, SERVER_SERVICE) ||
559         strcmp(kdata.pinst, SERVER_INSTANCE) ||
560         strcmp(kdata.prealm, ZGetRealm())) {
561         syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
562                kdata.pname, kdata.pinst,kdata.prealm);
563         cleanup(server);
564         return;
565     }
566 #endif /* HAVE_KRB4 */
567 #endif    
568     retval = setup_file_pointers();
569     if (retval != 0) {
570         syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
571                error_message (retval));
572         cleanup(server);
573         return;
574     }
575     retval = bdump_recv_loop(server);
576     if (retval != ZERR_NONE) {
577         syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
578                error_message(retval));
579         cleanup(server);
580         return;
581     }
582 #if 1
583     zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
584 #endif
585     retval = bdump_send_loop(server);
586     if (retval != ZERR_NONE) {
587         syslog(LOG_WARNING, "bdump_send_loop failed: %s",
588                error_message(retval));
589         cleanup(server);
590         return;
591     }
592 #if 1
593     zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
594 #endif
595     /* set this guy to be up, and schedule a hello */
596     server->state = SERV_UP;
597     timer_reset(server->timer);
598     server->timer = timer_set_rel(0L, server_timo, server);
599
600 #if 1
601     zdbug((LOG_DEBUG,"cleanup gbd"));
602 #endif
603     shutdown_file_pointers();
604 #ifdef _POSIX_VERSION
605     action.sa_handler = SIG_DFL;
606     sigaction(SIGPIPE, &action, NULL);
607 #else
608     signal(SIGPIPE, SIG_DFL);
609 #endif
610     bdumping = 0;
611     server->dumping = 0;
612     /* Now that we are finished dumping, send all the queued packets */
613     server_send_queue(server);
614
615     return;
616 }
617
618 void
619 bdump_get(notice, auth, who, server)
620     ZNotice_t *notice;
621     int auth;
622     struct sockaddr_in *who;
623     Server *server;
624 {
625     void (*proc) __P((ZNotice_t *, int, struct sockaddr_in *, Server *));
626
627     proc = NULL;
628
629 #if 1
630     if (zdebug) {
631         syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
632                notice->z_class_inst, inet_ntoa(who->sin_addr));
633     }
634 #endif
635     if (strcmp (notice->z_class_inst, "1.2") == 0)
636         proc = bdump_get_v12;
637
638     if (proc) {
639         (*proc)(notice, auth, who, server);
640     } else {
641         syslog(LOG_WARNING,
642                "bdump_get: Incompatible bdump version '%s' from %s",
643                notice->z_class_inst,
644                inet_ntoa(who->sin_addr));
645     }
646 }
647
648 /*
649  * Send a list off as the specified notice
650  */
651
652 Code_t
653 bdump_send_list_tcp(kind, addr, class_name, inst, opcode, sender, recip, lyst,
654                     num)
655     ZNotice_Kind_t kind;
656     struct sockaddr_in *addr;
657     int num;
658     char *class_name, *inst, *opcode, *sender, *recip, **lyst;
659 {
660     ZNotice_t notice;
661     char *pack, addrbuf[100];
662     int packlen, count;
663     Code_t retval;
664     u_short length;
665
666     memset (&notice, 0, sizeof(notice));
667  
668     retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
669                         (unsigned char *) &addr->sin_addr,
670                         sizeof(struct in_addr));
671     if (retval != ZERR_NONE)
672         return retval;
673     notice.z_kind = kind;
674  
675     notice.z_port = addr->sin_port;
676     notice.z_class = class_name;
677     notice.z_class_inst = inst;
678     notice.z_opcode = opcode;
679     notice.z_sender = sender;
680     notice.z_recipient = recip;
681     notice.z_default_format = "";
682     notice.z_num_other_fields = 1;
683     notice.z_other_fields[0] = addrbuf;
684  
685     retval = ZFormatNoticeList(&notice, lyst, num, &pack, &packlen, ZNOAUTH);
686     if (retval != ZERR_NONE)
687         return retval;
688         
689     length = htons((u_short) packlen);
690  
691     count = net_write(output, (char *) &length, sizeof(length));
692     if (count != sizeof(length)) {
693         if (count < 0) {
694             free(pack);
695             return(errno);
696         } else {
697             syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
698                    sizeof(length), count);
699             free(pack);
700             return(ZSRV_PKSHORT);
701         }
702     }
703  
704     count = net_write(output, pack, packlen);
705     if (count != packlen) {
706         if (count < 0) {
707             free(pack);
708             return(errno);
709         } else {
710             syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
711                    packlen, count);
712             free(pack);
713             return(ZSRV_PKSHORT);
714         }
715     }
716     free(pack);
717     return(ZERR_NONE);
718 }
719
720 static void
721 shutdown_file_pointers() {
722     if (input) {
723         fclose(input);
724         input = 0;
725     }
726     if (output) {
727         fclose(output);
728         output = 0;
729     }
730     if (live_socket >= 0) {
731         close(live_socket);
732         live_socket = -1;
733     }
734 }
735
736 static void
737 cleanup(server)
738     Server *server;
739 {
740 #ifdef _POSIX_VERSION
741     struct sigaction action;
742 #endif
743
744 #if 1
745     zdbug((LOG_DEBUG, "bdump cleanup"));
746 #endif
747     if (server != limbo_server) {
748         server->state = SERV_DEAD;
749         timer_reset(server->timer);
750         server->timer = timer_set_rel(0L, server_timo, server);
751     }
752     shutdown_file_pointers ();
753 #ifdef _POSIX_VERSION
754     action.sa_flags = 0;
755     sigemptyset(&action.sa_mask);
756     action.sa_handler = SIG_DFL;
757     sigaction(SIGPIPE,&action, NULL);
758 #else
759     signal(SIGPIPE, SIG_DFL);
760 #endif /* _POSIX_VERSION */
761     bdumping = 0;
762     server->dumping = 0;
763 }
764
765 #ifdef HAVE_KRB4
766 int
767 get_tgt()
768 {
769     /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
770      * at least INST_SZ bytes long. */
771     static char buf[INST_SZ + 1] = SERVER_INSTANCE;
772     int retval = 0;
773     CREDENTIALS cred;
774 #ifndef NOENCRYPTION
775     Sched *s;
776 #endif
777         
778     /* have they expired ? */
779     if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
780         /* +15 for leeway */
781 #if 0
782         zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
783                NOW - tkt_lifetime(TKTLIFETIME) + 15L));
784 #endif
785         dest_tkt();
786
787         retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
788                                     "krbtgt", ZGetRealm(),
789                                     TKTLIFETIME, srvtab_file);
790         if (retval != KSUCCESS) {
791             syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
792                    krb_get_err_text(retval));
793             ticket_time = 0;
794             return(1);
795         } else {
796             ticket_time = NOW;
797         }
798
799 #ifndef NOENCRYPTION
800         retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
801                                   ZGetRealm(), 0 /*kvno*/,
802                                   srvtab_file, serv_key);
803         if (retval != KSUCCESS) {
804             syslog(LOG_ERR, "get_tgt: read_service_key: %s",
805                    krb_get_err_text(retval));
806             return 1;
807         }
808 #if 0
809         s = (Sched *) check_key_sched_cache(serv_key);
810         if (s) {
811             serv_ksched = *s;
812         } else {
813             des_key_sched(serv_key, serv_ksched.s);
814             add_to_key_sched_cache(serv_key, &serv_ksched);
815         }
816 #else
817         des_key_sched(serv_key, serv_ksched.s);
818 #endif
819 #endif /* !NOENCRYPTION */
820     }
821 #ifdef HAVE_KRB5        
822     /* XXX */
823     if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
824         krb5_keytab kt;
825         krb5_get_init_creds_opt opt;
826         krb5_creds cred;
827         krb5_principal principal;
828
829         memset(&cred, 0, sizeof(cred));
830
831         retval = krb5_build_principal(Z_krb5_ctx, &principal, 
832                                       strlen(ZGetRealm()),
833                                       ZGetRealm(),
834                                       SERVER_KRB5_SERVICE, SERVER_INSTANCE,
835                                       0); 
836         if (retval) {
837           krb5_free_principal(Z_krb5_ctx, principal);
838           return(1);
839         }
840
841         krb5_get_init_creds_opt_init (&opt);
842         krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
843
844         retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
845         if (retval) return(1);
846         
847         retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
848                                              &cred,
849                                              principal,
850                                              kt,
851                                              0,
852                                              NULL,
853                                              &opt);
854         krb5_free_principal(Z_krb5_ctx, principal);
855         krb5_kt_close(Z_krb5_ctx, kt);
856         if (retval) return(1);
857
858         retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
859         if (retval) return(1);
860     
861         retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
862         if (retval) return(1);
863
864         ticket5_time = NOW;
865
866         krb5_free_cred_contents (Z_krb5_ctx, &cred);
867     }
868 #endif
869     return(0);
870 }
871 #endif /* HAVE_KRB4 */
872
873 /*
874  * The braindump offer wasn't taken, so we retract it.
875  */
876  
877 /*ARGSUSED*/
878 static void
879 close_bdump(arg)
880     void * arg;
881 {
882     if (bdump_socket >= 0) {
883         FD_CLR(bdump_socket, &interesting);
884         close(bdump_socket);
885         nfds = srv_socket + 1;
886         bdump_socket = -1;
887 #if 1
888         zdbug((LOG_DEBUG, "bdump not used"));
889 #endif
890     } else {
891 #if 1
892         zdbug((LOG_DEBUG, "bdump not open"));
893 #endif
894     }
895     return;
896 }
897  
898 /*
899  * Start receiving instruction notices from the brain dump socket
900  */
901  
902 static Code_t
903 bdump_recv_loop(server)
904     Server *server;
905 {
906     ZNotice_t notice;
907     ZPacket_t packet;
908     int len;
909     Code_t retval;
910     Client *client = NULL;
911     struct sockaddr_in who;
912 #ifdef HAVE_KRB4
913     char *cp;
914     C_Block cblock;
915 #endif /* HAVE_KRB4 */
916     ZRealm *realm = NULL;
917  
918 #if 1
919     zdbug((LOG_DEBUG, "bdump recv loop"));
920 #endif
921         
922     /* do the inverse of bdump_send_loop, registering stuff on the fly */
923     while (1) {
924         if (packets_waiting()) {
925             /* A non-braindump packet is waiting; handle it. */
926             bdumping = 0;
927             bdump_concurrent = 1;
928             handle_packet();
929             bdump_concurrent = 0;
930             bdumping = 1;
931         }
932         len = sizeof(packet);
933         retval = get_packet(packet, len, &len);
934         if (retval != ZERR_NONE) {
935             syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
936             return retval;
937         }
938
939         retval = ZParseNotice(packet, len, &notice);
940         if (retval != ZERR_NONE) {
941             syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
942             return retval;
943         }
944 #if defined (DEBUG)
945         if (zdebug) {
946             syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
947                     ZNoticeKinds[(int) notice.z_kind], notice.z_class,
948                     notice.z_class_inst, notice.z_opcode, notice.z_sender,
949                     notice.z_recipient);
950         }
951 #endif /* DEBUG */
952         if (notice.z_num_other_fields >= 1) {
953             retval = ZReadAscii(notice.z_other_fields[0],
954                                 strlen(notice.z_other_fields[0]),
955                                 (unsigned char *) &who.sin_addr,
956                                 sizeof(struct in_addr));
957             if (retval != ZERR_NONE) {
958                 syslog(LOG_ERR, "brl zreadascii failed: %s",
959                        error_message(retval));
960                 return retval;
961             }
962         } else {
963             who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
964         }
965         who.sin_family = AF_INET;
966         who.sin_port = notice.z_port;
967
968         if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
969             /* end of brain dump */
970             return ZERR_NONE;
971         } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
972             /* get a realm from the message */
973             realm = realm_get_realm_by_name(notice.z_message);
974             if (!realm) {
975                 syslog(LOG_ERR, "brl newrlm failed: no realm %s", 
976                        notice.z_message);
977             }
978         } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
979             /* 1 = tell it we are authentic */
980             retval = ulogin_dispatch(&notice, 1, &who, server);
981             if (retval != ZERR_NONE) {
982                 syslog(LOG_ERR, "brl ul_disp failed: %s",
983                        error_message(retval));
984                 return retval;
985             }
986         } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
987             /* a new client */
988             notice.z_port = htons((u_short) atoi(notice.z_message));
989             retval = client_register(&notice, &who.sin_addr, &client, 0);
990             if (retval != ZERR_NONE) {
991                 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
992                 return retval;
993             }
994 #ifdef HAVE_KRB4
995             memset(client->session_key, 0, sizeof(C_Block));
996             if (*notice.z_class_inst) {
997                 /* a C_Block is there */
998                 cp = notice.z_message + strlen(notice.z_message) + 1;
999                 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1000                 if (retval != ZERR_NONE) {
1001                     syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1002                            error_message(retval), cp);
1003                 } else {
1004 #ifdef NOENCRYPTION
1005                     memcpy(cblock, client->session_key, sizeof(C_Block));
1006 #else
1007                     des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1008                                     DES_DECRYPT);
1009 #endif
1010                 }
1011             }
1012 #endif /* HAVE_KRB4 */
1013         } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) { 
1014             /* a subscription packet */
1015             if (!client) {
1016                 syslog(LOG_ERR, "brl no client");
1017                 return ZSRV_NOCLT;
1018             }
1019             retval = subscr_subscribe(client, &notice, server);
1020             if (retval != ZERR_NONE) {
1021                 syslog(LOG_WARNING, "brl subscr failed: %s",
1022                        error_message(retval));
1023                 return retval;
1024             }
1025         } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1026             /* add a subscription for a realm */
1027             if (realm) {
1028                 retval = subscr_realm(realm, &notice);
1029                 if (retval != ZERR_NONE) {
1030                     syslog(LOG_WARNING, "brl subscr failed: %s",
1031                            error_message(retval));
1032                     return retval;
1033                 }
1034             } /* else 
1035                  /* Other side tried to send us subs for a realm we didn't
1036                     know about, and so we drop them silently */
1037         
1038         } else {
1039             syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1040             return ZSRV_UNKNOWNOPCODE;
1041         }
1042     }
1043 }
1044
1045 /*
1046  * Send all the state to the peer.
1047  */
1048
1049 static Code_t
1050 bdump_send_loop(server)
1051     Server *server;
1052 {
1053     Code_t retval;
1054
1055 #if 1
1056     zdbug((LOG_DEBUG, "bdump send loop"));
1057 #endif
1058
1059     retval = uloc_send_locations();
1060     if (retval != ZERR_NONE)
1061         return retval;
1062     retval = client_send_clients();
1063     if (retval != ZERR_NONE)
1064         return retval;
1065     retval = realm_send_realms();
1066     if (retval != ZERR_NONE)
1067         return retval;
1068     return send_done();
1069 }
1070
1071 /*
1072  * Send a sync indicating end of this host
1073  */
1074
1075 static Code_t
1076 send_done()
1077 {
1078     Code_t retval;
1079  
1080 #if 1
1081     zdbug((LOG_DEBUG, "send_done"));
1082 #endif
1083     retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1084                              "", ADMIN_DONE, myname, "", NULL, 0);
1085     return retval;
1086 }
1087
1088
1089 /*
1090  * Send a list off as the specified notice
1091  */
1092
1093 static Code_t
1094 send_list(kind, port, class_name, inst, opcode, sender, recip, lyst, num)
1095     ZNotice_Kind_t kind;
1096     int port, num;
1097     char *class_name, *inst, *opcode, *sender, *recip, **lyst;
1098 {
1099     ZNotice_t notice;
1100     char *pack;
1101     int packlen;
1102     Code_t retval;
1103  
1104     memset (&notice, 0, sizeof(notice));
1105
1106     notice.z_kind = kind;
1107     notice.z_port = port;
1108     notice.z_class = class_name;
1109     notice.z_class_inst = inst;
1110     notice.z_opcode = opcode;
1111     notice.z_sender = sender;
1112     notice.z_recipient = recip;
1113     notice.z_default_format = "";
1114     notice.z_num_other_fields = 0;
1115         
1116     retval = ZFormatNoticeList(&notice, lyst, num, &pack, &packlen, ZNOAUTH);
1117     if (retval != ZERR_NONE) {
1118         syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1119         return retval;
1120     }
1121         
1122     retval = ZSendPacket(pack, packlen, 0);
1123     if (retval != ZERR_NONE)
1124         syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1125     free(pack);
1126     return retval;
1127 }
1128
1129 /*
1130  * Send a message off as the specified notice, via TCP
1131  */
1132
1133 static Code_t
1134 send_normal_tcp(kind, port, class_name, inst, opcode, sender, recip,
1135                 message, len)
1136     ZNotice_Kind_t kind;
1137     int port, len;
1138     char *class_name, *inst, *opcode, *sender, *recip, *message;
1139 {
1140     ZNotice_t notice;
1141     char *pack;
1142     int packlen, count;
1143     Code_t retval;
1144     u_short length;
1145  
1146     memset (&notice, 0, sizeof(notice));
1147
1148     notice.z_kind = kind;
1149     notice.z_port = port;
1150     notice.z_class = class_name;
1151     notice.z_class_inst = inst;
1152     notice.z_opcode = opcode;
1153     notice.z_sender = sender;
1154     notice.z_recipient = recip;
1155     notice.z_default_format = "";
1156     notice.z_message = message;
1157     notice.z_message_len = len;
1158     notice.z_num_other_fields = 0;
1159  
1160     retval = ZFormatNotice(&notice, &pack, &packlen, ZNOAUTH);
1161     if (retval != ZERR_NONE) {
1162         syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1163         return retval;
1164     }
1165  
1166     length = htons((u_short) packlen);
1167  
1168     count = net_write(output, (char *) &length, sizeof(length));
1169     if (count != sizeof(length)) {
1170         if (count < 0) {
1171             syslog(LOG_WARNING, "snt xmit/len: %m");
1172             free(pack);
1173             return errno;
1174         } else {
1175             syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1176             free(pack);
1177             return ZSRV_LEN;
1178         }
1179     }
1180     count = net_write(output, pack, packlen);
1181     if (count != packlen) {
1182         if (count < 0) {
1183             syslog(LOG_WARNING, "snt xmit: %m");
1184             free(pack);
1185             return errno;
1186         } else {
1187             syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1188             free(pack);
1189             return ZSRV_LEN;
1190         }
1191     }
1192     free(pack);
1193     return ZERR_NONE;
1194 }
1195
1196 /*
1197  * get a packet from the TCP socket
1198  * return 0 if successful, error code else
1199  */
1200
1201 static Code_t
1202 get_packet(packet, len, retlen)
1203     void *packet;
1204     int len;
1205     int *retlen;
1206 {
1207     u_short length;
1208     int result;
1209  
1210     result = net_read(input, (char *) &length, sizeof(u_short));
1211     if (result < sizeof(short)) {
1212         if (result < 0) {
1213             return errno;
1214         } else {
1215             syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1216                    sizeof(short));
1217             return ZSRV_LEN;
1218         }
1219     }
1220         
1221     length = ntohs(length);
1222     if (len < length)
1223         return ZSRV_BUFSHORT;
1224     result = net_read(input, packet, (int) length);
1225     if (result < length) {
1226         if (result < 0) {
1227             return errno;
1228         } else {
1229             syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1230             return ZSRV_LEN;
1231         }
1232     }
1233     *retlen = length;
1234     return ZERR_NONE;
1235 }
1236
1237 static Code_t
1238 extract_sin(notice, target)
1239     ZNotice_t *notice;
1240     struct sockaddr_in *target;
1241 {
1242     char *cp = notice->z_message;
1243     char *buf;
1244
1245     buf = cp;
1246     if (!notice->z_message_len || *buf == '\0') {
1247 #if 0
1248         zdbug((LOG_DEBUG,"no addr"));
1249 #endif
1250         return ZSRV_PKSHORT;
1251     }
1252     target->sin_addr.s_addr = inet_addr(cp);
1253  
1254     cp += (strlen(cp) + 1);     /* past the null */
1255     if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1256 #if 0
1257         zdbug((LOG_DEBUG, "no port"));
1258 #endif
1259         return(ZSRV_PKSHORT);
1260     }
1261     target->sin_port = htons((u_short) atoi(cp));
1262     target->sin_family = AF_INET;
1263     return ZERR_NONE;
1264 }
1265
1266 static int
1267 net_read(f, buf, len)
1268     FILE *f;
1269     char *buf;
1270     int len;
1271 {
1272     int cc, len2 = 0;
1273  
1274     fflush (output);
1275     do {
1276         errno = 0;
1277         cc = fread(buf, 1, len, f);
1278         if (cc == 0)
1279           {
1280             if (feof(f))
1281               return len2;
1282             if (errno == 0)
1283               errno = EIO;
1284             return -1;
1285           }
1286         buf += cc;
1287         len2 += cc;
1288         len -= cc;
1289     } while (len > 0);
1290     return len2;
1291 }
1292
1293 static int
1294 net_write(f, buf, len)
1295     FILE *f;
1296     char *buf;
1297     int len;
1298 {
1299     int cc;
1300     int wrlen = len;
1301     do {
1302         cc = fwrite (buf, 1, wrlen, f);
1303         if (cc == 0)
1304             return -1;
1305         buf += cc;
1306         wrlen -= cc;
1307     } while (wrlen > 0);
1308     return len;
1309 }
1310
1311 static int
1312 setup_file_pointers ()
1313 {
1314     int fd;
1315
1316     input = fdopen (live_socket, "r");
1317     if (!input)
1318         return errno;
1319
1320     fd = dup (live_socket);
1321     if (fd < 0)
1322         return errno;
1323     output = fdopen (fd, "w");
1324     if (!output)
1325         return errno;
1326
1327     return 0;
1328 }