static krb5_error_code get_cred_kdc_capath(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_error_code ret; krb5_const_realm client_realm, server_realm, try_realm; client_realm = krb5_principal_get_realm(context, in_creds->client); server_realm = krb5_principal_get_realm(context, in_creds->server); try_realm = client_realm; ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, try_realm, impersonate_principal, second_ticket, out_creds, ret_tgts); if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) { try_realm = krb5_config_get_string(context, NULL, "capaths", client_realm, server_realm, NULL); if (try_realm != NULL && strcmp(try_realm, client_realm)) { ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, try_realm, impersonate_principal, second_ticket, out_creds, ret_tgts); } } return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_set_password_using_ccache(krb5_context context, krb5_ccache ccache, char *newpw, krb5_principal targprinc, int *result_code, krb5_data *result_code_string, krb5_data *result_string) { krb5_creds creds, *credsp; krb5_error_code ret; krb5_principal principal = NULL; *result_code = KRB5_KPASSWD_MALFORMED; result_code_string->data = result_string->data = NULL; result_code_string->length = result_string->length = 0; memset(&creds, 0, sizeof(creds)); if (targprinc == NULL) { ret = krb5_cc_get_principal(context, ccache, &principal); if (ret) return ret; } else principal = targprinc; ret = krb5_make_principal(context, &creds.server, krb5_principal_get_realm(context, principal), "kadmin", "changepw", NULL); if (ret) goto out; ret = krb5_cc_get_principal(context, ccache, &creds.client); if (ret) { krb5_free_principal(context, creds.server); goto out; } ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); krb5_free_principal(context, creds.server); krb5_free_principal(context, creds.client); if (ret) goto out; ret = krb5_set_password(context, credsp, newpw, principal, result_code, result_code_string, result_string); krb5_free_creds(context, credsp); return ret; out: if (targprinc == NULL) krb5_free_principal(context, principal); return ret; }
static krb5_boolean match_local_principals(krb5_context context, krb5_principal principal, const char *luser) { krb5_error_code ret; krb5_realm *realms, *r; krb5_boolean result = FALSE; /* multi-component principals can never match */ if(krb5_principal_get_comp_string(context, principal, 1) != NULL) return FALSE; ret = krb5_get_default_realms (context, &realms); if (ret) return FALSE; for (r = realms; *r != NULL; ++r) { if(strcmp(krb5_principal_get_realm(context, principal), *r) != 0) continue; if(strcmp(krb5_principal_get_comp_string(context, principal, 0), luser) == 0) { result = TRUE; break; } } krb5_free_host_realm (context, realms); return result; }
static krb5_error_code afslog_uid_int(struct kafs_data *data, const char *cell, const char *rh, uid_t uid, const char *homedir) { krb5_error_code ret; struct kafs_token kt; krb5_principal princ; const char *trealm; /* ticket realm */ struct krb5_kafs_data *d = data->data; if (cell == 0 || cell[0] == 0) return _kafs_afslog_all_local_cells (data, uid, homedir); ret = krb5_cc_get_principal (d->context, d->id, &princ); if (ret) return ret; trealm = krb5_principal_get_realm (d->context, princ); kt.ticket = NULL; ret = _kafs_get_cred(data, cell, d->realm, trealm, uid, &kt); krb5_free_principal (d->context, princ); if(ret == 0) { ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len); free(kt.ticket); } return ret; }
static krb5_error_code verify_user_opt_int(krb5_context context, krb5_principal principal, const char *password, krb5_verify_opt *vopt) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, NULL, krb5_principal_get_realm(context, principal), opt); ret = krb5_get_init_creds_password (context, &cred, principal, password, krb5_prompter_posix, NULL, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if(ret) return ret; #define OPT(V, D) ((vopt && (vopt->V)) ? (vopt->V) : (D)) return verify_common (context, principal, OPT(ccache, NULL), OPT(keytab, NULL), vopt ? vopt->secure : TRUE, OPT(service, "host"), cred); #undef OPT }
static krb5_error_code find_db (krb5_context context, char **dbname, char **mkey, krb5_const_principal principal) { krb5_const_realm realm = krb5_principal_get_realm(context, principal); krb5_error_code ret; struct hdb_dbinfo *head, *dbinfo = NULL; *dbname = *mkey = NULL; ret = hdb_get_dbinfo(context, &head); if (ret) return ret; while ((dbinfo = hdb_dbinfo_get_next(head, dbinfo)) != NULL) { const char *p = hdb_dbinfo_get_realm(context, dbinfo); if (p && strcmp (realm, p) == 0) { p = hdb_dbinfo_get_dbname(context, dbinfo); if (p) *dbname = strdup(p); p = hdb_dbinfo_get_mkey_file(context, dbinfo); if (p) *mkey = strdup(p); break; } } hdb_free_dbinfo(context, &head); if (*dbname == NULL) *dbname = strdup(HDB_DEFAULT_DB); return 0; }
static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, const char *name, struct drsuapi_DsNameInfo1 *info1) { krb5_error_code ret; krb5_principal principal; /* perhaps it's a principal with a realm, so return the right 'domain only' response */ const char *realm; ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal); if (ret) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } /* This isn't an allocation assignemnt, so it is free'ed with the krb5_free_principal */ realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal); info1->dns_domain_name = talloc_strdup(mem_ctx, realm); krb5_free_principal(smb_krb5_context->krb5_context, principal); W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name); info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY; return WERR_OK; }
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; }
krb5_error_code KRB5_LIB_FUNCTION krb5_fwd_tgt_creds (krb5_context context, krb5_auth_context auth_context, const char *hostname, krb5_principal client, krb5_principal server, krb5_ccache ccache, int forwardable, krb5_data *out_data) { krb5_flags flags = 0; krb5_creds creds; krb5_error_code ret; krb5_const_realm client_realm; flags |= KDC_OPT_FORWARDED; if (forwardable) flags |= KDC_OPT_FORWARDABLE; if (hostname == NULL && krb5_principal_get_type(context, server) == KRB5_NT_SRV_HST) { const char *inst = krb5_principal_get_comp_string(context, server, 0); const char *host = krb5_principal_get_comp_string(context, server, 1); if (inst != NULL && strcmp(inst, "host") == 0 && host != NULL && krb5_principal_get_comp_string(context, server, 2) == NULL) hostname = host; } client_realm = krb5_principal_get_realm(context, client); memset (&creds, 0, sizeof(creds)); creds.client = client; ret = krb5_build_principal(context, &creds.server, strlen(client_realm), client_realm, KRB5_TGS_NAME, client_realm, NULL); if (ret) return ret; ret = krb5_get_forwarded_creds (context, auth_context, ccache, flags, hostname, &creds, out_data); return ret; }
/* * Obtain renewed credentials for the given service using the existing * credentials in the provided ticket cache. */ krb5_error_code krb5_get_renewed_creds(krb5_context ctx, krb5_creds *creds, krb5_const_principal client, krb5_ccache ccache, const char *in_tkt_service) { krb5_kdc_flags flags; krb5_creds in, *old = NULL, *out = NULL; krb5_error_code code; flags.i = 0; flags.b.renewable = 1; flags.b.renew = 1; memset(&in, 0, sizeof(in)); code = krb5_copy_principal(ctx, client, &in.client); if (code != 0) goto done; if (in_tkt_service == NULL) { const char *realm; realm = krb5_principal_get_realm(ctx, client); if (realm == NULL) { code = KRB5_CONFIG_NODEFREALM; goto done; } code = krb5_build_principal(ctx, &in.server, strlen(realm), realm, "krbtgt", realm, (const char *) NULL); if (code != 0) goto done; } else { code = krb5_parse_name(ctx, in_tkt_service, &in.server); if (code != 0) goto done; } code = krb5_get_credentials(ctx, 0, ccache, &in, &old); if (code != 0) goto done; flags.b.forwardable = old->flags.b.forwardable; flags.b.proxiable = old->flags.b.proxiable; code = krb5_get_kdc_cred(ctx, ccache, flags, NULL, NULL, old, &out); if (code != 0) goto done; #ifdef HAVE_KRB5_COPY_CREDS_CONTENTS code = krb5_copy_creds_contents(ctx, out, creds); krb5_free_creds(ctx, out); #else /* No good alternative -- hope this works. */ *creds = *out; free(out); #endif done: krb5_free_cred_contents(ctx, &in); if (old != NULL) krb5_free_creds(ctx, old); return code; }
static char *cifs_krb5_principal_get_realm(krb5_context context __attribute__ ((unused)), krb5_principal principal) { #ifdef HAVE_KRB5_PRINCIPAL_GET_REALM /* Heimdal */ return krb5_principal_get_realm(context, principal); #elif defined(krb5_princ_realm) /* MIT */ krb5_data *realm; realm = krb5_princ_realm(context, principal); return (char *)realm->data; #else return NULL; #endif }
void sss_krb5_princ_realm(krb5_context context, krb5_const_principal princ, const char **realm, int *len) { const char *realm_str = krb5_principal_get_realm(context, princ); if (realm_str != NULL) { *realm = realm_str; *len = strlen(realm_str); } else { *realm = NULL; *len = 0; } }
static krb5_error_code get_server(krb5_context context, krb5_principal client, const char *server, krb5_principal *princ) { krb5_const_realm realm; if (server) return krb5_parse_name(context, server, princ); realm = krb5_principal_get_realm(context, client); return krb5_make_principal(context, princ, realm, KRB5_TGS_NAME, realm, NULL); }
static void parse_name_realm(krb5_context context, const char *name, int flags, const char *realm, krb5_principal *princ) { krb5_error_code ret; if (realm) flags |= KRB5_PRINCIPAL_PARSE_NO_DEF_REALM; if ((ret = krb5_parse_name_flags(context, name, flags, princ)) != 0) krb5_err(context, 1, ret, "krb5_parse_name_flags"); if (realm && krb5_principal_get_realm(context, *princ) == NULL) set_princ_realm(context, *princ, realm); }
static kadm5_ret_t get_default(kadm5_server_context *context, krb5_principal princ, kadm5_principal_ent_t def) { kadm5_ret_t ret; krb5_principal def_principal; krb5_const_realm realm = krb5_principal_get_realm(context->context, princ); ret = krb5_make_principal(context->context, &def_principal, realm, "default", NULL); if (ret) return ret; ret = kadm5_s_get_principal(context, def_principal, def, KADM5_PRINCIPAL_NORMAL_MASK); krb5_free_principal (context->context, def_principal); return ret; }
static int get_v5_user_realm(krb5_context context,char *realm) { static krb5_principal client_principal = 0; krb5_error_code code; if (!_krb425_ccache) { code = krb5_cc_default(context, &_krb425_ccache); if (code) return(code); } if (!client_principal) { code = krb5_cc_get_principal(context, _krb425_ccache, &client_principal); if (code) return(code); } strncpy(realm, krb5_principal_get_realm(context, client_principal), REALM_SZ - 1); realm[REALM_SZ - 1] = 0; return(KSUCCESS); }
OM_uint32 __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, krb5_context context, krb5_ccache id, krb5_principal principal, OM_uint32 *lifetime) { krb5_creds in_cred, out_cred; krb5_const_realm realm; krb5_error_code kret; memset(&in_cred, 0, sizeof(in_cred)); in_cred.client = principal; realm = krb5_principal_get_realm(context, principal); if (realm == NULL) { _gsskrb5_clear_status (); *minor_status = KRB5_PRINC_NOMATCH; /* XXX */ return GSS_S_FAILURE; } kret = krb5_make_principal(context, &in_cred.server, realm, KRB5_TGS_NAME, realm, NULL); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } kret = krb5_cc_retrieve_cred(context, id, 0, &in_cred, &out_cred); krb5_free_principal(context, in_cred.server); if (kret) { *minor_status = 0; *lifetime = 0; return GSS_S_COMPLETE; } *lifetime = out_cred.times.endtime; krb5_free_cred_contents(context, &out_cred); return GSS_S_COMPLETE; }
static int check_for_tgt (krb5_context context, krb5_ccache ccache, krb5_principal principal, time_t *expiration) { krb5_error_code ret; krb5_creds pattern; krb5_creds creds; krb5_const_realm client_realm; int expired; krb5_cc_clear_mcred(&pattern); client_realm = krb5_principal_get_realm(context, principal); ret = krb5_make_principal (context, &pattern.server, client_realm, KRB5_TGS_NAME, client_realm, NULL); if (ret) krb5_err (context, 1, ret, "krb5_make_principal"); pattern.client = principal; ret = krb5_cc_retrieve_cred (context, ccache, 0, &pattern, &creds); krb5_free_principal (context, pattern.server); if (ret) { if (ret == KRB5_CC_END) return 1; krb5_err (context, 1, ret, "krb5_cc_retrieve_cred"); } expired = time(NULL) > creds.times.endtime; if (expiration) *expiration = creds.times.endtime; krb5_free_cred_contents (context, &creds); return expired; }
static krb5_error_code LDAP_principal2message(krb5_context context, HDB * db, krb5_principal princ, LDAPMessage ** msg) { char *name, *name_short = NULL; krb5_error_code ret; krb5_realm *r, *r0; *msg = NULL; ret = krb5_unparse_name(context, princ, &name); if (ret) return ret; ret = krb5_get_default_realms(context, &r0); if(ret) { free(name); return ret; } for (r = r0; *r != NULL; r++) { if(strcmp(krb5_principal_get_realm(context, princ), *r) == 0) { ret = krb5_unparse_name_short(context, princ, &name_short); if (ret) { krb5_free_host_realm(context, r0); free(name); return ret; } break; } } krb5_free_host_realm(context, r0); ret = LDAP__lookup_princ(context, db, name, name_short, msg); free(name); free(name_short); return ret; }
static krb5_error_code get_new_cache(krb5_context context, krb5_principal client, const char *password, krb5_prompter_fct prompter, const char *keytab, const char *server_name, krb5_ccache *ret_cache) { krb5_error_code ret; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache id; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, "kadmin", krb5_principal_get_realm(context, client), opt); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); if(password == NULL && prompter == NULL) { krb5_keytab kt; if(keytab == NULL) ret = krb5_kt_default(context, &kt); else ret = krb5_kt_resolve(context, keytab, &kt); if(ret) { krb5_get_init_creds_opt_free(context, opt); return ret; } ret = krb5_get_init_creds_keytab (context, &cred, client, kt, 0, server_name, opt); krb5_kt_close(context, kt); } else { ret = krb5_get_init_creds_password (context, &cred, client, password, prompter, NULL, 0, server_name, opt); } krb5_get_init_creds_opt_free(context, opt); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: return KADM5_BAD_PASSWORD; default: return ret; } ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if(ret) return ret; ret = krb5_cc_initialize (context, id, cred.client); if (ret) return ret; ret = krb5_cc_store_cred (context, id, &cred); if (ret) return ret; krb5_free_cred_contents (context, &cred); *ret_cache = id; return 0; }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache = NULL; krb5_init_creds_context ctx = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_prompter_fct prompter = krb5_prompter_posix; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (!interactive) prompter = NULL; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) { krb5_warnx(context, "Failed to open the password file %s", password_file); return errno; } if (fgets(passwd, sizeof(passwd), f) == NULL) { krb5_warnx(context, N_("Failed to read password from file %s", ""), password_file); fclose(f); return EINVAL; /* XXX Need a better error */ } if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #ifdef __APPLE__ if (passwd[0] == '\0') { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm, strlen(name), name, &length, &buffer, NULL); free(name); if (osret == noErr && length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } nopassword: do { } while(0); } #endif memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_alloc"); goto out; } krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if (forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable(opt, forwardable_flag); if (proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable(opt, proxiable_flag); if (anonymous_flag) krb5_get_init_creds_opt_set_anonymous(opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, prompter, NULL, passwd); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_set_pkinit"); goto out; } if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time(renewstr, "s"); if (renew < 0) errx(1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life(opt, renew); } if (ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ticket_life); if (start_str) { int tmp = parse_time(start_str, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if (etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if (enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if (ret) errx(1, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx); if (ret) { krb5_warn(context, ret, "krb5_init_creds_init"); goto out; } if (server_str) { ret = krb5_init_creds_set_service(context, ctx, server_str); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_service"); goto out; } } if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) { krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)"); goto out; } ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); goto out; } } if (use_keytab || keytab_str) { ret = krb5_init_creds_set_keytab(context, ctx, kt); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_keytab"); goto out; } } else if (pk_user_id || ent_user_id || anonymous_flag) { } else if (!interactive && passwd[0] == '\0') { static int already_warned = 0; if (!already_warned) krb5_warnx(context, "Not interactive, failed to get " "initial ticket"); krb5_get_init_creds_opt_free(context, opt); already_warned = 1; return 0; } else { if (passwd[0] == '\0') { char *p, *prompt; int aret = 0; ret = krb5_unparse_name(context, principal, &p); if (ret) errx(1, "failed to generate passwd prompt: not enough memory"); aret = asprintf(&prompt, N_("%s's Password: "******""), p); free(p); if (aret == -1) errx(1, "failed to generate passwd prompt: not enough memory"); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free(prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, ctx, passwd); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_password"); goto out; } } } ret = krb5_init_creds_get(context, ctx); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5_GET_IN_TKT_LOOP: krb5_warnx(context, N_("Password incorrect", "")); goto out; case KRB5KRB_AP_ERR_V4_REPLY: krb5_warnx(context, N_("Looks like a Kerberos 4 reply", "")); goto out; case KRB5KDC_ERR_KEY_EXPIRED: krb5_warnx(context, N_("Password expired", "")); goto out; default: krb5_warn(context, ret, "krb5_get_init_creds"); goto out; } krb5_process_last_request(context, opt, ctx); ret = krb5_init_creds_get_creds(context, ctx, &cred); if (ret) { krb5_warn(context, ret, "krb5_init_creds_get_creds"); goto out; } if (ticket_life != 0) { if (abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { char life[64]; unparse_time_approx(cred.times.endtime - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life); } } if (renew_life) { if (abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { char life[64]; unparse_time_approx(cred.times.renew_till - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket renewable lifetime is %s", ""), life); } } krb5_free_cred_contents(context, &cred); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) { krb5_warn(context, ret, "krb5_cc_new_unique"); goto out; } ret = krb5_init_creds_store(context, ctx, tempccache); if (ret) { krb5_warn(context, ret, "krb5_init_creds_store"); goto out; } krb5_init_creds_free(context, ctx); ctx = NULL; ret = krb5_cc_move(context, tempccache, ccache); if (ret) { krb5_warn(context, ret, "krb5_cc_move"); goto out; } tempccache = NULL; if (switch_cache_flags) krb5_cc_switch(context, ccache); #ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); #endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } out: krb5_get_init_creds_opt_free(context, opt); if (ctx) krb5_init_creds_free(context, ctx); if (tempccache) krb5_cc_close(context, tempccache); if (enctype) free(enctype); return ret; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache ccache; krb5_principal principal = NULL; int optidx = 0; krb5_deltat ticket_life = 0; #ifdef HAVE_SIGACTION struct sigaction sa; #endif setprogname(argv[0]); setlocale(LC_ALL, ""); bindtextdomain("heimdal_kuser", HEIMDAL_LOCALEDIR); textdomain("heimdal_kuser"); ret = krb5_init_context(&context); if (ret == KRB5_CONFIG_BADFORMAT) errx(1, "krb5_init_context failed to parse configuration file"); else if (ret) errx(1, "krb5_init_context failed: %d", ret); if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage(0); if (version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; /* * Open the keytab now, we use the keytab to determine the principal's * realm when the requested principal has no realm. */ if (use_keytab || keytab_str) { if (keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) krb5_err(context, 1, ret, "resolving keytab"); } if (pk_enterprise_flag) { ret = krb5_pk_enterprise_cert(context, pk_user_id, argv[0], &principal, &ent_user_id); if (ret) krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); pk_user_id = NULL; } else if (anonymous_flag) { ret = krb5_make_principal(context, &principal, argv[0], KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); if (ret) krb5_err(context, 1, ret, "krb5_make_principal"); krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN); } else if (use_keytab || keytab_str) { get_princ_kt(context, &principal, argv[0]); } else { get_princ(context, &principal, argv[0]); } if (fcache_version) krb5_set_fcache_version(context, fcache_version); if (renewable_flag == -1) /* this seems somewhat pointless, but whatever */ krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "renewable", FALSE, &renewable_flag); if (do_afslog == -1) krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "afslog", TRUE, &do_afslog); if (cred_cache) ret = krb5_cc_resolve(context, cred_cache, &ccache); else { if (argc > 1) { char s[1024]; ret = krb5_cc_new_unique(context, NULL, NULL, &ccache); if (ret) krb5_err(context, 1, ret, "creating cred cache"); snprintf(s, sizeof(s), "%s:%s", krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache)); setenv("KRB5CCNAME", s, 1); } else { ret = krb5_cc_cache_match(context, principal, &ccache); if (ret) { const char *type; ret = krb5_cc_default(context, &ccache); if (ret) krb5_err(context, 1, ret, N_("resolving credentials cache", "")); /* * Check if the type support switching, and we do, * then do that instead over overwriting the current * default credential */ type = krb5_cc_get_type(context, ccache); if (krb5_cc_support_switch(context, type)) { krb5_cc_close(context, ccache); ret = get_switched_ccache(context, type, principal, &ccache); } } } } if (ret) krb5_err(context, 1, ret, N_("resolving credentials cache", "")); #ifndef NO_AFS if (argc > 1 && k_hasafs()) k_setpag(); #endif if (lifetime) { int tmp = parse_time(lifetime, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), lifetime); ticket_life = tmp; } if (addrs_flag == 0 && extra_addresses.num_strings > 0) krb5_errx(context, 1, N_("specifying both extra addresses and " "no addresses makes no sense", "")); { int i; krb5_addresses addresses; memset(&addresses, 0, sizeof(addresses)); for(i = 0; i < extra_addresses.num_strings; i++) { ret = krb5_parse_address(context, extra_addresses.strings[i], &addresses); if (ret == 0) { krb5_add_extra_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } free_getarg_strings(&extra_addresses); } if (renew_flag || validate_flag) { ret = renew_validate(context, renew_flag, validate_flag, ccache, server_str, ticket_life); #ifndef NO_AFS if (ret == 0 && server_str == NULL && do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); #endif exit(ret != 0); } ret = get_new_tickets(context, principal, ccache, ticket_life, 1); if (ret) exit(1); #ifndef NO_AFS if (ret == 0 && server_str == NULL && do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); #endif if (argc > 1) { struct renew_ctx ctx; time_t timeout; timeout = ticket_lifetime(context, ccache, principal, server_str, NULL) / 2; ctx.context = context; ctx.ccache = ccache; ctx.principal = principal; ctx.ticket_life = ticket_life; ctx.timeout = timeout; #ifdef HAVE_SIGACTION memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_handler = handle_siginfo; sigaction(SIGINFO, &sa, NULL); #endif ret = simple_execvp_timed(argv[1], argv+1, renew_func, &ctx, timeout); #define EX_NOEXEC 126 #define EX_NOTFOUND 127 if (ret == EX_NOEXEC) krb5_warnx(context, N_("permission denied: %s", ""), argv[1]); else if (ret == EX_NOTFOUND) krb5_warnx(context, N_("command not found: %s", ""), argv[1]); krb5_cc_destroy(context, ccache); #ifndef NO_AFS if (k_hasafs()) k_unlog(); #endif } else { krb5_cc_close(context, ccache); ret = 0; } krb5_free_principal(context, principal); if (kt) krb5_kt_close(context, kt); krb5_free_context(context); return ret; }
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 tgs_build_reply(krb5_context context, krb5_kdc_configuration *config, KDC_REQ *req, KDC_REQ_BODY *b, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, krb5_ticket *ticket, krb5_data *reply, const char *from, const char **e_text, AuthorizationData *auth_data, const struct sockaddr *from_addr, int datagram_reply) { krb5_error_code ret; krb5_principal cp = NULL, sp = NULL; krb5_principal client_principal = NULL; char *spn = NULL, *cpn = NULL; hdb_entry_ex *server = NULL, *client = NULL; EncTicketPart *tgt = &ticket->ticket; KRB5SignedPathPrincipals *spp = NULL; const EncryptionKey *ekey; krb5_keyblock sessionkey; krb5_kvno kvno; krb5_data rspac; int cross_realm = 0; PrincipalName *s; Realm r; int nloop = 0; EncTicketPart adtkt; char opt_str[128]; int require_signedpath = 0; memset(&sessionkey, 0, sizeof(sessionkey)); memset(&adtkt, 0, sizeof(adtkt)); krb5_data_zero(&rspac); s = b->sname; r = b->realm; if(b->kdc_options.enc_tkt_in_skey){ Ticket *t; hdb_entry_ex *uu; krb5_principal p; Key *uukey; if(b->additional_tickets == NULL || b->additional_tickets->len == 0){ ret = KRB5KDC_ERR_BADOPTION; /* ? */ kdc_log(context, config, 0, "No second ticket present in request"); goto out; } t = &b->additional_tickets->val[0]; if(!get_krbtgt_realm(&t->sname)){ kdc_log(context, config, 0, "Additional ticket is not a ticket-granting ticket"); ret = KRB5KDC_ERR_POLICY; goto out; } _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); ret = _kdc_db_fetch(context, config, p, HDB_F_GET_CLIENT|HDB_F_GET_SERVER, NULL, &uu); krb5_free_principal(context, p); if(ret){ if (ret == HDB_ERR_NOENTRY) ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; } ret = hdb_enctype2key(context, &uu->entry, t->enc_part.etype, &uukey); if(ret){ _kdc_free_ent(context, uu); ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ goto out; } ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0); _kdc_free_ent(context, uu); if(ret) goto out; ret = verify_flags(context, config, &adtkt, spn); if (ret) goto out; s = &adtkt.cname; r = adtkt.crealm; } _krb5_principalname2krb5_principal(context, &sp, *s, r); ret = krb5_unparse_name(context, sp, &spn); if (ret) goto out; _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm); ret = krb5_unparse_name(context, cp, &cpn); if (ret) goto out; unparse_flags (KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(), opt_str, sizeof(opt_str)); if(*opt_str) kdc_log(context, config, 0, "TGS-REQ %s from %s for %s [%s]", cpn, from, spn, opt_str); else kdc_log(context, config, 0, "TGS-REQ %s from %s for %s", cpn, from, spn); /* * Fetch server */ server_lookup: ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server); if(ret){ const char *new_rlm; Realm req_rlm; krb5_realm *realms; if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) { if(nloop++ < 2) { new_rlm = find_rpath(context, tgt->crealm, req_rlm); if(new_rlm) { kdc_log(context, config, 5, "krbtgt for realm %s " "not found, trying %s", req_rlm, new_rlm); krb5_free_principal(context, sp); free(spn); krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, new_rlm, NULL); ret = krb5_unparse_name(context, sp, &spn); if (ret) goto out; goto server_lookup; } } } else if(need_referral(context, sp, &realms)) { if (strcmp(realms[0], sp->realm) != 0) { kdc_log(context, config, 5, "Returning a referral to realm %s for " "server %s that was not found", realms[0], spn); krb5_free_principal(context, sp); free(spn); krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, realms[0], NULL); ret = krb5_unparse_name(context, sp, &spn); if (ret) goto out; krb5_free_host_realm(context, realms); goto server_lookup; } krb5_free_host_realm(context, realms); } kdc_log(context, config, 0, "Server not found in database: %s: %s", spn, krb5_get_err_text(context, ret)); if (ret == HDB_ERR_NOENTRY) ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; } ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client); if(ret) { const char *krbtgt_realm; /* * If the client belongs to the same realm as our krbtgt, it * should exist in the local database. * */ krbtgt_realm = krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1); if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) { if (ret == HDB_ERR_NOENTRY) ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; kdc_log(context, config, 1, "Client no longer in database: %s", cpn); goto out; } kdc_log(context, config, 1, "Client not found in database: %s: %s", cpn, krb5_get_err_text(context, ret)); cross_realm = 1; } /* * Check that service is in the same realm as the krbtgt. If its * not the same, its someone that is using a uni-directional trust * backward. */ if (strcmp(krb5_principal_get_realm(context, sp), krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1)) != 0) { char *tpn; ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn); kdc_log(context, config, 0, "Request with wrong krbtgt: %s", (ret == 0) ? tpn : "<unknown>"); if(ret == 0) free(tpn); ret = KRB5KRB_AP_ERR_NOT_US; goto out; } /* * */ client_principal = cp; if (client) { const PA_DATA *sdata; int i = 0; sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF); if (sdata) { krb5_crypto crypto; krb5_data datack; PA_S4U2Self self; char *selfcpn = NULL; const char *str; ret = decode_PA_S4U2Self(sdata->padata_value.data, sdata->padata_value.length, &self, NULL); if (ret) { kdc_log(context, config, 0, "Failed to decode PA-S4U2Self"); goto out; } ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack); if (ret) goto out; ret = krb5_crypto_init(context, &tgt->key, 0, &crypto); if (ret) { free_PA_S4U2Self(&self); krb5_data_free(&datack); kdc_log(context, config, 0, "krb5_crypto_init failed: %s", krb5_get_err_text(context, ret)); goto out; } ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, datack.data, datack.length, &self.cksum); krb5_data_free(&datack); krb5_crypto_destroy(context, crypto); if (ret) { free_PA_S4U2Self(&self); kdc_log(context, config, 0, "krb5_verify_checksum failed for S4U2Self: %s", krb5_get_err_text(context, ret)); goto out; } ret = _krb5_principalname2krb5_principal(context, &client_principal, self.name, self.realm); free_PA_S4U2Self(&self); if (ret) goto out; ret = krb5_unparse_name(context, client_principal, &selfcpn); if (ret) goto out; /* * Check that service doing the impersonating is * requesting a ticket to it-self. */ if (krb5_principal_compare(context, cp, sp) != TRUE) { kdc_log(context, config, 0, "S4U2Self: %s is not allowed " "to impersonate some other user " "(tried for user %s to service %s)", cpn, selfcpn, spn); free(selfcpn); ret = KRB5KDC_ERR_BADOPTION; /* ? */ goto out; } /* * If the service isn't trusted for authentication to * delegation, remove the forward flag. */ if (client->entry.flags.trusted_for_delegation) { str = "[forwardable]"; } else { b->kdc_options.forwardable = 0; str = ""; } kdc_log(context, config, 0, "s4u2self %s impersonating %s to " "service %s %s", cpn, selfcpn, spn, str); free(selfcpn); } } /* * Constrained delegation */ if (client != NULL && b->additional_tickets != NULL && b->additional_tickets->len != 0 && b->kdc_options.enc_tkt_in_skey == 0) { Key *clientkey; Ticket *t; char *str; t = &b->additional_tickets->val[0]; ret = hdb_enctype2key(context, &client->entry, t->enc_part.etype, &clientkey); if(ret){ ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ goto out; } ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0); if (ret) { kdc_log(context, config, 0, "failed to decrypt ticket for " "constrained delegation from %s to %s ", spn, cpn); goto out; } /* check that ticket is valid */ if (adtkt.flags.forwardable == 0) { kdc_log(context, config, 0, "Missing forwardable flag on ticket for " "constrained delegation from %s to %s ", spn, cpn); ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ goto out; } ret = check_constrained_delegation(context, config, client, sp); if (ret) { kdc_log(context, config, 0, "constrained delegation from %s to %s not allowed", spn, cpn); goto out; } ret = _krb5_principalname2krb5_principal(context, &client_principal, adtkt.cname, adtkt.crealm); if (ret) goto out; ret = krb5_unparse_name(context, client_principal, &str); if (ret) goto out; ret = verify_flags(context, config, &adtkt, str); if (ret) { free(str); goto out; } /* * Check KRB5SignedPath in authorization data and add new entry to * make sure servers can't fake a ticket to us. */ ret = check_KRB5SignedPath(context, config, krbtgt, &adtkt, &spp, 1); if (ret) { kdc_log(context, config, 0, "KRB5SignedPath check from service %s failed " "for delegation to %s for client %s " "from %s failed with %s", spn, str, cpn, from, krb5_get_err_text(context, ret)); free(str); goto out; } kdc_log(context, config, 0, "constrained delegation for %s " "from %s to %s", str, cpn, spn); free(str); /* * Also require that the KDC have issue the service's krbtgt * used to do the request. */ require_signedpath = 1; } /* * Check flags */ ret = _kdc_check_flags(context, config, client, cpn, server, spn, FALSE); if(ret) goto out; if((b->kdc_options.validate || b->kdc_options.renew) && !krb5_principal_compare(context, krbtgt->entry.principal, server->entry.principal)){ kdc_log(context, config, 0, "Inconsistent request."); ret = KRB5KDC_ERR_SERVER_NOMATCH; goto out; } /* check for valid set of addresses */ if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) { ret = KRB5KRB_AP_ERR_BADADDR; kdc_log(context, config, 0, "Request from wrong address"); goto out; } /* * Select enctype, return key and kvno. */ { krb5_enctype etype; if(b->kdc_options.enc_tkt_in_skey) { int i; ekey = &adtkt.key; for(i = 0; i < b->etype.len; i++) if (b->etype.val[i] == adtkt.key.keytype) break; if(i == b->etype.len) { krb5_clear_error_string(context); return KRB5KDC_ERR_ETYPE_NOSUPP; } etype = b->etype.val[i]; kvno = 0; } else { Key *skey; ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len, &skey, &etype); if(ret) { kdc_log(context, config, 0, "Server (%s) has no support for etypes", spp); return ret; } ekey = &skey->key; kvno = server->entry.kvno; } ret = krb5_generate_random_keyblock(context, etype, &sessionkey); if (ret) goto out; } /* check PAC if not cross realm and if there is one */ if (!cross_realm) { Key *tkey; ret = hdb_enctype2key(context, &krbtgt->entry, krbtgt_etype, &tkey); if(ret) { kdc_log(context, config, 0, "Failed to find key for krbtgt PAC check"); goto out; } ret = check_PAC(context, config, client_principal, client, server, ekey, &tkey->key, tgt, &rspac, &require_signedpath); if (ret) { kdc_log(context, config, 0, "Verify PAC failed for %s (%s) from %s with %s", spn, cpn, from, krb5_get_err_text(context, ret)); goto out; } } /* also check the krbtgt for signature */ ret = check_KRB5SignedPath(context, config, krbtgt, tgt, &spp, require_signedpath); if (ret) { kdc_log(context, config, 0, "KRB5SignedPath check failed for %s (%s) from %s with %s", spn, cpn, from, krb5_get_err_text(context, ret)); goto out; } /* * */ ret = tgs_make_reply(context, config, b, client_principal, tgt, ekey, &sessionkey, kvno, auth_data, server, spn, client, cp, krbtgt, krbtgt_etype, spp, &rspac, e_text, reply); out: free(spn); free(cpn); krb5_data_free(&rspac); krb5_free_keyblock_contents(context, &sessionkey); if(server) _kdc_free_ent(context, server); if(client) _kdc_free_ent(context, client); if (client_principal && client_principal != cp) krb5_free_principal(context, client_principal); if (cp) krb5_free_principal(context, cp); if (sp) krb5_free_principal(context, sp); free_EncTicketPart(&adtkt); return ret; }
static int proto (int sock, const char *hostname, const char *service) { struct sockaddr_in remote, local; socklen_t addrlen; krb5_address remote_addr, local_addr; krb5_context context; krb5_ccache ccache; krb5_auth_context auth_context; krb5_error_code status; krb5_principal client; krb5_data data; krb5_data packet; krb5_creds mcred, cred; krb5_ticket *ticket; addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 || addrlen != sizeof(local)) err (1, "getsockname(%s)", hostname); addrlen = sizeof(remote); if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 || addrlen != sizeof(remote)) err (1, "getpeername(%s)", hostname); status = krb5_init_context(&context); if (status) errx(1, "krb5_init_context failed: %d", status); status = krb5_cc_default (context, &ccache); if (status) krb5_err(context, 1, status, "krb5_cc_default"); status = krb5_auth_con_init (context, &auth_context); if (status) krb5_err(context, 1, status, "krb5_auth_con_init"); local_addr.addr_type = AF_INET; local_addr.address.length = sizeof(local.sin_addr); local_addr.address.data = &local.sin_addr; remote_addr.addr_type = AF_INET; remote_addr.address.length = sizeof(remote.sin_addr); remote_addr.address.data = &remote.sin_addr; status = krb5_auth_con_setaddrs (context, auth_context, &local_addr, &remote_addr); if (status) krb5_err(context, 1, status, "krb5_auth_con_setaddr"); krb5_cc_clear_mcred(&mcred); status = krb5_cc_get_principal(context, ccache, &client); if(status) krb5_err(context, 1, status, "krb5_cc_get_principal"); status = krb5_make_principal(context, &mcred.server, krb5_principal_get_realm(context, client), "krbtgt", krb5_principal_get_realm(context, client), NULL); if(status) krb5_err(context, 1, status, "krb5_make_principal"); mcred.client = client; status = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred); if(status) krb5_err(context, 1, status, "krb5_cc_retrieve_cred"); { char *client_name; krb5_data data; status = krb5_unparse_name(context, cred.client, &client_name); if(status) krb5_err(context, 1, status, "krb5_unparse_name"); data.data = client_name; data.length = strlen(client_name) + 1; status = krb5_write_message(context, &sock, &data); if(status) krb5_err(context, 1, status, "krb5_write_message"); free(client_name); } status = krb5_write_message(context, &sock, &cred.ticket); if(status) krb5_err(context, 1, status, "krb5_write_message"); status = krb5_auth_con_setuserkey(context, auth_context, &cred.session); if(status) krb5_err(context, 1, status, "krb5_auth_con_setuserkey"); status = krb5_recvauth(context, &auth_context, &sock, VERSION, client, 0, NULL, &ticket); if (status) krb5_err(context, 1, status, "krb5_recvauth"); if (ticket->ticket.authorization_data) { AuthorizationData *authz; int i; printf("Authorization data:\n"); authz = ticket->ticket.authorization_data; for (i = 0; i < authz->len; i++) { printf("\ttype %d, length %lu\n", authz->val[i].ad_type, (unsigned long)authz->val[i].ad_data.length); } } data.data = "hej"; data.length = 3; krb5_data_zero (&packet); status = krb5_mk_safe (context, auth_context, &data, &packet, NULL); if (status) krb5_err(context, 1, status, "krb5_mk_safe"); status = krb5_write_message(context, &sock, &packet); if(status) krb5_err(context, 1, status, "krb5_write_message"); data.data = "hemligt"; data.length = 7; krb5_data_free (&packet); status = krb5_mk_priv (context, auth_context, &data, &packet, NULL); if (status) krb5_err(context, 1, status, "krb5_mk_priv"); status = krb5_write_message(context, &sock, &packet); if(status) krb5_err(context, 1, status, "krb5_write_message"); return 0; }
krb5_error_code kcm_ccache_acquire(krb5_context context, kcm_ccache ccache, time_t *expire) { krb5_error_code ret = 0; krb5_creds cred; krb5_const_realm realm; krb5_get_init_creds_opt *opt = NULL; krb5_ccache_data ccdata; char *in_tkt_service = NULL; *expire = 0; memset(&cred, 0, sizeof(cred)); KCM_ASSERT_VALID(ccache); /* We need a cached key or keytab to acquire credentials */ if (ccache->flags & KCM_FLAGS_USE_PASSWORD) { if (ccache->password == NULL) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_PASSWORD without password"); } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) { if (ccache->keytab == NULL) krb5_abortx(context, "kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab"); } else { kcm_log(0, "Cannot acquire initial credentials for cache %s without key", ccache->name); return KRB5_FCC_INTERNAL; } /* Fake up an internal ccache */ kcm_internal_ccache(context, ccache, &ccdata); /* Now, actually acquire the creds */ if (ccache->server != NULL) { ret = krb5_unparse_name(context, ccache->server, &in_tkt_service); if (ret) { kcm_log(0, "Failed to unparse service name for cache %s", ccache->name); return ret; } } realm = krb5_principal_get_realm(context, ccache->client); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) goto out; krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, opt); if (ccache->tkt_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ccache->tkt_life); if (ccache->renew_life != 0) krb5_get_init_creds_opt_set_renew_life(opt, ccache->renew_life); krb5_get_init_creds_opt_set_forwardable(opt, 1); if (ccache->flags & KCM_FLAGS_USE_PASSWORD) { ret = krb5_get_init_creds_password(context, &cred, ccache->client, ccache->password, NULL, NULL, 0, in_tkt_service, opt); } else { ret = krb5_get_init_creds_keytab(context, &cred, ccache->client, ccache->keytab, 0, in_tkt_service, opt); } if (ret) { const char *msg = krb5_get_error_message(context, ret); kcm_log(0, "Failed to acquire credentials for cache %s: %s", ccache->name, msg); krb5_free_error_message(context, msg); if (in_tkt_service != NULL) free(in_tkt_service); goto out; } if (in_tkt_service != NULL) free(in_tkt_service); /* Swap them in */ kcm_ccache_remove_creds_internal(context, ccache); ret = kcm_ccache_store_cred_internal(context, ccache, &cred, NULL, 0); if (ret) { const char *msg = krb5_get_error_message(context, ret); kcm_log(0, "Failed to store credentials for cache %s: %s", ccache->name, msg); krb5_free_error_message(context, msg); krb5_free_cred_contents(context, &cred); goto out; } *expire = cred.times.endtime; out: if (opt) krb5_get_init_creds_opt_free(context, opt); return 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){ if (strcmp(try_realm, client_realm) != 0) ok_as_delegate = tgts.flags.b.ok_as_delegate; *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); } else { ret = get_cred_kdc_address(context, ccache, flags, NULL, in_creds, &tgts, impersonate_principal, second_ticket, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } else if (ok_as_delegate == 0) (*out_creds)->flags.b.ok_as_delegate = 0; } krb5_free_cred_contents(context, &tgts); krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } if(krb5_realm_compare(context, in_creds->client, in_creds->server)) return not_found(context, in_creds->server, KRB5_CC_NOTFOUND); /* XXX this can loop forever */ while(1){ heim_general_string tgt_inst; ret = get_cred_kdc_capath(context, flags, ccache, &tmp_creds, NULL, NULL, &tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } /* * if either of the chain or the ok_as_delegate was stripped * by the kdc, make sure we strip it too. */ if (ok_as_delegate == 0 || tgt->flags.b.ok_as_delegate == 0) { ok_as_delegate = 0; tgt->flags.b.ok_as_delegate = 0; } ret = add_cred(context, tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } tgt_inst = tgt->server->name.name_string.val[1]; if(strcmp(tgt_inst, server_realm) == 0) break; krb5_free_principal(context, tmp_creds.server); ret = krb5_make_principal(context, &tmp_creds.server, tgt_inst, KRB5_TGS_NAME, server_realm, NULL); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = krb5_free_creds(context, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); } else { ret = get_cred_kdc_address (context, ccache, flags, NULL, in_creds, tgt, impersonate_principal, second_ticket, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } krb5_free_creds(context, tgt); return ret; }
int main(int argc, char **argv) { const char *hostname; krb5_context context; krb5_auth_context ac; krb5_error_code ret; krb5_creds cred; krb5_ccache id; krb5_data data; int optidx = 0; setprogname (argv[0]); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag){ print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (argc < 1) usage(1); hostname = argv[0]; memset(&cred, 0, sizeof(cred)); ret = krb5_init_context(&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); ret = krb5_cc_default(context, &id); if (ret) krb5_err(context, 1, ret, "krb5_cc_default failed: %d", ret); ret = krb5_auth_con_init(context, &ac); if (ret) krb5_err(context, 1, ret, "krb5_auth_con_init failed: %d", ret); krb5_auth_con_addflags(context, ac, KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, NULL); ret = krb5_cc_get_principal(context, id, &cred.client); if (ret) krb5_err(context, 1, ret, "krb5_cc_get_principal"); ret = krb5_make_principal(context, &cred.server, krb5_principal_get_realm(context, cred.client), KRB5_TGS_NAME, krb5_principal_get_realm(context, cred.client), NULL); if (ret) krb5_err(context, 1, ret, "krb5_make_principal(server)"); ret = krb5_get_forwarded_creds (context, ac, id, KDC_OPT_FORWARDABLE, hostname, &cred, &data); if (ret) krb5_err (context, 1, ret, "krb5_get_forwarded_creds"); krb5_data_free(&data); krb5_free_context(context); return 0; }
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_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; }