krb5_error_code kcm_ccache_refresh(krb5_context context, kcm_ccache ccache, krb5_creds **credp) { krb5_error_code ret; krb5_creds in, *out; krb5_kdc_flags flags; krb5_const_realm realm; krb5_ccache_data ccdata; const char *estr; memset(&in, 0, sizeof(in)); KCM_ASSERT_VALID(ccache); if (ccache->client == NULL) { /* no primary principal */ kcm_log(0, "Refresh credentials requested but no client principal"); return KRB5_CC_NOTFOUND; } HEIMDAL_MUTEX_lock(&ccache->mutex); /* Fake up an internal ccache */ kcm_internal_ccache(context, ccache, &ccdata); /* Find principal */ in.client = ccache->client; if (ccache->server != NULL) { ret = krb5_copy_principal(context, ccache->server, &in.server); if (ret) { estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to copy service principal: %s", estr); krb5_free_error_message(context, estr); goto out; } } else { realm = krb5_principal_get_realm(context, in.client); ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, realm, NULL); if (ret) { estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to make TGS principal for realm %s: %s", realm, estr); krb5_free_error_message(context, estr); goto out; } } if (ccache->tkt_life) in.times.endtime = time(NULL) + ccache->tkt_life; if (ccache->renew_life) in.times.renew_till = time(NULL) + ccache->renew_life; flags.i = 0; flags.b.renewable = TRUE; flags.b.renew = TRUE; ret = krb5_get_kdc_cred(context, &ccdata, flags, NULL, NULL, &in, &out); if (ret) { estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to renew credentials for cache %s: %s", ccache->name, estr); krb5_free_error_message(context, estr); goto out; } /* Swap them in */ kcm_ccache_remove_creds_internal(context, ccache); ret = kcm_ccache_store_cred_internal(context, ccache, out, 0, credp); if (ret) { estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to store credentials for cache %s: %s", ccache->name, estr); krb5_free_error_message(context, estr); krb5_free_creds(context, out); goto out; } free(out); /* but not contents */ out: HEIMDAL_MUTEX_unlock(&ccache->mutex); return ret; }
/*ARGSUSED*/ void process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, const krb5_fulladdr *from, kdc_realm_t *kdc_active_realm, verto_ctx *vctx, loop_respond_fn respond, void *arg) { krb5_error_code errcode; unsigned int s_flags = 0; krb5_data encoded_req_body; krb5_enctype useenctype; struct as_req_state *state; krb5_audit_state *au_state = NULL; state = k5alloc(sizeof(*state), &errcode); if (state == NULL) { (*respond)(arg, errcode, NULL); return; } state->respond = respond; state->arg = arg; state->request = request; state->req_pkt = req_pkt; state->from = from; state->active_realm = kdc_active_realm; errcode = kdc_make_rstate(kdc_active_realm, &state->rstate); if (errcode != 0) { (*respond)(arg, errcode, NULL); free(state); return; } /* Initialize audit state. */ errcode = kau_init_kdc_req(kdc_context, state->request, from, &au_state); if (errcode) { (*respond)(arg, errcode, NULL); kdc_free_rstate(state->rstate); free(state); return; } state->au_state = au_state; if (state->request->msg_type != KRB5_AS_REQ) { state->status = "msg_type mismatch"; errcode = KRB5_BADMSGTYPE; goto errout; } /* Seed the audit trail with the request ID and basic information. */ kau_as_req(kdc_context, TRUE, au_state); if (fetch_asn1_field((unsigned char *) req_pkt->data, 1, 4, &encoded_req_body) != 0) { errcode = ASN1_BAD_ID; state->status = "Finding req_body"; goto errout; } errcode = kdc_find_fast(&state->request, &encoded_req_body, NULL, NULL, state->rstate, &state->inner_body); if (errcode) { state->status = "error decoding FAST"; goto errout; } if (state->inner_body == NULL) { /* Not a FAST request; copy the encoded request body. */ errcode = krb5_copy_data(kdc_context, &encoded_req_body, &state->inner_body); if (errcode) { state->status = "storing req body"; goto errout; } } au_state->request = state->request; state->rock.request = state->request; state->rock.inner_body = state->inner_body; state->rock.rstate = state->rstate; state->rock.vctx = vctx; if (!state->request->client) { state->status = "NULL_CLIENT"; errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; goto errout; } if ((errcode = krb5_unparse_name(kdc_context, state->request->client, &state->cname))) { state->status = "UNPARSING_CLIENT"; goto errout; } limit_string(state->cname); if (!state->request->server) { state->status = "NULL_SERVER"; errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto errout; } if ((errcode = krb5_unparse_name(kdc_context, state->request->server, &state->sname))) { state->status = "UNPARSING_SERVER"; goto errout; } limit_string(state->sname); /* * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint * to the backend to return naming information in lieu * of cross realm TGS entries. */ setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY); /* * Note that according to the referrals draft we should * always canonicalize enterprise principal names. */ if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) || state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL) { setflag(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE); setflag(state->c_flags, KRB5_KDB_FLAG_ALIAS_OK); } if (include_pac_p(kdc_context, state->request)) { setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC); } errcode = krb5_db_get_principal(kdc_context, state->request->client, state->c_flags, &state->client); if (errcode == KRB5_KDB_CANTLOCK_DB) errcode = KRB5KDC_ERR_SVC_UNAVAILABLE; if (errcode == KRB5_KDB_NOENTRY) { state->status = "CLIENT_NOT_FOUND"; if (vague_errors) errcode = KRB5KRB_ERR_GENERIC; else errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; goto errout; } else if (errcode) { state->status = "LOOKING_UP_CLIENT"; goto errout; } state->rock.client = state->client; /* * If the backend returned a principal that is not in the local * realm, then we need to refer the client to that realm. */ if (!is_local_principal(kdc_active_realm, state->client->princ)) { /* Entry is a referral to another realm */ state->status = "REFERRAL"; au_state->cl_realm = &state->client->princ->realm; errcode = KRB5KDC_ERR_WRONG_REALM; goto errout; } au_state->stage = SRVC_PRINC; s_flags = 0; setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK); if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) { setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE); } errcode = krb5_db_get_principal(kdc_context, state->request->server, s_flags, &state->server); if (errcode == KRB5_KDB_CANTLOCK_DB) errcode = KRB5KDC_ERR_SVC_UNAVAILABLE; if (errcode == KRB5_KDB_NOENTRY) { state->status = "SERVER_NOT_FOUND"; errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto errout; } else if (errcode) { state->status = "LOOKING_UP_SERVER"; goto errout; } au_state->stage = VALIDATE_POL; if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) { state->status = "TIMEOFDAY"; goto errout; } state->authtime = state->kdc_time; /* for audit_as_request() */ if ((errcode = validate_as_request(kdc_active_realm, state->request, *state->client, *state->server, state->kdc_time, &state->status, &state->e_data))) { if (!state->status) state->status = "UNKNOWN_REASON"; errcode += ERROR_TABLE_BASE_krb5; goto errout; } au_state->stage = ISSUE_TKT; /* * Select the keytype for the ticket session key. */ if ((useenctype = select_session_keytype(kdc_active_realm, state->server, state->request->nktypes, state->request->ktype)) == 0) { /* unsupported ktype */ state->status = "BAD_ENCRYPTION_TYPE"; errcode = KRB5KDC_ERR_ETYPE_NOSUPP; goto errout; } if ((errcode = krb5_c_make_random_key(kdc_context, useenctype, &state->session_key))) { state->status = "RANDOM_KEY_FAILED"; goto errout; } /* * Canonicalization is only effective if we are issuing a TGT * (the intention is to allow support for Windows "short" realm * aliases, nothing more). */ if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) && krb5_is_tgs_principal(state->request->server) && krb5_is_tgs_principal(state->server->princ)) { state->ticket_reply.server = state->server->princ; } else { state->ticket_reply.server = state->request->server; } state->enc_tkt_reply.flags = 0; state->enc_tkt_reply.times.authtime = state->authtime; setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL); setflag(state->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP); /* * It should be noted that local policy may affect the * processing of any of these flags. For example, some * realms may refuse to issue renewable tickets */ if (isflagset(state->request->kdc_options, KDC_OPT_FORWARDABLE)) setflag(state->enc_tkt_reply.flags, TKT_FLG_FORWARDABLE); if (isflagset(state->request->kdc_options, KDC_OPT_PROXIABLE)) setflag(state->enc_tkt_reply.flags, TKT_FLG_PROXIABLE); if (isflagset(state->request->kdc_options, KDC_OPT_ALLOW_POSTDATE)) setflag(state->enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE); state->enc_tkt_reply.session = &state->session_key; if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) { state->client_princ = *(state->client->princ); } else { state->client_princ = *(state->request->client); /* The realm is always canonicalized */ state->client_princ.realm = state->client->princ->realm; } state->enc_tkt_reply.client = &state->client_princ; state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS; state->enc_tkt_reply.transited.tr_contents = empty_string; if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) { setflag(state->enc_tkt_reply.flags, TKT_FLG_POSTDATED); setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID); state->enc_tkt_reply.times.starttime = state->request->from; } else state->enc_tkt_reply.times.starttime = state->kdc_time; kdc_get_ticket_endtime(kdc_active_realm, state->enc_tkt_reply.times.starttime, kdc_infinity, state->request->till, state->client, state->server, &state->enc_tkt_reply.times.endtime); kdc_get_ticket_renewtime(kdc_active_realm, state->request, NULL, state->client, state->server, &state->enc_tkt_reply); /* * starttime is optional, and treated as authtime if not present. * so we can nuke it if it matches */ if (state->enc_tkt_reply.times.starttime == state->enc_tkt_reply.times.authtime) state->enc_tkt_reply.times.starttime = 0; state->enc_tkt_reply.caddrs = state->request->addresses; state->enc_tkt_reply.authorization_data = 0; /* If anonymous requests are being used, adjust the realm of the client * principal. */ if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) { if (!krb5_principal_compare_any_realm(kdc_context, state->request->client, krb5_anonymous_principal())) { errcode = KRB5KDC_ERR_BADOPTION; state->status = "Anonymous requested but anonymous " "principal not used."; goto errout; } setflag(state->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS); krb5_free_principal(kdc_context, state->request->client); state->request->client = NULL; errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(), &state->request->client); if (errcode) { state->status = "Copying anonymous principal"; goto errout; } state->enc_tkt_reply.client = state->request->client; setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH); } /* * Check the preauthentication if it is there. */ if (state->request->padata) { check_padata(kdc_context, &state->rock, state->req_pkt, state->request, &state->enc_tkt_reply, &state->pa_context, &state->e_data, &state->typed_e_data, finish_preauth, state); } else finish_preauth(state, 0); return; errout: finish_process_as_req(state, errcode); }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_renewed_creds(krb5_context context, krb5_creds *creds, krb5_const_principal client, krb5_ccache ccache, const char *in_tkt_service) { krb5_error_code ret; krb5_kdc_flags flags; krb5_creds in, *template, *out = NULL; memset(&in, 0, sizeof(in)); memset(creds, 0, sizeof(*creds)); ret = krb5_copy_principal(context, client, &in.client); if (ret) return ret; if (in_tkt_service) { ret = krb5_parse_name(context, in_tkt_service, &in.server); if (ret) { krb5_free_principal(context, in.client); return ret; } } else { const char *realm = krb5_principal_get_realm(context, client); ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, realm, NULL); if (ret) {
kadm5_ret_t kadm5_s_get_principal(void *server_handle, krb5_principal princ, kadm5_principal_ent_t out, uint32_t mask) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); context->db->hdb_close(context->context, context->db); if(ret) return _kadm5_error_code(ret); memset(out, 0, sizeof(*out)); if(mask & KADM5_PRINCIPAL) ret = krb5_copy_principal(context->context, ent.entry.principal, &out->principal); if(ret) goto out; if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end) out->princ_expire_time = *ent.entry.valid_end; if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end) out->pw_expiration = *ent.entry.pw_end; if(mask & KADM5_LAST_PWD_CHANGE) hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change); if(mask & KADM5_ATTRIBUTES){ out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; } if(mask & KADM5_MAX_LIFE) { if(ent.entry.max_life) out->max_life = *ent.entry.max_life; else out->max_life = INT_MAX; } if(mask & KADM5_MOD_TIME) { if(ent.entry.modified_by) out->mod_date = ent.entry.modified_by->time; else out->mod_date = ent.entry.created_by.time; } if(mask & KADM5_MOD_NAME) { if(ent.entry.modified_by) { if (ent.entry.modified_by->principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.modified_by->principal, &out->mod_name); } else if(ent.entry.created_by.principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.created_by.principal, &out->mod_name); else out->mod_name = NULL; } if(ret) goto out; if(mask & KADM5_KVNO) out->kvno = ent.entry.kvno; if(mask & KADM5_MKVNO) { size_t n; out->mkvno = 0; /* XXX */ for(n = 0; n < ent.entry.keys.len; n++) if(ent.entry.keys.val[n].mkvno) { out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */ break; } } #if 0 /* XXX implement */ if(mask & KADM5_AUX_ATTRIBUTES) ; if(mask & KADM5_LAST_SUCCESS) ; if(mask & KADM5_LAST_FAILED) ; if(mask & KADM5_FAIL_AUTH_COUNT) ; #endif if(mask & KADM5_POLICY) out->policy = NULL; if(mask & KADM5_MAX_RLIFE) { if(ent.entry.max_renew) out->max_renewable_life = *ent.entry.max_renew; else out->max_renewable_life = INT_MAX; } if(mask & KADM5_KEY_DATA){ size_t i; Key *key; krb5_key_data *kd; krb5_salt salt; krb5_data *sp; krb5_get_pw_salt(context->context, ent.entry.principal, &salt); out->key_data = malloc(ent.entry.keys.len * sizeof(*out->key_data)); if (out->key_data == NULL && ent.entry.keys.len != 0) { ret = ENOMEM; goto out; } for(i = 0; i < ent.entry.keys.len; i++){ key = &ent.entry.keys.val[i]; kd = &out->key_data[i]; kd->key_data_ver = 2; kd->key_data_kvno = ent.entry.kvno; kd->key_data_type[0] = key->key.keytype; if(key->salt) kd->key_data_type[1] = key->salt->type; else kd->key_data_type[1] = KRB5_PADATA_PW_SALT; /* setup key */ kd->key_data_length[0] = key->key.keyvalue.length; kd->key_data_contents[0] = malloc(kd->key_data_length[0]); if(kd->key_data_contents[0] == NULL && kd->key_data_length[0] != 0){ ret = ENOMEM; break; } memcpy(kd->key_data_contents[0], key->key.keyvalue.data, kd->key_data_length[0]); /* setup salt */ if(key->salt) sp = &key->salt->salt; else sp = &salt.saltvalue; kd->key_data_length[1] = sp->length; kd->key_data_contents[1] = malloc(kd->key_data_length[1]); if(kd->key_data_length[1] != 0 && kd->key_data_contents[1] == NULL) { memset(kd->key_data_contents[0], 0, kd->key_data_length[0]); ret = ENOMEM; break; } memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]); out->n_key_data = i + 1; } krb5_free_salt(context->context, salt); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } if(mask & KADM5_TL_DATA) { time_t last_pw_expire; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_Aliases *aliases; ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire); if (ret == 0 && last_pw_expire) { unsigned char buf[4]; _krb5_put_int(buf, last_pw_expire, sizeof(buf)); ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } /* * If the client was allowed to get key data, let it have the * password too. */ if(mask & KADM5_KEY_DATA) { heim_utf8_string pw; ret = hdb_entry_get_password(context->context, context->db, &ent.entry, &pw); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); free(pw); } krb5_clear_error_message(context->context); } ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl); if (ret == 0 && acl) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length, acl, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } ret = hdb_entry_get_aliases(&ent.entry, &aliases); if (ret == 0 && aliases) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length, aliases, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } } out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
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){ /* only allow implicit ok_as_delegate if the realm is the clients realm */ if (strcmp(try_realm, client_realm) != 0 || strcmp(try_realm, server_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; }
int auks_krb5_cred_deladdr_buffer(char *in_buf,size_t in_buf_len, char** pout_buf,size_t *pout_buf_len) { int fstatus = AUKS_ERROR ; /* kerberos related variables */ krb5_error_code err_code; krb5_context context; krb5_auth_context auth_context; krb5_creds **creds; krb5_data data; krb5_replay_data krdata; krb5_data *p_outbuf; krb5_creds fwd_cred; krb5_creds *p_cred_out = NULL; krb5_address **addresses; char* buffer; size_t length; /* initialize kerberos context */ err_code = krb5_init_context(&context); if (err_code) { auks_error("unable to initialize kerberos context : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ; goto exit; } auks_log("kerberos context successfully initialized"); /* initialize a nullified kerberos authentication context in order */ /* to decode credential from buffer */ err_code = krb5_auth_con_init(context, &auth_context); if (err_code) { auks_error("unable to initialize kerberos authentication" " context : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ; goto ctx_exit; } auks_log("kerberos authentication context successfully initialized"); /* clear kerberos authentication context flags */ krb5_auth_con_setflags(context, auth_context, 0); /* build a kerberos data structure with input buffer */ data.data = in_buf; data.length = in_buf_len; /* build kerberos credential structure using this data structure */ err_code = krb5_rd_cred(context, auth_context, &data,&creds,&krdata); if (err_code) { auks_error("unable to deserialize credential data : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_RD_CRED ; goto auth_ctx_exit; } auks_log("credential data successfully deserialized"); memset(&fwd_cred, 0,sizeof(fwd_cred)); /* copy client principal in futur credential */ err_code = krb5_copy_principal(context,(*creds)->client, &fwd_cred.client); if (err_code) { auks_error("unable to put client principal into " "request cred : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ; goto cred_exit; } auks_log("client principal successfully put into request cred"); /* copy krbtgt/... principal in futur credential as required */ /* server principal for TGS */ err_code = krb5_copy_principal(context,(*creds)->server, &fwd_cred.server); if (err_code) { auks_error("unable to put server principal into " "request cred : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ; goto cred_exit; } auks_log("server principal successfully put into request cred"); /* get addressless forwarded ticket */ err_code = krb5_get_cred_via_tkt(context,(*creds), ( KDC_OPT_CANONICALIZE | KDC_OPT_FORWARDED | ( (*creds)->ticket_flags & KDC_TKT_COMMON_MASK ) ), addresses=NULL, &fwd_cred,&p_cred_out); if (err_code) { auks_error("unable to get addressless forwarded cred from auks" " cred buffer : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_GET_FWD_CRED ; goto cred_exit; } auks_log("addressless forwarded cred successfully" " got using auks cred buffer"); /* extract credential data */ err_code = krb5_mk_1cred(context,auth_context,p_cred_out, &p_outbuf,&krdata); if (err_code) { auks_error("unable to dump credential into working buffer : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_MK_CRED ; goto fwd_exit; } auks_log("credential successfully dumped into buffer"); /* allocate output buffer */ length = p_outbuf->length; buffer = (char *) malloc(length * sizeof(char)); if (buffer == NULL) { auks_error("unable to allocate memory for credential data " "storage"); fstatus = AUKS_ERROR_KRB5_CRED_MALLOC ; goto mk_exit; } /* copy credential data into output buffer */ memcpy(buffer,p_outbuf->data,length); *pout_buf = buffer; *pout_buf_len = length; auks_log("credential successfully stored in output buffer"); fstatus = AUKS_SUCCESS ; auks_log("in length : %u | out length : %u", in_buf_len, p_outbuf->length); mk_exit: krb5_free_data(context,p_outbuf); fwd_exit: krb5_free_creds(context,p_cred_out); cred_exit: krb5_free_cred_contents(context,&fwd_cred); krb5_free_creds(context, *creds); free(creds); auth_ctx_exit: krb5_auth_con_free(context, auth_context); ctx_exit: krb5_free_context(context); exit: return fstatus; }
/* * Populate the credentials structure corresponding to the ticket we are * printing. */ static int populate_creds(krb5_context context, krb5_principal service_principal, krb5_principal client_principal, krb5_keyblock *session_key, void *tr_in, void *er_in, krb5_creds *creds) { krb5_error_code code; #if USING_HEIMDAL Ticket *ticket_reply; EncTicketPart *enc_tkt_reply; size_t dummy; #else krb5_ticket *ticket_reply; krb5_enc_tkt_part *enc_tkt_reply; krb5_data *temp = NULL; #endif /* Requisite aliasing for Heimdal/MIT support. */ ticket_reply = tr_in; enc_tkt_reply = er_in; code = krb5_copy_principal(context, service_principal, &creds->server); if (code != 0) goto cleanup; code = krb5_copy_principal(context, client_principal, &creds->client); if (code != 0) goto cleanup; code = krb5_copy_keyblock_contents(context, session_key, &deref_session_key(creds)); if (code != 0) goto cleanup; #if USING_HEIMDAL creds->times.authtime = enc_tkt_reply->authtime; creds->times.starttime = *(enc_tkt_reply->starttime); creds->times.endtime = enc_tkt_reply->endtime; creds->times.renew_till = 0; /* *(enc_tkt_reply->renew_till) */ creds->flags.b = enc_tkt_reply->flags; #else creds->times = enc_tkt_reply->times; creds->ticket_flags = enc_tkt_reply->flags; #endif #if USING_HEIMDAL ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, ticket_reply, &dummy, code); if (code != 0 || dummy != creds->ticket.length) goto cleanup; #else code = encode_krb5_ticket(ticket_reply, &temp); if (code != 0) goto cleanup; creds->ticket = *temp; #endif cleanup: #if USING_HEIMDAL /* nothing */ #else free(temp); #endif return code; }
static krb5_error_code get_salt_and_kvno(krb5_context context, kcm_ccache ccache, krb5_enctype *etypes, char *cpn, char *newpw, krb5_salt *salt, unsigned *kvno) { krb5_error_code ret; krb5_creds creds; krb5_ccache_data ccdata; krb5_flags options = 0; krb5_kdc_rep reply; struct kcm_keyseed_data s; memset(&creds, 0, sizeof(creds)); memset(&reply, 0, sizeof(reply)); s.password = NULL; s.salt.salttype = (int)ETYPE_NULL; krb5_data_zero(&s.salt.saltvalue); *kvno = 0; kcm_internal_ccache(context, ccache, &ccdata); s.password = newpw; /* Do an AS-REQ to determine salt and key version number */ ret = krb5_copy_principal(context, ccache->client, &creds.client); if (ret) return ret; /* Yes, get a ticket to ourselves */ ret = krb5_copy_principal(context, ccache->client, &creds.server); if (ret) { krb5_free_principal(context, creds.client); return ret; } ret = krb5_get_in_tkt(context, options, NULL, etypes, NULL, kcm_password_key_proc, &s, NULL, NULL, &creds, &ccdata, &reply); if (ret) { kcm_log(0, "Failed to get self ticket for principal %s: %s", cpn, krb5_get_err_text(context, ret)); krb5_free_salt(context, s.salt); } else { *salt = s.salt; /* retrieve stashed salt */ if (reply.kdc_rep.enc_part.kvno != NULL) *kvno = *(reply.kdc_rep.enc_part.kvno); } /* ccache may have been modified but it will get trashed anyway */ krb5_free_creds_contents(context, &creds); krb5_free_kdc_rep(context, &reply); return ret; }
/** * @brief * Get a TGT for use at the remote host. * * @param[in] context - The Kerberos context. * @param[in] auth_context - Authentication context * @param[in] client - Principal to be copied * @param[in] server - Server of type krb5_principal * @param[in] cc - Credential cache handle * @param[out] outbuf - Replay cache data (NULL if not needed) * * @return krb5_error_code * @retval 0 - success * @retval !=0 - failure */ static krb5_error_code fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, krb5_principal client, krb5_principal server, krb5_ccache cc, krb5_data outbuf) { krb5_replay_data replaydata; krb5_data *scratch = 0; krb5_address **addrs = 0; krb5_flags kdcoptions; krb5_error_code retval; krb5_creds creds, tgt; krb5_creds *pcreds; int free_rhost = 0; char *rhost; memset((char *)&creds, 0, sizeof(creds)); memset((char *)&tgt, 0, sizeof(creds)); if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) return KRB5_FWD_BAD_PRINCIPAL; if (krb5_princ_size(context, server) < 2) return KRB5_CC_BADNAME; rhost = malloc(server->data[1].length+1); if (!rhost) return ENOMEM; free_rhost = 1; memcpy(rhost, server->data[1].data, server->data[1].length); rhost[server->data[1].length] = '\0'; retval = krb5_os_hostaddr(context, rhost, &addrs); if (retval) goto errout; if ((retval = krb5_copy_principal(context, client, &creds.client))) goto errout; if ((retval = krb5_build_principal_ext(context, &creds.server, client->realm.length, client->realm.data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, client->realm.length, client->realm.data, 0))) goto errout; /* fetch tgt directly from cache */ retval = krb5_cc_retrieve_cred(context, cc, KRB5_TC_SUPPORTED_KTYPES, &creds, &tgt); if (retval) goto errout; /* tgt->client must be equal to creds.client */ if (!krb5_principal_compare(context, tgt.client, creds.client)) { retval = KRB5_PRINC_NOMATCH; goto errout; } if (!tgt.ticket.length) { retval = KRB5_NO_TKT_SUPPLIED; goto errout; } kdcoptions = flags2options(tgt.ticket_flags)| KDC_OPT_FORWARDED; if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) goto errout; retval = krb5_mk_1cred(context, auth_context, pcreds, &scratch, &replaydata); krb5_free_creds(context, pcreds); if (retval) { if (scratch) krb5_free_data(context, scratch); } else { *outbuf = *scratch; free(scratch); } errout: if (addrs) krb5_free_addresses(context, addrs); if (free_rhost) free(rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; }
int kt_change (struct change_options *opt, int argc, char **argv) { krb5_error_code ret; krb5_keytab keytab; krb5_kt_cursor cursor; krb5_keytab_entry entry; int i, j, max; struct change_set *changeset; int errors = 0; if((keytab = ktutil_open_keytab()) == NULL) return 1; j = 0; max = 0; changeset = NULL; ret = krb5_kt_start_seq_get(context, keytab, &cursor); if(ret){ krb5_warn(context, ret, "%s", keytab_string); goto out; } while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) { int add = 0; for (i = 0; i < j; ++i) { if (krb5_principal_compare (context, changeset[i].principal, entry.principal)) { if (changeset[i].kvno < entry.vno) changeset[i].kvno = entry.vno; break; } } if (i < j) { krb5_kt_free_entry (context, &entry); continue; } if (argc == 0) { add = 1; } else { for (i = 0; i < argc; ++i) { krb5_principal princ; ret = krb5_parse_name (context, argv[i], &princ); if (ret) { krb5_warn (context, ret, "%s", argv[i]); continue; } if (krb5_principal_compare (context, princ, entry.principal)) add = 1; krb5_free_principal (context, princ); } } if (add) { if (j >= max) { void *tmp; max = max(max * 2, 1); tmp = realloc (changeset, max * sizeof(*changeset)); if (tmp == NULL) { krb5_kt_free_entry (context, &entry); krb5_warnx (context, "realloc: out of memory"); ret = ENOMEM; break; } changeset = tmp; } ret = krb5_copy_principal (context, entry.principal, &changeset[j].principal); if (ret) { krb5_warn (context, ret, "krb5_copy_principal"); krb5_kt_free_entry (context, &entry); break; } changeset[j].kvno = entry.vno; ++j; } krb5_kt_free_entry (context, &entry); } krb5_kt_end_seq_get(context, keytab, &cursor); if (ret == KRB5_KT_END) { ret = 0; for (i = 0; i < j; i++) { if (verbose_flag) { char *client_name; ret = krb5_unparse_name (context, changeset[i].principal, &client_name); if (ret) { krb5_warn (context, ret, "krb5_unparse_name"); } else { printf("Changing %s kvno %d\n", client_name, changeset[i].kvno); free(client_name); } } ret = change_entry (keytab, changeset[i].principal, changeset[i].kvno, opt->realm_string, opt->admin_server_string, opt->server_port_integer); if (ret != 0) errors = 1; } } else errors = 1; for (i = 0; i < j; i++) krb5_free_principal (context, changeset[i].principal); free (changeset); out: krb5_kt_close(context, keytab); return errors; }
principal::principal(principal& o):base(),free(TRUE),ctx(o.getCtx()),_principal(NULL){ if(o()!=NULL) krb5_copy_principal(ctx(),o(),&_principal); };
/* we can't use krb5_mk_req because w2k wants the service to be in a particular format */ static krb5_error_code ads_krb5_mk_req(krb5_context context, krb5_auth_context *auth_context, const krb5_flags ap_req_options, const char *principal, krb5_ccache ccache, krb5_data *outbuf, time_t *expire_time) { krb5_error_code retval; krb5_principal server; krb5_creds * credsp; krb5_creds creds; krb5_data in_data; BOOL creds_ready = False; int i = 0, maxtries = 3; retval = smb_krb5_parse_name(context, principal, &server); if (retval) { DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal)); return retval; } /* obtain ticket & session key */ ZERO_STRUCT(creds); if ((retval = krb5_copy_principal(context, server, &creds.server))) { DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n", error_message(retval))); goto cleanup_princ; } if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) { /* This can commonly fail on smbd startup with no ticket in the cache. * Report at higher level than 1. */ DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n", error_message(retval))); goto cleanup_creds; } while (!creds_ready && (i < maxtries)) { if ((retval = krb5_get_credentials(context, 0, ccache, &creds, &credsp))) { DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n", principal, error_message(retval))); goto cleanup_creds; } /* cope with ticket being in the future due to clock skew */ if ((unsigned)credsp->times.starttime > time(NULL)) { time_t t = time(NULL); int time_offset =(int)((unsigned)credsp->times.starttime-t); DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset)); krb5_set_real_time(context, t + time_offset + 1, 0); } if (!ads_cleanup_expired_creds(context, ccache, credsp)) { creds_ready = True; } i++; } DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n", principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache), http_timestring((unsigned)credsp->times.endtime), (unsigned)credsp->times.endtime)); if (expire_time) { *expire_time = (time_t)credsp->times.endtime; } in_data.length = 0; retval = krb5_mk_req_extended(context, auth_context, ap_req_options, &in_data, credsp, outbuf); if (retval) { DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n", error_message(retval))); } krb5_free_creds(context, credsp); cleanup_creds: krb5_free_cred_contents(context, &creds); cleanup_princ: krb5_free_principal(context, server); return retval; }
/* Get a TGT for use at the remote host */ krb5_error_code KRB5_CALLCONV krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf) /* Should forwarded TGT also be forwardable? */ { krb5_replay_data replaydata; krb5_data * scratch = 0; krb5_address **addrs = NULL; krb5_error_code retval; krb5_creds creds, tgt; krb5_creds *pcreds; krb5_flags kdcoptions; int close_cc = 0; int free_rhost = 0; krb5_enctype enctype = 0; krb5_keyblock *session_key; krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; memset(&creds, 0, sizeof(creds)); memset(&tgt, 0, sizeof(creds)); if (cc == 0) { if ((retval = krb5int_cc_default(context, &cc))) goto errout; close_cc = 1; } retval = krb5_auth_con_getkey (context, auth_context, &session_key); if (retval) goto errout; if (session_key) { enctype = session_key->enctype; krb5_free_keyblock (context, session_key); session_key = NULL; } else if (server) { /* must server be non-NULL when rhost is given? */ /* Try getting credentials to see what the remote side supports. Not bulletproof, just a heuristic. */ krb5_creds in, *out = 0; memset (&in, 0, sizeof(in)); retval = krb5_copy_principal (context, server, &in.server); if (retval) goto punt; retval = krb5_copy_principal (context, client, &in.client); if (retval) goto punt; retval = krb5_get_credentials (context, 0, cc, &in, &out); if (retval) goto punt; /* Got the credentials. Okay, now record the enctype and throw them away. */ enctype = out->keyblock.enctype; krb5_free_creds (context, out); punt: krb5_free_cred_contents (context, &in); } if ((retval = krb5_copy_principal(context, client, &creds.client))) goto errout; retval = krb5int_tgtname(context, &client->realm, &client->realm, &creds.server); if (retval) goto errout; /* fetch tgt directly from cache */ context->use_conf_ktypes = 1; retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES, &creds, &tgt); context->use_conf_ktypes = old_use_conf_ktypes; if (retval) goto errout; /* tgt->client must be equal to creds.client */ if (!krb5_principal_compare(context, tgt.client, creds.client)) { retval = KRB5_PRINC_NOMATCH; goto errout; } if (!tgt.ticket.length) { retval = KRB5_NO_TKT_SUPPLIED; goto errout; } if (tgt.addresses && *tgt.addresses) { if (rhost == NULL) { if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) { retval = KRB5_FWD_BAD_PRINCIPAL; goto errout; } if (krb5_princ_size(context, server) < 2){ retval = KRB5_CC_BADNAME; goto errout; } rhost = malloc(server->data[1].length+1); if (!rhost) { retval = ENOMEM; goto errout; } free_rhost = 1; memcpy(rhost, server->data[1].data, server->data[1].length); rhost[server->data[1].length] = '\0'; } retval = krb5_os_hostaddr(context, rhost, &addrs); if (retval) goto errout; } creds.keyblock.enctype = enctype; creds.times = tgt.times; creds.times.starttime = 0; kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED; if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */ kdcoptions &= ~(KDC_OPT_FORWARDABLE); if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) { if (enctype) { creds.keyblock.enctype = 0; if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) goto errout; } else goto errout; } retval = krb5_mk_1cred(context, auth_context, pcreds, &scratch, &replaydata); krb5_free_creds(context, pcreds); if (retval) { if (scratch) krb5_free_data(context, scratch); } else { *outbuf = *scratch; free(scratch); } errout: if (addrs) krb5_free_addresses(context, addrs); if (close_cc) krb5_cc_close(context, cc); if (free_rhost) free(rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; }
krb5_error_code KRB5_CALLCONV krb5_copy_creds(krb5_context context, const krb5_creds *incred, krb5_creds **outcred) { krb5_creds *tempcred; krb5_error_code retval; krb5_data *scratch; if (!(tempcred = (krb5_creds *)malloc(sizeof(*tempcred)))) return ENOMEM; #ifdef HAVE_C_STRUCTURE_ASSIGNMENT *tempcred = *incred; /* copy everything quickly */ #else memcpy(tempcred, incred, sizeof(krb5_creds)); #endif retval = krb5_copy_principal(context, incred->client, &tempcred->client); if (retval) goto cleanlast; retval = krb5_copy_principal(context, incred->server, &tempcred->server); if (retval) goto cleanclient; retval = krb5_copy_keyblock_contents(context, &incred->keyblock, &tempcred->keyblock); if (retval) goto cleanserver; retval = krb5_copy_addresses(context, incred->addresses, &tempcred->addresses); if (retval) goto cleanblock; retval = krb5_copy_data(context, &incred->ticket, &scratch); if (retval) goto cleanaddrs; tempcred->ticket = *scratch; krb5_xfree(scratch); retval = krb5_copy_data(context, &incred->second_ticket, &scratch); if (retval) goto cleanticket; tempcred->second_ticket = *scratch; krb5_xfree(scratch); retval = krb5_copy_authdata(context, incred->authdata,&tempcred->authdata); if (retval) goto clearticket; *outcred = tempcred; return 0; clearticket: memset(tempcred->ticket.data,0,tempcred->ticket.length); cleanticket: free(tempcred->ticket.data); cleanaddrs: krb5_free_addresses(context, tempcred->addresses); cleanblock: krb5_xfree(tempcred->keyblock.contents); cleanserver: krb5_free_principal(context, tempcred->server); cleanclient: krb5_free_principal(context, tempcred->client); cleanlast: krb5_xfree(tempcred); return retval; }
/* * Create, initialize, and add a new ple structure to the global list */ static struct gssd_k5_kt_princ *new_ple(krb5_context context, krb5_principal princ) { struct gssd_k5_kt_princ *ple = NULL, *p; krb5_error_code code; char *default_realm; int is_default_realm = 0; ple = gsh_malloc(sizeof(struct gssd_k5_kt_princ)); if (ple == NULL) goto outerr; memset(ple, 0, sizeof(*ple)); #ifdef HAVE_KRB5 ple->realm = gsh_malloc(princ->realm.length + 1); if (ple->realm == NULL) goto outerr; strmaxcpy(ple->realm, princ->realm.data, princ->realm.length); ple->realm[princ->realm.length] = '\0'; #else ple->realm = gsh_strdup(princ->realm); if (ple->realm == NULL) goto outerr; #endif code = krb5_copy_principal(context, princ, &ple->princ); if (code) goto outerr; /* * Add new entry onto the list (if this is the default * realm, always add to the front of the list) */ code = krb5_get_default_realm(context, &default_realm); if (code == 0) { if (strcmp(ple->realm, default_realm) == 0) is_default_realm = 1; k5_free_default_realm(context, default_realm); } if (is_default_realm) { ple->next = gssd_k5_kt_princ_list; gssd_k5_kt_princ_list = ple; } else { p = gssd_k5_kt_princ_list; while (p != NULL && p->next != NULL) p = p->next; if (p == NULL) gssd_k5_kt_princ_list = ple; else p->next = ple; } return ple; outerr: if (ple) { if (ple->realm) gsh_free(ple->realm); gsh_free(ple); } return NULL; }
krb5_error_code sam_get_db_entry(krb5_context context, krb5_principal client, int *sam_type, struct _krb5_db_entry_new **db_entry) { struct _krb5_db_entry_new *assoc = NULL; krb5_principal newp = NULL; int probeslot; void *ptr = NULL; krb5_error_code retval; if (db_entry) *db_entry = NULL; retval = krb5_copy_principal(context, client, &newp); if (retval) { com_err("krb5kdc", retval, "copying client name for preauth probe"); return retval; } probeslot = krb5_princ_size(context, newp)++; ptr = realloc(krb5_princ_name(context, newp), krb5_princ_size(context, newp) * sizeof(krb5_data)); if (ptr == NULL) { retval = ENOMEM; goto cleanup; } krb5_princ_name(context, newp) = ptr; for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) { if (*sam_type && *sam_type != sam_ptr->sam_type) continue; krb5_princ_component(context,newp,probeslot)->data = sam_ptr->name; krb5_princ_component(context,newp,probeslot)->length = strlen(sam_ptr->name); retval = krb5_db_get_principal(context, newp, 0, &assoc); if (!retval) break; } cleanup: if (ptr) { krb5_princ_component(context,newp,probeslot)->data = 0; krb5_princ_component(context,newp,probeslot)->length = 0; krb5_free_principal(context, newp); } if (probeslot) krb5_princ_size(context, newp)--; if (retval) return retval; if (sam_ptr->sam_type) { /* Found entry of type sam_ptr->sam_type */ if (sam_type) *sam_type = sam_ptr->sam_type; if (db_entry) *db_entry = assoc; else krb5_db_free_principal(context, assoc); return 0; } else { return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; } }
int auks_krb5_cred_renew(char *ccachefilename) { int fstatus = AUKS_ERROR ; int read_cred_is_tgt = 0; int read_cred_is_renewable = 0; /* kerberos related variables */ krb5_context context; krb5_error_code err_code; krb5_ccache ccache; krb5_creds *p_cred_out = NULL; krb5_creds read_cred; krb5_creds renew_cred; krb5_cc_cursor cc_cursor; /* initialize kerberos context */ err_code = krb5_init_context(&context); if (err_code) { auks_error("unable to initialize kerberos context : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ; goto exit; } auks_log("kerberos context successfully initialized"); /* initialize kerberos credential cache structure */ if (ccachefilename == NULL) err_code = krb5_cc_default(context,&ccache); else err_code = krb5_cc_resolve(context,ccachefilename,&ccache); if (err_code) { auks_error("unable to resolve credential cache : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_OPEN_CC ; goto ctx_exit ; } auks_log("credential cache successfully resolved"); /* start credential cache sequential reading */ err_code = krb5_cc_start_seq_get(context, ccache,&cc_cursor); if (err_code) { auks_error("unable to start credential cache sequential " "read : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_READ_CC ; goto cc_exit; } auks_log("credential cache sequential read successfully started"); /* try to get the first renewable TGT of the cache */ do { err_code = krb5_cc_next_cred(context,ccache, &cc_cursor,&read_cred); if (!err_code) { /* just check initial or forwarded tickets (TGTs) */ if ((read_cred.ticket_flags & TKT_FLG_INITIAL) || (read_cred.ticket_flags & TKT_FLG_FORWARDED)) { read_cred_is_tgt = 1; if (read_cred.ticket_flags & TKT_FLG_RENEWABLE) { read_cred_is_renewable = 1; break; } } } } while (!err_code); /* stop credential cache sequential reading */ err_code = krb5_cc_end_seq_get(context, ccache,&cc_cursor); if (err_code) { auks_error("unable to stop credential cache sequential " "read : %s",error_message(err_code)); } else auks_log("credential cache sequential read " "successfully stopped"); /* try to do renewal if a TGT was found */ if (!read_cred_is_tgt) { auks_error("no TGT found in credential cache"); fstatus = AUKS_ERROR_KRB5_CRED_NO_TGT_FOUND ; goto seq_exit; } /* try to do renewal if a renewable TGT was found */ if (!read_cred_is_renewable) { auks_error("no renewable TGT found in credential cache"); fstatus = AUKS_ERROR_KRB5_CRED_TGT_NOT_RENEWABLE ; goto seq_exit; } auks_log("renewable TGT found in credential cache"); /* test if renewal is possible */ if (read_cred.times.endtime >= read_cred.times.renew_till) { auks_error("TGT can't be renew anymore"); fstatus = AUKS_ERROR_KRB5_CRED_TGT_HAS_EXPIRED ; goto seq_exit; } auks_log("TGT is still renewable"); /* renew credential cache TGT */ memset(&renew_cred, 0,sizeof(renew_cred)); /* copy client principal in futur credential */ err_code = krb5_copy_principal(context,read_cred.client, &renew_cred.client); if (err_code) { auks_error("unable to put client principal into " "request cred : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ; goto cred_exit; } auks_log("client principal successfully put into request cred"); /* copy krbtgt/... principal in futur credential as required */ /* server principal for TGS */ err_code = krb5_copy_principal(context,read_cred.server, &renew_cred.server); if (err_code) { auks_error("unable to put server principal into " "request cred : %s",error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ; goto cred_exit; } auks_log("server principal successfully put into request cred"); /* renew credential cache TGT */ /* err_code = krb5_get_credentials_renew(context,KDC_OPT_RENEW,ccache, */ /* &renew_cred,&p_cred_out); */ err_code = krb5_get_cred_via_tkt(context,&read_cred,KDC_OPT_RENEW, NULL,&renew_cred,&p_cred_out); if (err_code) { auks_error("unable to renew credential cache TGT : %s", error_message(err_code)); fstatus = AUKS_ERROR_KRB5_CRED_TGT_RENEW ; } else { auks_log("credential cache TGT successfully renewed"); krb5_free_creds(context,p_cred_out); fstatus = AUKS_SUCCESS ; } cred_exit: /* potential bug to check */ krb5_free_cred_contents(context,&renew_cred); seq_exit: krb5_free_cred_contents(context,&read_cred); cc_exit: krb5_cc_close(context, ccache); ctx_exit: krb5_free_context(context); exit: return fstatus; }
/* * Try krb5 authentication. server_user is passed for logging purposes * only, in auth is received ticket, in client is returned principal * from the ticket */ int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *reply) { krb5_error_code problem; krb5_principal server; krb5_ticket *ticket; int fd, ret; const char *errtxt; ret = 0; server = NULL; ticket = NULL; reply->length = 0; problem = krb5_init(authctxt); if (problem) goto err; problem = krb5_auth_con_init(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx); if (problem) goto err; fd = packet_get_connection_in(); problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, &fd); if (problem) goto err; problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, KRB5_NT_SRV_HST, &server); if (problem) goto err; problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, auth, server, NULL, NULL, &ticket); if (problem) goto err; problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, &authctxt->krb5_user); if (problem) goto err; /* if client wants mutual auth */ problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, reply); if (problem) goto err; /* Check .k5login authorization now. */ if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name)) goto err; if (client) krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, client); ret = 1; err: if (server) krb5_free_principal(authctxt->krb5_ctx, server); if (ticket) krb5_free_ticket(authctxt->krb5_ctx, ticket); if (!ret && reply->length) { free(reply->data); memset(reply, 0, sizeof(*reply)); } if (problem) { errtxt = NULL; if (authctxt->krb5_ctx != NULL) errtxt = krb5_get_error_message(authctxt->krb5_ctx, problem); if (errtxt != NULL) { debug("Kerberos v5 authentication failed: %s", errtxt); krb5_free_error_message(authctxt->krb5_ctx, errtxt); } else debug("Kerberos v5 authentication failed: %d", problem); } return (ret); }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, krb5_context context, gss_const_OID credential_type, const void *credential_data, gss_const_name_t desired_name, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle ) { 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)); /* * If we have a preferred principal, lets try to find it in all * caches, otherwise, fall back to default cache, ignore all * errors while searching. */ if (credential_type != GSS_C_NO_OID && !gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { kret = KRB5_NOCREDS_SUPPLIED; /* XXX */ goto end; } if (handle->principal) { kret = krb5_cc_cache_match (context, handle->principal, &ccache); if (kret == 0) { ret = GSS_S_COMPLETE; goto found; } } if (ccache == NULL) { kret = krb5_cc_default(context, &ccache); if (kret) goto end; } kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_close(context, ccache); def_princ = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { krb5_free_principal(context, def_princ); def_princ = NULL; krb5_cc_close(context, ccache); ccache = 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(context, &handle->principal); if (kret) goto end; } kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; if (credential_type != GSS_C_NO_OID && gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { gss_buffer_t password = (gss_buffer_t)credential_data; /* XXX are we requiring password to be NUL terminated? */ kret = krb5_get_init_creds_password(context, &cred, handle->principal, password->value, NULL, NULL, 0, NULL, opt); } else { kret = get_keytab(context, &keytab); if (kret) { krb5_get_init_creds_opt_free(context, opt); goto end; } kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); } krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) { krb5_cc_destroy(context, ccache); goto end; } kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) { krb5_cc_destroy(context, ccache); goto end; } handle->lifetime = cred.times.endtime; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } else { ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &handle->lifetime); if (ret != GSS_S_COMPLETE) { krb5_cc_close(context, ccache); goto end; } kret = 0; } found: handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (keytab != NULL) krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
static void get_princ_kt(krb5_context context, krb5_principal *principal, char *name) { krb5_error_code ret; krb5_principal tmp; krb5_ccache ccache; krb5_kt_cursor cursor; krb5_keytab_entry entry; char *def_realm; if (name == NULL) { /* * If the credential cache exists and specifies a client principal, * use that. */ if (krb5_cc_default(context, &ccache) == 0) { ret = krb5_cc_get_principal(context, ccache, principal); krb5_cc_close(context, ccache); if (ret == 0) return; } } if (name) { /* If the principal specifies an explicit realm, just use that. */ int parseflags = KRB5_PRINCIPAL_PARSE_NO_DEF_REALM; parse_name_realm(context, name, parseflags, NULL, &tmp); if (krb5_principal_get_realm(context, tmp) != NULL) { *principal = tmp; return; } } else { /* Otherwise, search keytab for bare name of the default principal. */ get_default_principal(context, &tmp); set_princ_realm(context, tmp, NULL); } def_realm = get_default_realm(context); ret = krb5_kt_start_seq_get(context, kt, &cursor); if (ret) krb5_err(context, 1, ret, "krb5_kt_start_seq_get"); while (ret == 0 && krb5_kt_next_entry(context, kt, &entry, &cursor) == 0) { const char *realm; if (!krb5_principal_compare_any_realm(context, tmp, entry.principal)) continue; if (*principal && krb5_principal_compare(context, *principal, entry.principal)) continue; /* The default realm takes precedence */ realm = krb5_principal_get_realm(context, entry.principal); if (*principal && strcmp(def_realm, realm) == 0) { krb5_free_principal(context, *principal); ret = krb5_copy_principal(context, entry.principal, principal); break; } if (!*principal) ret = krb5_copy_principal(context, entry.principal, principal); } if (ret != 0 || (ret = krb5_kt_end_seq_get(context, kt, &cursor)) != 0) krb5_err(context, 1, ret, "get_princ_kt"); if (!*principal) { if (name) parse_name_realm(context, name, 0, NULL, principal); else krb5_err(context, 1, KRB5_CC_NOTFOUND, "get_princ_kt"); } krb5_free_principal(context, tmp); free(def_realm); }
static krb5_error_code kdcrep2creds(krb5_context context, krb5_kdc_rep *pkdcrep, krb5_address *const *address, krb5_data *psectkt, krb5_creds **ppcreds) { krb5_error_code retval; krb5_data *pdata; if ((*ppcreds = (krb5_creds *)calloc(1,sizeof(krb5_creds))) == NULL) { return ENOMEM; } if ((retval = krb5_copy_principal(context, pkdcrep->client, &(*ppcreds)->client))) goto cleanup; if ((retval = krb5_copy_principal(context, pkdcrep->enc_part2->server, &(*ppcreds)->server))) goto cleanup; if ((retval = krb5_copy_keyblock_contents(context, pkdcrep->enc_part2->session, &(*ppcreds)->keyblock))) goto cleanup; TRACE_TGS_REPLY(context, (*ppcreds)->client, (*ppcreds)->server, &(*ppcreds)->keyblock); if ((retval = krb5_copy_data(context, psectkt, &pdata))) goto cleanup_keyblock; (*ppcreds)->second_ticket = *pdata; free(pdata); (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags; (*ppcreds)->times = pkdcrep->enc_part2->times; (*ppcreds)->magic = KV5M_CREDS; (*ppcreds)->authdata = NULL; /* not used */ (*ppcreds)->is_skey = psectkt->length != 0; if (pkdcrep->enc_part2->caddrs) { if ((retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs, &(*ppcreds)->addresses))) goto cleanup_keyblock; } else { /* no addresses in the list means we got what we had */ if ((retval = krb5_copy_addresses(context, address, &(*ppcreds)->addresses))) goto cleanup_keyblock; } if ((retval = encode_krb5_ticket(pkdcrep->ticket, &pdata))) goto cleanup_keyblock; (*ppcreds)->ticket = *pdata; free(pdata); return 0; cleanup_keyblock: krb5_free_keyblock_contents(context, &(*ppcreds)->keyblock); cleanup: free (*ppcreds); *ppcreds = NULL; return retval; }
krb5_error_code KRB5_CALLCONV krb5_verify_init_creds(krb5_context context, krb5_creds *creds, krb5_principal server_arg, krb5_keytab keytab_arg, krb5_ccache *ccache_arg, krb5_verify_init_creds_opt *options) { krb5_error_code ret; krb5_principal server; krb5_keytab keytab; krb5_ccache ccache; krb5_keytab_entry kte; krb5_creds in_creds, *out_creds; krb5_auth_context authcon; krb5_data ap_req; /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */ server = NULL; keytab = NULL; ccache = NULL; out_creds = NULL; authcon = NULL; ap_req.data = NULL; if (keytab_arg) { keytab = keytab_arg; } else { if ((ret = krb5_kt_default(context, &keytab))) goto cleanup; } if (server_arg) { ret = krb5_copy_principal(context, server_arg, &server); if (ret) goto cleanup; } else { /* Use a principal name from the keytab. */ ret = k5_kt_get_principal(context, keytab, &server); if (ret) { /* There's no keytab, or it's empty, or we can't read it. * Allow this unless configuration demands verification. */ if (!nofail(context, options, creds)) ret = 0; goto cleanup; } } /* first, check if the server is in the keytab. If not, there's no reason to continue. rd_req does all this, but there's no way to know that a given error is caused by a missing keytab or key, and not by some other problem. */ if (krb5_is_referral_realm(&server->realm)) { krb5_free_data_contents(context, &server->realm); ret = krb5_get_default_realm(context, &server->realm.data); if (ret) goto cleanup; server->realm.length = strlen(server->realm.data); } if ((ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) { /* this means there is no keying material. This is ok, as long as it is not prohibited by the configuration */ if (!nofail(context, options, creds)) ret = 0; goto cleanup; } krb5_kt_free_entry(context, &kte); /* If the creds are for the server principal, we're set, just do a mk_req. * Otherwise, do a get_credentials first. */ if (krb5_principal_compare(context, server, creds->server)) { /* make an ap_req */ if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds, &ap_req))) goto cleanup; } else { /* this is unclean, but it's the easiest way without ripping the library into very small pieces. store the client's initial cred in a memory ccache, then call the library. Later, we'll copy everything except the initial cred into the ccache we return to the user. A clean implementation would involve library internals with a coherent idea of "in" and "out". */ /* insert the initial cred into the ccache */ if ((ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) { ccache = NULL; goto cleanup; } if ((ret = krb5_cc_initialize(context, ccache, creds->client))) goto cleanup; if ((ret = krb5_cc_store_cred(context, ccache, creds))) goto cleanup; /* set up for get_creds */ memset(&in_creds, 0, sizeof(in_creds)); in_creds.client = creds->client; in_creds.server = server; if ((ret = krb5_timeofday(context, &in_creds.times.endtime))) goto cleanup; in_creds.times.endtime += 5*60; if ((ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds))) goto cleanup; /* make an ap_req */ if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds, &ap_req))) goto cleanup; } /* wipe the auth context for mk_req */ if (authcon) { krb5_auth_con_free(context, authcon); authcon = NULL; } /* verify the ap_req */ if ((ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab, NULL, NULL))) goto cleanup; /* if we get this far, then the verification succeeded. We can still fail if the library stuff here fails, but that's it */ if (ccache_arg && ccache) { if (*ccache_arg == NULL) { krb5_ccache retcc; retcc = NULL; if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) || (ret = krb5_cc_initialize(context, retcc, creds->client)) || (ret = copy_creds_except(context, ccache, retcc, creds->server))) { if (retcc) krb5_cc_destroy(context, retcc); } else { *ccache_arg = retcc; } } else { ret = copy_creds_except(context, ccache, *ccache_arg, server); } } /* if any of the above paths returned an errors, then ret is set accordingly. * Either that, or it's zero, which is fine, too */ cleanup: if ( server) krb5_free_principal(context, server); if (!keytab_arg && keytab) krb5_kt_close(context, keytab); if (ccache) krb5_cc_destroy(context, ccache); if (out_creds) krb5_free_creds(context, out_creds); if (authcon) krb5_auth_con_free(context, authcon); if (ap_req.data) free(ap_req.data); return(ret); }
krb5_error_code KRB5_CALLCONV krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal client, krb5_principal server, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache, krb5_error **error, krb5_ap_rep_enc_part **rep_result, krb5_creds **out_creds) { krb5_octet result; krb5_creds creds; krb5_creds * credsp = NULL; krb5_creds * credspout = NULL; krb5_error_code retval = 0; krb5_data inbuf, outbuf; int len; krb5_ccache use_ccache = 0; if (error) *error = 0; /* * First, send over the length of the sendauth version string; * then, we send over the sendauth version. Next, we send * over the length of the application version strings followed * by the string itself. */ outbuf.length = strlen(sendauth_version) + 1; outbuf.data = (char *) sendauth_version; if ((retval = krb5_write_message(context, fd, &outbuf))) return(retval); outbuf.length = strlen(appl_version) + 1; outbuf.data = appl_version; if ((retval = krb5_write_message(context, fd, &outbuf))) return(retval); /* * Now, read back a byte: 0 means no error, 1 means bad sendauth * version, 2 means bad application version */ if ((len = krb5_net_read(context, *((int *) fd), (char *)&result, 1)) != 1) return((len < 0) ? errno : ECONNABORTED); if (result == 1) return(KRB5_SENDAUTH_BADAUTHVERS); else if (result == 2) return(KRB5_SENDAUTH_BADAPPLVERS); else if (result != 0) return(KRB5_SENDAUTH_BADRESPONSE); /* * We're finished with the initial negotiations; let's get and * send over the authentication header. (The AP_REQ message) */ /* * If no credentials were provided, try getting it from the * credentials cache. */ memset((char *)&creds, 0, sizeof(creds)); /* * See if we need to access the credentials cache */ if (!in_creds || !in_creds->ticket.length) { if (ccache) use_ccache = ccache; /* Solaris Kerberos */ else if ((retval = krb5int_cc_default(context, &use_ccache)) != 0) goto error_return; } if (!in_creds) { if ((retval = krb5_copy_principal(context, server, &creds.server))) goto error_return; if (client) retval = krb5_copy_principal(context, client, &creds.client); else retval = krb5_cc_get_principal(context, use_ccache, &creds.client); if (retval) { krb5_free_principal(context, creds.server); goto error_return; } /* creds.times.endtime = 0; -- memset 0 takes care of this zero means "as long as possible" */ /* creds.keyblock.enctype = 0; -- as well as this. zero means no session enctype preference */ in_creds = &creds; } if (!in_creds->ticket.length) { /* Solaris Kerberos */ if ((retval = krb5_get_credentials(context, 0, use_ccache, in_creds, &credsp)) != 0) goto error_return; credspout = credsp; } else { credsp = in_creds; } if (ap_req_options & AP_OPTS_USE_SUBKEY) { /* Provide some more fodder for random number code. This isn't strong cryptographically; the point here is not to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ char rnd_data[1024]; GETPEERNAME_ARG3_TYPE len2; krb5_data d; d.length = sizeof (rnd_data); d.data = rnd_data; len2 = sizeof (rnd_data); if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data, &len2) == 0) { d.length = len2; /* Solaris Kerberos */ (void) krb5_c_random_seed (context, &d); } len2 = sizeof (rnd_data); if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data, &len2) == 0) { d.length = len2; /* Solaris Kerberos */ (void) krb5_c_random_seed (context, &d); } } /* Solaris Kerberos */ if ((retval = krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, credsp, &outbuf)) != 0) goto error_return; /* * First write the length of the AP_REQ message, then write * the message itself. */ retval = krb5_write_message(context, fd, &outbuf); free(outbuf.data); if (retval) goto error_return; /* * Now, read back a message. If it was a null message (the * length was zero) then there was no error. If not, we the * authentication was rejected, and we need to return the * error structure. */ /* Solaris Kerberos */ if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) goto error_return; if (inbuf.length) { if (error) { /* Solaris Kerberos */ if ((retval = krb5_rd_error(context, &inbuf, error)) != 0) { krb5_xfree(inbuf.data); goto error_return; } } retval = KRB5_SENDAUTH_REJECTED; krb5_xfree(inbuf.data); goto error_return; } /* * If we asked for mutual authentication, we should now get a * length field, followed by a AP_REP message */ if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) { krb5_ap_rep_enc_part *repl = 0; /* Solaris Kerberos */ if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) goto error_return; /* Solaris Kerberos */ if ((retval = krb5_rd_rep(context, *auth_context, &inbuf, &repl)) != 0) { if (repl) krb5_free_ap_rep_enc_part(context, repl); krb5_xfree(inbuf.data); goto error_return; } krb5_xfree(inbuf.data); /* * If the user wants to look at the AP_REP message, * copy it for them. */ if (rep_result) *rep_result = repl; else krb5_free_ap_rep_enc_part(context, repl); } retval = 0; /* Normal return */ if (out_creds) { *out_creds = credsp; credspout = NULL; } error_return: krb5_free_cred_contents(context, &creds); if (credspout != NULL) krb5_free_creds(context, credspout); /* Solaris Kerberos */ if (!ccache && use_ccache) (void) krb5_cc_close(context, use_ccache); return(retval); }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( OM_uint32 *minor_status, gss_const_cred_id_t input_cred_handle, gss_const_name_t desired_name, const gss_OID desired_mech, gss_cred_usage_t cred_usage, OM_uint32 initiator_time_req, OM_uint32 acceptor_time_req, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec) { krb5_context context; OM_uint32 ret, lifetime; gsskrb5_cred cred, handle; krb5_const_principal dname; handle = NULL; cred = (gsskrb5_cred)input_cred_handle; dname = (krb5_const_principal)desired_name; GSSAPI_KRB5_INIT (&context); if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { *minor_status = 0; return GSS_S_BAD_MECH; } if (cred == NULL && output_cred_handle == NULL) { *minor_status = 0; return GSS_S_NO_CRED; } if (cred == NULL) { /* XXX standard conformance failure */ *minor_status = 0; return GSS_S_NO_CRED; } /* check if requested output usage is compatible with output usage */ if (output_cred_handle != NULL) { HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = GSS_KRB5_S_G_BAD_USAGE; return(GSS_S_FAILURE); } } /* check that we have the same name */ if (dname != NULL && krb5_principal_compare(context, dname, cred->principal) != FALSE) { if (output_cred_handle) HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = 0; return GSS_S_BAD_NAME; } /* make a copy */ if (output_cred_handle) { krb5_error_code kret; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = ENOMEM; return (GSS_S_FAILURE); } handle->usage = cred_usage; handle->lifetime = cred->lifetime; handle->principal = NULL; handle->keytab = NULL; handle->ccache = NULL; handle->mechanisms = NULL; HEIMDAL_MUTEX_init(&handle->cred_id_mutex); ret = GSS_S_FAILURE; kret = krb5_copy_principal(context, cred->principal, &handle->principal); if (kret) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); free(handle); *minor_status = kret; return GSS_S_FAILURE; } if (cred->keytab) { char *name = NULL; ret = GSS_S_FAILURE; kret = krb5_kt_get_full_name(context, cred->keytab, &name); if (kret) { *minor_status = kret; goto failure; } kret = krb5_kt_resolve(context, name, &handle->keytab); krb5_xfree(name); if (kret){ *minor_status = kret; goto failure; } } if (cred->ccache) { const char *type, *name; char *type_name = NULL; ret = GSS_S_FAILURE; type = krb5_cc_get_type(context, cred->ccache); if (type == NULL){ *minor_status = ENOMEM; goto failure; } if (strcmp(type, "MEMORY") == 0) { ret = krb5_cc_new_unique(context, type, NULL, &handle->ccache); if (ret) { *minor_status = ret; goto failure; } ret = krb5_cc_copy_cache(context, cred->ccache, handle->ccache); if (ret) { *minor_status = ret; goto failure; } } else { name = krb5_cc_get_name(context, cred->ccache); if (name == NULL) { *minor_status = ENOMEM; goto failure; } kret = asprintf(&type_name, "%s:%s", type, name); if (kret < 0 || type_name == NULL) { *minor_status = ENOMEM; goto failure; } kret = krb5_cc_resolve(context, type_name, &handle->ccache); free(type_name); if (kret) { *minor_status = kret; goto failure; } } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret) goto failure; ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret) goto failure; } HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, NULL, &lifetime, NULL, actual_mechs); if (ret) goto failure; if (initiator_time_rec) *initiator_time_rec = lifetime; if (acceptor_time_rec) *acceptor_time_rec = lifetime; if (output_cred_handle) { *output_cred_handle = (gss_cred_id_t)handle; } *minor_status = 0; return ret; failure: if (handle) { if (handle->principal) krb5_free_principal(context, handle->principal); if (handle->keytab) krb5_kt_close(context, handle->keytab); if (handle->ccache) krb5_cc_destroy(context, handle->ccache); if (handle->mechanisms) gss_release_oid_set(NULL, &handle->mechanisms); free(handle); } if (output_cred_handle) HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); return ret; }
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; }
static krb5_error_code krb5_mk_ncred_basic(krb5_context context, krb5_creds **ppcreds, krb5_int32 nppcreds, krb5_key key, krb5_replay_data *replaydata, krb5_address *local_addr, krb5_address *remote_addr, krb5_cred *pcred) { krb5_cred_enc_part credenc; krb5_error_code retval; size_t size; int i; credenc.magic = KV5M_CRED_ENC_PART; credenc.s_address = 0; credenc.r_address = 0; if (local_addr) krb5_copy_addr(context, local_addr, &credenc.s_address); if (remote_addr) krb5_copy_addr(context, remote_addr, &credenc.r_address); credenc.nonce = replaydata->seq; credenc.usec = replaydata->usec; credenc.timestamp = replaydata->timestamp; /* Get memory for creds and initialize it */ size = sizeof(krb5_cred_info *) * (nppcreds + 1); credenc.ticket_info = (krb5_cred_info **) calloc(1, size); if (credenc.ticket_info == NULL) return ENOMEM; /* * For each credential in the list, initialize a cred info * structure and copy the ticket into the ticket list. */ for (i = 0; i < nppcreds; i++) { credenc.ticket_info[i] = calloc(1, sizeof(krb5_cred_info)); if (credenc.ticket_info[i] == NULL) { retval = ENOMEM; goto cleanup; } credenc.ticket_info[i+1] = NULL; credenc.ticket_info[i]->magic = KV5M_CRED_INFO; credenc.ticket_info[i]->times = ppcreds[i]->times; credenc.ticket_info[i]->flags = ppcreds[i]->ticket_flags; if ((retval = decode_krb5_ticket(&ppcreds[i]->ticket, &pcred->tickets[i]))) goto cleanup; if ((retval = krb5_copy_keyblock(context, &ppcreds[i]->keyblock, &credenc.ticket_info[i]->session))) goto cleanup; if ((retval = krb5_copy_principal(context, ppcreds[i]->client, &credenc.ticket_info[i]->client))) goto cleanup; if ((retval = krb5_copy_principal(context, ppcreds[i]->server, &credenc.ticket_info[i]->server))) goto cleanup; if ((retval = krb5_copy_addresses(context, ppcreds[i]->addresses, &credenc.ticket_info[i]->caddrs))) goto cleanup; } /* * NULL terminate the lists. */ pcred->tickets[i] = NULL; /* encrypt the credential encrypted part */ retval = encrypt_credencpart(context, &credenc, key, &pcred->enc_part); cleanup: krb5_free_cred_enc_part(context, &credenc); return retval; }
krb5_error_code find_principal_in_keytab(krb5_context ctx, krb5_keytab keytab, const char *pattern_primary, const char *pattern_realm, krb5_principal *princ) { krb5_error_code kerr; krb5_error_code kt_err; krb5_error_code kerr_d; krb5_kt_cursor cursor; krb5_keytab_entry entry; bool principal_found = false; memset(&cursor, 0, sizeof(cursor)); kerr = krb5_kt_start_seq_get(ctx, keytab, &cursor); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "krb5_kt_start_seq_get failed.\n"); return kerr; } DEBUG(SSSDBG_TRACE_ALL, "Trying to find principal %s@%s in keytab.\n", pattern_primary, pattern_realm); memset(&entry, 0, sizeof(entry)); while ((kt_err = krb5_kt_next_entry(ctx, keytab, &entry, &cursor)) == 0) { principal_found = match_principal(ctx, entry.principal, pattern_primary, pattern_realm); if (principal_found) { break; } kerr = sss_krb5_free_keytab_entry_contents(ctx, &entry); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to free keytab entry.\n"); } memset(&entry, 0, sizeof(entry)); } /* Close the keytab here. Even though we're using cursors, the file * handle is stored in the krb5_keytab structure, and it gets * overwritten by other keytab calls, creating a leak. */ kerr = krb5_kt_end_seq_get(ctx, keytab, &cursor); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "krb5_kt_end_seq_get failed.\n"); goto done; } if (!principal_found) { kerr = KRB5_KT_NOTFOUND; DEBUG(SSSDBG_TRACE_FUNC, "No principal matching %s@%s found in keytab.\n", pattern_primary, pattern_realm); goto done; } /* check if we got any errors from krb5_kt_next_entry */ if (kt_err != 0 && kt_err != KRB5_KT_END) { DEBUG(SSSDBG_CRIT_FAILURE, "Error while reading keytab.\n"); goto done; } kerr = krb5_copy_principal(ctx, entry.principal, princ); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "krb5_copy_principal failed.\n"); goto done; } kerr = 0; done: kerr_d = sss_krb5_free_keytab_entry_contents(ctx, &entry); if (kerr_d != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to free keytab entry.\n"); } return kerr; }
static int create_krb5_tickets (krb5_context context, krb5_keytab kt) { krb5_error_code ret; krb5_keytab_entry entry; krb5_creds cred; krb5_enctype etype; krb5_ccache ccache; memset (&cred, 0, sizeof(cred)); ret = krb5_string_to_enctype (context, enc_type, &etype); if (ret) krb5_err (context, 1, ret, "krb5_string_to_enctype"); ret = krb5_kt_get_entry (context, kt, server_principal, 0, etype, &entry); if (ret) krb5_err (context, 1, ret, "krb5_kt_get_entry"); /* * setup cred */ ret = krb5_copy_principal (context, client_principal, &cred.client); if (ret) krb5_err (context, 1, ret, "krb5_copy_principal"); ret = krb5_copy_principal (context, server_principal, &cred.server); if (ret) krb5_err (context, 1, ret, "krb5_copy_principal"); krb5_generate_random_keyblock(context, etype, &cred.session); cred.times.authtime = time(NULL); cred.times.starttime = time(NULL); cred.times.endtime = time(NULL) + expiration_time; cred.times.renew_till = 0; krb5_data_zero(&cred.second_ticket); ret = krb5_get_all_client_addrs (context, &cred.addresses); if (ret) krb5_err (context, 1, ret, "krb5_get_all_client_addrs"); cred.flags.b = ticket_flags; /* * Encode encrypted part of ticket */ encode_ticket (context, &entry.keyblock, etype, entry.vno, &cred); /* * Write to cc */ if (ccache_str) { ret = krb5_cc_resolve(context, ccache_str, &ccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_resolve"); } else { ret = krb5_cc_default (context, &ccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_default"); } ret = krb5_cc_initialize (context, ccache, cred.client); if (ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred (context, ccache, &cred); if (ret) krb5_err (context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents (context, &cred); krb5_cc_close (context, ccache); return 0; }
static krb5_error_code get_cred_kdc(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_addresses *addresses, krb5_creds *in_creds, krb5_creds *krbtgt, krb5_principal impersonate_principal, Ticket *second_ticket, krb5_creds *out_creds) { TGS_REQ req; krb5_data enc; krb5_data resp; krb5_kdc_rep rep; KRB_ERROR error; krb5_error_code ret; unsigned nonce; krb5_keyblock *subkey = NULL; size_t len = 0; Ticket second_ticket_data; METHOD_DATA padata; krb5_data_zero(&resp); krb5_data_zero(&enc); padata.val = NULL; padata.len = 0; krb5_generate_random_block(&nonce, sizeof(nonce)); nonce &= 0xffffffff; if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ ret = decode_Ticket(in_creds->second_ticket.data, in_creds->second_ticket.length, &second_ticket_data, &len); if(ret) return ret; second_ticket = &second_ticket_data; } if (impersonate_principal) { krb5_crypto crypto; PA_S4U2Self self; krb5_data data; void *buf; size_t size = 0; self.name = impersonate_principal->name; self.realm = impersonate_principal->realm; self.auth = estrdup("Kerberos"); ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); if (ret) { free(self.auth); goto out; } ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); if (ret) { free(self.auth); krb5_data_free(&data); goto out; } ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, data.data, data.length, &self.cksum); krb5_crypto_destroy(context, crypto); krb5_data_free(&data); if (ret) { free(self.auth); goto out; } ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); free(self.auth); free_Checksum(&self.cksum); if (ret) goto out; if (len != size) krb5_abortx(context, "internal asn1 error"); ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); if (ret) goto out; } ret = init_tgs_req (context, id, addresses, flags, second_ticket, in_creds, krbtgt, nonce, &padata, &subkey, &req); if (ret) goto out; ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); if (ret) goto out; if(enc.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* don't free addresses */ req.req_body.addresses = NULL; free_TGS_REQ(&req); /* * Send and receive */ { krb5_sendto_ctx stctx; ret = krb5_sendto_ctx_alloc(context, &stctx); if (ret) return ret; krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); ret = krb5_sendto_context (context, stctx, &enc, krbtgt->server->name.name_string.val[1], &resp); krb5_sendto_ctx_free(context, stctx); } if(ret) goto out; memset(&rep, 0, sizeof(rep)); if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) { unsigned eflags = 0; ret = krb5_copy_principal(context, in_creds->client, &out_creds->client); if(ret) goto out2; ret = krb5_copy_principal(context, in_creds->server, &out_creds->server); if(ret) goto out2; /* this should go someplace else */ out_creds->times.endtime = in_creds->times.endtime; /* XXX should do better testing */ if (flags.b.constrained_delegation || impersonate_principal) eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; ret = _krb5_extract_ticket(context, &rep, out_creds, &krbtgt->session, NULL, 0, &krbtgt->addresses, nonce, eflags, NULL, decrypt_tkt_with_subkey, subkey); out2: krb5_free_kdc_rep(context, &rep); } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_message(context); } else { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_clear_error_message(context); } out: if (second_ticket == &second_ticket_data) free_Ticket(&second_ticket_data); free_METHOD_DATA(&padata); krb5_data_free(&resp); krb5_data_free(&enc); if(subkey) krb5_free_keyblock(context, subkey); return ret; }
int Condor_Auth_Kerberos :: init_user() { int rc = TRUE; krb5_error_code code; krb5_ccache ccache = (krb5_ccache) NULL; krb5_creds mcreds; memset(&mcreds, 0, sizeof(mcreds)); dprintf(D_SECURITY, "Acquiring credential for user\n"); //------------------------------------------ // First, try the default credential cache //------------------------------------------ ccname_ = strdup(krb5_cc_default_name(krb_context_)); if ((code = krb5_cc_resolve(krb_context_, ccname_, &ccache))) { goto error; } //------------------------------------------ // Get principal info //------------------------------------------ if ((code = krb5_cc_get_principal(krb_context_, ccache, &krb_principal_))) { goto error; } if ((code = krb5_copy_principal(krb_context_,krb_principal_,&mcreds.client))){ goto error; } if ((code = krb5_copy_principal(krb_context_, server_, &mcreds.server))) { goto error; } dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre mcreds->client is '%s'\n", mcreds.client); dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre mcreds->server is '%s'\n", mcreds.server); if (creds_) { dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre creds_->client is '%s'\n", creds_->client); dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre creds_->server is '%s'\n", creds_->server); } else { dprintf ( D_FULLDEBUG, "init_user: pre creds_ is NULL\n"); } if ((code = krb5_get_credentials(krb_context_, 0, ccache, &mcreds, &creds_))) { goto error; } dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post mcreds->client is '%s'\n", mcreds.client); dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post mcreds->server is '%s'\n", mcreds.server); if (creds_) { dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post creds_->client is '%s'\n", creds_->client); dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post creds_->server is '%s'\n", creds_->server); } else { dprintf ( D_FULLDEBUG, "init_user: post creds_ is NULL\n"); } dprintf(D_SECURITY, "Successfully located credential cache\n"); rc = TRUE; goto cleanup; error: dprintf( D_ALWAYS, "KERBEROS: %s\n", error_message(code) ); rc = FALSE; cleanup: krb5_free_cred_contents(krb_context_, &mcreds); if (ccache) { // maybe should destroy this krb5_cc_close(krb_context_, ccache); } return rc; }