Example #1
0
int
main(int argc, char **argv)
{
    gss_ctx_id_t acceptor;
    int dummy;

    /* Make the PRNG work since we're not using krb5_init_context. */
    krb5_c_random_os_entropy(NULL, 0, &dummy);

    read_lucid_context(&acceptor);
    send_ack(STDOUT_FILENO);
    read_wrap_token(acceptor);
    send_ack(STDOUT_FILENO);
    read_mic_token(acceptor);
    send_ack(STDOUT_FILENO);
    read_iov_token(acceptor);
    send_ack(STDOUT_FILENO);

    send_wrap_token(acceptor);
    read_ack(STDIN_FILENO);
    send_mic_token(acceptor);
    read_ack(STDIN_FILENO);
    send_iov_token(acceptor);
    read_ack(STDIN_FILENO);

    cleanup_context(acceptor);
    return 0;
}
Example #2
0
File: init_ctx.c Project: PADL/krb5
krb5_error_code KRB5_CALLCONV
krb5_init_context_profile(profile_t profile, krb5_flags flags,
                          krb5_context *context_out)
{
    krb5_context ctx = 0;
    krb5_error_code retval;
    struct {
        krb5_timestamp now;
        krb5_int32 now_usec;
        long pid;
    } seed_data;
    krb5_data seed;
    int tmp;
    char *plugin_dir = NULL;

    /* Verify some assumptions.  If the assumptions hold and the
       compiler is optimizing, this should result in no code being
       executed.  If we're guessing "unsigned long long" instead
       of using uint64_t, the possibility does exist that we're
       wrong.  */
    {
        uint64_t i64;
        assert(sizeof(i64) == 8);
        i64 = 0, i64--, i64 >>= 62;
        assert(i64 == 3);
        i64 = 1, i64 <<= 31, i64 <<= 31, i64 <<= 1;
        assert(i64 != 0);
        i64 <<= 1;
        assert(i64 == 0);
    }

    retval = krb5int_initialize_library();
    if (retval)
        return retval;

#if (defined(_WIN32))
    /*
     * Load the krbcc32.dll if necessary.  We do this here so that
     * we know to use API: later on during initialization.
     * The context being NULL is ok.
     */
    krb5_win_ccdll_load(ctx);

    /*
     * krb5_vercheck() is defined in win_glue.c, and this is
     * where we handle the timebomb and version server checks.
     */
    retval = krb5_vercheck();
    if (retval)
        return retval;
#endif

    *context_out = NULL;

    ctx = calloc(1, sizeof(struct _krb5_context));
    if (!ctx)
        return ENOMEM;
    ctx->magic = KV5M_CONTEXT;

    ctx->profile_secure = (flags & KRB5_INIT_CONTEXT_SECURE) != 0;

    retval = k5_os_init_context(ctx, profile, flags);
    if (retval)
        goto cleanup;

    ctx->trace_callback = NULL;
#ifndef DISABLE_TRACING
    if (!ctx->profile_secure)
        k5_init_trace(ctx);
#endif

    retval = get_boolean(ctx, KRB5_CONF_ALLOW_WEAK_CRYPTO, 0, &tmp);
    if (retval)
        goto cleanup;
    ctx->allow_weak_crypto = tmp;

    retval = get_boolean(ctx, KRB5_CONF_IGNORE_ACCEPTOR_HOSTNAME, 0, &tmp);
    if (retval)
        goto cleanup;
    ctx->ignore_acceptor_hostname = tmp;

    retval = get_tristate(ctx, KRB5_CONF_DNS_CANONICALIZE_HOSTNAME, "fallback",
                          CANONHOST_FALLBACK, 1, &tmp);
    if (retval)
        goto cleanup;
    ctx->dns_canonicalize_hostname = tmp;

    /* initialize the prng (not well, but passable) */
    if ((retval = krb5_c_random_os_entropy( ctx, 0, NULL)) !=0)
        goto cleanup;
    if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec)))
        goto cleanup;
    seed_data.pid = getpid ();
    seed.length = sizeof(seed_data);
    seed.data = (char *) &seed_data;
    if ((retval = krb5_c_random_add_entropy(ctx, KRB5_C_RANDSOURCE_TIMING, &seed)))
        goto cleanup;

    ctx->default_realm = 0;
    get_integer(ctx, KRB5_CONF_CLOCKSKEW, DEFAULT_CLOCKSKEW, &tmp);
    ctx->clockskew = tmp;

    /* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2)  */
    /* DCE add kdc_req_checksum_type = 2 to krb5.conf */
    get_integer(ctx, KRB5_CONF_KDC_REQ_CHECKSUM_TYPE, CKSUMTYPE_RSA_MD5,
                &tmp);
    ctx->kdc_req_sumtype = tmp;

    get_integer(ctx, KRB5_CONF_AP_REQ_CHECKSUM_TYPE, 0, &tmp);
    ctx->default_ap_req_sumtype = tmp;

    get_integer(ctx, KRB5_CONF_SAFE_CHECKSUM_TYPE, CKSUMTYPE_RSA_MD5_DES,
                &tmp);
    ctx->default_safe_sumtype = tmp;

    get_integer(ctx, KRB5_CONF_KDC_DEFAULT_OPTIONS, KDC_OPT_RENEWABLE_OK,
                &tmp);
    ctx->kdc_default_options = tmp;
