1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains functions for dumping server state between servers.
4 * Created by: John T. Kohl
6 * $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/bdump.c,v $
10 * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, see the file
15 #include <zephyr/mit-copyright.h>
17 #include <sys/socket.h>
21 static const char rcsid_bdump_c[] = "$Id$";
25 * External functions are:
27 * void bdump_offer(who)
28 * strut sockaddr_in *who;
32 * void bdump_get(notice, auth, who, server)
35 * struct sockaddr_in *who;
38 * Code_t bdump_send_list_tcp(kind, port, class, inst, opcode,
39 * sender, recip, lyst, num)
40 * ZNotice_Kind_t kind;
42 * char *class, *inst, *opcode, *sender, *recip;
47 #if defined(HAVE_KRB5) && 0
48 int krb5_init_keyblock(krb5_context context,
58 key=malloc(sizeof(*key));
59 memset(key, 0, sizeof(*key));
60 ret = krb5_enctype_keysize(context, type, &len);
65 krb5_set_error_string(context, "Encryption key %d is %lu bytes "
66 "long, %lu was passed in",
67 type, (unsigned long)len, (unsigned long)size);
68 return KRB5_PROG_ETYPE_NOSUPP;
71 ret = krb5_data_alloc(&key->keyvalue, len);
73 krb5_set_error_string(context, "malloc failed: %lu",
84 static void close_bdump(void* arg);
85 static Code_t bdump_send_loop(Server *server);
86 static Code_t bdump_recv_loop(Server *server);
87 static void bdump_get_v12(ZNotice_t *, int, struct sockaddr_in *,
89 static Code_t get_packet(void *packet, int len, int *retlen);
90 static Code_t extract_sin(ZNotice_t *notice, struct sockaddr_in *target);
91 static Code_t send_done(void);
92 static Code_t send_list(ZNotice_Kind_t kind, int port, char *class_name,
93 char *inst, char *opcode, char *sender,
94 char *recip, char **lyst, int num);
95 static Code_t send_normal_tcp(ZNotice_Kind_t kind, int port,
97 char *inst, char *opcode, char *sender,
98 char *recip, char *message, int len);
99 static int net_read(FILE *f, char *buf, int len);
100 static int net_write(FILE *f, char *buf, int len);
101 static int setup_file_pointers(void);
102 static void shutdown_file_pointers(void);
103 static void cleanup(Server *server);
106 static long ticket5_time;
107 #define TKT5LIFETIME 8*60*60
108 #define tkt5_lifetime(val) (val)
112 static long ticket_time;
114 #define TKTLIFETIME 120
115 #define tkt_lifetime(val) ((long) val * 5L * 60L)
117 extern C_Block serv_key;
118 extern Sched serv_ksched;
119 #endif /* HAVE_KRB4 */
121 static Timer *bdump_timer;
122 static int live_socket = -1;
123 static FILE *input, *output;
124 static struct sockaddr_in bdump_sin;
126 static krb5_auth_context bdump_ac;
130 int bdump_concurrent;
131 extern char *bdump_version;
132 extern int bdump_auth_proto;
135 * Functions for performing a brain dump between servers.
139 * offer the brain dump to another server
143 bdump_offer(struct sockaddr_in *who)
146 char buf[512], *addr, *lyst[2];
148 int bdump_port = IPPORT_RESERVED - 1;
149 #endif /* !HAVE_KRB4 */
151 zdbug((LOG_DEBUG, "bdump_offer"));
153 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
155 * when using kerberos server-server authentication, we can
156 * use any random local address
158 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
159 if (bdump_socket < 0) {
160 syslog(LOG_ERR,"bdump_offer: socket: %m");
164 memset(&bdump_sin, 0, sizeof(bdump_sin));
165 /* a port field of 0 makes the UNIX
166 * kernel choose an appropriate port/address pair */
168 bdump_sin.sin_port = 0;
169 bdump_sin.sin_addr = my_addr;
170 bdump_sin.sin_family = AF_INET;
171 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
174 syslog(LOG_ERR, "bdump_offer: bind: %m");
179 if (!bdump_sin.sin_port) {
180 unsigned int len = sizeof(bdump_sin);
182 if (getsockname(bdump_socket,
183 (struct sockaddr *) &bdump_sin, &len) < 0) {
184 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
190 #else /* !HAVE_KRB4 */
192 * when not using HAVE_KRB4, we can't use any old port, we use
193 * Internet reserved ports instead (rresvport)
195 bdump_socket = rresvport(&bdump_port);
196 if (bdump_socket < 0) {
197 syslog(LOG_ERR,"bdump_offer: socket: %m");
201 memset(&bdump_sin, 0, sizeof(bdump_sin));
202 bdump_sin.sin_port = htons((unsigned short) bdump_port);
203 bdump_sin.sin_addr = my_addr;
204 bdump_sin.sin_family = AF_INET;
205 #endif /* HAVE_KRB4 */
207 listen(bdump_socket, 1);
209 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
210 FD_SET(bdump_socket, &interesting);
211 nfds = max(bdump_socket, srv_socket) + 1;
213 addr = inet_ntoa(bdump_sin.sin_addr);
214 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
218 retval = ZSetDestAddr(who);
219 if (retval != ZERR_NONE) {
220 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
221 error_message(retval));
225 /* myname is the hostname */
226 /* the class instance is the version number, here it is */
227 /* bdump_version, which is set in main */
228 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
229 ADMIN_BDUMP, myname, "", lyst, 2);
231 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
232 inet_ntoa(bdump_sin.sin_addr),
233 ntohs(bdump_sin.sin_port)));
238 * Accept a connection, and send the brain dump to the other server
244 struct sockaddr_in from;
247 unsigned int fromlen = sizeof(from);
249 #ifdef _POSIX_VERSION
250 struct sigaction action;
252 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
260 /* may be moved into kstuff.c */
261 char instance [INST_SZ];
264 /* may be moved into kstuff.c */
265 krb5_principal principal;
269 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
270 unsigned short fromport;
271 #endif /* HAVE_KRB4 */
273 zdbug((LOG_DEBUG, "bdump_send"));
275 /* accept the connection, and send the brain dump */
276 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
277 if (live_socket < 0) {
278 syslog(LOG_ERR,"bdump_send: accept: %m");
281 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
283 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
286 fromport = ntohs(from.sin_port);
289 #ifdef _POSIX_VERSION
290 sigemptyset(&action.sa_mask);
292 action.sa_handler = SIG_IGN;
293 sigaction(SIGPIPE, &action, NULL);
296 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
299 from.sin_port = srv_addr.sin_port; /* we don't care what port
300 * it came from, and we need to
301 * fake out server_which_server() */
302 server = server_which_server(&from);
304 syslog(LOG_ERR, "bdump_send: unknown server?");
305 server = limbo_server;
308 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
309 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
314 if (bdump_socket >= 0) {
315 /* shut down the listening socket and the timer. */
316 FD_CLR(bdump_socket, &interesting);
318 nfds = srv_socket + 1;
320 timer_reset(bdump_timer);
323 /* Now begin the brain dump. */
324 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
325 retval = ReadKerberosData(live_socket, &len, &data, &proto);
328 syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
329 krb_get_err_text(retval));
334 syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
337 syslog(LOG_ERR, "bdump_send: get_tgt failed");
346 retval = krb5_build_principal(Z_krb5_ctx, &principal,
349 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
352 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
358 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
360 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
365 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
367 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
372 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
373 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
375 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
380 /* Get the "client" krb_ap_req */
382 memset((char *)&k5data, 0, sizeof(krb5_data));
386 syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
387 error_message(retval));
393 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
395 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
396 error_message(retval));
397 krb5_kt_close(Z_krb5_ctx, kt);
402 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
403 krb5_free_principal(Z_krb5_ctx, principal);
404 krb5_kt_close(Z_krb5_ctx, kt);
406 memset((char *)&k5data, 0, sizeof(krb5_data));
408 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
409 error_message(retval));
414 /* Now send back our auth packet */
416 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
418 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
422 retval = SendKrb5Data(live_socket, &k5data);
424 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
425 error_message(retval));
426 krb5_free_data_contents(Z_krb5_ctx, &k5data);
430 krb5_free_data_contents(Z_krb5_ctx, &k5data);
432 #endif /* HAVE_KRB5 */
435 /* here to krb_rd_req from GetKerberosData candidate for refactoring
436 back into kstuff.c */
437 (void) strcpy(instance, "*"); /* let Kerberos fill it in */
440 memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
441 retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
442 from.sin_addr.s_addr, &kdata, srvtab_file);
444 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
445 SERVER_SERVICE, srvtab_file);
447 if (retval != KSUCCESS) {
448 syslog(LOG_ERR, "bdump_send: getkdata: %s",
449 krb_get_err_text(retval));
453 if (strcmp(kdata.pname, SERVER_SERVICE) ||
454 strcmp(kdata.pinst, SERVER_INSTANCE) ||
455 strcmp(kdata.prealm, ZGetRealm())) {
456 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
457 kdata.pname, kdata.pinst, kdata.prealm);
461 /* authenticate back */
462 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
465 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
466 error_message (retval));
471 #endif /* HAVE_KRB4 */
473 #else /* HAVE_KRB4 || HAVE_KRB5 */
474 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
475 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
479 #endif /* HAVE_KRB4 || HAVE_KRB5 */
480 retval = setup_file_pointers();
482 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
483 error_message(retval));
487 retval = bdump_send_loop(server);
488 if (retval != ZERR_NONE) {
489 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
490 error_message(retval));
494 retval = bdump_recv_loop(server);
495 if (retval != ZERR_NONE) {
496 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
497 error_message(retval));
502 zdbug((LOG_DEBUG, "bdump_send: finished"));
504 if (server != limbo_server) {
505 /* set this guy to be up, and schedule a hello */
506 server->state = SERV_UP;
507 timer_reset(server->timer);
508 server->timer = timer_set_rel(0L, server_timo, server);
511 shutdown_file_pointers();
513 #ifdef _POSIX_VERSION
514 action.sa_handler = SIG_DFL;
515 sigaction(SIGPIPE, &action, NULL);
517 signal(SIGPIPE, SIG_DFL);
521 /* Now that we are finished dumping, send all the queued packets */
522 server_send_queue(server);
528 bdump_get_v12 (ZNotice_t *notice,
530 struct sockaddr_in *who,
533 struct sockaddr_in from;
536 #ifdef _POSIX_VERSION
537 struct sigaction action;
539 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
543 krb5_principal principal;
545 krb5_ap_rep_enc_part *rep;
551 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
552 int reserved_port = IPPORT_RESERVED - 1;
553 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
558 #ifdef _POSIX_VERSION
560 sigemptyset(&action.sa_mask);
561 action.sa_handler = SIG_IGN;
562 sigaction(SIGPIPE, &action, NULL);
564 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
565 #endif /* _POSIX_VRESION */
567 if (bdump_socket >= 0) {
568 /* We cannot go get a brain dump when someone may
569 potentially be connecting to us (if that other
570 server is the server to whom we are connecting,
571 we will deadlock. so we shut down the listening
572 socket and the timer. */
573 FD_CLR(bdump_socket, &interesting);
577 timer_reset(bdump_timer);
580 retval = extract_sin(notice, &from);
581 if (retval != ZERR_NONE) {
582 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
583 #ifdef _POSIX_VERSION
584 action.sa_handler = SIG_DFL;
585 sigaction(SIGPIPE, &action, NULL);
587 signal(SIGPIPE, SIG_DFL);
593 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
594 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
595 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
596 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
597 ntohs(from.sin_port));
601 live_socket = rresvport(&reserved_port);
602 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
603 live_socket = socket(AF_INET, SOCK_STREAM, 0);
604 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
605 if (live_socket < 0) {
606 syslog(LOG_ERR, "bdump_get: socket: %m");
610 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
611 syslog(LOG_ERR, "bdump_get: connect: %m");
615 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
617 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
619 zdbug((LOG_DEBUG, "bdump_get: connected"));
621 /* Now begin the brain dump. */
622 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
624 syslog(LOG_ERR, "bdump_get: get_tgt failed");
628 switch(bdump_auth_proto) {
630 case 5: /* "client" side */
631 memset((char *)&creds, 0, sizeof(creds));
633 retval = krb5_build_principal(Z_krb5_ctx, &principal,
636 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
639 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
644 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
646 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
647 krb5_free_principal(Z_krb5_ctx, principal);
652 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
653 krb5_free_principal(Z_krb5_ctx, principal);
655 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
656 krb5_free_cred_contents(Z_krb5_ctx, &creds);
661 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
663 krb5_free_cred_contents(Z_krb5_ctx, &creds);
665 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
670 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
672 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
673 krb5_free_creds(Z_krb5_ctx, credsp);
678 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
680 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
681 krb5_free_creds(Z_krb5_ctx, credsp);
686 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
687 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
689 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
690 krb5_free_creds(Z_krb5_ctx, credsp);
695 memset((char *)&data, 0, sizeof(krb5_data));
696 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
697 NULL, credsp, &data);
699 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
700 krb5_free_creds(Z_krb5_ctx, credsp);
704 retval = SendKrb5Data(live_socket, &data);
705 krb5_free_creds(Z_krb5_ctx, credsp);
707 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
708 error_message(retval));
709 krb5_free_data_contents(Z_krb5_ctx, &data);
713 krb5_free_data_contents(Z_krb5_ctx, &data);
714 memset((char *)&data, 0, sizeof(krb5_data));
715 retval = GetKrb5Data(live_socket, &data);
717 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
718 error_message(retval));
722 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
724 memset((char *)&data, 0, sizeof(krb5_data));
726 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
727 error_message(retval));
735 /* send an authenticator */
736 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
739 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
743 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
745 /* get his authenticator */
746 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
747 SERVER_SERVICE, srvtab_file);
748 if (retval != KSUCCESS) {
749 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
754 if (strcmp(kdata.pname, SERVER_SERVICE) ||
755 strcmp(kdata.pinst, SERVER_INSTANCE) ||
756 strcmp(kdata.prealm, ZGetRealm())) {
757 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
758 kdata.pname, kdata.pinst,kdata.prealm);
763 #endif /* HAVE_KRB4 */
765 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
766 retval = setup_file_pointers();
768 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
769 error_message (retval));
773 retval = bdump_recv_loop(server);
774 if (retval != ZERR_NONE) {
775 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
776 error_message(retval));
780 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
781 retval = bdump_send_loop(server);
782 if (retval != ZERR_NONE) {
783 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
784 error_message(retval));
789 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
791 /* set this guy to be up, and schedule a hello */
792 server->state = SERV_UP;
793 timer_reset(server->timer);
794 server->timer = timer_set_rel(0L, server_timo, server);
797 zdbug((LOG_DEBUG,"cleanup gbd"));
799 shutdown_file_pointers();
800 #ifdef _POSIX_VERSION
801 action.sa_handler = SIG_DFL;
802 sigaction(SIGPIPE, &action, NULL);
804 signal(SIGPIPE, SIG_DFL);
808 /* Now that we are finished dumping, send all the queued packets */
809 server_send_queue(server);
815 bdump_get(ZNotice_t *notice,
817 struct sockaddr_in *who,
820 void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *);
825 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
826 notice->z_class_inst, inet_ntoa(who->sin_addr));
829 if (strcmp (notice->z_class_inst, "1.2") == 0)
830 proc = bdump_get_v12;
833 (*proc)(notice, auth, who, server);
836 "bdump_get: Incompatible bdump version '%s' from %s",
837 notice->z_class_inst,
838 inet_ntoa(who->sin_addr));
843 * Send a list off as the specified notice
847 bdump_send_list_tcp(ZNotice_Kind_t kind,
848 struct sockaddr_in *addr,
858 char *pack, addrbuf[100];
863 memset (¬ice, 0, sizeof(notice));
865 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
866 (unsigned char *) &addr->sin_addr,
867 sizeof(struct in_addr));
868 if (retval != ZERR_NONE)
870 notice.z_kind = kind;
872 notice.z_port = addr->sin_port;
873 notice.z_class = class_name;
874 notice.z_class_inst = inst;
875 notice.z_opcode = opcode;
876 notice.z_sender = sender;
877 notice.z_recipient = recip;
878 notice.z_default_format = "";
879 notice.z_num_other_fields = 1;
880 notice.z_other_fields[0] = addrbuf;
882 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
883 if (retval != ZERR_NONE)
888 krb5_data indata, outmsg;
889 indata.length=packlen;
891 memset(&outmsg, 0, sizeof(krb5_data));
892 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
893 if (retval != ZERR_NONE)
895 if (outmsg.length > Z_MAXPKTLEN) {
896 syslog(LOG_ERR, "bsl: encrypted packet is too large");
899 packlen = outmsg.length;
901 pack=malloc(packlen);
904 memcpy(pack, outmsg.data, packlen);
905 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
909 length = htons((u_short) packlen);
911 count = net_write(output, (char *) &length, sizeof(length));
912 if (count != sizeof(length)) {
917 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
918 sizeof(length), count);
920 return(ZSRV_PKSHORT);
924 count = net_write(output, pack, packlen);
925 if (count != packlen) {
930 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
933 return(ZSRV_PKSHORT);
941 shutdown_file_pointers(void)
951 if (live_socket >= 0) {
956 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
963 cleanup(Server *server)
965 #ifdef _POSIX_VERSION
966 struct sigaction action;
969 zdbug((LOG_DEBUG, "bdump cleanup"));
971 if (server != limbo_server) {
972 server->state = SERV_DEAD;
973 timer_reset(server->timer);
974 server->timer = timer_set_rel(0L, server_timo, server);
976 shutdown_file_pointers ();
977 #ifdef _POSIX_VERSION
979 sigemptyset(&action.sa_mask);
980 action.sa_handler = SIG_DFL;
981 sigaction(SIGPIPE,&action, NULL);
983 signal(SIGPIPE, SIG_DFL);
984 #endif /* _POSIX_VERSION */
993 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
994 * at least INST_SZ bytes long. */
995 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
998 /* have they expired ? */
999 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1000 /* +15 for leeway */
1002 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1003 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1007 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
1008 "krbtgt", ZGetRealm(),
1009 TKTLIFETIME, srvtab_file);
1010 if (retval != KSUCCESS) {
1011 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1012 krb_get_err_text(retval));
1019 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1020 ZGetRealm(), 0 /*kvno*/,
1021 srvtab_file, (char *)serv_key);
1022 if (retval != KSUCCESS) {
1023 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1024 krb_get_err_text(retval));
1027 des_key_sched(serv_key, serv_ksched.s);
1031 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1033 krb5_get_init_creds_opt opt;
1035 krb5_principal principal;
1037 memset(&cred, 0, sizeof(cred));
1039 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1040 strlen(ZGetRealm()),
1042 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1045 krb5_free_principal(Z_krb5_ctx, principal);
1049 krb5_get_init_creds_opt_init (&opt);
1050 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1052 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1053 if (retval) return(1);
1055 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1062 krb5_free_principal(Z_krb5_ctx, principal);
1063 krb5_kt_close(Z_krb5_ctx, kt);
1064 if (retval) return(1);
1066 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1067 if (retval) return(1);
1069 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1070 if (retval) return(1);
1074 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1079 #endif /* HAVE_KRB4 */
1082 * The braindump offer wasn't taken, so we retract it.
1087 close_bdump(void *arg)
1089 if (bdump_socket >= 0) {
1090 FD_CLR(bdump_socket, &interesting);
1091 close(bdump_socket);
1092 nfds = srv_socket + 1;
1095 zdbug((LOG_DEBUG, "bdump not used"));
1097 zdbug((LOG_DEBUG, "bdump not open"));
1103 * Start receiving instruction notices from the brain dump socket
1107 bdump_recv_loop(Server *server)
1113 Client *client = NULL;
1114 struct sockaddr_in who;
1116 unsigned char buf[512];
1119 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1124 #endif /* HAVE_KRB4 */
1125 ZRealm *realm = NULL;
1127 zdbug((LOG_DEBUG, "bdump recv loop"));
1129 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1131 if (packets_waiting()) {
1132 /* A non-braindump packet is waiting; handle it. */
1134 bdump_concurrent = 1;
1136 bdump_concurrent = 0;
1139 len = sizeof(packet);
1140 retval = get_packet(packet, len, &len);
1141 if (retval != ZERR_NONE) {
1142 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1151 memset(&out, 0, sizeof(krb5_data));
1152 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1153 if (retval != ZERR_NONE) {
1154 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1157 memcpy(packet, out.data, out.length);
1159 krb5_free_data_contents(Z_krb5_ctx, &out);
1163 retval = ZParseNotice(packet, len, ¬ice);
1164 if (retval != ZERR_NONE) {
1165 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1170 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1171 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1172 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1173 notice.z_recipient);
1176 if (notice.z_num_other_fields >= 1) {
1177 retval = ZReadAscii(notice.z_other_fields[0],
1178 strlen(notice.z_other_fields[0]),
1179 (unsigned char *) &who.sin_addr,
1180 sizeof(struct in_addr));
1181 if (retval != ZERR_NONE) {
1182 syslog(LOG_ERR, "brl zreadascii failed: %s",
1183 error_message(retval));
1187 who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
1189 who.sin_family = AF_INET;
1190 who.sin_port = notice.z_port;
1192 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1193 /* end of brain dump */
1195 } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
1196 /* get a realm from the message */
1197 realm = realm_get_realm_by_name(notice.z_message);
1199 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
1202 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1203 /* 1 = tell it we are authentic */
1204 retval = ulogin_dispatch(¬ice, 1, &who, server);
1205 if (retval != ZERR_NONE) {
1206 syslog(LOG_ERR, "brl ul_disp failed: %s",
1207 error_message(retval));
1210 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1212 notice.z_port = htons((u_short) atoi(notice.z_message));
1213 retval = client_register(¬ice, &who.sin_addr, &client, 0);
1214 if (retval != ZERR_NONE) {
1215 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
1219 client->session_keyblock = NULL;
1220 if (*notice.z_class_inst) {
1221 /* check out this session key I found */
1222 cp = notice.z_message + strlen(notice.z_message) + 1;
1224 /* ****ing netascii; this is an encrypted DES keyblock
1225 XXX this code should be conditionalized for server
1227 retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1229 &client->session_keyblock);
1231 syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1232 error_message(retval));
1235 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1236 if (retval != ZERR_NONE) {
1237 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1238 error_message(retval), cp);
1240 des_ecb_encrypt((C_Block *)cblock, (C_Block *)Z_keydata(client->session_keyblock),
1241 serv_ksched.s, DES_DECRYPT);
1243 } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
1244 retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen);
1245 if (retval != ZERR_NONE) {
1246 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1247 error_message(retval), cp);
1249 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1250 ntohl(*(krb5_enctype *)&buf[0]),
1251 ntohl(*(u_int32_t *)&buf[4]),
1252 &client->session_keyblock);
1254 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1255 error_message(retval));
1258 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1259 Z_keylen(client->session_keyblock));
1265 memset(client->session_key, 0, sizeof(C_Block));
1266 if (*notice.z_class_inst) {
1267 /* a C_Block is there */
1268 cp = notice.z_message + strlen(notice.z_message) + 1;
1269 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1270 if (retval != ZERR_NONE) {
1271 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1272 error_message(retval), cp);
1274 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1278 #endif /* HAVE_KRB4 */
1280 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1281 /* a subscription packet */
1283 syslog(LOG_ERR, "brl no client");
1286 retval = subscr_subscribe(client, ¬ice, server);
1287 if (retval != ZERR_NONE) {
1288 syslog(LOG_WARNING, "brl subscr failed: %s",
1289 error_message(retval));
1292 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1293 /* add a subscription for a realm */
1295 retval = subscr_realm(realm, ¬ice);
1296 if (retval != ZERR_NONE) {
1297 syslog(LOG_WARNING, "brl subscr failed: %s",
1298 error_message(retval));
1302 /* Other side tried to send us subs for a realm we didn't
1303 know about, and so we drop them silently */
1306 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1307 return ZSRV_UNKNOWNOPCODE;
1313 * Send all the state to the peer.
1317 bdump_send_loop(Server *server)
1321 zdbug((LOG_DEBUG, "bdump send loop"));
1323 retval = uloc_send_locations();
1324 if (retval != ZERR_NONE)
1326 retval = client_send_clients();
1327 if (retval != ZERR_NONE)
1329 retval = realm_send_realms();
1330 if (retval != ZERR_NONE)
1336 * Send a sync indicating end of this host
1344 zdbug((LOG_DEBUG, "send_done"));
1346 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1347 "", ADMIN_DONE, myname, "", NULL, 0);
1353 * Send a list off as the specified notice
1357 send_list(ZNotice_Kind_t kind,
1372 memset (¬ice, 0, sizeof(notice));
1374 notice.z_kind = kind;
1375 notice.z_port = port;
1376 notice.z_class = class_name;
1377 notice.z_class_inst = inst;
1378 notice.z_opcode = opcode;
1379 notice.z_sender = sender;
1380 notice.z_recipient = recip;
1381 notice.z_default_format = "";
1382 notice.z_num_other_fields = 0;
1384 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1385 if (retval != ZERR_NONE) {
1386 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1390 retval = ZSendPacket(pack, packlen, 0);
1391 if (retval != ZERR_NONE)
1392 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1398 * Send a message off as the specified notice, via TCP
1402 send_normal_tcp(ZNotice_Kind_t kind,
1418 memset (¬ice, 0, sizeof(notice));
1420 notice.z_kind = kind;
1421 notice.z_port = port;
1422 notice.z_class = class_name;
1423 notice.z_class_inst = inst;
1424 notice.z_opcode = opcode;
1425 notice.z_sender = sender;
1426 notice.z_recipient = recip;
1427 notice.z_default_format = "";
1428 notice.z_message = message;
1429 notice.z_message_len = len;
1430 notice.z_num_other_fields = 0;
1432 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1433 if (retval != ZERR_NONE) {
1434 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1440 krb5_data indata, outmsg;
1441 indata.length=packlen;
1443 memset(&outmsg, 0, sizeof(krb5_data));
1444 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1445 if (retval != ZERR_NONE)
1447 if (outmsg.length > Z_MAXPKTLEN) {
1448 syslog(LOG_ERR, "sn: encrypted packet is too large");
1451 packlen = outmsg.length;
1453 pack=malloc(packlen);
1456 memcpy(pack, outmsg.data, packlen);
1457 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1461 length = htons((u_short) packlen);
1463 count = net_write(output, (char *) &length, sizeof(length));
1464 if (count != sizeof(length)) {
1466 syslog(LOG_WARNING, "snt xmit/len: %m");
1470 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1475 count = net_write(output, pack, packlen);
1476 if (count != packlen) {
1478 syslog(LOG_WARNING, "snt xmit: %m");
1482 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1492 * get a packet from the TCP socket
1493 * return 0 if successful, error code else
1497 get_packet(void *packet, int len, int *retlen)
1502 result = net_read(input, (char *) &length, sizeof(u_short));
1503 if (result < sizeof(short)) {
1507 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1513 length = ntohs(length);
1515 return ZSRV_BUFSHORT;
1516 result = net_read(input, packet, (int) length);
1517 if (result < length) {
1521 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1530 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1532 char *cp = notice->z_message;
1536 if (!notice->z_message_len || *buf == '\0') {
1537 return ZSRV_PKSHORT;
1539 target->sin_addr.s_addr = inet_addr(cp);
1541 cp += (strlen(cp) + 1); /* past the null */
1542 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1543 return(ZSRV_PKSHORT);
1545 target->sin_port = htons((u_short) atoi(cp));
1546 target->sin_family = AF_INET;
1551 net_read(FILE *f, char *buf, int len)
1558 cc = fread(buf, 1, len, f);
1575 net_write(FILE *f, char *buf, int len)
1580 cc = fwrite (buf, 1, wrlen, f);
1585 } while (wrlen > 0);
1590 setup_file_pointers (void)
1594 input = fdopen (live_socket, "r");
1598 fd = dup (live_socket);
1601 output = fdopen (fd, "w");