static krb5_error_code an2ln_plugin(krb5_context context, const char *rule, krb5_const_principal aname, size_t lnsize, char *lname) { krb5_error_code ret; struct plctx ctx; ctx.rule = rule; ctx.aname = aname; ctx.luser = NULL; /* * Order of plugin invocation is non-deterministic, but there should * really be no more than one plugin that can handle any given kind * rule, so the effect should be deterministic anyways. */ ret = _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_AN2LN, KRB5_PLUGIN_AN2LN_VERSION_0, 0, &ctx, plcallback); if (ret != 0) { heim_release(ctx.luser); return ret; } if (ctx.luser == NULL) return KRB5_PLUGIN_NO_HANDLE; if (strlcpy(lname, heim_string_get_utf8(ctx.luser), lnsize) >= lnsize) ret = KRB5_CONFIG_NOTENUFSPACE; heim_release(ctx.luser); return ret; }
static void error_dealloc(void *ptr) { struct heim_error *p = ptr; heim_release(p->msg); heim_release(p->next); }
/** heim_db_register * @brief Registers a DB type for use with heim_db_create(). * * @param dbtype Name of DB type * @param data Private data argument to the dbtype's openf method * @param plugin Structure with DB type methods (function pointers) * * Backends that provide begin/commit/rollback methods must provide ACID * semantics. * * The registered DB type will have ACID semantics for backends that do * not provide begin/commit/rollback methods but do provide lock/unlock * and rdjournal/wrjournal methods (using a replay log journalling * scheme). * * If the registered DB type does not natively provide read vs. write * transaction isolation but does provide a lock method then the DB will * provide read/write transaction isolation. * * @return ENOMEM on failure, else 0. * * @addtogroup heimbase */ int heim_db_register(const char *dbtype, void *data, struct heim_db_type *plugin) { heim_dict_t plugins; heim_string_t s; db_plugin plug, plug2; int ret = 0; if ((plugin->beginf != NULL && plugin->commitf == NULL) || (plugin->beginf != NULL && plugin->rollbackf == NULL) || (plugin->lockf != NULL && plugin->unlockf == NULL) || plugin->copyf == NULL) heim_abort("Invalid DB plugin; make sure methods are paired"); /* Initialize */ plugins = heim_dict_create(11); if (plugins == NULL) return ENOMEM; heim_base_once_f(&db_plugin_init_once, plugins, db_init_plugins_once); heim_release(plugins); heim_assert(db_plugins != NULL, "heim_db plugin table initialized"); s = heim_string_create(dbtype); if (s == NULL) return ENOMEM; plug = heim_alloc(sizeof (*plug), "db_plug", plugin_dealloc); if (plug == NULL) { heim_release(s); return ENOMEM; } plug->name = heim_retain(s); plug->openf = plugin->openf; plug->clonef = plugin->clonef; plug->closef = plugin->closef; plug->lockf = plugin->lockf; plug->unlockf = plugin->unlockf; plug->syncf = plugin->syncf; plug->beginf = plugin->beginf; plug->commitf = plugin->commitf; plug->rollbackf = plugin->rollbackf; plug->copyf = plugin->copyf; plug->setf = plugin->setf; plug->delf = plugin->delf; plug->iterf = plugin->iterf; plug->data = data; HEIMDAL_MUTEX_lock(&db_type_mutex); plug2 = heim_dict_get_value(db_plugins, s); if (plug2 == NULL) ret = heim_dict_set_value(db_plugins, s, plug); HEIMDAL_MUTEX_unlock(&db_type_mutex); heim_release(plug); heim_release(s); return ret; }
static void plug_dealloc(void *ptr) { struct plugin2 *p = ptr; heim_release(p->path); heim_release(p->names); if (p->dsohandle) dlclose(p->dsohandle); }
static void dealloc_sendto_ctx(void *ptr) { krb5_sendto_ctx ctx = (krb5_sendto_ctx)ptr; if (ctx->hostname) free(ctx->hostname); heim_release(ctx->hosts); heim_release(ctx->krbhst); }
/** * Delete a key and its value from the DB * * * @param db Open DB handle * @param key Key * @param error Output error object * * @return 0 on success, system error otherwise * * @addtogroup heimbase */ int heim_db_delete_key(heim_db_t db, heim_string_t table, heim_data_t key, heim_error_t *error) { heim_string_t key64 = NULL; int ret; if (error != NULL) *error = NULL; if (table == NULL) table = HSTR(""); if (heim_get_tid(db) != HEIM_TID_DB) return EINVAL; if (db->plug->delf == NULL) return EBADF; if (!db->in_transaction) { ret = heim_db_begin(db, 0, error); if (ret) goto err; heim_assert(db->in_transaction, "Internal error"); ret = heim_db_delete_key(db, table, key, error); if (ret) { (void) heim_db_rollback(db, NULL); return ret; } return heim_db_commit(db, error); } /* Transaction emulation */ heim_assert(db->set_keys != NULL, "Internal error"); key64 = to_base64(key, error); if (key64 == NULL) return HEIM_ENOMEM(error); if (db->ro_tx) { ret = heim_db_begin(db, 0, error); if (ret) goto err; } ret = heim_path_create(db->del_keys, 29, heim_number_create(1), error, table, key64, NULL); if (ret) goto err; heim_path_delete(db->set_keys, error, table, key64, NULL); heim_release(key64); return 0; err: heim_release(key64); return HEIM_ERROR(error, ret, (ret, N_("Could not set a dict value while while " "deleting a DB value", ""))); }
static int db_replay_log(heim_db_t db, heim_error_t *error) { int ret; heim_string_t journal_fname = NULL; heim_object_t journal; size_t len; heim_assert(!db->in_transaction, "DB transaction not open"); heim_assert(db->set_keys == NULL && db->set_keys == NULL, "DB transaction not open"); if (error) *error = NULL; if (db->options == NULL) return 0; journal_fname = heim_dict_get_value(db->options, HSTR("journal-filename")); if (journal_fname == NULL) return 0; ret = read_json(heim_string_get_utf8(journal_fname), &journal, error); if (ret == ENOENT) return 0; if (ret == 0 && journal == NULL) return 0; if (ret != 0) return ret; if (heim_get_tid(journal) != HEIM_TID_ARRAY) return HEIM_ERROR(error, EINVAL, (ret, N_("Invalid journal contents; delete journal", ""))); len = heim_array_get_length(journal); if (len > 0) db->set_keys = heim_array_get_value(journal, 0); if (len > 1) db->del_keys = heim_array_get_value(journal, 1); ret = db_do_log_actions(db, error); if (ret) return ret; /* Truncate replay log and we're done */ ret = open_file(heim_string_get_utf8(journal_fname), 1, 0, NULL, error); if (ret) return ret; heim_release(db->set_keys); heim_release(db->del_keys); db->set_keys = NULL; db->del_keys = NULL; return 0; }
static heim_data_t json_db_copy_value(void *db, heim_string_t table, heim_data_t key, heim_error_t *error) { json_db_t jsondb = db; heim_string_t key_string; const heim_octet_string *key_data = heim_data_get_data(key); struct stat st; heim_data_t result; if (error) *error = NULL; if (strnlen(key_data->data, key_data->length) != key_data->length) { HEIM_ERROR(error, EINVAL, (EINVAL, N_("JSON DB requires keys that are actually " "strings", ""))); return NULL; } if (stat(heim_string_get_utf8(jsondb->dbname), &st) == -1) { HEIM_ERROR(error, errno, (errno, N_("Could not stat JSON DB file", ""))); return NULL; } if (st.st_mtime > jsondb->last_read_time || st.st_ctime > jsondb->last_read_time) { heim_dict_t contents = NULL; int ret; /* Ignore file is gone (ENOENT) */ ret = read_json(heim_string_get_utf8(jsondb->dbname), (heim_object_t *)&contents, error); if (ret) return NULL; if (contents == NULL) contents = heim_dict_create(29); heim_release(jsondb->dict); jsondb->dict = contents; jsondb->last_read_time = time(NULL); } key_string = heim_string_create_with_bytes(key_data->data, key_data->length); if (key_string == NULL) { (void) HEIM_ENOMEM(error); return NULL; } result = heim_path_copy(jsondb->dict, error, table, key_string, NULL); heim_release(key_string); return result; }
static heim_dict_t parse_dict(struct parse_ctx *ctx) { heim_dict_t dict; size_t count = 0; int ret; heim_assert(*ctx->p == '{', "string doesn't start with {"); dict = heim_dict_create(11); if (dict == NULL) { ctx->error = heim_error_create_enomem(); return NULL; } ctx->p += 1; /* safe because parse_pair() calls white_spaces() first */ while ((ret = parse_pair(dict, ctx)) > 0) count++; if (ret < 0) { heim_release(dict); return NULL; } if (count == 1 && !(ctx->flags & HEIM_JSON_F_NO_DATA_DICT)) { heim_object_t v = heim_dict_copy_value(dict, heim_tid_data_uuid_key); /* * Binary data encoded as a dict with a single magic key with * base64-encoded value? Decode as heim_data_t. */ if (v != NULL && heim_get_tid(v) == HEIM_TID_STRING) { void *buf; size_t len; buf = malloc(strlen(heim_string_get_utf8(v))); if (buf == NULL) { heim_release(dict); heim_release(v); ctx->error = heim_error_create_enomem(); return NULL; } len = base64_decode(heim_string_get_utf8(v), buf); heim_release(v); if (len == -1) { free(buf); return dict; /* assume aliasing accident */ } heim_release(dict); return (heim_dict_t)heim_data_ref_create(buf, len, free); } } return dict; }
static int parse_pair(heim_dict_t dict, struct parse_ctx *ctx) { heim_string_t key; heim_object_t value; if (white_spaces(ctx)) return -1; if (*ctx->p == '}') return 0; key = parse_string(ctx); if (key == NULL) return -1; if (white_spaces(ctx)) return -1; if (*ctx->p != ':') { heim_release(key); return -1; } ctx->p += 1; if (white_spaces(ctx)) { heim_release(key); return -1; } value = parse_value(ctx); if (value == NULL) { heim_release(key); return -1; } heim_dict_set_value(dict, key, value); heim_release(key); heim_release(value); if (white_spaces(ctx)) return -1; if (*ctx->p == '}') { ctx->p++; return 0; } else if (*ctx->p == ',') { ctx->p++; return 1; } return -1; }
static int parse_item(heim_array_t array, struct parse_ctx *ctx) { heim_object_t value; if (white_spaces(ctx)) return -1; if (*ctx->p == ']') { ctx->p++; /* safe because parse_value() calls white_spaces() first */ return 0; } value = parse_value(ctx); if (value == NULL && (ctx->error || (ctx->flags & HEIM_JSON_F_NO_C_NULL))) return -1; heim_array_append_value(array, value); heim_release(value); if (white_spaces(ctx)) return -1; if (*ctx->p == ']') { ctx->p++; return 0; } else if (*ctx->p == ',') { ctx->p++; return 1; } return -1; }
static int json_db_del_key(void *db, heim_string_t table, heim_data_t key, heim_error_t *error) { json_db_t jsondb = db; heim_string_t key_string; const heim_octet_string *key_data = heim_data_get_data(key); if (error) *error = NULL; if (strnlen(key_data->data, key_data->length) != key_data->length) return HEIM_ERROR(error, EINVAL, (EINVAL, N_("JSON DB requires keys that are actually strings", ""))); key_string = heim_string_create_with_bytes(key_data->data, key_data->length); if (key_string == NULL) return HEIM_ENOMEM(error); if (table == NULL) table = HSTR(""); heim_path_delete(jsondb->dict, error, table, key_string, NULL); heim_release(key_string); return 0; }
static int json_db_close(void *db, heim_error_t *error) { json_db_t jsondb = db; if (error) *error = NULL; if (jsondb->fd > -1) (void) close(jsondb->fd); jsondb->fd = -1; heim_release(jsondb->dbname); heim_release(jsondb->bkpname); heim_release(jsondb->dict); heim_release(jsondb); return 0; }
static int db_do_log_actions(heim_db_t db, heim_error_t *error) { int ret; if (error) *error = NULL; db->ret = 0; db->error = NULL; if (db->set_keys != NULL) heim_dict_iterate_f(db->set_keys, db, db_replay_log_set_keys_iter); if (db->del_keys != NULL) heim_dict_iterate_f(db->del_keys, db, db_replay_log_del_keys_iter); ret = db->ret; db->ret = 0; if (error && db->error) { *error = db->error; db->error = NULL; } else { heim_release(db->error); db->error = NULL; } return ret; }
int heim_dict_add_value(heim_dict_t dict, heim_object_t key, heim_object_t value) { struct hashentry **tabptr, *h; h = _search(dict, key); if (h) { heim_release(h->value); h->value = heim_retain(value); } else { unsigned long v; h = malloc(sizeof(*h)); if (h == NULL) return ENOMEM; h->key = heim_retain(key); h->value = heim_retain(value); v = heim_get_hash(key); tabptr = &dict->tab[v % dict->size]; h->next = *tabptr; *tabptr = h; h->prev = tabptr; if (h->next) h->next->prev = &h->next; } return 0; }
void heim_dict_delete_key(heim_dict_t dict, heim_object_t key) { struct hashentry *h = _search(dict, key); if (h == NULL) return; heim_release(h->key); heim_release(h->value); if ((*(h->prev) = h->next) != NULL) h->next->prev = h->prev; free(h); }
static void dict_dealloc(void *ptr) { heim_dict_t dict = ptr; struct hashentry **h, *g, *i; for (h = dict->tab; h < &dict->tab[dict->size]; ++h) { for (g = h[0]; g; g = i) { i = g->next; heim_release(g->key); heim_release(g->value); free(g); } } free(dict->tab); }
char * hx509_get_error_string(hx509_context context, int error_code) { heim_error_t msg = context->error; heim_string_t s; char *str = NULL; if (msg == NULL || heim_error_get_code(msg) != error_code) { const char *cstr; cstr = com_right(context->et_list, error_code); if (cstr) return strdup(cstr); cstr = strerror(error_code); if (cstr) return strdup(cstr); if (asprintf(&str, "<unknown error: %d>", error_code) == -1) return NULL; return str; } s = heim_error_copy_string(msg); if (s) { const char *cstr = heim_string_get_utf8(s); if (cstr) str = strdup(cstr); heim_release(s); } return str; }
static int parse_item(heim_array_t array, struct parse_ctx *ctx) { heim_object_t value; if (white_spaces(ctx)) return -1; if (*ctx->p == ']') return 0; value = parse_value(ctx); if (value == NULL) return -1; heim_array_append_value(array, value); heim_release(value); if (white_spaces(ctx)) return -1; if (*ctx->p == ']') { ctx->p++; return 0; } else if (*ctx->p == ',') { ctx->p++; return 1; } return -1; }
heim_object_t heim_json_create_with_bytes(const void *data, size_t length, size_t max_depth, heim_json_flags_t flags, heim_error_t *error) { struct parse_ctx ctx; heim_object_t o; heim_base_once_f(&heim_json_once, NULL, json_init_once); ctx.lineno = 1; ctx.p = data; ctx.pstart = data; ctx.pend = ((uint8_t *)data) + length; ctx.error = NULL; ctx.flags = flags; ctx.depth = max_depth; o = parse_value(&ctx); if (o == NULL && error) { *error = ctx.error; } else if (ctx.error) { heim_release(ctx.error); } return o; }
static void plugin_dealloc(void *arg) { db_plugin plug = arg; heim_release(plug->name); }
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; }
static struct krb5_krbhst_data* common_init(krb5_context context, const char *service, const char *realm, int flags) { struct krb5_krbhst_data *kd; if ((kd = heim_alloc(sizeof(*kd), "krbhst-context", krbhost_dealloc)) == NULL) return NULL; if((kd->realm = strdup(realm)) == NULL) { heim_release(kd); return NULL; } _krb5_debug(context, 2, "Trying to find service %s for realm %s flags %x", service, realm, flags); /* For 'realms' without a . do not even think of going to DNS */ if (!strchr(realm, '.')) kd->flags |= KD_CONFIG_EXISTS; if (flags & KRB5_KRBHST_FLAGS_LARGE_MSG) kd->flags |= KD_LARGE_MSG; kd->end = kd->index = &kd->hosts; return kd; }
static int any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs) { int ret; size_t i; if (sd->certificates == NULL) return 0; for (i = 0; i < sd->certificates->len; i++) { heim_error_t error; hx509_cert c; c = hx509_cert_init_data(context, sd->certificates->val[i].data, sd->certificates->val[i].length, &error); if (c == NULL) { ret = heim_error_get_code(error); heim_release(error); return ret; } ret = hx509_certs_add(context, certs, c); hx509_cert_free(c); if (ret) return ret; } return 0; }
static void search_modules(heim_dict_t dict, heim_object_t key, heim_object_t value, void *ctx) { struct iter_ctx *s = ctx; struct plugin2 *p = value; struct plug *pl = heim_dict_copy_value(p->names, s->n); struct common_plugin_method *cpm; if (pl == NULL) { if (p->dsohandle == NULL) return; pl = heim_uniq_alloc(sizeof(*pl), "struct-plug", plug_free); cpm = pl->dataptr = dlsym(p->dsohandle, s->name); if (cpm) { int ret; ret = cpm->init(s->context, &pl->ctx); if (ret) cpm = pl->dataptr = NULL; } heim_dict_add_value(p->names, s->n, pl); } else { cpm = pl->dataptr; } if (cpm && cpm->version >= s->min_version) heim_array_append_value(s->result, pl); heim_release(pl); }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_flags options, krb5_tkt_creds_context *pctx) { krb5_tkt_creds_context ctx; krb5_error_code ret; *pctx = NULL; ctx = heim_uniq_alloc(sizeof(*ctx), "tkt-ctx", tkt_release); if (ctx == NULL) return ENOMEM; ctx->context = context; ctx->state = tkt_init; ctx->options = options; ctx->ccache = ccache; if (ctx->options & KRB5_GC_FORWARDABLE) ctx->req_kdc_flags.b.forwardable = 1; if (ctx->options & KRB5_GC_USER_USER) { ctx->req_kdc_flags.b.enc_tkt_in_skey = 1; ctx->options |= KRB5_GC_NO_STORE; } if (options & KRB5_GC_CANONICALIZE) ctx->req_kdc_flags.b.canonicalize = 1; ret = krb5_copy_creds(context, in_cred, &ctx->in_cred); if (ret) { heim_release(ctx); return ret; } ret = krb5_unparse_name(context, ctx->in_cred->server, &ctx->server_name); if (ret) { heim_release(ctx); return ret; } *pctx = ctx; return 0; }
KRB5_LIB_FUNCTION void KRB5_LIB_CALL _krb5_sendto_ctx_set_krb5hst(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_handle handle) { heim_release(ctx->krbhst); ctx->krbhst = heim_retain(handle); }
heim_data_t _heim_db_get_value(heim_db_t db, heim_string_t table, heim_data_t key, heim_error_t *error) { heim_release(db->to_release); db->to_release = heim_db_copy_value(db, table, key, error); return db->to_release; }
void hx509_certs_free(hx509_certs *certs) { if (certs && *certs) { heim_release(*certs); *certs = NULL; } }
void _krb5_unload_plugins(krb5_context context, const char *name) { HEIMDAL_MUTEX_lock(&plugin_mutex); heim_release(modules); modules = NULL; HEIMDAL_MUTEX_unlock(&plugin_mutex); }