static void get_init_creds_opt_init( krb5_get_init_creds_opt *outOptions ) { krb5_preauthtype preauth[] = { KRB5_PADATA_ENC_TIMESTAMP }; krb5_enctype etypes[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_CRC}; krb5_get_init_creds_opt_set_address_list(outOptions, NULL); krb5_get_init_creds_opt_set_etype_list( outOptions, etypes, sizeof(etypes)/sizeof(krb5_enctype) ); krb5_get_init_creds_opt_set_preauth_list(outOptions, preauth, sizeof(preauth)/sizeof(krb5_preauthtype) ); }
krb5_get_init_creds_opt *kim_options_init_cred_options (kim_options in_options) { kim_error err = KIM_NO_ERROR; krb5_address **addresses = NULL; if (!err && !in_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_options->init_cred_context) { err = krb5_error (NULL, krb5_init_context (&in_options->init_cred_context)); } if (!err && !in_options->addressless) { err = krb5_error (in_options->init_cred_context, krb5_os_localaddr (in_options->init_cred_context, &addresses)); } if (!err && !in_options->init_cred_options) { err = krb5_error (in_options->init_cred_context, krb5_get_init_creds_opt_alloc (in_options->init_cred_context, &in_options->init_cred_options)); } if (!err) { krb5_get_init_creds_opt_set_tkt_life (in_options->init_cred_options, in_options->lifetime); if (in_options->renewal_lifetime || in_options->renewable) krb5_get_init_creds_opt_set_renew_life (in_options->init_cred_options, in_options->renewal_lifetime); krb5_get_init_creds_opt_set_forwardable (in_options->init_cred_options, in_options->forwardable); krb5_get_init_creds_opt_set_proxiable (in_options->init_cred_options, in_options->proxiable); krb5_get_init_creds_opt_set_address_list (in_options->init_cred_options, addresses); addresses = NULL; } if (addresses) { krb5_free_addresses (in_options->init_cred_context, addresses); } return !check_error (err) ? in_options->init_cred_options : NULL; }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { char *ccname; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; char *tmp_str = NULL; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int canonicalize = 0; int kdc_time_offset_usec; int ret; krberr = krb5_init_context(&context); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n")); return krberr; } DEBUG(SSSDBG_TRACE_INTERNAL, ("Kerberos context initialized\n")); krberr = set_child_debugging(context); if (krberr != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot set krb5_child debugging\n")); } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } realm_name = talloc_strdup(memctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(memctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } DEBUG(SSSDBG_TRACE_INTERNAL, ("got realm_name: [%s]\n", realm_name)); if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(memctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(memctx, princ_str); } } else { char hostname[512]; ret = gethostname(hostname, 511); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[511] = '\0'; DEBUG(SSSDBG_TRACE_LIBS, ("got hostname: [%s]\n", hostname)); ret = select_principal_from_keytab(memctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) { krberr = KRB5_KT_IOERR; goto done; } } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_CONF_SETTINGS, ("Principal name is: [%s]\n", full_princ)); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(2, ("Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } DEBUG(SSSDBG_CONF_SETTINGS, ("Using keytab [%s]\n", KEYTAB_CLEAN_NAME)); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to read keytab file [%s]: %s\n", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr))); goto done; } /* Verify the keytab */ ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to verify principal is present in the keytab\n")); krberr = KRB5_KT_IOERR; goto done; } ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); if (!ccname) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("keytab ccname: [%s]\n", ccname)); krberr = krb5_cc_resolve(context, ccname, &ccache); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); tmp_str = getenv("KRB5_CANONICALIZE"); if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { DEBUG(SSSDBG_CONF_SETTINGS, ("Will canonicalize principals\n")); canonicalize = 1; } sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr))); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("credentials initialized\n")); /* Use updated principal if changed due to canonicalization. */ krberr = krb5_cc_initialize(context, ccache, my_creds.client); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("credentials stored\n")); #ifdef HAVE_KRB5_GET_TIME_OFFSETS krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr))); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } DEBUG(SSSDBG_TRACE_INTERNAL, ("Got KDC time offset\n")); #else /* If we don't have this function, just assume no offset */ kdc_time_offset = 0; #endif krberr = 0; *ccname_out = ccname; *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (krberr != 0) KRB5_SYSLOG(krberr); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return krberr; }
/* returns boolean */ static int k5_kinit(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) { char *doing; int notix = 1; krb5_keytab keytab = 0; krb5_creds my_creds; krb5_error_code code = 0; krb5_get_init_creds_opt options; krb5_address **addresses; krb5_get_init_creds_opt_init(&options); g_memset(&my_creds, 0, sizeof(my_creds)); /* From this point on, we can goto cleanup because my_creds is initialized. */ if (opts->lifetime) { krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); } if (opts->rlife) { krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); } if (opts->forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 1); } if (opts->not_forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 0); } if (opts->proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 1); } if (opts->not_proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 0); } if (opts->addresses) { addresses = NULL; code = krb5_os_localaddr(k5->ctx, &addresses); if (code != 0) { g_printf("krb5_os_localaddr failed in k5_kinit\n"); goto cleanup; } krb5_get_init_creds_opt_set_address_list(&options, addresses); } if (opts->no_addresses) { krb5_get_init_creds_opt_set_address_list(&options, NULL); } if ((opts->action == INIT_KT) && opts->keytab_name) { code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); if (code != 0) { g_printf("krb5_kt_resolve failed in k5_kinit\n"); goto cleanup; } } switch (opts->action) { case INIT_PW: code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0, kinit_prompter, u_info, opts->starttime, opts->service_name, &options); break; case INIT_KT: code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab, opts->starttime, opts->service_name, &options); break; case VALIDATE: code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; case RENEW: code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; } if (code != 0) { doing = 0; switch (opts->action) { case INIT_PW: case INIT_KT: doing = "getting initial credentials"; break; case VALIDATE: doing = "validating credentials"; break; case RENEW: doing = "renewing credentials"; break; } if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); } else { g_printf("sesman: error while %s in k5_kinit\n", doing); } goto cleanup; } if (!opts->lifetime) { /* We need to figure out what lifetime to use for Kerberos 4. */ opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; } code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); if (code != 0) { g_printf("krb5_cc_initialize failed in k5_kinit\n"); goto cleanup; } code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); if (code != 0) { g_printf("krb5_cc_store_cred failed in k5_kinit\n"); goto cleanup; } notix = 0; cleanup: if (my_creds.client == k5->me) { my_creds.client = 0; } krb5_free_cred_contents(k5->ctx, &my_creds); if (keytab) { krb5_kt_close(k5->ctx, keytab); } return notix ? 0 : 1; }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, krb5_context context, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { int fd; char *ccname; char *ccname_dummy; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; char *tmp_str = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int canonicalize = 0; int kdc_time_offset_usec; int ret; TALLOC_CTX *tmp_ctx; char *ccname_file_dummy = NULL; char *ccname_file; mode_t old_umask; tmp_ctx = talloc_new(memctx); if (tmp_ctx == NULL) { krberr = KRB5KRB_ERR_GENERIC; goto done; } krberr = set_child_debugging(context); if (krberr != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set krb5_child debugging\n"); } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } realm_name = talloc_strdup(tmp_ctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(tmp_ctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } DEBUG(SSSDBG_TRACE_INTERNAL, "got realm_name: [%s]\n", realm_name); if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(tmp_ctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(tmp_ctx, princ_str); } } else { char hostname[HOST_NAME_MAX + 1]; ret = gethostname(hostname, HOST_NAME_MAX); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[HOST_NAME_MAX] = '\0'; DEBUG(SSSDBG_TRACE_LIBS, "got hostname: [%s]\n", hostname); ret = select_principal_from_keytab(tmp_ctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) { krberr = KRB5_KT_IOERR; goto done; } } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_CONF_SETTINGS, "Principal name is: [%s]\n", full_princ); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } DEBUG(SSSDBG_CONF_SETTINGS, "Using keytab [%s]\n", KEYTAB_CLEAN_NAME); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read keytab file [%s]: %s\n", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } /* Verify the keytab */ ret = lc_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Unable to verify principal is present in the keytab\n"); krberr = KRB5_KT_IOERR; goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); tmp_str = getenv("KRB5_CANONICALIZE"); if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { DEBUG(SSSDBG_CONF_SETTINGS, "Will canonicalize principals\n"); canonicalize = 1; } sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize); ccname_file = talloc_asprintf(tmp_ctx, "%s/ccache_%s", DB_PATH, realm_name); if (ccname_file == NULL) { krberr = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed: %s:[%d].\n", strerror(krberr), krberr); goto done; } ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX", DB_PATH, realm_name); if (ccname_file_dummy == NULL) { krberr = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed: %s:[%d].\n", strerror(krberr), krberr); goto done; } old_umask = umask(077); fd = mkstemp(ccname_file_dummy); umask(old_umask); if (fd == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "mkstemp failed: %s:[%d].\n", strerror(ret), ret); krberr = KRB5KRB_ERR_GENERIC; goto done; } /* We only care about creating a unique file name here, we don't * need the fd */ close(fd); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); krb5_kt_close(context, keytab); keytab = NULL; if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr)); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n"); ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy); ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file); if (ccname_dummy == NULL || ccname == NULL) { krberr = ENOMEM; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy); krberr = krb5_cc_resolve(context, ccname_dummy, &ccache); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } /* Use updated principal if changed due to canonicalization. */ krberr = krb5_cc_initialize(context, ccache, my_creds.client); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "credentials stored\n"); #ifdef HAVE_KRB5_GET_TIME_OFFSETS krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr)); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } DEBUG(SSSDBG_TRACE_INTERNAL, "Got KDC time offset\n"); #else /* If we don't have this function, just assume no offset */ kdc_time_offset = 0; #endif DEBUG(SSSDBG_TRACE_INTERNAL, "Renaming [%s] to [%s]\n", ccname_file_dummy, ccname_file); ret = rename(ccname_file_dummy, ccname_file); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "rename failed [%d][%s].\n", ret, strerror(ret)); goto done; } ccname_file_dummy = NULL; krberr = 0; *ccname_out = talloc_steal(memctx, ccname); *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (krberr != 0) KRB5_SYSLOG(krberr); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); if (ccname_file_dummy) { DEBUG(SSSDBG_TRACE_INTERNAL, "Unlinking [%s]\n", ccname_file_dummy); ret = unlink(ccname_file_dummy); if (ret == -1) { ret = errno; DEBUG(SSSDBG_MINOR_FAILURE, "Unlink failed [%d][%s].\n", ret, strerror(ret)); } } talloc_free(tmp_ctx); return krberr; }
isc_result_t krb5_get_tgt(const char *principal, const char *keyfile) { isc_result_t result = ISC_R_FAILURE; char *ccname = NULL; krb5_context context = NULL; krb5_error_code krberr; krb5_ccache ccache = NULL; krb5_principal kprincpw = NULL; krb5_creds my_creds; krb5_creds * my_creds_ptr = NULL; krb5_get_init_creds_opt options; krb5_keytab keytab = NULL; int ret; if (keyfile == NULL || keyfile[0] == '\0') { keyfile = KRB_DEFAULT_KEYTAB; log_info("Using default keytab %s\n", keyfile); } else { if (strncmp(keyfile, "FILE:", 5) != 0) { log_error("Unknown keytab path format: Does it start with FILE:?\n"); return ISC_R_FAILURE; } } krberr = krb5_init_context(&context); CHECK_KRB5(NULL, krberr, "Kerberos context initialization failed"); result = ISC_R_SUCCESS; ccname = "MEMORY:dhcp_ld_krb5_cc"; log_info("Using ccache %s\n" , ccname); ret = setenv("KRB5CCNAME", ccname, 1); if (ret == -1) { log_error("Failed to setup environment\n"); result = ISC_R_FAILURE; goto cleanup; } krberr = krb5_cc_resolve(context, ccname, &ccache); CHECK_KRB5(context, krberr, "Couldnt resolve ccache '%s'", ccname); krberr = krb5_parse_name(context, principal, &kprincpw); CHECK_KRB5(context, krberr, "Failed to parse princ '%s'", princpal); result = check_credentials(context, ccache, kprincpw); if (result == ISC_R_SUCCESS) { log_info("Found valid kerberos credentials\n"); goto cleanup; } else { log_error("No valid krb5 credentials\n"); } krberr = krb5_kt_resolve(context, keyfile, &keytab); CHECK_KRB5(context, krberr, "Failed to resolve kt files '%s'\n", keyfile); memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_tkt_life(&options, KRB_MIN_TIME * 2); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprincpw, keytab, 0, NULL, &options); CHECK_KRB5(context, krberr, "Failed to get initial credentials TGT\n"); my_creds_ptr = &my_creds; krberr = krb5_cc_initialize(context, ccache, kprincpw); CHECK_KRB5(context, krberr, "Failed to init ccache\n"); krberr = krb5_cc_store_cred(context, ccache, &my_creds); CHECK_KRB5(context, krberr, "Failed to store credentials\n"); result = ISC_R_SUCCESS; log_info("Successfully init krb tgt %s", principal); cleanup: if (ccache) krb5_cc_close(context, ccache); if (keytab) krb5_kt_close(context, keytab); if (kprincpw) krb5_free_principal(context, kprincpw); if (my_creds_ptr) krb5_free_cred_contents(context, &my_creds); if (context) krb5_free_context(context); return result; }
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host, const char *principal, const char *oldpw, const char *newpw, int time_offset) { ADS_STATUS aret; krb5_error_code ret; krb5_context context = NULL; krb5_principal princ; krb5_get_init_creds_opt opts; krb5_creds creds; char *chpw_princ = NULL, *password; char *realm = NULL; int result_code; krb5_data result_code_string = { 0 }; krb5_data result_string = { 0 }; smb_krb5_addresses *addr = NULL; initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } if ((ret = smb_krb5_parse_name(context, principal, &princ))) { krb5_free_context(context); DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret))); return ADS_ERROR_KRB5(ret); } krb5_get_init_creds_opt_init(&opts); krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); krb5_get_init_creds_opt_set_renew_life(&opts, 0); krb5_get_init_creds_opt_set_forwardable(&opts, 0); krb5_get_init_creds_opt_set_proxiable(&opts, 0); /* note that heimdal will fill in the local addresses if the addresses * in the creds_init_opt are all empty and then later fail with invalid * address, sending our local netbios krb5 address - just like windows * - avoids this - gd */ ret = smb_krb5_gen_netbios_krb5_address(&addr, lp_netbios_name()); if (ret) { krb5_free_principal(context, princ); krb5_free_context(context); return ADS_ERROR_KRB5(ret); } krb5_get_init_creds_opt_set_address_list(&opts, addr->addrs); realm = smb_krb5_principal_get_realm(context, princ); /* We have to obtain an INITIAL changepw ticket for changing password */ if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) { krb5_free_context(context); free(realm); DEBUG(1,("ads_krb5_chg_password: asprintf fail\n")); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } free(realm); password = SMB_STRDUP(oldpw); ret = krb5_get_init_creds_password(context, &creds, princ, password, kerb_prompter, NULL, 0, chpw_princ, &opts); SAFE_FREE(chpw_princ); SAFE_FREE(password); if (ret) { if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) DEBUG(1,("Password incorrect while getting initial ticket")); else DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret))); krb5_free_principal(context, princ); krb5_free_context(context); return ADS_ERROR_KRB5(ret); } ret = krb5_change_password(context, &creds, discard_const_p(char, newpw), &result_code, &result_code_string, &result_string); if (ret) { DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret))); aret = ADS_ERROR_KRB5(ret); goto done; } if (result_code != KRB5_KPASSWD_SUCCESS) { ret = kpasswd_err_to_krb5_err(result_code); DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret))); aret = ADS_ERROR_KRB5(ret); goto done; } aret = ADS_SUCCESS; done: kerberos_free_data_contents(context, &result_code_string); kerberos_free_data_contents(context, &result_string); krb5_free_principal(context, princ); krb5_free_context(context); return aret; }
/* * Obtain credentials via a key in the keytab given * a keytab handle and a gssd_k5_kt_princ structure. * Checks to see if current credentials are expired, * if not, uses the keytab to obtain new credentials. * * Returns: * 0 => success (or credentials have not expired) * nonzero => error */ static int gssd_get_single_krb5_cred(krb5_context context, krb5_keytab kt, struct gssd_k5_kt_princ *ple, int nocache) { #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS krb5_get_init_creds_opt *init_opts = NULL; #else krb5_get_init_creds_opt options; #endif krb5_get_init_creds_opt *opts; krb5_creds my_creds; krb5_ccache ccache = NULL; char kt_name[BUFSIZ]; char cc_name[BUFSIZ]; int code; time_t now = time(0); char *cache_type; char *pname = NULL; char *k5err = NULL; memset(&my_creds, 0, sizeof(my_creds)); if (ple->ccname && ple->endtime > now && !nocache) { printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", ple->ccname, ple->endtime); code = 0; goto out; } code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ); if (code != 0) { printerr(0, "ERROR: Unable to get keytab name in " "gssd_get_single_krb5_cred\n"); goto out; } if ((krb5_unparse_name(context, ple->princ, &pname))) pname = NULL; #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS code = krb5_get_init_creds_opt_alloc(context, &init_opts); if (code) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s allocating gic options\n", k5err); goto out; } if (krb5_get_init_creds_opt_set_addressless(context, init_opts, 1)) printerr(1, "WARNING: Unable to set option for addressless " "tickets. May have problems behind a NAT.\n"); #ifdef TEST_SHORT_LIFETIME /* set a short lifetime (for debugging only!) */ printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); krb5_get_init_creds_opt_set_tkt_life(init_opts, 5 * 60); #endif opts = init_opts; #else /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS */ krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_address_list(&options, NULL); #ifdef TEST_SHORT_LIFETIME /* set a short lifetime (for debugging only!) */ printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); krb5_get_init_creds_opt_set_tkt_life(&options, 5 * 60); #endif opts = &options; #endif code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ, kt, 0, NULL, opts); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(1, "WARNING: %s while getting initial ticket for " "principal '%s' using keytab '%s'\n", k5err, pname ? pname : "<unparsable>", kt_name); goto out; } /* * Initialize cache file which we're going to be using */ if (use_memcache) cache_type = "MEMORY"; else cache_type = "FILE"; snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s", cache_type, ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX, GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); ple->endtime = my_creds.times.endtime; if (ple->ccname != NULL) gsh_free(ple->ccname); ple->ccname = gsh_strdup(cc_name); if (ple->ccname == NULL) { printerr(0, "ERROR: no storage to duplicate credentials " "cache name '%s'\n", cc_name); code = ENOMEM; goto out; } code = krb5_cc_resolve(context, cc_name, &ccache); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while opening credential cache '%s'\n", k5err, cc_name); goto out; } code = krb5_cc_initialize(context, ccache, ple->princ); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while initializing credential " "cache '%s'\n", k5err, cc_name); } code = krb5_cc_store_cred(context, ccache, &my_creds); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while storing credentials in '%s'\n", k5err, cc_name); goto out; } /* if we get this far, let gss mech know */ gssd_set_krb5_ccache_name(cc_name); code = 0; printerr(2, "Successfully obtained machine credentials for " "principal '%s' stored in ccache '%s'\n", pname, cc_name); out: #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS if (init_opts) krb5_get_init_creds_opt_free(context, init_opts); #endif if (pname) k5_free_unparsed_name(context, pname); if (ccache) krb5_cc_close(context, ccache); krb5_free_cred_contents(context, &my_creds); gsh_free(k5err); return code; }
/* * Function: Process WM_COMMAND messages */ static void kwin_command(HWND hwnd, int cid, HWND hwndCtl, UINT codeNotify) { char name[ANAME_SZ]; char realm[REALM_SZ]; char password[MAX_KPW_LEN]; HCURSOR hcursor; BOOL blogin; HMENU hmenu; char menuitem[MAX_K_NAME_SZ + 3]; char copyright[128]; int id; #ifdef KRB4 char instance[INST_SZ]; int lifetime; int krc; #endif #ifdef KRB5 long lifetime; krb5_error_code code; krb5_principal principal; krb5_creds creds; krb5_get_init_creds_opt opts; gic_data gd; #endif #ifdef KRB4 EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), krb_get_num_cred() > 0); #endif #ifdef KRB5 EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), k5_get_num_cred(1) > 0); #endif GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name)); trim(name); blogin = strlen(name) > 0; if (blogin) { GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm)); trim(realm); blogin = strlen(realm) > 0; } if (blogin) { GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password)); blogin = strlen(password) > 0; } EnableWindow(GetDlgItem(hwnd, IDD_LOGIN), blogin); id = (blogin) ? IDD_LOGIN : IDD_PASSWORD_CR2; SendMessage(hwnd, DM_SETDEFID, id, 0); if (codeNotify != BN_CLICKED && codeNotify != 0 && codeNotify != 1) return; /* FALSE */ /* * Check to see if this item is in a list of the ``recent hosts'' sort * of list, under the FILE menu. */ if (cid >= IDM_FIRST_LOGIN && cid < IDM_FIRST_LOGIN + FILE_MENU_MAX_LOGINS) { hmenu = GetMenu(hwnd); assert(hmenu != NULL); hmenu = GetSubMenu(hmenu, 0); assert(hmenu != NULL); if (!GetMenuString(hmenu, cid, menuitem, sizeof(menuitem), MF_BYCOMMAND)) return; /* TRUE */ if (menuitem[0]) kwin_init_name(hwnd, &menuitem[3]); return; /* TRUE */ } switch (cid) { case IDM_EXIT: if (isblocking) WSACancelBlockingCall(); WinHelp(hwnd, KERBEROS_HLP, HELP_QUIT, 0); PostQuitMessage(0); return; /* TRUE */ case IDD_PASSWORD_CR2: /* Make CR == TAB */ id = GetDlgCtrlID(GetFocus()); assert(id != 0); if (id == IDD_MAX_EDIT) PostMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwnd, IDD_MIN_EDIT), MAKELONG(1, 0)); else PostMessage(hwnd, WM_NEXTDLGCTL, 0, 0); return; /* TRUE */ case IDD_LOGIN: if (isblocking) return; /* TRUE */ GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name)); trim(name); GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm)); trim(realm); GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password)); SetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, ""); /* nuke the password */ trim(password); #ifdef KRB4 GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance)); trim(instance); #endif hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); lifetime = cns_res.lifetime; start_blocking_hook(BLOCK_MAX_SEC); #ifdef KRB4 lifetime = (lifetime + 4) / 5; krc = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm, lifetime, password); #endif #ifdef KRB5 principal = NULL; /* * convert the name + realm into a krb5 principal string and parse it into a principal */ sprintf(menuitem, "%s@%s", name, realm); code = krb5_parse_name(k5_context, menuitem, &principal); if (code) goto errorpoint; /* * set the various ticket options. First, initialize the structure, then set the ticket * to be forwardable if desired, and set the lifetime. */ krb5_get_init_creds_opt_init(&opts); krb5_get_init_creds_opt_set_forwardable(&opts, forwardable); krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime * 60); if (noaddresses) { krb5_get_init_creds_opt_set_address_list(&opts, NULL); } /* * get the initial creds using the password and the options we set above */ gd.hinstance = hinstance; gd.hwnd = hwnd; gd.id = ID_VARDLG; code = krb5_get_init_creds_password(k5_context, &creds, principal, password, gic_prompter, &gd, 0, NULL, &opts); if (code) goto errorpoint; /* * initialize the credential cache */ code = krb5_cc_initialize(k5_context, k5_ccache, principal); if (code) goto errorpoint; /* * insert the principal into the cache */ code = krb5_cc_store_cred(k5_context, k5_ccache, &creds); errorpoint: if (principal) krb5_free_principal(k5_context, principal); end_blocking_hook(); SetCursor(hcursor); kwin_set_default_focus(hwnd); if (code) { if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) MessageBox(hwnd, "Password incorrect", NULL, MB_OK | MB_ICONEXCLAMATION); else com_err(NULL, code, "while logging in"); } #endif /* KRB5 */ #ifdef KRB4 if (krc != KSUCCESS) { MessageBox(hwnd, krb_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION); return; /* TRUE */ } #endif kwin_save_name(hwnd); alerted = FALSE; switch (action) { case LOGIN_AND_EXIT: SendMessage(hwnd, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_EXIT, 0, 0)); break; case LOGIN_AND_MINIMIZE: ShowWindow(hwnd, SW_MINIMIZE); break; } return; /* TRUE */ case IDD_TICKET_DELETE: if (isblocking) return; /* TRUE */ #ifdef KRB4 krc = dest_tkt(); if (krc != KSUCCESS) MessageBox(hwnd, krb_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION); #endif #ifdef KRB5 code = k5_dest_tkt(); #endif kwin_set_default_focus(hwnd); alerted = FALSE; return; /* TRUE */ case IDD_CHANGE_PASSWORD: if (isblocking) return; /* TRUE */ password_dialog(hwnd); kwin_set_default_focus(hwnd); return; /* TRUE */ case IDM_OPTIONS: if (isblocking) return; /* TRUE */ opts_dialog(hwnd); return; /* TRUE */ case IDM_HELP_INDEX: WinHelp(hwnd, KERBEROS_HLP, HELP_INDEX, 0); return; /* TRUE */ case IDM_ABOUT: ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST)); if (isblocking) return; /* TRUE */ #ifdef KRB4 strcpy(copyright, " Kerberos 4 for Windows "); #endif #ifdef KRB5 strcpy(copyright, " Kerberos V5 for Windows "); #endif #ifdef _WIN32 strncat(copyright, "32-bit\n", sizeof(copyright) - 1 - strlen(copyright)); #else strncat(copyright, "16-bit\n", sizeof(copyright) - 1 - strlen(copyright)); #endif strncat(copyright, "\n Version 1.12\n\n", sizeof(copyright) - 1 - strlen(copyright)); #ifdef ORGANIZATION strncat(copyright, " For information, contact:\n", sizeof(copyright) - 1 - strlen(copyright)); strncat(copyright, ORGANIZATION, sizeof(copyright) - 1 - strlen(copyright)); #endif MessageBox(hwnd, copyright, KWIN_DIALOG_NAME, MB_OK); return; /* TRUE */ } return; /* FALSE */ }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { char *ccname; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int kdc_time_offset_usec; int ret; krberr = krb5_init_context(&context); if (krberr) { DEBUG(2, ("Failed to init kerberos context\n")); return krberr; } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(2, ("Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } realm_name = talloc_strdup(memctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(memctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(memctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(memctx, princ_str); } } else { char hostname[512]; ret = gethostname(hostname, 511); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[511] = '\0'; ret = select_principal_from_keytab(memctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) goto done; } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(4, ("Principal name is: [%s]\n", full_princ)); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(2, ("Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } if (krberr) { DEBUG(0, ("Failed to read keytab file: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } /* Verify the keytab */ ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(2, ("Unable to verify principal is present in the keytab\n")); krberr = KRB5_KT_IOERR; goto done; } ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); if (!ccname) { krberr = KRB5KRB_ERR_GENERIC; goto done; } krberr = krb5_cc_resolve(context, ccname, &ccache); if (krberr) { DEBUG(2, ("Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); if (krberr) { DEBUG(0, ("Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr))); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", keytab_name, sss_krb5_get_error_message(context, krberr)); goto done; } krberr = krb5_cc_initialize(context, ccache, kprinc); if (krberr) { DEBUG(2, ("Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(2, ("Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(2, ("Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr))); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } krberr = 0; *ccname_out = ccname; *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return krberr; }