#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
struct idmap_function_entry {
const char *name;
struct idmap_methods *methods;
struct idmap_function_entry *prev,*next;
};
static struct idmap_function_entry *backends = NULL;
static struct idmap_methods *cache_map;
static struct idmap_methods *remote_map;
static BOOL proxyonly = False;
static struct idmap_methods *get_methods(const char *name, BOOL cache_method)
{
struct idmap_function_entry *entry = backends;
for(entry = backends; entry; entry = entry->next) {
if (!cache_method && strequal(entry->name, "tdb"))
continue;
if (strequal(entry->name, name))
return entry->methods;
}
return NULL;
}
NTSTATUS smb_register_idmap(int version, const char *name, struct idmap_methods *methods)
{
struct idmap_function_entry *entry;
if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
DEBUG(0, ("smb_register_idmap: Failed to register idmap module.\n"
"The module was compiled against SMB_IDMAP_INTERFACE_VERSION %d,\n"
"current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
"Please recompile against the current version of samba!\n",
version, SMB_IDMAP_INTERFACE_VERSION));
return NT_STATUS_OBJECT_TYPE_MISMATCH;
}
if (!name || !name[0] || !methods) {
DEBUG(0,("smb_register_idmap: called with NULL pointer or empty name!\n"));
return NT_STATUS_INVALID_PARAMETER;
}
if (get_methods(name, False)) {
DEBUG(0,("smb_register_idmap: idmap module %s already registered!\n", name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
entry = SMB_XMALLOC_P(struct idmap_function_entry);
entry->name = smb_xstrdup(name);
entry->methods = methods;
DLIST_ADD(backends, entry);
DEBUG(5, ("smb_register_idmap: Successfully added idmap backend '%s'\n", name));
return NT_STATUS_OK;
}
BOOL idmap_init(const char **remote_backend)
{
if (!backends)
static_init_idmap;
if (!cache_map) {
cache_map = get_methods("tdb", True);
if (!cache_map) {
DEBUG(0, ("idmap_init: could not find tdb cache backend!\n"));
return False;
}
if (!NT_STATUS_IS_OK(cache_map->init( NULL ))) {
DEBUG(0, ("idmap_init: could not initialise tdb cache backend!\n"));
return False;
}
}
if ((remote_map == NULL) && (remote_backend != NULL) &&
(*remote_backend != NULL) && (**remote_backend != '\0')) {
char *rem_backend = smb_xstrdup(*remote_backend);
fstring params = "";
char *pparams;
if ( (pparams = strchr( rem_backend, ':' )) != NULL ) {
*pparams = '\0';
pparams++;
fstrcpy( params, pparams );
}
DEBUG(3, ("idmap_init: using '%s' as remote backend\n", rem_backend));
if((remote_map = get_methods(rem_backend, False)) ||
(NT_STATUS_IS_OK(smb_probe_module("idmap", rem_backend)) &&
(remote_map = get_methods(rem_backend, False)))) {
if (!NT_STATUS_IS_OK(remote_map->init(params))) {
DEBUG(0, ("idmap_init: failed to initialize remote backend!\n"));
return False;
}
} else {
DEBUG(0, ("idmap_init: could not load remote backend '%s'\n", rem_backend));
SAFE_FREE(rem_backend);
return False;
}
SAFE_FREE(rem_backend);
}
return True;
}
void idmap_proxyonly(void)
{
proxyonly = True;
}
NTSTATUS idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
{
struct idmap_methods *map = remote_map;
DOM_SID tmp_sid;
if (proxyonly)
return NT_STATUS_UNSUCCESSFUL;
DEBUG(10, ("idmap_set_mapping: Set %s to %s %lu\n",
sid_string_static(sid),
((id_type & ID_TYPEMASK) == ID_USERID) ? "UID" : "GID",
((id_type & ID_TYPEMASK) == ID_USERID) ? (unsigned long)id.uid :
(unsigned long)id.gid));
if ( (NT_STATUS_IS_OK(cache_map->
get_sid_from_id(&tmp_sid, id,
id_type | ID_QUERY_ONLY))) &&
sid_equal(sid, &tmp_sid) ) {
DEBUG(10, ("idmap_set_mapping: Mapping already there\n"));
return NT_STATUS_OK;
}
if (map == NULL) {
map = cache_map;
}
return map->set_mapping(sid, id, id_type);
}
NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
{
NTSTATUS ret;
int loc_type;
unid_t loc_id;
if (proxyonly)
return NT_STATUS_UNSUCCESSFUL;
loc_type = *id_type;
if (remote_map) {
loc_type |= ID_QUERY_ONLY;
}
ret = cache_map->get_id_from_sid(id, &loc_type, sid);
if (NT_STATUS_IS_OK(ret)) {
*id_type = loc_type & ID_TYPEMASK;
return NT_STATUS_OK;
}
if (remote_map == NULL) {
return ret;
}
loc_type = *id_type & ID_TYPEMASK;
switch (loc_type) {
case ID_USERID:
loc_type = ID_GROUPID;
break;
case ID_GROUPID:
loc_type = ID_USERID;
break;
default:
loc_type = ID_EMPTY;
}
loc_type |= ID_QUERY_ONLY;
ret = cache_map->get_id_from_sid(&loc_id, &loc_type, sid);
if (NT_STATUS_IS_OK(ret)) {
return NT_STATUS_UNSUCCESSFUL;
}
ret = remote_map->get_id_from_sid(id, id_type, sid);
if (NT_STATUS_IS_OK(ret)) {
ret = cache_map->set_mapping(sid, *id, *id_type);
}
return ret;
}
NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
{
NTSTATUS ret;
int loc_type;
if (proxyonly)
return NT_STATUS_UNSUCCESSFUL;
loc_type = id_type;
if (remote_map) {
loc_type = id_type | ID_QUERY_ONLY;
}
ret = cache_map->get_sid_from_id(sid, id, loc_type);
if (NT_STATUS_IS_OK(ret))
return ret;
if (remote_map == NULL)
return ret;
ret = remote_map->get_sid_from_id(sid, id, id_type);
if (NT_STATUS_IS_OK(ret)) {
ret = cache_map->set_mapping(sid, id, id_type);
}
return ret;
}
NTSTATUS idmap_allocate_id(unid_t *id, int id_type)
{
if (proxyonly)
return NT_STATUS_UNSUCCESSFUL;
if ( remote_map )
return remote_map->allocate_id( id, id_type );
return cache_map->allocate_id( id, id_type );
}
NTSTATUS idmap_allocate_rid(uint32 *rid, int type)
{
if (proxyonly)
return NT_STATUS_UNSUCCESSFUL;
if ( remote_map )
return remote_map->allocate_rid( rid, type );
return cache_map->allocate_rid( rid, type );
}
NTSTATUS idmap_close(void)
{
NTSTATUS ret;
if (proxyonly)
return NT_STATUS_OK;
ret = cache_map->close();
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(3, ("idmap_close: failed to close local tdb cache!\n"));
}
cache_map = NULL;
if (remote_map) {
ret = remote_map->close();
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(3, ("idmap_close: failed to close remote idmap repository!\n"));
}
remote_map = NULL;
}
return ret;
}
void idmap_status(void)
{
cache_map->status();
if (remote_map)
remote_map->status();
}