#define DEFAULT_KDC_TIMESYNC 1
    get_integer(ctx, KRB5_CONF_KDC_TIMESYNC, DEFAULT_KDC_TIMESYNC, &tmp);
    ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;

    retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
                                KRB5_CONF_PLUGIN_BASE_DIR, 0,
                                DEFAULT_PLUGIN_BASE_DIR, &plugin_dir);
    if (!retval)
        retval = k5_expand_path_tokens(ctx, plugin_dir, &ctx->plugin_base_dir);
    if (retval) {
        TRACE_PROFILE_ERR(ctx, KRB5_CONF_PLUGIN_BASE_DIR,
                          KRB5_CONF_LIBDEFAULTS, retval);
        goto cleanup;
    }

    /*
     * We use a default file credentials cache of 3.  See
     * lib/krb5/krb/ccache/file/fcc.h for a description of the
     * credentials cache types.
     *
     * Note: DCE 1.0.3a only supports a cache type of 1
     *      DCE 1.1 supports a cache type of 2.
     */
#define DEFAULT_CCACHE_TYPE 4
    get_integer(ctx, KRB5_CONF_CCACHE_TYPE, DEFAULT_CCACHE_TYPE, &tmp);
    ctx->fcc_default_format = tmp + 0x0500;
    ctx->prompt_types = 0;
    ctx->use_conf_ktypes = 0;
    ctx->udp_pref_limit = -1;

    /* It's OK if this fails */
    (void)profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
                             KRB5_CONF_ERR_FMT, NULL, NULL, &ctx->err_fmt);
    *context_out = ctx;
    ctx = NULL;

cleanup:
    profile_release_string(plugin_dir);
    krb5_free_context(ctx);
    return retval;
}
Example #3
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;
}
Example #4
0
static krb5_error_code
init_common (krb5_context *context, krb5_boolean secure, krb5_boolean kdc)
{
	krb5_context ctx = 0;
	krb5_error_code retval;
	struct {
	    krb5_int32 now, now_usec;
	    long pid;
	} seed_data;
	krb5_data seed;
	int tmp;

	/* Verify some assumptions.  If the assumptions hold and the
	   compiler is optimizing, this should result in no code being
	   executed.  If we're guessing "unsigned long long" instead
	   of using uint64_t, the possibility does exist that we're
	   wrong.  */
	{
	    krb5_ui_8 i64;
	    assert(sizeof(i64) == 8);
	    i64 = 0, i64--, i64 >>= 62;
	    assert(i64 == 3);
	    i64 = 1, i64 <<= 31, i64 <<= 31, i64 <<= 1;
	    assert(i64 != 0);
	    i64 <<= 1;
	    assert(i64 == 0);
	}

	retval = krb5int_initialize_library();
	if (retval)
	    return retval;

#if (defined(_WIN32))
	/* 
	 * Load the krbcc32.dll if necessary.  We do this here so that
	 * we know to use API: later on during initialization.
	 * The context being NULL is ok.
	 */
	krb5_win_ccdll_load(ctx);

	/*
	 * krb5_vercheck() is defined in win_glue.c, and this is
	 * where we handle the timebomb and version server checks.
	 */
	retval = krb5_vercheck();
	if (retval)
		return retval;
#endif

	*context = 0;

	ctx = calloc(1, sizeof(struct _krb5_context));
	if (!ctx)
		return ENOMEM;
	ctx->magic = KV5M_CONTEXT;

	ctx->profile_secure = secure;

	/* Set the default encryption types, possible defined in krb5/conf */
	if ((retval = krb5_set_default_in_tkt_ktypes(ctx, NULL)))
		goto cleanup;

	if ((retval = krb5_set_default_tgs_ktypes(ctx, NULL)))
		goto cleanup;

	if ((retval = krb5_os_init_context(ctx, kdc)))
		goto cleanup;

	/* initialize the prng (not well, but passable) */
	{
	    static pid_t done_seeding = 0;
	    static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
	    int success = 0;
	    
	    pthread_mutex_lock(&m);
	    if (done_seeding != getpid()) {
		retval = krb5_c_random_os_entropy( ctx, 0, &success);
		if (retval == 0 && success)
		    done_seeding = getpid();
	    }
	    pthread_mutex_unlock(&m);
	    if (retval)
		goto cleanup;
	}
	if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec)))
		goto cleanup;
	seed_data.pid = getpid ();
	seed.length = sizeof(seed_data);
	seed.data = (char *) &seed_data;
	if ((retval = krb5_c_random_add_entropy(ctx, KRB5_C_RANDSOURCE_TIMING, &seed)))
		goto cleanup;

	ctx->default_realm = 0;
	profile_get_integer(ctx->profile, "libdefaults", "clockskew",
			    0, 5 * 60, &tmp);
	ctx->clockskew = tmp;

