Beispiel #1
0
static krb5_error_code
kpasswd_get_next(krb5_context context,
		 struct krb5_krbhst_data *kd,
		 krb5_krbhst_info **host)
{
    krb5_error_code ret;

    if ((kd->flags & KD_PLUGIN) == 0) {
	plugin_get_hosts(context, kd, locate_service_kpasswd);
	kd->flags |= KD_PLUGIN;
	if(get_next(kd, host))
	    return 0;
    }

    if((kd->flags & KD_CONFIG) == 0) {
	config_get_hosts(context, kd, "kpasswd_server");
	kd->flags |= KD_CONFIG;
	if(get_next(kd, host))
	    return 0;
    }

    if (kd->flags & KD_CONFIG_EXISTS) {
	_krb5_debug(context, 1,
		    "Configuration exists for realm %s, wont go to DNS",
		    kd->realm);
	return KRB5_KDC_UNREACH;
    }

    if(context->srv_lookup) {
	if((kd->flags & KD_SRV_UDP) == 0) {
	    srv_get_hosts(context, kd, "udp", "kpasswd");
	    kd->flags |= KD_SRV_UDP;
	    if(get_next(kd, host))
		return 0;
	}
	if((kd->flags & KD_SRV_TCP) == 0) {
	    srv_get_hosts(context, kd, "tcp", "kpasswd");
	    kd->flags |= KD_SRV_TCP;
	    if(get_next(kd, host))
		return 0;
	}
    }

    /* no matches -> try admin */

    if (krbhst_empty(kd)) {
	kd->flags = 0;
	kd->port  = kd->def_port;
	kd->get_next = admin_get_next;
	ret = (*kd->get_next)(context, kd, host);
	if (ret == 0)
	    (*host)->proto = krbhst_get_default_proto(kd);
	return ret;
    }

    _krb5_debug(context, 0, "No kpasswd entries found for realm %s", kd->realm);

    return KRB5_KDC_UNREACH;
}
Beispiel #2
0
static krb5_error_code
admin_get_next(krb5_context context,
	       struct krb5_krbhst_data *kd,
	       krb5_krbhst_info **host)
{
    krb5_error_code ret;

    if ((kd->flags & KD_PLUGIN) == 0) {
	plugin_get_hosts(context, kd, locate_service_kadmin);
	kd->flags |= KD_PLUGIN;
	if(get_next(kd, host))
	    return 0;
    }

    if((kd->flags & KD_CONFIG) == 0) {
	config_get_hosts(context, kd, "admin_server");
	kd->flags |= KD_CONFIG;
	if(get_next(kd, host))
	    return 0;
    }

    if (kd->flags & KD_CONFIG_EXISTS) {
	_krb5_debug(context, 1,
		    "Configuration exists for realm %s, wont go to DNS",
		    kd->realm);
	return KRB5_KDC_UNREACH;
    }

    if(context->srv_lookup) {
	if((kd->flags & KD_SRV_TCP) == 0) {
	    srv_get_hosts(context, kd, "tcp", "kerberos-adm");
	    kd->flags |= KD_SRV_TCP;
	    if(get_next(kd, host))
		return 0;
	}
    }

    if (krbhst_empty(kd)
	&& (kd->flags & KD_FALLBACK) == 0) {
	ret = fallback_get_hosts(context, kd, "kerberos",
				 kd->def_port,
				 krbhst_get_default_proto(kd));
	if(ret)
	    return ret;
	kd->flags |= KD_FALLBACK;
	if(get_next(kd, host))
	    return 0;
    }

    _krb5_debug(context, 0, "No admin entries found for realm %s", kd->realm);

    return KRB5_KDC_UNREACH;	/* XXX */
}
Beispiel #3
0
static struct krb5_krbhst_data*
common_init(krb5_context context,
	    const char *service,
	    const char *realm,
	    int flags)
{
    struct krb5_krbhst_data *kd;

    if((kd = calloc(1, sizeof(*kd))) == NULL)
	return NULL;

    if((kd->realm = strdup(realm)) == NULL) {
	free(kd);
	return NULL;
    }

    _krb5_debug(context, 2, "Trying to find service %s for realm %s flags %x",
		service, realm, flags);

    /* For 'realms' without a . do not even think of going to DNS */
    if (!strchr(realm, '.'))
	kd->flags |= KD_CONFIG_EXISTS;

    if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG)
	kd->flags |= KD_LARGE_MSG;
    kd->end = kd->index = &kd->hosts;
    return kd;
}
Beispiel #4
0
static krb5_error_code
fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
		   const char *serv_string, int port, int proto)
{
    char *host = NULL;
    int ret;
    struct addrinfo *ai;
    struct addrinfo hints;
    char portstr[NI_MAXSERV];

    _krb5_debug(context, 2, "fallback lookup %d for realm %s (service %s)",
		kd->fallback_count, kd->realm, serv_string);

    /*
     * Don't try forever in case the DNS server keep returning us
     * entries (like wildcard entries or the .nu TLD)
     */
    if(kd->fallback_count >= 5) {
	kd->flags |= KD_FALLBACK;
	return 0;
    }

    if(kd->fallback_count == 0)
	ret = asprintf(&host, "%s.%s.", serv_string, kd->realm);
    else
	ret = asprintf(&host, "%s-%d.%s.",
		       serv_string, kd->fallback_count, kd->realm);

    if (ret < 0 || host == NULL)
	return ENOMEM;

    make_hints(&hints, proto);
    snprintf(portstr, sizeof(portstr), "%d", port);
    ret = getaddrinfo(host, portstr, &hints, &ai);
    if (ret) {
	/* no more hosts, so we're done here */
	free(host);
	kd->flags |= KD_FALLBACK;
    } else {
	struct krb5_krbhst_info *hi;
	size_t hostlen = strlen(host);

	hi = calloc(1, sizeof(*hi) + hostlen);
	if(hi == NULL) {
	    free(host);
	    return ENOMEM;
	}

	hi->proto = proto;
	hi->port  = hi->def_port = port;
	hi->ai    = ai;
	memmove(hi->hostname, host, hostlen);
	hi->hostname[hostlen] = '\0';
	free(host);
	append_host_hostinfo(kd, hi);
	kd->fallback_count++;
    }
    return 0;
}
Beispiel #5
0
void
_krb5_debug_backtrace(krb5_context context)
{
#if defined(HAVE_BACKTRACE) && !defined(HEIMDAL_SMALLER)
    void *stack[128];
    char **strs = NULL;
    int i, frames = backtrace(stack, sizeof(stack) / sizeof(stack[0]));
    if (frames > 0)
	strs = backtrace_symbols(stack, frames);
    if (strs) {
	for (i = 0; i < frames; i++)
	    _krb5_debug(context, 10, "frame %d: %s", i, strs[i]);
	free(strs);
    }
#endif
}
Beispiel #6
0
krb5_error_code
_krb5_einval(krb5_context context, const char *func, unsigned long argn)
{
#ifndef HEIMDAL_SMALLER
    krb5_set_error_message(context, EINVAL,
			   N_("programmer error: invalid argument to %s argument %lu",
			      "function:line"),
			   func, argn);
    if (_krb5_have_debug(context, 10)) {
	_krb5_debug(context, 10, "invalid argument to function %s argument %lu",
		    func, argn);
	_krb5_debug_backtrace(context);
    }
#endif
    return EINVAL;
}
Beispiel #7
0
static void
srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
	      const char *proto, const char *service)
{
    krb5_error_code ret;
    krb5_krbhst_info **res;
    int count, i;

    ret = srv_find_realm(context, &res, &count, kd->realm, "SRV", proto, service,
			 kd->port);
    _krb5_debug(context, 2, "searching DNS for realm %s %s.%s -> %d",
		kd->realm, proto, service, ret);
    if (ret)
	return;
    for(i = 0; i < count; i++)
	append_host_hostinfo(kd, res[i]);
    free(res);
}
Beispiel #8
0
static void
config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
		 const char *conf_string)
{
    int i;
    char **hostlist;
    hostlist = krb5_config_get_strings(context, NULL,
				       "realms", kd->realm, conf_string, NULL);

    _krb5_debug(context, 2, "configuration file for realm %s%s found",
		kd->realm, hostlist ? "" : " not");

    if(hostlist == NULL)
	return;
    kd->flags |= KD_CONFIG_EXISTS;
    for(i = 0; hostlist && hostlist[i] != NULL; i++)
	append_host_string(context, kd, hostlist[i], kd->def_port, kd->port);

    krb5_config_free_strings(hostlist);
}
Beispiel #9
0
static void
plugin_get_hosts(krb5_context context,
		 struct krb5_krbhst_data *kd,
		 enum locate_service_type type)
{
    struct krb5_plugin *list = NULL, *e;
    krb5_error_code ret;

    ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA,
			    KRB5_PLUGIN_LOCATE, &list);
    if(ret != 0 || list == NULL)
	return;

    for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) {
	krb5plugin_service_locate_ftable *service;
	void *ctx;

	service = _krb5_plugin_get_symbol(e);
	if (service->minor_version != 0)
	    continue;

	(*service->init)(context, &ctx);
	ret = (*service->lookup)(ctx, type, kd->realm, 0, 0, add_locate, kd);
	(*service->fini)(ctx);
	if (ret && ret != KRB5_PLUGIN_NO_HANDLE) {
	    krb5_set_error_message(context, ret,
				   N_("Locate plugin failed to lookup realm %s: %d", ""),
				   kd->realm, ret);
	    break;
	} else if (ret == 0) {
	    _krb5_debug(context, 2, "plugin found result for realm %s", kd->realm);
	    kd->flags |= KD_CONFIG_EXISTS;
	}

    }
    _krb5_plugin_free(list);
}
Beispiel #10
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_creds(krb5_context context,
	       krb5_get_creds_opt opt,
	       krb5_ccache ccache,
	       krb5_const_principal inprinc,
	       krb5_creds **out_creds)
{
    krb5_kdc_flags flags;
    krb5_flags options;
    krb5_creds in_creds;
    krb5_error_code ret;
    krb5_creds **tgts;
    krb5_creds *res_creds;
    int i;

    if (opt && opt->enctype) {
	ret = krb5_enctype_valid(context, opt->enctype);
	if (ret)
	    return ret;
    }

    memset(&in_creds, 0, sizeof(in_creds));
    in_creds.server = rk_UNCONST(inprinc);

    ret = krb5_cc_get_principal(context, ccache, &in_creds.client);
    if (ret)
	return ret;

    if (opt)
	options = opt->options;
    else
	options = 0;
    flags.i = 0;

    *out_creds = NULL;
    res_creds = calloc(1, sizeof(*res_creds));
    if (res_creds == NULL) {
	krb5_free_principal(context, in_creds.client);
	krb5_set_error_message(context, ENOMEM,
			       N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    if (opt && opt->enctype) {
	in_creds.session.keytype = opt->enctype;
	options |= KRB5_TC_MATCH_KEYTYPE;
    }

    /*
     * If we got a credential, check if credential is expired before
     * returning it.
     */
    ret = krb5_cc_retrieve_cred(context,
                                ccache,
				options & KRB5_TC_MATCH_KEYTYPE,
                                &in_creds, res_creds);
    /*
     * If we got a credential, check if credential is expired before
     * returning it, but only if KRB5_GC_EXPIRED_OK is not set.
     */
    if (ret == 0) {
	krb5_timestamp timeret;

	/* If expired ok, don't bother checking */
        if(options & KRB5_GC_EXPIRED_OK) {
            *out_creds = res_creds;
	    krb5_free_principal(context, in_creds.client);
            goto out;
        }
	
	krb5_timeofday(context, &timeret);
	if(res_creds->times.endtime > timeret) {
	    *out_creds = res_creds;
	    krb5_free_principal(context, in_creds.client);
            goto out;
	}
	if(options & KRB5_GC_CACHED)
	    krb5_cc_remove_cred(context, ccache, 0, res_creds);

    } else if(ret != KRB5_CC_END) {
        free(res_creds);
	krb5_free_principal(context, in_creds.client);
	goto out;
    }
    free(res_creds);
    if(options & KRB5_GC_CACHED) {
	krb5_free_principal(context, in_creds.client);
	ret = not_found(context, in_creds.server, KRB5_CC_NOTFOUND);
	goto out;
    }
    if(options & KRB5_GC_USER_USER) {
	flags.b.enc_tkt_in_skey = 1;
	options |= KRB5_GC_NO_STORE;
    }
    if (options & KRB5_GC_FORWARDABLE)
	flags.b.forwardable = 1;
    if (options & KRB5_GC_NO_TRANSIT_CHECK)
	flags.b.disable_transited_check = 1;
    if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
	flags.b.request_anonymous = 1; /* XXX ARGH confusion */
	flags.b.constrained_delegation = 1;
    }
    if (options & KRB5_GC_CANONICALIZE)
	flags.b.canonicalize = 1;

    tgts = NULL;
    ret = _krb5_get_cred_kdc_any(context, flags, ccache,
				 &in_creds, opt->self, opt->ticket,
				 out_creds, &tgts);
    krb5_free_principal(context, in_creds.client);
    for(i = 0; tgts && tgts[i]; i++) {
	krb5_cc_store_cred(context, ccache, tgts[i]);
	krb5_free_creds(context, tgts[i]);
    }
    free(tgts);
    if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0)
	krb5_cc_store_cred(context, ccache, *out_creds);

 out:
    _krb5_debug(context, 5, "krb5_get_creds: ret = %d", ret);

    return ret;
}
Beispiel #11
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_creds(krb5_context context,
	       krb5_get_creds_opt opt,
	       krb5_ccache ccache,
	       krb5_const_principal inprinc,
	       krb5_creds **out_creds)
{
    krb5_kdc_flags flags;
    krb5_flags options;
    krb5_creds in_creds;
    krb5_error_code ret;
    krb5_creds **tgts;
    krb5_creds *try_creds;
    krb5_creds *res_creds;
    krb5_name_canon_iterator name_canon_iter = NULL;
    krb5_name_canon_rule_options rule_opts;
    int i;

    if (opt && opt->enctype) {
	ret = krb5_enctype_valid(context, opt->enctype);
	if (ret)
	    return ret;
    }

    memset(&in_creds, 0, sizeof(in_creds));
    in_creds.server = rk_UNCONST(inprinc);

    ret = krb5_cc_get_principal(context, ccache, &in_creds.client);
    if (ret)
	return ret;

    if (opt)
	options = opt->options;
    else
	options = 0;
    flags.i = 0;

    *out_creds = NULL;
    res_creds = calloc(1, sizeof(*res_creds));
    if (res_creds == NULL) {
	krb5_free_principal(context, in_creds.client);
	return krb5_enomem(context);
    }

    if (opt && opt->enctype) {
	in_creds.session.keytype = opt->enctype;
	options |= KRB5_TC_MATCH_KEYTYPE;
    }

    /* Check for entry in ccache */
    if (inprinc->name.name_type == KRB5_NT_SRV_HST_NEEDS_CANON) {
	ret = check_cc(context, options, ccache, &in_creds, res_creds);
	if (ret == 0) {
	    *out_creds = res_creds;
	    goto out;
	}
    }

    ret = krb5_name_canon_iterator_start(context, NULL, &in_creds,
					 &name_canon_iter);
    if (ret)
	goto out;

next_rule:
    ret = krb5_name_canon_iterate_creds(context, &name_canon_iter, &try_creds,
					&rule_opts);
    if (ret)
	return ret;
    if (name_canon_iter == NULL) {
	if (options & KRB5_GC_CACHED)
	    ret = KRB5_CC_NOTFOUND;
	else
	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	goto out;
    }
    ret = check_cc(context, options, ccache, try_creds, res_creds);
    if (ret == 0) {
	*out_creds = res_creds;
	goto out;
    } else if(ret != KRB5_CC_END) {
	goto out;
    }
    if(options & KRB5_GC_CACHED)
	goto next_rule;

    if(rule_opts & KRB5_NCRO_USE_REFERRALS)
	flags.b.canonicalize = 1;
    else if(rule_opts & KRB5_NCRO_NO_REFERRALS)
	flags.b.canonicalize = 0;
    else
	flags.b.canonicalize = (options & KRB5_GC_CANONICALIZE) ? 1 : 0;
    if(options & KRB5_GC_USER_USER) {
	flags.b.enc_tkt_in_skey = 1;
	options |= KRB5_GC_NO_STORE;
    }
    if (options & KRB5_GC_FORWARDABLE)
	flags.b.forwardable = 1;
    if (options & KRB5_GC_NO_TRANSIT_CHECK)
	flags.b.disable_transited_check = 1;
    if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
	flags.b.request_anonymous = 1; /* XXX ARGH confusion */
	flags.b.constrained_delegation = 1;
    }

    tgts = NULL;
    ret = _krb5_get_cred_kdc_any(context, flags, ccache,
				 try_creds, opt ? opt->self : 0,
				 opt ? opt->ticket : 0, out_creds,
				 &tgts);
    for(i = 0; tgts && tgts[i]; i++) {
	krb5_cc_store_cred(context, ccache, tgts[i]);
	krb5_free_creds(context, tgts[i]);
    }
    free(tgts);

    if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN &&
	!(rule_opts & KRB5_NCRO_SECURE))
	goto next_rule;

    if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0)
	store_cred(context, ccache, inprinc, *out_creds);

