Implement a "max_dgram_size" parameter for realms, which will control when/if the server will respond with KRB_ERR_RESPONSE_TOO_BIG errors to requests from its clients. Because the reads settings by using libkadm5's krb5_read_realm_params function, its returned structure type needs to be expanded to hold this information, which breaks the ABI. When processing AS or TGS requests, the server needs to keep track of whether or not the client is issuing a request over a connected socket so that it won't issue RESPONSE_TOO_BIG errors to connected clients. The lookaside cache also needs to take note of the distinction so that it doesn't replay error messages to clients who've switched from using a connectionless socket to a connected socket and are sending the same request. --- krb5-1.4.3/doc/definitions.texinfo 2006-01-05 15:12:12.000000000 -0500 +++ krb5-1.4.3/doc/definitions.texinfo 2006-01-05 15:12:50.000000000 -0500 @@ -97,6 +97,8 @@ @set DefaultKDCRCache krb5kdc_rcache @comment KDCRCACHE @set DefaultRCTmpDirs /var/tmp, /usr/tmp, /var/usr/tmp, and /tmp +@comment MAX_DGRAM_SIZE +@set DefaultMaxDgramSize 4096 @ignore the following defaults should be consistent with the numbers set in --- krb5-1.4.3/doc/admin.texinfo 2006-01-05 15:13:04.000000000 -0500 +++ krb5-1.4.3/doc/admin.texinfo 2006-01-05 15:14:22.000000000 -0500 @@ -1264,6 +1264,14 @@ valid ticket may be renewed in this realm. The default value is @value{DefaultMaxRenewableLife}. +@itemx max_dgram_size +(Numeric value.) Specifies the maximum allowed size for responses to +client requests which are received over unconnected sockets (usually, +UDP, as opposed to TCP). If the response to a request would be larger +than the specified size, a KRB_ERR_RESPONSE_TOO_BIG error is sent in +its stead. The default value is +@value{DefaultMaxDgramSize}. + @itemx supported_enctypes List of key:salt strings. Specifies the default key/salt combinations of principals for this realm. Any principals created through @code{kadmin} --- krb5-1.4.3/src/lib/kadm5/srv/Makefile.in 2004-06-16 21:56:34.000000000 -0400 +++ krb5-1.4.3/src/lib/kadm5/srv/Makefile.in 2006-01-05 15:08:23.000000000 -0500 @@ -9,8 +9,8 @@ ##DOSLIBNAME = libkadm5srv.lib LIBBASE=kadm5srv -LIBMAJOR=5 -LIBMINOR=1 +LIBMAJOR=6 +LIBMINOR=0 STOBJLISTS=../OBJS.ST OBJS.ST SHLIB_EXPDEPS=\ --- krb5-1.4.3/src/lib/kadm5/clnt/Makefile.in 2004-06-16 16:18:10.000000000 -0400 +++ krb5-1.4.3/src/lib/kadm5/clnt/Makefile.in 2006-01-05 15:08:23.000000000 -0500 @@ -5,8 +5,8 @@ LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5 LIBBASE=kadm5clnt -LIBMAJOR=5 -LIBMINOR=1 +LIBMAJOR=6 +LIBMINOR=0 STOBJLISTS=../OBJS.ST OBJS.ST SHLIB_EXPDEPS=\ $(TOPLIBD)/libgssrpc$(SHLIBEXT) \ --- krb5-1.4.3/src/lib/kadm5/alt_prof.c 2004-06-24 16:08:30.000000000 -0400 +++ krb5-1.4.3/src/lib/kadm5/alt_prof.c 2006-01-05 15:08:23.000000000 -0500 @@ -936,6 +936,13 @@ krb5_xfree(svalue); } + /* Get the value for the maximum datagram response size */ + hierarchy[2] = "max_dgram_size"; + if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) { + rparams->realm_max_dgram_size = ivalue; + rparams->realm_max_dgram_size_valid = 1; + } + hierarchy[2] = "reject_bad_transit"; if (!krb5_aprof_get_boolean(aprofile, hierarchy, TRUE, &bvalue)) { rparams->realm_reject_bad_transit = bvalue; --- krb5-1.4.3/src/kdc/extern.h 2003-06-03 00:32:41.000000000 -0400 +++ krb5-1.4.3/src/kdc/extern.h 2006-01-05 15:08:23.000000000 -0500 @@ -64,6 +64,7 @@ krb5_deltat realm_maxlife; /* Maximum ticket life for realm */ krb5_deltat realm_maxrlife; /* Maximum renewable life for realm */ krb5_boolean realm_reject_bad_transit; /* Accept unverifiable transited_realm ? */ + int realm_max_dgram_size; /* Maximum datagram response size */ } kdc_realm_t; extern kdc_realm_t **kdc_realmlist; @@ -87,6 +88,7 @@ #define dbm_db_name kdc_active_realm->realm_dbname #define primary_port kdc_active_realm->realm_pport #define reject_bad_transit kdc_active_realm->realm_reject_bad_transit +#define max_dgram_size kdc_active_realm->realm_max_dgram_size /* various externs for KDC */ extern krb5_data empty_string; /* an empty string */ --- krb5-1.4.3/src/lib/kadm5/admin.h 2005-03-22 18:53:59.000000000 -0500 +++ krb5-1.4.3/src/lib/kadm5/admin.h 2006-01-05 15:08:23.000000000 -0500 @@ -263,6 +263,7 @@ krb5_deltat realm_max_rlife; krb5_timestamp realm_expiration; krb5_flags realm_flags; + int realm_max_dgram_size; krb5_key_salt_tuple *realm_keysalts; unsigned int realm_reject_bad_transit:1; unsigned int realm_kadmind_port_valid:1; @@ -272,6 +273,7 @@ unsigned int realm_expiration_valid:1; unsigned int realm_flags_valid:1; unsigned int realm_reject_bad_transit_valid:1; + unsigned int realm_max_dgram_size_valid:1; krb5_int32 realm_num_keysalts; } krb5_realm_params; --- krb5-1.4.3/src/kdc/do_as_req.c 2005-07-12 16:59:52.000000000 -0400 +++ krb5-1.4.3/src/kdc/do_as_req.c 2006-01-05 15:08:23.000000000 -0500 @@ -52,7 +52,7 @@ /*ARGSUSED*/ krb5_error_code process_as_req(krb5_kdc_req *request, const krb5_fulladdr *from, - krb5_data **response) + krb5_boolean connected, krb5_data **response) { krb5_db_entry client, server; krb5_kdc_rep reply; @@ -403,6 +403,13 @@ status = "ENCODE_KDC_REP"; goto errout; } + + if (!connected && ((*response)->length > max_dgram_size)) { + errcode = KRB5KRB_ERR_RESPONSE_TOO_BIG; + krb5_free_data(kdc_context, *response); + *response = NULL; + goto errout; + } /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we can use them in raw form if needed. But, we don't... */ --- krb5-1.4.3/src/kdc/dispatch.c 2002-09-10 23:59:27.000000000 -0400 +++ krb5-1.4.3/src/kdc/dispatch.c 2006-01-05 15:08:23.000000000 -0500 @@ -39,7 +39,8 @@ static krb5_int32 last_usec = 0, last_os_random = 0; krb5_error_code -dispatch(krb5_data *pkt, const krb5_fulladdr *from, krb5_data **response) +dispatch(krb5_data *pkt, const krb5_fulladdr *from, krb5_boolean connected, + krb5_data **response) { krb5_error_code retval; @@ -50,7 +51,7 @@ #ifndef NOCACHE /* try the replay lookaside buffer */ - if (kdc_check_lookaside(pkt, from, response)) { + if (kdc_check_lookaside(pkt, from, connected, response)) { /* a hit! */ const char *name = 0; char buf[46]; @@ -87,7 +88,7 @@ /* try TGS_REQ first; they are more common! */ if (krb5_is_tgs_req(pkt)) { - retval = process_tgs_req(pkt, from, response); + retval = process_tgs_req(pkt, from, connected, response); } else if (krb5_is_as_req(pkt)) { if (!(retval = decode_krb5_as_req(pkt, &as_req))) { /* @@ -95,7 +96,7 @@ * pointer. */ if (!(retval = setup_server_realm(as_req->server))) { - retval = process_as_req(as_req, from, response); + retval = process_as_req(as_req, from, connected, response); } krb5_free_kdc_req(kdc_context, as_req); } @@ -109,7 +110,7 @@ #ifndef NOCACHE /* put the response into the lookaside buffer */ if (!retval) - kdc_insert_lookaside(pkt, from, *response); + kdc_insert_lookaside(pkt, from, connected, *response); #endif return retval; --- krb5-1.4.3/src/kdc/network.c 2005-07-12 16:59:52.000000000 -0400 +++ krb5-1.4.3/src/kdc/network.c 2006-01-05 15:08:23.000000000 -0500 @@ -744,7 +744,7 @@ faddr.address = &addr; init_addr(&faddr, ss2sa(&saddr)); /* this address is in net order */ - if ((retval = dispatch(&request, &faddr, &response))) { + if ((retval = dispatch(&request, &faddr, FALSE, &response))) { com_err(prog, retval, "while dispatching (udp)"); return; } @@ -982,7 +982,7 @@ /* have a complete message, and exactly one message */ request.length = conn->u.tcp.msglen; request.data = conn->u.tcp.buffer + 4; - err = dispatch(&request, &conn->u.tcp.faddr, + err = dispatch(&request, &conn->u.tcp.faddr, TRUE, &conn->u.tcp.response); if (err) { com_err(prog, err, "while dispatching (tcp)"); --- krb5-1.4.3/src/kdc/kdc_util.h 2004-09-23 22:19:42.000000000 -0400 +++ krb5-1.4.3/src/kdc/kdc_util.h 2006-01-05 15:08:23.000000000 -0500 @@ -107,15 +107,18 @@ /* do_as_req.c */ krb5_error_code process_as_req (krb5_kdc_req *, const krb5_fulladdr *, + krb5_boolean, krb5_data ** ); /* do_tgs_req.c */ krb5_error_code process_tgs_req (krb5_data *, const krb5_fulladdr *, + krb5_boolean, krb5_data ** ); /* dispatch.c */ krb5_error_code dispatch (krb5_data *, const krb5_fulladdr *, + krb5_boolean, krb5_data **); /* main.c */ @@ -155,9 +158,9 @@ /* replay.c */ krb5_boolean kdc_check_lookaside (krb5_data *, const krb5_fulladdr *, - krb5_data **); -void kdc_insert_lookaside (krb5_data *, const krb5_fulladdr *, - krb5_data *); + krb5_boolean, krb5_data **); +void kdc_insert_lookaside (krb5_data *, const krb5_fulladdr *, krb5_boolean, + krb5_data *); void kdc_free_lookaside(krb5_context); /* which way to convert key? */ --- krb5-1.4.3/src/kdc/replay.c 2003-01-12 08:07:49.000000000 -0500 +++ krb5-1.4.3/src/kdc/replay.c 2006-01-05 15:08:23.000000000 -0500 @@ -42,6 +42,7 @@ krb5_data *req_packet; krb5_data *reply_packet; krb5_address *addr; /* XXX should these not be pointers? */ + krb5_boolean connected; } krb5_kdc_replay_ent; static krb5_kdc_replay_ent root_ptr = {0}; @@ -62,6 +63,7 @@ !memcmp((ptr)->addr->contents, \ from->address->contents, \ from->address->length)&& \ + (ptr->connected == connected) && \ ((ptr)->db_age == db_age)) /* XXX Todo: quench the size of the queue... @@ -72,7 +74,7 @@ krb5_boolean kdc_check_lookaside(krb5_data *inpkt, const krb5_fulladdr *from, - krb5_data **outpkt) + krb5_boolean connected, krb5_data **outpkt) { krb5_int32 timenow; register krb5_kdc_replay_ent *eptr, *last, *hold; @@ -126,7 +128,7 @@ void kdc_insert_lookaside(krb5_data *inpkt, const krb5_fulladdr *from, - krb5_data *outpkt) + krb5_boolean connected, krb5_data *outpkt) { register krb5_kdc_replay_ent *eptr; krb5_int32 timenow; @@ -142,6 +144,7 @@ return; eptr->timein = timenow; eptr->db_age = db_age; + eptr->connected = connected; /* * This is going to hurt a lot malloc()-wise due to the need to * allocate memory for the krb5_data and krb5_address elements. --- krb5-1.4.3/src/kdc/main.c 2004-02-24 16:07:22.000000000 -0500 +++ krb5-1.4.3/src/kdc/main.c 2006-01-05 15:08:23.000000000 -0500 @@ -231,6 +231,10 @@ rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ? rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE; + /* Handle maximum datagram response size */ + rdp->realm_max_dgram_size = (rparams && rparams->realm_max_dgram_size_valid) ? + rparams->realm_max_dgram_size : MAX_DGRAM_SIZE; + if (rparams) krb5_free_realm_params(rdp->realm_context, rparams); --- krb5-1.4.3/src/kdc/do_tgs_req.c 2005-07-12 16:59:52.000000000 -0400 +++ krb5-1.4.3/src/kdc/do_tgs_req.c 2006-01-05 15:08:23.000000000 -0500 @@ -56,7 +56,7 @@ /*ARGSUSED*/ krb5_error_code process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from, - krb5_data **response) + krb5_boolean connected, krb5_data **response) { krb5_keyblock * subkey; krb5_kdc_req *request = 0; @@ -630,7 +630,13 @@ if (errcode) { status = "ENCODE_KDC_REP"; } else { - status = "ISSUE"; + if (!connected && ((*response)->length > max_dgram_size)) { + errcode = KRB5KRB_ERR_RESPONSE_TOO_BIG; + krb5_free_data(kdc_context, *response); + *response = NULL; + } else { + status = "ISSUE"; + } } memset(ticket_reply.enc_part.ciphertext.data, 0, --- krb5-1.4.3/src/config-files/kdc.conf.M 2006-01-05 15:06:30.000000000 -0500 +++ krb5-1.4.3/src/config-files/kdc.conf.M 2006-01-05 15:08:23.000000000 -0500 @@ -208,6 +208,14 @@ .B key type string represents the master key's key type. +.IP max_dgram_size +This +.B size +specifes the maximum size for a response which the KDC will provide +to clients which use datagrams to communicate with it. Clients whose +requests require larger responses will instead receive RESPONSE_TOO_BIG +errors. + .IP max_life This .B delta time string --- krb5-1.4.3/src/include/krb5/adm.h 2002-09-18 16:45:36.000000000 -0400 +++ krb5-1.4.3/src/include/krb5/adm.h 2006-01-05 15:08:23.000000000 -0500 @@ -208,6 +208,7 @@ krb5_deltat realm_max_rlife; krb5_timestamp realm_expiration; krb5_flags realm_flags; + krb5_int32 realm_max_dgram_size; krb5_key_salt_tuple *realm_keysalts; unsigned int realm_reject_bad_transit:1; unsigned int realm_kadmind_port_valid:1; @@ -217,6 +218,7 @@ unsigned int realm_expiration_valid:1; unsigned int realm_flags_valid:1; unsigned int realm_reject_bad_transit_valid:1; + unsigned int realm_max_dgram_size_valid:1; krb5_int32 realm_num_keysalts; } krb5_realm_params; #endif /* KRB5_ADM_H__ */