/* Verify that the canonicalize bit is set in an AS-REQ and remove it. */ static krb5_error_code test_send_as_req(krb5_context context, void *data, const krb5_data *realm, const krb5_data *message, krb5_data **new_message_out, krb5_data **reply_out) { krb5_kdc_req *as_req; int cmp; assert(krb5_is_as_req(message)); check(decode_krb5_as_req(message, &as_req)); assert(as_req->msg_type == KRB5_AS_REQ); assert(as_req->kdc_options & KDC_OPT_CANONICALIZE); assert(as_req->client->realm.length == realm->length); cmp = memcmp(as_req->client->realm.data, realm->data, realm->length); assert(cmp == 0); /* Remove the canonicalize flag and create a new message. */ as_req->kdc_options &= ~KDC_OPT_CANONICALIZE; check(encode_krb5_as_req(as_req, new_message_out)); krb5_free_kdc_req(context, as_req); return 0; }
krb5_error_code dispatch(krb5_data *pkt, const krb5_fulladdr *from, krb5_data **response) { krb5_error_code retval; krb5_kdc_req *as_req; krb5_int32 now, now_usec; /* decode incoming packet, and dispatch */ #ifndef NOCACHE /* try the replay lookaside buffer */ if (kdc_check_lookaside(pkt, response)) { /* a hit! */ const char *name = 0; char buf[46]; name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype), from->address->contents, buf, sizeof (buf)); if (name == 0) name = "[unknown address type]"; krb5_klog_syslog(LOG_INFO, "DISPATCH: repeated (retransmitted?) request from %s, resending previous response", name); return 0; } #endif retval = krb5_crypto_us_timeofday(&now, &now_usec); if (retval == 0) { krb5_int32 usec_difference = now_usec-last_usec; krb5_data data; if(last_os_random == 0) last_os_random = now; /* Grab random data from OS every hour*/ if(now-last_os_random >= 60*60) { krb5_c_random_os_entropy(kdc_context, 0, NULL); last_os_random = now; } data.length = sizeof(krb5_int32); data.data = (void *) &usec_difference; krb5_c_random_add_entropy(kdc_context, KRB5_C_RANDSOURCE_TIMING, &data); last_usec = now_usec; } /* try TGS_REQ first; they are more common! */ if (krb5_is_tgs_req(pkt)) { retval = process_tgs_req(pkt, from, response); } else if (krb5_is_as_req(pkt)) { if (!(retval = decode_krb5_as_req(pkt, &as_req))) { /* * setup_server_realm() sets up the global realm-specific data * pointer. * process_as_req frees the request if it is called */ if (!(retval = setup_server_realm(as_req->server))) { retval = process_as_req(as_req, pkt, from, response); } else krb5_free_kdc_req(kdc_context, as_req); } } else retval = KRB5KRB_AP_ERR_MSG_TYPE; #ifndef NOCACHE /* put the response into the lookaside buffer */ if (!retval && *response != NULL) kdc_insert_lookaside(pkt, *response); #endif return retval; }
void dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from, krb5_data *pkt, int is_tcp, verto_ctx *vctx, loop_respond_fn respond, void *arg) { krb5_error_code retval; krb5_kdc_req *as_req; krb5_int32 now, now_usec; krb5_data *response = NULL; struct dispatch_state *state; state = malloc(sizeof(*state)); if (!state) { (*respond)(arg, ENOMEM, NULL); return; } state->respond = respond; state->arg = arg; state->request = pkt; state->is_tcp = is_tcp; /* decode incoming packet, and dispatch */ #ifndef NOCACHE /* try the replay lookaside buffer */ if (kdc_check_lookaside(pkt, &response)) { /* a hit! */ const char *name = 0; char buf[46]; if (!response || is_tcp != 0 || response->length <= max_dgram_reply_size) { name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype), from->address->contents, buf, sizeof (buf)); if (name == 0) name = "[unknown address type]"; if (response) krb5_klog_syslog(LOG_INFO, "DISPATCH: repeated (retransmitted?) request " "from %s, resending previous response", name); else krb5_klog_syslog(LOG_INFO, "DISPATCH: repeated (retransmitted?) request " "from %s during request processing, dropping " "repeated request", name); } finish_dispatch(state, response ? 0 : KRB5KDC_ERR_DISCARD, response); return; } /* Insert a NULL entry into the lookaside to indicate that this request * is currently being processed. */ kdc_insert_lookaside(pkt, NULL); #endif retval = krb5_crypto_us_timeofday(&now, &now_usec); if (retval == 0) { krb5_int32 usec_difference = now_usec-last_usec; krb5_data data; if(last_os_random == 0) last_os_random = now; /* Grab random data from OS every hour*/ if(now-last_os_random >= 60*60) { krb5_c_random_os_entropy(kdc_context, 0, NULL); last_os_random = now; } data.length = sizeof(krb5_int32); data.data = (void *) &usec_difference; krb5_c_random_add_entropy(kdc_context, KRB5_C_RANDSOURCE_TIMING, &data); last_usec = now_usec; } /* try TGS_REQ first; they are more common! */ if (krb5_is_tgs_req(pkt)) { retval = process_tgs_req(pkt, from, &response); } else if (krb5_is_as_req(pkt)) { if (!(retval = decode_krb5_as_req(pkt, &as_req))) { /* * setup_server_realm() sets up the global realm-specific data * pointer. * process_as_req frees the request if it is called */ if (!(retval = setup_server_realm(as_req->server))) { process_as_req(as_req, pkt, from, vctx, finish_dispatch, state); return; } else krb5_free_kdc_req(kdc_context, as_req); } } else retval = KRB5KRB_AP_ERR_MSG_TYPE; finish_dispatch(state, retval, response); }