コード例 #1
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);
}
コード例 #2
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;
}
コード例 #3
0
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;
}
コード例 #4
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;
}
コード例 #5
0
void
krb5_load_plugins(krb5_context context, const char *name, const char **paths)
{
#ifdef HAVE_DLOPEN
    heim_string_t s = heim_string_create(name);
    heim_dict_t module;
    struct dirent *entry;
    krb5_error_code ret;
    const char **di;
    DIR *d;

    HEIMDAL_MUTEX_lock(&plugin_mutex);

    if (modules == NULL) {
	modules = heim_dict_create(11);
	if (modules == NULL) {
	    HEIMDAL_MUTEX_unlock(&plugin_mutex);
	    return;
	}
    }

    module = heim_dict_copy_value(modules, s);
    if (module == NULL) {
	module = heim_dict_create(11);
	if (module == NULL) {
	    HEIMDAL_MUTEX_unlock(&plugin_mutex);
	    heim_release(s);
	    return;
	}
	heim_dict_add_value(modules, s, module);
    }
    heim_release(s);

    for (di = paths; *di != NULL; di++) {
	d = opendir(*di);
	if (d == NULL)
	    continue;
	rk_cloexec_dir(d);

	while ((entry = readdir(d)) != NULL) {
	    char *n = entry->d_name;
	    char *path = NULL;
	    heim_string_t spath;
	    struct plugin2 *p;

	    /* skip . and .. */
	    if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
		continue;

	    ret = 0;
#ifdef __APPLE__
	    { /* support loading bundles on MacOS */
		size_t len = strlen(n);
		if (len > 7 && strcmp(&n[len - 7],  ".bundle") == 0)
		    ret = asprintf(&path, "%s/%s/Contents/MacOS/%.*s", *di, n, (int)(len - 7), n);
	    }
#endif
	    if (ret < 0 || path == NULL)
		ret = asprintf(&path, "%s/%s", *di, n);

	    if (ret < 0 || path == NULL)
		continue;

	    spath = heim_string_create(n);
	    if (spath == NULL) {
		free(path);
		continue;
	    }

	    /* check if already cached */
	    p = heim_dict_copy_value(module, spath);
	    if (p == NULL) {
		p = heim_uniq_alloc(sizeof(*p), "krb5-plugin", plug_dealloc);
		if (p)
		    p->dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY);

		if (p && p->dsohandle) {
		    p->path = heim_retain(spath);
		    p->names = heim_dict_create(11);
		    heim_dict_add_value(module, spath, p);
		}
	    }
	    heim_release(spath);
	    heim_release(p);
	    free(path);
	}
	closedir(d);
    }
    heim_release(module);
    HEIMDAL_MUTEX_unlock(&plugin_mutex);
#endif /* HAVE_DLOPEN */
}
コード例 #6
0
ファイル: plugin.c プロジェクト: Kendra123/heimdal
/**
 * 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, &registered_plugins);

    HEIMDAL_MUTEX_lock(&plugin_mutex);

    s.context = context;
    s.name = name;
    s.n = heim_string_create(name);
    s.flags = flags;
    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_copy_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 &&
            !(flags & KRB5_PLUGIN_INVOKE_ALL))
	    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);
    heim_release(dict);

    return s.ret;
}