Пример #1
0
static void
get_creds(krb5_context context, krb5_ccache *cache)
{
    krb5_keytab keytab;
    krb5_principal client;
    krb5_error_code ret;
    krb5_get_init_creds_opt *init_opts;
    krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP;
    krb5_creds creds;

    ret = krb5_kt_register(context, &hdb_kt_ops);
    if(ret) krb5_err(context, 1, ret, "krb5_kt_register");

    ret = krb5_kt_resolve(context, ktname, &keytab);
    if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve");

    ret = krb5_make_principal(context, &client, NULL,
			      "kadmin", HPROP_NAME, NULL);
    if(ret) krb5_err(context, 1, ret, "krb5_make_principal");

    ret = krb5_get_init_creds_opt_alloc(context, &init_opts);
    if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
    krb5_get_init_creds_opt_set_preauth_list(init_opts, &preauth, 1);

    ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, init_opts);
    if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds");

    krb5_get_init_creds_opt_free(context, init_opts);

    ret = krb5_kt_close(context, keytab);
    if(ret) krb5_err(context, 1, ret, "krb5_kt_close");

    ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache);
    if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique");

    ret = krb5_cc_initialize(context, *cache, client);
    if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize");

    krb5_free_principal(context, client);

    ret = krb5_cc_store_cred(context, *cache, &creds);
    if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred");

    krb5_free_cred_contents(context, &creds);
}
Пример #2
0
static void
reply_error (krb5_realm realm,
             int s,
             struct sockaddr *sa,
             int sa_size,
             krb5_error_code error_code,
             uint16_t result_code,
             const char *expl)
{
    krb5_error_code ret;
    krb5_data error_data;
    krb5_data e_data;
    krb5_principal server = NULL;

    if (make_result(&e_data, result_code, expl))
        return;

    if (realm) {
        ret = krb5_make_principal (context, &server, realm,
                                   "kadmin", "changepw", NULL);
        if (ret) {
            krb5_data_free (&e_data);
            return;
        }
    }

    ret = krb5_mk_error (context,
                         error_code,
                         NULL,
                         &e_data,
                         NULL,
                         server,
                         NULL,
                         NULL,
                         &error_data);
    if (server)
        krb5_free_principal(context, server);
    krb5_data_free (&e_data);
    if (ret) {
        krb5_warn (context, ret, "Could not even generate error reply");
        return;
    }
    send_reply (s, sa, sa_size, NULL, &error_data);
    krb5_data_free (&error_data);
}
Пример #3
0
static krb5_error_code
get_default (kadm5_server_context *context,
	     krb5_principal princ,
	     kadm5_principal_ent_t default_ent)
{
    krb5_error_code ret;
    krb5_principal def_principal;
    krb5_const_realm realm = krb5_principal_get_realm(context->context, princ);

    ret = krb5_make_principal (context->context, &def_principal,
			       realm, "default", NULL);
    if (ret)
	return ret;
    ret = kadm5_get_principal (context, def_principal, default_ent,
			       KADM5_PRINCIPAL_NORMAL_MASK);
    krb5_free_principal (context->context, def_principal);
    return ret;
}
Пример #4
0
static int
get_cred(struct kafs_data *data, const char *name, const char *inst,
	 const char *realm, uid_t uid, struct kafs_token *kt)
{
    krb5_error_code ret;
    krb5_creds in_creds, *out_creds;
    struct krb5_kafs_data *d = data->data;
    int invalid;

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

    ret = krb5_make_principal(d->context, &in_creds.server,
			      realm, name, inst, NULL);
    if(ret)
	return ret;
    ret = krb5_cc_get_principal(d->context, d->id, &in_creds.client);
    if(ret){
	krb5_free_principal(d->context, in_creds.server);
	return ret;
    }

    in_creds.session.keytype = ETYPE_DES_CBC_CRC;

    /* check if des is disable, and in that case enable it for afs */
    invalid = krb5_enctype_valid(d->context, in_creds.session.keytype);
    if (invalid)
	krb5_enctype_enable(d->context, in_creds.session.keytype);

    ret = krb5_get_credentials(d->context, 0, d->id, &in_creds, &out_creds);

    if (invalid)
	krb5_enctype_disable(d->context, in_creds.session.keytype);

    krb5_free_principal(d->context, in_creds.server);
    krb5_free_principal(d->context, in_creds.client);
    if(ret)
	return ret;

    ret = v5_convert(d->context, d->id, out_creds, uid,
		     (inst != NULL && inst[0] != '\0') ? inst : realm, kt);
    krb5_free_creds(d->context, out_creds);

    return ret;
}
Пример #5
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_sname_to_principal (krb5_context context,
			 const char *hostname,
			 const char *sname,
			 int32_t type,
			 krb5_principal *ret_princ)
{
    krb5_error_code ret;
    char localhost[MAXHOSTNAMELEN];
    char **realms, *host = NULL;
	
    if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
	krb5_set_error_string (context, "unsupported name type %d",
			       type);
	return KRB5_SNAME_UNSUPP_NAMETYPE;
    }
    if(hostname == NULL) {
	gethostname(localhost, sizeof(localhost));
	hostname = localhost;
    }
    if(sname == NULL)
	sname = "host";
    if(type == KRB5_NT_SRV_HST) {
	ret = krb5_expand_hostname_realms (context, hostname,
					   &host, &realms);
	if (ret)
	    return ret;
	strlwr(host);
	hostname = host;
    } else {
	ret = krb5_get_host_realm(context, hostname, &realms);
	if(ret)
	    return ret;
    }

    ret = krb5_make_principal(context, ret_princ, realms[0], sname,
			      hostname, NULL);
    if(host)
	free(host);
    krb5_free_host_realm(context, realms);
    return ret;
}
Пример #6
0
static krb5_error_code
get_fastuser_crypto(kdc_request_t r, krb5_enctype enctype, krb5_crypto *crypto)
{
    krb5_principal fast_princ;
    hdb_entry_ex *fast_user = NULL;
    Key *cookie_key = NULL;
    krb5_error_code ret;

    *crypto = NULL;

    ret = krb5_make_principal(r->context, &fast_princ,
			      KRB5_WELLKNOWN_ORG_H5L_REALM,
			      KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL);
    if (ret)
	goto out;

    ret = _kdc_db_fetch(r->context, r->config, fast_princ,
			HDB_F_GET_CLIENT, NULL, NULL, &fast_user);
    krb5_free_principal(r->context, fast_princ);
    if (ret)
	goto out;

    if (enctype == KRB5_ENCTYPE_NULL)
	ret = _kdc_get_preferred_key(r->context, r->config, fast_user,
				     "fast-cookie", &enctype, &cookie_key);
    else
	ret = hdb_enctype2key(r->context, &fast_user->entry, NULL,
			      enctype, &cookie_key);
    if (ret)
	goto out;

    ret = krb5_crypto_init(r->context, &cookie_key->key, 0, crypto);
    if (ret)
	goto out;

 out:
    if (fast_user)
	_kdc_free_ent(r->context, fast_user);

    return ret;
}
Пример #7
0
OM_uint32
__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
			  krb5_context context,
			  krb5_ccache id,
			  krb5_principal principal,
			  OM_uint32 *lifetime)
{
    krb5_creds in_cred, out_cred;
    krb5_const_realm realm;
    krb5_error_code kret;

    memset(&in_cred, 0, sizeof(in_cred));
    in_cred.client = principal;

    realm = krb5_principal_get_realm(context,  principal);
    if (realm == NULL) {
	_gsskrb5_clear_status ();
	*minor_status = KRB5_PRINC_NOMATCH; /* XXX */
	return GSS_S_FAILURE;
    }

    kret = krb5_make_principal(context, &in_cred.server,
			       realm, KRB5_TGS_NAME, realm, NULL);
    if (kret) {
	*minor_status = kret;
	return GSS_S_FAILURE;
    }

    kret = krb5_cc_retrieve_cred(context, id, 0, &in_cred, &out_cred);
    krb5_free_principal(context, in_cred.server);
    if (kret) {
	*minor_status = 0;
	*lifetime = 0;
	return GSS_S_COMPLETE;
    }

    *lifetime = out_cred.times.endtime;
    krb5_free_cred_contents(context, &out_cred);

    return GSS_S_COMPLETE;
}
Пример #8
0
static OM_uint32
import_uuid_name(OM_uint32 *minor_status,
		 gss_const_OID mech,
		 const gss_buffer_t input_name_buffer,
		 gss_const_OID input_name_type,
		 gss_name_t *output_name)
{
    krb5_context context;
    krb5_error_code ret;
    krb5_principal princ;
    char uuid[36 + 1];

    GSSAPI_KRB5_INIT(&context);
    
    if (input_name_buffer->length < sizeof(uuid) - 1) {
	*minor_status = 0;
	return GSS_S_BAD_NAME;
    }
    
    memcpy(uuid, input_name_buffer->value, sizeof(uuid) - 1);
    uuid[sizeof(uuid) - 1] = '\0';
    
    /* validate that uuid is only uuid chars and the right length*/
    if (strspn(uuid, "0123456789abcdefABCDEF-") != 36) {
	*minor_status = 0;
	return GSS_S_BAD_NAME;
    }
    
    ret = krb5_make_principal(context, &princ, "UUID", uuid, NULL);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    krb5_principal_set_type(context, princ, KRB5_NT_CACHE_UUID);
    
    *output_name = (gss_name_t)princ;
    *minor_status = 0;

    return GSS_S_COMPLETE;
}
Пример #9
0
static OM_uint32
import_hostbased_name(OM_uint32 *minor_status,
		      krb5_context context,
		      const gss_buffer_t input_name_buffer,
		      gss_name_t *output_name)
{
    krb5_principal princ = NULL;
    krb5_error_code kerr;
    char *tmp, *p, *host = NULL;

    tmp = malloc (input_name_buffer->length + 1);
    if (tmp == NULL) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }
    memcpy (tmp,
	    input_name_buffer->value,
	    input_name_buffer->length);
    tmp[input_name_buffer->length] = '\0';

    p = strchr (tmp, '@');
    if (p != NULL) {
	*p = '\0';
	host = p + 1;
    }

    kerr = krb5_make_principal(context, &princ, "", tmp, host, NULL);
    free (tmp);
    *minor_status = kerr;
    if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
	return GSS_S_BAD_NAME;
    else if (kerr)
	return GSS_S_FAILURE;

    krb5_principal_set_type(context, princ, KRB5_NT_SRV_HST);
    *output_name = (gss_name_t)princ;

    return 0;
}
Пример #10
0
static int
check_for_tgt (krb5_context context,
	       krb5_ccache ccache,
	       krb5_principal principal,
	       time_t *expiration)
{
    krb5_error_code ret;
    krb5_creds pattern;
    krb5_creds creds;
    krb5_const_realm client_realm;
    int expired;

    krb5_cc_clear_mcred(&pattern);

    client_realm = krb5_principal_get_realm(context, principal);

    ret = krb5_make_principal (context, &pattern.server,
			       client_realm, KRB5_TGS_NAME, client_realm, NULL);
    if (ret)
	krb5_err (context, 1, ret, "krb5_make_principal");
    pattern.client = principal;

    ret = krb5_cc_retrieve_cred (context, ccache, 0, &pattern, &creds);
    krb5_free_principal (context, pattern.server);
    if (ret) {
	if (ret == KRB5_CC_END)
	    return 1;
	krb5_err (context, 1, ret, "krb5_cc_retrieve_cred");
    }

    expired = time(NULL) > creds.times.endtime;

    if (expiration)
	*expiration = creds.times.endtime;

    krb5_free_cred_contents (context, &creds);

    return expired;
}
Пример #11
0
static void
test_alname(krb5_context context, krb5_const_realm realm,
	    const char *user, const char *inst, 
	    const char *localuser, int ok)
{
    krb5_principal p;
    char localname[1024];
    krb5_error_code ret;
    char *princ;

    ret = krb5_make_principal(context, &p, realm, user, inst, NULL);
    if (ret)
	krb5_err(context, 1, ret, "krb5_build_principal");

    ret = krb5_unparse_name(context, p, &princ);
    if (ret)
	krb5_err(context, 1, ret, "krb5_unparse_name");

    ret = krb5_aname_to_localname(context, p, sizeof(localname), localname);
    krb5_free_principal(context, p);
    free(princ);
    if (ret) {
	if (!ok)
	    return;
	krb5_err(context, 1, ret, "krb5_aname_to_localname: %s -> %s", 
		 princ, localuser);
    }

    if (strcmp(localname, localuser) != 0) {
	if (ok)
	    errx(1, "compared failed %s != %s (should have succeded)", 
		 localname, localuser);
    } else {
	if (!ok)
	    errx(1, "compared failed %s == %s (should have failed)", 
		 localname, localuser);
    }
    
}
Пример #12
0
krb5_error_code
_krb5_get_krbtgt(krb5_context context,
		 krb5_ccache  id,
		 krb5_realm realm,
		 krb5_creds **cred)
{
    krb5_error_code ret;
    krb5_creds tmp_cred;

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

    ret = krb5_cc_get_principal(context, id, &tmp_cred.client);
    if (ret)
	return ret;

    ret = krb5_make_principal(context,
			      &tmp_cred.server,
			      realm,
			      KRB5_TGS_NAME,
			      realm,
			      NULL);
    if(ret) {
	krb5_free_principal(context, tmp_cred.client);
	return ret;
    }
    ret = krb5_get_credentials(context,
			       KRB5_GC_CACHED,
			       id,
			       &tmp_cred,
			       cred);
    krb5_free_principal(context, tmp_cred.client);
    krb5_free_principal(context, tmp_cred.server);
    if(ret)
	return ret;
    return 0;
}
Пример #13
0
int
init(struct init_options *opt, int argc, char **argv)
{
    kadm5_ret_t ret;
    int i;
    HDB *db;
    krb5_deltat max_life = 0, max_rlife = 0;

    if (!local_flag) {
	krb5_warnx(context, "init is only available in local (-l) mode");
	return 0;
    }

    if (opt->realm_max_ticket_life_string) {
	if (str2deltat (opt->realm_max_ticket_life_string, &max_life) != 0) {
	    krb5_warnx (context, "unable to parse \"%s\"",
			opt->realm_max_ticket_life_string);
	    return 0;
	}
    }
    if (opt->realm_max_renewable_life_string) {
	if (str2deltat (opt->realm_max_renewable_life_string, &max_rlife) != 0) {
	    krb5_warnx (context, "unable to parse \"%s\"",
			opt->realm_max_renewable_life_string);
	    return 0;
	}
    }

    db = _kadm5_s_get_db(kadm_handle);

    ret = db->hdb_open(context, db, O_RDWR | O_CREAT, 0600);
    if(ret){
	krb5_warn(context, ret, "hdb_open");
	return 0;
    }
    db->hdb_close(context, db);
    for(i = 0; i < argc; i++){
	krb5_principal princ;
	const char *realm = argv[i];

	if (opt->realm_max_ticket_life_string == NULL) {
	    max_life = 0;
	    if(edit_deltat ("Realm max ticket life", &max_life, NULL, 0)) {
		return 0;
	    }
	}
	if (opt->realm_max_renewable_life_string == NULL) {
	    max_rlife = 0;
	    if(edit_deltat("Realm max renewable ticket life", &max_rlife,
			   NULL, 0)) {
		return 0;
	    }
	}

	/* Create `krbtgt/REALM' */
	ret = krb5_make_principal(context, &princ, realm,
				  KRB5_TGS_NAME, realm, NULL);
	if(ret)
	    return 0;

	create_random_entry(princ, max_life, max_rlife, 0);
	krb5_free_principal(context, princ);

	if (opt->bare_flag)
	    continue;

	/* Create `kadmin/changepw' */
	krb5_make_principal(context, &princ, realm,
			    "kadmin", "changepw", NULL);
	/*
	 * The Windows XP (at least) password changing protocol
	 * request the `kadmin/changepw' ticket with `renewable_ok,
	 * renewable, forwardable' and so fails if we disallow
	 * forwardable here.
	 */
	create_random_entry(princ, 5*60, 5*60,
			    KRB5_KDB_DISALLOW_TGT_BASED|
			    KRB5_KDB_PWCHANGE_SERVICE|
			    KRB5_KDB_DISALLOW_POSTDATED|
			    KRB5_KDB_DISALLOW_RENEWABLE|
			    KRB5_KDB_DISALLOW_PROXIABLE|
			    KRB5_KDB_REQUIRES_PRE_AUTH);
	krb5_free_principal(context, princ);

	/* Create `kadmin/admin' */
	krb5_make_principal(context, &princ, realm,
			    "kadmin", "admin", NULL);
	create_random_entry(princ, 60*60, 60*60, KRB5_KDB_REQUIRES_PRE_AUTH);
	krb5_free_principal(context, princ);

	/* Create `changepw/kerberos' (for v4 compat) */
	krb5_make_principal(context, &princ, realm,
			    "changepw", "kerberos", NULL);
	create_random_entry(princ, 60*60, 60*60,
			    KRB5_KDB_DISALLOW_TGT_BASED|
			    KRB5_KDB_PWCHANGE_SERVICE);

	krb5_free_principal(context, princ);

	/* Create `kadmin/hprop' for database propagation */
	krb5_make_principal(context, &princ, realm,
			    "kadmin", "hprop", NULL);
	create_random_entry(princ, 60*60, 60*60,
			    KRB5_KDB_REQUIRES_PRE_AUTH|
			    KRB5_KDB_DISALLOW_TGT_BASED);
	krb5_free_principal(context, princ);

	/* Create `WELLKNOWN/ANONYMOUS' for anonymous as-req */
	krb5_make_principal(context, &princ, realm,
			    KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL);
	create_random_entry(princ, 60*60, 60*60,
			    KRB5_KDB_REQUIRES_PRE_AUTH);
	krb5_free_principal(context, princ);


	/* Create `default' */
	{
	    kadm5_principal_ent_rec ent;
	    int mask = 0;

	    memset (&ent, 0, sizeof(ent));
	    mask |= KADM5_PRINCIPAL;
	    krb5_make_principal(context, &ent.principal, realm,
				"default", NULL);
	    mask |= KADM5_MAX_LIFE;
	    ent.max_life = 24 * 60 * 60;
	    mask |= KADM5_MAX_RLIFE;
	    ent.max_renewable_life = 7 * ent.max_life;
	    ent.attributes = KRB5_KDB_DISALLOW_ALL_TIX;
	    mask |= KADM5_ATTRIBUTES;

	    ret = kadm5_create_principal(kadm_handle, &ent, mask, "");
	    if (ret)
		krb5_err (context, 1, ret, "kadm5_create_principal");

	    krb5_free_principal(context, ent.principal);
	}
    }
    return 0;
}
Пример #14
0
static krb5_error_code
tgs_build_reply(krb5_context context, 
		krb5_kdc_configuration *config,
		KDC_REQ *req, 
		KDC_REQ_BODY *b,
		hdb_entry_ex *krbtgt,
		krb5_enctype krbtgt_etype,
		krb5_ticket *ticket,
		krb5_data *reply,
		const char *from,
		const char **e_text,
		AuthorizationData *auth_data,
		const struct sockaddr *from_addr,
		int datagram_reply)
{
    krb5_error_code ret;
    krb5_principal cp = NULL, sp = NULL;
    krb5_principal client_principal = NULL;
    char *spn = NULL, *cpn = NULL;
    hdb_entry_ex *server = NULL, *client = NULL;
    EncTicketPart *tgt = &ticket->ticket;
    KRB5SignedPathPrincipals *spp = NULL;
    const EncryptionKey *ekey;
    krb5_keyblock sessionkey;
    krb5_kvno kvno;
    krb5_data rspac;
    int cross_realm = 0;

    PrincipalName *s;
    Realm r;
    int nloop = 0;
    EncTicketPart adtkt;
    char opt_str[128];
    int require_signedpath = 0;

    memset(&sessionkey, 0, sizeof(sessionkey));
    memset(&adtkt, 0, sizeof(adtkt));
    krb5_data_zero(&rspac);

    s = b->sname;
    r = b->realm;

    if(b->kdc_options.enc_tkt_in_skey){
	Ticket *t;
	hdb_entry_ex *uu;
	krb5_principal p;
	Key *uukey;
	    
	if(b->additional_tickets == NULL || 
	   b->additional_tickets->len == 0){
	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
	    kdc_log(context, config, 0,
		    "No second ticket present in request");
	    goto out;
	}
	t = &b->additional_tickets->val[0];
	if(!get_krbtgt_realm(&t->sname)){
	    kdc_log(context, config, 0,
		    "Additional ticket is not a ticket-granting ticket");
	    ret = KRB5KDC_ERR_POLICY;
	    goto out;
	}
	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
	ret = _kdc_db_fetch(context, config, p, 
			    HDB_F_GET_CLIENT|HDB_F_GET_SERVER, 
			    NULL, &uu);
	krb5_free_principal(context, p);
	if(ret){
	    if (ret == HDB_ERR_NOENTRY)
		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	    goto out;
	}
	ret = hdb_enctype2key(context, &uu->entry, 
			      t->enc_part.etype, &uukey);
	if(ret){
	    _kdc_free_ent(context, uu);
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}
	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
	_kdc_free_ent(context, uu);
	if(ret)
	    goto out;

	ret = verify_flags(context, config, &adtkt, spn);
	if (ret)
	    goto out;

	s = &adtkt.cname;
	r = adtkt.crealm;
    }

    _krb5_principalname2krb5_principal(context, &sp, *s, r);
    ret = krb5_unparse_name(context, sp, &spn);	
    if (ret)
	goto out;
    _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
    ret = krb5_unparse_name(context, cp, &cpn);
    if (ret)
	goto out;
    unparse_flags (KDCOptions2int(b->kdc_options),
		   asn1_KDCOptions_units(),
		   opt_str, sizeof(opt_str));
    if(*opt_str)
	kdc_log(context, config, 0,
		"TGS-REQ %s from %s for %s [%s]", 
		cpn, from, spn, opt_str);
    else
	kdc_log(context, config, 0,
		"TGS-REQ %s from %s for %s", cpn, from, spn);

    /*
     * Fetch server
     */

server_lookup:
    ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server);

    if(ret){
	const char *new_rlm;
	Realm req_rlm;
	krb5_realm *realms;

	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
	    if(nloop++ < 2) {
		new_rlm = find_rpath(context, tgt->crealm, req_rlm);
		if(new_rlm) {
		    kdc_log(context, config, 5, "krbtgt for realm %s "
			    "not found, trying %s", 
			    req_rlm, new_rlm);
		    krb5_free_principal(context, sp);
		    free(spn);
		    krb5_make_principal(context, &sp, r, 
					KRB5_TGS_NAME, new_rlm, NULL);
		    ret = krb5_unparse_name(context, sp, &spn);	
		    if (ret)
			goto out;
		    goto server_lookup;
		}
	    }
	} else if(need_referral(context, sp, &realms)) {
	    if (strcmp(realms[0], sp->realm) != 0) {
		kdc_log(context, config, 5,
			"Returning a referral to realm %s for "
			"server %s that was not found",
			realms[0], spn);
		krb5_free_principal(context, sp);
		free(spn);
		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
				    realms[0], NULL);
		ret = krb5_unparse_name(context, sp, &spn);
		if (ret)
		    goto out;
		krb5_free_host_realm(context, realms);
		goto server_lookup;
	    }
	    krb5_free_host_realm(context, realms);
	}
	kdc_log(context, config, 0,
		"Server not found in database: %s: %s", spn,
		krb5_get_err_text(context, ret));
	if (ret == HDB_ERR_NOENTRY)
	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	goto out;
    }

    ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client);
    if(ret) {
	const char *krbtgt_realm; 

	/*
	 * If the client belongs to the same realm as our krbtgt, it
	 * should exist in the local database.
	 *
	 */

	krbtgt_realm = 
	    krb5_principal_get_comp_string(context, 
					   krbtgt->entry.principal, 1);

	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
	    if (ret == HDB_ERR_NOENTRY)
		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
	    kdc_log(context, config, 1, "Client no longer in database: %s",
		    cpn);
	    goto out;
	}
	
	kdc_log(context, config, 1, "Client not found in database: %s: %s",
		cpn, krb5_get_err_text(context, ret));

	cross_realm = 1;
    }
    
    /*
     * Check that service is in the same realm as the krbtgt. If its
     * not the same, its someone that is using a uni-directional trust
     * backward.
     */
    
    if (strcmp(krb5_principal_get_realm(context, sp),
	       krb5_principal_get_comp_string(context, 
					      krbtgt->entry.principal, 
					      1)) != 0) {
	char *tpn;
	ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
	kdc_log(context, config, 0,
		"Request with wrong krbtgt: %s",
		(ret == 0) ? tpn : "<unknown>");
	if(ret == 0)
	    free(tpn);
	ret = KRB5KRB_AP_ERR_NOT_US;
	goto out;
    }

    /*
     *
     */

    client_principal = cp;

    if (client) {
	const PA_DATA *sdata;
	int i = 0;

	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
	if (sdata) {
	    krb5_crypto crypto;
	    krb5_data datack;
	    PA_S4U2Self self;
	    char *selfcpn = NULL;
	    const char *str;

	    ret = decode_PA_S4U2Self(sdata->padata_value.data, 
				     sdata->padata_value.length,
				     &self, NULL);
	    if (ret) {
		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
		goto out;
	    }

	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
	    if (ret)
		goto out;

	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
	    if (ret) {
		free_PA_S4U2Self(&self);
		krb5_data_free(&datack);
		kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
			krb5_get_err_text(context, ret));
		goto out;
	    }

	    ret = krb5_verify_checksum(context,
				       crypto,
				       KRB5_KU_OTHER_CKSUM,
				       datack.data, 
				       datack.length, 
				       &self.cksum);
	    krb5_data_free(&datack);
	    krb5_crypto_destroy(context, crypto);
	    if (ret) {
		free_PA_S4U2Self(&self);
		kdc_log(context, config, 0, 
			"krb5_verify_checksum failed for S4U2Self: %s",
			krb5_get_err_text(context, ret));
		goto out;
	    }

	    ret = _krb5_principalname2krb5_principal(context,
						     &client_principal,
						     self.name,
						     self.realm);
	    free_PA_S4U2Self(&self);
	    if (ret)
		goto out;

	    ret = krb5_unparse_name(context, client_principal, &selfcpn);	
	    if (ret)
		goto out;

	    /*
	     * Check that service doing the impersonating is
	     * requesting a ticket to it-self.
	     */
	    if (krb5_principal_compare(context, cp, sp) != TRUE) {
		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
			"to impersonate some other user "
			"(tried for user %s to service %s)",
			cpn, selfcpn, spn);
		free(selfcpn);
		ret = KRB5KDC_ERR_BADOPTION; /* ? */
		goto out;
	    }

	    /*
	     * If the service isn't trusted for authentication to
	     * delegation, remove the forward flag.
	     */

	    if (client->entry.flags.trusted_for_delegation) {
		str = "[forwardable]";
	    } else {
		b->kdc_options.forwardable = 0;
		str = "";
	    }
	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
		    "service %s %s", cpn, selfcpn, spn, str);
	    free(selfcpn);
	}
    }

    /*
     * Constrained delegation
     */

    if (client != NULL
	&& b->additional_tickets != NULL
	&& b->additional_tickets->len != 0
	&& b->kdc_options.enc_tkt_in_skey == 0)
    {
	Key *clientkey;
	Ticket *t;
	char *str;

	t = &b->additional_tickets->val[0];

	ret = hdb_enctype2key(context, &client->entry, 
			      t->enc_part.etype, &clientkey);
	if(ret){
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}

	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
	if (ret) {
	    kdc_log(context, config, 0,
		    "failed to decrypt ticket for "
		    "constrained delegation from %s to %s ", spn, cpn);
	    goto out;
	}

	/* check that ticket is valid */

	if (adtkt.flags.forwardable == 0) {
	    kdc_log(context, config, 0,
		    "Missing forwardable flag on ticket for "
		    "constrained delegation from %s to %s ", spn, cpn);
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}

	ret = check_constrained_delegation(context, config, client, sp);
	if (ret) {
	    kdc_log(context, config, 0,
		    "constrained delegation from %s to %s not allowed", 
		    spn, cpn);
	    goto out;
	}

	ret = _krb5_principalname2krb5_principal(context,
						 &client_principal,
						 adtkt.cname,
						 adtkt.crealm);
	if (ret)
	    goto out;

	ret = krb5_unparse_name(context, client_principal, &str);
	if (ret)
	    goto out;

	ret = verify_flags(context, config, &adtkt, str);
	if (ret) {
	    free(str);
	    goto out;
	}

	/*
	 * Check KRB5SignedPath in authorization data and add new entry to
	 * make sure servers can't fake a ticket to us.
	 */

	ret = check_KRB5SignedPath(context,
				   config,
				   krbtgt,
				   &adtkt,
				   &spp,
				   1);
	if (ret) {
	    kdc_log(context, config, 0,
		    "KRB5SignedPath check from service %s failed "
		    "for delegation to %s for client %s "
		    "from %s failed with %s",
		    spn, str, cpn, from, krb5_get_err_text(context, ret));
	    free(str);
	    goto out;
	}

	kdc_log(context, config, 0, "constrained delegation for %s "
		"from %s to %s", str, cpn, spn);
	free(str);

	/* 
	 * Also require that the KDC have issue the service's krbtgt
	 * used to do the request. 
	 */
	require_signedpath = 1;
    }

    /*
     * Check flags
     */

    ret = _kdc_check_flags(context, config, 
			   client, cpn,
			   server, spn,
			   FALSE);
    if(ret)
	goto out;

    if((b->kdc_options.validate || b->kdc_options.renew) && 
       !krb5_principal_compare(context, 
			       krbtgt->entry.principal,
			       server->entry.principal)){
	kdc_log(context, config, 0, "Inconsistent request.");
	ret = KRB5KDC_ERR_SERVER_NOMATCH;
	goto out;
    }

    /* check for valid set of addresses */
    if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
	ret = KRB5KRB_AP_ERR_BADADDR;
	kdc_log(context, config, 0, "Request from wrong address");
	goto out;
    }
	
    /*
     * Select enctype, return key and kvno.
     */

    {
	krb5_enctype etype;

	if(b->kdc_options.enc_tkt_in_skey) {
	    int i;
	    ekey = &adtkt.key;
	    for(i = 0; i < b->etype.len; i++)
		if (b->etype.val[i] == adtkt.key.keytype)
		    break;
	    if(i == b->etype.len) {
		krb5_clear_error_string(context);
		return KRB5KDC_ERR_ETYPE_NOSUPP;
	    }
	    etype = b->etype.val[i];
	    kvno = 0;
	} else {
	    Key *skey;
	    
	    ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
				  &skey, &etype);
	    if(ret) {
		kdc_log(context, config, 0, 
			"Server (%s) has no support for etypes", spp);
		return ret;
	    }
	    ekey = &skey->key;
	    kvno = server->entry.kvno;
	}
	
	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
	if (ret)
	    goto out;
    }

    /* check PAC if not cross realm and if there is one */
    if (!cross_realm) {
	Key *tkey;

	ret = hdb_enctype2key(context, &krbtgt->entry, 
			      krbtgt_etype, &tkey);
	if(ret) {
	    kdc_log(context, config, 0,
		    "Failed to find key for krbtgt PAC check");
	    goto out;
	}

	ret = check_PAC(context, config, client_principal, 
			client, server, ekey, &tkey->key,
			tgt, &rspac, &require_signedpath);
	if (ret) {
	    kdc_log(context, config, 0,
		    "Verify PAC failed for %s (%s) from %s with %s",
		    spn, cpn, from, krb5_get_err_text(context, ret));
	    goto out;
	}
    }

    /* also check the krbtgt for signature */
    ret = check_KRB5SignedPath(context,
			       config,
			       krbtgt,
			       tgt,
			       &spp,
			       require_signedpath);
    if (ret) {
	kdc_log(context, config, 0,
		"KRB5SignedPath check failed for %s (%s) from %s with %s",
		spn, cpn, from, krb5_get_err_text(context, ret));
	goto out;
    }

    /*
     *
     */

    ret = tgs_make_reply(context,
			 config, 
			 b, 
			 client_principal,
			 tgt, 
			 ekey,
			 &sessionkey,
			 kvno,
			 auth_data,
			 server, 
			 spn,
			 client, 
			 cp, 
			 krbtgt, 
			 krbtgt_etype,
			 spp,
			 &rspac,
			 e_text,
			 reply);
	
