diff options
author | Karl Ramm <kcr@1ts.org> | 2010-07-28 00:50:42 +0000 |
---|---|---|
committer | Karl Ramm <kcr@1ts.org> | 2010-07-28 00:50:42 +0000 |
commit | e4806cee25df4d4ac2fc725c48936511527f0a88 (patch) | |
tree | 04b66367546946986d8fd97a0c01280037caddb8 /server | |
parent | aaab96c5d7b7fa90701dbcade286cad8a1518889 (diff) |
fix subscriptions-too-wide-breaks-braindump problem
only send one sub per packet in braindump
refactor bdump_send_list_tcp and send_normal_tcp
brain dump can now cleanly receive overlarge encrypted packets
refactor subscr_send_subs and subscr_send_realm_subs
nuke trailing whitespace
Diffstat (limited to 'server')
-rw-r--r-- | server/bdump.c | 403 | ||||
-rw-r--r-- | server/subscr.c | 206 |
2 files changed, 288 insertions, 321 deletions
diff --git a/server/bdump.c b/server/bdump.c index c815809..f9dbe99 100644 --- a/server/bdump.c +++ b/server/bdump.c @@ -9,7 +9,7 @@ * * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. * For copying and distribution information, see the file - * "mit-copyright.h". + * "mit-copyright.h". */ #include <zephyr/mit-copyright.h> @@ -52,7 +52,7 @@ static Code_t bdump_send_loop(Server *server); static Code_t bdump_recv_loop(Server *server); static void bdump_get_v12(ZNotice_t *, int, struct sockaddr_in *, Server *); -static Code_t get_packet(void *packet, int len, int *retlen); +static Code_t get_packet(char **packet, int *len, int *retlen); static Code_t extract_sin(ZNotice_t *notice, struct sockaddr_in *target); static Code_t send_done(void); static Code_t send_list(ZNotice_Kind_t kind, int port, char *class_name, @@ -67,6 +67,7 @@ static int net_write(FILE *f, char *buf, int len); static int setup_file_pointers(void); static void shutdown_file_pointers(void); static void cleanup(Server *server); +static Code_t transmit_tcp(char *pack, int packlen); #ifdef HAVE_KRB5 static int des_service_decrypt(unsigned char *in, unsigned char *out); @@ -126,9 +127,9 @@ bdump_offer(struct sockaddr_in *who) zdbug((LOG_DEBUG, "bdump_offer")); #if defined(HAVE_KRB4) || defined(HAVE_KRB5) - /* + /* * when using kerberos server-server authentication, we can - * use any random local address + * use any random local address */ bdump_socket = socket(AF_INET, SOCK_STREAM, 0); if (bdump_socket < 0) { @@ -139,7 +140,7 @@ bdump_offer(struct sockaddr_in *who) memset(&bdump_sin, 0, sizeof(bdump_sin)); /* a port field of 0 makes the UNIX * kernel choose an appropriate port/address pair */ - + bdump_sin.sin_port = 0; bdump_sin.sin_addr = my_addr; bdump_sin.sin_family = AF_INET; @@ -180,7 +181,7 @@ bdump_offer(struct sockaddr_in *who) #endif /* HAVE_KRB4 */ listen(bdump_socket, 1); - + bdump_timer = timer_set_rel(20L, close_bdump, NULL); FD_SET(bdump_socket, &interesting); nfds = max(bdump_socket, srv_socket) + 1; @@ -189,20 +190,20 @@ bdump_offer(struct sockaddr_in *who) sprintf(buf, "%d", ntohs(bdump_sin.sin_port)); lyst[0] = addr; lyst[1] = buf; - + retval = ZSetDestAddr(who); if (retval != ZERR_NONE) { syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s", error_message(retval)); return; } - + /* myname is the hostname */ /* the class instance is the version number, here it is */ /* bdump_version, which is set in main */ send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version, ADMIN_BDUMP, myname, "", lyst, 2); - + zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n", inet_ntoa(bdump_sin.sin_addr), ntohs(bdump_sin.sin_port))); @@ -244,7 +245,7 @@ bdump_send(void) #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5) unsigned short fromport; #endif /* HAVE_KRB4 */ - + zdbug((LOG_DEBUG, "bdump_send")); /* accept the connection, and send the brain dump */ @@ -256,11 +257,11 @@ bdump_send(void) if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m"); - + #if !defined(HAVE_KRB4) && !defined(HAVE_KRB5) fromport = ntohs(from.sin_port); #endif - + #ifdef _POSIX_VERSION sigemptyset(&action.sa_mask); action.sa_flags = 0; @@ -270,7 +271,7 @@ bdump_send(void) #else signal(SIGPIPE, SIG_IGN); /* so we can detect failures */ #endif - + from.sin_port = srv_addr.sin_port; /* we don't care what port * it came from, and we need to * fake out server_which_server() */ @@ -280,7 +281,7 @@ bdump_send(void) server = limbo_server; } - zdbug((LOG_DEBUG, "bdump_send: connection from %s/%d", + zdbug((LOG_INFO, "bdump_send: connection from %s/%d", inet_ntoa(from.sin_addr), ntohs(from.sin_port))); bdumping = 1; @@ -306,30 +307,30 @@ bdump_send(void) return; } - syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto); + syslog(LOG_DEBUG, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto); if (get_tgt()) { syslog(LOG_ERR, "bdump_send: get_tgt failed"); cleanup(server); return; } - + switch(proto) { #ifdef HAVE_KRB5 case 5: /* "server" side */ - retval = krb5_build_principal(Z_krb5_ctx, &principal, + retval = krb5_build_principal(Z_krb5_ctx, &principal, strlen(ZGetRealm()), ZGetRealm(), SERVER_KRB5_SERVICE, SERVER_INSTANCE, - NULL); + NULL); if (retval) { syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval)); cleanup(server); return; } - + retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac); if (retval) { @@ -365,7 +366,7 @@ bdump_send(void) /* resolve keytab */ retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt); if (retval) { - syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s", + syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s", error_message(retval)); krb5_kt_close(Z_krb5_ctx, kt); cleanup(server); @@ -399,10 +400,10 @@ bdump_send(void) krb5_free_data_contents(Z_krb5_ctx, &k5data); cleanup(server); return; - } + } krb5_free_data_contents(Z_krb5_ctx, &k5data); break; -#endif /* HAVE_KRB5 */ +#endif /* HAVE_KRB5 */ #ifdef HAVE_KRB4 case 4: /* here to krb_rd_req from GetKerberosData candidate for refactoring @@ -524,10 +525,10 @@ bdump_get_v12 (ZNotice_t *notice, #else /* !HAVE_KRB4 && !HAVE_KRB5 */ int reserved_port = IPPORT_RESERVED - 1; #endif /* !HAVE_KRB4 && !HAVE_KRB5 */ - + bdumping = 1; server->dumping = 1; - + #ifdef _POSIX_VERSION action.sa_flags = 0; sigemptyset(&action.sa_mask); @@ -536,7 +537,7 @@ bdump_get_v12 (ZNotice_t *notice, #else signal(SIGPIPE, SIG_IGN); /* so we can detect problems */ #endif /* _POSIX_VRESION */ - + if (bdump_socket >= 0) { /* We cannot go get a brain dump when someone may potentially be connecting to us (if that other @@ -590,11 +591,11 @@ bdump_get_v12 (ZNotice_t *notice, syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m"); zdbug((LOG_DEBUG, "bdump_get: connected")); - + /* Now begin the brain dump. */ #if defined(HAVE_KRB4) || defined(HAVE_KRB5) if (get_tgt()) { - syslog(LOG_ERR, "bdump_get: get_tgt failed"); + syslog(LOG_ERR, "bdump_get: get_tgt failed"); cleanup(server); return; } @@ -603,11 +604,11 @@ bdump_get_v12 (ZNotice_t *notice, case 5: /* "client" side */ memset((char *)&creds, 0, sizeof(creds)); - retval = krb5_build_principal(Z_krb5_ctx, &principal, + retval = krb5_build_principal(Z_krb5_ctx, &principal, strlen(ZGetRealm()), ZGetRealm(), SERVER_KRB5_SERVICE, SERVER_INSTANCE, - NULL); + NULL); if (retval) { syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval)); @@ -623,7 +624,7 @@ bdump_get_v12 (ZNotice_t *notice, cleanup(server); return; } - + retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client); krb5_free_principal(Z_krb5_ctx, principal); if (retval) { @@ -685,7 +686,7 @@ bdump_get_v12 (ZNotice_t *notice, krb5_free_data_contents(Z_krb5_ctx, &data); cleanup(server); return; - } + } krb5_free_data_contents(Z_krb5_ctx, &data); memset((char *)&data, 0, sizeof(krb5_data)); retval = GetKrb5Data(live_socket, &data); @@ -694,7 +695,7 @@ bdump_get_v12 (ZNotice_t *notice, error_message(retval)); cleanup(server); return; - } + } retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep); free(data.data); memset((char *)&data, 0, sizeof(krb5_data)); @@ -703,7 +704,7 @@ bdump_get_v12 (ZNotice_t *notice, error_message(retval)); cleanup(server); return; - } + } break; #endif #ifdef HAVE_KRB4 @@ -717,7 +718,7 @@ bdump_get_v12 (ZNotice_t *notice, return; } zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok")); - + /* get his authenticator */ retval = GetKerberosData(live_socket, from.sin_addr, &kdata, SERVER_SERVICE, srvtab_file); @@ -738,7 +739,7 @@ bdump_get_v12 (ZNotice_t *notice, break; #endif /* HAVE_KRB4 */ } -#endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */ +#endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */ retval = setup_file_pointers(); if (retval != 0) { syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s", @@ -816,6 +817,77 @@ bdump_get(ZNotice_t *notice, } /* + * Send off a packet via tcp + */ +static Code_t +transmit_tcp(char *pack, int packlen) +{ + Code_t retval = ZERR_NONE; + u_short length; + int count; +#ifdef HAVE_KRB5 + krb5_data indata, outmsg; +#endif + /* output and bdump_ac are globals */ + + if (packlen > Z_MAXPKTLEN) { + syslog(LOG_ERR, "transmit_tcp: packet is too large (%d bytes)", packlen); + return ZERR_PKTLEN; + } + +#ifdef HAVE_KRB5 + if (bdump_ac) { + indata.length = packlen; + indata.data = pack; + memset(&outmsg, 0, sizeof(krb5_data)); + + retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL); + + if (retval != ZERR_NONE) + goto cleanup; + + packlen = outmsg.length; + pack = outmsg.data; + } +#endif + + syslog(LOG_DEBUG, "transmit_tcp: packet is %d bytes", packlen); + + length = htons((unsigned short) packlen); + + count = net_write(output, (char *) &length, sizeof(length)); + if (count != sizeof(length)) { + if (count < 0) { + syslog(LOG_WARNING, "transmit_tcp: writing length: %m"); + retval = errno; + } else { + syslog(LOG_WARNING, "transmit_tcp: writing length: %d vs %d", sizeof(length), count); + retval = ZSRV_LEN; + } + goto cleanup; + } + count = net_write(output, pack, packlen); + if (count != packlen) { + if (count < 0) { + syslog(LOG_WARNING, "transmit_tcp: writing data: %m"); + retval = errno; + } else { + syslog(LOG_WARNING, "transmit_tcp: writing data: %d vs %d", packlen, count); + retval = ZSRV_LEN; + } + goto cleanup; + } + + cleanup: +#ifdef HAVE_KRB5 + if (bdump_ac) + krb5_free_data_contents(Z_krb5_ctx, &outmsg); +#endif + + return retval; +} + +/* * Send a list off as the specified notice */ @@ -832,14 +904,13 @@ bdump_send_list_tcp(ZNotice_Kind_t kind, { ZNotice_t notice; char *pack; - int packlen, count; + int packlen; Code_t retval; - u_short length; memset (¬ice, 0, sizeof(notice)); - + notice.z_kind = kind; - + notice.z_port = addr->sin_port; notice.z_class = class_name; notice.z_class_inst = inst; @@ -850,63 +921,19 @@ bdump_send_list_tcp(ZNotice_Kind_t kind, notice.z_num_other_fields = 0; if (addr) notice.z_sender_sockaddr.ip4 = *addr; /*XXX*/ - + retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH); - if (retval != ZERR_NONE) + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "bdump_send_list_tcp: ZFormatNotice: %s", error_message(retval)); return retval; - -#ifdef HAVE_KRB5 - if (bdump_ac) { - krb5_data indata, outmsg; - indata.length=packlen; - indata.data=pack; - memset(&outmsg, 0, sizeof(krb5_data)); - retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL); - if (retval != ZERR_NONE) - return retval; - if (outmsg.length > Z_MAXPKTLEN) { - syslog(LOG_ERR, "bsl: encrypted packet is too large"); - return ZERR_PKTLEN; - } - packlen = outmsg.length; - free(pack); - pack=malloc(packlen); - if (!pack) - return ENOMEM; - memcpy(pack, outmsg.data, packlen); - krb5_free_data_contents(Z_krb5_ctx, &outmsg); } -#endif - length = htons((u_short) packlen); - - count = net_write(output, (char *) &length, sizeof(length)); - if (count != sizeof(length)) { - if (count < 0) { - free(pack); - return(errno); - } else { - syslog(LOG_WARNING, "slt (length) xmit: %d vs %d", - sizeof(length), count); - free(pack); - return(ZSRV_PKSHORT); - } - } - - count = net_write(output, pack, packlen); - if (count != packlen) { - if (count < 0) { - free(pack); - return(errno); - } else { - syslog(LOG_WARNING, "slt (packet) xmit: %d vs %d", - packlen, count); - free(pack); - return(ZSRV_PKSHORT); - } - } + retval = transmit_tcp(pack, packlen); free(pack); - return(ZERR_NONE); + if (retval != ZERR_NONE) + syslog(LOG_ERR, "bdump_send_list_tcp: transmit_tcp: %s", error_message(retval)); + + return retval; } static void @@ -1019,7 +1046,7 @@ get_tgt(void) got_des = 1; } #endif -#ifdef HAVE_KRB5 +#ifdef HAVE_KRB5 /* XXX */ if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) { krb5_keytab kt; @@ -1029,11 +1056,11 @@ get_tgt(void) memset(&cred, 0, sizeof(cred)); - retval = krb5_build_principal(Z_krb5_ctx, &principal, + retval = krb5_build_principal(Z_krb5_ctx, &principal, strlen(ZGetRealm()), ZGetRealm(), SERVER_KRB5_SERVICE, SERVER_INSTANCE, - NULL); + NULL); if (retval) { syslog(LOG_ERR, "get_tgt: krb5_build_principal: %s", error_message(retval)); @@ -1050,7 +1077,7 @@ get_tgt(void) krb5_free_principal(Z_krb5_ctx, principal); return 1; } - + retval = krb5_get_init_creds_keytab (Z_krb5_ctx, &cred, principal, @@ -1087,7 +1114,7 @@ get_tgt(void) krb5_kt_close(Z_krb5_ctx, kt); return 1; } - + got_des = 1; } #endif /* HAVE_KRB4 */ @@ -1100,7 +1127,7 @@ get_tgt(void) error_message(retval)); return 1; } - + retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred); if (retval) { syslog(LOG_ERR, "get_tgt: krb5_cc_store_cred: %s", @@ -1120,7 +1147,7 @@ get_tgt(void) /* * The braindump offer wasn't taken, so we retract it. */ - + /*ARGSUSED*/ static void close_bdump(void *arg) @@ -1137,17 +1164,18 @@ close_bdump(void *arg) } return; } - + /* * Start receiving instruction notices from the brain dump socket */ - + static Code_t bdump_recv_loop(Server *server) { ZNotice_t notice; - ZPacket_t packet; + char *packet = NULL; int len; + int pblen = Z_MAXPKTLEN; Code_t retval; Client *client = NULL; struct sockaddr_in who; @@ -1155,7 +1183,7 @@ bdump_recv_loop(Server *server) unsigned char buf[512]; int blen; #endif -#if defined(HAVE_KRB4) || defined(HAVE_KRB5) +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) char *cp; #ifndef HAVE_KRB4 unsigned char cblock[8]; @@ -1164,9 +1192,14 @@ bdump_recv_loop(Server *server) #endif #endif ZRealm *realm = NULL; - - zdbug((LOG_DEBUG, "bdump recv loop")); - + + zdbug((LOG_DEBUG, "bdump_recv_loop")); + + packet = malloc(Z_MAXPKTLEN); + + if (packet == NULL) + return ENOMEM; + /* do the inverse of bdump_send_loop, registering stuff on the fly */ while (1) { if (packets_waiting()) { @@ -1178,9 +1211,10 @@ bdump_recv_loop(Server *server) bdumping = 1; } len = sizeof(packet); - retval = get_packet(packet, len, &len); + retval = get_packet(&packet, &pblen, &len); if (retval != ZERR_NONE) { - syslog(LOG_ERR, "brl get pkt: %s", error_message(retval)); + syslog(LOG_ERR, "bdump_recv_loop: get_packet failed: %s", error_message(retval)); + free(packet); return retval; } @@ -1192,7 +1226,8 @@ bdump_recv_loop(Server *server) memset(&out, 0, sizeof(krb5_data)); retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL); if (retval != ZERR_NONE) { - syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval)); + syslog(LOG_ERR, "bdump_recv_loop: krb5_rd_priv failed: %s", error_message(retval)); + free(packet); return retval; } memcpy(packet, out.data, out.length); @@ -1203,15 +1238,16 @@ bdump_recv_loop(Server *server) retval = ZParseNotice(packet, len, ¬ice); if (retval != ZERR_NONE) { - syslog(LOG_ERR, "brl notice parse: %s", error_message(retval)); + syslog(LOG_ERR, "bdump_recv_loop: ZParseNotice failed: %s", error_message(retval)); + free(packet); return retval; } #if defined (DEBUG) if (zdebug) { - syslog(LOG_DEBUG, "bdump:%s '%s' '%s' '%s' '%s' '%s'", - ZNoticeKinds[(int) notice.z_kind], notice.z_class, - notice.z_class_inst, notice.z_opcode, notice.z_sender, - notice.z_recipient); + syslog(LOG_DEBUG, "bdump_recv_loop: %s '%s' '%s' '%s' '%s' '%s'", + ZNoticeKinds[(int) notice.z_kind], notice.z_class, + notice.z_class_inst, notice.z_opcode, notice.z_sender, + notice.z_recipient); } #endif /* DEBUG */ who.sin_family = AF_INET; /*XXX*/ @@ -1220,20 +1256,22 @@ bdump_recv_loop(Server *server) if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) { /* end of brain dump */ + free(packet); return ZERR_NONE; } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) { /* get a realm from the message */ realm = realm_get_realm_by_name(notice.z_message); if (!realm) { - syslog(LOG_ERR, "brl newrlm failed: no realm %s", + syslog(LOG_ERR, "bdump_recv_loop: realm_get_realm_by_name failed: no realm %s", notice.z_message); } } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) { /* 1 = tell it we are authentic */ retval = ulogin_dispatch(¬ice, 1, &who, server); if (retval != ZERR_NONE) { - syslog(LOG_ERR, "brl ul_disp failed: %s", + syslog(LOG_ERR, "bdump_recv_loop: ulogin_dispatch failed: %s", error_message(retval)); + free(packet); return retval; } } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) { @@ -1241,7 +1279,8 @@ bdump_recv_loop(Server *server) notice.z_port = htons((u_short) atoi(notice.z_message)); retval = client_register(¬ice, &who.sin_addr, &client, 0); if (retval != ZERR_NONE) { - syslog(LOG_ERR,"brl failed: %s", error_message(retval)); + syslog(LOG_ERR,"bdump_recv_loop: client_register failed: %s", error_message(retval)); + free(packet); return retval; } #ifdef HAVE_KRB5 @@ -1257,19 +1296,21 @@ bdump_recv_loop(Server *server) sizeof(cblock), &client->session_keyblock); if (retval) { - syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s", + syslog(LOG_ERR, "bdump_recv_loop: failed to allocate DES keyblock: %s", error_message(retval)); + free(packet); return retval; } retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(cblock)); if (retval != ZERR_NONE) { - syslog(LOG_ERR,"brl bad cblk read: %s (%s)", + syslog(LOG_ERR,"bdump_recv_loop: bad cblock read: %s (%s)", error_message(retval), cp); } else { retval = des_service_decrypt(cblock, Z_keydata(client->session_keyblock)); if (retval) { - syslog(LOG_ERR, "brl failed to decyrpt DES session key: %s", + syslog(LOG_ERR, "bdump_recv_loop: failed to decyrpt DES session key: %s", error_message(retval)); + free(packet); return retval; } } @@ -1277,7 +1318,7 @@ bdump_recv_loop(Server *server) /* Zcode! Long live the new flesh! */ retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen); if (retval != ZERR_NONE) { - syslog(LOG_ERR,"brl bad cblk read: %s (%s)", + syslog(LOG_ERR,"bdump_recv_loop: bad keyblock read: %s (%s)", error_message(retval), cp); } else { retval = Z_krb5_init_keyblock(Z_krb5_ctx, @@ -1285,8 +1326,9 @@ bdump_recv_loop(Server *server) ntohl(*(uint32_t *)&buf[4]), &client->session_keyblock); if (retval) { - syslog(LOG_ERR, "brl failed to allocate keyblock: %s", + syslog(LOG_ERR, "bdump_recv_loop: failed to allocate keyblock: %s", error_message(retval)); + free(packet); return retval; } memcpy(Z_keydata(client->session_keyblock), &buf[8], @@ -1302,7 +1344,7 @@ bdump_recv_loop(Server *server) cp = notice.z_message + strlen(notice.z_message) + 1; retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block)); if (retval != ZERR_NONE) { - syslog(LOG_ERR,"brl bad cblk read: %s (%s)", + syslog(LOG_ERR,"bdump_recv_loop: bad cblock read: %s (%s)", error_message(retval), cp); } else { des_ecb_encrypt((des_cblock *)cblock, @@ -1312,16 +1354,18 @@ bdump_recv_loop(Server *server) } #endif /* HAVE_KRB4 */ #endif - } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) { + } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) { /* a subscription packet */ if (!client) { - syslog(LOG_ERR, "brl no client"); + syslog(LOG_ERR, "bdump_recv_loop: no client"); + free(packet); return ZSRV_NOCLT; } retval = subscr_subscribe(client, ¬ice, server); if (retval != ZERR_NONE) { - syslog(LOG_WARNING, "brl subscr failed: %s", + syslog(LOG_WARNING, "bdump_recv_loop: subscr_subscribe failed: %s", error_message(retval)); + free(packet); return retval; } } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) { @@ -1329,16 +1373,18 @@ bdump_recv_loop(Server *server) if (realm) { retval = subscr_realm(realm, ¬ice); if (retval != ZERR_NONE) { - syslog(LOG_WARNING, "brl subscr failed: %s", + syslog(LOG_WARNING, "bdump_recv_loop: subscr_eralm failed: %s", error_message(retval)); + free(packet); return retval; } } /* else */ /* Other side tried to send us subs for a realm we didn't know about, and so we drop them silently */ - + } else { - syslog(LOG_ERR, "brl bad opcode %s",notice.z_opcode); + syslog(LOG_ERR, "bdump_recv_loop: bad opcode %s",notice.z_opcode); + free(packet); return ZSRV_UNKNOWNOPCODE; } } @@ -1375,7 +1421,7 @@ static Code_t send_done(void) { Code_t retval; - + zdbug((LOG_DEBUG, "send_done")); retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS, @@ -1403,7 +1449,7 @@ send_list(ZNotice_Kind_t kind, char *pack; int packlen; Code_t retval; - + memset (¬ice, 0, sizeof(notice)); notice.z_kind = kind; @@ -1415,13 +1461,13 @@ send_list(ZNotice_Kind_t kind, notice.z_recipient = recip; notice.z_default_format = ""; notice.z_num_other_fields = 0; - + retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH); if (retval != ZERR_NONE) { syslog(LOG_WARNING, "sl format: %s", error_message(retval)); return retval; } - + retval = ZSendPacket(pack, packlen, 0); if (retval != ZERR_NONE) syslog(LOG_WARNING, "sl xmit: %s", error_message(retval)); @@ -1446,10 +1492,9 @@ send_normal_tcp(ZNotice_Kind_t kind, { ZNotice_t notice; char *pack; - int packlen, count; + int packlen; Code_t retval; - unsigned short length; - + memset (¬ice, 0, sizeof(notice)); notice.z_kind = kind; @@ -1463,64 +1508,19 @@ send_normal_tcp(ZNotice_Kind_t kind, notice.z_message = message; notice.z_message_len = len; notice.z_num_other_fields = 0; - + retval = ZFormatNotice(¬ice, &pack, &packlen, ZNOAUTH); if (retval != ZERR_NONE) { - syslog(LOG_WARNING, "sn format: %s", error_message(retval)); + syslog(LOG_WARNING, "send_normal_tcp: ZFormatNotice: %s", error_message(retval)); return retval; } - -#ifdef HAVE_KRB5 - if (bdump_ac) { - krb5_data indata, outmsg; - indata.length=packlen; - indata.data=pack; - memset(&outmsg, 0, sizeof(krb5_data)); - retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL); - if (retval != ZERR_NONE) - return retval; - if (outmsg.length > Z_MAXPKTLEN) { - syslog(LOG_ERR, "sn: encrypted packet is too large"); - return ZERR_PKTLEN; - } - packlen = outmsg.length; - free(pack); - pack=malloc(packlen); - if (!pack) - return ENOMEM; - memcpy(pack, outmsg.data, packlen); - krb5_free_data_contents(Z_krb5_ctx, &outmsg); - } -#endif - length = htons((unsigned short) packlen); - - count = net_write(output, (char *) &length, sizeof(length)); - if (count != sizeof(length)) { - if (count < 0) { - syslog(LOG_WARNING, "snt xmit/len: %m"); - free(pack); - return errno; - } else { - syslog(LOG_WARNING, "snt xmit: %d vs %d",sizeof(length),count); - free(pack); - return ZSRV_LEN; - } - } - count = net_write(output, pack, packlen); - if (count != packlen) { - if (count < 0) { - syslog(LOG_WARNING, "snt xmit: %m"); - free(pack); - return errno; - } else { - syslog(LOG_WARNING, "snt xmit: %d vs %d",packlen, count); - free(pack); - return ZSRV_LEN; - } - } + retval = transmit_tcp(pack, packlen); free(pack); - return ZERR_NONE; + if (retval != ZERR_NONE) + syslog(LOG_ERR, "send_normal_tcp: transmit_tcp: %s", error_message(retval)); + + return retval; } /* @@ -1529,26 +1529,37 @@ send_normal_tcp(ZNotice_Kind_t kind, */ static Code_t -get_packet(void *packet, int len, int *retlen) +get_packet(char **packet, int *buflen, int *retlen) { unsigned short length; int result; - + char *p; + result = net_read(input, (char *) &length, sizeof(unsigned short)); if (result < sizeof(short)) { if (result < 0) { return errno; } else { - syslog(LOG_ERR, "get_pkt len: %d vs %d (%m)", result, + syslog(LOG_ERR, "get_packet: received length: %d vs %d (%m)", result, sizeof(short)); return ZSRV_LEN; } } - + length = ntohs(length); - if (len < length) - return ZSRV_BUFSHORT; - result = net_read(input, packet, (int) length); + if (*buflen < length) { + p = realloc(*packet, length); + if (p == NULL) { + syslog(LOG_ERR, "get_packet: failed to expand buffer to %d bytes from %d", + *buflen, length); + return ZSRV_BUFSHORT; + } + syslog(LOG_DEBUG, "get_packet: expanded buffer from %d bytes to %d", + *buflen, length); + *buflen = length; + *packet = p; + } + result = net_read(input, *packet, (int) length); if (result < length) { if (result < 0) { return errno; @@ -1572,7 +1583,7 @@ extract_sin(ZNotice_t *notice, struct sockaddr_in *target) return ZSRV_PKSHORT; } target->sin_addr.s_addr = inet_addr(cp); - + cp += (strlen(cp) + 1); /* past the null */ if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) { return(ZSRV_PKSHORT); @@ -1586,7 +1597,7 @@ static int net_read(FILE *f, char *buf, int len) { int cc, len2 = 0; - + fflush (output); do { errno = 0; diff --git a/server/subscr.c b/server/subscr.c index 0516647..a646f72 100644 --- a/server/subscr.c +++ b/server/subscr.c @@ -8,7 +8,7 @@ * * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. * For copying and distribution information, see the file - * "mit-copyright.h". + * "mit-copyright.h". */ #include <zephyr/mit-copyright.h> @@ -78,7 +78,7 @@ extern int old_compat_count_subscr; /* counter of old use */ #ifdef NEW_COMPAT #define NEW_OLD_ZEPHYR_VERSION "ZEPH0.1" static void new_old_compat_subscr_sendlist(ZNotice_t *notice, int auth, - struct sockaddr_in *who); + struct sockaddr_in *who); extern int new_compat_count_subscr; /* counter of old use */ #endif /* NEW_COMPAT */ @@ -93,7 +93,7 @@ static char **subscr_marshal_subs(ZNotice_t *notice, int auth, static Destlist *subscr_copy_def_subs(char *person); static Code_t subscr_realm_sendit(Client *who, Destlist *subs, ZNotice_t *notice, ZRealm *realm); -static void subscr_unsub_sendit(Client *who, Destlist *subs, +static void subscr_unsub_sendit(Client *who, Destlist *subs, ZRealm *realm); static int defaults_read = 0; /* set to 1 if the default subs @@ -105,7 +105,7 @@ String *empty; /* WARNING: make sure this is the same as the number of strings you */ /* plan to hand back to the user in response to a subscription check, */ -/* else you will lose. See subscr_sendlist() */ +/* else you will lose. See subscr_sendlist() */ #define NUM_FIELDS 3 /* @@ -502,9 +502,9 @@ subscr_marshal_subs(ZNotice_t *notice, int defsubs = 0; *found = 0; - + /* Note that the following code is an incredible crock! */ - + /* We cannot send multiple packets as acknowledgements to the client, since the hostmanager will ignore the later packets. So we need to send directly to the client. */ @@ -761,6 +761,33 @@ old_compat_subscr_sendlist(notice, auth, who) } #endif /* OLD_COMPAT */ +static Code_t +subscr_send_some_subs(char *opcode, struct sockaddr_in *addr, Destlist *subs, char *subject) +{ + char *list[NUM_FIELDS]; + Code_t retval; + + for (; subs; subs = subs->next) { + /* for each subscription */ + list[0] = subs->dest.classname->string; + list[1] = subs->dest.inst->string; + list[2] = subs->dest.recip->string; + retval = bdump_send_list_tcp(ACKED, addr, + ZEPHYR_CTL_CLASS, "", + opcode, "", "", list, + NUM_FIELDS); + if (retval == ZERR_PKTLEN) { + syslog(LOG_ERR, "subscr_send_some_subs: dropping overlarge packet (%s)", subject); + } else if (retval != ZERR_NONE) { + syslog(LOG_ERR, "subscr_send_some_subs: bdump_send_list_tcp: %s", + error_message(retval)); + return retval; + } + } + + return ZERR_NONE; +} + /* * Send the client's subscriptions to another server */ @@ -772,8 +799,6 @@ old_compat_subscr_sendlist(notice, auth, who) Code_t subscr_send_subs(Client *client) { - int i = 0; - Destlist *subs; #ifdef HAVE_KRB5 char buf[512]; unsigned char *bufp; @@ -825,13 +850,13 @@ subscr_send_subs(Client *client) retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block)); #endif /* HAVE_KRB4 */ -#endif /* HAVE_KRB5 */ +#endif /* HAVE_KRB5 */ #if defined(HAVE_KRB4) || defined(HAVE_KRB5) if (retval != ZERR_NONE) { } else { list[num++] = buf; - } + } #endif /* HAVE_KRB4 || HAVE_KRB5*/ retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS, num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT, @@ -841,41 +866,10 @@ subscr_send_subs(Client *client) return retval; } - if (!client->subs) - return ZERR_NONE; - - for (subs = client->subs; subs; subs = subs->next) { - /* for each subscription */ - list[i * NUM_FIELDS] = subs->dest.classname->string; - list[i * NUM_FIELDS + 1] = subs->dest.inst->string; - list[i * NUM_FIELDS + 2] = subs->dest.recip->string; - i++; - if (i >= 7) { - /* we only put 7 in each packet, so we don't run out of room */ - retval = bdump_send_list_tcp(ACKED, &client->addr, - ZEPHYR_CTL_CLASS, "", - CLIENT_SUBSCRIBE, "", "", list, - i * NUM_FIELDS); - if (retval != ZERR_NONE) { - syslog(LOG_ERR, "subscr_send_subs subs: %s", - error_message(retval)); - return retval; - } - i = 0; - } - } - if (i) { - retval = bdump_send_list_tcp(ACKED, &client->addr, ZEPHYR_CTL_CLASS, - "", CLIENT_SUBSCRIBE, "", "", list, - i * NUM_FIELDS); - if (retval != ZERR_NONE) { - syslog(LOG_ERR, "subscr_send_subs subs: %s", - error_message(retval)); - return retval; - } - } - - return ZERR_NONE; + retval = subscr_send_some_subs(CLIENT_SUBSCRIBE, &client->addr, client->subs, client->principal->string); + if (retval != ZERR_NONE) + syslog(LOG_ERR, "subscr_send_subs: subscr_send_some_subs: %s", error_message(retval)); + return retval; } /* @@ -987,7 +981,7 @@ subscr_dump_subs(FILE *fp, return (ZERR_NONE); \ }} -/* As it exists, this function expects to take only the first sub from the +/* As it exists, this function expects to take only the first sub from the * Destlist. At some point, it and the calling code should be replaced */ static Code_t subscr_realm_sendit(Client *who, @@ -1002,15 +996,15 @@ subscr_realm_sendit(Client *who, Code_t retval; char addr[16]; /* xxx.xxx.xxx.xxx max */ char port[16]; - + if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) { syslog(LOG_ERR, "subscr_rlm_sendit malloc"); return(ENOMEM); } /* convert the address to a string of the form x.x.x.x/port */ strcpy(addr, inet_ntoa(who->addr.sin_addr)); - if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) - &who->addr.sin_port, sizeof(unsigned short))) != ZERR_NONE) + if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) + &who->addr.sin_port, sizeof(unsigned short))) != ZERR_NONE) { syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s", error_message(retval)); @@ -1022,10 +1016,10 @@ subscr_realm_sendit(Client *who, text[2] = subs->dest.classname->string; text[3] = subs->dest.inst->string; text[4] = subs->dest.recip->string; - + zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n", text[0], text[1], who->principal->string, text[2], text[3], text[4])); - + /* format snotice */ memset (&snotice, 0, sizeof(snotice)); snotice.z_class_inst = ZEPHYR_CTL_REALM; @@ -1040,9 +1034,9 @@ subscr_realm_sendit(Client *who, snotice.z_sender = who->principal->string; snotice.z_recipient = notice->z_recipient; snotice.z_default_format = notice->z_default_format; - + if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2, - &pack, &packlen, ZNOAUTH)) != ZERR_NONE) + &pack, &packlen, ZNOAUTH)) != ZERR_NONE) { syslog(LOG_WARNING, "subscr_rlm_sendit format: %s", error_message(retval)); @@ -1050,17 +1044,17 @@ subscr_realm_sendit(Client *who, return(ZERR_NONE); } free(text); - + if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) { syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s", error_message(retval)); free(pack); return(ZERR_NONE); } - + realm_handoff(&snotice, 1, &(who->addr), realm, 0); free(pack); - + return(ZERR_NONE); } @@ -1094,7 +1088,7 @@ subscr_add_raw(Client *client, } } else { if (!realm) { - ZRealm *remrealm = + ZRealm *remrealm = realm_get_realm_by_name(subs->dest.recip->string + 1); if (remrealm) { Destlist *sub = (Destlist *) malloc(sizeof(Destlist)); @@ -1105,7 +1099,7 @@ subscr_add_raw(Client *client, sub->dest.inst = make_string(subs->dest.inst->string, 0); sub->dest.recip = make_string(subs->dest.recip->string, 0); zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s", - sub->dest.classname->string, sub->dest.inst->string, + sub->dest.classname->string, sub->dest.inst->string, sub->dest.recip->string, remrealm->name)); Destlist_insert(&remrealm->remsubs, sub); } @@ -1151,7 +1145,7 @@ subscr_unsub_sendit(Client *who, subsn = subsp->next; if (ZDest_eq(&subs->dest, &subsp->dest)) { zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s", - subsp->dest.classname->string, subsp->dest.inst->string, + subsp->dest.classname->string, subsp->dest.inst->string, subsp->dest.recip->string, realm->name)); Destlist_delete(subsp); free_subscription(subsp); @@ -1201,8 +1195,6 @@ subscr_unsub_sendit(Client *who, Code_t subscr_send_realm_subs(ZRealm *realm) { - int i = 0; - Destlist *subs, *next; char buf[512]; char *list[7 * NUM_FIELDS]; int num = 0; @@ -1217,47 +1209,11 @@ subscr_send_realm_subs(ZRealm *realm) syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval)); return retval; } - - if (!realm->subs) - return ZERR_NONE; - for (subs=realm->subs; subs; subs = next) { - next = subs->next; -#ifdef DEBUG - zdbug ((LOG_DEBUG, "send_realm_subs: %s/%s/%s", subs->dest.classname->string, - subs->dest.inst->string, subs->dest.recip->string)); -#endif - /* for each subscription */ - list[i * NUM_FIELDS] = subs->dest.classname->string; - list[i * NUM_FIELDS + 1] = subs->dest.inst->string; - list[i * NUM_FIELDS + 2] = subs->dest.recip->string; - i++; - if (i >= 7) { - /* we only put 7 in each packet, so we don't run out of room */ - retval = bdump_send_list_tcp(ACKED, &srv_addr, - ZEPHYR_CTL_CLASS, "", - REALM_SUBSCRIBE, "", "", list, - i * NUM_FIELDS); - if (retval != ZERR_NONE) { - syslog(LOG_ERR, "subscr_send_realm_subs subs: %s", - error_message(retval)); - return retval; - } - i = 0; - } - } - if (i) { - retval = bdump_send_list_tcp(ACKED, &srv_addr, ZEPHYR_CTL_CLASS, - "", REALM_SUBSCRIBE, "", "", list, - i * NUM_FIELDS); - if (retval != ZERR_NONE) { - syslog(LOG_ERR, "subscr_send_realm_subs subs: %s", - error_message(retval)); - return retval; - } - } - - return ZERR_NONE; + retval = subscr_send_some_subs(REALM_SUBSCRIBE, &srv_addr, realm->subs, realm->name); + if (retval != ZERR_NONE) + syslog(LOG_ERR, "subscr_send_realm_subs: subscr_send_some_subs: %s", error_message(retval)); + return retval; } Code_t @@ -1284,8 +1240,8 @@ subscr_realm_subs(ZRealm *realm) #endif num = 0; - if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) - &num, sizeof(unsigned short))) != ZERR_NONE) + if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) + &num, sizeof(unsigned short))) != ZERR_NONE) { syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s", error_message(retval)); @@ -1317,13 +1273,13 @@ subscr_realm_subs(ZRealm *realm) snotice.z_sender = (*clientp)->principal->string; if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2, - &pack, &packlen, ZNOAUTH)) != ZERR_NONE) + &pack, &packlen, ZNOAUTH)) != ZERR_NONE) { syslog(LOG_WARNING, "subscr_rlm_subs format: %s", error_message(retval)); return(ZERR_NONE); } - + if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) { syslog(LOG_WARNING, "subscr_rlm_subs parse: %s", error_message(retval)); @@ -1360,10 +1316,10 @@ subscr_check_foreign_subs(ZNotice_t *notice, if (found == 0) return(ZERR_NONE); - + sender = make_string(notice->z_sender, 0); - - if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *))) + + if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *))) == (char **) 0) { syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)"); free_string(sender); @@ -1392,18 +1348,18 @@ subscr_check_foreign_subs(ZNotice_t *notice, } acl = class_get_acl(subs->dest.classname); if (acl) { - rlm = realm_which_realm(who); - if (rlm && server == me_server) { - if (!realm_sender_in_realm(rlm->name, sender->string)) { + rlm = realm_which_realm(who); + if (rlm && server == me_server) { + if (!realm_sender_in_realm(rlm->name, sender->string)) { syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s", - sender->string, rlm->name, + sender->string, rlm->name, subs->dest.classname->string); free_subscriptions(newsubs); free_string(sender); free(text); return ZSRV_CLASSRESTRICTED; - } - } + } + } if (!access_check(sender->string, acl, SUBSCRIBE)) { syslog(LOG_WARNING, "subscr unauth %s class %s", sender->string, subs->dest.classname->string); @@ -1424,7 +1380,7 @@ subscr_check_foreign_subs(ZNotice_t *notice, text[found*NUM_FIELDS + 3] = subs->dest.inst->string; text[found*NUM_FIELDS + 4] = ""; found++; - + retval = triplet_register(realm->client, &subs->dest, realm); #ifdef DEBUG zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string, @@ -1454,7 +1410,7 @@ subscr_check_foreign_subs(ZNotice_t *notice, error_message(retval)); free_string(sender); free(text); - return(ZERR_NONE); + return(ZERR_NONE); } if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) { syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s", @@ -1485,9 +1441,9 @@ Code_t subscr_foreign_user(ZNotice_t *notice, struct sockaddr_in newwho; char *cp, *tp0, *tp1; char rlm_recipient[REALM_SZ + 1]; - + tp0 = cp = notice->z_message; - + newwho.sin_addr.s_addr = inet_addr(cp); if (newwho.sin_addr.s_addr == -1) { syslog(LOG_ERR, "malformed addr from %s", notice->z_sender); @@ -1496,12 +1452,12 @@ Code_t subscr_foreign_user(ZNotice_t *notice, I_ADVANCE(0); tp1 = cp; - + snotice = *notice; - + if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, sizeof(unsigned short))) - != ZERR_NONE) + != ZERR_NONE) { syslog(LOG_ERR, "subscr_foreign_user read ascii: %s", error_message(status)); @@ -1509,7 +1465,7 @@ Code_t subscr_foreign_user(ZNotice_t *notice, } I_ADVANCE(1); - + snotice.z_message = cp; snotice.z_message_len = notice->z_message_len - (cp - notice->z_message); @@ -1521,7 +1477,7 @@ Code_t subscr_foreign_user(ZNotice_t *notice, if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) { /* this was approved by the other realm, add subscriptions */ - + if (!strcmp(tp0, "0.0.0.0")) { /* skip bogus ADD reply from subscr_realm_subs */ zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped")); @@ -1536,13 +1492,13 @@ Code_t subscr_foreign_user(ZNotice_t *notice, free_subscriptions(newsubs); return(ZERR_NONE); } - + /* translate the recipient to represent the foreign realm */ sprintf(rlm_recipient, "@%s", realm->name); for (temp = newsubs; temp; temp = temp->next) { temp->dest.recip = make_string(rlm_recipient, 0); } - + status = subscr_add_raw(client, (ZRealm *)0, newsubs); } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) { zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1)); |