From ac16f380e349fa39ec7e26bccb5456cb300006a5 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Sun, 14 Sep 1997 17:50:06 +0000 Subject: Pull in sources from zephyr locker. See /mit/zephyr/repository for detailed change information. --- server/dispatch.c.auth | 1078 ------------------------------------------------ 1 file changed, 1078 deletions(-) delete mode 100644 server/dispatch.c.auth (limited to 'server/dispatch.c.auth') diff --git a/server/dispatch.c.auth b/server/dispatch.c.auth deleted file mode 100644 index 8707c2f..0000000 --- a/server/dispatch.c.auth +++ /dev/null @@ -1,1078 +0,0 @@ -/* This file is part of the Project Athena Zephyr Notification System. - * It contains functions for dispatching a notice. - * - * Created by: John T. Kohl - * - * $Source$ - * $Author$ - * - * Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology. - * For copying and distribution information, see the file - * "mit-copyright.h". - */ - -#include - -#ifndef lint -#ifndef SABER -static char rcsid_dispatch_c[] = - "$Id$"; -#endif -#endif - -#include "zserver.h" -#include - -#ifdef DEBUG -Zconst char *ZNoticeKinds[9] = {"UNSAFE", "UNACKED", "ACKED", "HMACK", - "HMCTL", "SERVACK", "SERVNAK", "CLIENTACK", - "STAT"}; -#endif -/* - * - * External Routines: - * - * void dispatch(notice, auth, who) - * ZNotice_t *notice; - * int auth; - * struct sockaddr_in *who; - * - * void clt_ack(notice, who, sent) - * ZNotice_t *notice; - * struct sockaddr_in *who; - * ZSentType sent; - * - * void nack_release(client) - * ZClient_t *client; - * - * void sendit(notice, auth, who) - * ZNotice_t *notice; - * int auth; - * struct sockaddr_in *who; - * - * void xmit(notice, dest, auth, client) - * ZNotice_t *notice; - * struct sockaddr_in *dest; - * int auth; - * ZClient_t *client; - */ - - -/* patchable magic numbers controlling the retransmission rate and count */ -int num_rexmits = NUM_REXMITS; -long rexmit_secs = REXMIT_SECS; -long abs_timo = REXMIT_SECS*NUM_REXMITS + 10; - -ZSTRING *class_control, *class_admin, *class_hm, *class_ulogin, - *class_ulocate; - -#ifdef __STDC__ -# define P(s) s -#else -# define P(s) () -#endif - -static void nack_cancel P((register ZNotice_t *, struct sockaddr_in *)); -static void dispatch P((ZNotice_t *, int, struct sockaddr_in *, int)); -static int send_to_dest P((ZNotice_t *, int, ZDestination *dest, int)); - -#undef P - -ZStatistic interserver_notices = {0, "inter-server notices"}; -ZStatistic hm_packets = {0, "hostmanager packets"}; -ZStatistic control_notices = {0, "client control notices"}; -ZStatistic message_notices = {0, "message notices"}; -ZStatistic login_notices = {0, "login notices"}; -ZStatistic i_s_ctls = {0, "inter-server control notices"}; -ZStatistic i_s_logins = {0, "inter-server login notices"}; -ZStatistic i_s_admins = {0, "inter-server admin notices"}; -ZStatistic i_s_locates = {0, "inter-server locate notices"}; -ZStatistic locate_notices = {0, "locate notices"}; -ZStatistic admin_notices = {0, "admin notices"}; - -static void -#ifdef __STDC__ -dump_stats (void *arg) -#else -dump_stats (arg) -void *arg; -#endif -{ - syslog(LOG_INFO, "stats: %s: %d", hm_packets.str, hm_packets.val); - syslog(LOG_INFO, "stats: %s: %d", control_notices.str, - control_notices.val); - syslog(LOG_INFO, "stats: %s: %d", message_notices.str, - message_notices.val); - syslog(LOG_INFO, "stats: %s: %d", login_notices.str, - login_notices.val); - syslog(LOG_INFO, "stats: %s: %d", locate_notices.str, - locate_notices.val); - syslog(LOG_INFO, "stats: %s: %d", admin_notices.str, - admin_notices.val); - syslog(LOG_INFO, "stats: %s: %d", interserver_notices.str, - interserver_notices.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_ctls.str, i_s_ctls.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_logins.str, i_s_logins.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_admins.str, i_s_admins.val); - syslog(LOG_INFO, "stats: %s: %d", i_s_locates.str, i_s_locates.val); - /* log stuff once an hour */ - (void) timer_set_rel ((long) 6*60*60, dump_stats, arg); -} - -/* - * Handle an input packet. - * Warning: this function may be called from within a brain dump. - */ - -void -handle_packet() -{ - Code_t status; - ZPacket_t input_packet; /* from the network */ - ZNotice_t new_notice; /* parsed from input_packet */ - int input_len; /* len of packet */ - struct sockaddr_in input_sin; /* Zconstructed for authent */ - struct sockaddr_in whoisit; /* for holding peer's address */ - int authentic; /* authentic flag */ - ZSrvPending_t *pending; /* pending packet */ - ZHostList_t *host; /* host ptr */ - int from_server; /* packet is from another server */ -#ifdef DEBUG - static int first_time = 1; -#endif - -#ifdef DEBUG - /* Dump statistics five minutes after startup */ - if (first_time) { - first_time = 0; - (void) timer_set_rel (5*60, dump_stats, (void *) 0); - } -#endif - /* handle traffic */ - - if (otherservers[me_server_idx].zs_update_queue) { - /* something here for me; take care of it */ -#if 1 - zdbug((LOG_DEBUG, "internal queue process")); -#endif - - pending = otherservers[me_server_idx].zs_update_queue->q_forw; - host = hostm_find_host(&(pending->pend_who.sin_addr)); - if (host && host->zh_locked) { - /* can't deal with it now. to preserve ordering, - we can't process other packets, esp. since we - may block since we don't really know if there - are things in the real queue. */ -#if 1 - zdbug((LOG_DEBUG,"host %s is locked", - inet_ntoa(host->zh_addr.sin_addr))); -#endif - return; - } - pending = server_dequeue(me_server); /* we can do it, remove */ - - if ((status = ZParseNotice(pending->pend_packet, - pending->pend_len, - &new_notice)) != ZERR_NONE) { - syslog(LOG_ERR, - "bad notice parse (%s): %s", - inet_ntoa(pending->pend_who.sin_addr), - error_message(status)); - } else - dispatch(&new_notice, pending->pend_auth, - &pending->pend_who, 1); - server_pending_free(pending); - return; - } - /* - * nothing in internal queue, go to the external library - * queue/socket - */ - if ((status = ZReceivePacket(input_packet, - &input_len, - &whoisit)) != ZERR_NONE) { - syslog(LOG_ERR, - "bad packet receive: %s from %s", - error_message(status), inet_ntoa(whoisit.sin_addr)); - return; - } - npackets++; - if ((status = ZParseNotice(input_packet, - input_len, - &new_notice)) != ZERR_NONE) { - syslog(LOG_ERR, - "bad notice parse (%s): %s", - inet_ntoa(whoisit.sin_addr), - error_message(status)); - return; - } - if (server_which_server(&whoisit)) { - /* we need to parse twice--once to get - the source addr, second to check - authentication */ - (void) memset((caddr_t) &input_sin, 0, - sizeof(input_sin)); - input_sin.sin_addr.s_addr = new_notice.z_sender_addr.s_addr; - input_sin.sin_port = new_notice.z_port; - input_sin.sin_family = AF_INET; - authentic = ZCheckAuthentication(&new_notice, &input_sin); - from_server = 1; - } else { - from_server = 0; - authentic = ZCheckAuthentication(&new_notice, &whoisit); - } - - if (whoisit.sin_port != hm_port && - strcasecmp (new_notice.z_class,ZEPHYR_ADMIN_CLASS) && - whoisit.sin_port != sock_sin.sin_port && - new_notice.z_kind != CLIENTACK) { - syslog(LOG_ERR, - "bad port %s/%d", - inet_ntoa(whoisit.sin_addr), - ntohs(whoisit.sin_port)); - return; - } - - message_notices.val++; - dispatch(&new_notice, authentic, &whoisit, from_server); - return; -} -/* - * Dispatch a notice. - */ - -static void -dispatch(notice, auth, who, from_server) - ZNotice_t *notice; - int auth; - struct sockaddr_in *who; - int from_server; -{ - Code_t status; - ZSTRING *notice_class; - struct sockaddr_in who2; - int authflag; -#ifdef DEBUG - char dbg_buf[BUFSIZ]; -#endif - - /* Set "authflag" to 1 or 0 for handler functions. Treat - * ZAUTH_CKSUM_FAILED as authentic except for sendit(), which is - * handled below. */ - switch (auth) { - case ZAUTH_YES: - case ZAUTH_CKSUM_FAILED: - authflag = 1; - break; - case ZAUTH_FAILED: - case ZAUTH_NO: - default: - authflag = 0; - break; - } - - if ((int) notice->z_kind < (int) UNSAFE || - (int) notice->z_kind > (int) CLIENTACK) { - syslog(LOG_NOTICE, "bad notice kind 0x%x from %s", - (int) notice->z_kind, - inet_ntoa(who->sin_addr)); - return; - } -#if 0 - if (zdebug) { - (void) sprintf (dbg_buf, - "disp:%s '%s' '%s' '%s' notice to '%s' from '%s' %s/%d/%d", - ZNoticeKinds[(int) notice->z_kind], - notice->z_class, - notice->z_class_inst, - notice->z_opcode, - notice->z_recipient, - notice->z_sender, - inet_ntoa(who->sin_addr), - ntohs(who->sin_port), - ntohs(notice->z_port)); - syslog (LOG_DEBUG, "%s", dbg_buf); - } -#endif - - if (notice->z_kind == CLIENTACK) { - nack_cancel(notice, who); - return; - } - - who2 = *who; -#if 0 - if (0 && from_server) { - /* incorporate server_dispatch here */ - } -#endif - notice_class = make_zstring(notice->z_class,1); - - if (from_server) { - interserver_notices.val++; - status = server_dispatch(notice, auth, who); - } else if (class_is_hm(notice_class)) { - hm_packets.val++; - status = hostm_dispatch(notice, auth, who, me_server); - } else if (class_is_control(notice_class)) { - control_notices.val++; - status = control_dispatch(notice, auth, who, me_server); - } else if (class_is_ulogin(notice_class)) { - login_notices.val++; - status = ulogin_dispatch(notice, auth, who, me_server); - } else if (class_is_ulocate(notice_class)) { - locate_notices.val++; - status = ulocate_dispatch(notice, auth, who, me_server); - } else if (class_is_admin(notice_class)) { - admin_notices.val++; - status = server_adispatch(notice, auth, who, me_server); - } else { - if (auth == ZAUTH_CKSUM_FAILED) - authflag = 0; - sendit (notice, auth, who); - free_zstring(notice_class); - return; - } - - if (status == ZSRV_REQUEUE) { -#ifdef CONCURRENT - server_self_queue(notice, auth, who); -#else - syslog(LOG_ERR, "requeue while not concurr"); - abort(); -#endif - } - free_zstring(notice_class); -} - -/* - * Send a notice off to those clients who have subscribed to it. - */ - -void -sendit(notice, auth, who) - ZNotice_t *notice; - int auth; - struct sockaddr_in *who; -{ - static int send_counter = 0; - int any = 0; - ZAcl_t *acl; - ZDestination dest; - ZSTRING *class; - - class = make_zstring(notice->z_class,1); - if ((acl = class_get_acl(class)) != NULLZACLT) { - /* if controlled and not auth, fail */ - if (!auth) { - syslog(LOG_WARNING, "sendit unauthentic %s from %s", - notice->z_class, notice->z_sender); - clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); - return; - } - /* if not auth to transmit, fail */ - if (!access_check(notice->z_sender, acl, TRANSMIT)) { - syslog(LOG_WARNING, "sendit unauthorized %s from %s", - notice->z_class, notice->z_sender); - clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); - return; - } - /* sender != inst and not auth to send to others --> fail */ - if ((strcmp (notice->z_sender, notice->z_class_inst)) && - (!access_check(notice->z_sender, acl, INSTUID))) { - syslog(LOG_WARNING, - "sendit unauth uid %s %s.%s", - notice->z_sender, - notice->z_class, - notice->z_class_inst); - clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); - return; - } - } - if (memcmp(¬ice->z_sender_addr.s_addr, &who->sin_addr.s_addr, - sizeof(notice->z_sender_addr.s_addr))) { - /* someone is playing games... */ - /* inet_ntoa returns pointer to static area */ - /* max size is 255.255.255.255 */ - char buffer[16]; - (void) strcpy(buffer, inet_ntoa(who->sin_addr)); - if (!auth) { - syslog(LOG_WARNING, "sendit unauthentic fake packet: claimed %s, real %s", - inet_ntoa(notice->z_sender_addr), buffer); - clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); - return; - } - if (ntohl(notice->z_sender_addr.s_addr) != 0) { - syslog(LOG_WARNING, "sendit invalid address: claimed %s, real %s", - inet_ntoa(notice->z_sender_addr), buffer); - clt_ack(notice, who, AUTH_FAILED); - free_zstring(class); - return; - } - syslog(LOG_WARNING, "sendit addr mismatch: claimed %s, real %s", - inet_ntoa(notice->z_sender_addr), buffer); - } - - /* Increment the send counter, used to prevent duplicate sends to - * clients. On the off-chance that we wrap around to 0, skip over - * it to prevent missing clients which have never had a packet - * sent to them. */ - send_counter++; - if (send_counter == 0) - send_counter = 1; - - /* Send to clients subscribed to the triplet itself. */ - dest.classname = class; - dest.inst = make_zstring(notice->z_class_inst, 1); - dest.recip = make_zstring(notice->z_recipient, 0); - if (send_to_dest(notice, auth, &dest, send_counter)) - any = 1; - - /* Send to clients subscribed to the triplet with the instance - * substituted with the wildcard instance. */ - free_zstring(dest.inst); - dest.inst = wildcard_instance; - if (send_to_dest(notice, auth, &dest, send_counter)) - any = 1; - - free_zstring(class); - free_zstring(dest.recip); - if (any) - ack(notice, who); - else - nack(notice, who); -} - -/* - * Send to each client in the list. Avoid duplicates by setting - * last_send on each client to send_counter, a nonce which is updated - * by sendit() above. - */ - -static int -send_to_dest(notice, auth, dest, send_counter) - ZNotice_t *notice; - int auth; - ZDestination *dest; - int send_counter; -{ - register ZClientList_t *list, *p; - register ZClient_t *client; - register int any = 0; - - list = triplet_lookup(dest); - if (list != NULLZCLT) { - for (p = list->q_forw; p != list; p = p->q_forw) { - client = p->zclt_client; - if (client->last_send == send_counter) - continue; - client->last_send = send_counter; - xmit(notice, &(client->zct_sin), auth, client); - any = 1; - } - } - return any; -} - -/* - * Clean up the not-yet-acked queue and release anything destined - * for the client. - */ - -void -nack_release(client) - ZClient_t *client; -{ - register ZNotAcked_t *nacked, *nack2; - - /* search the not-yet-acked list for anything destined to him, and - flush it. */ - for (nacked = nacklist->q_forw; - nacked != nacklist;) - if ((nacked->na_addr.sin_addr.s_addr == client->zct_sin.sin_addr.s_addr) && - (nacked->na_addr.sin_port == client->zct_sin.sin_port)) { - /* go back, since remque will change things */ - nack2 = nacked->q_back; - timer_reset(nacked->na_timer); - xremque(nacked); - xfree(nacked->na_packet); - xfree(nacked); - /* now that the remque adjusted the linked list, - we go forward again */ - nacked = nack2->q_forw; - } else - nacked = nacked->q_forw; - return; -} - -/* - * Send one packet of a fragmented message to a client. After transmitting, - * put it onto the not ack'ed list. - */ - -/* the arguments must be the same as the arguments to Z_XmitFragment */ -/*ARGSUSED*/ -Code_t -xmit_frag(notice, buf, len, waitforack) - ZNotice_t *notice; - char *buf; - int len; - int waitforack; -{ - char *savebuf; - register ZNotAcked_t *nacked; - Code_t retval; - - if ((retval = ZSendPacket(buf, len, 0)) != ZERR_NONE) { - syslog(LOG_WARNING, "xmit_frag send: %s", - error_message(retval)); - return(retval); - } - - /* now we've sent it, mark it as not ack'ed */ - - if (!(nacked = (ZNotAcked_t *)xmalloc(sizeof(ZNotAcked_t)))) { - /* no space: just punt */ - syslog(LOG_WARNING, "xmit_frag nack malloc"); - return(ENOMEM); - } - - if (!(savebuf = (char *)xmalloc(len))) { - /* no space: just punt */ - syslog(LOG_WARNING, "xmit_frag pack malloc"); - return(ENOMEM); - } - - (void) memcpy(savebuf, buf, len); - - nacked->na_rexmits = 0; - nacked->na_packet = savebuf; - nacked->na_srv_idx = 0; - nacked->na_addr = ZGetDestAddr(); - nacked->na_packsz = len; - nacked->na_uid = notice->z_uid; - nacked->q_forw = nacked->q_back = nacked; - nacked->na_abstimo = NOW + abs_timo; - - /* set a timer to retransmit when done */ - nacked->na_timer = timer_set_rel(rexmit_secs, - rexmit, - (void *) nacked); - /* chain in */ - xinsque(nacked, nacklist); - return(ZERR_NONE); -} - -/* - * Send the notice to the client. After transmitting, put it onto the - * not ack'ed list. - */ - -void -xmit(notice, dest, auth, client) - ZNotice_t *notice; - struct sockaddr_in *dest; - int auth; - ZClient_t *client; -{ - caddr_t noticepack; - register ZNotAcked_t *nacked; - int packlen; - Code_t retval; - -#if 0 - zdbug((LOG_DEBUG,"xmit")); -#endif - - if (!(noticepack = (caddr_t) xmalloc(sizeof(ZPacket_t)))) { - syslog(LOG_ERR, "xmit malloc"); - return; /* DON'T put on nack list */ - } - - packlen = sizeof(ZPacket_t); - - if (auth && client) { /* - we are distributing authentic and - we have a pointer to auth info - */ -#ifdef KERBEROS - - if ((retval = ZFormatAuthenticNotice(notice, - noticepack, - packlen, - &packlen, - client->zct_cblock)) - != ZERR_NONE) { - syslog(LOG_ERR, "xmit auth format: %s", - error_message(retval)); - xfree(noticepack); - return; - } -#else /* !KERBEROS */ - notice->z_auth = 1; - if ((retval = ZFormatSmallRawNotice(notice, - noticepack, - &packlen)) - != ZERR_NONE) { - syslog(LOG_ERR, "xmit auth/raw format: %s", - error_message(retval)); - xfree(noticepack); - return; - } -#endif /* KERBEROS */ - } else { - notice->z_auth = 0; - notice->z_authent_len = 0; - notice->z_ascii_authent = (char *)""; - if ((retval = ZFormatSmallRawNotice(notice, - noticepack, - &packlen)) != ZERR_NONE) { - syslog(LOG_ERR, "xmit format: %s", - error_message(retval)); - xfree(noticepack); - return; /* DON'T put on nack list */ - } - } -#if 0 - zdbug((LOG_DEBUG," to %s/%d",inet_ntoa(dest->sin_addr), - ntohs(dest->sin_port))); -#endif - if ((retval = ZSetDestAddr(dest)) != ZERR_NONE) { - syslog(LOG_WARNING, "xmit set addr: %s", - error_message(retval)); - xfree(noticepack); - return; - } - if ((retval = ZSendPacket(noticepack, packlen, 0)) != ZERR_NONE) { - syslog(LOG_WARNING, "xmit xmit: (%s/%d) %s", - inet_ntoa(dest->sin_addr), ntohs(dest->sin_port), - error_message(retval)); - xfree(noticepack); - return; - } - - /* now we've sent it, mark it as not ack'ed */ - - if (!(nacked = (ZNotAcked_t *)xmalloc(sizeof(ZNotAcked_t)))) { - /* no space: just punt */ - syslog(LOG_WARNING, "xmit nack malloc"); - xfree(noticepack); - return; - } - - nacked->na_rexmits = 0; - nacked->na_packet = noticepack; - nacked->na_srv_idx = 0; /* XXX */ - nacked->na_addr = *dest; - nacked->na_packsz = packlen; - nacked->na_uid = notice->z_uid; - nacked->q_forw = nacked->q_back = nacked; - nacked->na_abstimo = NOW + abs_timo; - - /* set a timer to retransmit when done */ - nacked->na_timer = timer_set_rel(rexmit_secs, - rexmit, - (void *) nacked); - /* chain in */ - xinsque(nacked, nacklist); - -} - - -/* - * Retransmit the packet specified. If we have timed out or retransmitted - * too many times, punt the packet and initiate the host recovery algorithm - * Else, increment the count and re-send the notice packet. - */ - -void -#ifdef __STDC__ -rexmit(void *arg) -#else -rexmit(arg) - void *arg; -#endif -{ - register ZNotAcked_t *nackpacket = (ZNotAcked_t*) arg; - int retval; - ZNotice_t dummy_notice; - register ZClient_t *client; - -#if 1 - zdbug((LOG_DEBUG,"rexmit")); -#endif - - if (++(nackpacket->na_rexmits) > num_rexmits || - NOW > nackpacket->na_abstimo) { - /* possibly dead client */ - - dummy_notice.z_port = nackpacket->na_addr.sin_port; - - client = client_which_client(&nackpacket->na_addr, - &dummy_notice); - - /* unlink & free packet */ - xremque(nackpacket); - xfree(nackpacket->na_packet); - xfree(nackpacket); - - /* initiate recovery */ - if (client) - server_recover(client); - return; - } - - /* retransmit the packet */ - -#if 0 - zdbug((LOG_DEBUG," to %s/%d", - inet_ntoa(nackpacket->na_addr.sin_addr), - ntohs(nackpacket->na_addr.sin_port))); -#endif - if ((retval = ZSetDestAddr(&nackpacket->na_addr)) - != ZERR_NONE) { - syslog(LOG_WARNING, "rexmit set addr: %s", - error_message(retval)); - goto requeue; - - } - if ((retval = ZSendPacket(nackpacket->na_packet, - nackpacket->na_packsz, 0)) != ZERR_NONE) - syslog(LOG_WARNING, "rexmit xmit: %s", error_message(retval)); - -requeue: - /* reset the timer */ - nackpacket->na_timer = timer_set_rel(rexmit_secs, - rexmit, - (void *) nackpacket); - return; - -} - -/* - * Send an acknowledgement to the sending client, by sending back the - * header from the original notice with the z_kind field changed to either - * SERVACK or SERVNAK, and the contents of the message either SENT or - * NOT_SENT, depending on the value of the sent argument. - */ - -void -clt_ack(notice, who, sent) - ZNotice_t *notice; - struct sockaddr_in *who; - ZSentType sent; -{ - ZNotice_t acknotice; - ZPacket_t ackpack; - int packlen; - int notme = 0; - char *sent_name; - Code_t retval; - - if (bdumping) { /* don't ack while dumping */ -#if 1 - zdbug((LOG_DEBUG,"bdumping, no ack")); -#endif - return; - } - - acknotice = *notice; - - acknotice.z_kind = SERVACK; - switch (sent) { - case SENT: - acknotice.z_message = ZSRVACK_SENT; - sent_name = "sent"; - break; - case NOT_FOUND: - acknotice.z_message = ZSRVACK_FAIL; - acknotice.z_kind = SERVNAK; - sent_name = "fail"; - break; - case AUTH_FAILED: - acknotice.z_kind = SERVNAK; - acknotice.z_message = ZSRVACK_NOTSENT; - sent_name = "nak/not_sent"; - break; - case NOT_SENT: - acknotice.z_message = ZSRVACK_NOTSENT; - sent_name = "not_sent"; - break; - default: - abort (); - } - -#if 0 - zdbug((LOG_DEBUG,"clt_ack type %s for %d to %s/%d", - sent_name, - ntohs(notice->z_port), - inet_ntoa(who->sin_addr), - ntohs(who->sin_port))); -#endif - - if (!server_which_server(who) && - (hostm_find_server(&who->sin_addr) != me_server)) { -#if 0 - zdbug((LOG_DEBUG,"not me")); -#endif - notme = 1; - } - - acknotice.z_multinotice = ""; - - /* leave room for the trailing null */ - acknotice.z_message_len = strlen(acknotice.z_message) + 1; - - packlen = sizeof(ackpack); - - if ((retval = ZFormatSmallRawNotice(&acknotice, - ackpack, - &packlen)) != ZERR_NONE) { - syslog(LOG_ERR, "clt_ack format: %s",error_message(retval)); - return; - } - if ((retval = ZSetDestAddr(who)) != ZERR_NONE) { - syslog(LOG_WARNING, "clt_ack set addr: %s", - error_message(retval)); - return; - } - if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) { - syslog(LOG_WARNING, "clt_ack xmit: %s", error_message(retval)); - return; - } - else - zdbug ((LOG_DEBUG, "packet sent")); - if (notme) - hostm_deathgram(who, me_server); - return; -} - -/* - * An ack has arrived. - * remove the packet matching this notice from the not-yet-acked queue - */ - -static void -nack_cancel(notice, who) - register ZNotice_t *notice; - struct sockaddr_in *who; -{ - register ZNotAcked_t *nacked; - - /* search the not-yet-acked list for this packet, and - flush it. */ -#if 0 - zdbug((LOG_DEBUG, "nack_cancel: %s:%08X,%08X", - inet_ntoa (notice->z_uid.zuid_addr), - notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); -#endif - for (nacked = nacklist->q_forw; - nacked != nacklist; - nacked = nacked->q_forw) - if ((nacked->na_addr.sin_addr.s_addr == who->sin_addr.s_addr) && - (nacked->na_addr.sin_port == who->sin_port)) - if (ZCompareUID(&nacked->na_uid, ¬ice->z_uid)) { - timer_reset(nacked->na_timer); - xfree(nacked->na_packet); - xremque(nacked); - xfree(nacked); - return; - } -#if 1 - zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X", - inet_ntoa (notice->z_uid.zuid_addr), - notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); -#endif - return; -} - -/* for compatibility when sending subscription information to old clients */ -#ifdef OLD_COMPAT -#define OLD_ZEPHYR_VERSION "ZEPH0.0" -#endif /* OLD_COMPAT */ - -/* - * Dispatch a ZEPHYR_CTL notice. - */ - -Code_t -control_dispatch(notice, auth, who, server) - ZNotice_t *notice; - int auth; - struct sockaddr_in *who; - ZServerDesc_t *server; -{ - register char *opcode = notice->z_opcode; - ZClient_t *client; - ZHostList_t *host; - Code_t retval; - int wantdefs; - - /* - * ZEPHYR_CTL Opcodes expected are: - * BOOT (inst HM): host has booted; flush data. - * CLIENT_SUBSCRIBE: process with the subscription mananger. - * CLIENT_UNSUBSCRIBE: "" - * CLIENT_CANCELSUB: "" - */ - - zdbug ((LOG_DEBUG, "ctl_disp: opc=%s", opcode)); - - if (!strcasecmp (notice->z_class_inst, ZEPHYR_CTL_HM)) - return(hostm_dispatch(notice, auth, who, server)); - else if (!strcmp (opcode, CLIENT_GIMMESUBS) || - !strcmp (opcode, CLIENT_GIMMEDEFS)) { - /* this special case is before the auth check so that - someone who has no subscriptions does NOT get a SERVNAK - but rather an empty list. Note we must therefore - check authentication inside subscr_sendlist */ -#ifdef OLD_COMPAT - /* only acknowledge if *not* old version; the old version - acknowledges the packet with the reply */ - if (strcmp (notice->z_version, OLD_ZEPHYR_VERSION)) - ack(notice, who); -#else /* !OLD_COMPAT */ - ack(notice, who); -#endif /* OLD_COMPAT */ - subscr_sendlist(notice, auth, who); - return(ZERR_NONE); - } else if (!auth) { -#if 0 - zdbug((LOG_DEBUG,"unauth ctrl_disp")); -#endif - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); - } - - /* the rest of the expected opcodes modify state; check for - unlocked host first */ - host = hostm_find_host(&who->sin_addr); - if (host && host->zh_locked) - return(ZSRV_REQUEUE); - - wantdefs = strcmp (opcode, CLIENT_SUBSCRIBE_NODEFS); - if (!wantdefs || !strcmp (opcode, CLIENT_SUBSCRIBE)) { - /* subscription notice */ - if (!(client = client_which_client(who, notice))) { - if ((retval = client_register(notice, - who, - &client, - server, - wantdefs)) != ZERR_NONE) - { - syslog(LOG_NOTICE, - "subscr. register %s/%s/%d failed: %s", - notice->z_sender, - inet_ntoa(who->sin_addr), - ntohs(notice->z_port), - error_message(retval)); - if (server == me_server) { - if (retval == ZSRV_BADSUBPORT) { - clt_ack(notice, who, AUTH_FAILED); - } else - hostm_deathgram(who, me_server); - } - return(ZERR_NONE); - } - if (!(client = client_which_client(who, notice))) { - syslog(LOG_CRIT, "subscr reg. failure"); - abort(); - } - } - if (strcmp (client->zct_principal->string, notice->z_sender)) { - /* you may only subscribe for your own clients */ - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); - } -#ifdef KERBEROS - /* in case it's changed */ - (void) memcpy((caddr_t) client->zct_cblock, (caddr_t) ZGetSession(), - sizeof(C_Block)); -#endif - if ((retval = subscr_subscribe(client,notice)) != ZERR_NONE) { - syslog(LOG_WARNING, "subscr failed: %s", - error_message(retval)); - if (server == me_server) - nack(notice, who); - return(ZERR_NONE); - } - } else if (!strcmp(opcode, CLIENT_UNSUBSCRIBE)) { - if ((client = client_which_client(who,notice)) != NULLZCNT) { - if (strcmp(client->zct_principal->string, notice->z_sender)) { - /* you may only cancel for your own clients */ - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); - } -#if 0 - if (zdebug) { - if (server == me_server) - syslog (LOG_DEBUG, - "subscription cancel for %s/%d\n", - inet_ntoa (who->sin_addr), - ntohs (who->sin_port)); - else - syslog (LOG_DEBUG, - "subscription cancel for %s/%d from %s\n", - inet_ntoa (who->sin_addr), - ntohs (who->sin_port), - server->addr); - } -#endif - (void) subscr_cancel(who, notice); - } else { - nack(notice, who); - return(ZERR_NONE); - } - } else if (!strcmp(opcode, CLIENT_CANCELSUB)) { - /* canceling subscriptions implies I can punt info about - this client */ - if ((client = client_which_client(who,notice)) != NULLZCNT) { - if (strcmp(client->zct_principal->string, notice->z_sender)) { - /* you may only cancel for your own clients */ - if (server == me_server) - clt_ack(notice, who, AUTH_FAILED); - return(ZERR_NONE); - } - if (host) { - /* don't flush locations here, let him - do it explicitly */ -#if 0 - zdbug((LOG_DEBUG, "cancelsub clt_dereg %s/%d", - inet_ntoa (who->sin_addr), - ntohs (who->sin_port))); -#endif - hostm_lose_ignore(client); - (void) client_deregister(client, host, 0); - } - - } - if (!client || !host) { -#if 0 - zdbug((LOG_DEBUG,"can_sub not found client")); -#endif - if (server == me_server) - nack(notice, who); - return(ZERR_NONE); - } - } else { - syslog(LOG_WARNING, "unknown ctl opcode %s", opcode); - if (server == me_server) - nack(notice, who); - return(ZERR_NONE); - } - - if (server == me_server) { - ack(notice, who); - server_forward(notice, auth, who); - } - return(ZERR_NONE); -} - - -- cgit v1.2.3