out:
    if (ret) {
	krb5_free_creds(context, res_creds);
	ret = not_found(context, inprinc, ret);
    }
    krb5_free_principal(context, in_creds.client);
    krb5_free_name_canon_iterator(context, name_canon_iter);
    _krb5_debug(context, 5, "krb5_get_creds: ret = %d", ret);
    return ret;
}
Beispiel #12
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_sendto (krb5_context context,
	     const krb5_data *send_data,
	     krb5_krbhst_handle handle,
	     krb5_data *receive)
{
     krb5_error_code ret;
     krb5_socket_t fd;
     size_t i;

     krb5_data_zero(receive);

     for (i = 0; i < context->max_retries; ++i) {
	 krb5_krbhst_info *hi;

	 while (krb5_krbhst_next(context, handle, &hi) == 0) {
	     struct addrinfo *ai, *a;

	     _krb5_debug(context, 2,
			 "trying to communicate with host %s in realm %s",
			 hi->hostname, _krb5_krbhst_get_realm(handle));

	     if (context->send_to_kdc) {
		 struct send_to_kdc *s = context->send_to_kdc;

		 ret = (*s->func)(context, s->data, hi,
				  context->kdc_timeout, send_data, receive);
		 if (ret == 0 && receive->length != 0)
		     goto out;
		 continue;
	     }

	     ret = send_via_plugin(context, hi, context->kdc_timeout,
				   send_data, receive);
	     if (ret == 0 && receive->length != 0)
		 goto out;
	     else if (ret != KRB5_PLUGIN_NO_HANDLE)
		 continue;

	     if(hi->proto == KRB5_KRBHST_HTTP && context->http_proxy) {
		 if (send_via_proxy (context, hi, send_data, receive) == 0) {
		     ret = 0;
		     goto out;
		 }
		 continue;
	     }

	     ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
	     if (ret)
		 continue;

	     for (a = ai; a != NULL; a = a->ai_next) {
		 fd = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol);
		 if (rk_IS_BAD_SOCKET(fd))
		     continue;
		 rk_cloexec(fd);
		 if (timed_connect (fd, a, context->kdc_timeout) < 0) {
		     rk_closesocket (fd);
		     continue;
		 }
		 switch (hi->proto) {
		 case KRB5_KRBHST_HTTP :
		     ret = send_and_recv_http(fd, context->kdc_timeout,
					      "", send_data, receive);
		     break;
		 case KRB5_KRBHST_TCP :
		     ret = send_and_recv_tcp (fd, context->kdc_timeout,
					      send_data, receive);
		     break;
		 case KRB5_KRBHST_UDP :
		     ret = send_and_recv_udp (fd, context->kdc_timeout,
					      send_data, receive);
		     break;
		 }
		 rk_closesocket (fd);
		 if(ret == 0 && receive->length != 0)
		     goto out;
	     }
	 }
	 krb5_krbhst_reset(context, handle);
     }
     krb5_clear_error_message (context);
     ret = KRB5_KDC_UNREACH;