out:
    free(spn);
    free(cpn);
	    
    krb5_data_free(&rspac);
    krb5_free_keyblock_contents(context, &sessionkey);
    if(server)
	_kdc_free_ent(context, server);
    if(client)
	_kdc_free_ent(context, client);

    if (client_principal && client_principal != cp)
	krb5_free_principal(context, client_principal);
    if (cp)
	krb5_free_principal(context, cp);
    if (sp)
	krb5_free_principal(context, sp);

    free_EncTicketPart(&adtkt);

    return ret;
}
Пример #15
0
static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
				 struct kdc_check_generic_kerberos *r)
{
	struct PAC_Validate pac_validate;
	DATA_BLOB srv_sig;
	struct PAC_SIGNATURE_DATA kdc_sig;
	struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server);
	krb5_kdc_configuration *kdc_config =
		(krb5_kdc_configuration *)kdc->private_data;
	enum ndr_err_code ndr_err;
	int ret;
	hdb_entry_ex ent;
	krb5_principal principal;


	/* There is no reply to this request */
	r->out.generic_reply = data_blob(NULL, 0);

	ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, &pac_validate,
				       (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (pac_validate.MessageType != NETLOGON_GENERIC_KRB5_PAC_VALIDATE) {
		/* We don't implement any other message types - such as certificate validation - yet */
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength)
	    || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength
	    || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
				  pac_validate.ChecksumLength);

	ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal,
				  lpcfg_realm(kdc->task->lp_ctx),
				  "krbtgt", lpcfg_realm(kdc->task->lp_ctx),
				  NULL);

	if (ret != 0) {
		return NT_STATUS_NO_MEMORY;
	}

	ret = kdc_config->db[0]->hdb_fetch_kvno(kdc->smb_krb5_context->krb5_context,
						 kdc_config->db[0],
						 principal,
						 HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
						 0,
						 &ent);

	if (ret != 0) {
		hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
		krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);

		return NT_STATUS_LOGON_FAILURE;
	}

	kdc_sig.type = pac_validate.SignatureType;
	kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
					    pac_validate.SignatureLength);

	ret = kdc_check_pac(kdc->smb_krb5_context->krb5_context, srv_sig, &kdc_sig, &ent);

	hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
	krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);

	if (ret != 0) {
		return NT_STATUS_LOGON_FAILURE;
	}

	return NT_STATUS_OK;
}
Пример #16
0
static int
proto (int sock, const char *hostname, const char *service)
{
    struct sockaddr_in remote, local;
    socklen_t addrlen;
    krb5_address remote_addr, local_addr;
    krb5_context context;
    krb5_ccache ccache;
    krb5_auth_context auth_context;
    krb5_error_code status;
    krb5_principal client;
    krb5_data data;
    krb5_data packet;
    krb5_creds mcred, cred;
    krb5_ticket *ticket;

    addrlen = sizeof(local);
    if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
	|| addrlen != sizeof(local))
	err (1, "getsockname(%s)", hostname);

    addrlen = sizeof(remote);
    if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
	|| addrlen != sizeof(remote))
	err (1, "getpeername(%s)", hostname);

    status = krb5_init_context(&context);
    if (status)
	errx(1, "krb5_init_context failed: %d", status);

    status = krb5_cc_default (context, &ccache);
    if (status)
	krb5_err(context, 1, status, "krb5_cc_default");

    status = krb5_auth_con_init (context, &auth_context);
    if (status)
	krb5_err(context, 1, status, "krb5_auth_con_init");

    local_addr.addr_type = AF_INET;
    local_addr.address.length = sizeof(local.sin_addr);
    local_addr.address.data   = &local.sin_addr;

    remote_addr.addr_type = AF_INET;
    remote_addr.address.length = sizeof(remote.sin_addr);
    remote_addr.address.data   = &remote.sin_addr;

    status = krb5_auth_con_setaddrs (context,
				     auth_context,
				     &local_addr,
				     &remote_addr);
    if (status)
	krb5_err(context, 1, status, "krb5_auth_con_setaddr");

    krb5_cc_clear_mcred(&mcred);

    status = krb5_cc_get_principal(context, ccache, &client);
    if(status)
	krb5_err(context, 1, status, "krb5_cc_get_principal");
    status = krb5_make_principal(context, &mcred.server,
				 krb5_principal_get_realm(context, client),
				 "krbtgt",
				 krb5_principal_get_realm(context, client),
				 NULL);
    if(status)
	krb5_err(context, 1, status, "krb5_make_principal");
    mcred.client = client;

    status = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
    if(status)
	krb5_err(context, 1, status, "krb5_cc_retrieve_cred");

    {
	char *client_name;
	krb5_data data;
	status = krb5_unparse_name(context, cred.client, &client_name);
	if(status)
	    krb5_err(context, 1, status, "krb5_unparse_name");
	data.data = client_name;
	data.length = strlen(client_name) + 1;
	status = krb5_write_message(context, &sock, &data);
	if(status)
	    krb5_err(context, 1, status, "krb5_write_message");
	free(client_name);
    }

    status = krb5_write_message(context, &sock, &cred.ticket);
    if(status)
	krb5_err(context, 1, status, "krb5_write_message");

    status = krb5_auth_con_setuserkey(context, auth_context, &cred.session);
    if(status)
	krb5_err(context, 1, status, "krb5_auth_con_setuserkey");

    status = krb5_recvauth(context, &auth_context, &sock,
			   VERSION, client, 0, NULL, &ticket);

    if (status)
	krb5_err(context, 1, status, "krb5_recvauth");

    if (ticket->ticket.authorization_data) {
	AuthorizationData *authz;
	int i;

	printf("Authorization data:\n");

	authz = ticket->ticket.authorization_data;
	for (i = 0; i < authz->len; i++) {
	    printf("\ttype %d, length %lu\n",
		   authz->val[i].ad_type,
		   (unsigned long)authz->val[i].ad_data.length);
	}
    }

    data.data   = "hej";
    data.length = 3;

    krb5_data_zero (&packet);

    status = krb5_mk_safe (context,
			   auth_context,
			   &data,
			   &packet,
			   NULL);
    if (status)
	krb5_err(context, 1, status, "krb5_mk_safe");

    status = krb5_write_message(context, &sock, &packet);
    if(status)
	krb5_err(context, 1, status, "krb5_write_message");

    data.data   = "hemligt";
    data.length = 7;

    krb5_data_free (&packet);

    status = krb5_mk_priv (context,
			   auth_context,
			   &data,
			   &packet,
			   NULL);
    if (status)
	krb5_err(context, 1, status, "krb5_mk_priv");

    status = krb5_write_message(context, &sock, &packet);
    if(status)
	krb5_err(context, 1, status, "krb5_write_message");
    return 0;
}
Пример #17
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_auth_context ac = NULL;
    krb5_principal c1, c2;
    krb5_authenticator authent;
    krb5_keytab keytab;
    krb5_socket_t sock = rk_INVALID_SOCKET;
    HDB *db = NULL;
    int optidx = 0;
    char *tmp_db;
    krb5_log_facility *fac;
    int nprincs;

    setprogname(argv[0]);

    ret = krb5_init_context(&context);
    if(ret)
	exit(1);

    ret = krb5_openlog(context, "hpropd", &fac);
    if(ret)
	errx(1, "krb5_openlog");
    krb5_set_warn_dest(context, fac);

    if(getarg(args, num_args, argc, argv, &optidx))
	usage(1);

    if(local_realm != NULL)
	krb5_set_default_realm(context, local_realm);

    if(help_flag)
	usage(0);
    if(version_flag) {
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    if (argc != 0)
	usage(1);

    if (database == NULL)
	database = hdb_default_db(context);

    if(from_stdin) {
	sock = STDIN_FILENO;
    } else {
	struct sockaddr_storage ss;
	struct sockaddr *sa = (struct sockaddr *)&ss;
	socklen_t sin_len = sizeof(ss);
	char addr_name[256];
	krb5_ticket *ticket;
	char *server;

	sock = STDIN_FILENO;
#ifdef SUPPORT_INETD
	if (inetd_flag == -1) {
	    if (getpeername (sock, sa, &sin_len) < 0) {
		inetd_flag = 0;
	    } else {
		inetd_flag = 1;
	    }
	}
#else
	inetd_flag = 0;
#endif
	if (!inetd_flag) {
	    mini_inetd (krb5_getportbyname (context, "hprop", "tcp",
					    HPROP_PORT), &sock);
	}
	sin_len = sizeof(ss);
	if(getpeername(sock, sa, &sin_len) < 0)
	    krb5_err(context, 1, errno, "getpeername");

	if (inet_ntop(sa->sa_family,
		      socket_get_address (sa),
		      addr_name,
		      sizeof(addr_name)) == NULL)
	    strlcpy (addr_name, "unknown address",
		     sizeof(addr_name));

	krb5_log(context, fac, 0, "Connection from %s", addr_name);

	ret = krb5_kt_register(context, &hdb_kt_ops);
	if(ret)
	    krb5_err(context, 1, ret, "krb5_kt_register");

	if (ktname != NULL) {
	    ret = krb5_kt_resolve(context, ktname, &keytab);
	    if (ret)
		krb5_err (context, 1, ret, "krb5_kt_resolve %s", ktname);
	} else {
	    ret = krb5_kt_default (context, &keytab);
	    if (ret)
		krb5_err (context, 1, ret, "krb5_kt_default");
	}

	ret = krb5_recvauth(context, &ac, &sock, HPROP_VERSION, NULL,
			    0, keytab, &ticket);
	if(ret)
	    krb5_err(context, 1, ret, "krb5_recvauth");

	ret = krb5_unparse_name(context, ticket->server, &server);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_unparse_name");
	if (strncmp(server, "hprop/", 5) != 0)
	    krb5_errx(context, 1, "ticket not for hprop (%s)", server);

	free(server);
	krb5_free_ticket (context, ticket);

	ret = krb5_auth_con_getauthenticator(context, ac, &authent);
	if(ret)
	    krb5_err(context, 1, ret, "krb5_auth_con_getauthenticator");

	ret = krb5_make_principal(context, &c1, NULL, "kadmin", "hprop", NULL);
	if(ret)
	    krb5_err(context, 1, ret, "krb5_make_principal");
	_krb5_principalname2krb5_principal(context, &c2,
					   authent->cname, authent->crealm);
	if(!krb5_principal_compare(context, c1, c2)) {
	    char *s;
	    ret = krb5_unparse_name(context, c2, &s);
	    if (ret)
		s = unparseable_name;
	    krb5_errx(context, 1, "Unauthorized connection from %s", s);
	}
	krb5_free_principal(context, c1);
	krb5_free_principal(context, c2);

	ret = krb5_kt_close(context, keytab);
	if(ret)
	    krb5_err(context, 1, ret, "krb5_kt_close");
    }

    if(!print_dump) {
	asprintf(&tmp_db, "%s~", database);

	ret = hdb_create(context, &db, tmp_db);
	if(ret)
	    krb5_err(context, 1, ret, "hdb_create(%s)", tmp_db);
	ret = db->hdb_open(context, db, O_RDWR | O_CREAT | O_TRUNC, 0600);
	if(ret)
	    krb5_err(context, 1, ret, "hdb_open(%s)", tmp_db);
    }

    nprincs = 0;
    while(1){
	krb5_data data;
	hdb_entry_ex entry;

	if(from_stdin) {
	    ret = krb5_read_message(context, &sock, &data);
	    if(ret != 0 && ret != HEIM_ERR_EOF)
		krb5_err(context, 1, ret, "krb5_read_message");
	} else {
	    ret = krb5_read_priv_message(context, ac, &sock, &data);
	    if(ret)
		krb5_err(context, 1, ret, "krb5_read_priv_message");
	}

	if(ret == HEIM_ERR_EOF || data.length == 0) {
	    if(!from_stdin) {
		data.data = NULL;
		data.length = 0;
		krb5_write_priv_message(context, ac, &sock, &data);
	    }
	    if(!print_dump) {
		ret = db->hdb_close(context, db);
		if(ret)
		    krb5_err(context, 1, ret, "db_close");
		ret = db->hdb_rename(context, db, database);
		if(ret)
		    krb5_err(context, 1, ret, "db_rename");
	    }
	    break;
	}
	memset(&entry, 0, sizeof(entry));
	ret = hdb_value2entry(context, &data, &entry.entry);
	krb5_data_free(&data);
	if(ret)
	    krb5_err(context, 1, ret, "hdb_value2entry");
	if(print_dump)
	    hdb_print_entry(context, db, &entry, stdout);
	else {
	    ret = db->hdb_store(context, db, 0, &entry);
	    if(ret == HDB_ERR_EXISTS) {
		char *s;
		ret = krb5_unparse_name(context, entry.entry.principal, &s);
		if (ret)
		    s = strdup(unparseable_name);
		krb5_warnx(context, "Entry exists: %s", s);
		free(s);
	    } else if(ret)
		krb5_err(context, 1, ret, "db_store");
	    else
		nprincs++;
	}
	hdb_free_entry(context, &entry);
    }
    if (!print_dump)
	krb5_log(context, fac, 0, "Received %d principals", nprincs);

    if (inetd_flag == 0)
	rk_closesocket(sock);

    exit(0);
}
Пример #18
0
Файл: su.c Проект: Sp1l/heimdal
static int
krb5_verify(const struct passwd *login_info,
	    const struct passwd *su_info,
	    const char *instance)
{
    krb5_error_code ret;
    krb5_principal p;
    krb5_realm *realms, *r;
    char *login_name = NULL;
    int user_ok = 0;

#if defined(HAVE_GETLOGIN) && !defined(POSIX_GETLOGIN)
    login_name = getlogin();
#endif
    ret = krb5_init_context (&context);
    if (ret) {
#if 0
	warnx("krb5_init_context failed: %d", ret);
#endif
	return 1;
    }

    ret = krb5_get_default_realms(context, &realms);
    if (ret)
	return 1;

    /* Check all local realms */
    for (r = realms; *r != NULL && !user_ok; r++) {

	if (login_name == NULL || strcmp (login_name, "root") == 0)
	    login_name = login_info->pw_name;
	if (strcmp (su_info->pw_name, "root") == 0)
	    ret = krb5_make_principal(context, &p, *r,
				      login_name,
				      instance,
				      NULL);
	else
	    ret = krb5_make_principal(context, &p, *r,
				      su_info->pw_name,
				      NULL);
	if (ret) {
	    krb5_free_host_realm(context, realms);
	    return 1;
	}

	/* if we are su-ing too root, check with krb5_kuserok */
	if (su_info->pw_uid == 0 && !krb5_kuserok(context, p, su_info->pw_name))
	    continue;

	ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
	if(ret) {
	    krb5_free_host_realm(context, realms);
	    krb5_free_principal (context, p);
	    return 1;
	}
  	ret = krb5_verify_user(context, p, ccache, NULL, TRUE, NULL);
	krb5_free_principal (context, p);
	switch (ret) {
	case 0:
	    user_ok = 1;
	    break;
	case KRB5_LIBOS_PWDINTR :
	    krb5_cc_destroy(context, ccache);
	    break;
	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
	case KRB5KRB_AP_ERR_MODIFIED:
	    krb5_cc_destroy(context, ccache);
	    krb5_warnx(context, "Password incorrect");
	    break;
	default :
	    krb5_cc_destroy(context, ccache);
	    krb5_warn(context, ret, "krb5_verify_user");
	    break;
	}
    }
    krb5_free_host_realm(context, realms);
    if (!user_ok)
	return 1;
    return 0;
}
Пример #19
0
static krb5_error_code
get_cred_kdc_capath_worker(krb5_context context,
                           krb5_kdc_flags flags,
                           krb5_ccache ccache,
                           krb5_creds *in_creds,
                           krb5_const_realm try_realm,
                           krb5_principal impersonate_principal,
                           Ticket *second_ticket,			
                           krb5_creds **out_creds,
                           krb5_creds ***ret_tgts)
{
    krb5_error_code ret;
    krb5_creds *tgt, tmp_creds;
    krb5_const_realm client_realm, server_realm;
    int ok_as_delegate = 1;

    *out_creds = NULL;

    client_realm = krb5_principal_get_realm(context, in_creds->client);
    server_realm = krb5_principal_get_realm(context, in_creds->server);
    memset(&tmp_creds, 0, sizeof(tmp_creds));
    ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client);
    if(ret)
	return ret;

    ret = krb5_make_principal(context,
			      &tmp_creds.server,
			      try_realm,
			      KRB5_TGS_NAME,
			      server_realm,
			      NULL);
    if(ret){
	krb5_free_principal(context, tmp_creds.client);
	return ret;
    }
    {
	krb5_creds tgts;

	ret = find_cred(context, ccache, tmp_creds.server,
			*ret_tgts, &tgts);
	if(ret == 0){
	    if (strcmp(try_realm, client_realm) != 0)
		ok_as_delegate = tgts.flags.b.ok_as_delegate;

	    *out_creds = calloc(1, sizeof(**out_creds));
	    if(*out_creds == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context, ret,
				       N_("malloc: out of memory", ""));
	    } else {
		ret = get_cred_kdc_address(context, ccache, flags, NULL,
					   in_creds, &tgts,
					   impersonate_principal,
					   second_ticket,
					   *out_creds);
		if (ret) {
		    free (*out_creds);
		    *out_creds = NULL;
		} else if (ok_as_delegate == 0)
		    (*out_creds)->flags.b.ok_as_delegate = 0;
	    }
	    krb5_free_cred_contents(context, &tgts);
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
    }
    if(krb5_realm_compare(context, in_creds->client, in_creds->server))
	return not_found(context, in_creds->server, KRB5_CC_NOTFOUND);

    /* XXX this can loop forever */
    while(1){
	heim_general_string tgt_inst;

	ret = get_cred_kdc_capath(context, flags, ccache, &tmp_creds,
				  NULL, NULL, &tgt, ret_tgts);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
	/* 
	 * if either of the chain or the ok_as_delegate was stripped
	 * by the kdc, make sure we strip it too.
	 */
	if (ok_as_delegate == 0 || tgt->flags.b.ok_as_delegate == 0) {
	    ok_as_delegate = 0;
	    tgt->flags.b.ok_as_delegate = 0;
	}

	ret = add_cred(context, tgt, ret_tgts);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
	tgt_inst = tgt->server->name.name_string.val[1];
	if(strcmp(tgt_inst, server_realm) == 0)
	    break;
	krb5_free_principal(context, tmp_creds.server);
	ret = krb5_make_principal(context, &tmp_creds.server,
				  tgt_inst, KRB5_TGS_NAME, server_realm, NULL);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
	ret = krb5_free_creds(context, tgt);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
    }
	
    krb5_free_principal(context, tmp_creds.server);
    krb5_free_principal(context, tmp_creds.client);
    *out_creds = calloc(1, sizeof(**out_creds));
    if(*out_creds == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
    } else {
	ret = get_cred_kdc_address (context, ccache, flags, NULL,
				    in_creds, tgt, impersonate_principal,
				    second_ticket, *out_creds);
	if (ret) {
	    free (*out_creds);
	    *out_creds = NULL;
	}
    }
    krb5_free_creds(context, tgt);
    return ret;
}                           
Пример #20
0
krb5_error_code
_kadm5_c_get_cred_cache(krb5_context context,
			const char *client_name,
			const char *server_name,
			const char *password,
			krb5_prompter_fct prompter,
			const char *keytab,
			krb5_ccache ccache,
			krb5_ccache *ret_cache)
{
    krb5_error_code ret;
    krb5_ccache id = NULL;
    krb5_principal default_client = NULL, client = NULL;

    /* treat empty password as NULL */
    if(password && *password == '\0')
	password = NULL;
    if(server_name == NULL)
	server_name = KADM5_ADMIN_SERVICE;

    if(client_name != NULL) {
	ret = krb5_parse_name(context, client_name, &client);
	if(ret)
	    return ret;
    }

    if(ccache != NULL) {
	id = ccache;
	ret = krb5_cc_get_principal(context, id, &client);
	if(ret)
	    return ret;
    } else {
	/* get principal from default cache, ok if this doesn't work */

	ret = get_cache_principal(context, &id, &default_client);
	if (ret) {
	    /*
	     * No client was specified by the caller and we cannot
	     * determine the client from a credentials cache.
	     */
	    const char *user;

	    user = get_default_username ();

	    if(user == NULL) {
		krb5_set_error_message(context, KADM5_FAILURE, "Unable to find local user name");
		return KADM5_FAILURE;
	    }
	    ret = krb5_make_principal(context, &default_client,
				      NULL, user, "admin", NULL);
	    if(ret)
		return ret;
	}
    }


    /*
     * No client was specified by the caller, but we have a client
     * from the default credentials cache.
     */
    if (client == NULL && default_client != NULL)
	client = default_client;


    if(id && client && (default_client == NULL ||
	      krb5_principal_compare(context, client, default_client) != 0)) {
	ret = get_kadm_ticket(context, id, client, server_name);
	if(ret == 0) {
	    *ret_cache = id;
	    krb5_free_principal(context, default_client);
	    if (default_client != client)
		krb5_free_principal(context, client);
	    return 0;
	}
	if(ccache != NULL)
	    /* couldn't get ticket from cache */
	    return -1;
    }
    /* get creds via AS request */
    if(id && (id != ccache))
	krb5_cc_close(context, id);
    if (client != default_client)
	krb5_free_principal(context, default_client);

    ret = get_new_cache(context, client, password, prompter, keytab,
			server_name, ret_cache);
    krb5_free_principal(context, client);
    return ret;
}
Пример #21
0
static krb5_error_code
get_cache_principal(krb5_context context,
		    krb5_ccache *id,
		    krb5_principal *client)
{
    krb5_error_code ret;
    const char *name, *inst;
    krb5_principal p1, p2;

    ret = krb5_cc_default(context, id);
    if(ret) {
	*id = NULL;
	return ret;
    }

    ret = krb5_cc_get_principal(context, *id, &p1);
    if(ret) {
	krb5_cc_close(context, *id);
	*id = NULL;
	return ret;
    }

    ret = krb5_make_principal(context, &p2, NULL,
			      "kadmin", "admin", NULL);
    if (ret) {
	krb5_cc_close(context, *id);
	*id = NULL;
	krb5_free_principal(context, p1);
	return ret;
    }

    {
	krb5_creds in, *out;
	krb5_kdc_flags flags;

	flags.i = 0;
	memset(&in, 0, sizeof(in));

	in.client = p1;
	in.server = p2;

	/* check for initial ticket kadmin/admin */
	ret = krb5_get_credentials_with_flags(context, KRB5_GC_CACHED, flags,
					      *id, &in, &out);
	krb5_free_principal(context, p2);
	if (ret == 0) {
	    if (out->flags.b.initial) {
		*client = p1;
		krb5_free_creds(context, out);
		return 0;
	    }
	    krb5_free_creds(context, out);
	}
    }
    krb5_cc_close(context, *id);
    *id = NULL;

    name = krb5_principal_get_comp_string(context, p1, 0);
    inst = krb5_principal_get_comp_string(context, p1, 1);
    if(inst == NULL || strcmp(inst, "admin") != 0) {
	ret = krb5_make_principal(context, &p2, NULL, name, "admin", NULL);
	krb5_free_principal(context, p1);
	if(ret != 0)
	    return ret;

	*client = p2;
	return 0;
    }

    *client = p1;

    return 0;
}
Пример #22
0
/*
 * Store the given private key (key) and certificate (cert)
 * into the Kerberos 5 credentials cache.  The "lifetime"
 * of the certificate is also given in notBefore, and notAfter.
 */