#if 0
	/* Default ticket lifetime is currently not supported */
	profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime",
			    0, 10 * 60 * 60, &tmp);
	ctx->tkt_lifetime = tmp;
#endif

	/* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2)  */
	/* DCE add kdc_req_checksum_type = 2 to krb5.conf */
	profile_get_integer(ctx->profile, "libdefaults",
			    "kdc_req_checksum_type", 0, CKSUMTYPE_RSA_MD5, 
			    &tmp);
	ctx->kdc_req_sumtype = tmp;

	profile_get_integer(ctx->profile, "libdefaults",
			    "ap_req_checksum_type", 0, CKSUMTYPE_RSA_MD5,
			    &tmp);
	ctx->default_ap_req_sumtype = tmp;

	profile_get_integer(ctx->profile, "libdefaults",
			    "safe_checksum_type", 0,
			    CKSUMTYPE_RSA_MD5_DES, &tmp);
	ctx->default_safe_sumtype = tmp;

	profile_get_integer(ctx->profile, "libdefaults",
			    "kdc_default_options", 0,
			    KDC_OPT_RENEWABLE_OK, &tmp);
	ctx->kdc_default_options = tmp;
#define DEFAULT_KDC_TIMESYNC 1
	profile_get_integer(ctx->profile, "libdefaults",
			    "kdc_timesync", 0, DEFAULT_KDC_TIMESYNC,
			    &tmp);
	ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;

	/*
	 * We use a default file credentials cache of 3.  See
	 * lib/krb5/krb/ccache/file/fcc.h for a description of the
	 * credentials cache types.
	 *
	 * Note: DCE 1.0.3a only supports a cache type of 1
	 * 	DCE 1.1 supports a cache type of 2.
	 */
#define DEFAULT_CCACHE_TYPE 4
	profile_get_integer(ctx->profile, "libdefaults", "ccache_type",
			    0, DEFAULT_CCACHE_TYPE, &tmp);
	ctx->fcc_default_format = tmp + 0x0500;
	ctx->prompt_types = 0;
	ctx->use_conf_ktypes = 0;

	ctx->udp_pref_limit = -1;
	*context = ctx;
	return 0;

