char * sss_get_ccache_name_for_principal(TALLOC_CTX *mem_ctx, krb5_context ctx, krb5_principal principal, const char *location) { #ifdef HAVE_KRB5_CC_COLLECTION krb5_error_code kerr; krb5_ccache tmp_cc = NULL; char *tmp_ccname = NULL; char *ret_ccname = NULL; DEBUG(SSSDBG_TRACE_ALL, "Location: [%s]\n", location); kerr = krb5_cc_set_default_name(ctx, location); if (kerr != 0) { KRB5_DEBUG(SSSDBG_MINOR_FAILURE, ctx, kerr); return NULL; } kerr = krb5_cc_cache_match(ctx, principal, &tmp_cc); if (kerr != 0) { const char *err_msg = sss_krb5_get_error_message(ctx, kerr); DEBUG(SSSDBG_TRACE_INTERNAL, "krb5_cc_cache_match failed: [%d][%s]\n", kerr, err_msg); sss_krb5_free_error_message(ctx, err_msg); return NULL; } kerr = krb5_cc_get_full_name(ctx, tmp_cc, &tmp_ccname); if (kerr != 0) { KRB5_DEBUG(SSSDBG_MINOR_FAILURE, ctx, kerr); goto done; } DEBUG(SSSDBG_TRACE_ALL, "tmp_ccname: [%s]\n", tmp_ccname); ret_ccname = talloc_strdup(mem_ctx, tmp_ccname); if (ret_ccname == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed (ENOMEM).\n"); } done: if (tmp_cc != NULL) { kerr = krb5_cc_close(ctx, tmp_cc); if (kerr != 0) { KRB5_DEBUG(SSSDBG_MINOR_FAILURE, ctx, kerr); } } krb5_free_string(ctx, tmp_ccname); return ret_ccname; #else return NULL; #endif /* HAVE_KRB5_CC_COLLECTION */ }
static int prepare_response(TALLOC_CTX *mem_ctx, const char *ccname, time_t expire_time, krb5_error_code kerr, struct response **rsp) { int ret; struct response *r = NULL; const char *krb5_msg = NULL; r = talloc_zero(mem_ctx, struct response); if (!r) return ENOMEM; r->buf = NULL; r->size = 0; DEBUG(SSSDBG_TRACE_FUNC, ("Building response for result [%d]\n", kerr)); if (kerr == 0) { ret = pack_buffer(r, EOK, kerr, ccname, expire_time); } else { krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr); if (krb5_msg == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("sss_krb5_get_error_message failed.\n")); return ENOMEM; } ret = pack_buffer(r, EFAULT, kerr, krb5_msg, 0); sss_krb5_free_error_message(krb5_error_ctx, krb5_msg); } if (ret != EOK) { DEBUG(1, ("pack_buffer failed\n")); return ret; } *rsp = r; return EOK; }
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; }
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; }
static int lc_verify_keytab_ex(const char *principal, const char *keytab_name, krb5_context context, krb5_keytab keytab) { bool found; char *kt_principal; krb5_error_code krberr; krb5_kt_cursor cursor; krb5_keytab_entry entry; krberr = krb5_kt_start_seq_get(context, keytab, &cursor); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Cannot read keytab [%s].\n", KEYTAB_CLEAN_NAME); sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. " "Unable to create GSSAPI-encrypted LDAP " "connection.", KEYTAB_CLEAN_NAME, krberr, sss_krb5_get_error_message(context, krberr)); return EIO; } found = false; while ((krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) { krberr = krb5_unparse_name(context, entry.principal, &kt_principal); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Could not parse keytab entry\n"); sss_log(SSS_LOG_ERR, "Could not parse keytab entry\n"); return EIO; } if (strcmp(principal, kt_principal) == 0) { found = true; } free(kt_principal); krberr = sss_krb5_free_keytab_entry_contents(context, &entry); if (krberr) { /* This should never happen. The API docs for this function * specify only success for this function */ DEBUG(SSSDBG_CRIT_FAILURE,"Could not free keytab entry contents\n"); /* This is non-fatal, so we'll continue here */ } if (found) { break; } } krberr = krb5_kt_end_seq_get(context, keytab, &cursor); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Could not close keytab.\n"); sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].", KEYTAB_CLEAN_NAME); return EIO; } if (!found) { DEBUG(SSSDBG_FATAL_FAILURE, "Principal [%s] not found in keytab [%s]\n", principal, KEYTAB_CLEAN_NAME); sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: " "Principal [%s] was not found. " "Unable to create GSSAPI-encrypted LDAP connection.", KEYTAB_CLEAN_NAME, principal); return EFAULT; } return EOK; }
errno_t select_principal_from_keytab(TALLOC_CTX *mem_ctx, const char *hostname, const char *desired_realm, const char *keytab_name, char **_principal, char **_primary, char **_realm) { krb5_error_code kerr = 0; krb5_context krb_ctx = NULL; krb5_keytab keytab = NULL; krb5_principal client_princ = NULL; TALLOC_CTX *tmp_ctx; char *primary = NULL; char *realm = NULL; int i = 0; errno_t ret; char *principal_string; const char *realm_name; int realm_len; /** * The %s conversion is passed as-is, the %S conversion is translated to * "short host name" * * Priority of lookup: * - our.hostname@REALM or host/our.hostname@REALM depending on the input * - SHORT.HOSTNAME$@REALM (AD domain) * - host/our.hostname@REALM * - foobar$@REALM (AD domain) * - host/foobar@REALM * - host/foo@BAR * - pick the first principal in the keytab */ const char *primary_patterns[] = {"%s", "%S$", "host/%s", "*$", "host/*", "host/*", NULL}; const char *realm_patterns[] = {"%s", "%s", "%s", "%s", "%s", NULL, NULL}; DEBUG(SSSDBG_FUNC_DATA, "trying to select the most appropriate principal from keytab\n"); tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed\n"); return ENOMEM; } kerr = krb5_init_context(&krb_ctx); if (kerr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to init kerberos context\n"); ret = EFAULT; goto done; } if (keytab_name != NULL) { kerr = krb5_kt_resolve(krb_ctx, keytab_name, &keytab); } else { kerr = krb5_kt_default(krb_ctx, &keytab); } if (kerr) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read keytab [%s]: %s\n", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(krb_ctx, kerr)); ret = EFAULT; goto done; } if (!desired_realm) { desired_realm = "*"; } if (!hostname) { hostname = "*"; } do { if (primary_patterns[i]) { primary = sss_krb5_get_primary(tmp_ctx, primary_patterns[i], hostname); if (primary == NULL) { ret = ENOMEM; goto done; } } else { primary = NULL; } if (realm_patterns[i]) { realm = talloc_asprintf(tmp_ctx, realm_patterns[i], desired_realm); if (realm == NULL) { ret = ENOMEM; goto done; } } else { realm = NULL; } kerr = find_principal_in_keytab(krb_ctx, keytab, primary, realm, &client_princ); talloc_zfree(primary); talloc_zfree(realm); if (kerr == 0) { break; } if (client_princ != NULL) { krb5_free_principal(krb_ctx, client_princ); client_princ = NULL; } i++; } while(primary_patterns[i-1] != NULL || realm_patterns[i-1] != NULL); if (kerr == 0) { if (_principal) { kerr = krb5_unparse_name(krb_ctx, client_princ, &principal_string); if (kerr) { DEBUG(SSSDBG_CRIT_FAILURE, "krb5_unparse_name failed\n"); ret = EFAULT; goto done; } *_principal = talloc_strdup(mem_ctx, principal_string); free(principal_string); if (!*_principal) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed\n"); ret = ENOMEM; goto done; } DEBUG(SSSDBG_FUNC_DATA, "Selected principal: %s\n", *_principal); } if (_primary) { kerr = sss_krb5_unparse_name_flags(krb_ctx, client_princ, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &principal_string); if (kerr) { DEBUG(SSSDBG_CRIT_FAILURE, "krb5_unparse_name failed\n"); ret = EFAULT; goto done; } *_primary = talloc_strdup(mem_ctx, principal_string); free(principal_string); if (!*_primary) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed\n"); if (_principal) talloc_zfree(*_principal); ret = ENOMEM; goto done; } DEBUG(SSSDBG_FUNC_DATA, "Selected primary: %s\n", *_primary); } if (_realm) { sss_krb5_princ_realm(krb_ctx, client_princ, &realm_name, &realm_len); if (realm_len == 0) { DEBUG(SSSDBG_CRIT_FAILURE, "sss_krb5_princ_realm failed.\n"); if (_principal) talloc_zfree(*_principal); if (_primary) talloc_zfree(*_primary); ret = EINVAL; goto done; } *_realm = talloc_asprintf(mem_ctx, "%.*s", realm_len, realm_name); if (!*_realm) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed\n"); if (_principal) talloc_zfree(*_principal); if (_primary) talloc_zfree(*_primary); ret = ENOMEM; goto done; } DEBUG(SSSDBG_FUNC_DATA, "Selected realm: %s\n", *_realm); } ret = EOK; } else { DEBUG(SSSDBG_MINOR_FAILURE, "No suitable principal found in keytab\n"); ret = ENOENT; } done: if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read keytab [%s]: %s\n", KEYTAB_CLEAN_NAME, strerror(ret)); sss_log(SSS_LOG_ERR, "Failed to read keytab [%s]: %s\n", KEYTAB_CLEAN_NAME, strerror(ret)); } if (keytab) krb5_kt_close(krb_ctx, keytab); if (krb_ctx) krb5_free_context(krb_ctx); if (client_princ != NULL) { krb5_free_principal(krb_ctx, client_princ); client_princ = NULL; } talloc_free(tmp_ctx); return ret; }
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; }