Files
2020-09-03 08:47:16 +00:00

669 lines
18 KiB
C

/**
* Copyright (c) 2008 Moritz Bechler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
**/
#include "php_krb5.h"
#include "php_krb5_kadm.h"
zend_class_entry *krb5_ce_kadm5;
zend_class_entry *krb5_ce_kadm5_principal;
zend_class_entry *krb5_ce_kadm5_policy;
zend_class_entry *krb5_ce_kadm5_tldata;
zend_object_handlers krb5_kadm5_handlers;
ZEND_BEGIN_ARG_INFO_EX(arginfo_KADM5__construct, 0, 0, 2)
ZEND_ARG_INFO(0, principal)
ZEND_ARG_INFO(0, credentials)
ZEND_ARG_INFO(0, use_keytab)
ZEND_ARG_ARRAY_INFO(0, config, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_KADM5_getPrincipal, 0, 0, 1)
ZEND_ARG_INFO(0, principal)
ZEND_ARG_INFO(0, noload)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_KADM5_getPrincipals, 0, 0, 0)
ZEND_ARG_INFO(0, filter)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_KADM5_createPrincipal, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, principal, KADM5Principal, 0)
ZEND_ARG_INFO(0, password)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_KADM5_getPolicy, 0, 0, 1)
ZEND_ARG_INFO(0, policy)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_KADM5_createPolicy, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, policy, KADM5Policy, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_KADM5_getPolicies, 0, 0, 0)
ZEND_ARG_INFO(0, filter)
ZEND_END_ARG_INFO()
static zend_function_entry krb5_kadm5_functions[] = {
PHP_ME(KADM5, __construct, arginfo_KADM5__construct, ZEND_ACC_CTOR | ZEND_ACC_PUBLIC)
PHP_ME(KADM5, getPrincipal, arginfo_KADM5_getPrincipal, ZEND_ACC_PUBLIC)
PHP_ME(KADM5, getPrincipals, arginfo_KADM5_getPrincipals, ZEND_ACC_PUBLIC)
PHP_ME(KADM5, createPrincipal, arginfo_KADM5_createPrincipal, ZEND_ACC_PUBLIC)
PHP_ME(KADM5, getPolicy, arginfo_KADM5_getPolicy, ZEND_ACC_PUBLIC)
PHP_ME(KADM5, createPolicy, arginfo_KADM5_createPolicy, ZEND_ACC_PUBLIC)
PHP_ME(KADM5, getPolicies, arginfo_KADM5_getPolicies, ZEND_ACC_PUBLIC)
PHP_FE_END
};
/* KADM5 ctor/dtor */
/* {{{ */
void php_krb5_free_kadm5_object(krb5_kadm5_object *obj) {
if(obj) {
kadm5_destroy(&obj->handle);
if ( obj->config.realm != NULL ) {
efree(obj->config.realm);
}
if ( obj->config.admin_server != NULL ) {
efree(obj->config.admin_server);
}
krb5_free_context(obj->ctx);
efree(obj);
}
}
/* }}} */
/* {{{ */
#if PHP_MAJOR_VERSION < 7
static void php_krb5_kadm5_object_dtor(void *obj, zend_object_handle handle TSRMLS_DC)
{
krb5_kadm5_object *object = (krb5_kadm5_object*)obj;
zend_object_std_dtor(&(object->std) TSRMLS_CC);
php_krb5_free_kadm5_object(object);
}
#else
static void php_krb5_kadm5_object_free(zend_object *obj TSRMLS_DC)
{
krb5_kadm5_object *object = (krb5_kadm5_object*)((char *)obj - XtOffsetOf(krb5_kadm5_object, std));
kadm5_destroy(&object->handle);
if ( object->config.realm != NULL ) {
efree(object->config.realm);
}
if ( object->config.admin_server != NULL ) {
efree(object->config.admin_server);
}
if ( object->ctx ) {
krb5_free_context(object->ctx);
object->ctx = NULL;
}
zend_object_std_dtor(obj);
}
#endif
/* }}} */
/* {{{ */
#if PHP_MAJOR_VERSION < 7
zend_object_value php_krb5_kadm5_object_new(zend_class_entry *ce TSRMLS_DC)
{
zend_object_value retval;
krb5_kadm5_object *object;
object = emalloc(sizeof(krb5_kadm5_object));
memset(&object->config, 0, sizeof (kadm5_config_params));
zend_object_std_init(&(object->std), ce TSRMLS_CC);
#if PHP_VERSION_ID < 50399
zend_hash_copy(object->std.properties, &ce->default_properties,
(copy_ctor_func_t) zval_add_ref, NULL,
sizeof(zval*));
#else
object_properties_init(&(object->std), ce);
#endif
retval.handle = zend_objects_store_put(object, php_krb5_kadm5_object_dtor, NULL, NULL TSRMLS_CC);
retval.handlers = &krb5_kadm5_handlers;
return retval;
}
#else
zend_object* php_krb5_kadm5_object_new(zend_class_entry *ce TSRMLS_DC)
{
krb5_kadm5_object *object = ecalloc(1, sizeof(krb5_kadm5_object) + zend_object_properties_size(ce));
zend_object_std_init(&object->std, ce TSRMLS_CC);
object_properties_init(&object->std, ce);
object->std.handlers = &krb5_kadm5_handlers;
return &object->std;
}
#endif
/* }}} */
/* Register classes */
/* {{{ */
int php_krb5_kadm5_register_classes(TSRMLS_D) {
zend_class_entry kadm5;
/** register KADM5 **/
INIT_CLASS_ENTRY(kadm5, "KADM5", krb5_kadm5_functions);
krb5_ce_kadm5 = zend_register_internal_class(&kadm5 TSRMLS_CC);
krb5_ce_kadm5->create_object = php_krb5_kadm5_object_new;
memcpy(&krb5_kadm5_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
#if PHP_MAJOR_VERSION >= 7
krb5_kadm5_handlers.offset = XtOffsetOf(krb5_kadm5_object, std);
krb5_kadm5_handlers.free_obj = php_krb5_kadm5_object_free;
#endif
/** register KADM5Principal **/
php_krb5_register_kadm5_principal(TSRMLS_C);
/** register KADM5Policy **/
php_krb5_register_kadm5_policy(TSRMLS_C);
/** register KADM5TLData **/
php_krb5_register_kadm5_tldata(TSRMLS_C);
return SUCCESS;
}
/* }}} */
static int php_krb5_kadm_parse_config(kadm5_config_params *kadm_params, zval *config TSRMLS_DC) {
int retval = 0;
zval *tmp = NULL;
if (Z_TYPE_P(config) != IS_ARRAY) {
return KRB5KRB_ERR_GENERIC;
}
/* realm */
tmp = zend_compat_hash_find(HASH_OF(config), "realm", sizeof("realm"));
if ( tmp != NULL ) {
zend_string *realm = zval_get_string(tmp TSRMLS_CC);
if ((kadm_params->realm = emalloc(1+realm->len))) {
strncpy(kadm_params->realm, realm->val, realm->len);
kadm_params->realm[realm->len] = '\0';
}
zend_string_release(realm);
kadm_params->mask |= KADM5_CONFIG_REALM;
}
/* admin_server */
tmp = zend_compat_hash_find(HASH_OF(config), "admin_server", sizeof("admin_server"));
if (tmp != NULL) {
zend_string *admin_server = zval_get_string(tmp TSRMLS_CC);
if ((kadm_params->admin_server = emalloc(1+admin_server->len))) {
strncpy(kadm_params->admin_server, admin_server->val, admin_server->len);
kadm_params->admin_server[admin_server->len] = '\0';
}
zend_string_release(admin_server);
kadm_params->mask |= KADM5_CONFIG_ADMIN_SERVER;
}
/* admin_port */
tmp = zend_compat_hash_find(HASH_OF(config), "kadmind_port", sizeof("kadmind_port"));
if (tmp != NULL) {
kadm_params->kadmind_port = zval_get_long(tmp TSRMLS_CC);
kadm_params->mask |= KADM5_CONFIG_KADMIND_PORT;
}
return retval;
}
/* {{{ proto KADM5::__construct(string $principal, string $credentials [, bool $use_keytab=0 [, array $config]])
Initialize a connection with the KADM server using the given credentials */
PHP_METHOD(KADM5, __construct)
{
kadm5_ret_t retval;
char *sprinc;
strsize_t sprinc_len;
char *spass = NULL;
strsize_t spass_len;
zend_bool use_keytab = 0;
zval* config = NULL;
krb5_kadm5_object *obj;
KRB5_SET_ERROR_HANDLING(EH_THROW);
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ba", &sprinc, &sprinc_len,
&spass, &spass_len,
&use_keytab, &config) == FAILURE) {
RETURN_FALSE;
}
KRB5_SET_ERROR_HANDLING(EH_NORMAL);
if(strlen(spass) == 0) {
zend_throw_exception(NULL, "You may not specify an empty password or keytab", 0 TSRMLS_CC);
RETURN_FALSE;
}
obj = KRB5_THIS_KADM;
if (config != NULL && php_krb5_kadm_parse_config(&(obj->config), config TSRMLS_CC)) {
zend_throw_exception(NULL, "Failed to parse kadmin config", 0 TSRMLS_CC);
RETURN_FALSE;
}
if(krb5_init_context(&obj->ctx)) {
zend_throw_exception(NULL, "Failed to initialize kerberos library", 0 TSRMLS_CC);
RETURN_FALSE;
}
if(!use_keytab) {
retval = kadm5_init_with_password(obj->ctx, sprinc, spass, KADM5_ADMIN_SERVICE, &obj->config,
KADM5_STRUCT_VERSION, KADM5_API_VERSION_3, NULL, &obj->handle);
} else {
if (strlen(spass) != spass_len) {
zend_throw_exception(NULL, "Invalid keytab path", 0 TSRMLS_CC);
krb5_free_context(obj->ctx);
obj->ctx = NULL;
RETURN_FALSE;
}
#if PHP_VERSION_ID < 50399
if((PG(safe_mode) && !php_checkuid(spass, NULL, CHECKUID_CHECK_FILE_AND_DIR)) ||
php_check_open_basedir(spass TSRMLS_CC)) {
krb5_free_context(obj->ctx);
obj->ctx = NULL;
RETURN_FALSE;
}
#else
if( php_check_open_basedir(spass TSRMLS_CC)) {
krb5_free_context(obj->ctx);
obj->ctx = NULL;
RETURN_FALSE;
}
#endif
retval = kadm5_init_with_skey(obj->ctx,sprinc, spass, KADM5_ADMIN_SERVICE, &obj->config,
KADM5_STRUCT_VERSION, KADM5_API_VERSION_3, NULL, &obj->handle);
}
if(retval != KADM5_OK) {
const char* errmsg = krb5_get_error_message(obj->ctx, (int)retval);
zend_throw_exception(NULL, errmsg, (int)retval TSRMLS_CC);
krb5_free_error_message(obj->ctx, errmsg);
krb5_free_context(obj->ctx);
obj->ctx = NULL;
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto KADM5Principal KADM5::getPrinicipal(string $principal [, boolean $noload ])
Fetch a principal entry by name */
PHP_METHOD(KADM5, getPrincipal)
{
zval *sprinc = NULL;
zend_bool noload = FALSE;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &sprinc, &noload) == FAILURE) {
RETURN_FALSE;
}
object_init_ex(return_value, krb5_ce_kadm5_principal);
#if PHP_MAJOR_VERSION < 7
zval *dummy_retval, *ctor, *znoload;
zval *args[3];
MAKE_STD_ZVAL(ctor);
ZVAL_STRING(ctor, "__construct",1);
MAKE_STD_ZVAL(znoload);
ZVAL_BOOL(znoload, noload);
args[0] = sprinc;
args[1] = getThis();
args[2] = znoload;
MAKE_STD_ZVAL(dummy_retval);
if(call_user_function(&krb5_ce_kadm5_principal->function_table,
&return_value, ctor, dummy_retval, 3,
args TSRMLS_CC) == FAILURE) {
zval_dtor(ctor);
zval_dtor(dummy_retval);
zend_throw_exception(NULL, "Failed to instantiate KADM5Principal object", 0 TSRMLS_CC);
}
zval_ptr_dtor(&ctor);
zval_ptr_dtor(&dummy_retval);
zval_ptr_dtor(&znoload);
#else
zval ctor;
zval args[3];
zval dummy_retval;
ZVAL_STRING(&ctor, "__construct");
args[0] = *sprinc;
args[1] = *getThis();
ZVAL_BOOL(&args[2], noload);
if(call_user_function(&krb5_ce_kadm5_principal->function_table, return_value, &ctor, &dummy_retval, 3,
args TSRMLS_CC) == FAILURE) {
zval_dtor(&ctor);
zval_dtor(&dummy_retval);
zval_dtor(&args[2]);
zend_throw_exception(NULL, "Failed to instantiate KADM5Principal object", 0 TSRMLS_CC);
return;
}
zval_dtor(&ctor);
zval_dtor(&dummy_retval);
zval_dtor(&args[2]);
#endif
} /* }}} */
/* {{{ proto array KADM5::getPrinicipals([string $filter])
Fetch an array of all principals matching $filter */
PHP_METHOD(KADM5, getPrincipals)
{
kadm5_ret_t retval;
krb5_kadm5_object *obj;
char *sexp = NULL;
strsize_t sexp_len;
char **princs;
int princ_count;
int i;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &sexp, &sexp_len) == FAILURE) {
RETURN_FALSE;
}
obj = KRB5_THIS_KADM;
retval = kadm5_get_principals(obj->handle, sexp, &princs, &princ_count);
if(retval) {
const char *errmsg = krb5_get_error_message(obj->ctx, (int)retval);
zend_throw_exception(NULL, errmsg, (int)retval TSRMLS_CC);
krb5_free_error_message(obj->ctx, errmsg);
return;
}
array_init(return_value);
for(i = 0; i < princ_count; i++) {
_add_next_index_string(return_value, princs[i]);
}
kadm5_free_name_list(obj->handle, princs, princ_count);
} /* }}} */
/* {{{ proto void KADM5::createPrincipal(KADM5Principal $principal [, string $password ])
Creates a principal */
PHP_METHOD(KADM5, createPrincipal)
{
kadm5_ret_t retval = 0;
zval *princ = NULL, *princname = NULL;
krb5_kadm5_principal_object *principal = NULL;
krb5_kadm5_object *obj = NULL;
char *pw = NULL;
strsize_t pw_len = 0;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &princ, krb5_ce_kadm5_principal, &pw, &pw_len) == FAILURE) {
return;
}
if ( Z_ISNULL_P(princ) ) {
zend_throw_exception(NULL, "Invalid principal object", 0 TSRMLS_CC);
return;
}
principal = KRB5_KADM_PRINCIPAL(princ);
obj = KRB5_THIS_KADM;
#if PHP_MAJOR_VERSION < 7
princname = zend_read_property(krb5_ce_kadm5_principal, princ, "princname",
sizeof("princname"),1 TSRMLS_CC);
#else
princname = zend_read_property(krb5_ce_kadm5_principal, OBJ_FOR_PROP(princ), "princname",
sizeof("princname"),1, NULL);
#endif
if ( principal->data.principal ) {
krb5_free_principal(obj->ctx, principal->data.principal);
}
zend_string *pnamestr = zval_get_string(princname TSRMLS_CC);
if(krb5_parse_name(obj->ctx, pnamestr->val, &principal->data.principal)) {
zend_string_release(pnamestr);
zend_throw_exception(NULL, "Failed to parse principal name", 0 TSRMLS_CC);
return;
}
zend_string_release(pnamestr);
principal->update_mask |= KADM5_PRINCIPAL;
principal->conn = obj;
zend_update_property(krb5_ce_kadm5_principal, OBJ_FOR_PROP(princ), "connection", sizeof("connection"), getThis() TSRMLS_CC);
retval = kadm5_create_principal(obj->handle, &principal->data, principal->update_mask, pw);
if(retval != KADM5_OK) {
const char* errmsg = krb5_get_error_message(obj->ctx, (int)retval);
zend_throw_exception(NULL, errmsg, (int)retval TSRMLS_CC);
krb5_free_error_message(obj->ctx, errmsg);
return;
}
#if PHP_MAJOR_VERSION < 7
zval *dummy_retval = NULL, *func = NULL;
MAKE_STD_ZVAL(func);
ZVAL_STRING(func, "load", 1);
MAKE_STD_ZVAL(dummy_retval);
if(call_user_function(&krb5_ce_kadm5_principal->function_table,
&princ, func, dummy_retval, 0,
NULL TSRMLS_CC) == FAILURE) {
zval_ptr_dtor(&func);
zval_ptr_dtor(&dummy_retval);
zend_throw_exception(NULL, "Failed to update KADM5Principal object", 0 TSRMLS_CC);
return;
}
zval_ptr_dtor(&func);
zval_ptr_dtor(&dummy_retval);
#else
zval func;
zval dummy_retval;
ZVAL_STRING(&func, "load");
if(call_user_function(&krb5_ce_kadm5_principal->function_table, princ, &func, &dummy_retval, 0,
NULL TSRMLS_CC) == FAILURE) {
zval_dtor(&func);
zval_dtor(&dummy_retval);
zend_throw_exception(NULL, "Failed to update KADM5Principal object", 0 TSRMLS_CC);
return;
}
zval_dtor(&func);
zval_dtor(&dummy_retval);
#endif
}
/* {{{ proto KADM5Policy KADM5::getPolicy(string $policy)
Fetches a policy */
PHP_METHOD(KADM5, getPolicy)
{
zval *spolicy = NULL;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &spolicy) == FAILURE) {
return;
}
object_init_ex(return_value, krb5_ce_kadm5_policy);
#if PHP_MAJOR_VERSION < 7
zval *dummy_retval, *ctor;
zval *args[2];
MAKE_STD_ZVAL(ctor);
ZVAL_STRING(ctor, "__construct", 1);
args[0] = spolicy;
args[1] = getThis();
MAKE_STD_ZVAL(dummy_retval);
if(call_user_function(&krb5_ce_kadm5_policy->function_table,
&return_value, ctor, dummy_retval, 2,
args TSRMLS_CC) == FAILURE) {
zval_dtor(ctor);
zval_dtor(dummy_retval);
zend_throw_exception(NULL, "Failed to instantiate KADM5Policy object", 0 TSRMLS_CC);
return;
}
zval_ptr_dtor(&ctor);
zval_ptr_dtor(&dummy_retval);
#else
zval ctor;
zval args[2];
zval dummy_retval;
ZVAL_STRING(&ctor, "__construct");
args[0] = *spolicy;
args[1] = *getThis();
if(call_user_function(&krb5_ce_kadm5_policy->function_table, return_value, &ctor, &dummy_retval, 2,
args TSRMLS_CC) == FAILURE) {
zval_dtor(&ctor);
zval_dtor(&dummy_retval);
zend_throw_exception(NULL, "Failed to instantiate KADM5Policy object", 0 TSRMLS_CC);
return;
}
zval_dtor(&ctor);
zval_dtor(&dummy_retval);
#endif
} /* }}} */
/* {{{ proto void KADM5::createPolicy(KADM5Policy $policy)
Creates a Policy */
PHP_METHOD(KADM5, createPolicy) {
kadm5_ret_t retval;
zval *zpolicy;
krb5_kadm5_policy_object *policy;
krb5_kadm5_object *obj;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zpolicy, krb5_ce_kadm5_policy) == FAILURE) {
return;
}
policy = KRB5_KADM_POLICY(zpolicy);
obj = KRB5_THIS_KADM;
policy->update_mask |= KADM5_POLICY;
policy->conn = obj;
policy->data.policy = policy->policy;
zend_update_property(krb5_ce_kadm5_policy, OBJ_FOR_PROP(zpolicy), "connection", sizeof("connection"), getThis() TSRMLS_CC);
retval = kadm5_create_policy(obj->handle, &policy->data, policy->update_mask);
if(retval != KADM5_OK) {
policy->data.policy = NULL;
const char* errmsg = krb5_get_error_message(obj->ctx, (int)retval);
zend_throw_exception(NULL, errmsg, (int)retval TSRMLS_CC);
krb5_free_error_message(obj->ctx, errmsg);
return;
}
policy->data.policy = NULL;
#if PHP_MAJOR_VERSION < 7
zval *dummy_retval, *func;
MAKE_STD_ZVAL(func);
ZVAL_STRING(func, "load", 1);
MAKE_STD_ZVAL(dummy_retval);
if(call_user_function(&krb5_ce_kadm5_policy->function_table,
&zpolicy, func, dummy_retval, 0,
NULL TSRMLS_CC) == FAILURE) {
zval_ptr_dtor(&func);
zval_ptr_dtor(&dummy_retval);
zend_throw_exception(NULL, "Failed to update KADM5Policy object", 0 TSRMLS_CC);
return;
}
zval_ptr_dtor(&func);
zval_ptr_dtor(&dummy_retval);
#else
zval func;
zval dummy_retval;
ZVAL_STRING(&func, "load");
if(call_user_function(&krb5_ce_kadm5_policy->function_table, zpolicy, &func, &dummy_retval, 0,
NULL TSRMLS_CC) == FAILURE) {
zval_dtor(&func);
zval_dtor(&dummy_retval);
zend_throw_exception(NULL, "Failed to update KADM5Policy object", 0 TSRMLS_CC);
return;
}
zval_dtor(&func);
zval_dtor(&dummy_retval);
#endif
} /* }}} */
/* {{{ proto array KADM5::getPolicies([string $filter])
Fetches all policies */
PHP_METHOD(KADM5, getPolicies)
{
kadm5_ret_t retval;
krb5_kadm5_object *obj;
char *sexp = NULL;
strsize_t sexp_len;
char **policies;
int pol_count;
int i;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &sexp, &sexp_len) == FAILURE) {
RETURN_FALSE;
}
obj = KRB5_THIS_KADM;
retval = kadm5_get_policies(obj->handle, sexp, &policies, &pol_count);
if(retval) {
const char* errmsg = krb5_get_error_message(obj->ctx, (int)retval);
zend_throw_exception(NULL, errmsg, (int)retval TSRMLS_CC);
krb5_free_error_message(obj->ctx, errmsg);
return;
}
array_init(return_value);
for(i = 0; i < pol_count; i++) {
_add_next_index_string(return_value, policies[i]);
}
kadm5_free_name_list(obj->handle, policies, pol_count);
} /* }}} */