|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* kdc/dispatch.c - Dispatch an incoming packet */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright 1990, 2009 by the Massachusetts Institute of Technology.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Export of this software from the United States of America may
|
|
Packit |
fd8b60 |
* require a specific license from the United States Government.
|
|
Packit |
fd8b60 |
* It is the responsibility of any person or organization contemplating
|
|
Packit |
fd8b60 |
* export to obtain such a license before exporting.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
|
Packit |
fd8b60 |
* distribute this software and its documentation for any purpose and
|
|
Packit |
fd8b60 |
* without fee is hereby granted, provided that the above copyright
|
|
Packit |
fd8b60 |
* notice appear in all copies and that both that copyright notice and
|
|
Packit |
fd8b60 |
* this permission notice appear in supporting documentation, and that
|
|
Packit |
fd8b60 |
* the name of M.I.T. not be used in advertising or publicity pertaining
|
|
Packit |
fd8b60 |
* to distribution of the software without specific, written prior
|
|
Packit |
fd8b60 |
* permission. Furthermore if you modify this software you must label
|
|
Packit |
fd8b60 |
* your software as modified software and not distribute it in such a
|
|
Packit |
fd8b60 |
* fashion that it might be confused with the original M.I.T. software.
|
|
Packit |
fd8b60 |
* M.I.T. makes no representations about the suitability of
|
|
Packit |
fd8b60 |
* this software for any purpose. It is provided "as is" without express
|
|
Packit |
fd8b60 |
* or implied warranty.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include "k5-int.h"
|
|
Packit |
fd8b60 |
#include <syslog.h>
|
|
Packit |
fd8b60 |
#include "kdc_util.h"
|
|
Packit |
fd8b60 |
#include "extern.h"
|
|
Packit |
fd8b60 |
#include "adm_proto.h"
|
|
Packit |
fd8b60 |
#include "realm_data.h"
|
|
Packit |
fd8b60 |
#include <netinet/in.h>
|
|
Packit |
fd8b60 |
#include <arpa/inet.h>
|
|
Packit |
fd8b60 |
#include <string.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static krb5_int32 last_usec = 0, last_os_random = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static krb5_error_code make_too_big_error(kdc_realm_t *kdc_active_realm,
|
|
Packit |
fd8b60 |
krb5_data **out);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
struct dispatch_state {
|
|
Packit |
fd8b60 |
loop_respond_fn respond;
|
|
Packit |
fd8b60 |
void *arg;
|
|
Packit |
fd8b60 |
krb5_data *request;
|
|
Packit |
fd8b60 |
int is_tcp;
|
|
Packit |
fd8b60 |
kdc_realm_t *active_realm;
|
|
Packit |
fd8b60 |
krb5_context kdc_err_context;
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
finish_dispatch(struct dispatch_state *state, krb5_error_code code,
|
|
Packit |
fd8b60 |
krb5_data *response)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
loop_respond_fn oldrespond = state->respond;
|
|
Packit |
fd8b60 |
void *oldarg = state->arg;
|
|
Packit |
fd8b60 |
kdc_realm_t *kdc_active_realm = state->active_realm;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (state->is_tcp == 0 && response &&
|
|
Packit |
fd8b60 |
response->length > (unsigned int)max_dgram_reply_size) {
|
|
Packit |
fd8b60 |
krb5_free_data(kdc_context, response);
|
|
Packit |
fd8b60 |
response = NULL;
|
|
Packit |
fd8b60 |
code = make_too_big_error(kdc_active_realm, &response);
|
|
Packit |
fd8b60 |
if (code)
|
|
Packit |
fd8b60 |
krb5_klog_syslog(LOG_ERR, "error constructing "
|
|
Packit |
fd8b60 |
"KRB_ERR_RESPONSE_TOO_BIG error: %s",
|
|
Packit |
fd8b60 |
error_message(code));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
free(state);
|
|
Packit |
fd8b60 |
(*oldrespond)(oldarg, code, response);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
finish_dispatch_cache(void *arg, krb5_error_code code, krb5_data *response)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct dispatch_state *state = arg;
|
|
Packit |
fd8b60 |
krb5_context kdc_err_context = state->kdc_err_context;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifndef NOCACHE
|
|
Packit |
fd8b60 |
/* Remove the null cache entry unless we actually want to discard this
|
|
Packit |
fd8b60 |
* request. */
|
|
Packit |
fd8b60 |
if (code != KRB5KDC_ERR_DISCARD)
|
|
Packit |
fd8b60 |
kdc_remove_lookaside(kdc_err_context, state->request);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Put the response into the lookaside buffer (if we produced one). */
|
|
Packit |
fd8b60 |
if (code == 0 && response != NULL)
|
|
Packit |
fd8b60 |
kdc_insert_lookaside(kdc_err_context, state->request, response);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
finish_dispatch(state, code, response);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
reseed_random(krb5_context kdc_err_context)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krb5_timestamp now;
|
|
Packit |
fd8b60 |
krb5_int32 now_usec, usec_difference;
|
|
Packit |
fd8b60 |
krb5_data data;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_crypto_us_timeofday(&now, &now_usec);
|
|
Packit |
fd8b60 |
if (retval == 0) {
|
|
Packit |
fd8b60 |
usec_difference = now_usec - last_usec;
|
|
Packit |
fd8b60 |
if (last_os_random == 0)
|
|
Packit |
fd8b60 |
last_os_random = now;
|
|
Packit |
fd8b60 |
/* Grab random data from OS every hour*/
|
|
Packit |
fd8b60 |
if (ts_delta(now, last_os_random) >= 60 * 60) {
|
|
Packit |
fd8b60 |
krb5_c_random_os_entropy(kdc_err_context, 0, NULL);
|
|
Packit |
fd8b60 |
last_os_random = now;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
data.length = sizeof(krb5_int32);
|
|
Packit |
fd8b60 |
data.data = (void *)&usec_difference;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_c_random_add_entropy(kdc_err_context,
|
|
Packit |
fd8b60 |
KRB5_C_RANDSOURCE_TIMING, &data);
|
|
Packit |
fd8b60 |
last_usec = now_usec;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void
|
|
Packit |
fd8b60 |
dispatch(void *cb, const krb5_fulladdr *local_addr,
|
|
Packit |
fd8b60 |
const krb5_fulladdr *remote_addr, krb5_data *pkt, int is_tcp,
|
|
Packit |
fd8b60 |
verto_ctx *vctx, loop_respond_fn respond, void *arg)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krb5_kdc_req *req = NULL;
|
|
Packit |
fd8b60 |
krb5_data *response = NULL;
|
|
Packit |
fd8b60 |
struct dispatch_state *state;
|
|
Packit |
fd8b60 |
struct server_handle *handle = cb;
|
|
Packit |
fd8b60 |
krb5_context kdc_err_context = handle->kdc_err_context;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
state = k5alloc(sizeof(*state), &retval);
|
|
Packit |
fd8b60 |
if (state == NULL) {
|
|
Packit |
fd8b60 |
(*respond)(arg, retval, NULL);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
state->respond = respond;
|
|
Packit |
fd8b60 |
state->arg = arg;
|
|
Packit |
fd8b60 |
state->request = pkt;
|
|
Packit |
fd8b60 |
state->is_tcp = is_tcp;
|
|
Packit |
fd8b60 |
state->kdc_err_context = kdc_err_context;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* decode incoming packet, and dispatch */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifndef NOCACHE
|
|
Packit |
fd8b60 |
/* try the replay lookaside buffer */
|
|
Packit |
fd8b60 |
if (kdc_check_lookaside(kdc_err_context, pkt, &response)) {
|
|
Packit |
fd8b60 |
/* a hit! */
|
|
Packit |
fd8b60 |
const char *name = 0;
|
|
Packit |
fd8b60 |
char buf[46];
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
name = inet_ntop(ADDRTYPE2FAMILY(remote_addr->address->addrtype),
|
|
Packit |
fd8b60 |
remote_addr->address->contents, buf, sizeof(buf));
|
|
Packit |
fd8b60 |
if (name == 0)
|
|
Packit |
fd8b60 |
name = "[unknown address type]";
|
|
Packit |
fd8b60 |
if (response)
|
|
Packit |
fd8b60 |
krb5_klog_syslog(LOG_INFO,
|
|
Packit |
fd8b60 |
"DISPATCH: repeated (retransmitted?) request "
|
|
Packit |
fd8b60 |
"from %s, resending previous response", name);
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
krb5_klog_syslog(LOG_INFO,
|
|
Packit |
fd8b60 |
"DISPATCH: repeated (retransmitted?) request "
|
|
Packit |
fd8b60 |
"from %s during request processing, dropping "
|
|
Packit |
fd8b60 |
"repeated request", name);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
finish_dispatch(state, response ? 0 : KRB5KDC_ERR_DISCARD, response);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Insert a NULL entry into the lookaside to indicate that this request
|
|
Packit |
fd8b60 |
* is currently being processed. */
|
|
Packit |
fd8b60 |
kdc_insert_lookaside(kdc_err_context, pkt, NULL);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
reseed_random(kdc_err_context);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* try TGS_REQ first; they are more common! */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (krb5_is_tgs_req(pkt))
|
|
Packit |
fd8b60 |
retval = decode_krb5_tgs_req(pkt, &req;;
|
|
Packit |
fd8b60 |
else if (krb5_is_as_req(pkt))
|
|
Packit |
fd8b60 |
retval = decode_krb5_as_req(pkt, &req;;
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
retval = KRB5KRB_AP_ERR_MSG_TYPE;
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
goto done;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
state->active_realm = setup_server_realm(handle, req->server);
|
|
Packit |
fd8b60 |
if (state->active_realm == NULL) {
|
|
Packit |
fd8b60 |
retval = KRB5KDC_ERR_WRONG_REALM;
|
|
Packit |
fd8b60 |
goto done;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (krb5_is_tgs_req(pkt)) {
|
|
Packit |
fd8b60 |
/* process_tgs_req frees the request */
|
|
Packit |
fd8b60 |
retval = process_tgs_req(req, pkt, remote_addr, state->active_realm,
|
|
Packit |
fd8b60 |
&response);
|
|
Packit |
fd8b60 |
req = NULL;
|
|
Packit |
fd8b60 |
} else if (krb5_is_as_req(pkt)) {
|
|
Packit |
fd8b60 |
/* process_as_req frees the request and calls finish_dispatch_cache. */
|
|
Packit |
fd8b60 |
process_as_req(req, pkt, local_addr, remote_addr, state->active_realm,
|
|
Packit |
fd8b60 |
vctx, finish_dispatch_cache, state);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
done:
|
|
Packit |
fd8b60 |
krb5_free_kdc_req(kdc_err_context, req);
|
|
Packit |
fd8b60 |
finish_dispatch_cache(state, retval, response);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
make_too_big_error(kdc_realm_t *kdc_active_realm, krb5_data **out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error errpkt;
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krb5_data *scratch;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*out = NULL;
|
|
Packit |
fd8b60 |
memset(&errpkt, 0, sizeof(errpkt));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
errpkt.error = KRB_ERR_RESPONSE_TOO_BIG;
|
|
Packit |
fd8b60 |
errpkt.server = tgs_server;
|
|
Packit |
fd8b60 |
errpkt.client = NULL;
|
|
Packit |
fd8b60 |
errpkt.text.length = 0;
|
|
Packit |
fd8b60 |
errpkt.text.data = 0;
|
|
Packit |
fd8b60 |
errpkt.e_data.length = 0;
|
|
Packit |
fd8b60 |
errpkt.e_data.data = 0;
|
|
Packit |
fd8b60 |
scratch = malloc(sizeof(*scratch));
|
|
Packit |
fd8b60 |
if (scratch == NULL)
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
retval = krb5_mk_error(kdc_context, &errpkt, scratch);
|
|
Packit |
fd8b60 |
if (retval) {
|
|
Packit |
fd8b60 |
free(scratch);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*out = scratch;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_context get_context(void *handle)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct server_handle *sh = handle;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return sh->kdc_err_context;
|
|
Packit |
fd8b60 |
}
|