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);
235 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
236 inet_ntoa(bdump_sin.sin_addr),
237 ntohs(bdump_sin.sin_port)));
243 * Accept a connection, and send the brain dump to the other server
249 struct sockaddr_in from;
252 unsigned int fromlen = sizeof(from);
254 #ifdef _POSIX_VERSION
255 struct sigaction action;
257 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
265 /* may be moved into kstuff.c */
266 char instance [INST_SZ];
269 /* may be moved into kstuff.c */
270 krb5_principal principal;
274 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
275 unsigned short fromport;
276 #endif /* HAVE_KRB4 */
279 zdbug((LOG_DEBUG, "bdump_send"));
281 /* accept the connection, and send the brain dump */
282 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
283 if (live_socket < 0) {
284 syslog(LOG_ERR,"bdump_send: accept: %m");
287 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
289 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
292 fromport = ntohs(from.sin_port);
295 #ifdef _POSIX_VERSION
296 sigemptyset(&action.sa_mask);
298 action.sa_handler = SIG_IGN;
299 sigaction(SIGPIPE, &action, NULL);
302 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
305 from.sin_port = srv_addr.sin_port; /* we don't care what port
306 * it came from, and we need to
307 * fake out server_which_server() */
308 server = server_which_server(&from);
310 syslog(LOG_ERR, "bdump_send: unknown server?");
311 server = limbo_server;
314 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
315 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
321 if (bdump_socket >= 0) {
322 /* shut down the listening socket and the timer. */
323 FD_CLR(bdump_socket, &interesting);
325 nfds = srv_socket + 1;
327 timer_reset(bdump_timer);
330 /* Now begin the brain dump. */
331 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
332 retval = ReadKerberosData(live_socket, &len, &data, &proto);
335 syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
336 krb_get_err_text(retval));
341 syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
344 syslog(LOG_ERR, "bdump_send: get_tgt failed");
353 retval = krb5_build_principal(Z_krb5_ctx, &principal,
356 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
359 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
365 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
367 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
372 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
374 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
379 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
380 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
382 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
387 /* Get the "client" krb_ap_req */
389 memset((char *)&k5data, 0, sizeof(krb5_data));
393 syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
394 error_message(retval));
400 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
402 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
403 error_message(retval));
404 krb5_kt_close(Z_krb5_ctx, kt);
409 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
410 krb5_free_principal(Z_krb5_ctx, principal);
411 krb5_kt_close(Z_krb5_ctx, kt);
413 memset((char *)&k5data, 0, sizeof(krb5_data));
415 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
416 error_message(retval));
421 /* Now send back our auth packet */
423 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
425 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
429 retval = SendKrb5Data(live_socket, &k5data);
431 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
432 error_message(retval));
433 krb5_free_data_contents(Z_krb5_ctx, &k5data);
437 krb5_free_data_contents(Z_krb5_ctx, &k5data);
439 #endif /* HAVE_KRB5 */
442 /* here to krb_rd_req from GetKerberosData candidate for refactoring
443 back into kstuff.c */
444 (void) strcpy(instance, "*"); /* let Kerberos fill it in */
447 memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
448 retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
449 from.sin_addr.s_addr, &kdata, srvtab_file);
451 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
452 SERVER_SERVICE, srvtab_file);
454 if (retval != KSUCCESS) {
455 syslog(LOG_ERR, "bdump_send: getkdata: %s",
456 krb_get_err_text(retval));
460 if (strcmp(kdata.pname, SERVER_SERVICE) ||
461 strcmp(kdata.pinst, SERVER_INSTANCE) ||
462 strcmp(kdata.prealm, ZGetRealm())) {
463 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
464 kdata.pname, kdata.pinst, kdata.prealm);
468 /* authenticate back */
469 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
472 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
473 error_message (retval));
478 #endif /* HAVE_KRB4 */
480 #else /* HAVE_KRB4 || HAVE_KRB5 */
481 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
482 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
486 #endif /* HAVE_KRB4 || HAVE_KRB5 */
487 retval = setup_file_pointers();
489 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
490 error_message(retval));
494 retval = bdump_send_loop(server);
495 if (retval != ZERR_NONE) {
496 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
497 error_message(retval));
501 retval = bdump_recv_loop(server);
502 if (retval != ZERR_NONE) {
503 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
504 error_message(retval));
509 zdbug((LOG_DEBUG, "bdump_send: finished"));
511 if (server != limbo_server) {
512 /* set this guy to be up, and schedule a hello */
513 server->state = SERV_UP;
514 timer_reset(server->timer);
515 server->timer = timer_set_rel(0L, server_timo, server);
518 zdbug((LOG_DEBUG,"cleanup sbd"));
520 shutdown_file_pointers();
522 #ifdef _POSIX_VERSION
523 action.sa_handler = SIG_DFL;
524 sigaction(SIGPIPE, &action, NULL);
526 signal(SIGPIPE, SIG_DFL);
530 /* Now that we are finished dumping, send all the queued packets */
531 server_send_queue(server);
537 bdump_get_v12 (ZNotice_t *notice,
539 struct sockaddr_in *who,
542 struct sockaddr_in from;
545 #ifdef _POSIX_VERSION
546 struct sigaction action;
548 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
552 krb5_principal principal;
554 krb5_ap_rep_enc_part *rep;
560 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
561 int reserved_port = IPPORT_RESERVED - 1;
562 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
567 #ifdef _POSIX_VERSION
569 sigemptyset(&action.sa_mask);
570 action.sa_handler = SIG_IGN;
571 sigaction(SIGPIPE, &action, NULL);
573 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
574 #endif /* _POSIX_VRESION */
576 if (bdump_socket >= 0) {
577 /* We cannot go get a brain dump when someone may
578 potentially be connecting to us (if that other
579 server is the server to whom we are connecting,
580 we will deadlock. so we shut down the listening
581 socket and the timer. */
582 FD_CLR(bdump_socket, &interesting);
586 timer_reset(bdump_timer);
589 retval = extract_sin(notice, &from);
590 if (retval != ZERR_NONE) {
591 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
592 #ifdef _POSIX_VERSION
593 action.sa_handler = SIG_DFL;
594 sigaction(SIGPIPE, &action, NULL);
596 signal(SIGPIPE, SIG_DFL);
602 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
603 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
604 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
605 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
606 ntohs(from.sin_port));
610 live_socket = rresvport(&reserved_port);
611 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
612 live_socket = socket(AF_INET, SOCK_STREAM, 0);
613 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
614 if (live_socket < 0) {
615 syslog(LOG_ERR, "bdump_get: socket: %m");
619 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
620 syslog(LOG_ERR, "bdump_get: connect: %m");
624 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
626 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
628 zdbug((LOG_DEBUG, "bdump_get: connected"));
631 /* Now begin the brain dump. */
632 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
634 syslog(LOG_ERR, "bdump_get: get_tgt failed");
638 switch(bdump_auth_proto) {
640 case 5: /* "client" side */
641 memset((char *)&creds, 0, sizeof(creds));
643 retval = krb5_build_principal(Z_krb5_ctx, &principal,
646 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
649 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
654 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
656 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
657 krb5_free_principal(Z_krb5_ctx, principal);
662 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
663 krb5_free_principal(Z_krb5_ctx, principal);
665 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
666 krb5_free_cred_contents(Z_krb5_ctx, &creds);
671 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
673 krb5_free_cred_contents(Z_krb5_ctx, &creds);
675 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
680 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
682 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
683 krb5_free_creds(Z_krb5_ctx, credsp);
688 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
690 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
691 krb5_free_creds(Z_krb5_ctx, credsp);
696 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
697 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
699 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
700 krb5_free_creds(Z_krb5_ctx, credsp);
705 memset((char *)&data, 0, sizeof(krb5_data));
706 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
707 NULL, credsp, &data);
709 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
710 krb5_free_creds(Z_krb5_ctx, credsp);
714 retval = SendKrb5Data(live_socket, &data);
715 krb5_free_creds(Z_krb5_ctx, credsp);
717 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
718 error_message(retval));
719 krb5_free_data_contents(Z_krb5_ctx, &data);
723 krb5_free_data_contents(Z_krb5_ctx, &data);
724 memset((char *)&data, 0, sizeof(krb5_data));
725 retval = GetKrb5Data(live_socket, &data);
727 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
728 error_message(retval));
732 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
734 memset((char *)&data, 0, sizeof(krb5_data));
736 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
737 error_message(retval));
745 /* send an authenticator */
746 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
749 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
753 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
755 /* get his authenticator */
756 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
757 SERVER_SERVICE, srvtab_file);
758 if (retval != KSUCCESS) {
759 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
764 if (strcmp(kdata.pname, SERVER_SERVICE) ||
765 strcmp(kdata.pinst, SERVER_INSTANCE) ||
766 strcmp(kdata.prealm, ZGetRealm())) {
767 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
768 kdata.pname, kdata.pinst,kdata.prealm);
773 #endif /* HAVE_KRB4 */
775 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
776 retval = setup_file_pointers();
778 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
779 error_message (retval));
783 retval = bdump_recv_loop(server);
784 if (retval != ZERR_NONE) {
785 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
786 error_message(retval));
790 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
791 retval = bdump_send_loop(server);
792 if (retval != ZERR_NONE) {
793 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
794 error_message(retval));
799 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
801 /* set this guy to be up, and schedule a hello */
802 server->state = SERV_UP;
803 timer_reset(server->timer);
804 server->timer = timer_set_rel(0L, server_timo, server);
807 zdbug((LOG_DEBUG,"cleanup gbd"));
809 shutdown_file_pointers();
810 #ifdef _POSIX_VERSION
811 action.sa_handler = SIG_DFL;
812 sigaction(SIGPIPE, &action, NULL);
814 signal(SIGPIPE, SIG_DFL);
818 /* Now that we are finished dumping, send all the queued packets */
819 server_send_queue(server);
825 bdump_get(ZNotice_t *notice,
827 struct sockaddr_in *who,
830 void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *);
836 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
837 notice->z_class_inst, inet_ntoa(who->sin_addr));
840 if (strcmp (notice->z_class_inst, "1.2") == 0)
841 proc = bdump_get_v12;
844 (*proc)(notice, auth, who, server);
847 "bdump_get: Incompatible bdump version '%s' from %s",
848 notice->z_class_inst,
849 inet_ntoa(who->sin_addr));
854 * Send a list off as the specified notice
858 bdump_send_list_tcp(ZNotice_Kind_t kind,
859 struct sockaddr_in *addr,
869 char *pack, addrbuf[100];
874 memset (¬ice, 0, sizeof(notice));
876 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
877 (unsigned char *) &addr->sin_addr,
878 sizeof(struct in_addr));
879 if (retval != ZERR_NONE)
881 notice.z_kind = kind;
883 notice.z_port = addr->sin_port;
884 notice.z_class = class_name;
885 notice.z_class_inst = inst;
886 notice.z_opcode = opcode;
887 notice.z_sender = sender;
888 notice.z_recipient = recip;
889 notice.z_default_format = "";
890 notice.z_num_other_fields = 1;
891 notice.z_other_fields[0] = addrbuf;
893 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
894 if (retval != ZERR_NONE)
899 krb5_data indata, outmsg;
900 indata.length=packlen;
902 memset(&outmsg, 0, sizeof(krb5_data));
903 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
904 if (retval != ZERR_NONE)
906 if (outmsg.length > Z_MAXPKTLEN) {
907 syslog(LOG_ERR, "bsl: encrypted packet is too large");
910 packlen = outmsg.length;
912 pack=malloc(packlen);
915 memcpy(pack, outmsg.data, packlen);
916 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
920 length = htons((u_short) packlen);
922 count = net_write(output, (char *) &length, sizeof(length));
923 if (count != sizeof(length)) {
928 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
929 sizeof(length), count);
931 return(ZSRV_PKSHORT);
935 count = net_write(output, pack, packlen);
936 if (count != packlen) {
941 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
944 return(ZSRV_PKSHORT);
952 shutdown_file_pointers(void)
962 if (live_socket >= 0) {
967 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
974 cleanup(Server *server)
976 #ifdef _POSIX_VERSION
977 struct sigaction action;
981 zdbug((LOG_DEBUG, "bdump cleanup"));
983 if (server != limbo_server) {
984 server->state = SERV_DEAD;
985 timer_reset(server->timer);
986 server->timer = timer_set_rel(0L, server_timo, server);
988 shutdown_file_pointers ();
989 #ifdef _POSIX_VERSION
991 sigemptyset(&action.sa_mask);
992 action.sa_handler = SIG_DFL;
993 sigaction(SIGPIPE,&action, NULL);
995 signal(SIGPIPE, SIG_DFL);
996 #endif /* _POSIX_VERSION */
1005 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
1006 * at least INST_SZ bytes long. */
1007 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
1010 /* have they expired ? */
1011 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1012 /* +15 for leeway */
1014 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1015 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1019 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
1020 "krbtgt", ZGetRealm(),
1021 TKTLIFETIME, srvtab_file);
1022 if (retval != KSUCCESS) {
1023 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1024 krb_get_err_text(retval));
1031 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1032 ZGetRealm(), 0 /*kvno*/,
1033 srvtab_file, (char *)serv_key);
1034 if (retval != KSUCCESS) {
1035 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1036 krb_get_err_text(retval));
1039 des_key_sched(serv_key, serv_ksched.s);
1043 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1045 krb5_get_init_creds_opt opt;
1047 krb5_principal principal;
1049 memset(&cred, 0, sizeof(cred));
1051 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1052 strlen(ZGetRealm()),
1054 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1057 krb5_free_principal(Z_krb5_ctx, principal);
1061 krb5_get_init_creds_opt_init (&opt);
1062 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1064 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1065 if (retval) return(1);
1067 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1074 krb5_free_principal(Z_krb5_ctx, principal);
1075 krb5_kt_close(Z_krb5_ctx, kt);
1076 if (retval) return(1);
1078 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1079 if (retval) return(1);
1081 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1082 if (retval) return(1);
1086 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1091 #endif /* HAVE_KRB4 */
1094 * The braindump offer wasn't taken, so we retract it.
1099 close_bdump(void *arg)
1101 if (bdump_socket >= 0) {
1102 FD_CLR(bdump_socket, &interesting);
1103 close(bdump_socket);
1104 nfds = srv_socket + 1;
1107 zdbug((LOG_DEBUG, "bdump not used"));
1111 zdbug((LOG_DEBUG, "bdump not open"));
1118 * Start receiving instruction notices from the brain dump socket
1122 bdump_recv_loop(Server *server)
1128 Client *client = NULL;
1129 struct sockaddr_in who;
1131 unsigned char buf[512];
1134 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1139 #endif /* HAVE_KRB4 */
1140 ZRealm *realm = NULL;
1143 zdbug((LOG_DEBUG, "bdump recv loop"));
1146 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1148 if (packets_waiting()) {
1149 /* A non-braindump packet is waiting; handle it. */
1151 bdump_concurrent = 1;
1153 bdump_concurrent = 0;
1156 len = sizeof(packet);
1157 retval = get_packet(packet, len, &len);
1158 if (retval != ZERR_NONE) {
1159 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1168 memset(&out, 0, sizeof(krb5_data));
1169 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1170 if (retval != ZERR_NONE) {
1171 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1174 memcpy(packet, out.data, out.length);
1176 krb5_free_data_contents(Z_krb5_ctx, &out);
1180 retval = ZParseNotice(packet, len, ¬ice);
1181 if (retval != ZERR_NONE) {
1182 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1187 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1188 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1189 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1190 notice.z_recipient);
1193 if (notice.z_num_other_fields >= 1) {
1194 retval = ZReadAscii(notice.z_other_fields[0],
1195 strlen(notice.z_other_fields[0]),
1196 (unsigned char *) &who.sin_addr,
1197 sizeof(struct in_addr));
1198 if (retval != ZERR_NONE) {
1199 syslog(LOG_ERR, "brl zreadascii failed: %s",
1200 error_message(retval));
1204 who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
1206 who.sin_family = AF_INET;
1207 who.sin_port = notice.z_port;
1209 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1210 /* end of brain dump */
1212 } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
1213 /* get a realm from the message */
1214 realm = realm_get_realm_by_name(notice.z_message);
1216 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
1219 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1220 /* 1 = tell it we are authentic */
1221 retval = ulogin_dispatch(¬ice, 1, &who, server);
1222 if (retval != ZERR_NONE) {
1223 syslog(LOG_ERR, "brl ul_disp failed: %s",
1224 error_message(retval));
1227 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1229 notice.z_port = htons((u_short) atoi(notice.z_message));
1230 retval = client_register(¬ice, &who.sin_addr, &client, 0);
1231 if (retval != ZERR_NONE) {
1232 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
1236 client->session_keyblock = NULL;
1237 if (*notice.z_class_inst) {
1238 /* check out this session key I found */
1239 cp = notice.z_message + strlen(notice.z_message) + 1;
1241 /* ****ing netascii; this is an encrypted DES keyblock
1242 XXX this code should be conditionalized for server
1244 retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1246 &client->session_keyblock);
1248 syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1249 error_message(retval));
1252 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1253 if (retval != ZERR_NONE) {
1254 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1255 error_message(retval), cp);
1257 des_ecb_encrypt((C_Block *)cblock, (C_Block *)Z_keydata(client->session_keyblock),
1258 serv_ksched.s, DES_DECRYPT);
1260 } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
1261 retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen);
1262 if (retval != ZERR_NONE) {
1263 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1264 error_message(retval), cp);
1266 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1267 ntohl(*(krb5_enctype *)&buf[0]),
1268 ntohl(*(u_int32_t *)&buf[4]),
1269 &client->session_keyblock);
1271 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1272 error_message(retval));
1275 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1276 Z_keylen(client->session_keyblock));
1282 memset(client->session_key, 0, sizeof(C_Block));
1283 if (*notice.z_class_inst) {
1284 /* a C_Block is there */
1285 cp = notice.z_message + strlen(notice.z_message) + 1;
1286 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1287 if (retval != ZERR_NONE) {
1288 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1289 error_message(retval), cp);
1291 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1295 #endif /* HAVE_KRB4 */
1297 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1298 /* a subscription packet */
1300 syslog(LOG_ERR, "brl no client");
1303 retval = subscr_subscribe(client, ¬ice, server);
1304 if (retval != ZERR_NONE) {
1305 syslog(LOG_WARNING, "brl subscr failed: %s",
1306 error_message(retval));
1309 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1310 /* add a subscription for a realm */
1312 retval = subscr_realm(realm, ¬ice);
1313 if (retval != ZERR_NONE) {
1314 syslog(LOG_WARNING, "brl subscr failed: %s",
1315 error_message(retval));
1319 /* Other side tried to send us subs for a realm we didn't
1320 know about, and so we drop them silently */
1323 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1324 return ZSRV_UNKNOWNOPCODE;
1330 * Send all the state to the peer.
1334 bdump_send_loop(Server *server)
1339 zdbug((LOG_DEBUG, "bdump send loop"));
1342 retval = uloc_send_locations();
1343 if (retval != ZERR_NONE)
1345 retval = client_send_clients();
1346 if (retval != ZERR_NONE)
1348 retval = realm_send_realms();
1349 if (retval != ZERR_NONE)
1355 * Send a sync indicating end of this host
1364 zdbug((LOG_DEBUG, "send_done"));
1366 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1367 "", ADMIN_DONE, myname, "", NULL, 0);
1373 * Send a list off as the specified notice
1377 send_list(ZNotice_Kind_t kind,
1392 memset (¬ice, 0, sizeof(notice));
1394 notice.z_kind = kind;
1395 notice.z_port = port;
1396 notice.z_class = class_name;
1397 notice.z_class_inst = inst;
1398 notice.z_opcode = opcode;
1399 notice.z_sender = sender;
1400 notice.z_recipient = recip;
1401 notice.z_default_format = "";
1402 notice.z_num_other_fields = 0;
1404 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1405 if (retval != ZERR_NONE) {
1406 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1410 retval = ZSendPacket(pack, packlen, 0);
1411 if (retval != ZERR_NONE)
1412 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1418 * Send a message off as the specified notice, via TCP
1422 send_normal_tcp(ZNotice_Kind_t kind,
1438 memset (¬ice, 0, sizeof(notice));
1440 notice.z_kind = kind;
1441 notice.z_port = port;
1442 notice.z_class = class_name;
1443 notice.z_class_inst = inst;
1444 notice.z_opcode = opcode;
1445 notice.z_sender = sender;
1446 notice.z_recipient = recip;
1447 notice.z_default_format = "";
1448 notice.z_message = message;
1449 notice.z_message_len = len;
1450 notice.z_num_other_fields = 0;
1452 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1453 if (retval != ZERR_NONE) {
1454 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1460 krb5_data indata, outmsg;
1461 indata.length=packlen;
1463 memset(&outmsg, 0, sizeof(krb5_data));
1464 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1465 if (retval != ZERR_NONE)
1467 if (outmsg.length > Z_MAXPKTLEN) {
1468 syslog(LOG_ERR, "sn: encrypted packet is too large");
1471 packlen = outmsg.length;
1473 pack=malloc(packlen);
1476 memcpy(pack, outmsg.data, packlen);
1477 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1481 length = htons((u_short) packlen);
1483 count = net_write(output, (char *) &length, sizeof(length));
1484 if (count != sizeof(length)) {
1486 syslog(LOG_WARNING, "snt xmit/len: %m");
1490 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1495 count = net_write(output, pack, packlen);
1496 if (count != packlen) {
1498 syslog(LOG_WARNING, "snt xmit: %m");
1502 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1512 * get a packet from the TCP socket
1513 * return 0 if successful, error code else
1517 get_packet(void *packet, int len, int *retlen)
1522 result = net_read(input, (char *) &length, sizeof(u_short));
1523 if (result < sizeof(short)) {
1527 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1533 length = ntohs(length);
1535 return ZSRV_BUFSHORT;
1536 result = net_read(input, packet, (int) length);
1537 if (result < length) {
1541 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1550 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1552 char *cp = notice->z_message;
1556 if (!notice->z_message_len || *buf == '\0') {
1558 zdbug((LOG_DEBUG,"no addr"));
1560 return ZSRV_PKSHORT;
1562 target->sin_addr.s_addr = inet_addr(cp);
1564 cp += (strlen(cp) + 1); /* past the null */
1565 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1567 zdbug((LOG_DEBUG, "no port"));
1569 return(ZSRV_PKSHORT);
1571 target->sin_port = htons((u_short) atoi(cp));
1572 target->sin_family = AF_INET;
1577 net_read(FILE *f, char *buf, int len)
1584 cc = fread(buf, 1, len, f);
1601 net_write(FILE *f, char *buf, int len)
1606 cc = fwrite (buf, 1, wrlen, f);
1611 } while (wrlen > 0);
1616 setup_file_pointers (void)
1620 input = fdopen (live_socket, "r");
1624 fd = dup (live_socket);
1627 output = fdopen (fd, "w");