int store_in_cc(RSA *key,
	BYTE 			*cert,
	DWORD 			cert_length,
	char 			*realm,
	ASN1_UTCTIME 		*notBefore,
	ASN1_UTCTIME 		*notAfter,
#if defined(KX509_LIB)
	char			*tkt_cache_name,
#endif
	char 			**err_msg)
{
	krb5_context		k5_context;
	krb5_ccache		cc;
	krb5_creds		fake_creds;
	DWORD			key_length;
	krb5_error_code		k5_rc		= 0;
	int			retcode		= KX509_STATUS_GOOD;
	BYTE			*ptr 		= NULL;
	BYTE			*memptr 	= NULL;


	/*
	 * Use fake_creds.ticket for private key and
	 * fake_creds.second_ticket for certificate
	 */

	memset(&fake_creds, '\0', sizeof(fake_creds));

	if (k5_rc = krb5_init_context(&k5_context))
	{
		log_printf("store_in_cc: unable to initialize Kerberos 5 context (%d)\n", k5_rc);
		*err_msg = "Error initializing kerberos 5 environment."; 
		return KX509_STATUS_CLNT_FIX;
	}

#if 0	/* DON'T NEED THIS, and it is a private function anyway... */
	if (k5_rc = krb5_set_default_realm(k5_context, realm))
	{
		log_printf("store_in_cc: failed to malloc space for k5 default_realm\n");
		*err_msg = "Try re-authenticating.  "
				"Hopefully temporary client-side problem";
		return KX509_STATUS_CLNT_FIX;
	}
#endif

#if defined(KX509_LIB)
	if (k5_rc = krb5_cc_resolve(k5_context, tkt_cache_name, &cc))
	{
		log_printf("store_in_cc: failed to resolve credential cache (%d)\n", k5_rc);
		*err_msg = "Try re-authenticating.  "
			"Could not resolve your credential cache name.";
		return KX509_STATUS_CLNT_FIX;
	}
#else
	if (k5_rc = krb5_cc_default(k5_context, &cc))
	{
		log_printf("store_in_cc: failed to resolve credential cache (%d)\n", k5_rc);
		*err_msg = "Try re-authenticating.  "
				"Could not resolve your credential cache name.";
		return KX509_STATUS_CLNT_FIX;
	}
#endif

#if defined(HAVE_HEIMDAL)
	if (k5_rc = krb5_make_principal(k5_context, &fake_creds.server,
						    realm,
						    KX509_CC_PRINCIPAL,
						    KX509_CC_INSTANCE,
						    NULL))
#else
	if (k5_rc = krb5_sname_to_principal(k5_context, KX509_CC_INSTANCE,
							KX509_CC_PRINCIPAL,
							KRB5_NT_UNKNOWN,
							&fake_creds.server))
#endif
	{
		log_printf("store_in_cc: unable to create server principal from sname (%d)\n",
				k5_rc);
		*err_msg = "Internal error with kerberos while creating fake server principal.";
		retcode = KX509_STATUS_CLNT_FIX;
		goto close_and_return;
	}

#if defined(CC_REMOVE_IMPLEMENTED)
	/*
	 * We really want to clear out any old private key/certificate entries
	 * from the credentials cache.  However, the function to do that is
	 * not defined...
	 */
	if (k5_rc = kx509_clear_old_certificates(k5_context, cc, fake_creds))
	{
		log_printf("store_in_cc: couldn't clear out old certificate "
			"from cred cache (%d)\n", k5_rc);
		*err_msg = "Error removing old certificate from your kerberos credentials cache.";
		retcode = KX509_STATUS_CLNT_FIX;
		goto close_and_return;
	}
#endif	/* CC_REMOVE_IMPLEMENTED */

	if (k5_rc = krb5_cc_get_principal(k5_context, cc, &fake_creds.client))
	{
		log_printf("store_in_cc: unable to create client principal from sname (%d)\n",
				k5_rc);
		*err_msg = "Internal error with kerberos while creating fake client principal.";
		retcode = KX509_STATUS_CLNT_FIX;
		goto close_and_return;
	}

	/*
	 * Get the DER-encoded length of the private key.
	 * Allocate storage to hold the private key and certificate.
	 */

	key_length = i2d_RSAPrivateKey(key, NULL);	/* Get DER-encoded len of Private Key */
	if (key_length <= 0)
	{
		log_printf("store_in_cc: unable to determine length of "
			"encoded private key (%d)\n", key_length);
		*err_msg = "Error determining encoded length of private key.";
		retcode = KX509_STATUS_CLNT_FIX;
		goto close_and_return;
	}

	ptr = Malloc(key_length + cert_length);
	if (!ptr)
	{
		log_printf("store_in_cc: error allocating %d bytes for "
			"private key (%d) and certificate (%d)\n", 
			key_length+cert_length, key_length, cert_length);
		*err_msg = "Error allocating storage for private key and certificate.";
		retcode = KX509_STATUS_CLNT_FIX;
		goto close_and_return;
	}

	memptr = ptr;	/* Save a ptr to the allocated area for later when we free it */

	fake_creds.ticket.data = (char *)ptr; 
	fake_creds.ticket.length = i2d_RSAPrivateKey(key, &ptr);

	/* Note that i2d_RSAPrivateKey() updates ptr!!! */
	memcpy(ptr, cert, cert_length);
	fake_creds.second_ticket.data = (char *)ptr;
	fake_creds.second_ticket.length = cert_length;

	/* Set up the ticket lifetime according to the certificate lifetime */
	fake_creds.times.starttime = utc2unix(notBefore, NULL);
	fake_creds.times.endtime = utc2unix(notAfter, NULL);

	/*
	 * Store the fake ticket (containing the private key
	 * and certificate) into the credentials cache.
	 */ 

#if defined(WRITE_CERT)
	/* Write the key-pair and certificate to file (code lifted from kxlist -p) */
	if (k5_rc = materialize_cert(k5_context, cc, &fake_creds))
#else	/* WRITE_CERT */
	/* Store the key-pair and certificate into the K5 credentials cache as a mock ticket */
	if (k5_rc = krb5_cc_store_cred(k5_context, cc, &fake_creds))
#endif	/* WRITE_CERT */
	{
		log_printf("store_in_cc: krb5_cc_store_cred returned %0d\n", k5_rc);
		*err_msg = "Try re-authenticating.  "
			"Currently unable to write your Kerberos credentials cache.";
		retcode = KX509_STATUS_CLNT_FIX;
		goto close_and_return;
	}

close_and_return:

	if (memptr)
	{
		Free(memptr);
		memptr = NULL;
	}

	krb5_cc_close(k5_context, cc);	/* ignore return code from close */

	return(retcode);
}
Пример #23
0
static OM_uint32 acquire_initiator_cred
		  (OM_uint32 * minor_status,
		   const gss_name_t desired_name,
		   OM_uint32 time_req,
		   const gss_OID_set desired_mechs,
		   gss_cred_usage_t cred_usage,
		   gss_cred_id_t handle,
		   gss_OID_set * actual_mechs,
		   OM_uint32 * time_rec
		  )
{
    OM_uint32 ret;
    krb5_creds cred;
    krb5_principal def_princ;
    krb5_get_init_creds_opt *opt;
    krb5_ccache ccache;
    krb5_keytab keytab;
    krb5_error_code kret;

    keytab = NULL;
    ccache = NULL;
    def_princ = NULL;
    ret = GSS_S_FAILURE;
    memset(&cred, 0, sizeof(cred));

    kret = krb5_cc_default(gssapi_krb5_context, &ccache);
    if (kret)
	goto end;
    kret = krb5_cc_get_principal(gssapi_krb5_context, ccache,
	&def_princ);
    if (kret != 0) {
	/* we'll try to use a keytab below */
	krb5_cc_destroy(gssapi_krb5_context, ccache);
	ccache = NULL;
	kret = 0;
    } else if (handle->principal == NULL)  {
	kret = krb5_copy_principal(gssapi_krb5_context, def_princ,
	    &handle->principal);
	if (kret)
	    goto end;
    } else if (handle->principal != NULL &&
	krb5_principal_compare(gssapi_krb5_context, handle->principal,
	def_princ) == FALSE) {
	/* Before failing, lets check the keytab */
	krb5_free_principal(gssapi_krb5_context, def_princ);
	def_princ = NULL;
    }
    if (def_princ == NULL) {
	/* We have no existing credentials cache,
	 * so attempt to get a TGT using a keytab.
	 */
	if (handle->principal == NULL) {
	    kret = krb5_get_default_principal(gssapi_krb5_context,
		&handle->principal);
	    if (kret)
		goto end;
	}
	kret = get_keytab(&keytab);
	if (kret)
	    goto end;
	kret = krb5_get_init_creds_opt_alloc(gssapi_krb5_context, &opt);
	if (kret)
	    goto end;
	kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred,
	    handle->principal, keytab, 0, NULL, opt);
	krb5_get_init_creds_opt_free(opt);
	if (kret)
	    goto end;
	kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops,
		&ccache);
	if (kret)
	    goto end;
	kret = krb5_cc_initialize(gssapi_krb5_context, ccache, cred.client);
	if (kret)
	    goto end;
	kret = krb5_cc_store_cred(gssapi_krb5_context, ccache, &cred);
	if (kret)
	    goto end;
	handle->lifetime = cred.times.endtime;
    } else {
	krb5_creds in_cred, *out_cred;
	krb5_const_realm realm;

	memset(&in_cred, 0, sizeof(in_cred));
	in_cred.client = handle->principal;
	
	realm = krb5_principal_get_realm(gssapi_krb5_context, 
					 handle->principal);
	if (realm == NULL) {
	    kret = KRB5_PRINC_NOMATCH; /* XXX */
	    goto end;
	}

	kret = krb5_make_principal(gssapi_krb5_context, &in_cred.server, 
				   realm, KRB5_TGS_NAME, realm, NULL);
	if (kret)
	    goto end;

	kret = krb5_get_credentials(gssapi_krb5_context, 0, 
				    ccache, &in_cred, &out_cred);
	krb5_free_principal(gssapi_krb5_context, in_cred.server);
	if (kret)
	    goto end;

	handle->lifetime = out_cred->times.endtime;
	krb5_free_creds(gssapi_krb5_context, out_cred);
    }

    handle->ccache = ccache;
    ret = GSS_S_COMPLETE;

