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