out:
     _krb5_debug(context, 2,
		 "result of trying to talk to realm %s = %d",
		 _krb5_krbhst_get_realm(handle), ret);
     return ret;
}
Beispiel #13
0
KRB5_LIB_FUNCTION int KRB5_LIB_CALL
_krb5_extract_ticket(krb5_context context,
		     krb5_kdc_rep *rep,
		     krb5_creds *creds,
		     krb5_keyblock *key,
		     krb5_const_pointer keyseed,
		     krb5_key_usage key_usage,
		     krb5_addresses *addrs,
		     unsigned nonce,
		     unsigned flags,
		     krb5_data *request,
		     krb5_decrypt_proc decrypt_proc,
		     krb5_const_pointer decryptarg)
{
    krb5_error_code ret;
    krb5_principal tmp_principal;
    size_t len = 0;
    time_t tmp_time;
    krb5_timestamp sec_now;

    /* decrypt */

    if (decrypt_proc == NULL)
	decrypt_proc = decrypt_tkt;

    ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
    if (ret)
	goto out;

    if (rep->enc_part.flags.enc_pa_rep && request) {
	krb5_crypto crypto = NULL;
	Checksum cksum;
	PA_DATA *pa = NULL;
	int idx = 0;

	_krb5_debug(context, 5, "processing enc-ap-rep");

	if (rep->enc_part.encrypted_pa_data == NULL ||
	    (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val,
				   rep->enc_part.encrypted_pa_data->len,
				   KRB5_PADATA_REQ_ENC_PA_REP,
				   &idx)) == NULL)
	{
	    _krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing");
	    ret = KRB5KRB_AP_ERR_MODIFIED;
	    goto out;
	}
	
	ret = krb5_crypto_init(context, key, 0, &crypto);
	if (ret)
	    goto out;
	
	ret = decode_Checksum(pa->padata_value.data,
			      pa->padata_value.length,
			      &cksum, NULL);
	if (ret) {
	    krb5_crypto_destroy(context, crypto);
	    goto out;
	}
	
	ret = krb5_verify_checksum(context, crypto,
				   KRB5_KU_AS_REQ,
				   request->data, request->length,
				   &cksum);
	krb5_crypto_destroy(context, crypto);
	free_Checksum(&cksum);
	_krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in");
	if (ret)
	    goto out;
    }

    /* save session key */

    creds->session.keyvalue.length = 0;
    creds->session.keyvalue.data   = NULL;
    creds->session.keytype = rep->enc_part.key.keytype;
    ret = krb5_data_copy (&creds->session.keyvalue,
			  rep->enc_part.key.keyvalue.data,
			  rep->enc_part.key.keyvalue.length);
    if (ret) {
	krb5_clear_error_message(context);
	goto out;
    }

    /* compare client and save */
    ret = _krb5_principalname2krb5_principal(context,
					     &tmp_principal,
					     rep->kdc_rep.cname,
					     rep->kdc_rep.crealm);
    if (ret)
	goto out;

    /* check client referral and save principal */
    /* anonymous here ? */
    if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
	ret = check_client_referral(context, rep,
				    creds->client,
				    tmp_principal,
				    &creds->session);
	if (ret) {
	    krb5_free_principal (context, tmp_principal);
	    goto out;
	}
    }
    krb5_free_principal (context, creds->client);
    creds->client = tmp_principal;

    /* check server referral and save principal */
    ret = _krb5_principalname2krb5_principal (context,
					      &tmp_principal,
					      rep->enc_part.sname,
					      rep->enc_part.srealm);
    if (ret)
	goto out;
    if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
	ret = check_server_referral(context,
				    rep,
				    flags,
				    creds->server,
				    tmp_principal,
				    &creds->session);
	if (ret) {
	    krb5_free_principal (context, tmp_principal);
	    goto out;
	}
    }
    krb5_free_principal(context, creds->server);
    creds->server = tmp_principal;

    /* verify names */
    if(flags & EXTRACT_TICKET_MATCH_REALM){
	const char *srealm = krb5_principal_get_realm(context, creds->server);
	const char *crealm = krb5_principal_get_realm(context, creds->client);

	if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
	    strcmp(rep->enc_part.srealm, crealm) != 0)
	{
	    ret = KRB5KRB_AP_ERR_MODIFIED;
	    krb5_clear_error_message(context);
	    goto out;
	}
    }

    /* compare nonces */

    if (nonce != (unsigned)rep->enc_part.nonce) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto out;
    }

    /* set kdc-offset */

    krb5_timeofday (context, &sec_now);
    if (rep->enc_part.flags.initial
	&& (flags & EXTRACT_TICKET_TIMESYNC)
	&& context->kdc_sec_offset == 0
	&& krb5_config_get_bool (context, NULL,
				 "libdefaults",
				 "kdc_timesync",
				 NULL)) {
	context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
	krb5_timeofday (context, &sec_now);
    }

    /* check all times */

    if (rep->enc_part.starttime) {
	tmp_time = *rep->enc_part.starttime;
    } else
	tmp_time = rep->enc_part.authtime;

    if (creds->times.starttime == 0
	&& labs(tmp_time - sec_now) > context->max_skew) {
	ret = KRB5KRB_AP_ERR_SKEW;
	krb5_set_error_message (context, ret,
				N_("time skew (%ld) larger than max (%ld)", ""),
			       labs(tmp_time - sec_now),
			       (long)context->max_skew);
	goto out;
    }

    if (creds->times.starttime != 0
	&& tmp_time != creds->times.starttime) {
	krb5_clear_error_message (context);
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto out;
    }

    creds->times.starttime = tmp_time;

    if (rep->enc_part.renew_till) {
	tmp_time = *rep->enc_part.renew_till;
    } else
	tmp_time = 0;

    if (creds->times.renew_till != 0
	&& tmp_time > creds->times.renew_till) {
	krb5_clear_error_message (context);
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto out;
    }

    creds->times.renew_till = tmp_time;

    creds->times.authtime = rep->enc_part.authtime;

    if (creds->times.endtime != 0
	&& rep->enc_part.endtime > creds->times.endtime) {
	krb5_clear_error_message (context);
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto out;
    }

    creds->times.endtime  = rep->enc_part.endtime;

    if(rep->enc_part.caddr)
	krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
    else if(addrs)
	krb5_copy_addresses (context, addrs, &creds->addresses);
    else {
	creds->addresses.len = 0;
	creds->addresses.val = NULL;
    }
    creds->flags.b = rep->enc_part.flags;

    creds->authdata.len = 0;
    creds->authdata.val = NULL;

    /* extract ticket */
    ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
		       &rep->kdc_rep.ticket, &len, ret);
    if(ret)
	goto out;
    if (creds->ticket.length != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");
    creds->second_ticket.length = 0;
    creds->second_ticket.data   = NULL;


out:
    memset (rep->enc_part.key.keyvalue.data, 0,
	    rep->enc_part.key.keyvalue.length);
    return ret;
}
Beispiel #14
0
static krb5_error_code
srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count,
	       const char *realm, const char *dns_type,
	       const char *proto, const char *service, int port)
{
    char domain[1024];
    struct rk_dns_reply *r;
    struct rk_resource_record *rr;
    int num_srv;
    int proto_num;
    int def_port;

    *res = NULL;
    *count = 0;

    proto_num = string_to_proto(proto);
    if(proto_num < 0) {
	krb5_set_error_message(context, EINVAL,
			       N_("unknown protocol `%s' to lookup", ""),
			       proto);
	return EINVAL;
    }

    if(proto_num == KRB5_KRBHST_HTTP)
	def_port = ntohs(krb5_getportbyname (context, "http", "tcp", 80));
    else if(port == 0)
	def_port = ntohs(krb5_getportbyname (context, service, proto, 88));
    else
	def_port = port;

    snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);

    r = rk_dns_lookup(domain, dns_type);
    if(r == NULL) {
	_krb5_debug(context, 0,
		    "DNS lookup failed domain: %s", domain);
	return KRB5_KDC_UNREACH;
    }

    for(num_srv = 0, rr = r->head; rr; rr = rr->next)
	if(rr->type == rk_ns_t_srv)
	    num_srv++;

    *res = malloc(num_srv * sizeof(**res));
    if(*res == NULL) {
	rk_dns_free_data(r);
	krb5_set_error_message(context, ENOMEM,
			       N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    rk_dns_srv_order(r);

    for(num_srv = 0, rr = r->head; rr; rr = rr->next)
	if(rr->type == rk_ns_t_srv) {
	    krb5_krbhst_info *hi;
	    size_t len = strlen(rr->u.srv->target);

	    hi = calloc(1, sizeof(*hi) + len);
	    if(hi == NULL) {
		rk_dns_free_data(r);
		while(--num_srv >= 0)
		    free((*res)[num_srv]);
		free(*res);
		*res = NULL;
		return ENOMEM;
	    }
	    (*res)[num_srv++] = hi;

	    hi->proto = proto_num;

	    hi->def_port = def_port;
	    if (port != 0)
		hi->port = port;
	    else
		hi->port = rr->u.srv->port;

	    strlcpy(hi->hostname, rr->u.srv->target, len + 1);
	}

    *count = num_srv;

    rk_dns_free_data(r);
    return 0;
}
Beispiel #15
0
static krb5_error_code
kdc_get_next(krb5_context context,
	     struct krb5_krbhst_data *kd,
	     krb5_krbhst_info **host)
{
    krb5_error_code ret;

    if ((kd->flags & KD_HOSTNAMES) == 0) {
	hostnames_get_hosts(context, kd, "kdc");
	if(get_next(kd, host))
	    return 0;
    }

    if ((kd->flags & KD_PLUGIN) == 0) {
	plugin_get_hosts(context, kd, locate_service_kdc);
	kd->flags |= KD_PLUGIN;
	if(get_next(kd, host))
	    return 0;
    }

    if((kd->flags & KD_CONFIG) == 0) {
	config_get_hosts(context, kd, "kdc");
	kd->flags |= KD_CONFIG;
	if(get_next(kd, host))
	    return 0;
    }

    if (kd->flags & KD_CONFIG_EXISTS) {
	_krb5_debug(context, 1,
		    "Configuration exists for realm %s, wont go to DNS",
		    kd->realm);
	return KRB5_KDC_UNREACH;
    }

    if(context->srv_lookup) {
	if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) {
	    srv_get_hosts(context, kd, "udp", "kerberos");
	    kd->flags |= KD_SRV_UDP;
	    if(get_next(kd, host))
		return 0;
	}

	if((kd->flags & KD_SRV_TCP) == 0) {
	    srv_get_hosts(context, kd, "tcp", "kerberos");
	    kd->flags |= KD_SRV_TCP;
	    if(get_next(kd, host))
		return 0;
	}
	if((kd->flags & KD_SRV_HTTP) == 0) {
	    srv_get_hosts(context, kd, "http", "kerberos");
	    kd->flags |= KD_SRV_HTTP;
	    if(get_next(kd, host))
		return 0;
	}
    }

    while((kd->flags & KD_FALLBACK) == 0) {
	ret = fallback_get_hosts(context, kd, "kerberos",
				 kd->def_port,
				 krbhst_get_default_proto(kd));
	if(ret)
	    return ret;
	if(get_next(kd, host))
	    return 0;
    }

    _krb5_debug(context, 0, "No KDC entries found for %s", kd->realm);

    return KRB5_KDC_UNREACH; /* XXX */
}