コード例 #1
0
ファイル: error.c プロジェクト: DavidMulder/heimdal
heim_string_t
heim_error_copy_string(heim_error_t error)
{
    if (heim_get_tid(error) != HEIM_TID_ERROR) {
	if (heim_get_tid(error) == heim_number_get_type_id())
	    return __heim_string_constant(strerror(heim_number_get_int((heim_number_t)error)));
	heim_abort("invalid heim_error_t");
    }
    /* XXX concat all strings */
    return heim_retain(error->msg);
}
コード例 #2
0
ファイル: error.c プロジェクト: DavidMulder/heimdal
int
heim_error_get_code(heim_error_t error)
{
    if (error == NULL)
	return -1;
    if (heim_get_tid(error) != HEIM_TID_ERROR) {
	if (heim_get_tid(error) == heim_number_get_type_id())
	    return heim_number_get_int((heim_number_t)error);
	heim_abort("invalid heim_error_t");
    }
    return error->error_code;
}
コード例 #3
0
ファイル: error.c プロジェクト: DavidMulder/heimdal
heim_error_t
heim_error_append(heim_error_t top, heim_error_t append)
{
    if (heim_get_tid(top) != HEIM_TID_ERROR) {
	if (heim_get_tid(top) == heim_number_get_type_id())
	    return top;
	heim_abort("invalid heim_error_t");
    }
    if (top->next)
	heim_release(top->next);
    top->next = heim_retain(append);
    return top;
}
コード例 #4
0
ファイル: kdc-tester.c プロジェクト: Kendra123/heimdal
static void
eval_object(heim_object_t o)
{
    heim_tid_t t = heim_get_tid(o);

    if (t == heim_array_get_type_id()) {
	heim_array_iterate_f(o, NULL, eval_array_element);
    } else if (t == heim_dict_get_type_id()) {
	const char *op = heim_dict_get_value(o, HSTR("op"));

	heim_assert(op != NULL, "op missing");

	if (strcmp(op, "repeat") == 0) {
	    eval_repeat(o);
	} else if (strcmp(op, "kinit") == 0) {
	    eval_kinit(o);
	} else if (strcmp(op, "kgetcred") == 0) {
	    eval_kgetcred(o);
	} else if (strcmp(op, "kdestroy") == 0) {
	    eval_kdestroy(o);
	} else {
	    errx(1, "unsupported ops %s", op);
	}

    } else
	errx(1, "unsupported");
}
コード例 #5
0
ファイル: json.c プロジェクト: SimonWilkinson/heimdal
int
heim_base2json(heim_object_t obj,
	       void (*out)(char *, void *), void *ctx)
{
    heim_tid_t type = heim_get_tid(obj);
    __block int fail = 0, needcomma = 0;

    switch (type) {
    case HEIM_TID_ARRAY:
	out("[ ", ctx);
	heim_array_iterate(obj, ^(heim_object_t sub) {
		if (needcomma)
		    out(", ", ctx);
		fail |= heim_base2json(sub, out, ctx);
		needcomma = 1;
	    });
	out("]", ctx);
	break;

    case HEIM_TID_DICT:
	out("{ ", ctx);
	heim_dict_iterate(obj, ^(heim_object_t key, heim_object_t value) {
		if (needcomma)
		    out(", ", ctx);
		fail |= heim_base2json(key, out, ctx);
		out(" = ", ctx);
		fail |= heim_base2json(value, out, ctx);
		needcomma = 1;
	    });
コード例 #6
0
static int
base2json(heim_object_t obj, struct twojson *j)
{
    heim_tid_t type;

    if (obj == NULL) {
	indent(j);
	j->out(j->ctx, "<NULL>\n");
    }

    type = heim_get_tid(obj);
    switch (type) {
    case HEIM_TID_ARRAY:
	indent(j);
	j->out(j->ctx, "[\n");
	j->indent++;
	heim_array_iterate_f(obj, j, array2json);
	j->indent--;
	indent(j);
	j->out(j->ctx, "]\n");
	break;

    case HEIM_TID_DICT:
	indent(j);
	j->out(j->ctx, "{\n");
	j->indent++;
	heim_dict_iterate_f(obj, j, dict2json);
	j->indent--;
	indent(j);
	j->out(j->ctx, "}\n");
	break;

    case HEIM_TID_STRING:
	indent(j);
	j->out(j->ctx, "\"");
	j->out(j->ctx, heim_string_get_utf8(obj));
	j->out(j->ctx, "\"");
	break;

    case HEIM_TID_NUMBER: {
	char num[16];
	indent(j);
	snprintf(num, sizeof(num), "%d", heim_number_get_int(obj));
	j->out(j->ctx, num);
	break;
    }
    case HEIM_TID_NULL:
	indent(j);
	j->out(j->ctx, "null");
	break;
    case HEIM_TID_BOOL:
	indent(j);
	j->out(j->ctx, heim_bool_val(obj) ? "true" : "false");
	break;
    default:
	return 1;
    }
    return 0;
}
コード例 #7
0
ファイル: db.c プロジェクト: InvLim/heimdal
/**
 * 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", "")));
}
コード例 #8
0
ファイル: db.c プロジェクト: abartlet/heimdal
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;
}
コード例 #9
0
ファイル: json.c プロジェクト: kaduk/heimdal
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;
}
コード例 #10
0
ファイル: db.c プロジェクト: InvLim/heimdal
/**
 * Open a 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_begin(heim_db_t db, int read_only, heim_error_t *error)
{
    int ret;

    if (heim_get_tid(db) != HEIM_TID_DB)
	return EINVAL;

    if (db->in_transaction && (read_only || !db->ro_tx || (!read_only && !db->ro_tx)))
	heim_abort("DB already in transaction");

    if (db->plug->setf == NULL || db->plug->delf == NULL)
	return EINVAL;

    if (db->plug->beginf) {
	ret = db->plug->beginf(db->db_data, read_only, error);
    } else if (!db->in_transaction) {
	/* Try to emulate transactions */

	if (db->plug->lockf == NULL)
	    return EINVAL; /* can't lock? -> no transactions */

	/* Assume unlock provides sync/durability */
	ret = db->plug->lockf(db->db_data, read_only, error);
	if (ret)
	    return ret;

	ret = db_replay_log(db, error);
	if (ret) {
	    ret = db->plug->unlockf(db->db_data, error);
	    return ret;
	}

	db->set_keys = heim_dict_create(11);
	if (db->set_keys == NULL)
	    return ENOMEM;
	db->del_keys = heim_dict_create(11);
	if (db->del_keys == NULL) {
	    heim_release(db->set_keys);
	    db->set_keys = NULL;
	    return ENOMEM;
	}
    } else {
	heim_assert(read_only == 0, "Internal error");
	ret = db->plug->lockf(db->db_data, 0, error);
	if (ret)
	    return ret;
    }
    db->in_transaction = 1;
    db->ro_tx = !!read_only;
    return 0;
}
コード例 #11
0
ファイル: db.c プロジェクト: InvLim/heimdal
/**
 * Iterate a callback function over keys and values from a DB.
 *
 * @param db        Open DB handle
 * @param iter_data Callback function's private data
 * @param iter_f    Callback function, called once per-key/value pair
 * @param error     Output error object
 *
 * @addtogroup heimbase
 */
