KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_verify_user_opt(krb5_context context, krb5_principal principal, const char *password, krb5_verify_opt *opt) { krb5_error_code ret; if(opt && (opt->flags & KRB5_VERIFY_LREALMS)) { krb5_realm *realms, *r; ret = krb5_get_default_realms (context, &realms); if (ret) return ret; ret = KRB5_CONFIG_NODEFREALM; for (r = realms; *r != NULL && ret != 0; ++r) { ret = krb5_principal_set_realm(context, principal, *r); if (ret) { krb5_free_host_realm (context, realms); return ret; } ret = verify_user_opt_int(context, principal, password, opt); } krb5_free_host_realm (context, realms); if(ret) return ret; } else ret = verify_user_opt_int(context, principal, password, opt); return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_init_creds_set_service(krb5_context context, krb5_init_creds_context ctx, const char *service) { krb5_const_realm client_realm; krb5_principal principal; krb5_error_code ret; client_realm = krb5_principal_get_realm (context, ctx->cred.client); if (service) { ret = krb5_parse_name (context, service, &principal); if (ret) return ret; krb5_principal_set_realm (context, principal, client_realm); } else { ret = krb5_make_principal(context, &principal, client_realm, KRB5_TGS_NAME, client_realm, NULL); if (ret) return ret; } krb5_free_principal(context, ctx->cred.server); ctx->cred.server = principal; return 0; }
static void set_princ_realm(krb5_context context, krb5_principal principal, const char *realm) { krb5_error_code ret; if ((ret = krb5_principal_set_realm(context, principal, realm)) != 0) krb5_err(context, 1, ret, "krb5_principal_set_realm"); }
OM_uint32 _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, int use_dns, krb5_const_principal sourcename, gss_name_t targetname, krb5_principal *out) { krb5_principal p = (krb5_principal)targetname; krb5_error_code ret; char *hostname = NULL, *service; *minor_status = 0; /* If its not a hostname */ if (krb5_principal_get_type(context, p) != MAGIC_HOSTBASED_NAME_TYPE) { ret = krb5_copy_principal(context, p, out); } else if (!use_dns) { ret = krb5_copy_principal(context, p, out); if (ret) goto out; krb5_principal_set_type(context, *out, KRB5_NT_SRV_HST); if (sourcename) ret = krb5_principal_set_realm(context, *out, sourcename->realm); } else { if (p->name.name_string.len == 0) return GSS_S_BAD_NAME; else if (p->name.name_string.len > 1) hostname = p->name.name_string.val[1]; service = p->name.name_string.val[0]; ret = krb5_sname_to_principal(context, hostname, service, KRB5_NT_SRV_HST, out); } out: if (ret) { *minor_status = ret; return GSS_S_FAILURE; } return 0; }
/* * Given the krb5_principal from kadmind, convert it to the corresponding * principal in Active Directory. This may involve removing ad_base_instance * and always involves changing the realm. Returns a Kerberos error code. */ static krb5_error_code get_ad_principal(kadm5_hook_modinfo *config, krb5_context ctx, krb5_const_principal principal, krb5_principal *ad_principal) { krb5_error_code code; int ncomp; /* * Set ad_principal to NULL to start. We fall back on copy and realm * setting if we don't have to build it, and use whether it's NULL as a * flag. */ *ad_principal = NULL; /* Get the number of components. */ ncomp = krb5_principal_get_num_comp(ctx, principal); /* See if this is an ad_base_instance principal that needs a rewrite. */ if (config->ad_base_instance != NULL && ncomp == 2) { const char *base, *instance; instance = krb5_principal_get_comp_string(ctx, principal, 1); if (strcmp(instance, config->ad_base_instance) == 0) { base = krb5_principal_get_comp_string(ctx, principal, 0); code = krb5_build_principal(ctx, ad_principal, strlen(config->ad_realm), config->ad_realm, base, (char *) 0); if (code != 0) return code; } } /* Otherwise, copy the principal and set the realm. */ if (*ad_principal == NULL) { code = krb5_copy_principal(ctx, principal, ad_principal); if (code != 0) return code; krb5_principal_set_realm(ctx, *ad_principal, config->ad_realm); } return 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; }
static krb5_error_code tkt_referral_recv(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 outcred, mcred; unsigned long n; _krb5_debugx(context, 10, "tkt_referral_recv: %s", ctx->server_name); memset(&outcred, 0, sizeof(outcred)); ret = parse_tgs_rep(context, ctx, in, &outcred); if (ret) { _krb5_debugx(context, 10, "tkt_referral_recv: parse_tgs_rep %d", ret); tkt_reset(context, ctx); ctx->state = tkt_capath_init; return 0; } /* * Check if we found the right ticket */ if (krb5_principal_compare_any_realm(context, ctx->next.server, outcred.server)) { ret = krb5_copy_creds(context, &outcred, &ctx->cred); if (ret) return (ctx->error = ret); krb5_free_cred_contents(context, &outcred); ctx->state = tkt_store; return 0; } if (!krb5_principal_is_krbtgt(context, outcred.server)) { krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US, N_("Got back an non krbtgt " "ticket referrals", "")); krb5_free_cred_contents(context, &outcred); ctx->state = tkt_capath_init; return 0; } _krb5_debugx(context, 10, "KDC for realm %s sends a referrals to %s", ctx->tgt.server->realm, outcred.server->name.name_string.val[1]); /* * check if there is a loop */ krb5_cc_clear_mcred(&mcred); mcred.server = outcred.server; for (n = 0; ctx->tickets && ctx->tickets[n]; n++) { if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, &mcred, ctx->tickets[n])) { _krb5_debugx(context, 5, "Referral from %s loops back to realm %s", ctx->tgt.server->realm, outcred.server->realm); ctx->state = tkt_capath_init; return 0; } } #define MAX_KDC_REFERRALS_LOOPS 15 if (n > MAX_KDC_REFERRALS_LOOPS) { ctx->state = tkt_capath_init; return 0; } /* * filter out ok-as-delegate if needed */ if (ctx->ok_as_delegate == 0 || outcred.flags.b.ok_as_delegate == 0) { ctx->ok_as_delegate = 0; outcred.flags.b.ok_as_delegate = 0; } /* add to iteration cache */ ret = add_cred(context, &outcred, &ctx->tickets); if (ret) { ctx->state = tkt_capath_init; return 0; } /* set up next server to talk to */ krb5_free_cred_contents(context, &ctx->tgt); ctx->tgt = outcred; /* * Setup next target principal to target */ ret = krb5_principal_set_realm(context, ctx->next.server, ctx->tgt.server->realm); if (ret) { ctx->state = tkt_capath_init; return 0; } ctx->state = tkt_referral_send; return 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; }
static int propagate_database (krb5_context context, int type, const char *database_name, HDB *db, krb5_ccache ccache, int optidx, int argc, char **argv) { krb5_principal server; krb5_error_code ret; int i, failed = 0; for(i = optidx; i < argc; i++){ krb5_auth_context auth_context; int fd; struct prop_data pd; krb5_data data; char *port, portstr[NI_MAXSERV]; char *host = argv[i]; port = strchr(host, ':'); if(port == NULL) { snprintf(portstr, sizeof(portstr), "%u", ntohs(krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT))); port = portstr; } else *port++ = '\0'; fd = open_socket(context, host, port); if(fd < 0) { failed++; krb5_warn (context, errno, "connect %s", host); continue; } ret = krb5_sname_to_principal(context, argv[i], HPROP_NAME, KRB5_NT_SRV_HST, &server); if(ret) { failed++; krb5_warn(context, ret, "krb5_sname_to_principal(%s)", host); close(fd); continue; } if (local_realm) { krb5_realm my_realm; krb5_get_default_realm(context,&my_realm); krb5_principal_set_realm(context,server,my_realm); krb5_xfree(my_realm); } auth_context = NULL; ret = krb5_sendauth(context, &auth_context, &fd, HPROP_VERSION, NULL, server, AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, NULL, /* in_data */ NULL, /* in_creds */ ccache, NULL, NULL, NULL); krb5_free_principal(context, server); if(ret) { failed++; krb5_warn(context, ret, "krb5_sendauth (%s)", host); close(fd); goto next_host; } pd.context = context; pd.auth_context = auth_context; pd.sock = fd; ret = iterate (context, database_name, db, type, &pd); if (ret) { krb5_warnx(context, "iterate to host %s failed", host); failed++; goto next_host; } krb5_data_zero (&data); ret = krb5_write_priv_message(context, auth_context, &fd, &data); if(ret) { krb5_warn(context, ret, "krb5_write_priv_message"); failed++; goto next_host; } ret = krb5_read_priv_message(context, auth_context, &fd, &data); if(ret) { krb5_warn(context, ret, "krb5_read_priv_message: %s", host); failed++; goto next_host; } else krb5_data_free (&data); next_host: krb5_auth_con_free(context, auth_context); close(fd); } if (failed) return 1; return 0; }
krb5_error_code KRB5_LIB_FUNCTION krb5_init_creds_step(krb5_context context, krb5_init_creds_context ctx, krb5_data *in, krb5_data *out, krb5_krbhst_info *hostinfo, unsigned int *flags) { krb5_error_code ret; size_t len; size_t size; krb5_data_zero(out); if (ctx->as_req.req_body.cname == NULL) { ret = init_as_req(context, ctx->flags, &ctx->cred, ctx->addrs, ctx->etypes, &ctx->as_req); if (ret) { free_init_creds_ctx(context, ctx); return ret; } } #define MAX_PA_COUNTER 10 if (ctx->pa_counter > MAX_PA_COUNTER) { krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, N_("Looping %d times while getting " "initial credentials", ""), ctx->pa_counter); return KRB5_GET_IN_TKT_LOOP; } ctx->pa_counter++; /* Lets process the input packet */ if (in && in->length) { krb5_kdc_rep rep; memset(&rep, 0, sizeof(rep)); ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); if (ret == 0) { krb5_keyblock *key = NULL; unsigned eflags = EXTRACT_TICKET_AS_REQ; if (ctx->flags.canonicalize) { eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; eflags |= EXTRACT_TICKET_MATCH_REALM; } if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; ret = process_pa_data_to_key(context, ctx, &ctx->cred, &ctx->as_req, &rep.kdc_rep, hostinfo, &key); if (ret) { free_AS_REP(&rep.kdc_rep); goto out; } ret = _krb5_extract_ticket(context, &rep, &ctx->cred, key, NULL, KRB5_KU_AS_REP_ENC_PART, NULL, ctx->nonce, eflags, NULL, NULL); krb5_free_keyblock(context, key); *flags = 0; if (ret == 0) ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); free_AS_REP(&rep.kdc_rep); free_EncASRepPart(&rep.enc_part); return ret; } else { /* let's try to parse it as a KRB-ERROR */ free_KRB_ERROR(&ctx->error); ret = krb5_rd_error(context, in, &ctx->error); if(ret && in->length && ((char*)in->data)[0] == 4) ret = KRB5KRB_AP_ERR_V4_REPLY; if (ret) goto out; ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); /* * If no preauth was set and KDC requires it, give it one * more try. */ if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) { free_METHOD_DATA(&ctx->md); memset(&ctx->md, 0, sizeof(ctx->md)); if (ctx->error.e_data) { ret = decode_METHOD_DATA(ctx->error.e_data->data, ctx->error.e_data->length, &ctx->md, NULL); if (ret) krb5_set_error_message(context, ret, N_("Failed to decode METHOD-DATA", "")); } else { krb5_set_error_message(context, ret, N_("Preauth required but no preauth " "options send by KDC", "")); } } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) { /* * Try adapt to timeskrew when we are using pre-auth, and * if there was a time skew, try again. */ krb5_set_real_time(context, ctx->error.stime, -1); if (context->kdc_sec_offset) ret = 0; } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { /* client referal to a new realm */ if (ctx->error.crealm == NULL) { krb5_set_error_message(context, ret, N_("Got a client referral, not but no realm", "")); goto out; } ret = krb5_principal_set_realm(context, ctx->cred.client, *ctx->error.crealm); } if (ret) goto out; } } if (ctx->as_req.padata) { free_METHOD_DATA(ctx->as_req.padata); free(ctx->as_req.padata); ctx->as_req.padata = NULL; } /* Set a new nonce. */ ctx->as_req.req_body.nonce = ctx->nonce; /* fill_in_md_data */ ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx, &ctx->md, &ctx->as_req.padata, ctx->prompter, ctx->prompter_data); if (ret) goto out; krb5_data_free(&ctx->req_buffer); ASN1_MALLOC_ENCODE(AS_REQ, ctx->req_buffer.data, ctx->req_buffer.length, &ctx->as_req, &len, ret); if (ret) goto out; if(len != ctx->req_buffer.length) krb5_abortx(context, "internal error in ASN.1 encoder"); out->data = ctx->req_buffer.data; out->length = ctx->req_buffer.length; *flags = 1; return 0; out: return ret; }
static OM_uint32 import_krb5_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_principal princ; krb5_error_code ret; char *tmp; GSSAPI_KRB5_INIT (&context); 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'; if (tmp[0] == '@') { princ = calloc(1, sizeof(*princ)); if (princ == NULL) { free(tmp); *minor_status = ENOMEM; return GSS_S_FAILURE; } princ->realm = strdup(&tmp[1]); if (princ->realm == NULL) { free(tmp); free(princ); return GSS_S_FAILURE; } } else { ret = krb5_parse_name (context, tmp, &princ); if (ret) { free(tmp); *minor_status = ret; if (ret == KRB5_PARSE_ILLCHAR || ret == KRB5_PARSE_MALFORMED) return GSS_S_BAD_NAME; return GSS_S_FAILURE; } } if (mech && gss_oid_equal(mech, GSS_PKU2U_MECHANISM) && strchr(tmp, '@') == NULL) krb5_principal_set_realm(context, princ, KRB5_PKU2U_REALM_NAME); free(tmp); if (princ->name.name_string.len == 2 && gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL)) krb5_principal_set_type(context, princ, KRB5_NT_GSS_HOSTBASED_SERVICE); *output_name = (gss_name_t)princ; return GSS_S_COMPLETE; }