end:
    if (cred.client != NULL)
	krb5_free_cred_contents(gssapi_krb5_context, &cred);
    if (def_princ != NULL)
	krb5_free_principal(gssapi_krb5_context, def_princ);
    if (keytab != NULL)
	krb5_kt_close(gssapi_krb5_context, keytab);
    if (ret != GSS_S_COMPLETE) {
	if (ccache != NULL)
	    krb5_cc_close(gssapi_krb5_context, ccache);
	if (kret != 0) {
	    *minor_status = kret;
	    gssapi_krb5_set_error_string ();
	}
    }
    return (ret);
}
Пример #24
0
static void
ntlm_service(void *ctx, const heim_idata *req,
	     const heim_icred cred,
	     heim_ipc_complete complete,
	     heim_sipc_call cctx)
{
    NTLMRequest2 ntq;
    unsigned char sessionkey[16];
    heim_idata rep = { 0, NULL };
    krb5_context context = ctx;
    hdb_entry_ex *user = NULL;
    Key *key = NULL;
    NTLMReply ntp;
    size_t size;
    int ret;
    char *domain;

    kdc_log(context, config, 1, "digest-request: uid=%d",
	    (int)heim_ipc_cred_get_uid(cred));
    
    if (heim_ipc_cred_get_uid(cred) != 0) {
	(*complete)(cctx, EPERM, NULL);
	return;
    }

    ntp.success = 0;
    ntp.flags = 0;
    ntp.sessionkey = NULL;

    ret = decode_NTLMRequest2(req->data, req->length, &ntq, NULL);
    if (ret)
	goto failed;

    /* XXX forward to NetrLogonSamLogonEx() if not a local domain */
    if (strcmp(ntq.loginDomainName, "BUILTIN") == 0) {
	domain = ntq.loginDomainName;
    } else if (strcmp(ntq.loginDomainName, "") == 0) {
	domain = "BUILTIN";
    } else {
	ret = EINVAL;
	goto failed;
    }

    kdc_log(context, config, 1, "digest-request: user=%s/%s",
	    ntq.loginUserName, domain);

    if (ntq.lmchallenge.length != 8)
	goto failed;

    if (ntq.ntChallengeResponce.length == 0)
	goto failed;

    {
	krb5_principal client;

	ret = krb5_make_principal(context, &client, domain,
				  ntq.loginUserName, NULL);
	if (ret)
	    goto failed;

	krb5_principal_set_type(context, client, KRB5_NT_NTLM);

	ret = _kdc_db_fetch(context, config, client,
			    HDB_F_GET_CLIENT, NULL, NULL, &user);
	krb5_free_principal(context, client);
	if (ret)
	    goto failed;

	ret = hdb_enctype2key(context, &user->entry,
			      ETYPE_ARCFOUR_HMAC_MD5, &key);
	if (ret) {
	    krb5_set_error_message(context, ret, "NTLM missing arcfour key");
	    goto failed;
	}
    }

    kdc_log(context, config, 2,
	    "digest-request: found user, processing ntlm request", ret);

    if (ntq.ntChallengeResponce.length != 24) {
	struct ntlm_buf infotarget, answer;
	
	answer.length = ntq.ntChallengeResponce.length;
	answer.data = ntq.ntChallengeResponce.data;
	
	ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data,
				     key->key.keyvalue.length,
				     ntq.loginUserName,
				     ntq.loginDomainName,
				     0,
				     ntq.lmchallenge.data,
				     &answer,
				     &infotarget,
				     sessionkey);
	if (ret) {
	    goto failed;
	}
	
	free(infotarget.data);
	/* XXX verify info target */
	
    } else {
	struct ntlm_buf answer;
	
	if (ntq.flags & NTLM_NEG_NTLM2_SESSION) {
	    unsigned char sessionhash[MD5_DIGEST_LENGTH];
	    EVP_MD_CTX *md5ctx;
	    
	    /* the first first 8 bytes is the challenge, what is the other 16 bytes ? */
	    if (ntq.lmChallengeResponce.length != 24)
		goto failed;

	    md5ctx = EVP_MD_CTX_create();
	    EVP_DigestInit_ex(md5ctx, EVP_md5(), NULL);
	    EVP_DigestUpdate(md5ctx, ntq.lmchallenge.data, 8);
	    EVP_DigestUpdate(md5ctx, ntq.lmChallengeResponce.data, 8);
	    EVP_DigestFinal_ex(md5ctx, sessionhash, NULL);
	    EVP_MD_CTX_destroy(md5ctx);
	    memcpy(ntq.lmchallenge.data, sessionhash, ntq.lmchallenge.length);
	}
	
	ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data,
					key->key.keyvalue.length,
					ntq.lmchallenge.data, &answer);
	if (ret)
	    goto failed;
	
	if (ntq.ntChallengeResponce.length != answer.length ||
	    memcmp(ntq.ntChallengeResponce.data, answer.data, answer.length) != 0) {
	    free(answer.data);
	    ret = EINVAL;
	    goto failed;
	}
	free(answer.data);
	
	{
	    EVP_MD_CTX *ctx;
	    
	    ctx = EVP_MD_CTX_create();
	    EVP_DigestInit_ex(ctx, EVP_md4(), NULL);
	    EVP_DigestUpdate(ctx, key->key.keyvalue.data, key->key.keyvalue.length);
	    EVP_DigestFinal_ex(ctx, sessionkey, NULL);
	    EVP_MD_CTX_destroy(ctx);
	}
    }

    ntp.success = 1;

    ASN1_MALLOC_ENCODE(NTLMReply, rep.data, rep.length, &ntp, &size, ret);
    if (ret)
	goto failed;
    if (rep.length != size)
	abort();
    
  failed:
    kdc_log(context, config, 1, "digest-request: %d", ret);

    (*complete)(cctx, ret, &rep);

    free(rep.data);

    free_NTLMRequest2(&ntq);
    if (user)
	_kdc_free_ent (context, user);
}
Пример #25
0
static int
proto (int sock, const char *hostname, const char *svc,
       char *message, size_t len)
{
    krb5_auth_context auth_context;
    krb5_error_code status;
    krb5_principal server;
    krb5_data data;
    krb5_data data_send;

    krb5_ccache     ccache;
    krb5_creds      creds;
    krb5_kdc_flags  flags;
    krb5_principal  principal;

    status = krb5_auth_con_init (context, &auth_context);
    if (status) {
	krb5_warn (context, status, "krb5_auth_con_init");
	return 1;
    }

    status = krb5_auth_con_setaddrs_from_fd (context,
					     auth_context,
					     &sock);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_auth_con_setaddr");
	return 1;
    }

    status = krb5_sname_to_principal (context,
				      hostname,
				      svc,
				      KRB5_NT_SRV_HST,
				      &server);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_sname_to_principal");
	return 1;
    }

    status = krb5_sendauth (context,
			    &auth_context,
			    &sock,
			    KF_VERSION_1,
			    NULL,
			    server,
			    AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
			    NULL,
			    NULL,
			    NULL,
			    NULL,
			    NULL,
			    NULL);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn(context, status, "krb5_sendauth");
	return 1;
    }

    if (ccache_name == NULL)
	ccache_name = "";

    data_send.data   = (void *)remote_name;
    data_send.length = strlen(remote_name) + 1;
    status = krb5_write_priv_message(context, auth_context, &sock, &data_send);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_write_message");
	return 1;
    }
    data_send.data   = (void *)ccache_name;
    data_send.length = strlen(ccache_name)+1;
    status = krb5_write_priv_message(context, auth_context, &sock, &data_send);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_write_message");
	return 1;
    }

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

    status = krb5_cc_default (context, &ccache);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_cc_default");
	return 1;
    }

    status = krb5_cc_get_principal (context, ccache, &principal);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_cc_get_principal");
	return 1;
    }

    creds.client = principal;

    status = krb5_make_principal (context,
				  &creds.server,
				  principal->realm,
				  KRB5_TGS_NAME,
				  principal->realm,
				  NULL);

    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_make_principal");
	return 1;
    }

    creds.times.endtime = 0;

    flags.i = 0;
    flags.b.forwarded   = 1;
    flags.b.forwardable = forwardable;

    status = krb5_get_forwarded_creds (context,
				       auth_context,
				       ccache,
				       flags.i,
				       hostname,
				       &creds,
				       &data);
    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_get_forwarded_creds");
	return 1;
    }

    status = krb5_write_priv_message(context, auth_context, &sock, &data);

    if (status) {
	krb5_auth_con_free(context, auth_context);
	krb5_warn (context, status, "krb5_mk_priv");
	return 1;
    }

    krb5_data_free (&data);

    status = krb5_read_priv_message(context, auth_context, &sock, &data);
    krb5_auth_con_free(context, auth_context);
    if (status) {
	krb5_warn (context, status, "krb5_mk_priv");
	return 1;
    }
    if(data.length >= len) {
	krb5_warnx (context, "returned string is too long, truncating");
	memcpy(message, data.data, len);
	message[len - 1] = '\0';
    } else {
	memcpy(message, data.data, data.length);
	message[data.length] = '\0';
    }
    krb5_data_free (&data);

    return(strcmp(message, "ok"));
}
Пример #26
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_ccache  ccache;
    krb5_principal principal = NULL;
    int optidx = 0;
    krb5_deltat ticket_life = 0;
