static heim_array_t get_realms(void) { heim_array_t array; char **realms, **r; unsigned int i; int ret; array = heim_array_create(); for(i = 0; i < config->num_db; i++) { if (config->db[i]->hdb_get_realms == NULL) continue; ret = (config->db[i]->hdb_get_realms)(context, config->db[i], &realms); if (ret == 0) { for (r = realms; r && *r; r++) { heim_string_t s = heim_string_create(*r); if (s) heim_array_append_value(array, s); heim_release(s); } krb5_free_host_realm(context, realms); } } return array; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_sendto_ctx_alloc(krb5_context context, krb5_sendto_ctx *ctx) { *ctx = heim_alloc(sizeof(**ctx), "sendto-context", dealloc_sendto_ctx); if (*ctx == NULL) return krb5_enomem(context); (*ctx)->hosts = heim_array_create(); return 0; }
static heim_array_t parse_array(struct parse_ctx *ctx) { heim_array_t array = heim_array_create(); int ret; heim_assert(*ctx->p == '[', "array doesn't start with ["); ctx->p += 1; while ((ret = parse_item(array, ctx)) > 0) ; if (ret < 0) { heim_release(array); return NULL; } return array; }
krb5_error_code krb5_plugin_run_f(krb5_context context, const char *module, const char *name, int min_version, int flags, void *userctx, krb5_error_code (*func)(krb5_context, const void *, void *, void *)) { heim_string_t m = heim_string_create(module); heim_dict_t dict; struct iter_ctx s; HEIMDAL_MUTEX_lock(&plugin_mutex); dict = heim_dict_copy_value(modules, m); heim_release(m); if (dict == NULL) { HEIMDAL_MUTEX_unlock(&plugin_mutex); return KRB5_PLUGIN_NO_HANDLE; } s.context = context; s.name = name; s.n = heim_string_create(name); s.min_version = min_version; s.result = heim_array_create(); s.func = func; s.userctx = userctx; heim_dict_iterate_f(dict, search_modules, &s); heim_release(dict); HEIMDAL_MUTEX_unlock(&plugin_mutex); s.ret = KRB5_PLUGIN_NO_HANDLE; heim_array_iterate_f(s.result, &s, eval_results); heim_release(s.result); heim_release(s.n); return s.ret; }
/** * Commit an open transaction on the given db. * * @param db Open DB handle * @param error Output error object * * @return 0 on success, system error otherwise * * @addtogroup heimbase */ int heim_db_commit(heim_db_t db, heim_error_t *error) { int ret, ret2; heim_string_t journal_fname = NULL; if (heim_get_tid(db) != HEIM_TID_DB) return EINVAL; if (!db->in_transaction) return 0; if (db->plug->commitf == NULL && db->plug->lockf == NULL) return EINVAL; if (db->plug->commitf != NULL) { ret = db->plug->commitf(db->db_data, error); if (ret) (void) db->plug->rollbackf(db->db_data, error); db->in_transaction = 0; db->ro_tx = 0; return ret; } if (db->ro_tx) { ret = 0; goto done; } if (db->options == NULL) journal_fname = heim_dict_get_value(db->options, HSTR("journal-filename")); if (journal_fname != NULL) { heim_array_t a; heim_string_t journal_contents; size_t len, bytes; int save_errno; /* Create contents for replay log */ ret = ENOMEM; a = heim_array_create(); if (a == NULL) goto err; ret = heim_array_append_value(a, db->set_keys); if (ret) { heim_release(a); goto err; } ret = heim_array_append_value(a, db->del_keys); if (ret) { heim_release(a); goto err; } journal_contents = heim_json_copy_serialize(a, 0, error); heim_release(a); /* Write replay log */ if (journal_fname != NULL) { int fd; ret = open_file(heim_string_get_utf8(journal_fname), 1, 0, &fd, error); if (ret) { heim_release(journal_contents); goto err; } len = strlen(heim_string_get_utf8(journal_contents)); bytes = write(fd, heim_string_get_utf8(journal_contents), len); save_errno = errno; heim_release(journal_contents); ret = close(fd); if (bytes != len) { /* Truncate replay log */ (void) open_file(heim_string_get_utf8(journal_fname), 1, 0, NULL, error); ret = save_errno; goto err; } if (ret) goto err; } } /* Apply logged actions */ ret = db_do_log_actions(db, error); if (ret) return ret; if (db->plug->syncf != NULL) { /* fsync() or whatever */ ret = db->plug->syncf(db->db_data, error); if (ret) return ret; } /* Truncate replay log and we're done */ if (journal_fname != NULL) { int fd; ret2 = open_file(heim_string_get_utf8(journal_fname), 1, 0, &fd, error); if (ret2 == 0) (void) close(fd); } /* * Clean up; if we failed to remore the replay log that's OK, we'll * handle that again in heim_db_commit() */ done: heim_release(db->set_keys); heim_release(db->del_keys); db->set_keys = NULL; db->del_keys = NULL; db->in_transaction = 0; db->ro_tx = 0; ret2 = db->plug->unlockf(db->db_data, error); if (ret == 0) ret = ret2; return ret; err: return HEIM_ERROR(error, ret, (ret, N_("Error while committing transaction: %s", ""), strerror(ret))); }
/** * Run plugins for the given @module (e.g., "krb5") and @name (e.g., * "kuserok"). Specifically, the @func is invoked once per-plugin with * four arguments: the @context, the plugin symbol value (a pointer to a * struct whose first three fields are the same as struct common_plugin_method), * a context value produced by the plugin's init method, and @userctx. * * @func should unpack arguments for a plugin function and invoke it * with arguments taken from @userctx. @func should save plugin * outputs, if any, in @userctx. * * All loaded and registered plugins are invoked via @func until @func * returns something other than KRB5_PLUGIN_NO_HANDLE. Plugins that * have nothing to do for the given arguments should return * KRB5_PLUGIN_NO_HANDLE. * * Inputs: * * @context A krb5_context * @module Name of module (typically "krb5") * @name Name of pluggable interface (e.g., "kuserok") * @min_version Lowest acceptable plugin minor version number * @flags Flags (none defined at this time) * @userctx Callback data for the callback function @func * @func A callback function, invoked once per-plugin * * Outputs: None, other than the return value and such outputs as are * gathered by @func. */ krb5_error_code _krb5_plugin_run_f(krb5_context context, const char *module, const char *name, int min_version, int flags, void *userctx, krb5_error_code (KRB5_LIB_CALL *func)(krb5_context, const void *, void *, void *)) { heim_string_t m = heim_string_create(module); heim_dict_t dict; void *plug_ctx; struct common_plugin_method *cpm; struct iter_ctx s; struct krb5_plugin *registered_plugins = NULL; struct krb5_plugin *p; /* Get registered plugins */ (void) _krb5_plugin_find(context, SYMBOL, name, ®istered_plugins); HEIMDAL_MUTEX_lock(&plugin_mutex); s.context = context; s.name = name; s.n = heim_string_create(name); s.min_version = min_version; s.result = heim_array_create(); s.func = func; s.userctx = userctx; s.ret = KRB5_PLUGIN_NO_HANDLE; /* Get loaded plugins */ dict = heim_dict_get_value(modules, m); heim_release(m); /* Add loaded plugins to s.result array */ if (dict) heim_dict_iterate_f(dict, &s, search_modules); /* We don't need to hold plugin_mutex during plugin invocation */ HEIMDAL_MUTEX_unlock(&plugin_mutex); /* Invoke registered plugins (old system) */ for (p = registered_plugins; p; p = p->next) { /* * XXX This is the wrong way to handle registered plugins, as we * call init/fini on each invocation! We do this because we * have nowhere in the struct plugin registered list to store * the context allocated by the plugin's init function. (But at * least we do call init/fini!) * * What we should do is adapt the old plugin system to the new * one and change how we register plugins so that we use the new * struct plug to keep track of their context structures, that * way we can init once, invoke many times, then fini. */ cpm = (struct common_plugin_method *)p->symbol; s.ret = cpm->init(context, &plug_ctx); if (s.ret) continue; s.ret = s.func(s.context, p->symbol, plug_ctx, s.userctx); cpm->fini(plug_ctx); if (s.ret != KRB5_PLUGIN_NO_HANDLE) break; } _krb5_plugin_free(registered_plugins); /* Invoke loaded plugins (new system) */ if (s.ret != KRB5_PLUGIN_NO_HANDLE) heim_array_iterate_f(s.result, &s, eval_results); heim_release(s.result); heim_release(s.n); return s.ret; }
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_get_init_creds_opt *opt; 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; krb5_init_creds_context icc; krb5_keytab kt = NULL; int will_use_keytab = (use_keytab || keytab_str); krb5_prompter_fct prompter = NULL; int need_prompt; passwd[0] = '\0'; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) krb5_errx(context, 1, "Failed to open the password file %s", password_file); if (fgets(passwd, sizeof(passwd), f) == NULL) krb5_errx(context, 1, N_("Failed to read password from file %s", ""), password_file); if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #if defined(__APPLE__) && !defined(__APPLE_TARGET_EMBEDDED__) if (passwd[0] == '\0' && !will_use_keytab && home_directory_flag) { 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, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, &length, &buffer, &passwordItem); free(name); if (osret != noErr) goto nopassword; if (length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } SecKeychainItemFreeContent(NULL, buffer); nopassword: do { } while(0); } #endif need_prompt = !(pk_user_id || ent_user_id || anonymous_flag || will_use_keytab || passwd[0] != '\0') && interactive; if (need_prompt) prompter = krb5_prompter_posix; else prompter = krb5_prompter_print_only; memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); 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, interactive ? krb5_prompter_posix : krb5_prompter_print_only, NULL, passwd); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_cert(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) krb5_err(context, 1, ret, "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, &icc); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_init"); if (server_str) { ret = krb5_init_creds_set_service(context, icc, server_str); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_service"); } if (kdc_hostname) krb5_init_creds_set_kdc_hostname(context, icc, kdc_hostname); if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve(FAST cache)"); ret = krb5_init_creds_set_fast_ccache(context, icc, fastid); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache"); } if(will_use_keytab) { 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"); ret = krb5_init_creds_set_keytab(context, icc, kt); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_keytab"); } if (passwd[0] == '\0' && need_prompt) { char *p, *prompt; krb5_unparse_name(context, principal, &p); asprintf (&prompt, N_("%s's Password: "******""), p); free(p); 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, icc, passwd); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_password"); } ret = krb5_init_creds_get(context, icc); #ifdef __APPLE__ /* * Save password in Keychain */ if (ret == 0 && keychain_flag && passwordItem == NULL) { krb5_error_code ret2; const char *realm; char *name; realm = krb5_principal_get_realm(context, principal); ret2 = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret2 == 0) { (void)SecKeychainAddGenericPassword(NULL, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, (UInt32)strlen(passwd), passwd, NULL); free(name); } } #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: #ifdef __APPLE__ if (passwordItem) SecKeychainItemDelete(passwordItem); #endif krb5_errx(context, 1, N_("Password incorrect", "")); case KRB5KRB_AP_ERR_V4_REPLY: krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", "")); case KRB5KDC_ERR_KEY_EXPIRED: krb5_errx(context, 1, N_("Password expired", "")); default: krb5_err(context, 1, ret, "krb5_get_init_creds"); } ret = krb5_init_creds_get_creds(context, icc, &cred); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_get_creds"); krb5_process_last_request(context, opt, icc); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_new_unique"); ret = krb5_init_creds_store(context, icc, tempccache); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_store"); ret = krb5_init_creds_store_config(context, icc, tempccache); if (ret) krb5_warn(context, ret, "krb5_init_creds_store_config"); ret = krb5_init_creds_warn_user(context, icc); if (ret) krb5_warn(context, ret, "krb5_init_creds_warn_user"); #ifdef __APPLE__ /* * Set for this case, default to * so that all processes can use * this cache. */ { heim_array_t bundleacl = heim_array_create(); heim_string_t ace; if (bundle_acl_strings.num_strings > 0) { int i; for (i = 0; i < bundle_acl_strings.num_strings; i++) { ace = heim_string_create(bundle_acl_strings.strings[i]); heim_array_append_value(bundleacl, ace); heim_release(ace); } } else { ace = heim_string_create("*"); heim_array_append_value(bundleacl, ace); heim_release(ace); } krb5_cc_set_acl(context, tempccache, "kHEIMAttrBundleIdentifierACL", bundleacl); heim_release(bundleacl); } #endif ret = krb5_cc_move(context, tempccache, ccache); if (ret) { (void)krb5_cc_destroy(context, tempccache); krb5_err (context, 1, ret, "krb5_cc_move"); } if (switch_cache_flags) krb5_cc_switch(context, ccache); 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); } if (enctype) free(enctype); krb5_init_creds_free(context, icc); krb5_get_init_creds_opt_free(context, opt); if (kt) krb5_kt_close(context, kt); #ifdef __APPLE__ if (passwordItem) CFRelease(passwordItem); #endif return 0; }