cleanup:
	krb5_free_context(ctx);
	return retval;
}
Example #5
0
int
main(int argc, char *argv[])
{
    OM_uint32 minor_status;
    gss_buffer_desc in_buf;
    gss_OID nt_krb5_name_oid = (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME;
    auth_gssapi_name names[4];
    kadm5_config_params params;
    verto_ctx *vctx;
    const char *pid_file = NULL;
    char **db_args = NULL, **tmpargs;
    int ret, i, db_args_size = 0, strong_random = 1, proponly = 0;

    setlocale(LC_ALL, "");
    setvbuf(stderr, NULL, _IONBF, 0);

    names[0].name = names[1].name = names[2].name = names[3].name = NULL;
    names[0].type = names[1].type = names[2].type = names[3].type =
        nt_krb5_name_oid;

    progname = (strrchr(argv[0], '/') != NULL) ? strrchr(argv[0], '/') + 1 :
        argv[0];

    memset(&params, 0, sizeof(params));

    argc--, argv++;
    while (argc) {
        if (strcmp(*argv, "-x") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            db_args_size++;
            tmpargs = realloc(db_args, sizeof(char *) * (db_args_size + 1));
            if (tmpargs == NULL) {
                fprintf(stderr, _("%s: cannot initialize. Not enough "
                                  "memory\n"), progname);
                exit(1);
            }
            db_args = tmpargs;
            db_args[db_args_size - 1] = *argv;
            db_args[db_args_size] = NULL;
        } else if (strcmp(*argv, "-r") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            params.realm = *argv;
            params.mask |= KADM5_CONFIG_REALM;
            argc--, argv++;
            continue;
        } else if (strcmp(*argv, "-m") == 0) {
            params.mkey_from_kbd = 1;
            params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
        } else if (strcmp(*argv, "-nofork") == 0) {
            nofork = 1;
#ifdef USE_PASSWORD_SERVER
        } else if (strcmp(*argv, "-passwordserver") == 0) {
            kadm5_set_use_password_server();
#endif
#ifndef DISABLE_IPROP
        } else if (strcmp(*argv, "-proponly") == 0) {
            proponly = 1;
#endif
        } else if (strcmp(*argv, "-port") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            params.kadmind_port = atoi(*argv);
            params.mask |= KADM5_CONFIG_KADMIND_PORT;
        } else if (strcmp(*argv, "-P") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            pid_file = *argv;
        } else if (strcmp(*argv, "-W") == 0) {
            strong_random = 0;
        } else if (strcmp(*argv, "-p") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            kdb5_util = *argv;
        } else if (strcmp(*argv, "-F") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            dump_file = *argv;
        } else if (strcmp(*argv, "-K") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            kprop = *argv;
        } else if (strcmp(*argv, "-k") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            kprop_port = *argv;
        } else {
            break;
        }
        argc--, argv++;
    }

    if (argc != 0)
        usage();

    ret = kadm5_init_krb5_context(&context);
    if (ret) {
        fprintf(stderr, _("%s: %s while initializing context, aborting\n"),
                progname, error_message(ret));
        exit(1);
    }

    krb5_klog_init(context, "admin_server", progname, 1);

    ret = kadm5_init(context, "kadmind", NULL, NULL, &params,
                     KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, db_args,
                     &global_server_handle);
    if (ret)
        fail_to_start(ret, _("initializing"));

    ret = kadm5_get_config_params(context, 1, &params, &params);
    if (ret)
        fail_to_start(ret, _("getting config parameters"));
    if (!(params.mask & KADM5_CONFIG_REALM))
        fail_to_start(0, _("Missing required realm configuration"));
    if (!(params.mask & KADM5_CONFIG_ACL_FILE))
        fail_to_start(0, _("Missing required ACL file configuration"));

    ret = setup_loop(proponly, &vctx);
    if (ret)
        fail_to_start(ret, _("initializing network"));

    names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
    names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
    if (names[0].name == NULL || names[1].name == NULL)
        fail_to_start(0, _("Cannot build GSSAPI auth names"));

    ret = setup_kdb_keytab();
    if (ret)
        fail_to_start(0, _("Cannot set up KDB keytab"));

    if (svcauth_gssapi_set_names(names, 2) == FALSE)
        fail_to_start(0, _("Cannot set GSSAPI authentication names"));

    /* if set_names succeeded, this will too */
    in_buf.value = names[1].name;
    in_buf.length = strlen(names[1].name) + 1;
    (void)gss_import_name(&minor_status, &in_buf, nt_krb5_name_oid,
                          &gss_changepw_name);

    svcauth_gssapi_set_log_badauth2_func(log_badauth, NULL);
    svcauth_gssapi_set_log_badverf_func(log_badverf, NULL);
    svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);

    svcauth_gss_set_log_badauth2_func(log_badauth, NULL);
    svcauth_gss_set_log_badverf_func(log_badverf, NULL);
    svcauth_gss_set_log_miscerr_func(log_miscerr, NULL);

    if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE)
        fail_to_start(0, _("Cannot initialize GSSAPI service name"));

    ret = acl_init(context, params.acl_file);
    if (ret)
        fail_to_start(ret, _("initializing ACL file"));

    if (!nofork && daemon(0, 0) != 0)
        fail_to_start(errno, _("spawning daemon process"));
    if (pid_file != NULL) {
        ret = write_pid_file(pid_file);
        if (ret)
            fail_to_start(ret, _("creating PID file"));
    }

    krb5_klog_syslog(LOG_INFO, _("Seeding random number generator"));
    ret = krb5_c_random_os_entropy(context, strong_random, NULL);
    if (ret)
        fail_to_start(ret, _("getting random seed"));

    if (params.iprop_enabled == TRUE) {
        ulog_set_role(context, IPROP_MASTER);

        ret = ulog_map(context, params.iprop_logfile, params.iprop_ulogsize);
        if (ret)
            fail_to_start(ret, _("mapping update log"));

        if (nofork) {
            fprintf(stderr,
                    _("%s: create IPROP svc (PROG=%d, VERS=%d)\n"),
                    progname, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
        }
    }

    if (kprop_port == NULL)
        kprop_port = getenv("KPROP_PORT");

    krb5_klog_syslog(LOG_INFO, _("starting"));
    if (nofork)
        fprintf(stderr, _("%s: starting...\n"), progname);

    verto_run(vctx);
    krb5_klog_syslog(LOG_INFO, _("finished, exiting"));

    /* Clean up memory, etc */
    svcauth_gssapi_unset_names();
    kadm5_destroy(global_server_handle);
    loop_free(vctx);
    acl_finish(context);
    (void)gss_release_name(&minor_status, &gss_changepw_name);
    (void)gss_release_name(&minor_status, &gss_oldchangepw_name);
    for (i = 0; i < 4; i++)
        free(names[i].name);

    krb5_klog_close(context);
    krb5_free_context(context);
    exit(2);
}
Example #6
0
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);
}