#ifdef HAVE_SIGACTION
    struct sigaction sa;
#endif

    setprogname(argv[0]);

    setlocale(LC_ALL, "");
    bindtextdomain("heimdal_kuser", HEIMDAL_LOCALEDIR);
    textdomain("heimdal_kuser");

    ret = krb5_init_context(&context);
    if (ret == KRB5_CONFIG_BADFORMAT)
	errx(1, "krb5_init_context failed to parse configuration file");
    else if (ret)
	errx(1, "krb5_init_context failed: %d", ret);

    if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
	usage(1);

    if (help_flag)
	usage(0);

    if (version_flag) {
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    /*
     * Open the keytab now, we use the keytab to determine the principal's
     * realm when the requested principal has no realm.
     */
    if (use_keytab || keytab_str) {
	if (keytab_str)
	    ret = krb5_kt_resolve(context, keytab_str, &kt);
	else
	    ret = krb5_kt_default(context, &kt);
	if (ret)
	    krb5_err(context, 1, ret, "resolving keytab");
    }

    if (pk_enterprise_flag) {
	ret = krb5_pk_enterprise_cert(context, pk_user_id,
				      argv[0], &principal,
				      &ent_user_id);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pk_enterprise_certs");

	pk_user_id = NULL;

    } else if (anonymous_flag) {

	ret = krb5_make_principal(context, &principal, argv[0],
				  KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME,
				  NULL);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_make_principal");
	krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN);

    } else if (use_keytab || keytab_str) {
	get_princ_kt(context, &principal, argv[0]);
    } else {
	get_princ(context, &principal, argv[0]);
    }

    if (fcache_version)
	krb5_set_fcache_version(context, fcache_version);

    if (renewable_flag == -1)
	/* this seems somewhat pointless, but whatever */
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"renewable", FALSE, &renewable_flag);
    if (do_afslog == -1)
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"afslog", TRUE, &do_afslog);

    if (cred_cache)
	ret = krb5_cc_resolve(context, cred_cache, &ccache);
    else {
	if (argc > 1) {
	    char s[1024];
	    ret = krb5_cc_new_unique(context, NULL, NULL, &ccache);
	    if (ret)
		krb5_err(context, 1, ret, "creating cred cache");
	    snprintf(s, sizeof(s), "%s:%s",
		     krb5_cc_get_type(context, ccache),
		     krb5_cc_get_name(context, ccache));
	    setenv("KRB5CCNAME", s, 1);
	} else {
	    ret = krb5_cc_cache_match(context, principal, &ccache);
	    if (ret) {
		const char *type;
		ret = krb5_cc_default(context, &ccache);
		if (ret)
		    krb5_err(context, 1, ret,
			     N_("resolving credentials cache", ""));

		/*
		 * Check if the type support switching, and we do,
		 * then do that instead over overwriting the current
		 * default credential
		 */
		type = krb5_cc_get_type(context, ccache);
		if (krb5_cc_support_switch(context, type)) {
		    krb5_cc_close(context, ccache);
		    ret = get_switched_ccache(context, type, principal,
					      &ccache);
		}
	    }
	}
    }
    if (ret)
	krb5_err(context, 1, ret, N_("resolving credentials cache", ""));