void
heim_db_iterate_f(heim_db_t db, heim_string_t table, void *iter_data,
		  heim_db_iterator_f_t iter_f, heim_error_t *error)
{
    if (error != NULL)
	*error = NULL;

    if (heim_get_tid(db) != HEIM_TID_DB)
	return;

    if (!db->in_transaction)
	db->plug->iterf(db->db_data, table, iter_data, iter_f, error);
}
コード例 #12
0
ファイル: db.c プロジェクト: InvLim/heimdal
/**
 * Lookup a key's value in the DB.
 *
 * Returns 0 on success, -1 if the key does not exist in the DB, or a
 * system error number on failure.
 *
 * @param db    Open DB handle
 * @param key   Key
 * @param error Output error object
 *
 * @return the value (retained), if there is one for the given key
 *
 * @addtogroup heimbase
 */
heim_data_t
heim_db_copy_value(heim_db_t db, heim_string_t table, heim_data_t key,
		   heim_error_t *error)
{
    heim_object_t v;
    heim_data_t result;

    if (heim_get_tid(db) != HEIM_TID_DB)
	return NULL;

    if (error != NULL)
	*error = NULL;

    if (table == NULL)
	table = HSTR("");

    if (db->in_transaction) {
	heim_string_t key64;

	key64 = to_base64(key, error);
	if (key64 == NULL) {
	    if (error)
		*error = heim_error_create_enomem();
	    return NULL;
	}

	v = heim_path_copy(db->set_keys, error, table, key64, NULL);
	if (v != NULL) {
	    heim_release(key64);
	    return v;
	}
	v = heim_path_copy(db->del_keys, error, table, key64, NULL); /* can't be NULL */
	heim_release(key64);
	if (v != NULL)
	    return NULL;
    }

    result = db->plug->copyf(db->db_data, table, key, error);

    return result;
}
コード例 #13
0
ファイル: db.c プロジェクト: InvLim/heimdal
/**
 * Clone (duplicate) an open DB handle.
 *
 * This is useful for multi-threaded applications.  Applications must
 * synchronize access to any given DB handle.
 *
 * Returns EBUSY if there is an open transaction for the input db.
 *
 * @param db      Open DB handle
 * @param error   Output error object
 *
 * @return a DB handle
 *
 * @addtogroup heimbase
 */
