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 int des_service_decrypt(unsigned char *in, unsigned char *out);
109 static long ticket5_time;
110 #define TKT5LIFETIME 8*60*60
111 #define tkt5_lifetime(val) (val)
115 static long ticket_time;
117 #define TKTLIFETIME 120
118 #define tkt_lifetime(val) ((long) val * 5L * 60L)
120 #endif /* HAVE_KRB4 */
122 #if defined(HAVE_KRB4)
123 extern C_Block serv_key;
124 extern Sched serv_ksched;
126 #if defined(HAVE_KRB5) && !defined(HAVE_KRB4)
127 krb5_keyblock *server_key;
130 static Timer *bdump_timer;
131 static int live_socket = -1;
132 static FILE *input, *output;
133 static struct sockaddr_in bdump_sin;
135 static krb5_auth_context bdump_ac;
139 int bdump_concurrent;
140 extern char *bdump_version;
141 extern int bdump_auth_proto;
144 * Functions for performing a brain dump between servers.
148 * offer the brain dump to another server
152 bdump_offer(struct sockaddr_in *who)
155 char buf[512], *addr, *lyst[2];
156 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
157 int bdump_port = IPPORT_RESERVED - 1;
158 #endif /* !HAVE_KRB4 */
160 zdbug((LOG_DEBUG, "bdump_offer"));
162 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
164 * when using kerberos server-server authentication, we can
165 * use any random local address
167 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
168 if (bdump_socket < 0) {
169 syslog(LOG_ERR,"bdump_offer: socket: %m");
173 memset(&bdump_sin, 0, sizeof(bdump_sin));
174 /* a port field of 0 makes the UNIX
175 * kernel choose an appropriate port/address pair */
177 bdump_sin.sin_port = 0;
178 bdump_sin.sin_addr = my_addr;
179 bdump_sin.sin_family = AF_INET;
180 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
183 syslog(LOG_ERR, "bdump_offer: bind: %m");
188 if (!bdump_sin.sin_port) {
189 unsigned int len = sizeof(bdump_sin);
191 if (getsockname(bdump_socket,
192 (struct sockaddr *) &bdump_sin, &len) < 0) {
193 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
199 #else /* !HAVE_KRB4 */
201 * when not using HAVE_KRB4, we can't use any old port, we use
202 * Internet reserved ports instead (rresvport)
204 bdump_socket = rresvport(&bdump_port);
205 if (bdump_socket < 0) {
206 syslog(LOG_ERR,"bdump_offer: socket: %m");
210 memset(&bdump_sin, 0, sizeof(bdump_sin));
211 bdump_sin.sin_port = htons((unsigned short) bdump_port);
212 bdump_sin.sin_addr = my_addr;
213 bdump_sin.sin_family = AF_INET;
214 #endif /* HAVE_KRB4 */
216 listen(bdump_socket, 1);
218 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
219 FD_SET(bdump_socket, &interesting);
220 nfds = max(bdump_socket, srv_socket) + 1;
222 addr = inet_ntoa(bdump_sin.sin_addr);
223 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
227 retval = ZSetDestAddr(who);
228 if (retval != ZERR_NONE) {
229 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
230 error_message(retval));
234 /* myname is the hostname */
235 /* the class instance is the version number, here it is */
236 /* bdump_version, which is set in main */
237 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
238 ADMIN_BDUMP, myname, "", lyst, 2);
240 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
241 inet_ntoa(bdump_sin.sin_addr),
242 ntohs(bdump_sin.sin_port)));
247 * Accept a connection, and send the brain dump to the other server
253 struct sockaddr_in from;
256 unsigned int fromlen = sizeof(from);
258 #ifdef _POSIX_VERSION
259 struct sigaction action;
261 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
269 /* may be moved into kstuff.c */
270 char instance [INST_SZ];
273 /* may be moved into kstuff.c */
274 krb5_principal principal;
278 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
279 unsigned short fromport;
280 #endif /* HAVE_KRB4 */
282 zdbug((LOG_DEBUG, "bdump_send"));
284 /* accept the connection, and send the brain dump */
285 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
286 if (live_socket < 0) {
287 syslog(LOG_ERR,"bdump_send: accept: %m");
290 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
292 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
294 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
295 fromport = ntohs(from.sin_port);
298 #ifdef _POSIX_VERSION
299 sigemptyset(&action.sa_mask);
301 action.sa_handler = SIG_IGN;
302 sigaction(SIGPIPE, &action, NULL);
305 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
308 from.sin_port = srv_addr.sin_port; /* we don't care what port
309 * it came from, and we need to
310 * fake out server_which_server() */
311 server = server_which_server(&from);
313 syslog(LOG_ERR, "bdump_send: unknown server?");
314 server = limbo_server;
317 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
318 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
323 if (bdump_socket >= 0) {
324 /* shut down the listening socket and the timer. */
325 FD_CLR(bdump_socket, &interesting);
327 nfds = srv_socket + 1;
329 timer_reset(bdump_timer);
332 /* Now begin the brain dump. */
333 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
334 retval = ReadKerberosData(live_socket, &len, &data, &proto);
337 syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
338 error_message(retval));
343 syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
346 syslog(LOG_ERR, "bdump_send: get_tgt failed");
355 retval = krb5_build_principal(Z_krb5_ctx, &principal,
358 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
361 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
367 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
369 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
374 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
376 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
381 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
382 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
384 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
389 /* Get the "client" krb_ap_req */
391 memset((char *)&k5data, 0, sizeof(krb5_data));
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 error_message(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",error_message(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 notice.z_kind = kind;
870 notice.z_port = addr->sin_port;
871 notice.z_class = class_name;
872 notice.z_class_inst = inst;
873 notice.z_opcode = opcode;
874 notice.z_sender = sender;
875 notice.z_recipient = recip;
876 notice.z_default_format = "";
877 notice.z_num_other_fields = 0;
879 notice.z_sender_sockaddr.ip4 = *addr; /*XXX*/
881 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
882 if (retval != ZERR_NONE)
887 krb5_data indata, outmsg;
888 indata.length=packlen;
890 memset(&outmsg, 0, sizeof(krb5_data));
891 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
892 if (retval != ZERR_NONE)
894 if (outmsg.length > Z_MAXPKTLEN) {
895 syslog(LOG_ERR, "bsl: encrypted packet is too large");
898 packlen = outmsg.length;
900 pack=malloc(packlen);
903 memcpy(pack, outmsg.data, packlen);
904 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
908 length = htons((u_short) packlen);
910 count = net_write(output, (char *) &length, sizeof(length));
911 if (count != sizeof(length)) {
916 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
917 sizeof(length), count);
919 return(ZSRV_PKSHORT);
923 count = net_write(output, pack, packlen);
924 if (count != packlen) {
929 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
932 return(ZSRV_PKSHORT);
940 shutdown_file_pointers(void)
950 if (live_socket >= 0) {
955 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
962 cleanup(Server *server)
964 #ifdef _POSIX_VERSION
965 struct sigaction action;
968 zdbug((LOG_DEBUG, "bdump cleanup"));
970 if (server != limbo_server) {
971 server->state = SERV_DEAD;
972 timer_reset(server->timer);
973 server->timer = timer_set_rel(0L, server_timo, server);
975 shutdown_file_pointers ();
976 #ifdef _POSIX_VERSION
978 sigemptyset(&action.sa_mask);
979 action.sa_handler = SIG_DFL;
980 sigaction(SIGPIPE,&action, NULL);
982 signal(SIGPIPE, SIG_DFL);
983 #endif /* _POSIX_VERSION */
988 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
993 unsigned int enctypes[] = {ENCTYPE_DES_CBC_CRC,
996 #ifdef ENCTYPE_DES_CBC_RAW
1009 krb5_keytab_entry kt_ent;
1012 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
1013 * at least INST_SZ bytes long. */
1014 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
1016 /* have they expired ? */
1017 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1018 /* +15 for leeway */
1020 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1021 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1025 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, (char *)ZGetRealm(),
1026 "krbtgt", (char *)ZGetRealm(),
1027 TKTLIFETIME, srvtab_file);
1028 if (retval != KSUCCESS) {
1029 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1030 error_message(retval));
1037 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1038 (char *)ZGetRealm(), 0 /*kvno*/,
1039 srvtab_file, (char *)serv_key);
1040 if (retval != KSUCCESS) {
1041 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1042 error_message(retval));
1045 des_key_sched(serv_key, serv_ksched.s);
1051 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1053 krb5_get_init_creds_opt opt;
1055 krb5_principal principal;
1057 memset(&cred, 0, sizeof(cred));
1059 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1060 strlen(ZGetRealm()),
1062 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1065 krb5_free_principal(Z_krb5_ctx, principal);
1069 krb5_get_init_creds_opt_init (&opt);
1070 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1072 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1073 if (retval) return(1);
1075 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1084 krb5_free_principal(Z_krb5_ctx, principal);
1085 krb5_kt_close(Z_krb5_ctx, kt);
1089 for (i = 0; enctypes[i]; i++) {
1090 retval = krb5_kt_get_entry(Z_krb5_ctx, kt, principal,
1091 0, enctypes[i], &kt_ent);
1096 #ifdef HAVE_KRB5_CRYPTO_INIT
1097 retval = krb5_copy_keyblock(Z_krb5_ctx, &kt_ent.keyblock,
1100 retval = krb5_copy_keyblock(Z_krb5_ctx, &kt_ent.key, &server_key);
1103 krb5_free_principal(Z_krb5_ctx, principal);
1104 krb5_kt_close(Z_krb5_ctx, kt);
1111 krb5_free_principal(Z_krb5_ctx, principal);
1112 krb5_kt_close(Z_krb5_ctx, kt);
1114 if (retval) return(1);
1117 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1118 if (retval) return(1);
1120 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1121 if (retval) return(1);
1125 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1130 #endif /* HAVE_KRB4 */
1133 * The braindump offer wasn't taken, so we retract it.
1138 close_bdump(void *arg)
1140 if (bdump_socket >= 0) {
1141 FD_CLR(bdump_socket, &interesting);
1142 close(bdump_socket);
1143 nfds = srv_socket + 1;
1146 zdbug((LOG_DEBUG, "bdump not used"));
1148 zdbug((LOG_DEBUG, "bdump not open"));
1154 * Start receiving instruction notices from the brain dump socket
1158 bdump_recv_loop(Server *server)
1164 Client *client = NULL;
1165 struct sockaddr_in who;
1167 unsigned char buf[512];
1170 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1173 unsigned char cblock[8];
1178 ZRealm *realm = NULL;
1180 zdbug((LOG_DEBUG, "bdump recv loop"));
1182 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1184 if (packets_waiting()) {
1185 /* A non-braindump packet is waiting; handle it. */
1187 bdump_concurrent = 1;
1189 bdump_concurrent = 0;
1192 len = sizeof(packet);
1193 retval = get_packet(packet, len, &len);
1194 if (retval != ZERR_NONE) {
1195 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1204 memset(&out, 0, sizeof(krb5_data));
1205 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1206 if (retval != ZERR_NONE) {
1207 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1210 memcpy(packet, out.data, out.length);
1212 krb5_free_data_contents(Z_krb5_ctx, &out);
1216 retval = ZParseNotice(packet, len, ¬ice);
1217 if (retval != ZERR_NONE) {
1218 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1223 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1224 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1225 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1226 notice.z_recipient);
1229 who.sin_family = AF_INET; /*XXX*/
1230 who.sin_addr.s_addr = notice.z_sender_sockaddr.ip4.sin_addr.s_addr;
1231 who.sin_port = notice.z_port;
1233 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1234 /* end of brain dump */
1236 } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
1237 /* get a realm from the message */
1238 realm = realm_get_realm_by_name(notice.z_message);
1240 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
1243 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1244 /* 1 = tell it we are authentic */
1245 retval = ulogin_dispatch(¬ice, 1, &who, server);
1246 if (retval != ZERR_NONE) {
1247 syslog(LOG_ERR, "brl ul_disp failed: %s",
1248 error_message(retval));
1251 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1253 notice.z_port = htons((u_short) atoi(notice.z_message));
1254 retval = client_register(¬ice, &who.sin_addr, &client, 0);
1255 if (retval != ZERR_NONE) {
1256 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
1260 client->session_keyblock = NULL;
1261 if (*notice.z_class_inst) {
1262 /* check out this session key I found */
1263 cp = notice.z_message + strlen(notice.z_message) + 1;
1264 if (*cp == '0' && got_des) {
1265 /* ****ing netascii; this is an encrypted DES keyblock
1266 XXX this code should be conditionalized for server
1268 retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1270 &client->session_keyblock);
1272 syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1273 error_message(retval));
1276 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(cblock));
1277 if (retval != ZERR_NONE) {
1278 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1279 error_message(retval), cp);
1281 retval = des_service_decrypt(cblock, Z_keydata(client->session_keyblock));
1283 syslog(LOG_ERR, "brl failed to decyrpt DES session key: %s",
1284 error_message(retval));
1288 } else if (*cp == 'Z') {
1289 /* Zcode! Long live the new flesh! */
1290 retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen);
1291 if (retval != ZERR_NONE) {
1292 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1293 error_message(retval), cp);
1295 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1296 ntohl(*(krb5_enctype *)&buf[0]),
1297 ntohl(*(u_int32_t *)&buf[4]),
1298 &client->session_keyblock);
1300 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1301 error_message(retval));
1304 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1305 Z_keylen(client->session_keyblock));
1311 memset(client->session_key, 0, sizeof(C_Block));
1312 if (*notice.z_class_inst) {
1313 /* a C_Block is there */
1314 cp = notice.z_message + strlen(notice.z_message) + 1;
1315 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1316 if (retval != ZERR_NONE) {
1317 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1318 error_message(retval), cp);
1320 des_ecb_encrypt((des_cblock *)cblock,
1321 (des_cblock *)client->session_key,
1322 serv_ksched.s, DES_DECRYPT);
1325 #endif /* HAVE_KRB4 */
1327 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1328 /* a subscription packet */
1330 syslog(LOG_ERR, "brl no client");
1333 retval = subscr_subscribe(client, ¬ice, server);
1334 if (retval != ZERR_NONE) {
1335 syslog(LOG_WARNING, "brl subscr failed: %s",
1336 error_message(retval));
1339 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1340 /* add a subscription for a realm */
1342 retval = subscr_realm(realm, ¬ice);
1343 if (retval != ZERR_NONE) {
1344 syslog(LOG_WARNING, "brl subscr failed: %s",
1345 error_message(retval));
1349 /* Other side tried to send us subs for a realm we didn't
1350 know about, and so we drop them silently */
1353 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1354 return ZSRV_UNKNOWNOPCODE;
1360 * Send all the state to the peer.
1364 bdump_send_loop(Server *server)
1368 zdbug((LOG_DEBUG, "bdump send loop"));
1370 retval = uloc_send_locations();
1371 if (retval != ZERR_NONE)
1373 retval = client_send_clients();
1374 if (retval != ZERR_NONE)
1376 retval = realm_send_realms();
1377 if (retval != ZERR_NONE)
1383 * Send a sync indicating end of this host
1391 zdbug((LOG_DEBUG, "send_done"));
1393 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1394 "", ADMIN_DONE, myname, "", NULL, 0);
1400 * Send a list off as the specified notice
1404 send_list(ZNotice_Kind_t kind,
1419 memset (¬ice, 0, sizeof(notice));
1421 notice.z_kind = kind;
1422 notice.z_port = port;
1423 notice.z_class = class_name;
1424 notice.z_class_inst = inst;
1425 notice.z_opcode = opcode;
1426 notice.z_sender = sender;
1427 notice.z_recipient = recip;
1428 notice.z_default_format = "";
1429 notice.z_num_other_fields = 0;
1431 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1432 if (retval != ZERR_NONE) {
1433 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1437 retval = ZSendPacket(pack, packlen, 0);
1438 if (retval != ZERR_NONE)
1439 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1445 * Send a message off as the specified notice, via TCP
1449 send_normal_tcp(ZNotice_Kind_t kind,
1465 memset (¬ice, 0, sizeof(notice));
1467 notice.z_kind = kind;
1468 notice.z_port = port;
1469 notice.z_class = class_name;
1470 notice.z_class_inst = inst;
1471 notice.z_opcode = opcode;
1472 notice.z_sender = sender;
1473 notice.z_recipient = recip;
1474 notice.z_default_format = "";
1475 notice.z_message = message;
1476 notice.z_message_len = len;
1477 notice.z_num_other_fields = 0;
1479 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1480 if (retval != ZERR_NONE) {
1481 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1487 krb5_data indata, outmsg;
1488 indata.length=packlen;
1490 memset(&outmsg, 0, sizeof(krb5_data));
1491 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1492 if (retval != ZERR_NONE)
1494 if (outmsg.length > Z_MAXPKTLEN) {
1495 syslog(LOG_ERR, "sn: encrypted packet is too large");
1498 packlen = outmsg.length;
1500 pack=malloc(packlen);
1503 memcpy(pack, outmsg.data, packlen);
1504 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1508 length = htons((u_short) packlen);
1510 count = net_write(output, (char *) &length, sizeof(length));
1511 if (count != sizeof(length)) {
1513 syslog(LOG_WARNING, "snt xmit/len: %m");
1517 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1522 count = net_write(output, pack, packlen);
1523 if (count != packlen) {
1525 syslog(LOG_WARNING, "snt xmit: %m");
1529 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1539 * get a packet from the TCP socket
1540 * return 0 if successful, error code else
1544 get_packet(void *packet, int len, int *retlen)
1549 result = net_read(input, (char *) &length, sizeof(u_short));
1550 if (result < sizeof(short)) {
1554 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1560 length = ntohs(length);
1562 return ZSRV_BUFSHORT;
1563 result = net_read(input, packet, (int) length);
1564 if (result < length) {
1568 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1577 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1579 char *cp = notice->z_message;
1583 if (!notice->z_message_len || *buf == '\0') {
1584 return ZSRV_PKSHORT;
1586 target->sin_addr.s_addr = inet_addr(cp);
1588 cp += (strlen(cp) + 1); /* past the null */
1589 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1590 return(ZSRV_PKSHORT);
1592 target->sin_port = htons((u_short) atoi(cp));
1593 target->sin_family = AF_INET;
1598 net_read(FILE *f, char *buf, int len)
1605 cc = fread(buf, 1, len, f);
1622 net_write(FILE *f, char *buf, int len)
1627 cc = fwrite (buf, 1, wrlen, f);
1632 } while (wrlen > 0);
1637 setup_file_pointers (void)
1641 input = fdopen (live_socket, "r");
1645 fd = dup (live_socket);
1648 output = fdopen (fd, "w");
1656 static int des_service_decrypt(unsigned char *in, unsigned char *out) {
1661 #ifdef HAS_KRB5_C_DECRYPT
1665 din.ciphertext.length = 8;
1666 din.ciphertext.data = in;
1667 din.enctype = Z_enctype(server_key);
1669 #ifdef HAVE_KRB5_CRYPTO_INIT
1670 return krb5_c_decrypt(Z_krb5_ctx, *server_key, 0, 0, &din, &dout);
1672 return krb5_c_decrypt(Z_krb5_ctx, server_key, 0, 0, &din, &dout);
1674 #elif defined(HAVE_KRB5_CRYPTO_INIT)
1681 ret = krb5_crypto_init(Z_krb5_ctx, server_key, Z_enctype(server_key), &crypto);
1685 ret = krb5_decrypt_ivec(Z_krb5_ctx, crypto, 0, in, 8, &dout, NULL);
1687 krb5_crypto_destroy(Z_krb5_ctx, crypto);
1692 des_ecb_encrypt((C_Block *)in, (C_Block *)out, serv_ksched.s, DES_DECRYPT);
1694 return 0; /* sigh */