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 $
7 * $Id: bdump.c 2544 2009-08-27 15:19:01Z kcr@ATHENA.MIT.EDU $
8 * $Author: kcr@ATHENA.MIT.EDU $
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>
20 static const char rcsid_bdump_c[] = "$Id: bdump.c 2544 2009-08-27 15:19:01Z kcr@ATHENA.MIT.EDU $";
24 #define MIN(x, y) ((x) < (y) ? (x) : (y))
28 * External functions are:
30 * void bdump_offer(who)
31 * strut sockaddr_in *who;
35 * void bdump_get(notice, auth, who, server)
38 * struct sockaddr_in *who;
41 * Code_t bdump_send_list_tcp(kind, port, class, inst, opcode,
42 * sender, recip, lyst, num)
43 * ZNotice_Kind_t kind;
45 * char *class, *inst, *opcode, *sender, *recip;
50 static void close_bdump(void* arg);
51 static Code_t bdump_send_loop(Server *server);
52 static Code_t bdump_recv_loop(Server *server);
53 static void bdump_get_v12(ZNotice_t *, int, struct sockaddr_in *,
55 static Code_t get_packet(void *packet, int len, int *retlen);
56 static Code_t extract_sin(ZNotice_t *notice, struct sockaddr_in *target);
57 static Code_t send_done(void);
58 static Code_t send_list(ZNotice_Kind_t kind, int port, char *class_name,
59 char *inst, char *opcode, char *sender,
60 char *recip, char **lyst, int num);
61 static Code_t send_normal_tcp(ZNotice_Kind_t kind, int port,
63 char *inst, char *opcode, char *sender,
64 char *recip, char *message, int len);
65 static int net_read(FILE *f, char *buf, int len);
66 static int net_write(FILE *f, char *buf, int len);
67 static int setup_file_pointers(void);
68 static void shutdown_file_pointers(void);
69 static void cleanup(Server *server);
72 static int des_service_decrypt(unsigned char *in, unsigned char *out);
75 static long ticket5_time;
76 #define TKT5LIFETIME 8*60*60
77 #define tkt5_lifetime(val) (val)
81 static long ticket_time;
83 #define TKTLIFETIME 120
84 #define tkt_lifetime(val) ((long) val * 5L * 60L)
86 #endif /* HAVE_KRB4 */
88 #if defined(HAVE_KRB4)
89 extern C_Block serv_key;
90 extern Sched serv_ksched;
92 #if defined(HAVE_KRB5) && !defined(HAVE_KRB4)
93 krb5_keyblock *server_key;
96 static Timer *bdump_timer;
97 static int live_socket = -1;
98 static FILE *input, *output;
99 static struct sockaddr_in bdump_sin;
101 static krb5_auth_context bdump_ac;
105 int bdump_concurrent;
106 extern char *bdump_version;
107 extern int bdump_auth_proto;
110 * Functions for performing a brain dump between servers.
114 * offer the brain dump to another server
118 bdump_offer(struct sockaddr_in *who)
121 char buf[512], *addr, *lyst[2];
122 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
123 int bdump_port = IPPORT_RESERVED - 1;
124 #endif /* !HAVE_KRB4 */
126 zdbug((LOG_DEBUG, "bdump_offer"));
128 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
130 * when using kerberos server-server authentication, we can
131 * use any random local address
133 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
134 if (bdump_socket < 0) {
135 syslog(LOG_ERR,"bdump_offer: socket: %m");
139 memset(&bdump_sin, 0, sizeof(bdump_sin));
140 /* a port field of 0 makes the UNIX
141 * kernel choose an appropriate port/address pair */
143 bdump_sin.sin_port = 0;
144 bdump_sin.sin_addr = my_addr;
145 bdump_sin.sin_family = AF_INET;
146 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
149 syslog(LOG_ERR, "bdump_offer: bind: %m");
154 if (!bdump_sin.sin_port) {
155 unsigned int len = sizeof(bdump_sin);
157 if (getsockname(bdump_socket,
158 (struct sockaddr *) &bdump_sin, &len) < 0) {
159 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
165 #else /* !HAVE_KRB4 */
167 * when not using HAVE_KRB4, we can't use any old port, we use
168 * Internet reserved ports instead (rresvport)
170 bdump_socket = rresvport(&bdump_port);
171 if (bdump_socket < 0) {
172 syslog(LOG_ERR,"bdump_offer: socket: %m");
176 memset(&bdump_sin, 0, sizeof(bdump_sin));
177 bdump_sin.sin_port = htons((unsigned short) bdump_port);
178 bdump_sin.sin_addr = my_addr;
179 bdump_sin.sin_family = AF_INET;
180 #endif /* HAVE_KRB4 */
182 listen(bdump_socket, 1);
184 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
185 FD_SET(bdump_socket, &interesting);
186 nfds = max(bdump_socket, srv_socket) + 1;
188 addr = inet_ntoa(bdump_sin.sin_addr);
189 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
193 retval = ZSetDestAddr(who);
194 if (retval != ZERR_NONE) {
195 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
196 error_message(retval));
200 /* myname is the hostname */
201 /* the class instance is the version number, here it is */
202 /* bdump_version, which is set in main */
203 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
204 ADMIN_BDUMP, myname, "", lyst, 2);
206 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
207 inet_ntoa(bdump_sin.sin_addr),
208 ntohs(bdump_sin.sin_port)));
213 * Accept a connection, and send the brain dump to the other server
219 struct sockaddr_in from;
222 unsigned int fromlen = sizeof(from);
224 #ifdef _POSIX_VERSION
225 struct sigaction action;
227 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
235 /* may be moved into kstuff.c */
236 char instance [INST_SZ];
239 /* may be moved into kstuff.c */
240 krb5_principal principal;
244 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
245 unsigned short fromport;
246 #endif /* HAVE_KRB4 */
248 zdbug((LOG_DEBUG, "bdump_send"));
250 /* accept the connection, and send the brain dump */
251 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
252 if (live_socket < 0) {
253 syslog(LOG_ERR,"bdump_send: accept: %m");
256 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
258 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
260 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
261 fromport = ntohs(from.sin_port);
264 #ifdef _POSIX_VERSION
265 sigemptyset(&action.sa_mask);
267 action.sa_handler = SIG_IGN;
268 sigaction(SIGPIPE, &action, NULL);
271 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
274 from.sin_port = srv_addr.sin_port; /* we don't care what port
275 * it came from, and we need to
276 * fake out server_which_server() */
277 server = server_which_server(&from);
279 syslog(LOG_ERR, "bdump_send: unknown server?");
280 server = limbo_server;
283 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
284 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
289 if (bdump_socket >= 0) {
290 /* shut down the listening socket and the timer. */
291 FD_CLR(bdump_socket, &interesting);
293 nfds = srv_socket + 1;
295 timer_reset(bdump_timer);
298 /* Now begin the brain dump. */
299 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
300 retval = ReadKerberosData(live_socket, &len, &data, &proto);
303 syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
304 error_message(retval));
309 syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
312 syslog(LOG_ERR, "bdump_send: get_tgt failed");
321 retval = krb5_build_principal(Z_krb5_ctx, &principal,
324 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
327 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s",
328 error_message(retval));
334 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
336 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s",
337 error_message(retval));
342 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac,
343 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
345 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s",
346 error_message(retval));
351 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
352 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
354 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
359 /* Get the "client" krb_ap_req */
361 memset((char *)&k5data, 0, sizeof(krb5_data));
366 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
368 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
369 error_message(retval));
370 krb5_kt_close(Z_krb5_ctx, kt);
375 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
376 krb5_free_principal(Z_krb5_ctx, principal);
377 krb5_kt_close(Z_krb5_ctx, kt);
379 memset((char *)&k5data, 0, sizeof(krb5_data));
381 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
382 error_message(retval));
387 /* Now send back our auth packet */
389 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
391 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
395 retval = SendKrb5Data(live_socket, &k5data);
397 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
398 error_message(retval));
399 krb5_free_data_contents(Z_krb5_ctx, &k5data);
403 krb5_free_data_contents(Z_krb5_ctx, &k5data);
405 #endif /* HAVE_KRB5 */
408 /* here to krb_rd_req from GetKerberosData candidate for refactoring
409 back into kstuff.c */
410 (void) strcpy(instance, "*"); /* let Kerberos fill it in */
413 memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
414 retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
415 from.sin_addr.s_addr, &kdata, srvtab_file);
417 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
418 SERVER_SERVICE, srvtab_file);
420 if (retval != KSUCCESS) {
421 syslog(LOG_ERR, "bdump_send: getkdata: %s",
422 error_message(retval));
426 if (strcmp(kdata.pname, SERVER_SERVICE) ||
427 strcmp(kdata.pinst, SERVER_INSTANCE) ||
428 strcmp(kdata.prealm, ZGetRealm())) {
429 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
430 kdata.pname, kdata.pinst, kdata.prealm);
434 /* authenticate back */
435 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
438 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
439 error_message (retval));
444 #endif /* HAVE_KRB4 */
446 #else /* HAVE_KRB4 || HAVE_KRB5 */
447 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
448 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
452 #endif /* HAVE_KRB4 || HAVE_KRB5 */
453 retval = setup_file_pointers();
455 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
456 error_message(retval));
460 retval = bdump_send_loop(server);
461 if (retval != ZERR_NONE) {
462 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
463 error_message(retval));
467 retval = bdump_recv_loop(server);
468 if (retval != ZERR_NONE) {
469 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
470 error_message(retval));
475 zdbug((LOG_DEBUG, "bdump_send: finished"));
477 if (server != limbo_server) {
478 /* set this guy to be up, and schedule a hello */
479 server->state = SERV_UP;
480 timer_reset(server->timer);
481 server->timer = timer_set_rel(0L, server_timo, server);
484 shutdown_file_pointers();
486 #ifdef _POSIX_VERSION
487 action.sa_handler = SIG_DFL;
488 sigaction(SIGPIPE, &action, NULL);
490 signal(SIGPIPE, SIG_DFL);
494 /* Now that we are finished dumping, send all the queued packets */
495 server_send_queue(server);
501 bdump_get_v12 (ZNotice_t *notice,
503 struct sockaddr_in *who,
506 struct sockaddr_in from;
509 #ifdef _POSIX_VERSION
510 struct sigaction action;
512 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
516 krb5_principal principal;
518 krb5_ap_rep_enc_part *rep;
524 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
525 int reserved_port = IPPORT_RESERVED - 1;
526 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
531 #ifdef _POSIX_VERSION
533 sigemptyset(&action.sa_mask);
534 action.sa_handler = SIG_IGN;
535 sigaction(SIGPIPE, &action, NULL);
537 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
538 #endif /* _POSIX_VRESION */
540 if (bdump_socket >= 0) {
541 /* We cannot go get a brain dump when someone may
542 potentially be connecting to us (if that other
543 server is the server to whom we are connecting,
544 we will deadlock. so we shut down the listening
545 socket and the timer. */
546 FD_CLR(bdump_socket, &interesting);
550 timer_reset(bdump_timer);
553 retval = extract_sin(notice, &from);
554 if (retval != ZERR_NONE) {
555 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
556 #ifdef _POSIX_VERSION
557 action.sa_handler = SIG_DFL;
558 sigaction(SIGPIPE, &action, NULL);
560 signal(SIGPIPE, SIG_DFL);
566 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
567 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
568 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
569 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
570 ntohs(from.sin_port));
574 live_socket = rresvport(&reserved_port);
575 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
576 live_socket = socket(AF_INET, SOCK_STREAM, 0);
577 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
578 if (live_socket < 0) {
579 syslog(LOG_ERR, "bdump_get: socket: %m");
583 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
584 syslog(LOG_ERR, "bdump_get: connect: %m");
588 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
590 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
592 zdbug((LOG_DEBUG, "bdump_get: connected"));
594 /* Now begin the brain dump. */
595 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
597 syslog(LOG_ERR, "bdump_get: get_tgt failed");
601 switch(bdump_auth_proto) {
603 case 5: /* "client" side */
604 memset((char *)&creds, 0, sizeof(creds));
606 retval = krb5_build_principal(Z_krb5_ctx, &principal,
609 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
612 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s",
613 error_message(retval));
618 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
620 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s",
621 error_message(retval));
622 krb5_free_principal(Z_krb5_ctx, principal);
627 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
628 krb5_free_principal(Z_krb5_ctx, principal);
630 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s",
631 error_message(retval));
632 krb5_free_cred_contents(Z_krb5_ctx, &creds);
637 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
639 krb5_free_cred_contents(Z_krb5_ctx, &creds);
641 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
646 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
648 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
649 krb5_free_creds(Z_krb5_ctx, credsp);
654 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
656 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
657 krb5_free_creds(Z_krb5_ctx, credsp);
662 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
663 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
665 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
666 krb5_free_creds(Z_krb5_ctx, credsp);
671 memset((char *)&data, 0, sizeof(krb5_data));
672 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
673 NULL, credsp, &data);
675 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
676 krb5_free_creds(Z_krb5_ctx, credsp);
680 retval = SendKrb5Data(live_socket, &data);
681 krb5_free_creds(Z_krb5_ctx, credsp);
683 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
684 error_message(retval));
685 krb5_free_data_contents(Z_krb5_ctx, &data);
689 krb5_free_data_contents(Z_krb5_ctx, &data);
690 memset((char *)&data, 0, sizeof(krb5_data));
691 retval = GetKrb5Data(live_socket, &data);
693 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
694 error_message(retval));
698 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
700 memset((char *)&data, 0, sizeof(krb5_data));
702 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
703 error_message(retval));
711 /* send an authenticator */
712 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
715 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
719 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
721 /* get his authenticator */
722 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
723 SERVER_SERVICE, srvtab_file);
724 if (retval != KSUCCESS) {
725 syslog(LOG_ERR, "bdump_get getkdata: %s",error_message(retval));
730 if (strcmp(kdata.pname, SERVER_SERVICE) ||
731 strcmp(kdata.pinst, SERVER_INSTANCE) ||
732 strcmp(kdata.prealm, ZGetRealm())) {
733 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
734 kdata.pname, kdata.pinst,kdata.prealm);
739 #endif /* HAVE_KRB4 */
741 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
742 retval = setup_file_pointers();
744 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
745 error_message (retval));
749 retval = bdump_recv_loop(server);
750 if (retval != ZERR_NONE) {
751 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
752 error_message(retval));
756 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
757 retval = bdump_send_loop(server);
758 if (retval != ZERR_NONE) {
759 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
760 error_message(retval));
765 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
767 /* set this guy to be up, and schedule a hello */
768 server->state = SERV_UP;
769 timer_reset(server->timer);
770 server->timer = timer_set_rel(0L, server_timo, server);
773 zdbug((LOG_DEBUG,"cleanup gbd"));
775 shutdown_file_pointers();
776 #ifdef _POSIX_VERSION
777 action.sa_handler = SIG_DFL;
778 sigaction(SIGPIPE, &action, NULL);
780 signal(SIGPIPE, SIG_DFL);
784 /* Now that we are finished dumping, send all the queued packets */
785 server_send_queue(server);
791 bdump_get(ZNotice_t *notice,
793 struct sockaddr_in *who,
796 void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *);
801 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
802 notice->z_class_inst, inet_ntoa(who->sin_addr));
805 if (strcmp (notice->z_class_inst, "1.2") == 0)
806 proc = bdump_get_v12;
809 (*proc)(notice, auth, who, server);
812 "bdump_get: Incompatible bdump version '%s' from %s",
813 notice->z_class_inst,
814 inet_ntoa(who->sin_addr));
819 * Send a list off as the specified notice
823 bdump_send_list_tcp(ZNotice_Kind_t kind,
824 struct sockaddr_in *addr,
839 memset (¬ice, 0, sizeof(notice));
841 notice.z_kind = kind;
843 notice.z_port = addr->sin_port;
844 notice.z_class = class_name;
845 notice.z_class_inst = inst;
846 notice.z_opcode = opcode;
847 notice.z_sender = sender;
848 notice.z_recipient = recip;
849 notice.z_default_format = "";
850 notice.z_num_other_fields = 0;
852 notice.z_sender_sockaddr.ip4 = *addr; /*XXX*/
854 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
855 if (retval != ZERR_NONE)
860 krb5_data indata, outmsg;
861 indata.length=packlen;
863 memset(&outmsg, 0, sizeof(krb5_data));
864 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
865 if (retval != ZERR_NONE)
867 if (outmsg.length > Z_MAXPKTLEN) {
868 syslog(LOG_ERR, "bsl: encrypted packet is too large");
871 packlen = outmsg.length;
873 pack=malloc(packlen);
876 memcpy(pack, outmsg.data, packlen);
877 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
881 length = htons((u_short) packlen);
883 count = net_write(output, (char *) &length, sizeof(length));
884 if (count != sizeof(length)) {
889 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
890 sizeof(length), count);
892 return(ZSRV_PKSHORT);
896 count = net_write(output, pack, packlen);
897 if (count != packlen) {
902 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
905 return(ZSRV_PKSHORT);
913 shutdown_file_pointers(void)
923 if (live_socket >= 0) {
928 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
935 cleanup(Server *server)
937 #ifdef _POSIX_VERSION
938 struct sigaction action;
941 zdbug((LOG_DEBUG, "bdump cleanup"));
943 if (server != limbo_server) {
944 server->state = SERV_DEAD;
945 timer_reset(server->timer);
946 server->timer = timer_set_rel(0L, server_timo, server);
948 shutdown_file_pointers ();
949 #ifdef _POSIX_VERSION
951 sigemptyset(&action.sa_mask);
952 action.sa_handler = SIG_DFL;
953 sigaction(SIGPIPE,&action, NULL);
955 signal(SIGPIPE, SIG_DFL);
956 #endif /* _POSIX_VERSION */
961 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
966 unsigned int enctypes[] = {ENCTYPE_DES_CBC_CRC,
969 #ifdef ENCTYPE_DES_CBC_RAW
982 krb5_keytab_entry kt_ent;
985 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
986 * at least INST_SZ bytes long. */
987 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
989 /* have they expired ? */
990 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
993 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
994 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
998 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, (char *)ZGetRealm(),
999 "krbtgt", (char *)ZGetRealm(),
1000 TKTLIFETIME, srvtab_file);
1001 if (retval != KSUCCESS) {
1002 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1003 error_message(retval));
1010 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1011 (char *)ZGetRealm(), 0 /*kvno*/,
1012 srvtab_file, (char *)serv_key);
1013 if (retval != KSUCCESS) {
1014 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1015 error_message(retval));
1018 des_key_sched(serv_key, serv_ksched.s);
1024 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1026 krb5_get_init_creds_opt opt;
1028 krb5_principal principal;
1030 memset(&cred, 0, sizeof(cred));
1032 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1033 strlen(ZGetRealm()),
1035 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1038 syslog(LOG_ERR, "get_tgt: krb5_build_principal: %s",
1039 error_message(retval));
1043 krb5_get_init_creds_opt_init (&opt);
1044 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1046 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1048 syslog(LOG_ERR, "get_tgt: krb5_kt_resolve: %s",
1049 error_message(retval));
1050 krb5_free_principal(Z_krb5_ctx, principal);
1054 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1062 syslog(LOG_ERR, "get_tgt: krb5_get_init_creds_keytab: %s",
1063 error_message(retval));
1064 krb5_free_principal(Z_krb5_ctx, principal);
1065 krb5_kt_close(Z_krb5_ctx, kt);
1070 for (i = 0; enctypes[i]; i++) {
1071 retval = krb5_kt_get_entry(Z_krb5_ctx, kt, principal,
1072 0, enctypes[i], &kt_ent);
1077 #ifdef HAVE_KRB5_CRYPTO_INIT
1078 retval = krb5_copy_keyblock(Z_krb5_ctx, &kt_ent.keyblock,
1081 retval = krb5_copy_keyblock(Z_krb5_ctx, &kt_ent.key, &server_key);
1084 syslog(LOG_ERR, "get_tgt: krb5_copy_keyblock: %s",
1085 error_message(retval));
1086 krb5_free_principal(Z_krb5_ctx, principal);
1087 krb5_kt_close(Z_krb5_ctx, kt);
1093 #endif /* HAVE_KRB4 */
1094 krb5_free_principal(Z_krb5_ctx, principal);
1095 krb5_kt_close(Z_krb5_ctx, kt);
1097 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1099 syslog(LOG_ERR, "get_tgt: krb5_cc_initialize: %s",
1100 error_message(retval));
1104 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1106 syslog(LOG_ERR, "get_tgt: krb5_cc_store_cred: %s",
1107 error_message(retval));
1113 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1118 #endif /* HAVE_KRB4 */
1121 * The braindump offer wasn't taken, so we retract it.
1126 close_bdump(void *arg)
1128 if (bdump_socket >= 0) {
1129 FD_CLR(bdump_socket, &interesting);
1130 close(bdump_socket);
1131 nfds = srv_socket + 1;
1134 zdbug((LOG_DEBUG, "bdump not used"));
1136 zdbug((LOG_DEBUG, "bdump not open"));
1142 * Start receiving instruction notices from the brain dump socket
1146 bdump_recv_loop(Server *server)
1152 Client *client = NULL;
1153 struct sockaddr_in who;
1155 unsigned char buf[512];
1158 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1161 unsigned char cblock[8];
1166 ZRealm *realm = NULL;
1168 zdbug((LOG_DEBUG, "bdump recv loop"));
1170 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1172 if (packets_waiting()) {
1173 /* A non-braindump packet is waiting; handle it. */
1175 bdump_concurrent = 1;
1177 bdump_concurrent = 0;
1180 len = sizeof(packet);
1181 retval = get_packet(packet, len, &len);
1182 if (retval != ZERR_NONE) {
1183 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1192 memset(&out, 0, sizeof(krb5_data));
1193 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1194 if (retval != ZERR_NONE) {
1195 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1198 memcpy(packet, out.data, out.length);
1200 krb5_free_data_contents(Z_krb5_ctx, &out);
1204 retval = ZParseNotice(packet, len, ¬ice);
1205 if (retval != ZERR_NONE) {
1206 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1211 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1212 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1213 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1214 notice.z_recipient);
1217 who.sin_family = AF_INET; /*XXX*/
1218 who.sin_addr.s_addr = notice.z_sender_sockaddr.ip4.sin_addr.s_addr;
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;
1252 if (*cp == '0' && got_des) {
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(cblock));
1265 if (retval != ZERR_NONE) {
1266 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1267 error_message(retval), cp);
1269 retval = des_service_decrypt(cblock, Z_keydata(client->session_keyblock));
1271 syslog(LOG_ERR, "brl failed to decyrpt DES session key: %s",
1272 error_message(retval));
1276 } else if (*cp == 'Z') {
1277 /* Zcode! Long live the new flesh! */
1278 retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen);
1279 if (retval != ZERR_NONE) {
1280 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1281 error_message(retval), cp);
1283 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1284 ntohl(*(krb5_enctype *)&buf[0]),
1285 ntohl(*(uint32_t *)&buf[4]),
1286 &client->session_keyblock);
1288 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1289 error_message(retval));
1292 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1293 Z_keylen(client->session_keyblock));
1299 memset(client->session_key, 0, sizeof(C_Block));
1300 if (*notice.z_class_inst) {
1301 /* a C_Block is there */
1302 cp = notice.z_message + strlen(notice.z_message) + 1;
1303 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1304 if (retval != ZERR_NONE) {
1305 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1306 error_message(retval), cp);
1308 des_ecb_encrypt((des_cblock *)cblock,
1309 (des_cblock *)client->session_key,
1310 serv_ksched.s, DES_DECRYPT);
1313 #endif /* HAVE_KRB4 */
1315 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1316 /* a subscription packet */
1318 syslog(LOG_ERR, "brl no client");
1321 retval = subscr_subscribe(client, ¬ice, server);
1322 if (retval != ZERR_NONE) {
1323 syslog(LOG_WARNING, "brl subscr failed: %s",
1324 error_message(retval));
1327 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1328 /* add a subscription for a realm */
1330 retval = subscr_realm(realm, ¬ice);
1331 if (retval != ZERR_NONE) {
1332 syslog(LOG_WARNING, "brl subscr failed: %s",
1333 error_message(retval));
1337 /* Other side tried to send us subs for a realm we didn't
1338 know about, and so we drop them silently */
1341 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1342 return ZSRV_UNKNOWNOPCODE;
1348 * Send all the state to the peer.
1352 bdump_send_loop(Server *server)
1356 zdbug((LOG_DEBUG, "bdump send loop"));
1358 retval = uloc_send_locations();
1359 if (retval != ZERR_NONE)
1361 retval = client_send_clients();
1362 if (retval != ZERR_NONE)
1364 retval = realm_send_realms();
1365 if (retval != ZERR_NONE)
1371 * Send a sync indicating end of this host
1379 zdbug((LOG_DEBUG, "send_done"));
1381 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1382 "", ADMIN_DONE, myname, "", NULL, 0);
1388 * Send a list off as the specified notice
1392 send_list(ZNotice_Kind_t kind,
1407 memset (¬ice, 0, sizeof(notice));
1409 notice.z_kind = kind;
1410 notice.z_port = port;
1411 notice.z_class = class_name;
1412 notice.z_class_inst = inst;
1413 notice.z_opcode = opcode;
1414 notice.z_sender = sender;
1415 notice.z_recipient = recip;
1416 notice.z_default_format = "";
1417 notice.z_num_other_fields = 0;
1419 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1420 if (retval != ZERR_NONE) {
1421 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1425 retval = ZSendPacket(pack, packlen, 0);
1426 if (retval != ZERR_NONE)
1427 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1433 * Send a message off as the specified notice, via TCP
1437 send_normal_tcp(ZNotice_Kind_t kind,
1451 unsigned short length;
1453 memset (¬ice, 0, sizeof(notice));
1455 notice.z_kind = kind;
1456 notice.z_port = port;
1457 notice.z_class = class_name;
1458 notice.z_class_inst = inst;
1459 notice.z_opcode = opcode;
1460 notice.z_sender = sender;
1461 notice.z_recipient = recip;
1462 notice.z_default_format = "";
1463 notice.z_message = message;
1464 notice.z_message_len = len;
1465 notice.z_num_other_fields = 0;
1467 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1468 if (retval != ZERR_NONE) {
1469 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1475 krb5_data indata, outmsg;
1476 indata.length=packlen;
1478 memset(&outmsg, 0, sizeof(krb5_data));
1479 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1480 if (retval != ZERR_NONE)
1482 if (outmsg.length > Z_MAXPKTLEN) {
1483 syslog(LOG_ERR, "sn: encrypted packet is too large");
1486 packlen = outmsg.length;
1488 pack=malloc(packlen);
1491 memcpy(pack, outmsg.data, packlen);
1492 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1496 length = htons((unsigned short) packlen);
1498 count = net_write(output, (char *) &length, sizeof(length));
1499 if (count != sizeof(length)) {
1501 syslog(LOG_WARNING, "snt xmit/len: %m");
1505 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1510 count = net_write(output, pack, packlen);
1511 if (count != packlen) {
1513 syslog(LOG_WARNING, "snt xmit: %m");
1517 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1527 * get a packet from the TCP socket
1528 * return 0 if successful, error code else
1532 get_packet(void *packet, int len, int *retlen)
1534 unsigned short length;
1537 result = net_read(input, (char *) &length, sizeof(unsigned short));
1538 if (result < sizeof(short)) {
1542 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1548 length = ntohs(length);
1550 return ZSRV_BUFSHORT;
1551 result = net_read(input, packet, (int) length);
1552 if (result < length) {
1556 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1565 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1567 char *cp = notice->z_message;
1571 if (!notice->z_message_len || *buf == '\0') {
1572 return ZSRV_PKSHORT;
1574 target->sin_addr.s_addr = inet_addr(cp);
1576 cp += (strlen(cp) + 1); /* past the null */
1577 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1578 return(ZSRV_PKSHORT);
1580 target->sin_port = htons((unsigned short)atoi(cp));
1581 target->sin_family = AF_INET;
1586 net_read(FILE *f, char *buf, int len)
1593 cc = fread(buf, 1, len, f);
1610 net_write(FILE *f, char *buf, int len)
1615 cc = fwrite (buf, 1, wrlen, f);
1620 } while (wrlen > 0);
1625 setup_file_pointers (void)
1629 input = fdopen (live_socket, "r");
1633 fd = dup (live_socket);
1636 output = fdopen (fd, "w");
1644 static int des_service_decrypt(unsigned char *in, unsigned char *out) {
1647 #ifdef HAVE_KRB5_C_DECRYPT
1651 dout.data = (char *)out; /*What*/
1653 din.ciphertext.length = 8;
1654 din.ciphertext.data = (char *)in;
1655 din.enctype = Z_enctype(server_key);
1657 #ifdef HAVE_KRB5_CRYPTO_INIT
1658 return krb5_c_decrypt(Z_krb5_ctx, *server_key, 0, 0, &din, &dout);
1660 return krb5_c_decrypt(Z_krb5_ctx, server_key, 0, 0, &din, &dout);
1662 #elif defined(HAVE_KRB5_CRYPTO_INIT)
1669 ret = krb5_crypto_init(Z_krb5_ctx, server_key, Z_enctype(server_key), &crypto);
1673 ret = krb5_decrypt_ivec(Z_krb5_ctx, crypto, 0, in, 8, &dout, NULL);
1675 krb5_crypto_destroy(Z_krb5_ctx, crypto);
1680 des_ecb_encrypt((C_Block *)in, (C_Block *)out, serv_ksched.s, DES_DECRYPT);
1681 return 0; /* sigh */