heim_db_t
heim_db_clone(heim_db_t db, heim_error_t *error)
{
    heim_db_t result;
    int ret;

    if (heim_get_tid(db) != HEIM_TID_DB)
	heim_abort("Expected a database");
    if (db->in_transaction)
	heim_abort("DB handle is busy");

    if (db->plug->clonef == NULL) {
	return heim_db_create(heim_string_get_utf8(db->dbtype),
			      heim_string_get_utf8(db->dbname),
			      db->options, error);
    }

    result = _heim_alloc_object(&db_object, sizeof(*result));
    if (result == NULL) {
	if (error)
	    *error = heim_error_create_enomem();
	return NULL;
    }

    result->set_keys = NULL;
    result->del_keys = NULL;
    ret = db->plug->clonef(db->db_data, &result->db_data, error);
    if (ret) {
	heim_release(result);
	if (error && !*error)
	    *error = heim_error_create(ENOENT,
				       N_("Could not re-open DB while cloning", ""));
	return NULL;
    }
    db->db_data = NULL;
    return result;
}
コード例 #14
0
ファイル: db.c プロジェクト: InvLim/heimdal
/**
 * Rollback 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_rollback(heim_db_t db, heim_error_t *error)
{
    int ret = 0;

    if (heim_get_tid(db) != HEIM_TID_DB)
	return EINVAL;
    if (!db->in_transaction)
	return 0;

    if (db->plug->rollbackf != NULL)
	ret = db->plug->rollbackf(db->db_data, error);
    else if (db->plug->unlockf != NULL)
	ret = db->plug->unlockf(db->db_data, error);

    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;

    return ret;
}
コード例 #15
0
OM_uint32 GSSAPI_CALLCONV
_gss_krb5_acquire_cred_ext(OM_uint32 * minor_status,
			   const gss_name_t desired_name,
			   gss_const_OID credential_type,
			   const void *credential_data,
			   OM_uint32 time_req,
			   gss_const_OID desired_mech,
			   gss_cred_usage_t cred_usage,
			   gss_cred_id_t * output_cred_handle)
{
    krb5_init_creds_context ctx = NULL;
    krb5_get_init_creds_opt *opt = NULL;
    krb5_principal principal;
    krb5_context context;
    krb5_error_code kret;
    gsskrb5_cred handle = NULL;
    krb5_ccache ccache = NULL, ccachereplace = NULL;
    char *passwordstr = NULL;
    char *cache_name = NULL;
    char *lkdc_hostname = NULL;
    hx509_cert hxcert = NULL;
    heim_array_t bundleacl = NULL;
    krb5_principal new_name = NULL;

    GSSAPI_KRB5_INIT(&context);

    cred_usage &= GSS_C_OPTION_MASK;

    if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }
    
    if (desired_name == GSS_C_NO_NAME)
	return GSS_S_FAILURE;

    if (gss_oid_equal(credential_type, GSS_C_CRED_HEIMBASE)) {
	heim_object_t pw, cname, cert, lkdc;
	heim_dict_t dict = (heim_dict_t)credential_data;

	pw = heim_dict_copy_value(dict, _gsskrb5_kGSSICPassword);
	if (pw) {
	    if (heim_get_tid(pw) == heim_string_get_type_id()) {
		passwordstr = heim_string_copy_utf8(pw);
		if (passwordstr == NULL) {
		    kret = ENOMEM;
		    goto out;
		}
	    } else if (heim_get_tid(pw) == heim_data_get_type_id()) {
		passwordstr = malloc(heim_data_get_length(pw) + 1);
		if (passwordstr == NULL) {
		    kret = ENOMEM;
		    goto out;
		}
		memcpy(passwordstr, heim_data_get_bytes(pw), heim_data_get_length(pw));
		passwordstr[heim_data_get_length(pw)] = '\0';
	    }
	    heim_release(pw);
	}

	cname = heim_dict_copy_value(dict, _gsskrb5_kGSSICKerberosCacheName);
	if (cname) {
	    cache_name = heim_string_copy_utf8(cname);
	    heim_release(cname);
	}
	
	bundleacl = heim_dict_copy_value(dict, _gsskrb5_kGSSICAppIdentifierACL);

#ifdef PKINIT
	cert = heim_dict_copy_value(dict, _gsskrb5_kGSSICCertificate);
	if (cert) {
	    kret = hx509_cert_init_SecFramework(context->hx509ctx, cert, &hxcert);
	    if (kret)
		goto out;
	    heim_release(cert);
	}
#endif

	lkdc = heim_dict_copy_value(dict, _gsskrb5_kGSSICLKDCHostname);
	if (lkdc) {
	    lkdc_hostname = heim_string_copy_utf8(lkdc);
	    heim_release(lkdc);
	}

    } else if (gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) {
	gss_buffer_t password = (gss_buffer_t)credential_data;
	
	passwordstr = malloc(password->length + 1);
	if (passwordstr == NULL) {
	    kret = ENOMEM;
	    goto out;
	}
	
	memcpy(passwordstr, password->value, password->length);
	passwordstr[password->length] = '\0';

    } else {
	*minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */
	return GSS_S_FAILURE;
    }

    if (passwordstr == NULL && hxcert == NULL) {
	*minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */
	return GSS_S_FAILURE;
    }

    *output_cred_handle = NULL;

    handle = calloc(1, sizeof(*handle));
    if (handle == NULL) {
	*minor_status = ENOMEM;
        return (GSS_S_FAILURE);
    }

    principal = (krb5_principal)desired_name;

    HEIMDAL_MUTEX_init(&handle->cred_id_mutex);

    kret = krb5_copy_principal(context, principal, &handle->principal);
    if (kret)
	goto out;

    kret = krb5_cc_new_unique(context, NULL, NULL, &ccache);
    if (kret)
	goto out;

    kret = krb5_get_init_creds_opt_alloc(context, &opt);
    if (kret)
	goto out;
    
    krb5_get_init_creds_opt_set_default_flags(context, "gss", krb5_principal_get_realm(context, principal), opt);

    krb5_get_init_creds_opt_set_forwardable(opt, 1);
    krb5_get_init_creds_opt_set_proxiable(opt, 1);
    krb5_get_init_creds_opt_set_renew_life(opt, 3600 * 24 * 30); /* 1 month */


    if (hxcert) {
	char *cert_pool[2] = { "KEYCHAIN:", NULL };
	kret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal,
						 NULL, "KEYCHAIN:", 
						 cert_pool, NULL, 8,
						 NULL, NULL, NULL);
	if (kret)
	    goto out;
    }

    kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, NULL, opt, &ctx);
    if (kret)
	goto out;

    if (passwordstr) {
	kret = krb5_init_creds_set_password(context, ctx, passwordstr);

	memset(passwordstr, 0, strlen(passwordstr));
	free(passwordstr);
	passwordstr = NULL;

	if (kret)
	    goto out;
    }

    if (hxcert) {
	kret = krb5_init_creds_set_pkinit_client_cert(context, ctx, hxcert);
	if (kret)
	    goto out;
    }

    if (lkdc_hostname) {
	kret = krb5_init_creds_set_kdc_hostname(context, ctx, lkdc_hostname);
	free(lkdc_hostname);
	lkdc_hostname = NULL;
	if (kret)
	    goto out;
    }

    kret = krb5_init_creds_get(context, ctx);
    if (kret)
	goto out;

    handle->endtime = _krb5_init_creds_get_cred_endtime(context, ctx);

    /*
     * If we where subjected to a referral, update the name of the credential
     */
    new_name = _krb5_init_creds_get_cred_client(context, ctx);
    if (new_name && !krb5_principal_compare(context, new_name, handle->principal)) {
	krb5_free_principal(context, handle->principal);
	kret = krb5_copy_principal(context, new_name, &handle->principal);
	if (kret)
	    goto out;
    }

    /*
     * Now store the credential
     */

    if (cache_name) {
	/* check if caller told us to use a specific cache */
	kret = krb5_cc_resolve(context, cache_name, &ccachereplace);
	if (kret)
	    goto out;

    } else {
	/*
	 * check if there an existing cache to overwrite before we lay
	 * down the new cache
	 */
	(void)krb5_cc_cache_match(context, principal, &ccachereplace);
    }


    kret = krb5_init_creds_store(context, ctx, ccache);
    if (kret == 0)
	kret = krb5_init_creds_store_config(context, ctx, ccache);

    if (bundleacl)
	krb5_cc_set_acl(context, ccache, "kHEIMAttrBundleIdentifierACL", bundleacl);

    krb5_init_creds_free(context, ctx);
    ctx = NULL;
    if (kret)
	goto out;

    krb5_get_init_creds_opt_free(context, opt);
    opt = NULL;

    /*
     * If we have a credential with the same naame, lets overwrite it
     */
    
    if (ccachereplace) {
	kret = krb5_cc_move(context, ccache, ccachereplace);
	if (kret)
	    goto out;
	handle->ccache = ccachereplace;
	ccachereplace = NULL;
    } else {
	handle->ccache = ccache;
    }

    handle->usage = cred_usage;
    *minor_status = 0;
    *output_cred_handle = (gss_cred_id_t)handle;

    if (cache_name)
	free(cache_name);

    heim_release(bundleacl);

    return GSS_S_COMPLETE;

 out:
    if (bundleacl)
	heim_release(bundleacl);
    if (opt)
	krb5_get_init_creds_opt_free(context, opt);
    if (ctx)
	krb5_init_creds_free(context, ctx);
    if (lkdc_hostname)
	free(lkdc_hostname);
    if (cache_name)
	free(cache_name);
    if (passwordstr) {
	memset(passwordstr, 0, strlen(passwordstr));
	free(passwordstr);
    }
    if (ccachereplace)
	krb5_cc_close(context, ccachereplace);
    if (ccache)
	krb5_cc_destroy(context, ccache);
    if (handle) {
	if (handle->principal)
	    krb5_free_principal(context, handle->principal);

	HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
	free(handle);
    }

    *minor_status = kret;
    return GSS_S_FAILURE;
}
コード例 #16
0
ファイル: json.c プロジェクト: kaduk/heimdal
static int
base2json(heim_object_t obj, struct twojson *j)
{
    heim_tid_t type;
    int first = 0;

    if (obj == NULL) {
	if (j->flags & HEIM_JSON_F_CNULL2JSNULL) {
	    obj = heim_null_create();
	} else if (j->flags & HEIM_JSON_F_NO_C_NULL) {
	    return EINVAL;
	} else {
	    indent(j);
	    j->out(j->ctx, "<NULL>\n"); /* This is NOT valid JSON! */
	    return 0;
	}
    }

    type = heim_get_tid(obj);
    switch (type) {
    case HEIM_TID_ARRAY:
	indent(j);
	j->out(j->ctx, "[\n");
	j->indent++;
	first = j->first;
	j->first = 1;
	heim_array_iterate_f(obj, j, array2json);
	j->indent--;
	if (!j->first)
	    j->out(j->ctx, "\n");
	indent(j);
	j->out(j->ctx, "]\n");
	j->first = first;
	break;

    case HEIM_TID_DICT:
	indent(j);
	j->out(j->ctx, "{\n");
	j->indent++;
	first = j->first;
	j->first = 1;
	heim_dict_iterate_f(obj, j, dict2json);
	j->indent--;
	if (!j->first)
	    j->out(j->ctx, "\n");
	indent(j);
	j->out(j->ctx, "}\n");
	j->first = first;
	break;

    case HEIM_TID_STRING:
	indent(j);
	j->out(j->ctx, "\"");
	j->out(j->ctx, heim_string_get_utf8(obj));
	j->out(j->ctx, "\"");
	break;

    case HEIM_TID_DATA: {
	heim_dict_t d;
	heim_string_t v;
	const heim_octet_string *data;
	char *b64 = NULL;
	int ret;

	if (j->flags & HEIM_JSON_F_NO_DATA)
	    return EINVAL; /* JSON doesn't do binary */

	data = heim_data_get_data(obj);
	ret = base64_encode(data->data, data->length, &b64);
	if (ret < 0 || b64 == NULL)
	    return ENOMEM;

	if (j->flags & HEIM_JSON_F_NO_DATA_DICT) {
	    indent(j);
	    j->out(j->ctx, "\"");
	    j->out(j->ctx, b64); /* base64-encode; hope there's no aliasing */
	    j->out(j->ctx, "\"");
	    free(b64);
	} else {
	    /*
	     * JSON has no way to represent binary data, therefore the
	     * following is a Heimdal-specific convention.
	     *
	     * We encode binary data as a dict with a single very magic
	     * key with a base64-encoded value.  The magic key includes
	     * a uuid, so we're not likely to alias accidentally.
	     */
	    d = heim_dict_create(2);
	    if (d == NULL) {
		free(b64);
		return ENOMEM;
	    }
	    v = heim_string_ref_create(b64, free);
	    if (v == NULL) {
		free(b64);
		heim_release(d);
		return ENOMEM;
	    }
	    ret = heim_dict_set_value(d, heim_tid_data_uuid_key, v);
	    heim_release(v);
	    if (ret) {
		heim_release(d);
		return ENOMEM;
	    }
	    ret = base2json(d, j);
	    heim_release(d);
	    if (ret)
		return ret;
	}
	break;
    }

    case HEIM_TID_NUMBER: {
	char num[32];
	indent(j);
	snprintf(num, sizeof (num), "%d", heim_number_get_int(obj));
	j->out(j->ctx, num);
	break;
    }
    case HEIM_TID_NULL:
	indent(j);
	j->out(j->ctx, "null");
	break;
    case HEIM_TID_BOOL:
	indent(j);
	j->out(j->ctx, heim_bool_val(obj) ? "true" : "false");
	break;
    default:
	return 1;
    }
    return 0;
}
コード例 #17
0
ファイル: db.c プロジェクト: InvLim/heimdal
/**
 * 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)));
}
コード例 #18
0
ファイル: db.c プロジェクト: InvLim/heimdal
static int
json_db_open(void *plug, const char *dbtype, const char *dbname,
	     heim_dict_t options, void **db, heim_error_t *error)
{
    json_db_t jsondb;
    heim_dict_t contents = NULL;
    heim_string_t dbname_s = NULL;
    heim_string_t bkpname_s = NULL;

    if (error)
	*error = NULL;
    if (dbtype && *dbtype && strcmp(dbtype, "json"))
	return HEIM_ERROR(error, EINVAL, (EINVAL, N_("Wrong DB type", "")));
    if (dbname && *dbname && strcmp(dbname, "MEMORY") != 0) {
	char *ext = strrchr(dbname, '.');
	char *bkpname;
	size_t len;
	int ret;

	if (ext == NULL || strcmp(ext, ".json") != 0)
	    return HEIM_ERROR(error, EINVAL,
			      (EINVAL, N_("JSON DB files must end in .json",
					  "")));

	if (options) {
	    heim_object_t vc, ve, vt;

	    vc = heim_dict_get_value(options, HSTR("create"));
	    ve = heim_dict_get_value(options, HSTR("exclusive"));
	    vt = heim_dict_get_value(options, HSTR("truncate"));
	    if (vc && vt) {
		ret = open_file(dbname, 1, ve ? 1 : 0, NULL, error);
		if (ret)
		    return ret;
	    } else if (vc || ve || vt) {
		return HEIM_ERROR(error, EINVAL,
				  (EINVAL, N_("Invalid JSON DB open options",
					      "")));
	    }
	    /*
	     * We don't want cloned handles to truncate the DB, eh?
	     *
	     * We should really just create a copy of the options dict
	     * rather than modify the caller's!  But for that it'd be
	     * nicer to have copy utilities in heimbase, something like
	     * this:
	     *
	     * heim_object_t heim_copy(heim_object_t src, int depth,
	     *                         heim_error_t *error);
	     * 
	     * so that options = heim_copy(options, 1); means copy the
	     * dict but nothing else (whereas depth == 0 would mean
	     * heim_retain(), and depth > 1 would be copy that many
	     * levels).
	     */
	    heim_dict_delete_key(options, HSTR("create"));
	    heim_dict_delete_key(options, HSTR("exclusive"));
	    heim_dict_delete_key(options, HSTR("truncate"));
	}
	dbname_s = heim_string_create(dbname);
	if (dbname_s == NULL)
	    return HEIM_ENOMEM(error);
	
	len = snprintf(NULL, 0, "%s~", dbname);
	bkpname = malloc(len + 2);
	if (bkpname == NULL) {
	    heim_release(dbname_s);
	    return HEIM_ENOMEM(error);
	}
	(void) snprintf(bkpname, len + 1, "%s~", dbname);
	bkpname_s = heim_string_create(bkpname);
	free(bkpname);
	if (bkpname_s == NULL) {
	    heim_release(dbname_s);
	    return HEIM_ENOMEM(error);
	}

	ret = read_json(dbname, (heim_object_t *)&contents, error);
	if (ret)
	    return ret;

	if (contents != NULL && heim_get_tid(contents) != HEIM_TID_DICT)
	    return HEIM_ERROR(error, EINVAL,
			      (EINVAL, N_("JSON DB contents not valid JSON",
					  "")));
    }

    jsondb = heim_alloc(sizeof (*jsondb), "json_db", NULL);
    if (jsondb == NULL) {
	heim_release(contents);
	heim_release(dbname_s);
	return ENOMEM;
    }

    jsondb->last_read_time = time(NULL);
    jsondb->fd = -1;
    jsondb->dbname = dbname_s;
    jsondb->bkpname = bkpname_s;
    jsondb->read_only = 0;

    if (contents != NULL)
	jsondb->dict = contents;
    else {
	jsondb->dict = heim_dict_create(29);
	if (jsondb->dict == NULL) {
	    heim_release(jsondb);
	    return ENOMEM;
	}
    }

    *db = jsondb;
    return 0;
}