#ifndef NO_AFS
    if (argc > 1 && k_hasafs())
	k_setpag();
#endif

    if (lifetime) {
	int tmp = parse_time(lifetime, "s");
	if (tmp < 0)
	    errx(1, N_("unparsable time: %s", ""), lifetime);

	ticket_life = tmp;
    }

    if (addrs_flag == 0 && extra_addresses.num_strings > 0)
	krb5_errx(context, 1,
		  N_("specifying both extra addresses and "
		     "no addresses makes no sense", ""));
    {
	int i;
	krb5_addresses addresses;
	memset(&addresses, 0, sizeof(addresses));
	for(i = 0; i < extra_addresses.num_strings; i++) {
	    ret = krb5_parse_address(context, extra_addresses.strings[i],
				     &addresses);
	    if (ret == 0) {
		krb5_add_extra_addresses(context, &addresses);
		krb5_free_addresses(context, &addresses);
	    }
	}
	free_getarg_strings(&extra_addresses);
    }

    if (renew_flag || validate_flag) {
	ret = renew_validate(context, renew_flag, validate_flag,
			     ccache, server_str, ticket_life);

#ifndef NO_AFS
	if (ret == 0 && server_str == NULL && do_afslog && k_hasafs())
	    krb5_afslog(context, ccache, NULL, NULL);
#endif

	exit(ret != 0);
    }

    ret = get_new_tickets(context, principal, ccache, ticket_life, 1);
    if (ret)
	exit(1);

