1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains functions for dumping server state between servers.
4 * Created by: John T. Kohl
6 * $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/bdump.c,v $
10 * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, see the file
15 #include <zephyr/mit-copyright.h>
17 #include <sys/socket.h>
21 static const char rcsid_bdump_c[] = "$Id$";
25 * External functions are:
27 * void bdump_offer(who)
28 * strut sockaddr_in *who;
32 * void bdump_get(notice, auth, who, server)
35 * struct sockaddr_in *who;
38 * Code_t bdump_send_list_tcp(kind, port, class, inst, opcode,
39 * sender, recip, lyst, num)
40 * ZNotice_Kind_t kind;
42 * char *class, *inst, *opcode, *sender, *recip;
47 #if defined(HAVE_KRB5) && 0
48 int krb5_init_keyblock(krb5_context context,
58 key=malloc(sizeof(*key));
59 memset(key, 0, sizeof(*key));
60 ret = krb5_enctype_keysize(context, type, &len);
65 krb5_set_error_string(context, "Encryption key %d is %lu bytes "
66 "long, %lu was passed in",
67 type, (unsigned long)len, (unsigned long)size);
68 return KRB5_PROG_ETYPE_NOSUPP;
71 ret = krb5_data_alloc(&key->keyvalue, len);
73 krb5_set_error_string(context, "malloc failed: %lu",
84 static void close_bdump __P((void* arg));
85 static Code_t bdump_send_loop __P((Server *server)),
86 bdump_ask_for __P((char *inst)),
87 bdump_recv_loop __P((Server *server));
88 static void bdump_get_v12 __P((ZNotice_t *, int, struct sockaddr_in *,
90 static Code_t get_packet __P((void *packet, int len, int *retlen));
91 static Code_t extract_sin __P((ZNotice_t *notice, struct sockaddr_in *target));
92 static Code_t send_done __P((void));
93 static Code_t send_list __P((ZNotice_Kind_t kind, int port, char *class_name,
94 char *inst, char *opcode, char *sender,
95 char *recip, char **lyst, int num));
96 static Code_t send_normal_tcp __P((ZNotice_Kind_t kind, int port,
98 char *inst, char *opcode, char *sender,
99 char *recip, char *message, int len));
100 static int net_read __P((FILE *f, char *buf, int len));
101 static int net_write __P((FILE *f, char *buf, int len));
102 static int setup_file_pointers __P((void));
103 static void shutdown_file_pointers __P((void));
104 static void cleanup __P((Server *server));
107 static long ticket5_time;
108 #define TKT5LIFETIME 8*60*60
109 #define tkt5_lifetime(val) (val)
113 static long ticket_time;
115 #define TKTLIFETIME 120
116 #define tkt_lifetime(val) ((long) val * 5L * 60L)
119 extern C_Block serv_key;
120 extern Sched serv_ksched;
122 #endif /* HAVE_KRB4 */
124 static Timer *bdump_timer;
125 static int live_socket = -1;
126 static FILE *input, *output;
127 static struct sockaddr_in bdump_sin;
129 static krb5_auth_context bdump_ac;
132 static int cancel_outgoing_dump;
136 int bdump_concurrent;
137 extern char *bdump_version;
138 extern int bdump_auth_proto;
141 * Functions for performing a brain dump between servers.
145 * offer the brain dump to another server
150 struct sockaddr_in *who;
153 char buf[512], *addr, *lyst[2];
155 int bdump_port = IPPORT_RESERVED - 1;
156 #endif /* !HAVE_KRB4 */
158 zdbug((LOG_DEBUG, "bdump_offer"));
160 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
162 * when using kerberos server-server authentication, we can
163 * use any random local address
165 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
166 if (bdump_socket < 0) {
167 syslog(LOG_ERR,"bdump_offer: socket: %m");
171 memset(&bdump_sin, 0, sizeof(bdump_sin));
172 /* a port field of 0 makes the UNIX
173 * kernel choose an appropriate port/address pair */
175 bdump_sin.sin_port = 0;
176 bdump_sin.sin_addr = my_addr;
177 bdump_sin.sin_family = AF_INET;
178 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
181 syslog(LOG_ERR, "bdump_offer: bind: %m");
186 if (!bdump_sin.sin_port) {
187 int len = sizeof(bdump_sin);
189 if (getsockname(bdump_socket,
190 (struct sockaddr *) &bdump_sin, &len) < 0) {
191 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
197 #else /* !HAVE_KRB4 */
199 * when not using HAVE_KRB4, we can't use any old port, we use
200 * Internet reserved ports instead (rresvport)
202 bdump_socket = rresvport(&bdump_port);
203 if (bdump_socket < 0) {
204 syslog(LOG_ERR,"bdump_offer: socket: %m");
208 memset(&bdump_sin, 0, sizeof(bdump_sin));
209 bdump_sin.sin_port = htons((unsigned short) bdump_port);
210 bdump_sin.sin_addr = my_addr;
211 bdump_sin.sin_family = AF_INET;
212 #endif /* HAVE_KRB4 */
214 listen(bdump_socket, 1);
216 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
217 FD_SET(bdump_socket, &interesting);
218 nfds = max(bdump_socket, srv_socket) + 1;
220 addr = inet_ntoa(bdump_sin.sin_addr);
221 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
225 retval = ZSetDestAddr(who);
226 if (retval != ZERR_NONE) {
227 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
228 error_message(retval));
232 /* myname is the hostname */
233 /* the class instance is the version number, here it is */
234 /* bdump_version, which is set in main */
235 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
236 ADMIN_BDUMP, myname, "", lyst, 2);
239 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
240 inet_ntoa(bdump_sin.sin_addr),
241 ntohs(bdump_sin.sin_port)));
247 * Accept a connection, and send the brain dump to the other server
253 struct sockaddr_in from;
256 int fromlen = sizeof(from);
258 #ifdef _POSIX_VERSION
259 struct sigaction action;
261 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
269 /* may be moved into kstuff.c */
270 char instance [INST_SZ];
273 /* may be moved into kstuff.c */
274 krb5_principal principal;
276 krb5_ap_rep_enc_part *rep;
279 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
280 unsigned short fromport;
281 #endif /* HAVE_KRB4 */
284 zdbug((LOG_DEBUG, "bdump_send"));
286 /* accept the connection, and send the brain dump */
287 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
288 if (live_socket < 0) {
289 syslog(LOG_ERR,"bdump_send: accept: %m");
292 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
294 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
297 fromport = ntohs(from.sin_port);
300 #ifdef _POSIX_VERSION
301 sigemptyset(&action.sa_mask);
303 action.sa_handler = SIG_IGN;
304 sigaction(SIGPIPE, &action, NULL);
307 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
310 from.sin_port = srv_addr.sin_port; /* we don't care what port
311 * it came from, and we need to
312 * fake out server_which_server() */
313 server = server_which_server(&from);
315 syslog(LOG_ERR, "bdump_send: unknown server?");
316 server = limbo_server;
319 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
320 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
326 if (bdump_socket >= 0) {
327 /* shut down the listening socket and the timer. */
328 FD_CLR(bdump_socket, &interesting);
330 nfds = srv_socket + 1;
332 timer_reset(bdump_timer);
335 /* Now begin the brain dump. */
336 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
337 retval = ReadKerberosData(live_socket, &len, &data, &proto);
340 syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
341 krb_get_err_text(retval));
346 syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
349 syslog(LOG_ERR, "bdump_send: get_tgt failed");
358 retval = krb5_build_principal(Z_krb5_ctx, &principal,
361 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
364 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
370 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
372 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
377 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
379 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
384 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
385 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
387 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
392 /* Get the "client" krb_ap_req */
394 memset((char *)&k5data, 0, sizeof(krb5_data));
398 syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
399 error_message(retval));
405 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
407 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
408 error_message(retval));
409 krb5_kt_close(Z_krb5_ctx, kt);
414 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
415 krb5_free_principal(Z_krb5_ctx, principal);
416 krb5_kt_close(Z_krb5_ctx, kt);
418 memset((char *)&k5data, 0, sizeof(krb5_data));
420 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
421 error_message(retval));
426 /* Now send back our auth packet */
428 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
430 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
434 retval = SendKrb5Data(live_socket, &k5data);
436 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
437 error_message(retval));
438 krb5_free_data_contents(Z_krb5_ctx, &k5data);
442 krb5_free_data_contents(Z_krb5_ctx, &k5data);
444 #endif /* HAVE_KRB5 */
447 /* here to krb_rd_req from GetKerberosData candidate for refactoring
448 back into kstuff.c */
449 (void) strcpy(instance, "*"); /* let Kerberos fill it in */
452 memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
453 retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
454 from.sin_addr.s_addr, &kdata, srvtab_file);
456 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
457 SERVER_SERVICE, srvtab_file);
459 if (retval != KSUCCESS) {
460 syslog(LOG_ERR, "bdump_send: getkdata: %s",
461 krb_get_err_text(retval));
465 if (strcmp(kdata.pname, SERVER_SERVICE) ||
466 strcmp(kdata.pinst, SERVER_INSTANCE) ||
467 strcmp(kdata.prealm, ZGetRealm())) {
468 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
469 kdata.pname, kdata.pinst, kdata.prealm);
473 /* authenticate back */
474 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
477 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
478 error_message (retval));
483 #endif /* HAVE_KRB4 */
485 #else /* HAVE_KRB4 || HAVE_KRB5 */
486 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
487 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
491 #endif /* HAVE_KRB4 || HAVE_KRB5 */
492 retval = setup_file_pointers();
494 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
495 error_message(retval));
499 retval = bdump_send_loop(server);
500 if (retval != ZERR_NONE) {
501 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
502 error_message(retval));
506 retval = bdump_recv_loop(server);
507 if (retval != ZERR_NONE) {
508 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
509 error_message(retval));
514 zdbug((LOG_DEBUG, "bdump_send: finished"));
516 if (server != limbo_server) {
517 /* set this guy to be up, and schedule a hello */
518 server->state = SERV_UP;
519 timer_reset(server->timer);
520 server->timer = timer_set_rel(0L, server_timo, server);
523 zdbug((LOG_DEBUG,"cleanup sbd"));
525 shutdown_file_pointers();
527 #ifdef _POSIX_VERSION
528 action.sa_handler = SIG_DFL;
529 sigaction(SIGPIPE, &action, NULL);
531 signal(SIGPIPE, SIG_DFL);
535 /* Now that we are finished dumping, send all the queued packets */
536 server_send_queue(server);
542 bdump_get_v12 (notice, auth, who, server)
545 struct sockaddr_in *who;
548 struct sockaddr_in from;
551 #ifdef _POSIX_VERSION
552 struct sigaction action;
554 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
558 krb5_principal principal;
560 krb5_ap_rep_enc_part *rep;
566 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
567 int reserved_port = IPPORT_RESERVED - 1;
568 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
573 #ifdef _POSIX_VERSION
575 sigemptyset(&action.sa_mask);
576 action.sa_handler = SIG_IGN;
577 sigaction(SIGPIPE, &action, NULL);
579 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
580 #endif /* _POSIX_VRESION */
582 if (bdump_socket >= 0) {
583 /* We cannot go get a brain dump when someone may
584 potentially be connecting to us (if that other
585 server is the server to whom we are connecting,
586 we will deadlock. so we shut down the listening
587 socket and the timer. */
588 FD_CLR(bdump_socket, &interesting);
592 timer_reset(bdump_timer);
595 retval = extract_sin(notice, &from);
596 if (retval != ZERR_NONE) {
597 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
598 #ifdef _POSIX_VERSION
599 action.sa_handler = SIG_DFL;
600 sigaction(SIGPIPE, &action, NULL);
602 signal(SIGPIPE, SIG_DFL);
608 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
609 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
610 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
611 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
612 ntohs(from.sin_port));
616 live_socket = rresvport(&reserved_port);
617 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
618 live_socket = socket(AF_INET, SOCK_STREAM, 0);
619 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
620 if (live_socket < 0) {
621 syslog(LOG_ERR, "bdump_get: socket: %m");
625 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
626 syslog(LOG_ERR, "bdump_get: connect: %m");
630 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
632 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
634 zdbug((LOG_DEBUG, "bdump_get: connected"));
637 /* Now begin the brain dump. */
638 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
640 syslog(LOG_ERR, "bdump_get: get_tgt failed");
644 switch(bdump_auth_proto) {
646 case 5: /* "client" side */
647 memset((char *)&creds, 0, sizeof(creds));
649 retval = krb5_build_principal(Z_krb5_ctx, &principal,
652 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
655 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
660 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
662 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
663 krb5_free_principal(Z_krb5_ctx, principal);
668 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
669 krb5_free_principal(Z_krb5_ctx, principal);
671 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
672 krb5_free_cred_contents(Z_krb5_ctx, &creds);
677 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
679 krb5_free_cred_contents(Z_krb5_ctx, &creds);
681 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
686 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
688 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
689 krb5_free_creds(Z_krb5_ctx, credsp);
694 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
696 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
697 krb5_free_creds(Z_krb5_ctx, credsp);
702 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
703 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
705 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
706 krb5_free_creds(Z_krb5_ctx, credsp);
711 memset((char *)&data, 0, sizeof(krb5_data));
712 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
713 NULL, credsp, &data);
715 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
716 krb5_free_creds(Z_krb5_ctx, credsp);
720 retval = SendKrb5Data(live_socket, &data);
721 krb5_free_creds(Z_krb5_ctx, credsp);
723 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
724 error_message(retval));
725 krb5_free_data_contents(Z_krb5_ctx, &data);
729 krb5_free_data_contents(Z_krb5_ctx, &data);
730 memset((char *)&data, 0, sizeof(krb5_data));
731 retval = GetKrb5Data(live_socket, &data);
733 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
734 error_message(retval));
738 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
740 memset((char *)&data, 0, sizeof(krb5_data));
742 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
743 error_message(retval));
751 /* send an authenticator */
752 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
755 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
759 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
761 /* get his authenticator */
762 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
763 SERVER_SERVICE, srvtab_file);
764 if (retval != KSUCCESS) {
765 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
770 if (strcmp(kdata.pname, SERVER_SERVICE) ||
771 strcmp(kdata.pinst, SERVER_INSTANCE) ||
772 strcmp(kdata.prealm, ZGetRealm())) {
773 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
774 kdata.pname, kdata.pinst,kdata.prealm);
779 #endif /* HAVE_KRB4 */
781 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
782 retval = setup_file_pointers();
784 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
785 error_message (retval));
789 retval = bdump_recv_loop(server);
790 if (retval != ZERR_NONE) {
791 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
792 error_message(retval));
796 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
797 retval = bdump_send_loop(server);
798 if (retval != ZERR_NONE) {
799 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
800 error_message(retval));
805 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
807 /* set this guy to be up, and schedule a hello */
808 server->state = SERV_UP;
809 timer_reset(server->timer);
810 server->timer = timer_set_rel(0L, server_timo, server);
813 zdbug((LOG_DEBUG,"cleanup gbd"));
815 shutdown_file_pointers();
816 #ifdef _POSIX_VERSION
817 action.sa_handler = SIG_DFL;
818 sigaction(SIGPIPE, &action, NULL);
820 signal(SIGPIPE, SIG_DFL);
824 /* Now that we are finished dumping, send all the queued packets */
825 server_send_queue(server);
831 bdump_get(notice, auth, who, server)
834 struct sockaddr_in *who;
837 void (*proc) __P((ZNotice_t *, int, struct sockaddr_in *, Server *));
843 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
844 notice->z_class_inst, inet_ntoa(who->sin_addr));
847 if (strcmp (notice->z_class_inst, "1.2") == 0)
848 proc = bdump_get_v12;
851 (*proc)(notice, auth, who, server);
854 "bdump_get: Incompatible bdump version '%s' from %s",
855 notice->z_class_inst,
856 inet_ntoa(who->sin_addr));
861 * Send a list off as the specified notice
865 bdump_send_list_tcp(kind, addr, class_name, inst, opcode, sender, recip, lyst,
868 struct sockaddr_in *addr;
870 char *class_name, *inst, *opcode, *sender, *recip, **lyst;
873 char *pack, addrbuf[100];
878 memset (¬ice, 0, sizeof(notice));
880 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
881 (unsigned char *) &addr->sin_addr,
882 sizeof(struct in_addr));
883 if (retval != ZERR_NONE)
885 notice.z_kind = kind;
887 notice.z_port = addr->sin_port;
888 notice.z_class = class_name;
889 notice.z_class_inst = inst;
890 notice.z_opcode = opcode;
891 notice.z_sender = sender;
892 notice.z_recipient = recip;
893 notice.z_default_format = "";
894 notice.z_num_other_fields = 1;
895 notice.z_other_fields[0] = addrbuf;
897 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
898 if (retval != ZERR_NONE)
903 krb5_data indata, outmsg;
904 indata.length=packlen;
906 memset(&outmsg, 0, sizeof(krb5_data));
907 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
908 if (retval != ZERR_NONE)
910 if (outmsg.length > Z_MAXPKTLEN) {
911 syslog(LOG_ERR, "bsl: encrypted packet is too large");
914 packlen = outmsg.length;
916 pack=malloc(packlen);
919 memcpy(pack, outmsg.data, packlen);
920 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
924 length = htons((u_short) packlen);
926 count = net_write(output, (char *) &length, sizeof(length));
927 if (count != sizeof(length)) {
932 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
933 sizeof(length), count);
935 return(ZSRV_PKSHORT);
939 count = net_write(output, pack, packlen);
940 if (count != packlen) {
945 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
948 return(ZSRV_PKSHORT);
956 shutdown_file_pointers() {
965 if (live_socket >= 0) {
970 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
980 #ifdef _POSIX_VERSION
981 struct sigaction action;
985 zdbug((LOG_DEBUG, "bdump cleanup"));
987 if (server != limbo_server) {
988 server->state = SERV_DEAD;
989 timer_reset(server->timer);
990 server->timer = timer_set_rel(0L, server_timo, server);
992 shutdown_file_pointers ();
993 #ifdef _POSIX_VERSION
995 sigemptyset(&action.sa_mask);
996 action.sa_handler = SIG_DFL;
997 sigaction(SIGPIPE,&action, NULL);
999 signal(SIGPIPE, SIG_DFL);
1000 #endif /* _POSIX_VERSION */
1002 server->dumping = 0;
1009 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
1010 * at least INST_SZ bytes long. */
1011 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
1014 #ifndef NOENCRYPTION
1018 /* have they expired ? */
1019 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1020 /* +15 for leeway */
1022 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1023 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1027 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
1028 "krbtgt", ZGetRealm(),
1029 TKTLIFETIME, srvtab_file);
1030 if (retval != KSUCCESS) {
1031 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1032 krb_get_err_text(retval));
1039 #ifndef NOENCRYPTION
1040 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1041 ZGetRealm(), 0 /*kvno*/,
1042 srvtab_file, serv_key);
1043 if (retval != KSUCCESS) {
1044 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1045 krb_get_err_text(retval));
1048 des_key_sched(serv_key, serv_ksched.s);
1049 #endif /* !NOENCRYPTION */
1053 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1055 krb5_get_init_creds_opt opt;
1057 krb5_principal principal;
1059 memset(&cred, 0, sizeof(cred));
1061 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1062 strlen(ZGetRealm()),
1064 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1067 krb5_free_principal(Z_krb5_ctx, principal);
1071 krb5_get_init_creds_opt_init (&opt);
1072 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1074 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1075 if (retval) return(1);
1077 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1084 krb5_free_principal(Z_krb5_ctx, principal);
1085 krb5_kt_close(Z_krb5_ctx, kt);
1086 if (retval) return(1);
1088 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1089 if (retval) return(1);
1091 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1092 if (retval) return(1);
1096 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1101 #endif /* HAVE_KRB4 */
1104 * The braindump offer wasn't taken, so we retract it.
1112 if (bdump_socket >= 0) {
1113 FD_CLR(bdump_socket, &interesting);
1114 close(bdump_socket);
1115 nfds = srv_socket + 1;
1118 zdbug((LOG_DEBUG, "bdump not used"));
1122 zdbug((LOG_DEBUG, "bdump not open"));
1129 * Start receiving instruction notices from the brain dump socket
1133 bdump_recv_loop(server)
1140 Client *client = NULL;
1141 struct sockaddr_in who;
1146 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1151 #endif /* HAVE_KRB4 */
1152 ZRealm *realm = NULL;
1155 zdbug((LOG_DEBUG, "bdump recv loop"));
1158 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1160 if (packets_waiting()) {
1161 /* A non-braindump packet is waiting; handle it. */
1163 bdump_concurrent = 1;
1165 bdump_concurrent = 0;
1168 len = sizeof(packet);
1169 retval = get_packet(packet, len, &len);
1170 if (retval != ZERR_NONE) {
1171 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1180 memset(&out, 0, sizeof(krb5_data));
1181 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1182 if (retval != ZERR_NONE) {
1183 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1186 memcpy(packet, out.data, out.length);
1188 krb5_free_data_contents(Z_krb5_ctx, &out);
1192 retval = ZParseNotice(packet, len, ¬ice);
1193 if (retval != ZERR_NONE) {
1194 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1199 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1200 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1201 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1202 notice.z_recipient);
1205 if (notice.z_num_other_fields >= 1) {
1206 retval = ZReadAscii(notice.z_other_fields[0],
1207 strlen(notice.z_other_fields[0]),
1208 (unsigned char *) &who.sin_addr,
1209 sizeof(struct in_addr));
1210 if (retval != ZERR_NONE) {
1211 syslog(LOG_ERR, "brl zreadascii failed: %s",
1212 error_message(retval));
1216 who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
1218 who.sin_family = AF_INET;
1219 who.sin_port = notice.z_port;
1221 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1222 /* end of brain dump */
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);
1228 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
1231 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1232 /* 1 = tell it we are authentic */
1233 retval = ulogin_dispatch(¬ice, 1, &who, server);
1234 if (retval != ZERR_NONE) {
1235 syslog(LOG_ERR, "brl ul_disp failed: %s",
1236 error_message(retval));
1239 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1241 notice.z_port = htons((u_short) atoi(notice.z_message));
1242 retval = client_register(¬ice, &who.sin_addr, &client, 0);
1243 if (retval != ZERR_NONE) {
1244 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
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;
1253 /* ****ing netascii; this is an encrypted DES keyblock
1254 XXX this code should be conditionalized for server
1256 retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1258 &client->session_keyblock);
1260 syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1261 error_message(retval));
1264 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1265 if (retval != ZERR_NONE) {
1266 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1267 error_message(retval), cp);
1269 des_ecb_encrypt(cblock, Z_keydata(client->session_keyblock),
1270 serv_ksched.s, DES_DECRYPT);
1272 } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
1273 retval = ZReadZcode(cp, buf, sizeof(buf), &blen);
1274 if (retval != ZERR_NONE) {
1275 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1276 error_message(retval), cp);
1278 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1279 ntohl(*(krb5_enctype *)&buf[0]),
1280 ntohl(*(u_int32_t *)&buf[4]),
1281 &client->session_keyblock);
1283 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1284 error_message(retval));
1287 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1288 Z_keylen(client->session_keyblock));
1294 memset(client->session_key, 0, sizeof(C_Block));
1295 if (*notice.z_class_inst) {
1296 /* a C_Block is there */
1297 cp = notice.z_message + strlen(notice.z_message) + 1;
1298 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1299 if (retval != ZERR_NONE) {
1300 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1301 error_message(retval), cp);
1304 memcpy(cblock, client->session_key, sizeof(C_Block));
1306 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1311 #endif /* HAVE_KRB4 */
1313 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1314 /* a subscription packet */
1316 syslog(LOG_ERR, "brl no client");
1319 retval = subscr_subscribe(client, ¬ice, server);
1320 if (retval != ZERR_NONE) {
1321 syslog(LOG_WARNING, "brl subscr failed: %s",
1322 error_message(retval));
1325 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1326 /* add a subscription for a realm */
1328 retval = subscr_realm(realm, ¬ice);
1329 if (retval != ZERR_NONE) {
1330 syslog(LOG_WARNING, "brl subscr failed: %s",
1331 error_message(retval));
1335 /* Other side tried to send us subs for a realm we didn't
1336 know about, and so we drop them silently */
1339 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1340 return ZSRV_UNKNOWNOPCODE;
1346 * Send all the state to the peer.
1350 bdump_send_loop(server)
1356 zdbug((LOG_DEBUG, "bdump send loop"));
1359 retval = uloc_send_locations();
1360 if (retval != ZERR_NONE)
1362 retval = client_send_clients();
1363 if (retval != ZERR_NONE)
1365 retval = realm_send_realms();
1366 if (retval != ZERR_NONE)
1372 * Send a sync indicating end of this host
1381 zdbug((LOG_DEBUG, "send_done"));
1383 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1384 "", ADMIN_DONE, myname, "", NULL, 0);
1390 * Send a list off as the specified notice
1394 send_list(kind, port, class_name, inst, opcode, sender, recip, lyst, num)
1395 ZNotice_Kind_t kind;
1397 char *class_name, *inst, *opcode, *sender, *recip, **lyst;
1404 memset (¬ice, 0, sizeof(notice));
1406 notice.z_kind = kind;
1407 notice.z_port = port;
1408 notice.z_class = class_name;
1409 notice.z_class_inst = inst;
1410 notice.z_opcode = opcode;
1411 notice.z_sender = sender;
1412 notice.z_recipient = recip;
1413 notice.z_default_format = "";
1414 notice.z_num_other_fields = 0;
1416 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1417 if (retval != ZERR_NONE) {
1418 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1422 retval = ZSendPacket(pack, packlen, 0);
1423 if (retval != ZERR_NONE)
1424 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1430 * Send a message off as the specified notice, via TCP
1434 send_normal_tcp(kind, port, class_name, inst, opcode, sender, recip,
1436 ZNotice_Kind_t kind;
1438 char *class_name, *inst, *opcode, *sender, *recip, *message;
1446 memset (¬ice, 0, sizeof(notice));
1448 notice.z_kind = kind;
1449 notice.z_port = port;
1450 notice.z_class = class_name;
1451 notice.z_class_inst = inst;
1452 notice.z_opcode = opcode;
1453 notice.z_sender = sender;
1454 notice.z_recipient = recip;
1455 notice.z_default_format = "";
1456 notice.z_message = message;
1457 notice.z_message_len = len;
1458 notice.z_num_other_fields = 0;
1460 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1461 if (retval != ZERR_NONE) {
1462 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1468 krb5_data indata, outmsg;
1469 indata.length=packlen;
1471 memset(&outmsg, 0, sizeof(krb5_data));
1472 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1473 if (retval != ZERR_NONE)
1475 if (outmsg.length > Z_MAXPKTLEN) {
1476 syslog(LOG_ERR, "sn: encrypted packet is too large");
1479 packlen = outmsg.length;
1481 pack=malloc(packlen);
1484 memcpy(pack, outmsg.data, packlen);
1485 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1489 length = htons((u_short) packlen);
1491 count = net_write(output, (char *) &length, sizeof(length));
1492 if (count != sizeof(length)) {
1494 syslog(LOG_WARNING, "snt xmit/len: %m");
1498 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1503 count = net_write(output, pack, packlen);
1504 if (count != packlen) {
1506 syslog(LOG_WARNING, "snt xmit: %m");
1510 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1520 * get a packet from the TCP socket
1521 * return 0 if successful, error code else
1525 get_packet(packet, len, retlen)
1533 result = net_read(input, (char *) &length, sizeof(u_short));
1534 if (result < sizeof(short)) {
1538 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1544 length = ntohs(length);
1546 return ZSRV_BUFSHORT;
1547 result = net_read(input, packet, (int) length);
1548 if (result < length) {
1552 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1561 extract_sin(notice, target)
1563 struct sockaddr_in *target;
1565 char *cp = notice->z_message;
1569 if (!notice->z_message_len || *buf == '\0') {
1571 zdbug((LOG_DEBUG,"no addr"));
1573 return ZSRV_PKSHORT;
1575 target->sin_addr.s_addr = inet_addr(cp);
1577 cp += (strlen(cp) + 1); /* past the null */
1578 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1580 zdbug((LOG_DEBUG, "no port"));
1582 return(ZSRV_PKSHORT);
1584 target->sin_port = htons((u_short) atoi(cp));
1585 target->sin_family = AF_INET;
1590 net_read(f, buf, len)
1600 cc = fread(buf, 1, len, f);
1617 net_write(f, buf, len)
1625 cc = fwrite (buf, 1, wrlen, f);
1630 } while (wrlen > 0);
1635 setup_file_pointers ()
1639 input = fdopen (live_socket, "r");
1643 fd = dup (live_socket);
1646 output = fdopen (fd, "w");