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_ask_for(char *inst);
87 static Code_t bdump_recv_loop(Server *server);
88 static void bdump_get_v12(ZNotice_t *, int, struct sockaddr_in *,
90 static Code_t get_packet(void *packet, int len, int *retlen);
91 static Code_t extract_sin(ZNotice_t *notice, struct sockaddr_in *target);
92 static Code_t send_done(void);
93 static Code_t send_list(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(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(FILE *f, char *buf, int len);
101 static int net_write(FILE *f, char *buf, int len);
102 static int setup_file_pointers(void);
103 static void shutdown_file_pointers(void);
104 static void cleanup(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;
138 extern int bdump_auth_proto;
141 * Functions for performing a brain dump between servers.
145 * offer the brain dump to another server
149 bdump_offer(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;
260 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
268 /* may be moved into kstuff.c */
269 char instance [INST_SZ];
272 /* may be moved into kstuff.c */
273 krb5_principal principal;
275 krb5_ap_rep_enc_part *rep;
278 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
279 unsigned short fromport;
280 #endif /* HAVE_KRB4 */
283 zdbug((LOG_DEBUG, "bdump_send"));
285 /* accept the connection, and send the brain dump */
286 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
287 if (live_socket < 0) {
288 syslog(LOG_ERR,"bdump_send: accept: %m");
291 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
293 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
296 fromport = ntohs(from.sin_port);
299 #ifdef _POSIX_VERSION
300 sigemptyset(&action.sa_mask);
302 action.sa_handler = SIG_IGN;
303 sigaction(SIGPIPE, &action, NULL);
306 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
309 from.sin_port = srv_addr.sin_port; /* we don't care what port
310 * it came from, and we need to
311 * fake out server_which_server() */
312 server = server_which_server(&from);
314 syslog(LOG_ERR, "bdump_send: unknown server?");
315 server = limbo_server;
318 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
319 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
325 if (bdump_socket >= 0) {
326 /* shut down the listening socket and the timer. */
327 FD_CLR(bdump_socket, &interesting);
329 nfds = srv_socket + 1;
331 timer_reset(bdump_timer);
334 /* Now begin the brain dump. */
335 #if defined(HAVE_KRB5) || defined(HAVE_KRB4)
336 retval = ReadKerberosData(live_socket, &len, &data, &proto);
339 syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
340 krb_get_err_text(retval));
345 syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
348 syslog(LOG_ERR, "bdump_send: get_tgt failed");
357 retval = krb5_build_principal(Z_krb5_ctx, &principal,
360 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
363 syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
369 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
371 syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
376 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
378 syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
383 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
384 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
386 syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
391 /* Get the "client" krb_ap_req */
393 memset((char *)&k5data, 0, sizeof(krb5_data));
397 syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
398 error_message(retval));
404 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
406 syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
407 error_message(retval));
408 krb5_kt_close(Z_krb5_ctx, kt);
413 retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
414 krb5_free_principal(Z_krb5_ctx, principal);
415 krb5_kt_close(Z_krb5_ctx, kt);
417 memset((char *)&k5data, 0, sizeof(krb5_data));
419 syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
420 error_message(retval));
425 /* Now send back our auth packet */
427 retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
429 syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
433 retval = SendKrb5Data(live_socket, &k5data);
435 syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
436 error_message(retval));
437 krb5_free_data_contents(Z_krb5_ctx, &k5data);
441 krb5_free_data_contents(Z_krb5_ctx, &k5data);
443 #endif /* HAVE_KRB5 */
446 /* here to krb_rd_req from GetKerberosData candidate for refactoring
447 back into kstuff.c */
448 (void) strcpy(instance, "*"); /* let Kerberos fill it in */
451 memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
452 retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
453 from.sin_addr.s_addr, &kdata, srvtab_file);
455 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
456 SERVER_SERVICE, srvtab_file);
458 if (retval != KSUCCESS) {
459 syslog(LOG_ERR, "bdump_send: getkdata: %s",
460 krb_get_err_text(retval));
464 if (strcmp(kdata.pname, SERVER_SERVICE) ||
465 strcmp(kdata.pinst, SERVER_INSTANCE) ||
466 strcmp(kdata.prealm, ZGetRealm())) {
467 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
468 kdata.pname, kdata.pinst, kdata.prealm);
472 /* authenticate back */
473 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
476 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
477 error_message (retval));
482 #endif /* HAVE_KRB4 */
484 #else /* HAVE_KRB4 || HAVE_KRB5 */
485 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
486 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
490 #endif /* HAVE_KRB4 || HAVE_KRB5 */
491 retval = setup_file_pointers();
493 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
494 error_message(retval));
498 retval = bdump_send_loop(server);
499 if (retval != ZERR_NONE) {
500 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
501 error_message(retval));
505 retval = bdump_recv_loop(server);
506 if (retval != ZERR_NONE) {
507 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
508 error_message(retval));
513 zdbug((LOG_DEBUG, "bdump_send: finished"));
515 if (server != limbo_server) {
516 /* set this guy to be up, and schedule a hello */
517 server->state = SERV_UP;
518 timer_reset(server->timer);
519 server->timer = timer_set_rel(0L, server_timo, server);
522 zdbug((LOG_DEBUG,"cleanup sbd"));
524 shutdown_file_pointers();
526 #ifdef _POSIX_VERSION
527 action.sa_handler = SIG_DFL;
528 sigaction(SIGPIPE, &action, NULL);
530 signal(SIGPIPE, SIG_DFL);
534 /* Now that we are finished dumping, send all the queued packets */
535 server_send_queue(server);
541 bdump_get_v12 (ZNotice_t *notice,
543 struct sockaddr_in *who,
546 struct sockaddr_in from;
549 #ifdef _POSIX_VERSION
550 struct sigaction action;
552 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
556 krb5_principal principal;
558 krb5_ap_rep_enc_part *rep;
564 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
565 int reserved_port = IPPORT_RESERVED - 1;
566 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
571 #ifdef _POSIX_VERSION
573 sigemptyset(&action.sa_mask);
574 action.sa_handler = SIG_IGN;
575 sigaction(SIGPIPE, &action, NULL);
577 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
578 #endif /* _POSIX_VRESION */
580 if (bdump_socket >= 0) {
581 /* We cannot go get a brain dump when someone may
582 potentially be connecting to us (if that other
583 server is the server to whom we are connecting,
584 we will deadlock. so we shut down the listening
585 socket and the timer. */
586 FD_CLR(bdump_socket, &interesting);
590 timer_reset(bdump_timer);
593 retval = extract_sin(notice, &from);
594 if (retval != ZERR_NONE) {
595 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
596 #ifdef _POSIX_VERSION
597 action.sa_handler = SIG_DFL;
598 sigaction(SIGPIPE, &action, NULL);
600 signal(SIGPIPE, SIG_DFL);
606 #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
607 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
608 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
609 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
610 ntohs(from.sin_port));
614 live_socket = rresvport(&reserved_port);
615 #else /* !HAVE_KRB4 && !HAVE_KRB5 */
616 live_socket = socket(AF_INET, SOCK_STREAM, 0);
617 #endif /* !HAVE_KRB4 && !HAVE_KRB5 */
618 if (live_socket < 0) {
619 syslog(LOG_ERR, "bdump_get: socket: %m");
623 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
624 syslog(LOG_ERR, "bdump_get: connect: %m");
628 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
630 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
632 zdbug((LOG_DEBUG, "bdump_get: connected"));
635 /* Now begin the brain dump. */
636 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
638 syslog(LOG_ERR, "bdump_get: get_tgt failed");
642 switch(bdump_auth_proto) {
644 case 5: /* "client" side */
645 memset((char *)&creds, 0, sizeof(creds));
647 retval = krb5_build_principal(Z_krb5_ctx, &principal,
650 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
653 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
658 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
660 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
661 krb5_free_principal(Z_krb5_ctx, principal);
666 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
667 krb5_free_principal(Z_krb5_ctx, principal);
669 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
670 krb5_free_cred_contents(Z_krb5_ctx, &creds);
675 retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
677 krb5_free_cred_contents(Z_krb5_ctx, &creds);
679 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
684 retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
686 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
687 krb5_free_creds(Z_krb5_ctx, credsp);
692 retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
694 syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
695 krb5_free_creds(Z_krb5_ctx, credsp);
700 retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
701 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
703 syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
704 krb5_free_creds(Z_krb5_ctx, credsp);
709 memset((char *)&data, 0, sizeof(krb5_data));
710 retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
711 NULL, credsp, &data);
713 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
714 krb5_free_creds(Z_krb5_ctx, credsp);
718 retval = SendKrb5Data(live_socket, &data);
719 krb5_free_creds(Z_krb5_ctx, credsp);
721 syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
722 error_message(retval));
723 krb5_free_data_contents(Z_krb5_ctx, &data);
727 krb5_free_data_contents(Z_krb5_ctx, &data);
728 memset((char *)&data, 0, sizeof(krb5_data));
729 retval = GetKrb5Data(live_socket, &data);
731 syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
732 error_message(retval));
736 retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
738 memset((char *)&data, 0, sizeof(krb5_data));
740 syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
741 error_message(retval));
749 /* send an authenticator */
750 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
753 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
757 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
759 /* get his authenticator */
760 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
761 SERVER_SERVICE, srvtab_file);
762 if (retval != KSUCCESS) {
763 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
768 if (strcmp(kdata.pname, SERVER_SERVICE) ||
769 strcmp(kdata.pinst, SERVER_INSTANCE) ||
770 strcmp(kdata.prealm, ZGetRealm())) {
771 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
772 kdata.pname, kdata.pinst,kdata.prealm);
777 #endif /* HAVE_KRB4 */
779 #endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
780 retval = setup_file_pointers();
782 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
783 error_message (retval));
787 retval = bdump_recv_loop(server);
788 if (retval != ZERR_NONE) {
789 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
790 error_message(retval));
794 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
795 retval = bdump_send_loop(server);
796 if (retval != ZERR_NONE) {
797 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
798 error_message(retval));
803 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
805 /* set this guy to be up, and schedule a hello */
806 server->state = SERV_UP;
807 timer_reset(server->timer);
808 server->timer = timer_set_rel(0L, server_timo, server);
811 zdbug((LOG_DEBUG,"cleanup gbd"));
813 shutdown_file_pointers();
814 #ifdef _POSIX_VERSION
815 action.sa_handler = SIG_DFL;
816 sigaction(SIGPIPE, &action, NULL);
818 signal(SIGPIPE, SIG_DFL);
822 /* Now that we are finished dumping, send all the queued packets */
823 server_send_queue(server);
829 bdump_get(ZNotice_t *notice,
831 struct sockaddr_in *who,
834 void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *);
840 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
841 notice->z_class_inst, inet_ntoa(who->sin_addr));
844 if (strcmp (notice->z_class_inst, "1.2") == 0)
845 proc = bdump_get_v12;
848 (*proc)(notice, auth, who, server);
851 "bdump_get: Incompatible bdump version '%s' from %s",
852 notice->z_class_inst,
853 inet_ntoa(who->sin_addr));
858 * Send a list off as the specified notice
862 bdump_send_list_tcp(ZNotice_Kind_t kind,
863 struct sockaddr_in *addr,
873 char *pack, addrbuf[100];
878 memset (¬ice, 0, sizeof(notice));
880 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
881 (unsigned char *) &addr->sin_addr,
882 sizeof(struct in_addr));
883 if (retval != ZERR_NONE)
885 notice.z_kind = kind;
887 notice.z_port = addr->sin_port;
888 notice.z_class = class_name;
889 notice.z_class_inst = inst;
890 notice.z_opcode = opcode;
891 notice.z_sender = sender;
892 notice.z_recipient = recip;
893 notice.z_default_format = "";
894 notice.z_num_other_fields = 1;
895 notice.z_other_fields[0] = addrbuf;
897 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
898 if (retval != ZERR_NONE)
903 krb5_data indata, outmsg;
904 indata.length=packlen;
906 memset(&outmsg, 0, sizeof(krb5_data));
907 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
908 if (retval != ZERR_NONE)
910 if (outmsg.length > Z_MAXPKTLEN) {
911 syslog(LOG_ERR, "bsl: encrypted packet is too large");
914 packlen = outmsg.length;
916 pack=malloc(packlen);
919 memcpy(pack, outmsg.data, packlen);
920 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
924 length = htons((u_short) packlen);
926 count = net_write(output, (char *) &length, sizeof(length));
927 if (count != sizeof(length)) {
932 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
933 sizeof(length), count);
935 return(ZSRV_PKSHORT);
939 count = net_write(output, pack, packlen);
940 if (count != packlen) {
945 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
948 return(ZSRV_PKSHORT);
956 shutdown_file_pointers(void)
966 if (live_socket >= 0) {
971 krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
978 cleanup(Server *server)
980 #ifdef _POSIX_VERSION
981 struct sigaction action;
985 zdbug((LOG_DEBUG, "bdump cleanup"));
987 if (server != limbo_server) {
988 server->state = SERV_DEAD;
989 timer_reset(server->timer);
990 server->timer = timer_set_rel(0L, server_timo, server);
992 shutdown_file_pointers ();
993 #ifdef _POSIX_VERSION
995 sigemptyset(&action.sa_mask);
996 action.sa_handler = SIG_DFL;
997 sigaction(SIGPIPE,&action, NULL);
999 signal(SIGPIPE, SIG_DFL);
1000 #endif /* _POSIX_VERSION */
1002 server->dumping = 0;
1009 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
1010 * at least INST_SZ bytes long. */
1011 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
1014 #ifndef NOENCRYPTION
1018 /* have they expired ? */
1019 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
1020 /* +15 for leeway */
1022 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
1023 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
1027 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
1028 "krbtgt", ZGetRealm(),
1029 TKTLIFETIME, srvtab_file);
1030 if (retval != KSUCCESS) {
1031 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
1032 krb_get_err_text(retval));
1039 #ifndef NOENCRYPTION
1040 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
1041 ZGetRealm(), 0 /*kvno*/,
1042 srvtab_file, serv_key);
1043 if (retval != KSUCCESS) {
1044 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
1045 krb_get_err_text(retval));
1048 des_key_sched(serv_key, serv_ksched.s);
1049 #endif /* !NOENCRYPTION */
1053 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
1055 krb5_get_init_creds_opt opt;
1057 krb5_principal principal;
1059 memset(&cred, 0, sizeof(cred));
1061 retval = krb5_build_principal(Z_krb5_ctx, &principal,
1062 strlen(ZGetRealm()),
1064 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
1067 krb5_free_principal(Z_krb5_ctx, principal);
1071 krb5_get_init_creds_opt_init (&opt);
1072 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
1074 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
1075 if (retval) return(1);
1077 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
1084 krb5_free_principal(Z_krb5_ctx, principal);
1085 krb5_kt_close(Z_krb5_ctx, kt);
1086 if (retval) return(1);
1088 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
1089 if (retval) return(1);
1091 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
1092 if (retval) return(1);
1096 krb5_free_cred_contents (Z_krb5_ctx, &cred);
1101 #endif /* HAVE_KRB4 */
1104 * The braindump offer wasn't taken, so we retract it.
1109 close_bdump(void *arg)
1111 if (bdump_socket >= 0) {
1112 FD_CLR(bdump_socket, &interesting);
1113 close(bdump_socket);
1114 nfds = srv_socket + 1;
1117 zdbug((LOG_DEBUG, "bdump not used"));
1121 zdbug((LOG_DEBUG, "bdump not open"));
1128 * Start receiving instruction notices from the brain dump socket
1132 bdump_recv_loop(Server *server)
1138 Client *client = NULL;
1139 struct sockaddr_in who;
1144 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
1149 #endif /* HAVE_KRB4 */
1150 ZRealm *realm = NULL;
1153 zdbug((LOG_DEBUG, "bdump recv loop"));
1156 /* do the inverse of bdump_send_loop, registering stuff on the fly */
1158 if (packets_waiting()) {
1159 /* A non-braindump packet is waiting; handle it. */
1161 bdump_concurrent = 1;
1163 bdump_concurrent = 0;
1166 len = sizeof(packet);
1167 retval = get_packet(packet, len, &len);
1168 if (retval != ZERR_NONE) {
1169 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
1178 memset(&out, 0, sizeof(krb5_data));
1179 retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
1180 if (retval != ZERR_NONE) {
1181 syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
1184 memcpy(packet, out.data, out.length);
1186 krb5_free_data_contents(Z_krb5_ctx, &out);
1190 retval = ZParseNotice(packet, len, ¬ice);
1191 if (retval != ZERR_NONE) {
1192 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
1197 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
1198 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
1199 notice.z_class_inst, notice.z_opcode, notice.z_sender,
1200 notice.z_recipient);
1203 if (notice.z_num_other_fields >= 1) {
1204 retval = ZReadAscii(notice.z_other_fields[0],
1205 strlen(notice.z_other_fields[0]),
1206 (unsigned char *) &who.sin_addr,
1207 sizeof(struct in_addr));
1208 if (retval != ZERR_NONE) {
1209 syslog(LOG_ERR, "brl zreadascii failed: %s",
1210 error_message(retval));
1214 who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
1216 who.sin_family = AF_INET;
1217 who.sin_port = notice.z_port;
1219 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
1220 /* end of brain dump */
1222 } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
1223 /* get a realm from the message */
1224 realm = realm_get_realm_by_name(notice.z_message);
1226 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
1229 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
1230 /* 1 = tell it we are authentic */
1231 retval = ulogin_dispatch(¬ice, 1, &who, server);
1232 if (retval != ZERR_NONE) {
1233 syslog(LOG_ERR, "brl ul_disp failed: %s",
1234 error_message(retval));
1237 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
1239 notice.z_port = htons((u_short) atoi(notice.z_message));
1240 retval = client_register(¬ice, &who.sin_addr, &client, 0);
1241 if (retval != ZERR_NONE) {
1242 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
1246 client->session_keyblock = NULL;
1247 if (*notice.z_class_inst) {
1248 /* check out this session key I found */
1249 cp = notice.z_message + strlen(notice.z_message) + 1;
1251 /* ****ing netascii; this is an encrypted DES keyblock
1252 XXX this code should be conditionalized for server
1254 retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
1256 &client->session_keyblock);
1258 syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
1259 error_message(retval));
1262 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1263 if (retval != ZERR_NONE) {
1264 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1265 error_message(retval), cp);
1267 des_ecb_encrypt(cblock, Z_keydata(client->session_keyblock),
1268 serv_ksched.s, DES_DECRYPT);
1270 } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
1271 retval = ZReadZcode(cp, buf, sizeof(buf), &blen);
1272 if (retval != ZERR_NONE) {
1273 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1274 error_message(retval), cp);
1276 retval = Z_krb5_init_keyblock(Z_krb5_ctx,
1277 ntohl(*(krb5_enctype *)&buf[0]),
1278 ntohl(*(u_int32_t *)&buf[4]),
1279 &client->session_keyblock);
1281 syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
1282 error_message(retval));
1285 memcpy(Z_keydata(client->session_keyblock), &buf[8],
1286 Z_keylen(client->session_keyblock));
1292 memset(client->session_key, 0, sizeof(C_Block));
1293 if (*notice.z_class_inst) {
1294 /* a C_Block is there */
1295 cp = notice.z_message + strlen(notice.z_message) + 1;
1296 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1297 if (retval != ZERR_NONE) {
1298 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1299 error_message(retval), cp);
1302 memcpy(cblock, client->session_key, sizeof(C_Block));
1304 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1309 #endif /* HAVE_KRB4 */
1311 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1312 /* a subscription packet */
1314 syslog(LOG_ERR, "brl no client");
1317 retval = subscr_subscribe(client, ¬ice, server);
1318 if (retval != ZERR_NONE) {
1319 syslog(LOG_WARNING, "brl subscr failed: %s",
1320 error_message(retval));
1323 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1324 /* add a subscription for a realm */
1326 retval = subscr_realm(realm, ¬ice);
1327 if (retval != ZERR_NONE) {
1328 syslog(LOG_WARNING, "brl subscr failed: %s",
1329 error_message(retval));
1333 /* Other side tried to send us subs for a realm we didn't
1334 know about, and so we drop them silently */
1337 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1338 return ZSRV_UNKNOWNOPCODE;
1344 * Send all the state to the peer.
1348 bdump_send_loop(Server *server)
1353 zdbug((LOG_DEBUG, "bdump send loop"));
1356 retval = uloc_send_locations();
1357 if (retval != ZERR_NONE)
1359 retval = client_send_clients();
1360 if (retval != ZERR_NONE)
1362 retval = realm_send_realms();
1363 if (retval != ZERR_NONE)
1369 * Send a sync indicating end of this host
1378 zdbug((LOG_DEBUG, "send_done"));
1380 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1381 "", ADMIN_DONE, myname, "", NULL, 0);
1387 * Send a list off as the specified notice
1391 send_list(ZNotice_Kind_t kind,
1406 memset (¬ice, 0, sizeof(notice));
1408 notice.z_kind = kind;
1409 notice.z_port = port;
1410 notice.z_class = class_name;
1411 notice.z_class_inst = inst;
1412 notice.z_opcode = opcode;
1413 notice.z_sender = sender;
1414 notice.z_recipient = recip;
1415 notice.z_default_format = "";
1416 notice.z_num_other_fields = 0;
1418 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1419 if (retval != ZERR_NONE) {
1420 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1424 retval = ZSendPacket(pack, packlen, 0);
1425 if (retval != ZERR_NONE)
1426 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1432 * Send a message off as the specified notice, via TCP
1436 send_normal_tcp(ZNotice_Kind_t kind,
1452 memset (¬ice, 0, sizeof(notice));
1454 notice.z_kind = kind;
1455 notice.z_port = port;
1456 notice.z_class = class_name;
1457 notice.z_class_inst = inst;
1458 notice.z_opcode = opcode;
1459 notice.z_sender = sender;
1460 notice.z_recipient = recip;
1461 notice.z_default_format = "";
1462 notice.z_message = message;
1463 notice.z_message_len = len;
1464 notice.z_num_other_fields = 0;
1466 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1467 if (retval != ZERR_NONE) {
1468 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1474 krb5_data indata, outmsg;
1475 indata.length=packlen;
1477 memset(&outmsg, 0, sizeof(krb5_data));
1478 retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
1479 if (retval != ZERR_NONE)
1481 if (outmsg.length > Z_MAXPKTLEN) {
1482 syslog(LOG_ERR, "sn: encrypted packet is too large");
1485 packlen = outmsg.length;
1487 pack=malloc(packlen);
1490 memcpy(pack, outmsg.data, packlen);
1491 krb5_free_data_contents(Z_krb5_ctx, &outmsg);
1495 length = htons((u_short) packlen);
1497 count = net_write(output, (char *) &length, sizeof(length));
1498 if (count != sizeof(length)) {
1500 syslog(LOG_WARNING, "snt xmit/len: %m");
1504 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1509 count = net_write(output, pack, packlen);
1510 if (count != packlen) {
1512 syslog(LOG_WARNING, "snt xmit: %m");
1516 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1526 * get a packet from the TCP socket
1527 * return 0 if successful, error code else
1531 get_packet(void *packet, int len, int *retlen)
1536 result = net_read(input, (char *) &length, sizeof(u_short));
1537 if (result < sizeof(short)) {
1541 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1547 length = ntohs(length);
1549 return ZSRV_BUFSHORT;
1550 result = net_read(input, packet, (int) length);
1551 if (result < length) {
1555 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1564 extract_sin(ZNotice_t *notice, struct sockaddr_in *target)
1566 char *cp = notice->z_message;
1570 if (!notice->z_message_len || *buf == '\0') {
1572 zdbug((LOG_DEBUG,"no addr"));
1574 return ZSRV_PKSHORT;
1576 target->sin_addr.s_addr = inet_addr(cp);
1578 cp += (strlen(cp) + 1); /* past the null */
1579 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1581 zdbug((LOG_DEBUG, "no port"));
1583 return(ZSRV_PKSHORT);
1585 target->sin_port = htons((u_short) atoi(cp));
1586 target->sin_family = AF_INET;
1591 net_read(FILE *f, char *buf, int len)
1598 cc = fread(buf, 1, len, f);
1615 net_write(FILE *f, char *buf, int len)
1620 cc = fwrite (buf, 1, wrlen, f);
1625 } while (wrlen > 0);
1630 setup_file_pointers (void)
1634 input = fdopen (live_socket, "r");
1638 fd = dup (live_socket);
1641 output = fdopen (fd, "w");