nscd_config.c revision cb5caa98562cf06753163f558cbcfe30b8f4673a
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h> /* gettext */
#include <dlfcn.h>
#include <string.h>
#include <sys/varargs.h>
#include <errno.h>
#include "nscd_db.h"
#include "nscd_config.h"
#include "nscd_cfgdef.h"
#include "nscd_log.h"
typedef struct {
rwlock_t *global;
rwlock_t *alldb;
rwlock_t *nswdb;
} nscd_cfg_lock_t;
static rwlock_t cfg_paramDB_rwlock = DEFAULTRWLOCK;
static nscd_db_t *cfg_paramDB = NULL;
static nscd_cfg_global_data_t *nscd_cfg_global_current;
static nscd_cfg_nsw_db_data_t *nscd_cfg_nsw_db_data_current;
static nscd_cfg_nsw_db_data_t *nscd_cfg_nsw_alldb_current;
static rwlock_t *nscd_cfg_global_rwlock;
static rwlock_t *nscd_cfg_nsw_db_data_rwlock;
static rwlock_t *nscd_cfg_nsw_alldb_rwlock;
extern int _nscd_cfg_num_nsw_src_all;
extern nscd_cfg_id_t *_nscd_cfg_nsw_src_all;
nscd_cfg_error_t *
_nscd_cfg_make_error(
nscd_rc_t rc,
char *msg)
{
nscd_cfg_error_t *ret;
int size, msglen;
msglen = (msg != NULL ? strlen(msg) + 1 : 0);
size = sizeof (nscd_cfg_error_t) + msglen;
ret = calloc(1, size);
if (ret == NULL)
return (NULL);
ret->rc = rc;
if (msg != NULL) {
ret->msg = (char *)ret +
sizeof (nscd_cfg_error_t);
(void) memcpy(ret->msg, msg, msglen);
}
return (ret);
}
static nscd_rc_t
_nscd_cfg_get_list(
nscd_cfg_list_t **list,
nscd_cfg_list_type_t type)
{
char *me = "_nscd_cfg_get_list";
int i, num, size;
nscd_cfg_id_t *l;
nscd_cfg_list_t *ret;
nscd_cfg_param_desc_t *pl;
nscd_cfg_stat_desc_t *sl;
void *p;
if (list == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "invalid argument: list = %p\n", list);
return (NSCD_INVALID_ARGUMENT);
}
*list = NULL;
switch (type) {
case NSCD_CFG_LIST_NSW_DB:
num = _nscd_cfg_num_nsw_db;
l = &_nscd_cfg_nsw_db[0];
break;
case NSCD_CFG_LIST_NSW_SRC:
num = _nscd_cfg_num_nsw_src_all;
l = _nscd_cfg_nsw_src_all;
break;
case NSCD_CFG_LIST_PARAM:
num = _nscd_cfg_num_param;
pl = &_nscd_cfg_param_desc[0];
break;
case NSCD_CFG_LIST_STAT:
num = _nscd_cfg_num_stat;
sl = &_nscd_cfg_stat_desc[0];
break;
default:
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "invalid argument: type (%d)\n", type);
return (NSCD_INVALID_ARGUMENT);
break;
}
size = sizeof (nscd_cfg_list_t) + sizeof (nscd_cfg_id_t *) * (num + 1);
ret = calloc(1, size);
if (ret == NULL)
return (NSCD_NO_MEMORY);
ret->num = num;
p = (char *)ret + sizeof (nscd_cfg_list_t);
ret->list = (nscd_cfg_id_t **)p;
if (type == NSCD_CFG_LIST_PARAM) {
for (i = 0; i <= num; i++)
ret->list[i] = (nscd_cfg_id_t *)&pl[i];
} else if (type == NSCD_CFG_LIST_STAT) {
for (i = 0; i <= num; i++)
ret->list[i] = (nscd_cfg_id_t *)&sl[i];
} else {
for (i = 0; i <= num; i++)
ret->list[i] = &l[i];
}
*list = ret;
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_cfg_get_param_desc_list(
nscd_cfg_param_desc_list_t **list)
{
return (_nscd_cfg_get_list((nscd_cfg_list_t **)list,
NSCD_CFG_LIST_PARAM));
}
/* find function pointer in the executable via dlopen(0) */
static nscd_rc_t
_nscd_cfg_init_funcs(
char *name,
void **func_p,
nscd_cfg_error_t **errorp)
{
char *me = "_nscd_cfg_init_funcs";
char msg[NSCD_CFG_MAX_ERR_MSG_LEN];
static void *handle = NULL;
void *sym;
nscd_rc_t rc = NSCD_SUCCESS;
if (name == NULL && handle != NULL) {
(void) dlclose(handle);
return (rc);
}
if (name == NULL)
return (rc);
if (handle == NULL) {
handle = dlopen((const char *)0, RTLD_LAZY);
if (handle == NULL) {
rc = NSCD_CFG_DLOPEN_ERROR;
(void) snprintf(msg, sizeof (msg),
gettext("unable to dlopen the nscd executable: %s"),
dlerror());
goto error_exit;
}
}
if (func_p) {
if ((sym = dlsym(handle, name)) == NULL) {
rc = NSCD_CFG_DLSYM_ERROR;
(void) snprintf(msg, sizeof (msg),
gettext("unable to get the address of a symbol in the nscd executable: %s"),
dlerror());
goto error_exit;
} else
(void) memcpy(func_p, &sym, sizeof (void *));
}
return (rc);
error_exit:
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "%s\n", msg);
if (errorp != NULL)
*errorp = _nscd_cfg_make_error(rc, msg);
return (rc);
}
/*
* FUNCTION: _nscd_cfg_create_paramDB
*
* Create the internal config parameter database
*/
static nscd_db_t *
_nscd_cfg_create_paramDB()
{
nscd_db_t *ret;
(void) rw_wrlock(&cfg_paramDB_rwlock);
ret = _nscd_alloc_db(NSCD_DB_SIZE_MEDIUM);
if (ret != NULL)
cfg_paramDB = ret;
(void) rw_unlock(&cfg_paramDB_rwlock);
return (ret);
}
/*
* FUNCTION: _nscd_cfg_add_index_entry
*
* Add a config index entry (a name to index mapping)
* to the internal configuration database.
*/
static nscd_rc_t
_nscd_cfg_add_index_entry(
char *name,
int index,
nscd_cfg_list_type_t type)
{
int *idx;
int size;
int dbe_type;
nscd_db_entry_t *db_entry;
if (name == NULL)
return (NSCD_INVALID_ARGUMENT);
if (type == NSCD_CFG_LIST_NSW_DB)
dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX;
else if (type == NSCD_CFG_LIST_NSW_SRC)
dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX;
else if (type == NSCD_CFG_LIST_PARAM)
dbe_type = NSCD_DATA_CFG_PARAM_INDEX;
else if (type == NSCD_CFG_LIST_STAT)
dbe_type = NSCD_DATA_CFG_STAT_INDEX;
size = sizeof (int);
db_entry = _nscd_alloc_db_entry(dbe_type, (const char *)name,
size, 1, 1);
if (db_entry == NULL)
return (NSCD_NO_MEMORY);
idx = (int *)*(db_entry->data_array);
*idx = index;
(void) rw_wrlock(&cfg_paramDB_rwlock);
(void) _nscd_add_db_entry(cfg_paramDB, name, db_entry,
NSCD_ADD_DB_ENTRY_FIRST);
(void) rw_unlock(&cfg_paramDB_rwlock);
return (NSCD_SUCCESS);
}
/*
* FUNCTION: _nscd_cfg_get_index
*
* Get the index of a config data item by searching the internal config
* database. Do not free the returned data.
*/
static int
_nscd_cfg_get_index(
char *name,
nscd_cfg_list_type_t type)
{
int index = -1, dbe_type;
const nscd_db_entry_t *db_entry;
if (name == NULL)
return (-1);
if (type == NSCD_CFG_LIST_NSW_DB)
dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX;
else if (type == NSCD_CFG_LIST_NSW_SRC)
dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX;
else if (type == NSCD_CFG_LIST_PARAM)
dbe_type = NSCD_DATA_CFG_PARAM_INDEX;
else if (type == NSCD_CFG_LIST_STAT)
dbe_type = NSCD_DATA_CFG_STAT_INDEX;
else
return (-1);
db_entry = _nscd_get_db_entry(cfg_paramDB, dbe_type,
(const char *)name, NSCD_GET_FIRST_DB_ENTRY, 0);
if (db_entry != NULL)
index = *(int *)*(db_entry->data_array);
return (index);
}
static nscd_rc_t
_nscd_cfg_verify_group_info(
nscd_cfg_group_info_t *g_info,
nscd_cfg_param_desc_t *gdesc)
{
char *me = "_nscd_cfg_verify_group_info";
void *vp;
nscd_cfg_group_info_t *gi;
if (_nscd_cfg_flag_is_set(gdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) {
vp = (char *)&nscd_cfg_global_default +
gdesc->g_offset;
gi = (nscd_cfg_group_info_t *)vp;
} else {
vp = (char *)&nscd_cfg_nsw_db_data_default +
gdesc->g_offset;
gi = (nscd_cfg_group_info_t *)vp;
}
if (g_info->num_param == gi->num_param &&
_nscd_cfg_bitmap_is_equal(g_info->bitmap, gi->bitmap))
return (NSCD_SUCCESS);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: group (%s) info mismatched: group info "
"(%d, %#6.4x) not equal to that of default configuration data "
"(%d, %#6.4x)\n", gdesc->id.name, g_info->num_param,
_nscd_cfg_bitmap_value(g_info->bitmap), gi->num_param,
_nscd_cfg_bitmap_value(gi->bitmap));
return (NSCD_CFG_PARAM_DESC_ERROR);
}
static nscd_rc_t
_nscd_cfg_init_nsw()
{
char *me = "_nscd_cfg_init_nsw";
int i, j, idx, rc, num;
nscd_cfg_id_t *id;
nscd_cfg_list_type_t type[2] = { NSCD_CFG_LIST_NSW_DB,
NSCD_CFG_LIST_NSW_SRC };
nscd_cfg_id_t *list[2] = { _nscd_cfg_nsw_db, NULL};
list[1] = _nscd_cfg_nsw_src_all;
for (j = 0; j < 2; j++) {
if (j == 0)
num = _nscd_cfg_num_nsw_db + 1;
else
num = _nscd_cfg_num_nsw_src_all;
for (i = 0; i < num; i++) {
/*
* _nscd_cfg_nsw_alldb is the id for the
* special ALLDB (defaults for all db)
*/
if (j == 0 && i == _nscd_cfg_num_nsw_db) {
id = &_nscd_cfg_nsw_alldb;
idx = NSCD_CFG_NSW_ALLDB_INDEX;
} else {
id = &(list[j])[i];
id->index = idx = i;
}
if (id->name == NULL)
continue;
if ((rc = _nscd_cfg_add_index_entry(id->name,
idx, type[j])) != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_ERROR)
(me, "unable to add index entry for "
"nsswitch entry %s\n", id->name);
_nscd_free_db(cfg_paramDB);
return (rc);
}
}
}
return (NSCD_SUCCESS);
}
/*
* get the address of a function in the nscd executable
* and store it in where 'dest_p' points to
*/
static nscd_rc_t
_nscd_cfg_get_funcp(
char *name,
void *dest_p,
void **gfunc_a,
nscd_cfg_error_t **errorp)
{
void *func;
nscd_rc_t rc;
if (gfunc_a != NULL) {
if (strcmp(name, NSCD_CFG_FUNC_NAME_AS_GROUP) == 0)
(void) memcpy(dest_p, gfunc_a, sizeof (void *));
return (NSCD_SUCCESS);
}
rc = _nscd_cfg_init_funcs(name, &func, errorp);
if (rc != NSCD_SUCCESS)
return (rc);
(void) memcpy(dest_p, &func, sizeof (func));
return (NSCD_SUCCESS);
}
static nscd_rc_t
_nscd_cfg_init_param()
{
char *me = "_nscd_cfg_init_param";
int i, gi, fn = 0;
nscd_cfg_id_t *id;
nscd_cfg_param_desc_t *desc, *gdesc = NULL;
nscd_cfg_group_info_t g_info;
nscd_cfg_list_type_t type = NSCD_CFG_LIST_PARAM;
nscd_rc_t rc;
void *nfunc, *vfunc;
if (_nscd_cfg_create_paramDB() == NULL)
return (NSCD_NO_MEMORY);
desc = &_nscd_cfg_param_desc[0];
/*
* need to loop to the last (+1) param description
* which is a fake group and which marks the end
* of list. It is used to signal the end of the
* previous group so that the proper data will be
* set for that group
*/
for (i = 0; i < _nscd_cfg_num_param + 1; i++, desc++) {
id = (nscd_cfg_id_t *)desc;
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_GROUP)) {
if (gdesc != NULL) {
g_info.num_param = fn;
gdesc->p_fn = fn;
if ((rc = _nscd_cfg_verify_group_info(
&g_info, gdesc)) != NSCD_SUCCESS)
return (rc);
}
gi = i;
fn = 0;
gdesc = desc;
g_info.bitmap = NSCD_CFG_BITMAP_ZERO;
nfunc = NULL;
vfunc = NULL;
/*
* set the notify/verify functions
*/
if (gdesc->nfunc_name != NULL) {
rc = _nscd_cfg_get_funcp(gdesc->nfunc_name,
&gdesc->notify, NULL, NULL);
if (rc != NULL)
return (rc);
nfunc = (void *)gdesc->notify;
}
if (gdesc->vfunc_name != NULL) {
rc = _nscd_cfg_get_funcp(gdesc->vfunc_name,
&gdesc->verify, NULL, NULL);
if (rc != NULL)
return (rc);
vfunc = (void *)gdesc->verify;
}
} else {
if (i == 0) {
_NSCD_LOG(NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: first parameter "
"description is not for a group\n");
return (NSCD_CFG_PARAM_DESC_ERROR);
}
/*
* set bitmap: the rightmost bit represents
* the first member (index = 0) in the group,
* the next bit is for the second member
* (index = 1), and so on
*/
_nscd_cfg_bitmap_set_nth(g_info.bitmap, fn);
desc->p_fn = fn++;
/*
* set the notify/verify functions
*/
if (desc->nfunc_name != NULL) {
rc = _nscd_cfg_get_funcp(desc->nfunc_name,
&desc->notify, &nfunc, NULL);
if (rc != NULL)
return (rc);
}
if (desc->vfunc_name != NULL) {
rc = _nscd_cfg_get_funcp(desc->vfunc_name,
&desc->verify, &vfunc, NULL);
if (rc != NULL)
return (rc);
}
}
/* if end of list reached, we are done */
if (i == _nscd_cfg_num_param)
break;
desc->g_index = gi;
id->index = i;
if ((rc = _nscd_cfg_add_index_entry(id->name,
i, type)) != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to add index entry for parameter "
"%s\n", id->name);
_nscd_free_db(cfg_paramDB);
return (rc);
} else {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "index entry for parameter "
"%s added\n", id->name);
}
}
return (_nscd_cfg_init_nsw());
}
static nscd_rc_t
_nscd_cfg_init_stat()
{
char *me = "_nscd_cfg_init_stat";
int i, gi, fn = 0;
nscd_cfg_id_t *id;
nscd_cfg_stat_desc_t *desc, *gdesc = NULL;
nscd_cfg_group_info_t g_info;
nscd_cfg_list_type_t type = NSCD_CFG_LIST_STAT;
nscd_rc_t rc;
void *gsfunc;
desc = &_nscd_cfg_stat_desc[0];
/*
* need to loop to the last (+1) stat description
* which is a fake group and which marks the end
* of list. It is used to signal the end of the
* previous group so that the proper data will be
* set for that group
*/
for (i = 0; i < _nscd_cfg_num_stat + 1; i++, desc++) {
id = (nscd_cfg_id_t *)desc;
if (_nscd_cfg_flag_is_set(desc->sflag,
NSCD_CFG_SFLAG_GROUP)) {
if (gdesc != NULL) {
g_info.num_param = fn;
gdesc->s_fn = fn;
if (g_info.num_param !=
gdesc->gi.num_param ||
!_nscd_cfg_bitmap_is_equal(
g_info.bitmap, gdesc->gi.bitmap)) {
_NSCD_LOG(NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: group (%s) "
"info mismatched: "
"group info (%d, %#6.4x) not "
"equal to the predefined one "
"(%d, %#6.4x)\n", gdesc->id.name,
g_info.num_param,
_nscd_cfg_bitmap_value(g_info.bitmap),
gdesc->gi.num_param,
_nscd_cfg_bitmap_value(
gdesc->gi.bitmap));
exit(1);
return (NSCD_CFG_STAT_DESC_ERROR);
}
}
gi = i;
fn = 0;
gdesc = desc;
g_info.bitmap = NSCD_CFG_BITMAP_ZERO;
gsfunc = NULL;
/*
* set the get_stat function
*/
if (gdesc->gsfunc_name != NULL) {
rc = _nscd_cfg_get_funcp(gdesc->gsfunc_name,
&gdesc->get_stat, NULL, NULL);
if (rc != NULL)
return (rc);
gsfunc = (void *)gdesc->get_stat;
}
} else {
if (i == 0) {
_NSCD_LOG(NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: first stat "
"description is not for a group\n");
return (NSCD_CFG_STAT_DESC_ERROR);
}
/*
* set bitmap: the rightmost bit represents
* the first member (index = 0) in the group,
* the next bit is for the second member
* (index = 1), and so on
*/
_nscd_cfg_bitmap_set_nth(g_info.bitmap, fn);
desc->s_fn = fn++;
/*
* set the get_stat function
*/
if (desc->gsfunc_name != NULL) {
rc = _nscd_cfg_get_funcp(desc->gsfunc_name,
&desc->get_stat, &gsfunc, NULL);
if (rc != NULL)
return (rc);
}
}
/* if end of list reached, we are done */
if (i == _nscd_cfg_num_stat)
break;
desc->g_index = gi;
id->index = i;
if ((rc = _nscd_cfg_add_index_entry(id->name,
i, type)) != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to add index entry for stat "
"description %s\n", id->name);
_nscd_free_db(cfg_paramDB);
return (rc);
} else {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "index entry for stat description "
"%s added\n", id->name);
}
}
return (NSCD_SUCCESS);
}
static nscd_rc_t
_nscd_cfg_copy_vlen_data(
void *data,
void **new_data_p,
nscd_cfg_param_desc_t *desc,
int *data_len,
nscd_bool_t in)
{
int len, dlen;
nscd_cfg_vlen_data_t *v = NULL;
*new_data_p = NULL;
*data_len = 0;
/* it is OK if there is nothing to copy */
if (data == NULL)
return (NSCD_SUCCESS);
/*
* if copy to the config store we need to allocate space
* for the extra vlen header
*/
if (desc->type == NSCD_CFG_DATA_STRING) {
len = dlen = strlen((char *)data) + 1;
if (in == nscd_true)
len += sizeof (nscd_cfg_vlen_data_t);
} else {
/*
* should not be here, since for now
* only string variable length data
* is supported
*/
*new_data_p = NULL;
return (NSCD_CFG_PARAM_DESC_ERROR);
}
v = calloc(1, len);
if (v == NULL) {
*new_data_p = NULL;
return (NSCD_NO_MEMORY);
}
/*
* if copy to the config store, set up
* the extra vlen header in which the
* pointer to, and length of, the real
* data are kept. The pointer to the real
* data, not the vlen header, is returned.
*/
if (in == nscd_true) {
v->ptr = (char *)v + sizeof (nscd_cfg_vlen_data_t);
v->len = dlen;
(void) memcpy(v->ptr, data, dlen);
*new_data_p = v->ptr;
} else {
(void) memcpy(v, data, dlen);
*new_data_p = v;
}
*data_len = dlen;
return (NSCD_SUCCESS);
}
static void
_nscd_cfg_free_vlen_data_int(
void *data)
{
nscd_cfg_vlen_data_t *v = NULL;
void *p;
if (data == NULL)
return;
p = (char *)data - sizeof (nscd_cfg_vlen_data_t);
v = (nscd_cfg_vlen_data_t *)p;
if (v->ptr == data)
free(v);
}
static nscd_rc_t
_nscd_cfg_set_vlen_data_int(
void *src,
void *dest,
nscd_bool_t global)
{
int i, offset, dlen = 0;
void *s, *d, *new;
void *cptr;
nscd_rc_t rc;
nscd_cfg_param_desc_t *desc;
desc = &_nscd_cfg_param_desc[0];
for (i = 0; i < _nscd_cfg_num_param; i++, desc++) {
if (global == nscd_true &&
_nscd_cfg_flag_is_not_set(desc->pflag,
NSCD_CFG_PFLAG_GLOBAL))
continue;
else if (global != nscd_true &&
_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_GLOBAL))
continue;
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA)) {
offset = desc->g_offset + desc->p_offset;
s = (char *)src + offset;
cptr = *(char **)s;
rc = _nscd_cfg_copy_vlen_data(cptr, &new,
desc, &dlen, nscd_true);
if (rc != NSCD_SUCCESS)
return (rc);
d = (char *)dest + offset;
/* free the old vlen data */
if (*(char **)d == NULL)
_nscd_cfg_free_vlen_data_int(*(char **)d);
*(char **)d = new;
}
}
return (NSCD_SUCCESS);
}
static void *
_nscd_cfg_locate_vlen_data(
void *cfg_data,
int *len)
{
void *ptr, *ret;
ptr = *(char **)cfg_data;
ret = ptr;
if (ret == NULL) {
*len = 0;
return (NULL);
}
ptr = (char *)ptr - sizeof (nscd_cfg_vlen_data_t);
*len = ((nscd_cfg_vlen_data_t *)ptr)->len;
return (ret);
}
static void
_nscd_cfg_lock(
nscd_bool_t is_read,
nscd_cfg_lock_t *cfglock)
{
int (*lockfunc)(rwlock_t *);
if (cfglock == NULL)
return;
if (is_read == nscd_true)
lockfunc = rw_rdlock;
else
lockfunc = rw_wrlock;
if (cfglock->global != NULL) {
(lockfunc)(cfglock->global);
return;
}
if (cfglock->alldb != NULL)
(lockfunc)(cfglock->alldb);
if (cfglock->nswdb != NULL)
(lockfunc)(cfglock->nswdb);
}
static void
_nscd_cfg_unlock(
nscd_cfg_lock_t *cfglock)
{
if (cfglock == NULL)
return;
if (cfglock->global != NULL) {
(void) rw_unlock(cfglock->global);
free(cfglock);
return;
}
if (cfglock->nswdb != NULL)
(void) rw_unlock(cfglock->nswdb);
if (cfglock->alldb != NULL)
(void) rw_unlock(cfglock->alldb);
free(cfglock);
}
/*
* If vlen_data_addr is given, it will be set to the
* address of the pointer pointing to the vlen data.
* 'cfglock' will be set to point to the reader/writer
* lock(s) protecting the (group) configuration data.
*/
static nscd_rc_t
_nscd_cfg_locate_cfg_data(
void **cfg_data,
nscd_bool_t is_read,
nscd_cfg_param_desc_t *desc,
nscd_cfg_id_t *nswdb,
nscd_bool_t get_group,
void **vlen_data_addr,
int *len,
nscd_cfg_lock_t **cfglock)
{
int offset;
*cfg_data = NULL;
if (len != NULL)
*len = 0;
if (vlen_data_addr != NULL)
*vlen_data_addr = NULL;
if (cfglock != NULL) {
*cfglock = calloc(1, sizeof (nscd_cfg_lock_t));
if (*cfglock == NULL)
return (NSCD_NO_MEMORY);
}
/* assume if nswdb is NULL, the param is a global one */
if (nswdb == NULL) {
offset = desc->g_offset;
if (get_group != nscd_true)
offset += desc->p_offset;
*cfg_data = (char *)nscd_cfg_global_current + offset;
if (cfglock != NULL)
(*cfglock)->global = nscd_cfg_global_rwlock;
} else if (nswdb->index == NSCD_CFG_NSW_ALLDB_INDEX) {
offset = desc->g_offset;
if (get_group != nscd_true)
offset += desc->p_offset;
*cfg_data = (char *)nscd_cfg_nsw_alldb_current +
offset;
if (cfglock != NULL)
(*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock;
} else {
offset = nswdb->index *
(sizeof (nscd_cfg_nsw_db_data_t)) + desc->g_offset;
if (get_group != nscd_true)
offset += desc->p_offset;
*cfg_data = (char *)nscd_cfg_nsw_db_data_current +
offset;
if (cfglock != NULL) {
(*cfglock)->nswdb =
&nscd_cfg_nsw_db_data_rwlock[nswdb->index];
(*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock;
}
}
/* lock the config data */
if (cfglock != NULL)
_nscd_cfg_lock(is_read, *cfglock);
if (get_group != nscd_true &&
_nscd_cfg_flag_is_not_set(desc->pflag,
NSCD_CFG_PFLAG_GROUP) &&
(_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA))) {
if (vlen_data_addr != NULL)
*vlen_data_addr = *cfg_data;
*cfg_data = _nscd_cfg_locate_vlen_data(*cfg_data, len);
return (NSCD_SUCCESS);
}
if (len != NULL) {
if (get_group == nscd_true)
*len = desc->g_size;
else
*len = desc->p_size;
}
return (NSCD_SUCCESS);
}
/*
* perform the preliminary (range) check on 'data' based on the
* datatype (desc->datatype) of the config parameter
*/
nscd_rc_t
_nscd_cfg_prelim_check(
nscd_cfg_param_desc_t *desc,
void *data,
nscd_cfg_error_t **errorp)
{
char *me = "_nscd_cfg_prelim_check";
char msg[NSCD_CFG_MAX_ERR_MSG_LEN];
nscd_cfg_str_check_t *sc;
nscd_cfg_int_check_t *ic;
nscd_cfg_bitmap_check_t *bmc;
nscd_rc_t rc = NSCD_CFG_PRELIM_CHECK_FAILED;
if ((nscd_cfg_str_check_t *)desc->p_check == NULL)
return (NSCD_SUCCESS);
switch (desc->type) {
case NSCD_CFG_DATA_STRING:
sc = (nscd_cfg_str_check_t *)desc->p_check;
if (sc->must_not_null == nscd_true && data == NULL) {
if (errorp == NULL)
break;
(void) snprintf(msg, sizeof (msg),
gettext("data must be specified for %s"),
desc->id.name);
break;
}
if (data == NULL) {
rc = NSCD_SUCCESS;
break;
}
if (sc->maxlen != 0 &&
strlen((char *)data) > sc->maxlen) {
if (errorp == NULL)
break;
(void) snprintf(msg, sizeof (msg),
gettext("length of data (%s) for %s larger than %d"),
(char *)data, desc->id.name, sc->maxlen);
break;
}
rc = NSCD_SUCCESS;
break;
case NSCD_CFG_DATA_INTEGER:
ic = (nscd_cfg_int_check_t *)desc->p_check;
if (*(int *)data > ic->max ||
*(int *)data < ic->min) {
if (errorp == NULL)
break;
(void) snprintf(msg, sizeof (msg),
gettext("data (%d) for %s out of range (%d - %d)"),
*(int *)data, desc->id.name,
ic->min, ic->max);
break;
}
rc = NSCD_SUCCESS;
break;
case NSCD_CFG_DATA_BITMAP:
bmc = (nscd_cfg_bitmap_check_t *)desc->p_check;
if (_nscd_cfg_bitmap_value(*(nscd_cfg_bitmap_t *)data) &
~(bmc->valid_bits)) {
if (errorp == NULL)
break;
(void) snprintf(msg, sizeof (msg),
gettext("data (%#6.4x) for %s contain bit not in 0x%x"),
_nscd_cfg_bitmap_value(
*(nscd_cfg_bitmap_t *)data),
desc->id.name,
_nscd_cfg_bitmap_value(bmc->valid_bits));
break;
}
rc = NSCD_SUCCESS;
break;
}
if (rc != NSCD_SUCCESS && errorp != NULL) {
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "invalid argument: %s\n", (*errorp)->msg);
}
return (rc);
}
static nscd_rc_t
_nscd_cfg_notify_i(
nscd_cfg_param_desc_t *desc,
nscd_cfg_id_t *nswdb,
int *skip,
nscd_cfg_error_t **errorp)
{
char *me = "_nscd_cfg_notify_i";
int i, num, skip_bk;
void *cfg_data, *cdata;
void *cookie = NULL;
nscd_rc_t rc;
nscd_cfg_flag_t dflag, dflag1;
nscd_cfg_bitmap_t bitmap_c, bitmap_s, *bitmap_addr;
nscd_cfg_group_info_t *gi;
if (errorp != NULL)
*errorp = NULL;
if (skip == NULL)
skip = &skip_bk;
*skip = 0;
if (_nscd_cfg_flag_is_not_set(desc->pflag,
NSCD_CFG_PFLAG_GROUP)) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: expect parameter description for group, "
"but receive parameter description is for %s\n",
desc->id.name);
return (NSCD_CFG_PARAM_DESC_ERROR);
}
/*
* Set data flag going with data to be sent to the
* verify/notify routines. Allowing the config flag
* be exipandable, set the bits one by one.
*/
dflag = NSCD_CFG_FLAG_ZERO;
dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA);
dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_INIT);
dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP);
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_INIT_SET_ALL_DB))
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_SET_ALL_DB);
/* get to the group data in the config store */
rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true,
desc, nswdb, nscd_true, NULL, NULL, NULL);
if (rc != NSCD_SUCCESS)
goto error;
/*
* the static bitmap associated with the group
* may be replaced before sending to the components,
* so save the bitmap for later use
*/
gi = _nscd_cfg_get_gi(cfg_data);
bitmap_c = gi->bitmap;
bitmap_addr = &(gi->bitmap);
/*
* the elements in this group will all be handled
* so the caller can skip them
*/
*skip = desc->p_fn;
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP))
/* send the entire group just once */
num = 1;
else { /* send individual members one by one */
num = desc->p_fn;
/*
* skip the first desc which is for the group
* and get to the desc for the first member
*/
desc++;
dflag = _nscd_cfg_flag_unset(dflag,
NSCD_CFG_DFLAG_GROUP);
}
dflag1 = dflag;
for (i = 0; i < num; i++, desc++) {
dflag = dflag1;
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) {
/* set the bitmap to select just this member */
bitmap_s = NSCD_CFG_BITMAP_ZERO;
_nscd_cfg_bitmap_set_nth(bitmap_s, i);
/* replace the bitmap in the cfg data */
_nscd_cfg_bitmap_set(bitmap_addr, bitmap_s);
/*
* send the whole group but with only one
* member selected
*/
cdata = cfg_data;
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_GROUP);
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_BIT_SELECTED);
} else {
/*
* send param data or group data:
* param data - non-xero desc->p_offset
* group data - zero desc->p_offset
*/
cdata = (char *)cfg_data + desc->p_offset;
/*
* if variable length data, need to send pointer
* to the data (not the address of the pointer)
*/
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA))
cdata = *(char **)cdata;
}
if (desc->verify != NULL) {
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_VERIFY);
rc = desc->verify(cdata, desc, nswdb,
dflag, errorp, &cookie);
if (rc != NSCD_SUCCESS)
goto error;
}
if (desc->notify != NULL) {
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_NOTIFY);
rc = desc->notify(cfg_data, desc, nswdb,
dflag, errorp, cookie);
if (rc != NSCD_SUCCESS)
goto error;
}
}
rc = NSCD_SUCCESS;
/* restore the bitmap in the cfg data */
_nscd_cfg_bitmap_set(bitmap_addr, bitmap_c);
error:
return (rc);
}
static nscd_rc_t
_nscd_cfg_notify_init(
nscd_cfg_error_t **errorp)
{
int i, j, skip;
nscd_rc_t rc;
nscd_cfg_id_t *nswdb = NULL;
nscd_cfg_param_desc_t *desc;
if (errorp != NULL)
*errorp = NULL;
for (i = 0; i < _nscd_cfg_num_param; i++) {
desc = &_nscd_cfg_param_desc[i];
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_GLOBAL)) { /* global cfg data */
rc = _nscd_cfg_notify_i(desc, NULL, &skip, errorp);
} else {
/*
* if use defaults for all nsswitch database,
* send the config data to verify/notify once
*/
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_INIT_SET_ALL_DB)) {
nswdb = &_nscd_cfg_nsw_alldb;
rc = _nscd_cfg_notify_i(desc, nswdb,
&skip, errorp);
} else { /* send data once for each nsw db */
for (j = 0; j < _nscd_cfg_num_nsw_db;
j++) {
nswdb = &_nscd_cfg_nsw_db[j];
rc = _nscd_cfg_notify_i(desc,
nswdb, &skip, errorp);
}
}
}
if (rc != NSCD_SUCCESS)
return (rc);
i += skip;
}
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_cfg_init(
nscd_cfg_error_t **errorp)
{
int i, j, datalen;
int dbi = 0, dbj = 0;
char *dest, *src;
char *dbni = NULL, *dbnj = NULL;
nscd_rc_t rc;
nscd_cfg_nsw_spc_default_t *spc;
if (errorp != NULL)
*errorp = NULL;
rc = _nscd_cfg_init_param();
if (rc != NSCD_SUCCESS)
return (rc);
rc = _nscd_cfg_init_stat();
if (rc != NSCD_SUCCESS)
return (rc);
nscd_cfg_global_current = calloc(1,
sizeof (nscd_cfg_global_data_t));
if (nscd_cfg_global_current == NULL)
return (NSCD_NO_MEMORY);
nscd_cfg_nsw_alldb_current = calloc(1,
sizeof (nscd_cfg_nsw_db_data_t));
if (nscd_cfg_nsw_alldb_current == NULL)
return (NSCD_NO_MEMORY);
nscd_cfg_nsw_db_data_current = calloc(_nscd_cfg_num_nsw_db,
sizeof (nscd_cfg_nsw_db_data_t));
if (nscd_cfg_nsw_db_data_current == NULL)
return (NSCD_NO_MEMORY);
nscd_cfg_global_rwlock = calloc(1, sizeof (rwlock_t));
if (nscd_cfg_global_rwlock == NULL)
return (NSCD_NO_MEMORY);
(void) rwlock_init(nscd_cfg_global_rwlock, NULL, NULL);
*nscd_cfg_global_current = nscd_cfg_global_default;
rc = _nscd_cfg_set_vlen_data_int(&nscd_cfg_global_default,
nscd_cfg_global_current, nscd_true);
if (rc != NSCD_SUCCESS)
return (rc);
nscd_cfg_nsw_db_data_rwlock = calloc(_nscd_cfg_num_nsw_db,
sizeof (rwlock_t));
if (nscd_cfg_nsw_db_data_rwlock == NULL)
return (NSCD_NO_MEMORY);
/* set per switch db config to the default for all db's */
for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
nscd_cfg_nsw_db_data_current[i] =
nscd_cfg_nsw_db_data_default;
(void) rwlock_init(&nscd_cfg_nsw_db_data_rwlock[i],
NULL, NULL);
}
/* add db specific defaults */
for (i = 0; i < _nscd_cfg_num_nsw_default; i++) {
if (_nscd_cfg_nsw_spc_default[i].data == NULL)
continue;
if (_nscd_cfg_nsw_spc_default[i].db != dbni) {
for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
if (strcmp(_nscd_cfg_nsw_db[j].name,
_nscd_cfg_nsw_spc_default[i].db) != 0)
continue;
dbi = _nscd_cfg_nsw_db[j].index;
dbni = _nscd_cfg_nsw_db[j].name;
break;
}
}
dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] +
_nscd_cfg_nsw_spc_default[i].group_off +
_nscd_cfg_nsw_spc_default[i].param_off;
src = _nscd_cfg_nsw_spc_default[i].data;
datalen = _nscd_cfg_nsw_spc_default[i].data_len;
(void) memcpy(dest, src, datalen);
}
/* add db specific defaults via links */
for (i = 0; i < _nscd_cfg_num_link_default; i++) {
if (_nscd_cfg_nsw_link_default[i].data == NULL)
continue;
spc = _nscd_cfg_nsw_link_default[i].data;
if (_nscd_cfg_nsw_link_default[i].db != dbni) {
for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
if (strcmp(_nscd_cfg_nsw_db[j].name,
_nscd_cfg_nsw_link_default[i].db) != 0)
continue;
dbi = _nscd_cfg_nsw_db[j].index;
dbni = _nscd_cfg_nsw_db[j].name;
break;
}
}
dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] +
_nscd_cfg_nsw_link_default[i].group_off +
_nscd_cfg_nsw_link_default[i].param_off;
if (_nscd_cfg_nsw_db[j].name != dbnj) {
for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
if (strcmp(spc->db,
_nscd_cfg_nsw_db[j].name) != 0)
continue;
dbnj = _nscd_cfg_nsw_db[j].name;
dbj = _nscd_cfg_nsw_db[j].index;
break;
}
}
src = (char *)&nscd_cfg_nsw_db_data_current[dbj] +
spc->group_off + spc->param_off;
datalen = spc->data_len;
(void) memcpy(dest, src, datalen);
}
/* fix up variable length fields */
for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
rc = _nscd_cfg_set_vlen_data_int(
&nscd_cfg_nsw_db_data_current[i],
&nscd_cfg_nsw_db_data_current[i], nscd_false);
if (rc != NSCD_SUCCESS)
return (rc);
}
nscd_cfg_nsw_alldb_rwlock = calloc(1, sizeof (rwlock_t));
if (nscd_cfg_nsw_alldb_rwlock == NULL)
return (NSCD_NO_MEMORY);
(void) rwlock_init(nscd_cfg_nsw_alldb_rwlock, NULL, NULL);
rc = _nscd_cfg_set_vlen_data_int(
&nscd_cfg_nsw_db_data_default,
&nscd_cfg_nsw_alldb_current, nscd_false);
if (rc != NSCD_SUCCESS)
return (rc);
/*
* notify and send the configuration data to
* the nscd components
*/
rc = _nscd_cfg_notify_init(errorp);
if (rc != NSCD_SUCCESS)
return (rc);
return (NSCD_SUCCESS);
}
static nscd_rc_t
_nscd_cfg_get_handle_common(
nscd_cfg_list_type_t type,
char *name,
char *nswdb_name,
nscd_cfg_handle_t **handle,
nscd_cfg_error_t **errorp)
{
int i, is_global;
char *desc_str;
nscd_cfg_handle_t *h;
nscd_cfg_param_desc_t *pdesc;
nscd_cfg_stat_desc_t *sdesc;
char *me = "_nscd_cfg_get_handle_common";
char msg[NSCD_CFG_MAX_ERR_MSG_LEN];
nscd_rc_t rc = NSCD_INVALID_ARGUMENT;
if (handle == NULL) {
(void) snprintf(msg, sizeof (msg),
gettext("address of handle not specified"));
if (errorp)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "invalid argument: %s\n", msg);
return (rc);
}
*handle = NULL;
if (name == NULL) {
(void) snprintf(msg, sizeof (msg),
gettext("name not specified"));
if (errorp)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "invalid argument: %s\n");
return (rc);
}
h = calloc(1, sizeof (nscd_cfg_handle_t));
if (h == NULL)
return (NSCD_NO_MEMORY);
h->type = type;
if (type == NSCD_CFG_LIST_PARAM)
desc_str = gettext("configuration parameter");
else
desc_str = gettext("statistics");
/* get param or stat descriptor */
i = _nscd_cfg_get_index(name, type);
if (i != -1) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "%s: index of %s is %d\n", desc_str, name, i);
if (type == NSCD_CFG_LIST_PARAM) {
pdesc = &_nscd_cfg_param_desc[i];
(void) memcpy(&h->desc, &pdesc, sizeof (pdesc));
is_global = _nscd_cfg_flag_is_set(
pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL);
/* hidden params are not exposed */
if (_nscd_cfg_flag_is_set(
pdesc->pflag, NSCD_CFG_PFLAG_HIDDEN))
i = -1;
if (_nscd_cfg_flag_is_set(pdesc->pflag,
NSCD_CFG_PFLAG_OBSOLETE)) {
_NSCD_LOG(NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_WARNING)
(me,
gettext("%s: %s is obsolete and will be ignored\n"),
desc_str, name);
}
} else {
sdesc = &_nscd_cfg_stat_desc[i];
(void) memcpy(&h->desc, &sdesc, sizeof (sdesc));
is_global = _nscd_cfg_flag_is_set(
sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL);
}
}
if (i == -1) {
(void) snprintf(msg, sizeof (msg),
gettext("%s: unknown name \"%s\""), desc_str, name);
if (errorp)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "%s\n", msg);
free(h);
return (rc);
}
/*
* if the param/stat is not a global one, we need to
* know which nsswitch database we are dealing with
*/
if (is_global == 0) {
if (nswdb_name == NULL) {
(void) snprintf(msg, sizeof (msg),
gettext("%s: switch database name not specified"),
desc_str);
if (errorp)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "%s for non-global param or stat %s\n",
msg, name);
free(h);
return (rc);
}
} else {
if (nswdb_name != NULL) {
(void) snprintf(msg, sizeof (msg),
gettext("%s: switch database specified for global data"),
desc_str);
if (errorp)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "%s %s\n", msg, name);
free(h);
return (rc);
}
*handle = h;
return (NSCD_SUCCESS);
}
/* get nsw DB id */
i = _nscd_cfg_get_index(nswdb_name, NSCD_CFG_LIST_NSW_DB);
if (i != -1) {
if (i == NSCD_CFG_NSW_ALLDB_INDEX)
h->nswdb = &_nscd_cfg_nsw_alldb;
else
h->nswdb = &_nscd_cfg_nsw_db[i];
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "%s: index of %s is %d\n",
desc_str, nswdb_name, i);
} else {
(void) snprintf(msg, sizeof (msg),
gettext("%s: unknown switch database name \"%s\""),
desc_str, nswdb_name);
if (errorp)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "%s\n", msg);
free(h);
return (NSCD_CFG_UNSUPPORTED_SWITCH_DB);
}
*handle = h;
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_cfg_get_handle(
char *param_name,
char *nswdb_name,
nscd_cfg_handle_t **handle,
nscd_cfg_error_t **errorp)
{
return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_PARAM,
param_name, nswdb_name, handle, errorp));
}
nscd_rc_t
_nscd_cfg_get_stat_handle(
char *stat_name,
char *nswdb_name,
nscd_cfg_handle_t **handle,
nscd_cfg_error_t **errorp)
{
return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_STAT,
stat_name, nswdb_name, handle, errorp));
}
void
_nscd_cfg_free_handle(
nscd_cfg_handle_t *handle)
{
free(handle);
}
static void
_nscd_cfg_free_vlen_data_group(
nscd_cfg_param_desc_t *gdesc,
void *group_data,
nscd_bool_t in)
{
int num;
void *dest, *ptr;
nscd_cfg_param_desc_t *desc;
desc = gdesc;
num = ((nscd_cfg_group_info_t *)group_data)->num_param;
while (num-- > 0) {
desc++;
/* skip fixed length data */
if (_nscd_cfg_flag_is_not_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA))
continue;
dest = (char *)group_data + desc->p_offset;
ptr = *(char **)dest;
if (ptr == NULL)
continue;
if (in == nscd_true)
_nscd_cfg_free_vlen_data_int(ptr);
else
free(ptr);
}
}
void
_nscd_cfg_free_param_data(
void *data)
{
if (data == NULL)
return;
free(data);
}
void
_nscd_cfg_free_group_data(
nscd_cfg_handle_t *handle,
void *data)
{
nscd_cfg_param_desc_t *desc;
nscd_cfg_group_info_t *gi;
if (handle == NULL || data == NULL)
return;
desc = _nscd_cfg_get_desc(handle);
gi = (nscd_cfg_group_info_t *)data;
if (desc->p_fn != gi->num_param)
return;
_nscd_cfg_free_vlen_data_group(desc, data, nscd_false);
free(data);
}
void
_nscd_cfg_free_error(
nscd_cfg_error_t *error)
{
if (error == NULL)
return;
free(error);
}
static nscd_rc_t
_nscd_cfg_copy_param_data(
nscd_cfg_param_desc_t *desc,
void *dest,
void *pdata,
nscd_bool_t in,
nscd_bool_t set_addr)
{
char *me = "_nscd_cfg_copy_param_data";
void *tmp;
int dlen;
nscd_rc_t rc = NSCD_SUCCESS;
if (desc == NULL || dest == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "input desc == %p, dest == %p\n", desc, dest);
return (NSCD_INVALID_ARGUMENT);
}
/* fixed length data */
if (_nscd_cfg_flag_is_not_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA)) {
(void) memcpy(dest, pdata, desc->p_size);
goto done;
}
/* variable length data from this point on */
/* make a copy of the variable length data */
rc = _nscd_cfg_copy_vlen_data(pdata, &tmp, desc, &dlen, in);
if (rc != NSCD_SUCCESS)
goto done;
if (in == nscd_true) { /* data to internal */
/* free the variable length data in the config store */
if (*(char **)dest != NULL)
_nscd_cfg_free_vlen_data_int(*(char **)dest);
}
if (set_addr == nscd_true) {
/*
* set the addr of the vlen data
*/
*(char **)dest = tmp;
} else {
/*
* copy the data content (not address)
*/
(void) memcpy(dest, tmp, dlen);
}
done:
return (rc);
}
static nscd_rc_t
_nscd_cfg_copy_group_data_in(
nscd_cfg_param_desc_t *gdesc,
nscd_cfg_group_info_t *gi,
void *group_dest,
void *group_src)
{
int i, num;
nscd_cfg_param_desc_t *desc;
void *src, *dest;
i = 0;
num = gi->num_param;
desc = gdesc;
while (num-- > 0) {
desc++;
/* if member not selected by bitmap, skip */
if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++))
continue;
src = (char *)group_src + desc->p_offset;
dest = (char *)group_dest + desc->p_offset;
/*
* if variable length data, free and replace the old
* with the new
*/
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA)) {
_nscd_cfg_free_vlen_data_int(*(char **)dest);
*(char **)dest = *(char **)src;
*(char **)src = NULL;
} else {
/*
* fixed length data, just copy it
*/
(void) memcpy(dest, src, desc->p_size);
}
}
return (NSCD_SUCCESS);
}
static nscd_rc_t
_nscd_cfg_copy_group_data_out(
nscd_cfg_param_desc_t *gdesc,
void *group_dest,
void *group_src)
{
char *me = "_nscd_cfg_copy_group_data_out";
void *src, *dest;
int dlen;
int num;
nscd_cfg_group_info_t *gi;
nscd_rc_t rc = NSCD_SUCCESS;
nscd_cfg_param_desc_t *desc;
if (group_dest == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "input group_dest = NULL\n");
return (NSCD_INVALID_ARGUMENT);
}
gi = _nscd_cfg_get_gi(group_src);
num = gi->num_param;
desc = gdesc;
while (num-- > 0) {
desc++;
dest = (char *)group_dest + desc->p_offset;
src = (char *)group_src + desc->p_offset;
/*
* if variable length data, get the real
* address and length of the data
*/
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA)) {
src = _nscd_cfg_locate_vlen_data(src, &dlen);
if (dlen == NULL)
continue;
}
/*
* The nscd_true asks _nscd_cfg_copy_param_data
* to set addr of the vlen data in 'dest' rather
* than copying the data content
*/
rc = _nscd_cfg_copy_param_data(desc, dest, src,
nscd_false, nscd_true);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to copy param data for %s\n",
desc->id.name);
_nscd_cfg_free_vlen_data_group(gdesc,
group_dest, nscd_false);
free(group_dest);
return (rc);
}
}
/*
* set group bitmap
*/
(void) memcpy(group_dest, group_src,
sizeof (nscd_cfg_group_info_t));
return (rc);
}
/*
* group_cfg is needed always; group_src may be NULL if
* param_index not zero and pdata not NULL; group_cfg and
* pdata should not be both non-NULL
*/
static nscd_rc_t
_nscd_cfg_copy_group_data_merge(
nscd_cfg_param_desc_t *gdesc,
void **group_dest,
void *group_src,
void *group_cfg,
int param_index,
void *pdata)
{
char *me = "_nscd_cfg_copy_group_data_merge";
void *src, *dest, *tmp_dest = NULL;
int num, i = 0;
nscd_cfg_group_info_t *gi;
nscd_rc_t rc = NSCD_SUCCESS;
nscd_cfg_param_desc_t *desc;
nscd_cfg_bitmap_t bitmap;
if (group_dest == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "input **group_dest == NULL\n");
return (NSCD_INVALID_ARGUMENT);
}
if (group_cfg == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "input **group_cfg == NULL\n");
return (NSCD_INVALID_ARGUMENT);
}
if (param_index != NULL && pdata == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "param_index != NULL but pdata == %p\n", pdata);
return (NSCD_INVALID_ARGUMENT);
}
tmp_dest = calloc(1, gdesc->g_size);
if (tmp_dest == NULL)
return (NSCD_NO_MEMORY);
if (group_src != NULL)
gi = _nscd_cfg_get_gi(group_src);
else {
gi = _nscd_cfg_get_gi(group_cfg);
bitmap = NSCD_CFG_BITMAP_ZERO;
}
num = gi->num_param;
desc = gdesc;
while (num-- > 0) {
desc++;
dest = (char *)tmp_dest + desc->p_offset;
/*
* if member not selected by bitmap in group_src,
* get the member data in group_cfg
*/
if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++) ||
group_src == NULL) {
src = (char *)group_cfg + desc->p_offset;
} else
src = (char *)group_src + desc->p_offset;
if (desc->id.index == param_index) {
/* use the param data in pdata if provided */
src = pdata;
_nscd_cfg_bitmap_set_nth(bitmap, i);
}
/*
* if variable length data, get to the data
* instead of pointer to the data
*/
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA))
src = *(char **)src;
/*
* nscd_true asks _nscd_cfg_copy_param_data to
* set addr of the vlen data in 'dest' rather
* than copying the data content
*/
rc = _nscd_cfg_copy_param_data(desc, dest, src,
nscd_true, nscd_true);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to copy param data for %s\n",
desc->id.name);
_nscd_cfg_free_vlen_data_group(gdesc,
tmp_dest, nscd_true);
free(tmp_dest);
return (rc);
}
}
*group_dest = tmp_dest;
/*
* set bitmap: if input is group data, use the one
* given; if input is param data, use the one computed
* above
*/
if (group_src != NULL)
(void) memcpy(*group_dest, group_src,
sizeof (nscd_cfg_group_info_t));
else {
gi = _nscd_cfg_get_gi(*group_dest);
_nscd_cfg_bitmap_set(&gi->bitmap, bitmap);
}
return (rc);
}
/* ARGSUSED */
nscd_rc_t
_nscd_cfg_get(
nscd_cfg_handle_t *handle,
void **data,
int *data_len,
nscd_cfg_error_t **errorp)
{
char *me = "_nscd_cfg_get";
int dlen;
nscd_rc_t rc = NSCD_SUCCESS;
nscd_cfg_id_t *nswdb;
nscd_cfg_param_desc_t *desc;
void *cfg_data, *ptr = NULL;
nscd_bool_t get_group = nscd_false;
nscd_bool_t out = nscd_false;
nscd_cfg_lock_t *lock = NULL;
if (data_len != NULL)
*data_len = 0;
if (data == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "input data = %p\n", data);
return (NSCD_INVALID_ARGUMENT);
}
*data = NULL;
if (handle == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "handle is NULL\n");
return (NSCD_INVALID_ARGUMENT);
}
nswdb = handle->nswdb;
desc = (nscd_cfg_param_desc_t *)handle->desc;
if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP))
get_group = nscd_true;
/*
* locate the current value of the param or group
* and lock the config data for reading
*/
rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true, desc,
nswdb, get_group, NULL, &dlen, &lock);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to locate config data\n");
return (rc);
} else if (cfg_data == NULL) /* NULL vlen data */
goto done;
ptr = calloc(1, dlen);
if (ptr == NULL) {
rc = NSCD_NO_MEMORY;
goto error_exit;
}
if (get_group == nscd_true) {
rc = _nscd_cfg_copy_group_data_out(desc, ptr, cfg_data);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to copy group data %p: "
"error = %d\n", cfg_data, rc);
goto error_exit;
}
} else {
/*
* nscd_false asks _nscd_cfg_copy_param_data to
* copy the data content rather than just setting
* the addr of the vlen data in 'ptr'
*/
rc = _nscd_cfg_copy_param_data(desc, ptr, cfg_data,
out, nscd_false);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to copy param data %p: "
"error = %d\n", cfg_data, rc);
goto error_exit;
}
}
*data = ptr;
done:
if (data_len != NULL)
*data_len = dlen;
_nscd_cfg_unlock(lock);
return (NSCD_SUCCESS);
error_exit:
_nscd_cfg_unlock(lock);
if (ptr != NULL)
free(ptr);
return (rc);
}
/*
* three type of data:
* 1 - single param
* desc is that of the param
* 2 - single param to be sent in a group
* a single bit is set in the bitmap,
* desc is that of the group
* 3 - group data
* one of more bits are set in the bitmap,
* desc is that of the group
*/
static nscd_rc_t
_nscd_cfg_notify_s(
nscd_cfg_param_desc_t *desc,
nscd_cfg_id_t *nswdb,
void *data,
nscd_cfg_error_t **errorp)
{
int i, num, is_group = 0;
void *cookie = NULL;
void *cdata;
nscd_rc_t rc;
nscd_cfg_flag_t dflag, dflag1;
nscd_cfg_bitmap_t bitmap_s, bitmap_in, *bitmap_addr = NULL;
nscd_cfg_group_info_t *gi;
if (errorp != NULL)
*errorp = NULL;
/*
* Set data flag going with data to be sent to the
* verify/notify routines. To allow the config flag
* be exipandable, set the bits one by one.
*/
dflag = NSCD_CFG_FLAG_ZERO;
dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA);
if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) {
dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP);
is_group = 1;
}
if (nswdb != NULL &&
strcmp(NSCD_CFG_NSW_ALLDB, nswdb->name) == 0)
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_SET_ALL_DB);
/*
* the bitmap in the input data may be replaced before
* sending to the components, so save the bitmap for
* later use
*/
if (is_group == 1) {
gi = _nscd_cfg_get_gi(data);
bitmap_in = gi->bitmap;
bitmap_addr = &(gi->bitmap);
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP))
/* send the entire group just once */
num = 1;
else { /* send individual members one by one */
num = desc->p_fn;
/*
* skip the first desc which is for the group
* and get to the desc for the first member
*/
desc++;
dflag = _nscd_cfg_flag_unset(dflag,
NSCD_CFG_DFLAG_GROUP);
}
} else {
/* not group data, send the member once */
num = 1;
}
dflag1 = dflag;
for (i = 0; i < num; i++, desc++) {
dflag = dflag1;
if (is_group == 0) {
cdata = data;
goto verify_data;
}
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) {
/* set the bitmap to select just this member */
bitmap_s = NSCD_CFG_BITMAP_ZERO;
_nscd_cfg_bitmap_set_nth(bitmap_s, i);
/* replace the bitmap in the input data */
_nscd_cfg_bitmap_set(bitmap_addr, bitmap_s);
/*
* send the whole group but with only one
* member selected
*/
cdata = data;
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_GROUP);
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_BIT_SELECTED);
} else {
/*
* send param data or group data:
* param data - non-xero desc->p_offset
* group data - zero desc->p_offset
*/
cdata = (char *)data + desc->p_offset;
/*
* if variable length data, need to send pointer
* to the data (not the address of the pointer)
*/
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA))
cdata = *(char **)cdata;
}
verify_data:
if (desc->verify != NULL) {
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_VERIFY);
rc = desc->verify(cdata, desc, nswdb,
dflag, errorp, &cookie);
if (rc != NSCD_SUCCESS)
goto error_exit;
}
if (desc->notify != NULL) {
dflag = _nscd_cfg_flag_set(dflag,
NSCD_CFG_DFLAG_NOTIFY);
rc = desc->notify(data, desc, nswdb,
dflag, errorp, cookie);
if (rc != NSCD_SUCCESS)
goto error_exit;
}
}
rc = NSCD_SUCCESS;
error_exit:
/* restore the bitmap in the input data */
if (bitmap_addr != NULL)
_nscd_cfg_bitmap_set(bitmap_addr, bitmap_in);
return (rc);
}
/*
* Convert string 'str' to data based on the data type in 'desc'.
* 'data' points to the buffer in which the converted data
* is placed. '*data_p' points to the buffer, or in the case
* of a string data type, points to the untoched string (i.e.,
* 'str').
*/
nscd_rc_t
_nscd_cfg_str_to_data(
nscd_cfg_param_desc_t *desc,
char *str,
void *data,
void **data_p,
nscd_cfg_error_t **errorp)
{
char *me = "_nscd_cfg_str_to_data";
char *c;
nscd_cfg_bitmap_t bitmap;
char msg[NSCD_CFG_MAX_ERR_MSG_LEN];
nscd_rc_t rc = NSCD_CFG_DATA_CONVERSION_FAILED;
if (desc == NULL || str == NULL || data == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: one of the following is NULL "
"desc = %p, str = %p, data = %p, data_p = %p\n",
desc, str, data, data_p);
return (NSCD_INVALID_ARGUMENT);
}
*data_p = data;
/* if description is that of a group, return error */
if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) {
(void) snprintf(msg, sizeof (msg),
gettext("single data specified for group %s"), desc->id.name);
if (errorp != NULL)
*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: %s)\n", msg);
return (NSCD_INVALID_ARGUMENT);
}
if (desc->type == NSCD_CFG_DATA_STRING) {
if (strcmp(str, NSCD_NULL) == 0)
*(char **)data_p = NULL;
else {
/* remove the " char if quoted string */
if (str[0] == '"') {
c = str + strlen(str) - 1;
if (*c == '"')
*c = '\0';
*(char **)data_p = str + 1;
} else
*(char **)data_p = str;
}
return (NSCD_SUCCESS);
}
if (str == NULL) {
(void) snprintf(msg, sizeof (msg),
gettext("data must be specified for %s"), desc->id.name);
if (errorp != NULL)
*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: %s\n", msg);
return (NSCD_INVALID_ARGUMENT);
}
switch (desc->type) {
case NSCD_CFG_DATA_BOOLEAN:
if (strcasecmp(str, "yes") == 0)
*(nscd_bool_t *)data = nscd_true;
else if (strcasecmp(str, "no") == 0)
*(nscd_bool_t *)data = nscd_false;
else {
(void) snprintf(msg, sizeof (msg),
gettext("data (%s) must be 'yes' or 'no' for %s"),
str, desc->id.name);
if (errorp != NULL)
*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: %s\n", msg);
return (NSCD_INVALID_ARGUMENT);
}
break;
case NSCD_CFG_DATA_INTEGER:
errno = 0;
*(int *)data = (int)strtol(str, (char **)NULL, 10);
if (errno != NULL) {
(void) snprintf(msg, sizeof (msg),
gettext("unable to convert data (%s) for %s"),
str, desc->id.name);
if (errorp != NULL)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: %s\n", msg);
return (rc);
}
break;
case NSCD_CFG_DATA_BITMAP:
errno = 0;
bitmap = (nscd_cfg_bitmap_t)strtol(str, (char **)NULL, 10);
if (errno != NULL) {
(void) snprintf(msg, sizeof (msg),
gettext("unable to convert data (%s) for %s"),
str, desc->id.name);
if (errorp != NULL)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: %s\n", msg);
return (rc);
}
_nscd_cfg_bitmap_set(data, bitmap);
break;
}
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_cfg_set(
nscd_cfg_handle_t *handle,
void *data,
nscd_cfg_error_t **errorp)
{
char *me = "_nscd_cfg_set";
int dlen;
nscd_cfg_id_t *nswdb;
nscd_cfg_param_desc_t *desc, *gdesc;
nscd_cfg_group_info_t *gi;
char *nswdb_name, *param_name;
void *pdata = NULL;
void *cfg_data, *vdata_addr = NULL;
nscd_bool_t get_group = 0;
nscd_bool_t in = nscd_true;
nscd_cfg_lock_t *lock = NULL;
nscd_rc_t rc = NSCD_SUCCESS;
if (handle == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "handle is NULL\n");
return (NSCD_INVALID_ARGUMENT);
}
nswdb = handle->nswdb;
desc = (nscd_cfg_param_desc_t *)handle->desc;
if (nswdb == NULL)
nswdb_name = "global";
else
nswdb_name = nswdb->name;
param_name = desc->id.name;
if (data == NULL && _nscd_cfg_flag_is_not_set(desc->pflag,
NSCD_CFG_PFLAG_VLEN_DATA)) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "data == NULL\n");
return (NSCD_INVALID_ARGUMENT);
}
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_UPDATE_SEND_WHOLE_GROUP) ||
_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP))
get_group = nscd_true;
/*
* locate the current value of the param or group
* and lock the config data for writing
*/
rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_false, desc,
nswdb, get_group, &vdata_addr, &dlen, &lock);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to locate config data (rc = %d)\n", rc);
return (rc);
}
if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP) &&
((nscd_cfg_group_info_t *)cfg_data)->num_param !=
((nscd_cfg_group_info_t *)data)->num_param) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "number of parameters in group <%s : %s> not equal: "
"%d in input data, should be %d\n",
NSCD_STR_OR_GLOBAL(nswdb_name),
NSCD_STR_OR_NULL(param_name),
((nscd_cfg_group_info_t *)data)->num_param,
((nscd_cfg_group_info_t *)cfg_data)->num_param);
rc = NSCD_INVALID_ARGUMENT;
goto error_exit;
}
/*
* if variable length data, we want the address
* of the pointer pointing to the data
*/
if (vdata_addr != NULL)
cfg_data = vdata_addr;
/*
* just copy in the specified data, if no need
* to verify the data or notify the associated
* component
*/
if (get_group == nscd_true) {
gdesc = &_nscd_cfg_param_desc[desc->g_index];
rc = _nscd_cfg_copy_group_data_merge(
gdesc, &pdata, data, cfg_data,
desc->id.index, data);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to copy group data <%s : %s>\n",
NSCD_STR_OR_GLOBAL(nswdb_name),
NSCD_STR_OR_NULL(param_name));
goto error_exit;
}
rc = _nscd_cfg_notify_s(gdesc, nswdb,
pdata, errorp);
} else
rc = _nscd_cfg_notify_s(desc, nswdb, data,
errorp);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "verifying/notifying of new configuration "
"parameter <%s : %s> failed. %s\n",
NSCD_STR_OR_GLOBAL(nswdb_name),
param_name, (*errorp && (*errorp)->msg) ?
(*errorp)->msg : "");
goto error_exit;
}
/*
* Move the new config into the config store
*/
rc = NSCD_CFG_SET_PARAM_FAILED;
if (_nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_GROUP)) {
gi = _nscd_cfg_get_gi(pdata);
rc = _nscd_cfg_copy_group_data_in(gdesc, gi,
cfg_data, pdata);
} else {
/*
* nscd_true asks _nscd_cfg_copy_param_data to
* set addr of the vlen data in 'cfg_data' rather
* than copying the data content
*/
if (pdata != NULL)
_nscd_cfg_free_vlen_data_group(gdesc,
pdata, in);
rc = _nscd_cfg_copy_param_data(desc,
cfg_data, data, in, nscd_true);
}
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "unable to make new param data <%s : %s> current\n",
NSCD_STR_OR_GLOBAL(nswdb_name),
NSCD_STR_OR_NULL(param_name));
}
error_exit:
_nscd_cfg_unlock(lock);
return (rc);
}
nscd_rc_t
_nscd_cfg_set_linked(
nscd_cfg_handle_t *handle,
void *data,
nscd_cfg_error_t **errorp)
{
char *me = "_nscd_cfg_set_linked";
nscd_cfg_id_t *nswdb;
nscd_cfg_handle_t *hl;
nscd_cfg_param_desc_t *desc;
char *nswdb_name, *param_name, *dbl;
nscd_rc_t rc = NSCD_SUCCESS;
nscd_cfg_nsw_spc_default_t *spc;
int i;
char msg[NSCD_CFG_MAX_ERR_MSG_LEN];
if (handle == NULL) {
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "handle is NULL\n");
return (NSCD_INVALID_ARGUMENT);
}
nswdb = handle->nswdb;
desc = (nscd_cfg_param_desc_t *)handle->desc;
/*
* no need to do the special linking thing,
* if a global param, or a group, or not a linked param
*/
if (nswdb == NULL || _nscd_cfg_flag_is_set(desc->pflag,
NSCD_CFG_PFLAG_GROUP) ||
_nscd_cfg_flag_is_not_set(desc->pflag,
NSCD_CFG_PFLAG_LINKED))
return (_nscd_cfg_set(handle, data, errorp));
else
nswdb_name = nswdb->name;
param_name = desc->id.name;
/*
* if a param is linked to another, it can not be
* changed directly
*/
for (i = 0; i < _nscd_cfg_num_link_default; i++) {
if (_nscd_cfg_nsw_link_default[i].data == NULL)
continue;
if (strcmp(_nscd_cfg_nsw_link_default[i].db,
nswdb_name) == 0 &&
_nscd_cfg_nsw_link_default[i].group_off ==
desc->g_offset &&
_nscd_cfg_nsw_link_default[i].param_off ==
desc->p_offset) {
rc = NSCD_CFG_READ_ONLY;
(void) snprintf(msg, sizeof (msg),
gettext("vaule of \'%s\' not changeable, change that of \'%s\' instead"),
nswdb->name, "passwd");
if (errorp != NULL)
*errorp = _nscd_cfg_make_error(rc, msg);
_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
(me, "ERROR: %s\n", msg);
return (rc);
}
}
/*
* if a param is linked from another, it should be verify
* and changed first
*/
for (i = 0; i < _nscd_cfg_num_link_default; i++) {
if (_nscd_cfg_nsw_link_default[i].data == NULL)
continue;
spc = _nscd_cfg_nsw_link_default[i].data;
if (strcmp(spc->db, nswdb_name) == 0 &&
spc->group_off == desc->g_offset &&
spc->param_off == desc->p_offset) {
rc = _nscd_cfg_set(handle, data, errorp);
if (rc != NSCD_SUCCESS)
return (rc);
break;
}
}
/*
* then change all those linked to the one that has been changed
*/
for (i = 0; i < _nscd_cfg_num_link_default; i++) {
if (_nscd_cfg_nsw_link_default[i].data == NULL)
continue;
spc = _nscd_cfg_nsw_link_default[i].data;
if (strcmp(spc->db, nswdb_name) == 0 &&
spc->group_off == desc->g_offset &&
spc->param_off == desc->p_offset &&
_nscd_cfg_nsw_link_default[i].group_off ==
desc->g_offset &&
_nscd_cfg_nsw_link_default[i].param_off ==
desc->p_offset) {
dbl = _nscd_cfg_nsw_link_default[i].db;
rc = _nscd_cfg_get_handle(param_name, dbl,
&hl, errorp);
rc = _nscd_cfg_set(hl, data, errorp);
_nscd_cfg_free_handle(hl);
if (rc != NSCD_SUCCESS)
return (rc);
}
}
return (_nscd_cfg_set(handle, data, errorp));
}
/*
* Return a list of space-separated database names that
* have at least one of the input sources appeared in the
* configured nsswitch policy string of the databases.
* The return string should be freed by the caller.
*
* For compat sources (compat_group and compat_passwd),
* "group" will be returned, if the policy string for
* compat_group contains one of the input sources. Same
* for compat_passwd and passwd.
*/
char *
_nscd_srcs_in_db_nsw_policy(
int num_src,
char **srcs)
{
uint8_t i, j, n = 0, nc = 0;
uint8_t compat_grp = 0, compat_pwd = 0;
uint8_t *db;
uint8_t *db_compat;
int dlen = 0;
nscd_cfg_nsw_db_data_t *dbcfg;
nscd_cfg_switch_t *sw;
char *outstr = NULL;
char *dbname;
db = (uint8_t *)calloc(_nscd_cfg_num_nsw_db, sizeof (uint8_t));
if (db == NULL)
return (NULL);
db_compat = (uint8_t *)calloc(_nscd_cfg_num_nsw_db,
sizeof (uint8_t));
if (db_compat == NULL) {
free(db);
return (NULL);
}
for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
(void) rw_rdlock(&nscd_cfg_nsw_db_data_rwlock[i]);
dbcfg = &nscd_cfg_nsw_db_data_current[i];
sw = &dbcfg->sw;
if (sw->nsw_config_string == NULL)
continue;
dbname = _nscd_cfg_nsw_db[i].name;
for (j = 0; j < num_src; j++) {
if (strstr(sw->nsw_config_string, srcs[j]) !=
NULL) {
db[n++] = i;
dlen += strlen(dbname) + 1;
} else if (strcmp(sw->nsw_config_string,
"compat") == 0) {
if (strcmp(dbname, "passwd") == 0) {
compat_pwd = 1;
dlen += 7;
} else if (strcmp(dbname, "group") == 0) {
compat_grp = 1;
dlen += 6;
} else {
db_compat[nc++] = i;
dlen += strlen(dbname) + 1;
}
}
}
(void) rw_unlock(&nscd_cfg_nsw_db_data_rwlock[i]);
}
if (dlen != NULL)
outstr = (char *)calloc(1, dlen);
if (outstr == NULL) {
free(db_compat);
free(db);
return (NULL);
}
for (j = 0; j < n; j++) {
dbname = _nscd_cfg_nsw_db[db[j]].name;
if (strstr(dbname, "group_compat") != NULL) {
if (compat_grp == 1)
dbname = "group";
else
continue;
} else if (strstr(dbname, "passwd_compat") != NULL) {
if (compat_pwd == 1)
dbname = "passwd";
else
continue;
}
(void) strlcat(outstr, dbname, dlen);
(void) strlcat(outstr, ",", dlen);
}
for (j = 0; j < nc; j++) {
dbname = _nscd_cfg_nsw_db[db_compat[j]].name;
if (compat_pwd == 1) {
(void) strlcat(outstr, dbname, dlen);
(void) strlcat(outstr, " ", dlen);
}
}
free(db);
free(db_compat);
return (outstr);
}