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(void* arg);
85 static Code_t bdump_send_loop(Server *server);
86 static Code_t bdump_recv_loop(Server *server);
87 static void bdump_get_v12(ZNotice_t *, int, struct sockaddr_in *,
89 static Code_t get_packet(void *packet, int len, int *retlen);
90 static Code_t extract_sin(ZNotice_t *notice, struct sockaddr_in *target);
91 static Code_t send_done(void);
92 static Code_t send_list(ZNotice_Kind_t kind, int port, char *class_name,
93 char *inst, char *opcode, char *sender,
94 char *recip, char **lyst, int num);
95 static Code_t send_normal_tcp(ZNotice_Kind_t kind, int port,
97 char *inst, char *opcode, char *sender,
98 char *recip, char *message, int len);
99 static int net_read(FILE *f, char *buf, int len);
100 static int net_write(FILE *f, char *buf, int len);
101 static int setup_file_pointers(void);
102 static void shutdown_file_pointers(void);
103 static void cleanup(Server *server);
106 static long ticket5_time;
107 #define TKT5LIFETIME 8*60*60
108 #define tkt5_lifetime(val) (val)
112 static long ticket_time;
114 #define TKTLIFETIME 120
115 #define tkt_lifetime(val) ((long) val * 5L * 60L)
117 extern C_Block serv_key;
118 extern Sched serv_ksched;
119 #endif /* HAVE_KRB4 */
121 static Timer *bdump_timer;
122 static int live_socket = -1;
123 static FILE *input, *output;
124 static struct sockaddr_in bdump_sin;
126 static krb5_auth_context bdump_ac;
129 static int cancel_outgoing_dump;
133 int bdump_concurrent;
134 extern char *bdump_version;
135 extern int bdump_auth_proto;
138 * Functions for performing a brain dump between servers.
142 * offer the brain dump to another server
146 bdump_offer(struct sockaddr_in *who)
149 char buf[512], *addr, *lyst[2];
151 int bdump_port = IPPORT_RESERVED - 1;
152 #endif /* !HAVE_KRB4 */
154 zdbug((LOG_DEBUG, "bdump_offer"));
156 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
158 * when using kerberos server-server authentication, we can
159 * use any random local address
161 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
162 if (bdump_socket < 0) {
163 syslog(LOG_ERR,"bdump_offer: socket: %m");
167 memset(&bdump_sin, 0, sizeof(bdump_sin));
168 /* a port field of 0 makes the UNIX
169 * kernel choose an appropriate port/address pair */
171 bdump_sin.sin_port = 0;
172 bdump_sin.sin_addr = my_addr;
173 bdump_sin.sin_family = AF_INET;
174 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
177 syslog(LOG_ERR, "bdump_offer: bind: %m");
182 if (!bdump_sin.sin_port) {
183 unsigned int len = sizeof(bdump_sin);
185 if (getsockname(bdump_socket,
186 (struct sockaddr *) &bdump_sin, &len) < 0) {
187 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
193 #else /* !HAVE_KRB4 */
195 * when not using HAVE_KRB4, we can't use any old port, we use
196 * Internet reserved ports instead (rresvport)
198 bdump_socket = rresvport(&bdump_port);
199 if (bdump_socket < 0) {
200 syslog(LOG_ERR,"bdump_offer: socket: %m");
204 memset(&bdump_sin, 0, sizeof(bdump_sin));
205 bdump_sin.sin_port = htons((unsigned short) bdump_port);
206 bdump_sin.sin_addr = my_addr;
207 bdump_sin.sin_family = AF_INET;
208 #endif /* HAVE_KRB4 */
210 listen(bdump_socket, 1);
212 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
213 FD_SET(bdump_socket, &interesting);
214 nfds = max(bdump_socket, srv_socket) + 1;
216 addr = inet_ntoa(bdump_sin.sin_addr);
217 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
221 retval = ZSetDestAddr(who);
222 if (retval != ZERR_NONE) {
223 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
224 error_message(retval));
228 /* myname is the hostname */
229 /* the class instance is the version number, here it is */
230 /* bdump_version, which is set in main */
231 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
232 ADMIN_BDUMP, myname, "", lyst, 2);
234 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
235 inet_ntoa(bdump_sin.sin_addr),
236 ntohs(bdump_sin.sin_port)));
241 * Accept a connection, and send the brain dump to the other server
247 struct sockaddr_in from;
250 unsigned int fromlen = sizeof(from);
252 #ifdef _POSIX_VERSION
253 struct sigaction action;
255 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
263 /* may be moved into kstuff.c */
264 char instance [INST_SZ];
267 /* may be moved into kstuff.c */
268 krb5_principal principal;
272 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
273 unsigned short fromport;
274 #endif /* HAVE_KRB4 */
276 zdbug((LOG_DEBUG, "bdump_send"));
278 /* accept the connection, and send the brain dump */
279 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
280 if (live_socket < 0) {
281 syslog(LOG_ERR,"bdump_send: accept: %m");
284 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
286 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
289 fromport = ntohs(from.sin_port);
292 #ifdef _POSIX_VERSION
293 sigemptyset(&action.sa_mask);
295 action.sa_handler = SIG_IGN;
296 sigaction(SIGPIPE, &action, NULL);
299 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
302 from.sin_port = srv_addr.sin_port; /* we don't care what port
303 * it came from, and we need to
304 * fake out server_which_server() */
305 server = server_which_server(&from);
307 syslog(LOG_ERR, "bdump_send: unknown server?");
308 server = limbo_server;
311 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
312 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
317 if (bdump_socket >= 0) {
318 /* shut down the listening socket and the timer. */
319 FD_CLR(bdump_socket, &interesting);
321 nfds = srv_socket + 1;
323 timer_reset(bdump_timer);
326 /* Now begin the brain dump. */
327 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
328 retval = ReadKerberosData(live_socket, &len, &data, &proto);
331 syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
332 krb_get_err_text(retval));
337 syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
340 syslog(LOG_ERR, "bdump_send: get_tgt failed");
349 retval = krb5_build_principal(Z_krb5_ctx, &principal,
352 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
355 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
361 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
363 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
368 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
370 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
375 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
376 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
378 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
383 /* Get the "client" krb_ap_req */
385 memset((char *)&k5data, 0, sizeof(krb5_data));
389 syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
390 error_message(retval));
396 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
398 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
399 error_message(retval));
400 krb5_kt_close(Z_krb5_ctx, kt);
405 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
406 krb5_free_principal(Z_krb5_ctx, principal);
407 krb5_kt_close(Z_krb5_ctx, kt);
409 memset((char *)&k5data, 0, sizeof(krb5_data));
411 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
412 error_message(retval));
417 /* Now send back our auth packet */
419 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
421 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
425 retval = SendKrb5Data(live_socket, &k5data);
427 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
428 error_message(retval));
429 krb5_free_data_contents(Z_krb5_ctx, &k5data);
433 krb5_free_data_contents(Z_krb5_ctx, &k5data);
435 #endif /* HAVE_KRB5 */
438 /* here to krb_rd_req from GetKerberosData candidate for refactoring
439 back into kstuff.c */
440 (void) strcpy(instance, "*"); /* let Kerberos fill it in */
443 memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
444 retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
445 from.sin_addr.s_addr, &kdata, srvtab_file);
447 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
448 SERVER_SERVICE, srvtab_file);
450 if (retval != KSUCCESS) {
451 syslog(LOG_ERR, "bdump_send: getkdata: %s",
452 krb_get_err_text(retval));
456 if (strcmp(kdata.pname, SERVER_SERVICE) ||
457 strcmp(kdata.pinst, SERVER_INSTANCE) ||
458 strcmp(kdata.prealm, ZGetRealm())) {
459 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
460 kdata.pname, kdata.pinst, kdata.prealm);
464 /* authenticate back */
465 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
468 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
469 error_message (retval));
474 #endif /* HAVE_KRB4 */
476 #else /* HAVE_KRB4 || HAVE_KRB5 */
477 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
478 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
482 #endif /* HAVE_KRB4 || HAVE_KRB5 */
483 retval = setup_file_pointers();
485 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
486 error_message(retval));
490 retval = bdump_send_loop(server);
491 if (retval != ZERR_NONE) {
492 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
493 error_message(retval));
497 retval = bdump_recv_loop(server);
498 if (retval != ZERR_NONE) {
499 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
500 error_message(retval));
505 zdbug((LOG_DEBUG, "bdump_send: finished"));
507 if (server != limbo_server) {
508 /* set this guy to be up, and schedule a hello */
509 server->state = SERV_UP;
510 timer_reset(server->timer);
511 server->timer = timer_set_rel(0L, server_timo, server);
514 shutdown_file_pointers();
516 #ifdef _POSIX_VERSION
517 action.sa_handler = SIG_DFL;
518 sigaction(SIGPIPE, &action, NULL);
520 signal(SIGPIPE, SIG_DFL);
524 /* Now that we are finished dumping, send all the queued packets */
525 server_send_queue(server);
531 bdump_get_v12 (ZNotice_t *notice,
533 struct sockaddr_in *who,
536 struct sockaddr_in from;
539 #ifdef _POSIX_VERSION
540 struct sigaction action;
542 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
546 krb5_principal principal;
548 krb5_ap_rep_enc_part *rep;
554 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
555 int reserved_port = IPPORT_RESERVED - 1;
556 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
561 #ifdef _POSIX_VERSION
563 sigemptyset(&action.sa_mask);
564 action.sa_handler = SIG_IGN;
565 sigaction(SIGPIPE, &action, NULL);
567 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
568 #endif /* _POSIX_VRESION */
570 if (bdump_socket >= 0) {
571 /* We cannot go get a brain dump when someone may
572 potentially be connecting to us (if that other
573 server is the server to whom we are connecting,
574 we will deadlock. so we shut down the listening
575 socket and the timer. */
576 FD_CLR(bdump_socket, &interesting);
580 timer_reset(bdump_timer);
583 retval = extract_sin(notice, &from);
584 if (retval != ZERR_NONE) {
585 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
586 #ifdef _POSIX_VERSION
587 action.sa_handler = SIG_DFL;
588 sigaction(SIGPIPE, &action, NULL);
590 signal(SIGPIPE, SIG_DFL);
596 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
597 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
598 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
599 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
600 ntohs(from.sin_port));
604 live_socket = rresvport(&reserved_port);
605 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
606 live_socket = socket(AF_INET, SOCK_STREAM, 0);
607 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
608 if (live_socket < 0) {
609 syslog(LOG_ERR, "bdump_get: socket: %m");
613 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
614 syslog(LOG_ERR, "bdump_get: connect: %m");
618 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
620 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
622 zdbug((LOG_DEBUG, "bdump_get: connected"));
624 /* Now begin the brain dump. */
625 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
627 syslog(LOG_ERR, "bdump_get: get_tgt failed");
631 switch(bdump_auth_proto) {
633 case 5: /* "client" side */
634 memset((char *)&creds, 0, sizeof(creds));
636 retval = krb5_build_principal(Z_krb5_ctx, &principal,
639 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
642 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
647 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
649 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
650 krb5_free_principal(Z_krb5_ctx, principal);
655 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
656 krb5_free_principal(Z_krb5_ctx, principal);
658 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
659 krb5_free_cred_contents(Z_krb5_ctx, &creds);
664 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
666 krb5_free_cred_contents(Z_krb5_ctx, &creds);
668 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
673 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
675 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
676 krb5_free_creds(Z_krb5_ctx, credsp);
681 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
683 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
684 krb5_free_creds(Z_krb5_ctx, credsp);
689 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
690 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
692 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
693 krb5_free_creds(Z_krb5_ctx, credsp);
698 memset((char *)&data, 0, sizeof(krb5_data));
699 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
700 NULL, credsp, &data);
702 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
703 krb5_free_creds(Z_krb5_ctx, credsp);
707 retval = SendKrb5Data(live_socket, &data);
708 krb5_free_creds(Z_krb5_ctx, credsp);
710 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
711 error_message(retval));
712 krb5_free_data_contents(Z_krb5_ctx, &data);
716 krb5_free_data_contents(Z_krb5_ctx, &data);
717 memset((char *)&data, 0, sizeof(krb5_data));
718 retval = GetKrb5Data(live_socket, &data);
720 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
721 error_message(retval));
725 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
727 memset((char *)&data, 0, sizeof(krb5_data));
729 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
730 error_message(retval));
738 /* send an authenticator */
739 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
742 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
746 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
748 /* get his authenticator */
749 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
750 SERVER_SERVICE, srvtab_file);
751 if (retval != KSUCCESS) {
752 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
757 if (strcmp(kdata.pname, SERVER_SERVICE) ||
758 strcmp(kdata.pinst, SERVER_INSTANCE) ||
759 strcmp(kdata.prealm, ZGetRealm())) {
760 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
761 kdata.pname, kdata.pinst,kdata.prealm);
766 #endif /* HAVE_KRB4 */
768 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
769 retval = setup_file_pointers();
771 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
772 error_message (retval));
776 retval = bdump_recv_loop(server);
777 if (retval != ZERR_NONE) {
778 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
779 error_message(retval));
783 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
784 retval = bdump_send_loop(server);
785 if (retval != ZERR_NONE) {
786 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
787 error_message(retval));
792 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
794 /* set this guy to be up, and schedule a hello */
795 server->state = SERV_UP;
796 timer_reset(server->timer);
797 server->timer = timer_set_rel(0L, server_timo, server);
800 zdbug((LOG_DEBUG,"cleanup gbd"));
802 shutdown_file_pointers();
803 #ifdef _POSIX_VERSION
804 action.sa_handler = SIG_DFL;
805 sigaction(SIGPIPE, &action, NULL);
807 signal(SIGPIPE, SIG_DFL);
811 /* Now that we are finished dumping, send all the queued packets */
812 server_send_queue(server);
818 bdump_get(ZNotice_t *notice,
820 struct sockaddr_in *who,
823 void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *);
828 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
829 notice->z_class_inst, inet_ntoa(who->sin_addr));
832 if (strcmp (notice->z_class_inst, "1.2") == 0)
833 proc = bdump_get_v12;
836 (*proc)(notice, auth, who, server);
839 "bdump_get: Incompatible bdump version '%s' from %s",
840 notice->z_class_inst,
841 inet_ntoa(who->sin_addr));
846 * Send a list off as the specified notice
850 bdump_send_list_tcp(ZNotice_Kind_t kind,
851 struct sockaddr_in *addr,
861 char *pack, addrbuf[100];
866 memset (¬ice, 0, sizeof(notice));
868 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
869 (unsigned char *) &addr->sin_addr,
870 sizeof(struct in_addr));
871 if (retval != ZERR_NONE)
873 notice.z_kind = kind;
875 notice.z_port = addr->sin_port;
876 notice.z_class = class_name;
877 notice.z_class_inst = inst;
878 notice.z_opcode = opcode;
879 notice.z_sender = sender;
880 notice.z_recipient = recip;
881 notice.z_default_format = "";
882 notice.z_num_other_fields = 1;
883 notice.z_other_fields[0] = addrbuf;
885 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
886 if (retval != ZERR_NONE)
891 krb5_data indata, outmsg;
892 indata.length=packlen;
894 memset(&outmsg, 0, sizeof(krb5_data));
895 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
896 if (retval != ZERR_NONE)
898 if (outmsg.length > Z_MAXPKTLEN) {
899 syslog(LOG_ERR, "bsl: encrypted packet is too large");
902 packlen = outmsg.length;
904 pack=malloc(packlen);
907 memcpy(pack, outmsg.data, packlen);
908 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
912 length = htons((u_short) packlen);
914 count = net_write(output, (char *) &length, sizeof(length));
915 if (count != sizeof(length)) {
920 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
921 sizeof(length), count);
923 return(ZSRV_PKSHORT);
927 count = net_write(output, pack, packlen);
928 if (count != packlen) {
933 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
936 return(ZSRV_PKSHORT);
944 shutdown_file_pointers(void)
954 if (live_socket >= 0) {
959 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
966 cleanup(Server *server)
968 #ifdef _POSIX_VERSION
969 struct sigaction action;
972 zdbug((LOG_DEBUG, "bdump cleanup"));
974 if (server != limbo_server) {
975 server->state = SERV_DEAD;
976 timer_reset(server->timer);
977 server->timer = timer_set_rel(0L, server_timo, server);
979 shutdown_file_pointers ();
980 #ifdef _POSIX_VERSION
982 sigemptyset(&action.sa_mask);
983 action.sa_handler = SIG_DFL;
984 sigaction(SIGPIPE,&action, NULL);
986 signal(SIGPIPE, SIG_DFL);
987 #endif /* _POSIX_VERSION */
996 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
997 * at least INST_SZ bytes long. */
998 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
1001 /* have they expired ? */
1002 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1003 /* +15 for leeway */
1005 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1006 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1010 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
1011 "krbtgt", ZGetRealm(),
1012 TKTLIFETIME, srvtab_file);
1013 if (retval != KSUCCESS) {
1014 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1015 krb_get_err_text(retval));
1022 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1023 ZGetRealm(), 0 /*kvno*/,
1024 srvtab_file, (char *)serv_key);
1025 if (retval != KSUCCESS) {
1026 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1027 krb_get_err_text(retval));
1030 des_key_sched(serv_key, serv_ksched.s);
1034 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1036 krb5_get_init_creds_opt opt;
1038 krb5_principal principal;
1040 memset(&cred, 0, sizeof(cred));
1042 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1043 strlen(ZGetRealm()),
1045 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1048 krb5_free_principal(Z_krb5_ctx, principal);
1052 krb5_get_init_creds_opt_init (&opt);
1053 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1055 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1056 if (retval) return(1);
1058 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1065 krb5_free_principal(Z_krb5_ctx, principal);
1066 krb5_kt_close(Z_krb5_ctx, kt);
1067 if (retval) return(1);
1069 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1070 if (retval) return(1);
1072 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1073 if (retval) return(1);
1077 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1082 #endif /* HAVE_KRB4 */
1085 * The braindump offer wasn't taken, so we retract it.
1090 close_bdump(void *arg)
1092 if (bdump_socket >= 0) {
1093 FD_CLR(bdump_socket, &interesting);
1094 close(bdump_socket);
1095 nfds = srv_socket + 1;
1098 zdbug((LOG_DEBUG, "bdump not used"));
1100 zdbug((LOG_DEBUG, "bdump not open"));
1106 * Start receiving instruction notices from the brain dump socket
1110 bdump_recv_loop(Server *server)
1116 Client *client = NULL;
1117 struct sockaddr_in who;
1119 unsigned char buf[512];
1122 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1127 #endif /* HAVE_KRB4 */
1128 ZRealm *realm = NULL;
1130 zdbug((LOG_DEBUG, "bdump recv loop"));
1132 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1134 if (packets_waiting()) {
1135 /* A non-braindump packet is waiting; handle it. */
1137 bdump_concurrent = 1;
1139 bdump_concurrent = 0;
1142 len = sizeof(packet);
1143 retval = get_packet(packet, len, &len);
1144 if (retval != ZERR_NONE) {
1145 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1154 memset(&out, 0, sizeof(krb5_data));
1155 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1156 if (retval != ZERR_NONE) {
1157 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1160 memcpy(packet, out.data, out.length);
1162 krb5_free_data_contents(Z_krb5_ctx, &out);
1166 retval = ZParseNotice(packet, len, ¬ice);
1167 if (retval != ZERR_NONE) {
1168 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1173 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1174 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1175 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1176 notice.z_recipient);
1179 if (notice.z_num_other_fields >= 1) {
1180 retval = ZReadAscii(notice.z_other_fields[0],
1181 strlen(notice.z_other_fields[0]),
1182 (unsigned char *) &who.sin_addr,
1183 sizeof(struct in_addr));
1184 if (retval != ZERR_NONE) {
1185 syslog(LOG_ERR, "brl zreadascii failed: %s",
1186 error_message(retval));
1190 who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
1192 who.sin_family = AF_INET;
1193 who.sin_port = notice.z_port;
1195 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1196 /* end of brain dump */
1198 } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
1199 /* get a realm from the message */
1200 realm = realm_get_realm_by_name(notice.z_message);
1202 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
1205 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1206 /* 1 = tell it we are authentic */
1207 retval = ulogin_dispatch(¬ice, 1, &who, server);
1208 if (retval != ZERR_NONE) {
1209 syslog(LOG_ERR, "brl ul_disp failed: %s",
1210 error_message(retval));
1213 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1215 notice.z_port = htons((u_short) atoi(notice.z_message));
1216 retval = client_register(¬ice, &who.sin_addr, &client, 0);
1217 if (retval != ZERR_NONE) {
1218 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
1222 client->session_keyblock = NULL;
1223 if (*notice.z_class_inst) {
1224 /* check out this session key I found */
1225 cp = notice.z_message + strlen(notice.z_message) + 1;
1227 /* ****ing netascii; this is an encrypted DES keyblock
1228 XXX this code should be conditionalized for server
1230 retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1232 &client->session_keyblock);
1234 syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1235 error_message(retval));
1238 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1239 if (retval != ZERR_NONE) {
1240 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1241 error_message(retval), cp);
1243 des_ecb_encrypt((C_Block *)cblock, (C_Block *)Z_keydata(client->session_keyblock),
1244 serv_ksched.s, DES_DECRYPT);
1246 } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
1247 retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen);
1248 if (retval != ZERR_NONE) {
1249 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1250 error_message(retval), cp);
1252 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1253 ntohl(*(krb5_enctype *)&buf[0]),
1254 ntohl(*(u_int32_t *)&buf[4]),
1255 &client->session_keyblock);
1257 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1258 error_message(retval));
1261 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1262 Z_keylen(client->session_keyblock));
1268 memset(client->session_key, 0, sizeof(C_Block));
1269 if (*notice.z_class_inst) {
1270 /* a C_Block is there */
1271 cp = notice.z_message + strlen(notice.z_message) + 1;
1272 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1273 if (retval != ZERR_NONE) {
1274 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1275 error_message(retval), cp);
1277 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1281 #endif /* HAVE_KRB4 */
1283 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1284 /* a subscription packet */
1286 syslog(LOG_ERR, "brl no client");
1289 retval = subscr_subscribe(client, ¬ice, server);
1290 if (retval != ZERR_NONE) {
1291 syslog(LOG_WARNING, "brl subscr failed: %s",
1292 error_message(retval));
1295 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1296 /* add a subscription for a realm */
1298 retval = subscr_realm(realm, ¬ice);
1299 if (retval != ZERR_NONE) {
1300 syslog(LOG_WARNING, "brl subscr failed: %s",
1301 error_message(retval));
1305 /* Other side tried to send us subs for a realm we didn't
1306 know about, and so we drop them silently */
1309 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1310 return ZSRV_UNKNOWNOPCODE;
1316 * Send all the state to the peer.
1320 bdump_send_loop(Server *server)
1324 zdbug((LOG_DEBUG, "bdump send loop"));
1326 retval = uloc_send_locations();
1327 if (retval != ZERR_NONE)
1329 retval = client_send_clients();
1330 if (retval != ZERR_NONE)
1332 retval = realm_send_realms();
1333 if (retval != ZERR_NONE)
1339 * Send a sync indicating end of this host
1347 zdbug((LOG_DEBUG, "send_done"));
1349 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1350 "", ADMIN_DONE, myname, "", NULL, 0);
1356 * Send a list off as the specified notice
1360 send_list(ZNotice_Kind_t kind,
1375 memset (¬ice, 0, sizeof(notice));
1377 notice.z_kind = kind;
1378 notice.z_port = port;
1379 notice.z_class = class_name;
1380 notice.z_class_inst = inst;
1381 notice.z_opcode = opcode;
1382 notice.z_sender = sender;
1383 notice.z_recipient = recip;
1384 notice.z_default_format = "";
1385 notice.z_num_other_fields = 0;
1387 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1388 if (retval != ZERR_NONE) {
1389 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1393 retval = ZSendPacket(pack, packlen, 0);
1394 if (retval != ZERR_NONE)
1395 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1401 * Send a message off as the specified notice, via TCP
1405 send_normal_tcp(ZNotice_Kind_t kind,
1421 memset (¬ice, 0, sizeof(notice));
1423 notice.z_kind = kind;
1424 notice.z_port = port;
1425 notice.z_class = class_name;
1426 notice.z_class_inst = inst;
1427 notice.z_opcode = opcode;
1428 notice.z_sender = sender;
1429 notice.z_recipient = recip;
1430 notice.z_default_format = "";
1431 notice.z_message = message;
1432 notice.z_message_len = len;
1433 notice.z_num_other_fields = 0;
1435 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1436 if (retval != ZERR_NONE) {
1437 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1443 krb5_data indata, outmsg;
1444 indata.length=packlen;
1446 memset(&outmsg, 0, sizeof(krb5_data));
1447 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1448 if (retval != ZERR_NONE)
1450 if (outmsg.length > Z_MAXPKTLEN) {
1451 syslog(LOG_ERR, "sn: encrypted packet is too large");
1454 packlen = outmsg.length;
1456 pack=malloc(packlen);
1459 memcpy(pack, outmsg.data, packlen);
1460 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1464 length = htons((u_short) packlen);
1466 count = net_write(output, (char *) &length, sizeof(length));
1467 if (count != sizeof(length)) {
1469 syslog(LOG_WARNING, "snt xmit/len: %m");
1473 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1478 count = net_write(output, pack, packlen);
1479 if (count != packlen) {
1481 syslog(LOG_WARNING, "snt xmit: %m");
1485 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1495 * get a packet from the TCP socket
1496 * return 0 if successful, error code else
1500 get_packet(void *packet, int len, int *retlen)
1505 result = net_read(input, (char *) &length, sizeof(u_short));
1506 if (result < sizeof(short)) {
1510 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1516 length = ntohs(length);
1518 return ZSRV_BUFSHORT;
1519 result = net_read(input, packet, (int) length);
1520 if (result < length) {
1524 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1533 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1535 char *cp = notice->z_message;
1539 if (!notice->z_message_len || *buf == '\0') {
1540 return ZSRV_PKSHORT;
1542 target->sin_addr.s_addr = inet_addr(cp);
1544 cp += (strlen(cp) + 1); /* past the null */
1545 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1546 return(ZSRV_PKSHORT);
1548 target->sin_port = htons((u_short) atoi(cp));
1549 target->sin_family = AF_INET;
1554 net_read(FILE *f, char *buf, int len)
1561 cc = fread(buf, 1, len, f);
1578 net_write(FILE *f, char *buf, int len)
1583 cc = fwrite (buf, 1, wrlen, f);
1588 } while (wrlen > 0);
1593 setup_file_pointers (void)
1597 input = fdopen (live_socket, "r");
1601 fd = dup (live_socket);
1604 output = fdopen (fd, "w");