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 $
7 * $Id: bdump.c,v 1.54 2001/02/27 04:43:01 zacheiss Exp $
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: bdump.c,v 1.54 2001/02/27 04:43:01 zacheiss Exp $";
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 static void close_bdump __P((void* arg));
48 static Code_t bdump_send_loop __P((Server *server)),
49 bdump_ask_for __P((char *inst)),
50 bdump_recv_loop __P((Server *server));
51 static void bdump_get_v12 __P((ZNotice_t *, int, struct sockaddr_in *,
53 static Code_t get_packet __P((void *packet, int len, int *retlen));
54 static Code_t extract_sin __P((ZNotice_t *notice, struct sockaddr_in *target));
55 static Code_t send_done __P((void));
56 static Code_t send_list __P((ZNotice_Kind_t kind, int port, char *class_name,
57 char *inst, char *opcode, char *sender,
58 char *recip, char **lyst, int num));
59 static Code_t send_normal_tcp __P((ZNotice_Kind_t kind, int port,
61 char *inst, char *opcode, char *sender,
62 char *recip, char *message, int len));
63 static int net_read __P((FILE *f, char *buf, int len));
64 static int net_write __P((FILE *f, char *buf, int len));
65 static int setup_file_pointers __P((void));
66 static void shutdown_file_pointers __P((void));
67 static void cleanup __P((Server *server));
70 static long ticket5_time;
71 #define TKT5LIFETIME 8*60*60
72 #define tkt5_lifetime(val) (val)
76 static long ticket_time;
78 #define TKTLIFETIME 120
79 #define tkt_lifetime(val) ((long) val * 5L * 60L)
82 extern C_Block serv_key;
83 extern Sched serv_ksched;
85 #endif /* HAVE_KRB4 */
87 static Timer *bdump_timer;
88 static int live_socket = -1;
89 static FILE *input, *output;
90 static struct sockaddr_in bdump_sin;
92 static int cancel_outgoing_dump;
97 extern char *bdump_version;
100 * Functions for performing a brain dump between servers.
104 * offer the brain dump to another server
109 struct sockaddr_in *who;
112 char buf[512], *addr, *lyst[2];
114 int bdump_port = IPPORT_RESERVED - 1;
115 #endif /* !HAVE_KRB4 */
117 zdbug((LOG_DEBUG, "bdump_offer"));
121 * when using HAVE_KRB4 server-server authentication, we can
122 * use any random local address
124 bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
125 if (bdump_socket < 0) {
126 syslog(LOG_ERR,"bdump_offer: socket: %m");
130 memset(&bdump_sin, 0, sizeof(bdump_sin));
131 /* a port field of 0 makes the UNIX
132 * kernel choose an appropriate port/address pair */
134 bdump_sin.sin_port = 0;
135 bdump_sin.sin_addr = my_addr;
136 bdump_sin.sin_family = AF_INET;
137 retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin,
140 syslog(LOG_ERR, "bdump_offer: bind: %m");
145 if (!bdump_sin.sin_port) {
146 int len = sizeof(bdump_sin);
148 if (getsockname(bdump_socket,
149 (struct sockaddr *) &bdump_sin, &len) < 0) {
150 syslog(LOG_ERR, "bdump_offer: getsockname: %m");
156 #else /* !HAVE_KRB4 */
158 * when not using HAVE_KRB4, we can't use any old port, we use
159 * Internet reserved ports instead (rresvport)
161 bdump_socket = rresvport(&bdump_port);
162 if (bdump_socket < 0) {
163 syslog(LOG_ERR,"bdump_offer: socket: %m");
167 memset(&bdump_sin, 0, sizeof(bdump_sin));
168 bdump_sin.sin_port = htons((unsigned short) bdump_port);
169 bdump_sin.sin_addr = my_addr;
170 bdump_sin.sin_family = AF_INET;
171 #endif /* HAVE_KRB4 */
173 listen(bdump_socket, 1);
175 bdump_timer = timer_set_rel(20L, close_bdump, NULL);
176 FD_SET(bdump_socket, &interesting);
177 nfds = max(bdump_socket, srv_socket) + 1;
179 addr = inet_ntoa(bdump_sin.sin_addr);
180 sprintf(buf, "%d", ntohs(bdump_sin.sin_port));
184 retval = ZSetDestAddr(who);
185 if (retval != ZERR_NONE) {
186 syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s",
187 error_message(retval));
191 /* myname is the hostname */
192 /* the class instance is the version number, here it is */
193 /* bdump_version, which is set in main */
194 send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version,
195 ADMIN_BDUMP, myname, "", lyst, 2);
198 zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n",
199 inet_ntoa(bdump_sin.sin_addr),
200 ntohs(bdump_sin.sin_port)));
206 * Accept a connection, and send the brain dump to the other server
212 struct sockaddr_in from;
215 int fromlen = sizeof(from);
217 #ifdef _POSIX_VERSION
218 struct sigaction action;
225 unsigned short fromport;
226 #endif /* HAVE_KRB4 */
229 zdbug((LOG_DEBUG, "bdump_send"));
231 /* accept the connection, and send the brain dump */
232 live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen);
233 if (live_socket < 0) {
234 syslog(LOG_ERR,"bdump_send: accept: %m");
237 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
239 syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m");
242 fromport = ntohs(from.sin_port);
245 #ifdef _POSIX_VERSION
246 sigemptyset(&action.sa_mask);
248 action.sa_handler = SIG_IGN;
249 sigaction(SIGPIPE, &action, NULL);
252 signal(SIGPIPE, SIG_IGN); /* so we can detect failures */
255 from.sin_port = srv_addr.sin_port; /* we don't care what port
256 * it came from, and we need to
257 * fake out server_which_server() */
258 server = server_which_server(&from);
260 syslog(LOG_ERR, "bdump_send: unknown server?");
261 server = limbo_server;
264 zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d",
265 inet_ntoa(from.sin_addr), ntohs(from.sin_port)));
271 if (bdump_socket >= 0) {
272 /* shut down the listening socket and the timer. */
273 FD_CLR(bdump_socket, &interesting);
275 nfds = srv_socket + 1;
277 timer_reset(bdump_timer);
280 /* Now begin the brain dump. */
282 { /* "server" side */
283 krb5_auth_context actx;
286 #else /* HAVE_KRB5 */
288 /* receive the authenticator */
289 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
290 SERVER_SERVICE, srvtab_file);
291 if (retval != KSUCCESS) {
292 syslog(LOG_ERR, "bdump_send: getkdata: %s",
293 krb_get_err_text(retval));
301 if (strcmp(kdata.pname, SERVER_SERVICE) ||
302 strcmp(kdata.pinst, SERVER_INSTANCE) ||
303 strcmp(kdata.prealm, ZGetRealm())) {
304 syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
305 kdata.pname, kdata.pinst, kdata.prealm);
309 /* authenticate back */
310 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
313 syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
314 error_message (retval));
318 #else /* !HAVE_KRB4 */
319 if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
320 syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
324 #endif /* HAVE_KRB4 */
325 #endif /* HAVE_KRB5 */
327 retval = setup_file_pointers();
329 syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
330 error_message(retval));
334 retval = bdump_send_loop(server);
335 if (retval != ZERR_NONE) {
336 syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s",
337 error_message(retval));
341 retval = bdump_recv_loop(server);
342 if (retval != ZERR_NONE) {
343 syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s",
344 error_message(retval));
349 zdbug((LOG_DEBUG, "bdump_send: finished"));
351 if (server != limbo_server) {
352 /* set this guy to be up, and schedule a hello */
353 server->state = SERV_UP;
354 timer_reset(server->timer);
355 server->timer = timer_set_rel(0L, server_timo, server);
358 zdbug((LOG_DEBUG,"cleanup sbd"));
360 shutdown_file_pointers();
362 #ifdef _POSIX_VERSION
363 action.sa_handler = SIG_DFL;
364 sigaction(SIGPIPE, &action, NULL);
366 signal(SIGPIPE, SIG_DFL);
370 /* Now that we are finished dumping, send all the queued packets */
371 server_send_queue(server);
377 bdump_get_v12 (notice, auth, who, server)
380 struct sockaddr_in *who;
383 struct sockaddr_in from;
386 #ifdef _POSIX_VERSION
387 struct sigaction action;
392 #else /* !HAVE_KRB4 */
393 int reserved_port = IPPORT_RESERVED - 1;
394 #endif /* HAVE_KRB4 */
399 #ifdef _POSIX_VERSION
401 sigemptyset(&action.sa_mask);
402 action.sa_handler = SIG_IGN;
403 sigaction(SIGPIPE, &action, NULL);
405 signal(SIGPIPE, SIG_IGN); /* so we can detect problems */
406 #endif /* _POSIX_VRESION */
408 if (bdump_socket >= 0) {
409 /* We cannot go get a brain dump when someone may
410 potentially be connecting to us (if that other
411 server is the server to whom we are connecting,
412 we will deadlock. so we shut down the listening
413 socket and the timer. */
414 FD_CLR(bdump_socket, &interesting);
418 timer_reset(bdump_timer);
421 retval = extract_sin(notice, &from);
422 if (retval != ZERR_NONE) {
423 syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval));
424 #ifdef _POSIX_VERSION
425 action.sa_handler = SIG_DFL;
426 sigaction(SIGPIPE, &action, NULL);
428 signal(SIGPIPE, SIG_DFL);
435 if (ntohs(from.sin_port) > IPPORT_RESERVED ||
436 ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
437 syslog(LOG_ERR, "bdump_get: port not reserved: %d",
438 ntohs(from.sin_port));
442 live_socket = rresvport(&reserved_port);
443 #else /* !HAVE_KRB4 */
444 live_socket = socket(AF_INET, SOCK_STREAM, 0);
445 #endif /* HAVE_KRB4 */
446 if (live_socket < 0) {
447 syslog(LOG_ERR, "bdump_get: socket: %m");
451 if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) {
452 syslog(LOG_ERR, "bdump_get: connect: %m");
456 if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
458 syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m");
460 zdbug((LOG_DEBUG, "bdump_get: connected"));
463 /* Now begin the brain dump. */
466 { /* "client" side */
467 krb5_auth_context actx;
470 krb5_principal principal;
473 memset((char *)&creds, 0, sizeof(creds));
475 retval = krb5_build_principal(Z_krb5_ctx, &principal,
478 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
481 syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
486 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
488 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
489 krb5_free_principal(Z_krb5_ctx, principal);
494 retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
495 krb5_free_principal(Z_krb5_ctx, principal);
497 syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
498 krb5_free_cred_contents(Z_krb5_ctx, creds);
503 retval = krb5_get_credentials(Z_krb5_context, 0, Z_krb5_ccache,
505 krb5_free_cred_contents(Z_krb5_ctx, creds);
507 syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
512 retval = krb5_auth_con_init(Z_krb5_ctx, &actx);
514 syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
515 krb5_free_creds(Z_krb5_ctx, credsp);
520 memset((char *)data, 0, sizeof(krb5_data));
521 retval = krb5_mk_req_ext(Z_krb5_ctx, &actx, AP_OPTS_MUTUAL_REQUIRE|AP_OPTS_USE_SUBKEY,
522 NULL, credsp, &data);
524 syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
525 krb5_auth_con_free(Z_krb5_ctx, actx);
526 krb5_free_creds(Z_krb5_ctx, credsp);
533 /* send an authenticator */
538 retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
541 syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
546 zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
549 /* get his authenticator */
550 retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
551 SERVER_SERVICE, srvtab_file);
552 if (retval != KSUCCESS) {
553 syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
558 if (strcmp(kdata.pname, SERVER_SERVICE) ||
559 strcmp(kdata.pinst, SERVER_INSTANCE) ||
560 strcmp(kdata.prealm, ZGetRealm())) {
561 syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
562 kdata.pname, kdata.pinst,kdata.prealm);
566 #endif /* HAVE_KRB4 */
568 retval = setup_file_pointers();
570 syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
571 error_message (retval));
575 retval = bdump_recv_loop(server);
576 if (retval != ZERR_NONE) {
577 syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s",
578 error_message(retval));
583 zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
585 retval = bdump_send_loop(server);
586 if (retval != ZERR_NONE) {
587 syslog(LOG_WARNING, "bdump_send_loop failed: %s",
588 error_message(retval));
593 zdbug((LOG_DEBUG, "bdump_get: gbd finished"));
595 /* set this guy to be up, and schedule a hello */
596 server->state = SERV_UP;
597 timer_reset(server->timer);
598 server->timer = timer_set_rel(0L, server_timo, server);
601 zdbug((LOG_DEBUG,"cleanup gbd"));
603 shutdown_file_pointers();
604 #ifdef _POSIX_VERSION
605 action.sa_handler = SIG_DFL;
606 sigaction(SIGPIPE, &action, NULL);
608 signal(SIGPIPE, SIG_DFL);
612 /* Now that we are finished dumping, send all the queued packets */
613 server_send_queue(server);
619 bdump_get(notice, auth, who, server)
622 struct sockaddr_in *who;
625 void (*proc) __P((ZNotice_t *, int, struct sockaddr_in *, Server *));
631 syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s",
632 notice->z_class_inst, inet_ntoa(who->sin_addr));
635 if (strcmp (notice->z_class_inst, "1.2") == 0)
636 proc = bdump_get_v12;
639 (*proc)(notice, auth, who, server);
642 "bdump_get: Incompatible bdump version '%s' from %s",
643 notice->z_class_inst,
644 inet_ntoa(who->sin_addr));
649 * Send a list off as the specified notice
653 bdump_send_list_tcp(kind, addr, class_name, inst, opcode, sender, recip, lyst,
656 struct sockaddr_in *addr;
658 char *class_name, *inst, *opcode, *sender, *recip, **lyst;
661 char *pack, addrbuf[100];
666 memset (¬ice, 0, sizeof(notice));
668 retval = ZMakeAscii(addrbuf, sizeof(addrbuf),
669 (unsigned char *) &addr->sin_addr,
670 sizeof(struct in_addr));
671 if (retval != ZERR_NONE)
673 notice.z_kind = kind;
675 notice.z_port = addr->sin_port;
676 notice.z_class = class_name;
677 notice.z_class_inst = inst;
678 notice.z_opcode = opcode;
679 notice.z_sender = sender;
680 notice.z_recipient = recip;
681 notice.z_default_format = "";
682 notice.z_num_other_fields = 1;
683 notice.z_other_fields[0] = addrbuf;
685 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
686 if (retval != ZERR_NONE)
689 length = htons((u_short) packlen);
691 count = net_write(output, (char *) &length, sizeof(length));
692 if (count != sizeof(length)) {
697 syslog(LOG_WARNING, "slt (length) xmit: %d vs %d",
698 sizeof(length), count);
700 return(ZSRV_PKSHORT);
704 count = net_write(output, pack, packlen);
705 if (count != packlen) {
710 syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d",
713 return(ZSRV_PKSHORT);
721 shutdown_file_pointers() {
730 if (live_socket >= 0) {
740 #ifdef _POSIX_VERSION
741 struct sigaction action;
745 zdbug((LOG_DEBUG, "bdump cleanup"));
747 if (server != limbo_server) {
748 server->state = SERV_DEAD;
749 timer_reset(server->timer);
750 server->timer = timer_set_rel(0L, server_timo, server);
752 shutdown_file_pointers ();
753 #ifdef _POSIX_VERSION
755 sigemptyset(&action.sa_mask);
756 action.sa_handler = SIG_DFL;
757 sigaction(SIGPIPE,&action, NULL);
759 signal(SIGPIPE, SIG_DFL);
760 #endif /* _POSIX_VERSION */
769 /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and
770 * at least INST_SZ bytes long. */
771 static char buf[INST_SZ + 1] = SERVER_INSTANCE;
778 /* have they expired ? */
779 if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
782 zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW,
783 NOW - tkt_lifetime(TKTLIFETIME) + 15L));
787 retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, ZGetRealm(),
788 "krbtgt", ZGetRealm(),
789 TKTLIFETIME, srvtab_file);
790 if (retval != KSUCCESS) {
791 syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s",
792 krb_get_err_text(retval));
800 retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE,
801 ZGetRealm(), 0 /*kvno*/,
802 srvtab_file, serv_key);
803 if (retval != KSUCCESS) {
804 syslog(LOG_ERR, "get_tgt: read_service_key: %s",
805 krb_get_err_text(retval));
809 s = (Sched *) check_key_sched_cache(serv_key);
813 des_key_sched(serv_key, serv_ksched.s);
814 add_to_key_sched_cache(serv_key, &serv_ksched);
817 des_key_sched(serv_key, serv_ksched.s);
819 #endif /* !NOENCRYPTION */
823 if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
825 krb5_get_init_creds_opt opt;
827 krb5_principal principal;
829 memset(&cred, 0, sizeof(cred));
831 retval = krb5_build_principal(Z_krb5_ctx, &principal,
834 SERVER_KRB5_SERVICE, SERVER_INSTANCE,
837 krb5_free_principal(Z_krb5_ctx, principal);
841 krb5_get_init_creds_opt_init (&opt);
842 krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
844 retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
845 if (retval) return(1);
847 retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
854 krb5_free_principal(Z_krb5_ctx, principal);
855 krb5_kt_close(Z_krb5_ctx, kt);
856 if (retval) return(1);
858 retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
859 if (retval) return(1);
861 retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
862 if (retval) return(1);
866 krb5_free_cred_contents (Z_krb5_ctx, &cred);
871 #endif /* HAVE_KRB4 */
874 * The braindump offer wasn't taken, so we retract it.
882 if (bdump_socket >= 0) {
883 FD_CLR(bdump_socket, &interesting);
885 nfds = srv_socket + 1;
888 zdbug((LOG_DEBUG, "bdump not used"));
892 zdbug((LOG_DEBUG, "bdump not open"));
899 * Start receiving instruction notices from the brain dump socket
903 bdump_recv_loop(server)
910 Client *client = NULL;
911 struct sockaddr_in who;
915 #endif /* HAVE_KRB4 */
916 ZRealm *realm = NULL;
919 zdbug((LOG_DEBUG, "bdump recv loop"));
922 /* do the inverse of bdump_send_loop, registering stuff on the fly */
924 if (packets_waiting()) {
925 /* A non-braindump packet is waiting; handle it. */
927 bdump_concurrent = 1;
929 bdump_concurrent = 0;
932 len = sizeof(packet);
933 retval = get_packet(packet, len, &len);
934 if (retval != ZERR_NONE) {
935 syslog(LOG_ERR, "brl get pkt: %s", error_message(retval));
939 retval = ZParseNotice(packet, len, ¬ice);
940 if (retval != ZERR_NONE) {
941 syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
946 syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'",
947 ZNoticeKinds[(int) notice.z_kind], notice.z_class,
948 notice.z_class_inst, notice.z_opcode, notice.z_sender,
952 if (notice.z_num_other_fields >= 1) {
953 retval = ZReadAscii(notice.z_other_fields[0],
954 strlen(notice.z_other_fields[0]),
955 (unsigned char *) &who.sin_addr,
956 sizeof(struct in_addr));
957 if (retval != ZERR_NONE) {
958 syslog(LOG_ERR, "brl zreadascii failed: %s",
959 error_message(retval));
963 who.sin_addr.s_addr = notice.z_sender_addr.s_addr;
965 who.sin_family = AF_INET;
966 who.sin_port = notice.z_port;
968 if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) {
969 /* end of brain dump */
971 } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) {
972 /* get a realm from the message */
973 realm = realm_get_realm_by_name(notice.z_message);
975 syslog(LOG_ERR, "brl newrlm failed: no realm %s",
978 } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
979 /* 1 = tell it we are authentic */
980 retval = ulogin_dispatch(¬ice, 1, &who, server);
981 if (retval != ZERR_NONE) {
982 syslog(LOG_ERR, "brl ul_disp failed: %s",
983 error_message(retval));
986 } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) {
988 notice.z_port = htons((u_short) atoi(notice.z_message));
989 retval = client_register(¬ice, &who.sin_addr, &client, 0);
990 if (retval != ZERR_NONE) {
991 syslog(LOG_ERR,"brl failed: %s", error_message(retval));
995 memset(client->session_key, 0, sizeof(C_Block));
996 if (*notice.z_class_inst) {
997 /* a C_Block is there */
998 cp = notice.z_message + strlen(notice.z_message) + 1;
999 retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
1000 if (retval != ZERR_NONE) {
1001 syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
1002 error_message(retval), cp);
1005 memcpy(cblock, client->session_key, sizeof(C_Block));
1007 des_ecb_encrypt(cblock, client->session_key, serv_ksched.s,
1012 #endif /* HAVE_KRB4 */
1013 } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
1014 /* a subscription packet */
1016 syslog(LOG_ERR, "brl no client");
1019 retval = subscr_subscribe(client, ¬ice, server);
1020 if (retval != ZERR_NONE) {
1021 syslog(LOG_WARNING, "brl subscr failed: %s",
1022 error_message(retval));
1025 } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) {
1026 /* add a subscription for a realm */
1028 retval = subscr_realm(realm, ¬ice);
1029 if (retval != ZERR_NONE) {
1030 syslog(LOG_WARNING, "brl subscr failed: %s",
1031 error_message(retval));
1035 /* Other side tried to send us subs for a realm we didn't
1036 know about, and so we drop them silently */
1039 syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode);
1040 return ZSRV_UNKNOWNOPCODE;
1046 * Send all the state to the peer.
1050 bdump_send_loop(server)
1056 zdbug((LOG_DEBUG, "bdump send loop"));
1059 retval = uloc_send_locations();
1060 if (retval != ZERR_NONE)
1062 retval = client_send_clients();
1063 if (retval != ZERR_NONE)
1065 retval = realm_send_realms();
1066 if (retval != ZERR_NONE)
1072 * Send a sync indicating end of this host
1081 zdbug((LOG_DEBUG, "send_done"));
1083 retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS,
1084 "", ADMIN_DONE, myname, "", NULL, 0);
1090 * Send a list off as the specified notice
1094 send_list(kind, port, class_name, inst, opcode, sender, recip, lyst, num)
1095 ZNotice_Kind_t kind;
1097 char *class_name, *inst, *opcode, *sender, *recip, **lyst;
1104 memset (¬ice, 0, sizeof(notice));
1106 notice.z_kind = kind;
1107 notice.z_port = port;
1108 notice.z_class = class_name;
1109 notice.z_class_inst = inst;
1110 notice.z_opcode = opcode;
1111 notice.z_sender = sender;
1112 notice.z_recipient = recip;
1113 notice.z_default_format = "";
1114 notice.z_num_other_fields = 0;
1116 retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
1117 if (retval != ZERR_NONE) {
1118 syslog(LOG_WARNING, "sl format: %s", error_message(retval));
1122 retval = ZSendPacket(pack, packlen, 0);
1123 if (retval != ZERR_NONE)
1124 syslog(LOG_WARNING, "sl xmit: %s", error_message(retval));
1130 * Send a message off as the specified notice, via TCP
1134 send_normal_tcp(kind, port, class_name, inst, opcode, sender, recip,
1136 ZNotice_Kind_t kind;
1138 char *class_name, *inst, *opcode, *sender, *recip, *message;
1146 memset (¬ice, 0, sizeof(notice));
1148 notice.z_kind = kind;
1149 notice.z_port = port;
1150 notice.z_class = class_name;
1151 notice.z_class_inst = inst;
1152 notice.z_opcode = opcode;
1153 notice.z_sender = sender;
1154 notice.z_recipient = recip;
1155 notice.z_default_format = "";
1156 notice.z_message = message;
1157 notice.z_message_len = len;
1158 notice.z_num_other_fields = 0;
1160 retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH);
1161 if (retval != ZERR_NONE) {
1162 syslog(LOG_WARNING, "sn format: %s", error_message(retval));
1166 length = htons((u_short) packlen);
1168 count = net_write(output, (char *) &length, sizeof(length));
1169 if (count != sizeof(length)) {
1171 syslog(LOG_WARNING, "snt xmit/len: %m");
1175 syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count);
1180 count = net_write(output, pack, packlen);
1181 if (count != packlen) {
1183 syslog(LOG_WARNING, "snt xmit: %m");
1187 syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count);
1197 * get a packet from the TCP socket
1198 * return 0 if successful, error code else
1202 get_packet(packet, len, retlen)
1210 result = net_read(input, (char *) &length, sizeof(u_short));
1211 if (result < sizeof(short)) {
1215 syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result,
1221 length = ntohs(length);
1223 return ZSRV_BUFSHORT;
1224 result = net_read(input, packet, (int) length);
1225 if (result < length) {
1229 syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length);
1238 extract_sin(notice, target)
1240 struct sockaddr_in *target;
1242 char *cp = notice->z_message;
1246 if (!notice->z_message_len || *buf == '\0') {
1248 zdbug((LOG_DEBUG,"no addr"));
1250 return ZSRV_PKSHORT;
1252 target->sin_addr.s_addr = inet_addr(cp);
1254 cp += (strlen(cp) + 1); /* past the null */
1255 if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) {
1257 zdbug((LOG_DEBUG, "no port"));
1259 return(ZSRV_PKSHORT);
1261 target->sin_port = htons((u_short) atoi(cp));
1262 target->sin_family = AF_INET;
1267 net_read(f, buf, len)
1277 cc = fread(buf, 1, len, f);
1294 net_write(f, buf, len)
1302 cc = fwrite (buf, 1, wrlen, f);
1307 } while (wrlen > 0);
1312 setup_file_pointers ()
1316 input = fdopen (live_socket, "r");
1320 fd = dup (live_socket);
1323 output = fdopen (fd, "w");