#ifndef NO_AFS
    if (ret == 0 && server_str == NULL && do_afslog && k_hasafs())
	krb5_afslog(context, ccache, NULL, NULL);
#endif

    if (argc > 1) {
	struct renew_ctx ctx;
	time_t timeout;

	timeout = ticket_lifetime(context, ccache, principal,
				  server_str, NULL) / 2;

	ctx.context = context;
	ctx.ccache = ccache;
	ctx.principal = principal;
	ctx.ticket_life = ticket_life;
	ctx.timeout = timeout;

#ifdef HAVE_SIGACTION
	memset(&sa, 0, sizeof(sa));
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = handle_siginfo;

	sigaction(SIGINFO, &sa, NULL);
#endif

	ret = simple_execvp_timed(argv[1], argv+1,
				  renew_func, &ctx, timeout);
#define EX_NOEXEC	126
#define EX_NOTFOUND	127
	if (ret == EX_NOEXEC)
	    krb5_warnx(context, N_("permission denied: %s", ""), argv[1]);
	else if (ret == EX_NOTFOUND)
	    krb5_warnx(context, N_("command not found: %s", ""), argv[1]);

	krb5_cc_destroy(context, ccache);
#ifndef NO_AFS
	if (k_hasafs())
	    k_unlog();
#endif
    } else {
	krb5_cc_close(context, ccache);
	ret = 0;
    }
    krb5_free_principal(context, principal);
    if (kt)
	krb5_kt_close(context, kt);
    krb5_free_context(context);
    return ret;
}
Пример #27
0
int
main(int argc, char **argv)
{
    const char *hostname;
    krb5_context context;
    krb5_auth_context ac;
    krb5_error_code ret;
    krb5_creds cred;
    krb5_ccache id;
    krb5_data data;
    int optidx = 0;

    setprogname (argv[0]);

    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
	usage(1);
    
    if (help_flag)
	usage (0);

    if(version_flag){
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    if (argc < 1)
	usage(1);

    hostname = argv[0];

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

    ret = krb5_init_context(&context);
    if (ret)
	errx (1, "krb5_init_context failed: %d", ret);

    ret = krb5_cc_default(context, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_default failed: %d", ret);

    ret = krb5_auth_con_init(context, &ac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_auth_con_init failed: %d", ret);

    krb5_auth_con_addflags(context, ac,
			   KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, NULL);

    ret = krb5_cc_get_principal(context, id, &cred.client);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_get_principal");

    ret = krb5_make_principal(context,
			      &cred.server,
			      krb5_principal_get_realm(context, cred.client),
			      KRB5_TGS_NAME,
			      krb5_principal_get_realm(context, cred.client),
			      NULL);
    if (ret)
	krb5_err(context, 1, ret, "krb5_make_principal(server)");

    ret = krb5_get_forwarded_creds (context,
				    ac,
				    id,
				    KDC_OPT_FORWARDABLE,
				    hostname,
				    &cred,
				    &data);
    if (ret)
	krb5_err (context, 1, ret, "krb5_get_forwarded_creds");

    krb5_data_free(&data);
    krb5_free_context(context);

    return 0;
}
Пример #28
0
static krb5_error_code
tkt_referral_init(krb5_context context,
		  krb5_tkt_creds_context ctx,
		  krb5_data *in,
		  krb5_data *out,
		  krb5_realm *realm,
		  unsigned int *flags)
{
    krb5_error_code ret;
    krb5_creds ticket;
    krb5_const_realm client_realm;
    krb5_principal tgtname;

    _krb5_debugx(context, 10, "tkt_step_referrals: %s", ctx->server_name);

    memset(&ticket, 0, sizeof(ticket));
    memset(&ctx->kdc_flags, 0, sizeof(ctx->kdc_flags));
    memset(&ctx->next, 0, sizeof(ctx->next));

    ctx->kdc_flags.b.canonicalize = 1;

    client_realm = krb5_principal_get_realm(context, ctx->in_cred->client);

    /* find tgt for the clients base realm */
    ret = krb5_make_principal(context, &tgtname,
			      client_realm,
			      KRB5_TGS_NAME,
			      client_realm,
			      NULL);
    if(ret)
	goto out;
	
    ret = find_cred(context, ctx->ccache, tgtname, NULL, &ctx->tgt);
    krb5_free_principal(context, tgtname);
    if (ret)
	goto out;


    ret = krb5_copy_principal(context, ctx->in_cred->client, &ctx->next.client);
    if (ret)
	goto out;

    ret = krb5_copy_principal(context, ctx->in_cred->server, &ctx->next.server);
    if (ret)
	goto out;

    ret = krb5_principal_set_realm(context, ctx->next.server, ctx->tgt.server->realm);
    if (ret)
	goto out;


 out:
    if (ret) {
	ctx->error = ret;
	ctx->state = tkt_direct_init;
    } else {
	ctx->error = 0;
	ctx->state = tkt_referral_send;
    }

    return 0;
}
Пример #29
0
static krb5_error_code
get_cred_kdc_referral(krb5_context context,
		      krb5_kdc_flags flags,
		      krb5_ccache ccache,
		      krb5_creds *in_creds,
		      krb5_principal impersonate_principal,
		      Ticket *second_ticket,			
		      krb5_creds **out_creds,
		      krb5_creds ***ret_tgts)
{
    krb5_const_realm client_realm;
    krb5_error_code ret;
    krb5_creds tgt, referral, ticket;
    int loop = 0;
    int ok_as_delegate = 1;

    if (in_creds->server->name.name_string.len < 2 && !flags.b.canonicalize) {
	krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED,
			       N_("Name too short to do referals, skipping", ""));
	return KRB5KDC_ERR_PATH_NOT_ACCEPTED;
    }

    memset(&tgt, 0, sizeof(tgt));
    memset(&ticket, 0, sizeof(ticket));

    flags.b.canonicalize = 1;

    *out_creds = NULL;

    client_realm = krb5_principal_get_realm(context, in_creds->client);

    /* find tgt for the clients base realm */
    {
	krb5_principal tgtname;
	
	ret = krb5_make_principal(context, &tgtname,
				  client_realm,
				  KRB5_TGS_NAME,
				  client_realm,
				  NULL);
	if(ret)
	    return ret;
	
	ret = find_cred(context, ccache, tgtname, *ret_tgts, &tgt);
	krb5_free_principal(context, tgtname);
	if (ret)
	    return ret;
    }

    referral = *in_creds;
    ret = krb5_copy_principal(context, in_creds->server, &referral.server);
    if (ret) {
	krb5_free_cred_contents(context, &tgt);
	return ret;
    }
    ret = krb5_principal_set_realm(context, referral.server, client_realm);
    if (ret) {
	krb5_free_cred_contents(context, &tgt);
	krb5_free_principal(context, referral.server);
	return ret;
    }

    while (loop++ < 17) {
	krb5_creds **tickets;
	krb5_creds mcreds;
	char *referral_realm;

	/* Use cache if we are not doing impersonation or contrainte deleg */
	if (impersonate_principal == NULL || flags.b.constrained_delegation) {
	    krb5_cc_clear_mcred(&mcreds);
	    mcreds.server = referral.server;
	    ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &ticket);
	} else
	    ret = EINVAL;

	if (ret) {
	    ret = get_cred_kdc_address(context, ccache, flags, NULL,
				       &referral, &tgt, impersonate_principal,
				       second_ticket, &ticket);
	    if (ret)
		goto out;
	}

	/* Did we get the right ticket ? */
	if (krb5_principal_compare_any_realm(context,
					     referral.server,
					     ticket.server))
	    break;

	if (!krb5_principal_is_krbtgt(context, ticket.server)) {
	    krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US,
				   N_("Got back an non krbtgt "
				      "ticket referrals", ""));
	    ret = KRB5KRB_AP_ERR_NOT_US;
	    goto out;
	}

	referral_realm = ticket.server->name.name_string.val[1];

	/* check that there are no referrals loops */
	tickets = *ret_tgts;

	krb5_cc_clear_mcred(&mcreds);
	mcreds.server = ticket.server;

	while(tickets && *tickets){
	    if(krb5_compare_creds(context,
				  KRB5_TC_DONT_MATCH_REALM,
				  &mcreds,
				  *tickets))
	    {
		krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
				       N_("Referral from %s "
					  "loops back to realm %s", ""),
				       tgt.server->realm,
				       referral_realm);
		ret = KRB5_GET_IN_TKT_LOOP;
                goto out;
	    }
	    tickets++;
	}	

	/* 
	 * if either of the chain or the ok_as_delegate was stripped
	 * by the kdc, make sure we strip it too.
	 */

	if (ok_as_delegate == 0 || ticket.flags.b.ok_as_delegate == 0) {
	    ok_as_delegate = 0;
	    ticket.flags.b.ok_as_delegate = 0;
	}

	ret = add_cred(context, &ticket, ret_tgts);
	if (ret)
	    goto out;

	/* try realm in the referral */
	ret = krb5_principal_set_realm(context,
				       referral.server,
				       referral_realm);
	krb5_free_cred_contents(context, &tgt);
	tgt = ticket;
	memset(&ticket, 0, sizeof(ticket));
	if (ret)
	    goto out;
    }

    ret = krb5_copy_creds(context, &ticket, out_creds);

