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)
118 extern C_Block serv_key;
119 extern Sched serv_ksched;
121 #endif /* HAVE_KRB4 */
123 static Timer *bdump_timer;
124 static int live_socket = -1;
125 static FILE *input, *output;
126 static struct sockaddr_in bdump_sin;
128 static krb5_auth_context bdump_ac;
131 static int cancel_outgoing_dump;
135 int bdump_concurrent;
136 extern char *bdump_version;
137 extern int bdump_auth_proto;
140 * Functions for performing a brain dump between servers.
144 * offer the brain dump to another server
148 bdump_offer(struct sockaddr_in *who)
151 char buf[512], *addr, *lyst[2];
153 int bdump_port = IPPORT_RESERVED - 1;
154 #endif /* !HAVE_KRB4 */
156 zdbug((LOG_DEBUG, "bdump_offer"));
158 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
160 * when using kerberos server-server authentication, we can
161 * use any random local address
163 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
164 if (bdump_socket < 0) {
165 syslog(LOG_ERR,"bdump_offer: socket: %m");
169 memset(&bdump_sin, 0, sizeof(bdump_sin));
170 /* a port field of 0 makes the UNIX
171 * kernel choose an appropriate port/address pair */
173 bdump_sin.sin_port = 0;
174 bdump_sin.sin_addr = my_addr;
175 bdump_sin.sin_family = AF_INET;
176 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
179 syslog(LOG_ERR, "bdump_offer: bind: %m");
184 if (!bdump_sin.sin_port) {
185 unsigned int len = sizeof(bdump_sin);
187 if (getsockname(bdump_socket,
188 (struct sockaddr *) &bdump_sin, &len) < 0) {
189 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
195 #else /* !HAVE_KRB4 */
197 * when not using HAVE_KRB4, we can't use any old port, we use
198 * Internet reserved ports instead (rresvport)
200 bdump_socket = rresvport(&bdump_port);
201 if (bdump_socket < 0) {
202 syslog(LOG_ERR,"bdump_offer: socket: %m");
206 memset(&bdump_sin, 0, sizeof(bdump_sin));
207 bdump_sin.sin_port = htons((unsigned short) bdump_port);
208 bdump_sin.sin_addr = my_addr;
209 bdump_sin.sin_family = AF_INET;
210 #endif /* HAVE_KRB4 */
212 listen(bdump_socket, 1);
214 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
215 FD_SET(bdump_socket, &interesting);
216 nfds = max(bdump_socket, srv_socket) + 1;
218 addr = inet_ntoa(bdump_sin.sin_addr);
219 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
223 retval = ZSetDestAddr(who);
224 if (retval != ZERR_NONE) {
225 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
226 error_message(retval));
230 /* myname is the hostname */
231 /* the class instance is the version number, here it is */
232 /* bdump_version, which is set in main */
233 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
234 ADMIN_BDUMP, myname, "", lyst, 2);
237 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
238 inet_ntoa(bdump_sin.sin_addr),
239 ntohs(bdump_sin.sin_port)));
245 * Accept a connection, and send the brain dump to the other server
251 struct sockaddr_in from;
254 unsigned int fromlen = sizeof(from);
256 #ifdef _POSIX_VERSION
257 struct sigaction action;
259 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
267 /* may be moved into kstuff.c */
268 char instance [INST_SZ];
271 /* may be moved into kstuff.c */
272 krb5_principal principal;
276 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
277 unsigned short fromport;
278 #endif /* HAVE_KRB4 */
281 zdbug((LOG_DEBUG, "bdump_send"));
283 /* accept the connection, and send the brain dump */
284 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
285 if (live_socket < 0) {
286 syslog(LOG_ERR,"bdump_send: accept: %m");
289 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
291 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
294 fromport = ntohs(from.sin_port);
297 #ifdef _POSIX_VERSION
298 sigemptyset(&action.sa_mask);
300 action.sa_handler = SIG_IGN;
301 sigaction(SIGPIPE, &action, NULL);
304 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
307 from.sin_port = srv_addr.sin_port; /* we don't care what port
308 * it came from, and we need to
309 * fake out server_which_server() */
310 server = server_which_server(&from);
312 syslog(LOG_ERR, "bdump_send: unknown server?");
313 server = limbo_server;
316 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
317 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 krb_get_err_text(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));
395 syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
396 error_message(retval));
402 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
404 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
405 error_message(retval));
406 krb5_kt_close(Z_krb5_ctx, kt);
411 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
412 krb5_free_principal(Z_krb5_ctx, principal);
413 krb5_kt_close(Z_krb5_ctx, kt);
415 memset((char *)&k5data, 0, sizeof(krb5_data));
417 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
418 error_message(retval));
423 /* Now send back our auth packet */
425 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
427 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
431 retval = SendKrb5Data(live_socket, &k5data);
433 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
434 error_message(retval));
435 krb5_free_data_contents(Z_krb5_ctx, &k5data);
439 krb5_free_data_contents(Z_krb5_ctx, &k5data);
441 #endif /* HAVE_KRB5 */
444 /* here to krb_rd_req from GetKerberosData candidate for refactoring
445 back into kstuff.c */
446 (void) strcpy(instance, "*"); /* let Kerberos fill it in */
449 memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
450 retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
451 from.sin_addr.s_addr, &kdata, srvtab_file);
453 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
454 SERVER_SERVICE, srvtab_file);
456 if (retval != KSUCCESS) {
457 syslog(LOG_ERR, "bdump_send: getkdata: %s",
458 krb_get_err_text(retval));
462 if (strcmp(kdata.pname, SERVER_SERVICE) ||
463 strcmp(kdata.pinst, SERVER_INSTANCE) ||
464 strcmp(kdata.prealm, ZGetRealm())) {
465 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
466 kdata.pname, kdata.pinst, kdata.prealm);
470 /* authenticate back */
471 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
474 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
475 error_message (retval));
480 #endif /* HAVE_KRB4 */
482 #else /* HAVE_KRB4 || HAVE_KRB5 */
483 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
484 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
488 #endif /* HAVE_KRB4 || HAVE_KRB5 */
489 retval = setup_file_pointers();
491 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
492 error_message(retval));
496 retval = bdump_send_loop(server);
497 if (retval != ZERR_NONE) {
498 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
499 error_message(retval));
503 retval = bdump_recv_loop(server);
504 if (retval != ZERR_NONE) {
505 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
506 error_message(retval));
511 zdbug((LOG_DEBUG, "bdump_send: finished"));
513 if (server != limbo_server) {
514 /* set this guy to be up, and schedule a hello */
515 server->state = SERV_UP;
516 timer_reset(server->timer);
517 server->timer = timer_set_rel(0L, server_timo, server);
520 zdbug((LOG_DEBUG,"cleanup sbd"));
522 shutdown_file_pointers();
524 #ifdef _POSIX_VERSION
525 action.sa_handler = SIG_DFL;
526 sigaction(SIGPIPE, &action, NULL);
528 signal(SIGPIPE, SIG_DFL);
532 /* Now that we are finished dumping, send all the queued packets */
533 server_send_queue(server);
539 bdump_get_v12 (ZNotice_t *notice,
541 struct sockaddr_in *who,
544 struct sockaddr_in from;
547 #ifdef _POSIX_VERSION
548 struct sigaction action;
550 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
554 krb5_principal principal;
556 krb5_ap_rep_enc_part *rep;
562 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
563 int reserved_port = IPPORT_RESERVED - 1;
564 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
569 #ifdef _POSIX_VERSION
571 sigemptyset(&action.sa_mask);
572 action.sa_handler = SIG_IGN;
573 sigaction(SIGPIPE, &action, NULL);
575 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
576 #endif /* _POSIX_VRESION */
578 if (bdump_socket >= 0) {
579 /* We cannot go get a brain dump when someone may
580 potentially be connecting to us (if that other
581 server is the server to whom we are connecting,
582 we will deadlock. so we shut down the listening
583 socket and the timer. */
584 FD_CLR(bdump_socket, &interesting);
588 timer_reset(bdump_timer);
591 retval = extract_sin(notice, &from);
592 if (retval != ZERR_NONE) {
593 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
594 #ifdef _POSIX_VERSION
595 action.sa_handler = SIG_DFL;
596 sigaction(SIGPIPE, &action, NULL);
598 signal(SIGPIPE, SIG_DFL);
604 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
605 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
606 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
607 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
608 ntohs(from.sin_port));
612 live_socket = rresvport(&reserved_port);
613 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
614 live_socket = socket(AF_INET, SOCK_STREAM, 0);
615 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
616 if (live_socket < 0) {
617 syslog(LOG_ERR, "bdump_get: socket: %m");
621 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
622 syslog(LOG_ERR, "bdump_get: connect: %m");
626 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
628 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
630 zdbug((LOG_DEBUG, "bdump_get: connected"));
633 /* Now begin the brain dump. */
634 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
636 syslog(LOG_ERR, "bdump_get: get_tgt failed");
640 switch(bdump_auth_proto) {
642 case 5: /* "client" side */
643 memset((char *)&creds, 0, sizeof(creds));
645 retval = krb5_build_principal(Z_krb5_ctx, &principal,
648 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
651 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
656 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
658 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
659 krb5_free_principal(Z_krb5_ctx, principal);
664 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
665 krb5_free_principal(Z_krb5_ctx, principal);
667 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
668 krb5_free_cred_contents(Z_krb5_ctx, &creds);
673 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
675 krb5_free_cred_contents(Z_krb5_ctx, &creds);
677 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
682 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
684 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
685 krb5_free_creds(Z_krb5_ctx, credsp);
690 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
692 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
693 krb5_free_creds(Z_krb5_ctx, credsp);
698 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
699 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
701 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
702 krb5_free_creds(Z_krb5_ctx, credsp);
707 memset((char *)&data, 0, sizeof(krb5_data));
708 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
709 NULL, credsp, &data);
711 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
712 krb5_free_creds(Z_krb5_ctx, credsp);
716 retval = SendKrb5Data(live_socket, &data);
717 krb5_free_creds(Z_krb5_ctx, credsp);
719 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
720 error_message(retval));
721 krb5_free_data_contents(Z_krb5_ctx, &data);
725 krb5_free_data_contents(Z_krb5_ctx, &data);
726 memset((char *)&data, 0, sizeof(krb5_data));
727 retval = GetKrb5Data(live_socket, &data);
729 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
730 error_message(retval));
734 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
736 memset((char *)&data, 0, sizeof(krb5_data));
738 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
739 error_message(retval));
747 /* send an authenticator */
748 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
751 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
755 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
757 /* get his authenticator */
758 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
759 SERVER_SERVICE, srvtab_file);
760 if (retval != KSUCCESS) {
761 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
766 if (strcmp(kdata.pname, SERVER_SERVICE) ||
767 strcmp(kdata.pinst, SERVER_INSTANCE) ||
768 strcmp(kdata.prealm, ZGetRealm())) {
769 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
770 kdata.pname, kdata.pinst,kdata.prealm);
775 #endif /* HAVE_KRB4 */
777 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
778 retval = setup_file_pointers();
780 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
781 error_message (retval));
785 retval = bdump_recv_loop(server);
786 if (retval != ZERR_NONE) {
787 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
788 error_message(retval));
792 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
793 retval = bdump_send_loop(server);
794 if (retval != ZERR_NONE) {
795 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
796 error_message(retval));
801 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
803 /* set this guy to be up, and schedule a hello */
804 server->state = SERV_UP;
805 timer_reset(server->timer);
806 server->timer = timer_set_rel(0L, server_timo, server);
809 zdbug((LOG_DEBUG,"cleanup gbd"));
811 shutdown_file_pointers();
812 #ifdef _POSIX_VERSION
813 action.sa_handler = SIG_DFL;
814 sigaction(SIGPIPE, &action, NULL);
816 signal(SIGPIPE, SIG_DFL);
820 /* Now that we are finished dumping, send all the queued packets */
821 server_send_queue(server);
827 bdump_get(ZNotice_t *notice,
829 struct sockaddr_in *who,
832 void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *);
838 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
839 notice->z_class_inst, inet_ntoa(who->sin_addr));
842 if (strcmp (notice->z_class_inst, "1.2") == 0)
843 proc = bdump_get_v12;
846 (*proc)(notice, auth, who, server);
849 "bdump_get: Incompatible bdump version '%s' from %s",
850 notice->z_class_inst,
851 inet_ntoa(who->sin_addr));
856 * Send a list off as the specified notice
860 bdump_send_list_tcp(ZNotice_Kind_t kind,
861 struct sockaddr_in *addr,
871 char *pack, addrbuf[100];
876 memset (¬ice, 0, sizeof(notice));
878 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
879 (unsigned char *) &addr->sin_addr,
880 sizeof(struct in_addr));
881 if (retval != ZERR_NONE)
883 notice.z_kind = kind;
885 notice.z_port = addr->sin_port;
886 notice.z_class = class_name;
887 notice.z_class_inst = inst;
888 notice.z_opcode = opcode;
889 notice.z_sender = sender;
890 notice.z_recipient = recip;
891 notice.z_default_format = "";
892 notice.z_num_other_fields = 1;
893 notice.z_other_fields[0] = addrbuf;
895 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
896 if (retval != ZERR_NONE)
901 krb5_data indata, outmsg;
902 indata.length=packlen;
904 memset(&outmsg, 0, sizeof(krb5_data));
905 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
906 if (retval != ZERR_NONE)
908 if (outmsg.length > Z_MAXPKTLEN) {
909 syslog(LOG_ERR, "bsl: encrypted packet is too large");
912 packlen = outmsg.length;
914 pack=malloc(packlen);
917 memcpy(pack, outmsg.data, packlen);
918 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
922 length = htons((u_short) packlen);
924 count = net_write(output, (char *) &length, sizeof(length));
925 if (count != sizeof(length)) {
930 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
931 sizeof(length), count);
933 return(ZSRV_PKSHORT);
937 count = net_write(output, pack, packlen);
938 if (count != packlen) {
943 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
946 return(ZSRV_PKSHORT);
954 shutdown_file_pointers(void)
964 if (live_socket >= 0) {
969 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
976 cleanup(Server *server)
978 #ifdef _POSIX_VERSION
979 struct sigaction action;
983 zdbug((LOG_DEBUG, "bdump cleanup"));
985 if (server != limbo_server) {
986 server->state = SERV_DEAD;
987 timer_reset(server->timer);
988 server->timer = timer_set_rel(0L, server_timo, server);
990 shutdown_file_pointers ();
991 #ifdef _POSIX_VERSION
993 sigemptyset(&action.sa_mask);
994 action.sa_handler = SIG_DFL;
995 sigaction(SIGPIPE,&action, NULL);
997 signal(SIGPIPE, SIG_DFL);
998 #endif /* _POSIX_VERSION */
1000 server->dumping = 0;
1007 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
1008 * at least INST_SZ bytes long. */
1009 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
1012 /* have they expired ? */
1013 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1014 /* +15 for leeway */
1016 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1017 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1021 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
1022 "krbtgt", ZGetRealm(),
1023 TKTLIFETIME, srvtab_file);
1024 if (retval != KSUCCESS) {
1025 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1026 krb_get_err_text(retval));
1033 #ifndef NOENCRYPTION
1034 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1035 ZGetRealm(), 0 /*kvno*/,
1036 srvtab_file, (char *)serv_key);
1037 if (retval != KSUCCESS) {
1038 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1039 krb_get_err_text(retval));
1042 des_key_sched(serv_key, serv_ksched.s);
1043 #endif /* !NOENCRYPTION */
1047 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1049 krb5_get_init_creds_opt opt;
1051 krb5_principal principal;
1053 memset(&cred, 0, sizeof(cred));
1055 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1056 strlen(ZGetRealm()),
1058 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1061 krb5_free_principal(Z_krb5_ctx, principal);
1065 krb5_get_init_creds_opt_init (&opt);
1066 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1068 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1069 if (retval) return(1);
1071 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1078 krb5_free_principal(Z_krb5_ctx, principal);
1079 krb5_kt_close(Z_krb5_ctx, kt);
1080 if (retval) return(1);
1082 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1083 if (retval) return(1);
1085 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1086 if (retval) return(1);
1090 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1095 #endif /* HAVE_KRB4 */
1098 * The braindump offer wasn't taken, so we retract it.
1103 close_bdump(void *arg)
1105 if (bdump_socket >= 0) {
1106 FD_CLR(bdump_socket, &interesting);
1107 close(bdump_socket);
1108 nfds = srv_socket + 1;
1111 zdbug((LOG_DEBUG, "bdump not used"));
1115 zdbug((LOG_DEBUG, "bdump not open"));
1122 * Start receiving instruction notices from the brain dump socket
1126 bdump_recv_loop(Server *server)
1132 Client *client = NULL;
1133 struct sockaddr_in who;
1135 unsigned char buf[512];
1138 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1143 #endif /* HAVE_KRB4 */
1144 ZRealm *realm = NULL;
1147 zdbug((LOG_DEBUG, "bdump recv loop"));
1150 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1152 if (packets_waiting()) {
1153 /* A non-braindump packet is waiting; handle it. */
1155 bdump_concurrent = 1;
1157 bdump_concurrent = 0;
1160 len = sizeof(packet);
1161 retval = get_packet(packet, len, &len);
1162 if (retval != ZERR_NONE) {
1163 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1172 memset(&out, 0, sizeof(krb5_data));
1173 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1174 if (retval != ZERR_NONE) {
1175 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1178 memcpy(packet, out.data, out.length);
1180 krb5_free_data_contents(Z_krb5_ctx, &out);
1184 retval = ZParseNotice(packet, len, ¬ice);
1185 if (retval != ZERR_NONE) {
1186 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1191 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1192 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1193 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1194 notice.z_recipient);
1197 if (notice.z_num_other_fields >= 1) {
1198 retval = ZReadAscii(notice.z_other_fields[0],
1199 strlen(notice.z_other_fields[0]),
1200 (unsigned char *) &who.sin_addr,
1201 sizeof(struct in_addr));
1202 if (retval != ZERR_NONE) {
1203 syslog(LOG_ERR, "brl zreadascii failed: %s",
1204 error_message(retval));
1208 who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
1210 who.sin_family = AF_INET;
1211 who.sin_port = notice.z_port;
1213 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1214 /* end of brain dump */
1216 } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
1217 /* get a realm from the message */
1218 realm = realm_get_realm_by_name(notice.z_message);
1220 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
1223 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1224 /* 1 = tell it we are authentic */
1225 retval = ulogin_dispatch(¬ice, 1, &who, server);
1226 if (retval != ZERR_NONE) {
1227 syslog(LOG_ERR, "brl ul_disp failed: %s",
1228 error_message(retval));
1231 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1233 notice.z_port = htons((u_short) atoi(notice.z_message));
1234 retval = client_register(¬ice, &who.sin_addr, &client, 0);
1235 if (retval != ZERR_NONE) {
1236 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
1240 client->session_keyblock = NULL;
1241 if (*notice.z_class_inst) {
1242 /* check out this session key I found */
1243 cp = notice.z_message + strlen(notice.z_message) + 1;
1245 /* ****ing netascii; this is an encrypted DES keyblock
1246 XXX this code should be conditionalized for server
1248 retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1250 &client->session_keyblock);
1252 syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1253 error_message(retval));
1256 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1257 if (retval != ZERR_NONE) {
1258 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1259 error_message(retval), cp);
1261 des_ecb_encrypt(cblock, Z_keydata(client->session_keyblock),
1262 serv_ksched.s, DES_DECRYPT);
1264 } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
1265 retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen);
1266 if (retval != ZERR_NONE) {
1267 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1268 error_message(retval), cp);
1270 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1271 ntohl(*(krb5_enctype *)&buf[0]),
1272 ntohl(*(u_int32_t *)&buf[4]),
1273 &client->session_keyblock);
1275 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1276 error_message(retval));
1279 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1280 Z_keylen(client->session_keyblock));
1286 memset(client->session_key, 0, sizeof(C_Block));
1287 if (*notice.z_class_inst) {
1288 /* a C_Block is there */
1289 cp = notice.z_message + strlen(notice.z_message) + 1;
1290 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1291 if (retval != ZERR_NONE) {
1292 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1293 error_message(retval), cp);
1296 memcpy(cblock, client->session_key, sizeof(C_Block));
1298 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1303 #endif /* HAVE_KRB4 */
1305 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1306 /* a subscription packet */
1308 syslog(LOG_ERR, "brl no client");
1311 retval = subscr_subscribe(client, ¬ice, server);
1312 if (retval != ZERR_NONE) {
1313 syslog(LOG_WARNING, "brl subscr failed: %s",
1314 error_message(retval));
1317 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1318 /* add a subscription for a realm */
1320 retval = subscr_realm(realm, ¬ice);
1321 if (retval != ZERR_NONE) {
1322 syslog(LOG_WARNING, "brl subscr failed: %s",
1323 error_message(retval));
1327 /* Other side tried to send us subs for a realm we didn't
1328 know about, and so we drop them silently */
1331 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1332 return ZSRV_UNKNOWNOPCODE;
1338 * Send all the state to the peer.
1342 bdump_send_loop(Server *server)
1347 zdbug((LOG_DEBUG, "bdump send loop"));
1350 retval = uloc_send_locations();
1351 if (retval != ZERR_NONE)
1353 retval = client_send_clients();
1354 if (retval != ZERR_NONE)
1356 retval = realm_send_realms();
1357 if (retval != ZERR_NONE)
1363 * Send a sync indicating end of this host
1372 zdbug((LOG_DEBUG, "send_done"));
1374 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1375 "", ADMIN_DONE, myname, "", NULL, 0);
1381 * Send a list off as the specified notice
1385 send_list(ZNotice_Kind_t kind,
1400 memset (¬ice, 0, sizeof(notice));
1402 notice.z_kind = kind;
1403 notice.z_port = port;
1404 notice.z_class = class_name;
1405 notice.z_class_inst = inst;
1406 notice.z_opcode = opcode;
1407 notice.z_sender = sender;
1408 notice.z_recipient = recip;
1409 notice.z_default_format = "";
1410 notice.z_num_other_fields = 0;
1412 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1413 if (retval != ZERR_NONE) {
1414 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1418 retval = ZSendPacket(pack, packlen, 0);
1419 if (retval != ZERR_NONE)
1420 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1426 * Send a message off as the specified notice, via TCP
1430 send_normal_tcp(ZNotice_Kind_t kind,
1446 memset (¬ice, 0, sizeof(notice));
1448 notice.z_kind = kind;
1449 notice.z_port = port;
1450 notice.z_class = class_name;
1451 notice.z_class_inst = inst;
1452 notice.z_opcode = opcode;
1453 notice.z_sender = sender;
1454 notice.z_recipient = recip;
1455 notice.z_default_format = "";
1456 notice.z_message = message;
1457 notice.z_message_len = len;
1458 notice.z_num_other_fields = 0;
1460 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1461 if (retval != ZERR_NONE) {
1462 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1468 krb5_data indata, outmsg;
1469 indata.length=packlen;
1471 memset(&outmsg, 0, sizeof(krb5_data));
1472 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1473 if (retval != ZERR_NONE)
1475 if (outmsg.length > Z_MAXPKTLEN) {
1476 syslog(LOG_ERR, "sn: encrypted packet is too large");
1479 packlen = outmsg.length;
1481 pack=malloc(packlen);
1484 memcpy(pack, outmsg.data, packlen);
1485 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1489 length = htons((u_short) packlen);
1491 count = net_write(output, (char *) &length, sizeof(length));
1492 if (count != sizeof(length)) {
1494 syslog(LOG_WARNING, "snt xmit/len: %m");
1498 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1503 count = net_write(output, pack, packlen);
1504 if (count != packlen) {
1506 syslog(LOG_WARNING, "snt xmit: %m");
1510 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1520 * get a packet from the TCP socket
1521 * return 0 if successful, error code else
1525 get_packet(void *packet, int len, int *retlen)
1530 result = net_read(input, (char *) &length, sizeof(u_short));
1531 if (result < sizeof(short)) {
1535 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1541 length = ntohs(length);
1543 return ZSRV_BUFSHORT;
1544 result = net_read(input, packet, (int) length);
1545 if (result < length) {
1549 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1558 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1560 char *cp = notice->z_message;
1564 if (!notice->z_message_len || *buf == '\0') {
1566 zdbug((LOG_DEBUG,"no addr"));
1568 return ZSRV_PKSHORT;
1570 target->sin_addr.s_addr = inet_addr(cp);
1572 cp += (strlen(cp) + 1); /* past the null */
1573 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1575 zdbug((LOG_DEBUG, "no port"));
1577 return(ZSRV_PKSHORT);
1579 target->sin_port = htons((u_short) atoi(cp));
1580 target->sin_family = AF_INET;
1585 net_read(FILE *f, char *buf, int len)
1592 cc = fread(buf, 1, len, f);
1609 net_write(FILE *f, char *buf, int len)
1614 cc = fwrite (buf, 1, wrlen, f);
1619 } while (wrlen > 0);
1624 setup_file_pointers (void)
1628 input = fdopen (live_socket, "r");
1632 fd = dup (live_socket);
1635 output = fdopen (fd, "w");