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 __P((void* arg));
85 static Code_t bdump_send_loop __P((Server *server)),
86 bdump_ask_for __P((char *inst)),
87 bdump_recv_loop __P((Server *server));
88 static void bdump_get_v12 __P((ZNotice_t *, int, struct sockaddr_in *,
90 static Code_t get_packet __P((void *packet, int len, int *retlen));
91 static Code_t extract_sin __P((ZNotice_t *notice, struct sockaddr_in *target));
92 static Code_t send_done __P((void));
93 static Code_t send_list __P((ZNotice_Kind_t kind, int port, char *class_name,
94 char *inst, char *opcode, char *sender,
95 char *recip, char **lyst, int num));
96 static Code_t send_normal_tcp __P((ZNotice_Kind_t kind, int port,
98 char *inst, char *opcode, char *sender,
99 char *recip, char *message, int len));
100 static int net_read __P((FILE *f, char *buf, int len));
101 static int net_write __P((FILE *f, char *buf, int len));
102 static int setup_file_pointers __P((void));
103 static void shutdown_file_pointers __P((void));
104 static void cleanup __P((Server *server));
107 static long ticket5_time;
108 #define TKT5LIFETIME 8*60*60
109 #define tkt5_lifetime(val) (val)
113 static long ticket_time;
115 #define TKTLIFETIME 120
116 #define tkt_lifetime(val) ((long) val * 5L * 60L)
119 extern C_Block serv_key;
120 extern Sched serv_ksched;
122 #endif /* HAVE_KRB4 */
124 static Timer *bdump_timer;
125 static int live_socket = -1;
126 static FILE *input, *output;
127 static struct sockaddr_in bdump_sin;
129 static krb5_auth_context bdump_ac;
132 static int cancel_outgoing_dump;
136 int bdump_concurrent;
137 extern char *bdump_version;
140 * Functions for performing a brain dump between servers.
144 * offer the brain dump to another server
149 struct sockaddr_in *who;
152 char buf[512], *addr, *lyst[2];
154 int bdump_port = IPPORT_RESERVED - 1;
155 #endif /* !HAVE_KRB4 */
157 zdbug((LOG_DEBUG, "bdump_offer"));
159 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
161 * when using kerberos server-server authentication, we can
162 * use any random local address
164 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
165 if (bdump_socket < 0) {
166 syslog(LOG_ERR,"bdump_offer: socket: %m");
170 memset(&bdump_sin, 0, sizeof(bdump_sin));
171 /* a port field of 0 makes the UNIX
172 * kernel choose an appropriate port/address pair */
174 bdump_sin.sin_port = 0;
175 bdump_sin.sin_addr = my_addr;
176 bdump_sin.sin_family = AF_INET;
177 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
180 syslog(LOG_ERR, "bdump_offer: bind: %m");
185 if (!bdump_sin.sin_port) {
186 int len = sizeof(bdump_sin);
188 if (getsockname(bdump_socket,
189 (struct sockaddr *) &bdump_sin, &len) < 0) {
190 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
196 #else /* !HAVE_KRB4 */
198 * when not using HAVE_KRB4, we can't use any old port, we use
199 * Internet reserved ports instead (rresvport)
201 bdump_socket = rresvport(&bdump_port);
202 if (bdump_socket < 0) {
203 syslog(LOG_ERR,"bdump_offer: socket: %m");
207 memset(&bdump_sin, 0, sizeof(bdump_sin));
208 bdump_sin.sin_port = htons((unsigned short) bdump_port);
209 bdump_sin.sin_addr = my_addr;
210 bdump_sin.sin_family = AF_INET;
211 #endif /* HAVE_KRB4 */
213 listen(bdump_socket, 1);
215 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
216 FD_SET(bdump_socket, &interesting);
217 nfds = max(bdump_socket, srv_socket) + 1;
219 addr = inet_ntoa(bdump_sin.sin_addr);
220 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
224 retval = ZSetDestAddr(who);
225 if (retval != ZERR_NONE) {
226 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
227 error_message(retval));
231 /* myname is the hostname */
232 /* the class instance is the version number, here it is */
233 /* bdump_version, which is set in main */
234 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
235 ADMIN_BDUMP, myname, "", lyst, 2);
238 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
239 inet_ntoa(bdump_sin.sin_addr),
240 ntohs(bdump_sin.sin_port)));
246 * Accept a connection, and send the brain dump to the other server
252 struct sockaddr_in from;
255 int fromlen = sizeof(from);
257 #ifdef _POSIX_VERSION
258 struct sigaction action;
265 unsigned short fromport;
266 #endif /* HAVE_KRB4 */
269 zdbug((LOG_DEBUG, "bdump_send"));
271 /* accept the connection, and send the brain dump */
272 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
273 if (live_socket < 0) {
274 syslog(LOG_ERR,"bdump_send: accept: %m");
277 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
279 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
282 fromport = ntohs(from.sin_port);
285 #ifdef _POSIX_VERSION
286 sigemptyset(&action.sa_mask);
288 action.sa_handler = SIG_IGN;
289 sigaction(SIGPIPE, &action, NULL);
292 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
295 from.sin_port = srv_addr.sin_port; /* we don't care what port
296 * it came from, and we need to
297 * fake out server_which_server() */
298 server = server_which_server(&from);
300 syslog(LOG_ERR, "bdump_send: unknown server?");
301 server = limbo_server;
304 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
305 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
311 if (bdump_socket >= 0) {
312 /* shut down the listening socket and the timer. */
313 FD_CLR(bdump_socket, &interesting);
315 nfds = srv_socket + 1;
317 timer_reset(bdump_timer);
320 /* Now begin the brain dump. */
322 { /* "server" side */
323 krb5_principal principal;
325 krb5_ap_rep_enc_part *rep;
329 syslog(LOG_ERR, "bdump_send: get_tgt failed");
334 retval = krb5_build_principal(Z_krb5_ctx, &principal,
337 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
340 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
346 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
348 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
353 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
355 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
360 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
361 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
363 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
368 /* Get the "client" krb_ap_req */
370 memset((char *)&data, 0, sizeof(krb5_data));
371 retval = GetKrb5Data(live_socket, &data);
373 syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
374 error_message(retval));
380 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
382 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
383 error_message(retval));
384 krb5_kt_close(Z_krb5_ctx, kt);
389 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &data, principal, kt, NULL, NULL);
390 krb5_free_principal(Z_krb5_ctx, principal);
391 krb5_kt_close(Z_krb5_ctx, kt);
393 memset((char *)&data, 0, sizeof(krb5_data));
395 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
396 error_message(retval));
401 /* Now send back our auth packet */
403 memset((char *)&data, 0, sizeof(krb5_data));
404 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &data);
406 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
410 retval = SendKrb5Data(live_socket, &data);
412 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
413 error_message(retval));
414 krb5_free_data_contents(Z_krb5_ctx, &data);
418 krb5_free_data_contents(Z_krb5_ctx, &data);
420 #else /* HAVE_KRB5 */
422 /* receive the authenticator */
423 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
424 SERVER_SERVICE, srvtab_file);
425 if (retval != KSUCCESS) {
426 syslog(LOG_ERR, "bdump_send: getkdata: %s",
427 krb_get_err_text(retval));
435 if (strcmp(kdata.pname, SERVER_SERVICE) ||
436 strcmp(kdata.pinst, SERVER_INSTANCE) ||
437 strcmp(kdata.prealm, ZGetRealm())) {
438 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
439 kdata.pname, kdata.pinst, kdata.prealm);
443 /* authenticate back */
444 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
447 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
448 error_message (retval));
452 #else /* !HAVE_KRB4 */
453 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
454 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
458 #endif /* HAVE_KRB4 */
459 #endif /* HAVE_KRB5 */
461 retval = setup_file_pointers();
463 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
464 error_message(retval));
468 retval = bdump_send_loop(server);
469 if (retval != ZERR_NONE) {
470 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
471 error_message(retval));
475 retval = bdump_recv_loop(server);
476 if (retval != ZERR_NONE) {
477 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
478 error_message(retval));
483 zdbug((LOG_DEBUG, "bdump_send: finished"));
485 if (server != limbo_server) {
486 /* set this guy to be up, and schedule a hello */
487 server->state = SERV_UP;
488 timer_reset(server->timer);
489 server->timer = timer_set_rel(0L, server_timo, server);
492 zdbug((LOG_DEBUG,"cleanup sbd"));
494 shutdown_file_pointers();
496 #ifdef _POSIX_VERSION
497 action.sa_handler = SIG_DFL;
498 sigaction(SIGPIPE, &action, NULL);
500 signal(SIGPIPE, SIG_DFL);
504 /* Now that we are finished dumping, send all the queued packets */
505 server_send_queue(server);
511 bdump_get_v12 (notice, auth, who, server)
514 struct sockaddr_in *who;
517 struct sockaddr_in from;
520 #ifdef _POSIX_VERSION
521 struct sigaction action;
526 #else /* !HAVE_KRB4 */
527 int reserved_port = IPPORT_RESERVED - 1;
528 #endif /* HAVE_KRB4 */
533 #ifdef _POSIX_VERSION
535 sigemptyset(&action.sa_mask);
536 action.sa_handler = SIG_IGN;
537 sigaction(SIGPIPE, &action, NULL);
539 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
540 #endif /* _POSIX_VRESION */
542 if (bdump_socket >= 0) {
543 /* We cannot go get a brain dump when someone may
544 potentially be connecting to us (if that other
545 server is the server to whom we are connecting,
546 we will deadlock. so we shut down the listening
547 socket and the timer. */
548 FD_CLR(bdump_socket, &interesting);
552 timer_reset(bdump_timer);
555 retval = extract_sin(notice, &from);
556 if (retval != ZERR_NONE) {
557 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
558 #ifdef _POSIX_VERSION
559 action.sa_handler = SIG_DFL;
560 sigaction(SIGPIPE, &action, NULL);
562 signal(SIGPIPE, SIG_DFL);
569 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
570 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
571 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
572 ntohs(from.sin_port));
576 live_socket = rresvport(&reserved_port);
577 #else /* !HAVE_KRB4 */
578 live_socket = socket(AF_INET, SOCK_STREAM, 0);
579 #endif /* HAVE_KRB4 */
580 if (live_socket < 0) {
581 syslog(LOG_ERR, "bdump_get: socket: %m");
585 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
586 syslog(LOG_ERR, "bdump_get: connect: %m");
590 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
592 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
594 zdbug((LOG_DEBUG, "bdump_get: connected"));
597 /* Now begin the brain dump. */
601 syslog(LOG_ERR, "bdump_get: get_tgt failed");
605 { /* "client" side */
608 krb5_principal principal;
610 krb5_ap_rep_enc_part *rep;
612 memset((char *)&creds, 0, sizeof(creds));
614 retval = krb5_build_principal(Z_krb5_ctx, &principal,
617 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
620 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
625 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
627 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
628 krb5_free_principal(Z_krb5_ctx, principal);
633 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
634 krb5_free_principal(Z_krb5_ctx, principal);
636 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
637 krb5_free_cred_contents(Z_krb5_ctx, &creds);
642 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
644 krb5_free_cred_contents(Z_krb5_ctx, &creds);
646 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
651 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
653 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
654 krb5_free_creds(Z_krb5_ctx, credsp);
659 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
661 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
662 krb5_free_creds(Z_krb5_ctx, credsp);
667 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
668 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
670 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
671 krb5_free_creds(Z_krb5_ctx, credsp);
676 memset((char *)&data, 0, sizeof(krb5_data));
677 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
678 NULL, credsp, &data);
680 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
681 krb5_free_creds(Z_krb5_ctx, credsp);
685 retval = SendKrb5Data(live_socket, &data);
686 krb5_free_creds(Z_krb5_ctx, credsp);
688 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
689 error_message(retval));
690 krb5_free_data_contents(Z_krb5_ctx, &data);
694 krb5_free_data_contents(Z_krb5_ctx, &data);
695 memset((char *)&data, 0, sizeof(krb5_data));
696 retval = GetKrb5Data(live_socket, &data);
698 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
699 error_message(retval));
703 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
705 memset((char *)&data, 0, sizeof(krb5_data));
707 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
708 error_message(retval));
716 /* send an authenticator */
721 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
724 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
729 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
732 /* get his authenticator */
733 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
734 SERVER_SERVICE, srvtab_file);
735 if (retval != KSUCCESS) {
736 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
741 if (strcmp(kdata.pname, SERVER_SERVICE) ||
742 strcmp(kdata.pinst, SERVER_INSTANCE) ||
743 strcmp(kdata.prealm, ZGetRealm())) {
744 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
745 kdata.pname, kdata.pinst,kdata.prealm);
749 #endif /* HAVE_KRB4 */
751 retval = setup_file_pointers();
753 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
754 error_message (retval));
758 retval = bdump_recv_loop(server);
759 if (retval != ZERR_NONE) {
760 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
761 error_message(retval));
766 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
768 retval = bdump_send_loop(server);
769 if (retval != ZERR_NONE) {
770 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
771 error_message(retval));
776 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
778 /* set this guy to be up, and schedule a hello */
779 server->state = SERV_UP;
780 timer_reset(server->timer);
781 server->timer = timer_set_rel(0L, server_timo, server);
784 zdbug((LOG_DEBUG,"cleanup gbd"));
786 shutdown_file_pointers();
787 #ifdef _POSIX_VERSION
788 action.sa_handler = SIG_DFL;
789 sigaction(SIGPIPE, &action, NULL);
791 signal(SIGPIPE, SIG_DFL);
795 /* Now that we are finished dumping, send all the queued packets */
796 server_send_queue(server);
802 bdump_get(notice, auth, who, server)
805 struct sockaddr_in *who;
808 void (*proc) __P((ZNotice_t *, int, struct sockaddr_in *, Server *));
814 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
815 notice->z_class_inst, inet_ntoa(who->sin_addr));
818 if (strcmp (notice->z_class_inst, "1.2") == 0)
819 proc = bdump_get_v12;
822 (*proc)(notice, auth, who, server);
825 "bdump_get: Incompatible bdump version '%s' from %s",
826 notice->z_class_inst,
827 inet_ntoa(who->sin_addr));
832 * Send a list off as the specified notice
836 bdump_send_list_tcp(kind, addr, class_name, inst, opcode, sender, recip, lyst,
839 struct sockaddr_in *addr;
841 char *class_name, *inst, *opcode, *sender, *recip, **lyst;
844 char *pack, addrbuf[100];
849 memset (¬ice, 0, sizeof(notice));
851 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
852 (unsigned char *) &addr->sin_addr,
853 sizeof(struct in_addr));
854 if (retval != ZERR_NONE)
856 notice.z_kind = kind;
858 notice.z_port = addr->sin_port;
859 notice.z_class = class_name;
860 notice.z_class_inst = inst;
861 notice.z_opcode = opcode;
862 notice.z_sender = sender;
863 notice.z_recipient = recip;
864 notice.z_default_format = "";
865 notice.z_num_other_fields = 1;
866 notice.z_other_fields[0] = addrbuf;
868 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
869 if (retval != ZERR_NONE)
874 krb5_data indata, outmsg;
875 indata.length=packlen;
877 memset(&outmsg, 0, sizeof(krb5_data));
878 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
879 if (retval != ZERR_NONE)
881 if (outmsg.length > Z_MAXPKTLEN) {
882 syslog(LOG_ERR, "bsl: encrypted packet is too large");
885 packlen = outmsg.length;
887 pack=malloc(packlen);
890 memcpy(pack, outmsg.data, packlen);
891 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
895 length = htons((u_short) packlen);
897 count = net_write(output, (char *) &length, sizeof(length));
898 if (count != sizeof(length)) {
903 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
904 sizeof(length), count);
906 return(ZSRV_PKSHORT);
910 count = net_write(output, pack, packlen);
911 if (count != packlen) {
916 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
919 return(ZSRV_PKSHORT);
927 shutdown_file_pointers() {
936 if (live_socket >= 0) {
941 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
951 #ifdef _POSIX_VERSION
952 struct sigaction action;
956 zdbug((LOG_DEBUG, "bdump cleanup"));
958 if (server != limbo_server) {
959 server->state = SERV_DEAD;
960 timer_reset(server->timer);
961 server->timer = timer_set_rel(0L, server_timo, server);
963 shutdown_file_pointers ();
964 #ifdef _POSIX_VERSION
966 sigemptyset(&action.sa_mask);
967 action.sa_handler = SIG_DFL;
968 sigaction(SIGPIPE,&action, NULL);
970 signal(SIGPIPE, SIG_DFL);
971 #endif /* _POSIX_VERSION */
980 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
981 * at least INST_SZ bytes long. */
982 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
989 /* have they expired ? */
990 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
993 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
994 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
998 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
999 "krbtgt", ZGetRealm(),
1000 TKTLIFETIME, srvtab_file);
1001 if (retval != KSUCCESS) {
1002 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1003 krb_get_err_text(retval));
1010 #ifndef NOENCRYPTION
1011 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1012 ZGetRealm(), 0 /*kvno*/,
1013 srvtab_file, serv_key);
1014 if (retval != KSUCCESS) {
1015 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1016 krb_get_err_text(retval));
1019 des_key_sched(serv_key, serv_ksched.s);
1020 #endif /* !NOENCRYPTION */
1024 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1026 krb5_get_init_creds_opt opt;
1028 krb5_principal principal;
1030 memset(&cred, 0, sizeof(cred));
1032 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1033 strlen(ZGetRealm()),
1035 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1038 krb5_free_principal(Z_krb5_ctx, principal);
1042 krb5_get_init_creds_opt_init (&opt);
1043 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1045 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1046 if (retval) return(1);
1048 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1055 krb5_free_principal(Z_krb5_ctx, principal);
1056 krb5_kt_close(Z_krb5_ctx, kt);
1057 if (retval) return(1);
1059 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1060 if (retval) return(1);
1062 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1063 if (retval) return(1);
1067 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1072 #endif /* HAVE_KRB4 */
1075 * The braindump offer wasn't taken, so we retract it.
1083 if (bdump_socket >= 0) {
1084 FD_CLR(bdump_socket, &interesting);
1085 close(bdump_socket);
1086 nfds = srv_socket + 1;
1089 zdbug((LOG_DEBUG, "bdump not used"));
1093 zdbug((LOG_DEBUG, "bdump not open"));
1100 * Start receiving instruction notices from the brain dump socket
1104 bdump_recv_loop(server)
1111 Client *client = NULL;
1112 struct sockaddr_in who;
1117 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1122 #endif /* HAVE_KRB4 */
1123 ZRealm *realm = NULL;
1126 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(cblock, 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(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);
1275 memcpy(cblock, client->session_key, sizeof(C_Block));
1277 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1282 #endif /* HAVE_KRB4 */
1284 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1285 /* a subscription packet */
1287 syslog(LOG_ERR, "brl no client");
1290 retval = subscr_subscribe(client, ¬ice, server);
1291 if (retval != ZERR_NONE) {
1292 syslog(LOG_WARNING, "brl subscr failed: %s",
1293 error_message(retval));
1296 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1297 /* add a subscription for a realm */
1299 retval = subscr_realm(realm, ¬ice);
1300 if (retval != ZERR_NONE) {
1301 syslog(LOG_WARNING, "brl subscr failed: %s",
1302 error_message(retval));
1306 /* Other side tried to send us subs for a realm we didn't
1307 know about, and so we drop them silently */
1310 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1311 return ZSRV_UNKNOWNOPCODE;
1317 * Send all the state to the peer.
1321 bdump_send_loop(server)
1327 zdbug((LOG_DEBUG, "bdump send loop"));
1330 retval = uloc_send_locations();
1331 if (retval != ZERR_NONE)
1333 retval = client_send_clients();
1334 if (retval != ZERR_NONE)
1336 retval = realm_send_realms();
1337 if (retval != ZERR_NONE)
1343 * Send a sync indicating end of this host
1352 zdbug((LOG_DEBUG, "send_done"));
1354 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1355 "", ADMIN_DONE, myname, "", NULL, 0);
1361 * Send a list off as the specified notice
1365 send_list(kind, port, class_name, inst, opcode, sender, recip, lyst, num)
1366 ZNotice_Kind_t kind;
1368 char *class_name, *inst, *opcode, *sender, *recip, **lyst;
1375 memset (¬ice, 0, sizeof(notice));
1377 notice.z_kind = kind;
1378 notice.z_port = port;
1379 notice.z_class = class_name;
1380 notice.z_class_inst = inst;
1381 notice.z_opcode = opcode;
1382 notice.z_sender = sender;
1383 notice.z_recipient = recip;
1384 notice.z_default_format = "";
1385 notice.z_num_other_fields = 0;
1387 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1388 if (retval != ZERR_NONE) {
1389 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1393 retval = ZSendPacket(pack, packlen, 0);
1394 if (retval != ZERR_NONE)
1395 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1401 * Send a message off as the specified notice, via TCP
1405 send_normal_tcp(kind, port, class_name, inst, opcode, sender, recip,
1407 ZNotice_Kind_t kind;
1409 char *class_name, *inst, *opcode, *sender, *recip, *message;
1417 memset (¬ice, 0, sizeof(notice));
1419 notice.z_kind = kind;
1420 notice.z_port = port;
1421 notice.z_class = class_name;
1422 notice.z_class_inst = inst;
1423 notice.z_opcode = opcode;
1424 notice.z_sender = sender;
1425 notice.z_recipient = recip;
1426 notice.z_default_format = "";
1427 notice.z_message = message;
1428 notice.z_message_len = len;
1429 notice.z_num_other_fields = 0;
1431 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1432 if (retval != ZERR_NONE) {
1433 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1439 krb5_data indata, outmsg;
1440 indata.length=packlen;
1442 memset(&outmsg, 0, sizeof(krb5_data));
1443 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1444 if (retval != ZERR_NONE)
1446 if (outmsg.length > Z_MAXPKTLEN) {
1447 syslog(LOG_ERR, "sn: encrypted packet is too large");
1450 packlen = outmsg.length;
1452 pack=malloc(packlen);
1455 memcpy(pack, outmsg.data, packlen);
1456 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1460 length = htons((u_short) packlen);
1462 count = net_write(output, (char *) &length, sizeof(length));
1463 if (count != sizeof(length)) {
1465 syslog(LOG_WARNING, "snt xmit/len: %m");
1469 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1474 count = net_write(output, pack, packlen);
1475 if (count != packlen) {
1477 syslog(LOG_WARNING, "snt xmit: %m");
1481 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1491 * get a packet from the TCP socket
1492 * return 0 if successful, error code else
1496 get_packet(packet, len, retlen)
1504 result = net_read(input, (char *) &length, sizeof(u_short));
1505 if (result < sizeof(short)) {
1509 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1515 length = ntohs(length);
1517 return ZSRV_BUFSHORT;
1518 result = net_read(input, packet, (int) length);
1519 if (result < length) {
1523 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1532 extract_sin(notice, target)
1534 struct sockaddr_in *target;
1536 char *cp = notice->z_message;
1540 if (!notice->z_message_len || *buf == '\0') {
1542 zdbug((LOG_DEBUG,"no addr"));
1544 return ZSRV_PKSHORT;
1546 target->sin_addr.s_addr = inet_addr(cp);
1548 cp += (strlen(cp) + 1); /* past the null */
1549 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1551 zdbug((LOG_DEBUG, "no port"));
1553 return(ZSRV_PKSHORT);
1555 target->sin_port = htons((u_short) atoi(cp));
1556 target->sin_family = AF_INET;
1561 net_read(f, buf, len)
1571 cc = fread(buf, 1, len, f);
1588 net_write(f, buf, len)
1596 cc = fwrite (buf, 1, wrlen, f);
1601 } while (wrlen > 0);
1606 setup_file_pointers ()
1610 input = fdopen (live_socket, "r");
1614 fd = dup (live_socket);
1617 output = fdopen (fd, "w");