out:
    krb5_free_principal(context, referral.server);
    krb5_free_cred_contents(context, &tgt);
    krb5_free_cred_contents(context, &ticket);
    return ret;
}
krb5_error_code
_gsspku2u_principal(krb5_context context,
		    struct hx509_cert_data *cert,
		    krb5_principal *principal)
{
    hx509_octet_string_list list;
    krb5_error_code ret;
    int found = 0;
    unsigned i;
    char *name;

    *principal = NULL;

    /*
     * First try to map PKINIT SAN to a Kerberos principal
     */

    ret = hx509_cert_find_subjectAltName_otherName(context->hx509ctx, cert,
						   &asn1_oid_id_pkinit_san,
						   &list);
    if (ret == 0) {
	for (i = 0; !found && i < list.len; i++) {
	    KRB5PrincipalName r;

	    ret = decode_KRB5PrincipalName(list.val[i].data,
					   list.val[i].length,
					   &r, NULL);
	    if (ret)
		continue;
	    
	    ret = _krb5_principalname2krb5_principal(context, principal,
						     r.principalName,
						     KRB5_PKU2U_REALM_NAME);
	    free_KRB5PrincipalName(&r);
	    if (ret == 0)
		found = 1;
	}
	hx509_free_octet_string_list(&list);
    }
    if (found)
	return 0;

    /*
     *
     */

    ret = hx509_cert_get_appleid(context->hx509ctx, cert, &name);
    if (ret == 0) {
	ret = krb5_make_principal(context, principal,
				  KRB5_PKU2U_REALM_NAME,
				  name, NULL);
	hx509_xfree(name);
	if (ret == 0) {
	    (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL;
	    return 0;
	}
    }
    
    /*
     * Give up and just WELLKNOWN and assertion instead
     */

    ret = krb5_make_principal(context, principal, KRB5_PKU2U_REALM_NAME,
			      KRB5_WELLKNOWN_NAME, KRB5_NULL_NAME, NULL);
    if (ret == 0)
	(*principal)->name.name_type = KRB5_NT_WELLKNOWN;
    return ret;
}