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; }
static OM_uint32 import_uuid_name(OM_uint32 *minor_status, gss_const_OID mech, const gss_buffer_t input_name_buffer, gss_const_OID input_name_type, gss_name_t *output_name) { krb5_context context; krb5_error_code ret; krb5_principal princ; char uuid[36 + 1]; GSSAPI_KRB5_INIT(&context); if (input_name_buffer->length < sizeof(uuid) - 1) { *minor_status = 0; return GSS_S_BAD_NAME; } memcpy(uuid, input_name_buffer->value, sizeof(uuid) - 1); uuid[sizeof(uuid) - 1] = '\0'; /* validate that uuid is only uuid chars and the right length*/ if (strspn(uuid, "0123456789abcdefABCDEF-") != 36) { *minor_status = 0; return GSS_S_BAD_NAME; } ret = krb5_make_principal(context, &princ, "UUID", uuid, NULL); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } krb5_principal_set_type(context, princ, KRB5_NT_CACHE_UUID); *output_name = (gss_name_t)princ; *minor_status = 0; return GSS_S_COMPLETE; }
static OM_uint32 import_hostbased_name(OM_uint32 *minor_status, krb5_context context, const gss_buffer_t input_name_buffer, gss_name_t *output_name) { krb5_principal princ = NULL; krb5_error_code kerr; char *tmp, *p, *host = NULL; tmp = malloc (input_name_buffer->length + 1); if (tmp == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy (tmp, input_name_buffer->value, input_name_buffer->length); tmp[input_name_buffer->length] = '\0'; p = strchr (tmp, '@'); if (p != NULL) { *p = '\0'; host = p + 1; } kerr = krb5_make_principal(context, &princ, "", tmp, host, NULL); free (tmp); *minor_status = kerr; if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) return GSS_S_BAD_NAME; else if (kerr) return GSS_S_FAILURE; krb5_principal_set_type(context, princ, KRB5_NT_SRV_HST); *output_name = (gss_name_t)princ; return 0; }
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 ntlm_service(void *ctx, const heim_idata *req, const heim_icred cred, heim_ipc_complete complete, heim_sipc_call cctx) { NTLMRequest2 ntq; unsigned char sessionkey[16]; heim_idata rep = { 0, NULL }; krb5_context context = ctx; hdb_entry_ex *user = NULL; Key *key = NULL; NTLMReply ntp; size_t size; int ret; char *domain; kdc_log(context, config, 1, "digest-request: uid=%d", (int)heim_ipc_cred_get_uid(cred)); if (heim_ipc_cred_get_uid(cred) != 0) { (*complete)(cctx, EPERM, NULL); return; } ntp.success = 0; ntp.flags = 0; ntp.sessionkey = NULL; ret = decode_NTLMRequest2(req->data, req->length, &ntq, NULL); if (ret) goto failed; /* XXX forward to NetrLogonSamLogonEx() if not a local domain */ if (strcmp(ntq.loginDomainName, "BUILTIN") == 0) { domain = ntq.loginDomainName; } else if (strcmp(ntq.loginDomainName, "") == 0) { domain = "BUILTIN"; } else { ret = EINVAL; goto failed; } kdc_log(context, config, 1, "digest-request: user=%s/%s", ntq.loginUserName, domain); if (ntq.lmchallenge.length != 8) goto failed; if (ntq.ntChallengeResponce.length == 0) goto failed; { krb5_principal client; ret = krb5_make_principal(context, &client, domain, ntq.loginUserName, NULL); if (ret) goto failed; krb5_principal_set_type(context, client, KRB5_NT_NTLM); ret = _kdc_db_fetch(context, config, client, HDB_F_GET_CLIENT, NULL, NULL, &user); krb5_free_principal(context, client); if (ret) goto failed; ret = hdb_enctype2key(context, &user->entry, ETYPE_ARCFOUR_HMAC_MD5, &key); if (ret) { krb5_set_error_message(context, ret, "NTLM missing arcfour key"); goto failed; } } kdc_log(context, config, 2, "digest-request: found user, processing ntlm request", ret); if (ntq.ntChallengeResponce.length != 24) { struct ntlm_buf infotarget, answer; answer.length = ntq.ntChallengeResponce.length; answer.data = ntq.ntChallengeResponce.data; ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, key->key.keyvalue.length, ntq.loginUserName, ntq.loginDomainName, 0, ntq.lmchallenge.data, &answer, &infotarget, sessionkey); if (ret) { goto failed; } free(infotarget.data); /* XXX verify info target */ } else { struct ntlm_buf answer; if (ntq.flags & NTLM_NEG_NTLM2_SESSION) { unsigned char sessionhash[MD5_DIGEST_LENGTH]; EVP_MD_CTX *md5ctx; /* the first first 8 bytes is the challenge, what is the other 16 bytes ? */ if (ntq.lmChallengeResponce.length != 24) goto failed; md5ctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(md5ctx, EVP_md5(), NULL); EVP_DigestUpdate(md5ctx, ntq.lmchallenge.data, 8); EVP_DigestUpdate(md5ctx, ntq.lmChallengeResponce.data, 8); EVP_DigestFinal_ex(md5ctx, sessionhash, NULL); EVP_MD_CTX_destroy(md5ctx); memcpy(ntq.lmchallenge.data, sessionhash, ntq.lmchallenge.length); } ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, key->key.keyvalue.length, ntq.lmchallenge.data, &answer); if (ret) goto failed; if (ntq.ntChallengeResponce.length != answer.length || memcmp(ntq.ntChallengeResponce.data, answer.data, answer.length) != 0) { free(answer.data); ret = EINVAL; goto failed; } free(answer.data); { EVP_MD_CTX *ctx; ctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(ctx, EVP_md4(), NULL); EVP_DigestUpdate(ctx, key->key.keyvalue.data, key->key.keyvalue.length); EVP_DigestFinal_ex(ctx, sessionkey, NULL); EVP_MD_CTX_destroy(ctx); } } ntp.success = 1; ASN1_MALLOC_ENCODE(NTLMReply, rep.data, rep.length, &ntp, &size, ret); if (ret) goto failed; if (rep.length != size) abort(); failed: kdc_log(context, config, 1, "digest-request: %d", ret); (*complete)(cctx, ret, &rep); free(rep.data); free_NTLMRequest2(&ntq); if (user) _kdc_free_ent (context, user); }
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; }
static OM_uint32 import_hostbased_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 = NULL; krb5_error_code kerr; char *tmp, *p, *host = NULL, *realm = NULL; if (gss_oid_equal(mech, GSS_PKU2U_MECHANISM)) realm = KRB5_PKU2U_REALM_NAME; else realm = KRB5_GSS_REFERALS_REALM_NAME; /* should never hit the network */ 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'; p = strchr (tmp, '@'); if (p != NULL && p[1] != '\0') { size_t len; *p = '\0'; host = p + 1; /* * Squash any trailing . on the hostname since that is jolly * good to have when looking up a DNS name (qualified), but * its no good to have in the kerberos principal since those * are supposed to be in qualified format already. */ len = strlen(host); if (len > 0 && host[len - 1] == '.') host[len - 1] = '\0'; } else { host = KRB5_GSS_HOSTBASED_SERVICE_NAME; } kerr = krb5_make_principal(context, &princ, realm, tmp, host, NULL); free (tmp); *minor_status = kerr; if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) return GSS_S_BAD_NAME; else if (kerr) return GSS_S_FAILURE; krb5_principal_set_type(context, princ, KRB5_NT_GSS_HOSTBASED_SERVICE); *output_name = (gss_name_t)princ; return 0; }