summaryrefslogtreecommitdiff
path: root/source3/sam
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2003-07-16 05:34:56 +0000
committerGerald Carter <jerry@samba.org>2003-07-16 05:34:56 +0000
commit4a090ba06a54f5da179ac02bb307cc03d08831bf (patch)
treeed652ef36be7f16682c358816334f969a22f1c27 /source3/sam
parent95fe82670032a3a43571b46d7bbf2c26bc8cdcd9 (diff)
downloadsamba-4a090ba06a54f5da179ac02bb307cc03d08831bf.tar.gz
samba-4a090ba06a54f5da179ac02bb307cc03d08831bf.tar.bz2
samba-4a090ba06a54f5da179ac02bb307cc03d08831bf.zip
trying to get HEAD building again. If you want the code
prior to this merge, checkout HEAD_PRE_3_0_0_BETA_3_MERGE (This used to be commit adb98e7b7cd0f025b52c570e4034eebf4047b1ad)
Diffstat (limited to 'source3/sam')
-rw-r--r--source3/sam/idmap.c308
-rw-r--r--source3/sam/idmap_ldap.c1363
-rw-r--r--source3/sam/idmap_tdb.c398
-rw-r--r--source3/sam/idmap_util.c333
4 files changed, 1410 insertions, 992 deletions
diff --git a/source3/sam/idmap.c b/source3/sam/idmap.c
index 9695e7b764..7a8f270e15 100644
--- a/source3/sam/idmap.c
+++ b/source3/sam/idmap.c
@@ -4,6 +4,7 @@
Copyright (C) Tim Potter 2000
Copyright (C) Anthony Liguori <aliguor@us.ibm.com> 2003
Copyright (C) Simo Sorce 2003
+ Copyright (C) Jeremy Allison 2003.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,189 +25,292 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
-static struct {
-
+struct idmap_function_entry {
const char *name;
- /* Function to create a member of the idmap_methods list */
- NTSTATUS (*reg_meth)(struct idmap_methods **methods);
struct idmap_methods *methods;
-
-} remote_idmap_functions[] = {
- { NULL, NULL, NULL }
+ struct idmap_function_entry *prev,*next;
};
-static struct idmap_methods *local_map;
-static struct idmap_methods *remote_map;
-
-static void lazy_initialize_idmap(void)
-{
- static BOOL initialized = False;
- if (initialized) return;
- idmap_init();
- initialized = True;
-}
+static struct idmap_function_entry *backends = NULL;
+static struct idmap_methods *cache_map;
+static struct idmap_methods *remote_map;
+/**********************************************************************
+ Get idmap methods. Don't allow tdb to be a remote method.
+**********************************************************************/
-static struct idmap_methods *get_methods(const char *name)
+static struct idmap_methods *get_methods(const char *name, BOOL cache_method)
{
- int i = 0;
- struct idmap_methods *ret = NULL;
+ struct idmap_function_entry *entry = backends;
- while (remote_idmap_functions[i].name && strcmp(remote_idmap_functions[i].name, name)) {
- i++;
+ for(entry = backends; entry; entry = entry->next) {
+ if (!cache_method && strequal(entry->name, "tdb"))
+ continue; /* tdb is only cache method. */
+ if (strequal(entry->name, name))
+ return entry->methods;
}
- if (remote_idmap_functions[i].name) {
+ return NULL;
+}
- if (!remote_idmap_functions[i].methods) {
- remote_idmap_functions[i].reg_meth(&remote_idmap_functions[i].methods);
- }
+/**********************************************************************
+ Allow a module to register itself as a method.
+**********************************************************************/
- ret = remote_idmap_functions[i].methods;
+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;
}
- return ret;
+ 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(sizeof(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;
}
-/* Initialize backend */
-BOOL idmap_init(void)
+/**********************************************************************
+ Initialise idmap cache and a remote backend (if configured).
+**********************************************************************/
+
+BOOL idmap_init(const char *remote_backend)
{
- const char *remote_backend = lp_idmap_backend();
+ if (!backends)
+ static_init_idmap;
+
+ if (!cache_map) {
+ cache_map = get_methods("tdb", True);
- if (!local_map) {
- idmap_reg_tdb(&local_map);
- if (NT_STATUS_IS_ERR(local_map->init())) {
- DEBUG(0, ("idmap_init: could not load or create local backend!\n"));
+ 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 && remote_backend && *remote_backend != 0) {
- DEBUG(3, ("idmap_init: using '%s' as remote backend\n", remote_backend));
+ char *rem_backend = smb_xstrdup(remote_backend);
+ fstring params = "";
+ char *pparams;
+
+ /* get any mode parameters passed in */
+
+ if ( (pparams = strchr( rem_backend, ':' )) != NULL ) {
+ *pparams = '\0';
+ pparams++;
+ fstrcpy( params, pparams );
+ }
+
+ DEBUG(3, ("idmap_init: using '%s' as remote backend\n", rem_backend));
- remote_map = get_methods(remote_backend);
- if (!remote_map) {
- DEBUG(0, ("idmap_init: could not load remote backend '%s'\n", remote_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)))) {
+ remote_map->init(params);
+ } else {
+ DEBUG(0, ("idmap_init: could not load remote backend '%s'\n", rem_backend));
+ SAFE_FREE(rem_backend);
return False;
}
- remote_map->init();
+ SAFE_FREE(rem_backend);
}
return True;
}
+/**************************************************************************
+ This is a rare operation, designed to allow an explicit mapping to be
+ set up for a sid to a POSIX id.
+**************************************************************************/
+
NTSTATUS idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
{
- NTSTATUS ret;
-
- lazy_initialize_idmap();
-
- ret = local_map->set_mapping(sid, id, id_type);
- if (NT_STATUS_IS_ERR(ret)) {
- DEBUG (0, ("idmap_set_mapping: Error, unable to modify local cache!\n"));
- DEBUGADD(0, ("Error: %s", nt_errstr(ret)));
- return ret;
+ struct idmap_methods *map = remote_map;
+ DOM_SID tmp_sid;
+
+ DEBUG(10, ("idmap_set_mapping: Set %s to %s %d\n",
+ sid_string_static(sid),
+ ((id_type & ID_TYPEMASK) == ID_USERID) ? "UID" : "GID",
+ ((id_type & ID_TYPEMASK) == ID_USERID) ? id.uid : 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) ) {
+ /* Nothing to do, we already have that mapping */
+ DEBUG(10, ("idmap_set_mapping: Mapping already there\n"));
+ return NT_STATUS_OK;
}
- /* Being able to update the remote cache is seldomly right.
- Generally this is a forbidden operation. */
- if (!(id_type & ID_CACHE) && (remote_map != NULL)) {
- remote_map->set_mapping(sid, id, id_type);
- if (NT_STATUS_IS_ERR(ret)) {
- DEBUG (0, ("idmap_set_mapping: Error, unable to modify remote cache!\n"));
- DEBUGADD(0, ("Error: %s", nt_errstr(ret)));
- }
+ if (map == NULL) {
+ /* Ok, we don't have a authoritative remote
+ mapping. So update our local cache only. */
+ map = cache_map;
}
- return ret;
+ return map->set_mapping(sid, id, id_type);
}
-/* Get ID from SID */
+/**************************************************************************
+ Get ID from SID. This can create a mapping for a SID to a POSIX id.
+**************************************************************************/
+
NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
{
NTSTATUS ret;
int loc_type;
- lazy_initialize_idmap();
-
loc_type = *id_type;
- if (remote_map) { /* We have a central remote idmap */
- loc_type |= ID_NOMAP;
+
+ if (remote_map) {
+ /* We have a central remote idmap so only look in
+ cache, don't allocate */
+ loc_type |= ID_QUERY_ONLY;
}
- ret = local_map->get_id_from_sid(id, &loc_type, sid);
- if (NT_STATUS_IS_ERR(ret)) {
- if (remote_map) {
- ret = remote_map->get_id_from_sid(id, id_type, sid);
- if (NT_STATUS_IS_ERR(ret)) {
- DEBUG(3, ("idmap_get_id_from_sid: error fetching id!\n"));
- return ret;
- } else {
- loc_type |= ID_CACHE;
- idmap_set_mapping(sid, *id, loc_type);
- }
- }
- } else {
+
+ 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;
+ }
+
+ /* Ok, the mapping was not in the cache, give the remote map a
+ second try. */
+
+ ret = remote_map->get_id_from_sid(id, id_type, sid);
+
+ if (NT_STATUS_IS_OK(ret)) {
+ /* The remote backend gave us a valid mapping, cache it. */
+ ret = cache_map->set_mapping(sid, *id, *id_type);
}
return ret;
}
-/* Get SID from ID */
+/**************************************************************************
+ Get SID from ID. This must have been created before.
+**************************************************************************/
+
NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
{
NTSTATUS ret;
int loc_type;
- lazy_initialize_idmap();
-
loc_type = id_type;
if (remote_map) {
- loc_type = id_type | ID_NOMAP;
+ loc_type = id_type | ID_QUERY_ONLY;
}
- ret = local_map->get_sid_from_id(sid, id, loc_type);
- if (NT_STATUS_IS_ERR(ret)) {
- if (remote_map) {
- ret = remote_map->get_sid_from_id(sid, id, id_type);
- if (NT_STATUS_IS_ERR(ret)) {
- DEBUG(3, ("idmap_get_sid_from_id: unable to fetch sid!\n"));
- return ret;
- } else {
- loc_type |= ID_CACHE;
- idmap_set_mapping(sid, id, loc_type);
- }
- }
+
+ 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;
+
+ /* We have a second chance, ask our authoritative backend */
+
+ ret = remote_map->get_sid_from_id(sid, id, id_type);
+
+ if (NT_STATUS_IS_OK(ret)) {
+ /* The remote backend gave us a valid mapping, cache it. */
+ ret = cache_map->set_mapping(sid, id, id_type);
}
return ret;
}
-/* Close backend */
+/**************************************************************************
+ Alloocate a new UNIX uid/gid
+**************************************************************************/
+
+NTSTATUS idmap_allocate_id(unid_t *id, int id_type)
+{
+ /* we have to allocate from the authoritative backend */
+
+ if ( remote_map )
+ return remote_map->allocate_id( id, id_type );
+
+ return cache_map->allocate_id( id, id_type );
+}
+
+/**************************************************************************
+ Alloocate a new RID
+**************************************************************************/
+
+NTSTATUS idmap_allocate_rid(uint32 *rid, int type)
+{
+ /* we have to allocate from the authoritative backend */
+
+ if ( remote_map )
+ return remote_map->allocate_rid( rid, type );
+
+ return cache_map->allocate_rid( rid, type );
+}
+
+/**************************************************************************
+ Shutdown maps.
+**************************************************************************/
+
NTSTATUS idmap_close(void)
{
NTSTATUS ret;
- ret = local_map->close();
- if (NT_STATUS_IS_ERR(ret)) {
- DEBUG(3, ("idmap_close: failed to close local cache!\n"));
+ 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_ERR(ret)) {
+ if (!NT_STATUS_IS_OK(ret)) {
DEBUG(3, ("idmap_close: failed to close remote idmap repository!\n"));
}
+ remote_map = NULL;
}
return ret;
}
-/* Dump backend status */
+/**************************************************************************
+ Dump backend status.
+**************************************************************************/
+
void idmap_status(void)
{
- lazy_initialize_idmap();
-
- local_map->status();
- if (remote_map) remote_map->status();
+ cache_map->status();
+ if (remote_map)
+ remote_map->status();
}
diff --git a/source3/sam/idmap_ldap.c b/source3/sam/idmap_ldap.c
index 33cf5fb030..9a1ee039d0 100644
--- a/source3/sam/idmap_ldap.c
+++ b/source3/sam/idmap_ldap.c
@@ -3,9 +3,10 @@
idmap LDAP backend
- Copyright (C) Tim Potter 2000
- Copyright (C) Anthony Liguori 2003
- Copyright (C) Simo Sorce 2003
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Anthony Liguori 2003
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Gerald Carter 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,781 +32,912 @@
#include <lber.h>
#include <ldap.h>
+#include "smbldap.h"
+
+#define IDMAP_GROUP_SUFFIX "ou=idmap group"
+#define IDMAP_USER_SUFFIX "ou=idmap people"
+
+
struct ldap_idmap_state {
- LDAP *ldap_struct;
- time_t last_ping;
- const char *uri;
- char *bind_dn;
- char *bind_secret;
- unsigned int num_failures;
- struct ldap_idmap_state *prev, *next;
+ struct smbldap_state *smbldap_state;
+ TALLOC_CTX *mem_ctx;
+
+ uint32 low_allocated_user_rid;
+ uint32 high_allocated_user_rid;
+ uint32 low_allocated_group_rid;
+ uint32 high_allocated_group_rid;
+
};
-#define LDAP_IDMAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
#define LDAP_MAX_ALLOC_ID 128 /* number tries while allocating
new id */
static struct ldap_idmap_state ldap_state;
-static int ldap_idmap_connect_system(struct ldap_idmap_state *state);
static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type);
+static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, int id_type,
+ const char *ldap_dn, LDAPMessage *entry);
static NTSTATUS ldap_idmap_close(void);
-/*******************************************************************
- find the ldap password
-******************************************************************/
-static BOOL fetch_ldapsam_pw(char **dn, char** pw)
-{
- char *key = NULL;
- size_t size;
-
- *dn = smb_xstrdup(lp_ldap_admin_dn());
-
- if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
- SAFE_FREE(*dn);
- DEBUG(0, ("fetch_ldapsam_pw: asprintf failed!\n"));
- }
-
- *pw=secrets_fetch(key, &size);
- SAFE_FREE(key);
-
- if (!size) {
- /* Upgrade 2.2 style entry */
- char *p;
- char* old_style_key = strdup(*dn);
- char *data;
- fstring old_style_pw;
-
- if (!old_style_key) {
- DEBUG(0, ("fetch_ldapsam_pw: strdup failed!\n"));
- return False;
- }
-
- for (p=old_style_key; *p; p++)
- if (*p == ',') *p = '/';
-
- data=secrets_fetch(old_style_key, &size);
- if (!size && size < sizeof(old_style_pw)) {
- DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
- SAFE_FREE(old_style_key);
- SAFE_FREE(*dn);
- return False;
- }
+/**********************************************************************
+ Even if the sambaDomain attribute in LDAP tells us that this RID is
+ safe to use, always check before use.
+*********************************************************************/
- strncpy(old_style_pw, data, size);
- old_style_pw[size] = 0;
+static BOOL sid_in_use(struct ldap_idmap_state *state,
+ const DOM_SID *sid, int *error)
+{
+ fstring filter;
+ fstring sid_string;
+ LDAPMessage *result = NULL;
+ int count;
+ int rc;
+ char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
- SAFE_FREE(data);
+ slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
- if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
- DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
- SAFE_FREE(old_style_key);
- SAFE_FREE(*dn);
- return False;
- }
- if (!secrets_delete(old_style_key)) {
- DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
- }
+ rc = smbldap_search_suffix(state->smbldap_state,
+ filter, sid_attr, &result);
- SAFE_FREE(old_style_key);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n",
+ sid_string, ld_error));
+ SAFE_FREE(ld_error);
- *pw = smb_xstrdup(old_style_pw);
+ *error = rc;
+ return True;
}
- return True;
+ if ((count = ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) {
+ DEBUG(3, ("Sid %s already in use - trying next RID\n",
+ sid_string));
+ ldap_msgfree(result);
+ return True;
+ }
+
+ ldap_msgfree(result);
+
+ /* good, sid is not in use */
+ return False;
}
-/*******************************************************************
- open a connection to the ldap server.
-******************************************************************/
-static int ldap_idmap_open_connection(struct ldap_idmap_state *state)
+/**********************************************************************
+ Set the new nextRid attribute, and return one we can use.
+
+ This also checks that this RID is actually free - in case the admin
+ manually stole it :-).
+*********************************************************************/
+static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid,
+ int rid_type)
{
- int rc = LDAP_SUCCESS;
- int version;
- BOOL ldap_v3 = False;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ int rc;
+ LDAPMessage *domain_result = NULL;
+ LDAPMessage *entry = NULL;
+ char *dn;
+ LDAPMod **mods = NULL;
+ fstring old_rid_string;
+ fstring next_rid_string;
+ fstring algorithmic_rid_base_string;
+ uint32 next_rid;
+ uint32 alg_rid_base;
+ int attempts = 0;
+ char *ld_error = NULL;
-#ifdef HAVE_LDAP_INITIALIZE
- DEBUG(10, ("ldap_idmap_open_connection: %s\n", state->uri));
-
- if ((rc = ldap_initialize(&state->ldap_struct, state->uri))
- != LDAP_SUCCESS) {
- DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
- return rc;
- }
-#else
- /* Parse the string manually */
+ while (attempts < 10)
{
- int port = 0;
- fstring protocol;
- fstring host;
- const char *p = state->uri;
- SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
-
- /* skip leading "URL:" (if any) */
- if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
- p += 4;
+ if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state,
+ &domain_result, get_global_sam_name(), True)))
+ {
+ return ret;
}
-
- sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
-
- if (port == 0) {
- if (strequal(protocol, "ldap")) {
- port = LDAP_PORT;
- } else if (strequal(protocol, "ldaps")) {
- port = LDAPS_PORT;
- } else {
- DEBUG(0, ("unrecognised protocol (%s)!\n",
- protocol));
- }
+
+ entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
+ if (!entry) {
+ DEBUG(0, ("Could not get domain info entry\n"));
+ ldap_msgfree(domain_result);
+ return ret;
}
-
- if ((state->ldap_struct = ldap_init(host, port)) == NULL) {
- DEBUG(0, ("ldap_init failed !\n"));
- return LDAP_OPERATIONS_ERROR;
+
+ if ((dn = ldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
+ DEBUG(0, ("Could not get domain info DN\n"));
+ ldap_msgfree(domain_result);
+ return ret;
}
+
+ /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and
+ algorithmic_rid_base. The other two are to avoid stomping on the
+ different sets of algorithmic RIDs */
- if (strequal(protocol, "ldaps")) {
-#ifdef LDAP_OPT_X_TLS
- int tls = LDAP_OPT_X_TLS_HARD;
- if (ldap_set_option (state->ldap_struct,
- LDAP_OPT_X_TLS, &tls) !=
- LDAP_SUCCESS)
- {
- DEBUG(0, ("Failed to setup a TLS session\n"));
- }
+ if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
+ algorithmic_rid_base_string))
+ {
- DEBUG(3,("LDAPS option set...!\n"));
-#else
- DEBUG(0,("ldap_idmap_open_connection: Secure "
- "connection not supported by LDAP client "
- "libraries!\n"));
- return LDAP_OPERATIONS_ERROR;
-#endif
- }
- }
-#endif
-
- if (ldap_get_option(state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
- &version) == LDAP_OPT_SUCCESS) {
- if (version != LDAP_VERSION3) {
- version = LDAP_VERSION3;
- if (ldap_set_option(state->ldap_struct,
- LDAP_OPT_PROTOCOL_VERSION,
- &version) == LDAP_OPT_SUCCESS) {
- ldap_v3 = True;
- }
+ alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
} else {
- ldap_v3 = True;
+ alg_rid_base = algorithmic_rid_base();
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
+ algorithmic_rid_base_string);
}
- }
- if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
-#ifdef LDAP_OPT_X_TLS
- if (ldap_v3) {
- if ((rc = ldap_start_tls_s(state->ldap_struct, NULL,
- NULL)) != LDAP_SUCCESS) {
- DEBUG(0,("Failed to issue the StartTLS "
- "instruction: %s\n",
- ldap_err2string(rc)));
- return rc;
+ next_rid = 0;
+
+ if (alg_rid_base > BASE_RID) {
+ /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we
+ can allocate to new users */
+ if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
+ old_rid_string))
+ {
+ *rid = (uint32)atol(old_rid_string);
+ } else {
+ *rid = BASE_RID;
+ }
+
+ next_rid = *rid+1;
+ if (next_rid >= alg_rid_base) {
+ return NT_STATUS_UNSUCCESSFUL;
}
- DEBUG (3, ("StartTLS issued: using a TLS "
- "connection\n"));
- } else {
- DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
- return LDAP_OPERATIONS_ERROR;
+ slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
+
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
+ next_rid_string);
}
-#else
- DEBUG(0,("ldap_idmap_open_connection: StartTLS not supported by "
- "LDAP client libraries!\n"));
- return LDAP_OPERATIONS_ERROR;
-#endif
- }
-
- DEBUG(2, ("ldap_idmap_open_connection: connection opened\n"));
- return rc;
-}
-/**********************************************************************
-Connect to LDAP server
-*********************************************************************/
-static int ldap_idmap_open(struct ldap_idmap_state *state)
-{
- int rc;
- SMB_ASSERT(state);
-
-#ifndef NO_LDAP_SECURITY
- if (geteuid() != 0) {
- DEBUG(0,
- ("ldap_idmap_open: cannot access LDAP when not root\n"));
- return LDAP_INSUFFICIENT_ACCESS;
- }
-#endif
-
- if ((state->ldap_struct != NULL) &&
- ((state->last_ping + LDAP_IDMAP_DONT_PING_TIME)<time(NULL))) {
- struct sockaddr_un addr;
- socklen_t len = sizeof(addr);
- int sd;
-
- if (!ldap_get_option(state->ldap_struct, LDAP_OPT_DESC, &sd)&&
- getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
- /* the other end has died. reopen. */
- ldap_unbind_ext(state->ldap_struct, NULL, NULL);
- state->ldap_struct = NULL;
- state->last_ping = (time_t)0;
- } else {
- state->last_ping = time(NULL);
- }
- }
-
- if (state->ldap_struct != NULL) {
- DEBUG(5,("ldap_idmap_open: already connected to the LDAP "
- "server\n"));
- return LDAP_SUCCESS;
- }
-
- if ((rc = ldap_idmap_open_connection(state))) {
- return rc;
- }
-
- if ((rc = ldap_idmap_connect_system(state))) {
- ldap_unbind_ext(state->ldap_struct, NULL, NULL);
- state->ldap_struct = NULL;
- return rc;
- }
-
-
- state->last_ping = time(NULL);
- DEBUG(4,("The LDAP server is succesful connected\n"));
-
- return LDAP_SUCCESS;
-}
+ if (!next_rid) { /* not got one already */
+ switch (rid_type) {
+ case USER_RID_TYPE:
+ if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
+ old_rid_string))
+ {
+
+ *rid = (uint32)atol(old_rid_string);
+
+ } else {
+ *rid = state->low_allocated_user_rid;
+ }
+ break;
+ case GROUP_RID_TYPE:
+ if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
+ old_rid_string))
+ {
+ *rid = (uint32)atol(old_rid_string);
+ } else {
+ *rid = state->low_allocated_group_rid;
+ }
+ break;
+ }
+
+ /* This is the core of the whole routine. If we had
+ scheme-style closures, there would be a *lot* less code
+ duplication... */
-static int ldap_idmap_retry_open(struct ldap_idmap_state *state, int *attempts)
-{
- int rc;
+ next_rid = *rid+RID_MULTIPLIER;
+ slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
+
+ switch (rid_type) {
+ case USER_RID_TYPE:
+ if (next_rid > state->high_allocated_user_rid) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
+ next_rid_string);
+ break;
+
+ case GROUP_RID_TYPE:
+ if (next_rid > state->high_allocated_group_rid) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
+ next_rid_string);
+ break;
+ }
+ }
- SMB_ASSERT(state && attempts);
+ if ((rc = ldap_modify_s(state->smbldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
+ DOM_SID dom_sid;
+ DOM_SID sid;
+ pstring domain_sid_string;
+ int error = 0;
- if (*attempts != 0) {
- unsigned int sleep_time;
- uint8 rand_byte = 128; /* a reasonable place to start */
+ if (!smbldap_get_single_attribute(state->smbldap_state->ldap_struct, domain_result,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
+ domain_sid_string))
+ {
+ ldap_mods_free(mods, True);
+ ldap_memfree(dn);
+ ldap_msgfree(domain_result);
+ return ret;
+ }
- generate_random_buffer(&rand_byte, 1, False);
+ if (!string_to_sid(&dom_sid, domain_sid_string)) {
+ ldap_mods_free(mods, True);
+ ldap_memfree(dn);
+ ldap_msgfree(domain_result);
+ return ret;
+ }
- sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2;
- /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
- on average.
- */
- DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n",
- sleep_time));
- msleep(sleep_time);
- }
- (*attempts)++;
+ ldap_mods_free(mods, True);
+ mods = NULL;
+ ldap_memfree(dn);
+ ldap_msgfree(domain_result);
- if ((rc = ldap_idmap_open(state))) {
- DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",
- *attempts));
- return rc;
- }
-
- return LDAP_SUCCESS;
-}
+ sid_copy(&sid, &dom_sid);
+ sid_append_rid(&sid, *rid);
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
- int *methodp, int freeit, void *arg)
-{
- struct ldap_idmap_state *state = arg;
-
- /** @TODO Should we be doing something to check what servers we rebind
- to? Could we get a referral to a machine that we don't want to
- give our username and password to? */
-
- if (freeit) {
- SAFE_FREE(*whop);
- memset(*credp, '\0', strlen(*credp));
- SAFE_FREE(*credp);
- } else {
- DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
- state->bind_dn));
+ /* check RID is not in use */
+ if (sid_in_use(state, &sid, &error)) {
+ if (error) {
+ return ret;
+ }
+ continue;
+ }
- *whop = strdup(state->bind_dn);
- if (!*whop) {
- return LDAP_NO_MEMORY;
+ return NT_STATUS_OK;
}
- *credp = strdup(state->bind_secret);
- if (!*credp) {
- SAFE_FREE(*whop);
- return LDAP_NO_MEMORY;
- }
- *methodp = LDAP_AUTH_SIMPLE;
- }
- return 0;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
- and actually does the connection.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-static int rebindproc_connect_with_state (LDAP *ldap_struct,
- LDAP_CONST char *url,
- ber_tag_t request,
- ber_int_t msgid, void *arg)
-{
- struct ldap_idmap_state *state = arg;
- int rc;
- DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n",
- state->bind_dn));
-
- /** @TODO Should we be doing something to check what servers we rebind
- to? Could we get a referral to a machine that we don't want to
- give our username and password to? */
- rc = ldap_simple_bind_s(ldap_struct, state->bind_dn,
- state->bind_secret);
-
- return rc;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- Add a rebind function for authenticated referrals
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
- int *method, int freeit )
-{
- return rebindproc_with_state(ldap_struct, whop, credp,
- method, freeit, &ldap_state);
-
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- this also does the connection, but no void*.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
- ber_int_t msgid)
-{
- return rebindproc_connect_with_state(ld, url, (ber_tag_t)request,
- msgid, &ldap_state);
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- connect to the ldap server under system privilege.
-******************************************************************/
-static int ldap_idmap_connect_system(struct ldap_idmap_state *state)
-{
- int rc;
- char *ldap_dn;
- char *ldap_secret;
+ ld_error = NULL;
+ ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
+ SAFE_FREE(ld_error);
- /* get the password */
- if (!fetch_ldapsam_pw(&ldap_dn, &ldap_secret))
- {
- DEBUG(0, ("ldap_idmap_connect_system: Failed to retrieve "
- "password from secrets.tdb\n"));
- return LDAP_INVALID_CREDENTIALS;
- }
+ ldap_mods_free(mods, True);
+ mods = NULL;
- state->bind_dn = ldap_dn;
- state->bind_secret = ldap_secret;
+ ldap_memfree(dn);
+ dn = NULL;
- /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
- (OpenLDAP) doesnt' seem to support it */
-
- DEBUG(10,("ldap_idmap_connect_system: Binding to ldap server %s as "
- "\"%s\"\n", state->uri, ldap_dn));
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc(state->ldap_struct, &rebindproc_connect);
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc(state->ldap_struct,
- &rebindproc_connect_with_state, (void *)state);
-# endif
-#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-# if LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc(state->ldap_struct, &rebindproc);
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc(state->ldap_struct, &rebindproc_with_state,
- (void *)state);
-# endif
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
- rc = ldap_simple_bind_s(state->ldap_struct, ldap_dn, ldap_secret);
+ ldap_msgfree(domain_result);
+ domain_result = NULL;
- if (rc != LDAP_SUCCESS) {
- char *ld_error = NULL;
- ldap_get_option(state->ldap_struct, LDAP_OPT_ERROR_STRING,
- &ld_error);
- DEBUG(state->num_failures ? 2 : 0,
- ("failed to bind to server with dn= %s Error: "
- "%s\n\t%s\n",
- ldap_dn ? ld_error : "(unknown)",
- ldap_err2string(rc), ld_error));
- SAFE_FREE(ld_error);
- state->num_failures++;
- return rc;
+ {
+ /* Sleep for a random timeout */
+ unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
+ attempts += 1;
+
+ sleeptime %= 100;
+ msleep(sleeptime);
+ }
}
- state->num_failures = 0;
-
- DEBUG(3, ("ldap_idmap_connect_system: succesful connection to the "
- "LDAP server\n"));
- return rc;
+ DEBUG(0, ("Failed to set new RID\n"));
+ return ret;
}
-static int ldap_idmap_search(struct ldap_idmap_state *state,
- const char *base, int scope, const char *filter,
- const char *attrs[], int attrsonly,
- LDAPMessage **res)
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_filter;
-
- SMB_ASSERT(state);
-
- if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
- if ((rc = ldap_idmap_retry_open(state, &attempts)) !=
- LDAP_SUCCESS) continue;
-
- rc = ldap_search_s(state->ldap_struct, base, scope,
- utf8_filter, (char**)attrs, attrsonly, res);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("ldap_idmap_search: LDAP server is down!\n"));
- ldap_idmap_close();
- }
- SAFE_FREE(utf8_filter);
- return rc;
-}
+/*****************************************************************************
+ Allocate a new RID
+*****************************************************************************/
-/*******************************************************************
-search an attribute and return the first value found.
-******************************************************************/
-static BOOL ldap_idmap_attribute (struct ldap_idmap_state *state,
- LDAPMessage * entry,
- const char *attribute, pstring value)
+static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
{
- char **values;
- value[0] = '\0';
-
- if ((values = ldap_get_values (state->ldap_struct, entry, attribute))
- == NULL) {
- DEBUG(10,("get_single_attribute: [%s] = [<does not exist>]\n",
- attribute));
- return False;
- }
- if (convert_string(CH_UTF8, CH_UNIX,
- values[0], -1,
- value, sizeof(pstring)) == (size_t)-1)
- {
- DEBUG(1, ("ldap_idmap_attribute: string conversion of [%s] = "
- "[%s] failed!\n", attribute, values[0]));
- ldap_value_free(values);
- return False;
- }
- ldap_value_free(values);
-
- return True;
+ return ldap_next_rid( &ldap_state, rid, rid_type );
}
-static const char *attrs[] = {"objectClass", "uidNumber", "gidNumber",
- "ntSid", NULL};
-static const char *pool_attr[] = {"uidNumber", "gidNumber", NULL};
+/*****************************************************************************
+ Allocate a new uid or gid
+*****************************************************************************/
static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
int rc = LDAP_SERVER_DOWN;
int count = 0;
- LDAPMessage *result = 0;
- LDAPMessage *entry = 0;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
pstring id_str, new_id_str;
- LDAPMod mod[2];
- LDAPMod *mods[3];
- const char *type = (id_type & ID_USERID) ? "uidNumber" : "gidNumber";
- char *val[4];
+ LDAPMod **mods = NULL;
+ const char *type;
char *dn;
+ char **attr_list;
+ pstring filter;
+ uid_t luid, huid;
+ gid_t lgid, hgid;
+
- rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(),
- LDAP_SCOPE_SUBTREE, "(objectClass=unixIdPool)",
- pool_attr, 0, &result);
+ type = (id_type & ID_USERID) ?
+ get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
+ get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
+
+ snprintf(filter, sizeof(filter)-1, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
+
+ attr_list = get_attr_list( idpool_attr_list );
+
+ rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter,
+ attr_list, 0, &result);
+ free_attr_list( attr_list );
+
if (rc != LDAP_SUCCESS) {
- DEBUG(0,("ldap_allocate_id: unixIdPool object not found\n"));
+ DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
goto out;
}
- count = ldap_count_entries(ldap_state.ldap_struct, result);
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
if (count != 1) {
- DEBUG(0,("ldap_allocate_id: single unixIdPool not found\n"));
+ DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
goto out;
}
- dn = ldap_get_dn(ldap_state.ldap_struct, result);
- entry = ldap_first_entry(ldap_state.ldap_struct, result);
+ dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+ entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
- if (!ldap_idmap_attribute(&ldap_state, entry, type, id_str)) {
+ if (!smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
type));
goto out;
}
+
+ /* this must succeed or else we wouldn't have initialized */
+
+ lp_idmap_uid( &luid, &huid);
+ lp_idmap_gid( &lgid, &hgid);
+
+ /* make sure we still have room to grow */
+
if (id_type & ID_USERID) {
id->uid = strtoul(id_str, NULL, 10);
- } else {
+ if (id->uid > huid ) {
+ DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %d!\n", huid));
+ goto out;
+ }
+ }
+ else {
id->gid = strtoul(id_str, NULL, 10);
+ if (id->gid > hgid ) {
+ DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %d!\n", hgid));
+ goto out;
+ }
}
-
- mod[0].mod_op = LDAP_MOD_DELETE;
- mod[0].mod_type = strdup(type);
- val[0] = id_str; val[1] = NULL;
- mod[0].mod_values = val;
-
- pstr_sprintf(new_id_str, "%ud",
+
+ snprintf(new_id_str, sizeof(new_id_str), "%u",
((id_type & ID_USERID) ? id->uid : id->gid) + 1);
- mod[1].mod_op = LDAP_MOD_ADD;
- mod[1].mod_type = strdup(type);
- val[3] = new_id_str; val[4] = NULL;
- mod[1].mod_values = val + 2;
+
+ smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
+ smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
+
+ rc = ldap_modify_s(ldap_state.smbldap_state->ldap_struct, dn, mods);
- mods[0] = mod; mods[1] = mod + 1; mods[2] = NULL;
- rc = ldap_modify_s(ldap_state.ldap_struct, dn, mods);
ldap_memfree(dn);
-
- if (rc == LDAP_SUCCESS) ret = NT_STATUS_OK;
+ ldap_mods_free( mods, True );
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldap_allocate_id: Failed to allocate new %s. ldap_modify() failed.\n",
+ type));
+ goto out;
+ }
+
+ ret = NT_STATUS_OK;
out:
return ret;
}
-/* Get a sid from an id */
+/*****************************************************************************
+ get a sid from an id
+*****************************************************************************/
+
static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
{
- LDAPMessage *result = 0;
- LDAPMessage *entry = 0;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ fstring id_str;
pstring sid_str;
pstring filter;
- char type = (id_type & ID_USERID) ? 'u' : 'g';
+ pstring suffix;
+ const char *type;
+ const char *obj_class;
int rc;
int count;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-
- pstr_sprintf(filter, "(&(%cidNumber=%ud)(objectClass=sambaAccount))",
- type, ((id_type & ID_USERID) ? id.uid : id.gid));
- rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(),
- LDAP_SCOPE_SUBTREE, filter, attrs, 0,
- &result);
- if (rc != LDAP_SUCCESS) {
+ char **attr_list;
+
+ /* first we try for a samba user or group mapping */
+
+ if ( id_type & ID_USERID ) {
+ type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
+ obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
+ snprintf(id_str, sizeof(id_str), "%u", id.uid );
+ pstrcpy( suffix, lp_ldap_suffix());
+ }
+ else {
+ type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
+ obj_class = LDAP_OBJ_GROUPMAP;
+ snprintf(id_str, sizeof(id_str), "%u", id.gid );
+ pstrcpy( suffix, lp_ldap_group_suffix() );
+ }
+
+ attr_list = get_attr_list( sidmap_attr_list );
+ snprintf(filter, sizeof(filter), "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))",
+ LDAP_OBJ_IDMAP_ENTRY, obj_class, type, id_str);
+
+ rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
goto out;
- }
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+
+ /* fall back to looking up an idmap entry if we didn't find and
+ actual user or group */
- count = ldap_count_entries(ldap_state.ldap_struct, result);
if (count == 0) {
- pstr_sprintf(filter,
- "(&(objectClass=idmapEntry)(%cidNumber=%ud))",
- type, ((id_type & ID_USERID) ? id.uid : id.gid));
- rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(),
- LDAP_SCOPE_SUBTREE, filter,
- attrs, 0, &result);
- if (rc != LDAP_SUCCESS) {
+ ldap_msgfree(result);
+ result = NULL;
+
+ snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%u))",
+ LDAP_OBJ_IDMAP_ENTRY, type, ((id_type & ID_USERID) ? id.uid : id.gid));
+
+ pstrcpy( suffix, lp_ldap_idmap_suffix() );
+
+ rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
goto out;
- }
- count = ldap_count_entries(ldap_state.ldap_struct, result);
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
}
if (count != 1) {
- DEBUG(0,("ldap_get_sid_from_id: mapping not found for "
- "%cid: %ud\n", (id_type&ID_USERID)?'u':'g',
- ((id_type & ID_USERID) ? id.uid : id.gid)));
+ DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %u\n",
+ type, ((id_type & ID_USERID) ? id.uid : id.gid)));
goto out;
}
- entry = ldap_first_entry(ldap_state.ldap_struct, result);
+ entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
- if (!ldap_idmap_attribute(&ldap_state, entry, "ntSid", sid_str)) {
+ if ( !smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
goto out;
- }
- if (!string_to_sid(sid, sid_str)) {
+ if (!string_to_sid(sid, sid_str))
goto out;
- }
ret = NT_STATUS_OK;
out:
+ free_attr_list( attr_list );
+
+ if (result)
+ ldap_msgfree(result);
+
return ret;
}
-/* Get an id from a sid */
-static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type,
- const DOM_SID *sid)
+/***********************************************************************
+ Get an id from a sid
+***********************************************************************/
+
+static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
{
- LDAPMessage *result = 0;
- LDAPMessage *entry = 0;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
pstring sid_str;
pstring filter;
pstring id_str;
- const char *type = (*id_type & ID_USERID) ? "uidNumber" : "gidNumber";
- const char *class =
- (*id_type & ID_USERID) ? "sambaAccount" : "sambaGroupMapping";
+ const char *suffix;
+ const char *type;
+ const char *obj_class;
+ const char *posix_obj_class;
int rc;
int count;
+ char **attr_list;
+ char *dn = NULL;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-
+
+ /* first try getting the mapping from a samba user or group */
+
sid_to_string(sid_str, sid);
- pstr_sprintf(filter, "(&(objectClass=%s)(ntSid=%s)", class, sid_str);
- rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(),
- LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
- if (rc != LDAP_SUCCESS) {
- goto out;
+ if ( *id_type & ID_USERID ) {
+ type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
+ obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
+ posix_obj_class = LDAP_OBJ_POSIXACCOUNT;
+ suffix = lp_ldap_suffix();
+ snprintf(filter, sizeof(filter),
+ "(&(|(&(objectClass=%s)(objectClass=%s))(objectClass=%s))(%s=%s))",
+ obj_class, posix_obj_class, LDAP_OBJ_IDMAP_ENTRY,
+ get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
+ sid_str);
+ }
+ else {
+ type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
+ obj_class = LDAP_OBJ_GROUPMAP;
+ posix_obj_class = LDAP_OBJ_POSIXGROUP;
+ suffix = lp_ldap_group_suffix();
+ snprintf(filter, sizeof(filter),
+ "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))",
+ obj_class, LDAP_OBJ_IDMAP_ENTRY,
+ get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
+ sid_str);
}
- count = ldap_count_entries(ldap_state.ldap_struct, result);
+
+ attr_list = get_attr_list( sidmap_attr_list );
+ rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto out;
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+
+ /* fall back to looking up an idmap entry if we didn't find anything under the idmap
+ user or group suffix */
+
if (count == 0) {
- pstr_sprintf(filter,
- "(&(objectClass=idmapEntry)(ntSid=%s))", sid_str);
+ ldap_msgfree(result);
+
+ snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
- rc = ldap_idmap_search(&ldap_state, lp_ldap_suffix(),
- LDAP_SCOPE_SUBTREE, filter,
- attrs, 0, &result);
- if (rc != LDAP_SUCCESS) {
- goto out;
- }
- count = ldap_count_entries(ldap_state.ldap_struct, result);
- }
+ suffix = lp_ldap_idmap_suffix();
- /* our search filters may 2 objects in the case that a user and group
- rid are the same */
- if (count != 1 && count != 2) {
- DEBUG(0,
- ("ldap_get_id_from_sid: incorrect number of objects\n"));
+ rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ goto out;
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+ }
+
+ if ( count > 1 ) {
+ DEBUG(0, ("ldap_get_id_from_sid: search %s returned more than on entry!\n",
+ filter));
goto out;
}
- entry = ldap_first_entry(ldap_state.ldap_struct, result);
- if (!ldap_idmap_attribute(&ldap_state, entry, type, id_str)) {
- entry = ldap_next_entry(ldap_state.ldap_struct, entry);
-
- if (!ldap_idmap_attribute(&ldap_state, entry, type, id_str)) {
- int i;
-
- for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
- ret = ldap_allocate_id(id, *id_type);
- if (NT_STATUS_IS_OK(ret)) {
- break;
- }
- }
- if (NT_STATUS_IS_OK(ret)) {
- ret = ldap_set_mapping(sid, *id, *id_type);
- } else {
- DEBUG(0,("ldap_allocate_id: cannot acquire id"
- " lock\n"));
- }
- } else {
- if ((*id_type & ID_USERID)) {
+ /* we might have an existing entry to work with so pull out the requested information */
+
+ if ( count ) {
+ entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
+
+ dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+ DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
+
+ if ( smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) )
+ {
+ if ( (*id_type & ID_USERID) )
id->uid = strtoul(id_str, NULL, 10);
- } else {
+ else
id->gid = strtoul(id_str, NULL, 10);
- }
+
ret = NT_STATUS_OK;
+ goto out;
}
- } else {
- if ((*id_type & ID_USERID)) {
- id->uid = strtoul(id_str, NULL, 10);
- } else {
- id->gid = strtoul(id_str, NULL, 10);
+ }
+
+ if (!(*id_type & ID_QUERY_ONLY)) {
+ /* if entry == NULL, and we are asked to - allocate a new id */
+ int i;
+
+ for (i = 0; i < LDAP_MAX_ALLOC_ID; i++)
+ {
+ ret = ldap_allocate_id(id, *id_type);
+ if ( NT_STATUS_IS_OK(ret) )
+ break;
+ }
+
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
+ goto out;
}
- ret = NT_STATUS_OK;
+
+ ret = ldap_set_mapping(sid, *id, *id_type);
+ } else {
+ /* no match, and not adding one */
+ ret = NT_STATUS_UNSUCCESSFUL;
}
+
out:
+ free_attr_list( attr_list );
+ if (result)
+ ldap_msgfree(result);
+ if (dn)
+ ldap_memfree(dn);
+
return ret;
}
-/* This function cannot be called to modify a mapping, only set a new one */
-static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
+/***********************************************************************
+ This function cannot be called to modify a mapping, only set a new one
+
+ This takes a possible pointer to the existing entry for the UID or SID
+ involved.
+***********************************************************************/
+
+static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id,
+ int id_type, const char *ldap_dn,
+ LDAPMessage *entry)
{
- pstring dn, sid_str, id_str;
- const char *type = (id_type & ID_USERID) ? "uidNumber" : "gidNumber";
- LDAPMod *mods[3];
- LDAPMod mod[2];
- char *val[4];
- int rc;
- int attempts = 0;
+ char *dn = NULL;
+ pstring id_str;
+ fstring type;
+ LDAPMod **mods = NULL;
+ int rc = -1;
+ int ldap_op;
+ fstring sid_string;
+ char **values = NULL;
+ int i;
+
+ sid_to_string( sid_string, sid );
+
+ if (ldap_dn) {
+ DEBUG(10, ("Adding new IDMAP mapping on DN: %s", ldap_dn));
+ ldap_op = LDAP_MOD_REPLACE;
+ dn = strdup(ldap_dn);
+ } else {
+ ldap_op = LDAP_MOD_ADD;
+ asprintf(&dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
+ sid_string, lp_ldap_idmap_suffix());
+ }
+
+ if (!dn) {
+ DEBUG(0, ("ldap_set_mapping_internals: out of memory allocating DN!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
- pstr_sprintf(id_str, "%ud", ((id_type & ID_USERID) ? id.uid : id.gid));
- sid_to_string(sid_str, sid);
- pstr_sprintf(dn, "%s=%ud,%s", type, ((id_type & ID_USERID) ? id.uid : id.gid), lp_ldap_suffix());
- mod[0].mod_op = LDAP_MOD_REPLACE;
- mod[0].mod_type = strdup(type);
- val[0] = id_str; val[1] = NULL;
- mod[0].mod_values = val;
-
- mod[1].mod_op = LDAP_MOD_REPLACE;
- mod[1].mod_type = strdup("ntSid");
- val[2] = sid_str; val[3] = NULL;
- mod[1].mod_values = val + 2;
-
- mods[0] = mod; mods[1] = mod + 1; mods[2] = NULL;
-
- do {
- if ((rc = ldap_idmap_retry_open(&ldap_state, &attempts)) !=
- LDAP_SUCCESS) continue;
+ if ( id_type & ID_USERID )
+ fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
+ else
+ fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
+
+ snprintf(id_str, sizeof(id_str), "%u", ((id_type & ID_USERID) ? id.uid : id.gid));
+
+ if (entry)
+ values = ldap_get_values(ldap_state.smbldap_state->ldap_struct, entry, "objectClass");
+
+ if (values) {
+ BOOL found_idmap = False;
+ for (i=0; values[i]; i++) {
+ if (StrCaseCmp(values[i], LDAP_OBJ_IDMAP_ENTRY) == 0) {
+ found_idmap = True;
+ break;
+ }
+ }
+ if (!found_idmap)
+ smbldap_set_mod( &mods, LDAP_MOD_ADD,
+ "objectClass", LDAP_OBJ_IDMAP_ENTRY );
+ } else {
+ smbldap_set_mod( &mods, LDAP_MOD_ADD,
+ "objectClass", LDAP_OBJ_IDMAP_ENTRY );
+ }
+
+ smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
+ entry, &mods, type, id_str );
+
+ smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
+ entry, &mods,
+ get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
+ sid_string );
+
+ /* There may well be nothing at all to do */
+ if (mods) {
+ switch(ldap_op)
+ {
+ case LDAP_MOD_ADD:
+ smbldap_set_mod( &mods, LDAP_MOD_ADD,
+ "objectClass", LDAP_OBJ_SID_ENTRY );
+ rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
+ break;
+ case LDAP_MOD_REPLACE:
+ rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
+ break;
+ }
- rc = ldap_modify_s(ldap_state.ldap_struct, dn, mods);
- } while ((rc == LDAP_SERVER_DOWN) && (attempts <= 8));
+ ldap_mods_free( mods, True );
+ } else {
+ rc = LDAP_SUCCESS;
+ }
if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %u [%s]\n",
+ (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
+ sid_string, (unsigned int)((id_type & ID_USERID) ? id.uid : id.gid), type));
+ DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
return NT_STATUS_UNSUCCESSFUL;
}
+
+ DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %d [%s]\n",
+ sid_string, ((id_type & ID_USERID) ? id.uid : id.gid), type));
return NT_STATUS_OK;
}
+/***********************************************************************
+ This function cannot be called to modify a mapping, only set a new one
+***********************************************************************/
+
+static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ char *dn = NULL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ const char *type;
+ const char *obj_class;
+ const char *posix_obj_class;
+ const char *suffix;
+ fstring sid_str;
+ fstring id_str;
+ pstring filter;
+ char **attr_list;
+ int rc;
+ int count;
+
+ /* try for a samba user or group mapping (looking for an entry with a SID) */
+ if ( id_type & ID_USERID ) {
+ obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
+ suffix = lp_ldap_suffix();
+ type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
+ posix_obj_class = LDAP_OBJ_POSIXACCOUNT;
+ snprintf(id_str, sizeof(id_str), "%u", id.uid );
+ }
+ else {
+ obj_class = LDAP_OBJ_GROUPMAP;
+ suffix = lp_ldap_group_suffix();
+ type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
+ posix_obj_class = LDAP_OBJ_POSIXGROUP;
+ snprintf(id_str, sizeof(id_str), "%u", id.gid );
+ }
+
+ sid_to_string(sid_str, sid);
+ snprintf(filter, sizeof(filter),
+ "(|"
+ "(&(|(objectClass=%s)(|(objectClass=%s)(objectClass=%s)))(%s=%s))"
+ "(&(objectClass=%s)(%s=%s))"
+ ")",
+ /* objectClasses that might contain a SID */
+ LDAP_OBJ_SID_ENTRY, LDAP_OBJ_IDMAP_ENTRY, obj_class,
+ get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ),
+ sid_str,
+
+ /* objectClasses that might contain a Unix UID/GID */
+ posix_obj_class,
+ /* Unix UID/GID specifier*/
+ type,
+ /* actual ID */
+ id_str);
+
+ attr_list = get_attr_list( sidmap_attr_list );
+ rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+ free_attr_list( attr_list );
+
+ if (rc != LDAP_SUCCESS)
+ goto out;
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+
+ /* fall back to looking up an idmap entry if we didn't find anything under the idmap
+ user or group suffix */
+
+ if (count == 1) {
+ entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
+
+ dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+ DEBUG(10, ("Found partial mapping entry at dn=%s, looking for %s\n", dn, type));
+
+ ret = ldap_set_mapping_internals(sid, id, id_type, dn, entry);
+
+ goto out;
+ } else if (count > 1) {
+ DEBUG(0, ("Too many entries trying to find DN to attach ldap \n"));
+ goto out;
+ }
+
+ ret = ldap_set_mapping_internals(sid, id, id_type, NULL, NULL);
+
+out:
+ if (result)
+ ldap_msgfree(result);
+ if (dn)
+ ldap_memfree(dn);
+
+ return ret;
+}
/*****************************************************************************
Initialise idmap database.
*****************************************************************************/
-static NTSTATUS ldap_idmap_init(void)
+static NTSTATUS ldap_idmap_init( char *params )
{
- /* We wait for the first search request before we try to connect to
- the LDAP server. We may want to connect upon initialization though
- -- aliguori */
+ fstring filter;
+ int rc;
+ char **attr_list;
+ LDAPMessage *result = NULL;
+ LDAPMod **mods = NULL;
+ int count;
+ NTSTATUS nt_status;
+
+ ldap_state.mem_ctx = talloc_init("idmap_ldap");
+ if (!ldap_state.mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* assume location is the only parameter */
+ if (!NT_STATUS_IS_OK(nt_status =
+ smbldap_init(ldap_state.mem_ctx, params,
+ &ldap_state.smbldap_state))) {
+ talloc_destroy(ldap_state.mem_ctx);
+ return nt_status;
+ }
+
+ /* see if the idmap suffix and sub entries exists */
+
+ snprintf( filter, sizeof(filter), "(objectclass=%s)", LDAP_OBJ_IDPOOL );
+
+ attr_list = get_attr_list( idpool_attr_list );
+ rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
+ free_attr_list ( attr_list );
+
+ if (rc != LDAP_SUCCESS)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+
+ if ( count > 1 ) {
+ DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
+ filter, lp_ldap_idmap_suffix() ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ else if (count == 0) {
+ uid_t luid, huid;
+ gid_t lgid, hgid;
+ fstring uid_str, gid_str;
+
+ if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
+ DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ snprintf( uid_str, sizeof(uid_str), "%d", luid );
+ snprintf( gid_str, sizeof(gid_str), "%d", lgid );
+
+ smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
+ smbldap_set_mod( &mods, LDAP_MOD_ADD,
+ get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
+ smbldap_set_mod( &mods, LDAP_MOD_ADD,
+ get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
+
+ rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
+ }
+
return NT_STATUS_OK;
}
-/* End the LDAP session */
+/*****************************************************************************
+ End the LDAP session
+*****************************************************************************/
+
static NTSTATUS ldap_idmap_close(void)
{
- if (ldap_state.ldap_struct != NULL) {
- ldap_unbind_ext(ldap_state.ldap_struct, NULL, NULL);
- ldap_state.ldap_struct = NULL;
- }
+
+ smbldap_free_struct(&(ldap_state).smbldap_state);
+ talloc_destroy(ldap_state.mem_ctx);
DEBUG(5,("The connection to the LDAP server was closed\n"));
/* maybe free the results here --metze */
@@ -823,6 +955,8 @@ static void ldap_idmap_status(void)
static struct idmap_methods ldap_methods = {
ldap_idmap_init,
+ ldap_allocate_rid,
+ ldap_allocate_id,
ldap_get_sid_from_id,
ldap_get_id_from_sid,
ldap_set_mapping,
@@ -833,6 +967,5 @@ static struct idmap_methods ldap_methods = {
NTSTATUS idmap_ldap_init(void)
{
- DEBUG(0,("idmap_reg_ldap: no LDAP support\n"));
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
}
diff --git a/source3/sam/idmap_tdb.c b/source3/sam/idmap_tdb.c
index 31c12241bf..7f8dce1f1a 100644
--- a/source3/sam/idmap_tdb.c
+++ b/source3/sam/idmap_tdb.c
@@ -45,44 +45,126 @@ static struct idmap_state {
gid_t gid_low, gid_high; /* Range of gids to allocate */
} idmap_state;
-/* Allocate either a user or group id from the pool */
+/**********************************************************************
+ Return the TDB_CONTEXT* for winbindd_idmap. I **really** feel
+ dirty doing this, but not so dirty that I want to create another
+ tdb
+***********************************************************************/
+
+TDB_CONTEXT *idmap_tdb_handle( void )
+{
+ if ( idmap_tdb )
+ return idmap_tdb;
+
+ return NULL;
+}
+
+/**********************************************************************
+ allocate a new RID; We don't care if is a user or group
+**********************************************************************/
+
+static NTSTATUS db_allocate_rid(uint32 *rid, int rid_type)
+{
+ uint32 lowrid, highrid;
+ uint32 tmp_rid;
+
+ /* can't handle group rids right now. This is such a mess.... */
+
+ if ( rid_type == GROUP_RID_TYPE )
+ return NT_STATUS_UNSUCCESSFUL;
+
+ /* cannot fail since idmap is only called winbindd */
+
+ idmap_get_free_rid_range( &lowrid, &highrid );
+
+ tmp_rid = lowrid;
+
+ if ( !tdb_change_uint32_atomic(idmap_tdb, "RID_COUNTER", &tmp_rid, RID_MULTIPLIER) ) {
+ DEBUG(3,("db_allocate_rid: Failed to locate next rid record in idmap db\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if ( tmp_rid > highrid ) {
+ DEBUG(0, ("db_allocate_rid: no RIDs available!\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ *rid = tmp_rid;
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Allocate either a user or group id from the pool
+**********************************************************************/
+
static NTSTATUS db_allocate_id(unid_t *id, int id_type)
{
+ BOOL ret;
int hwm;
- if (!id) return NT_STATUS_INVALID_PARAMETER;
+ if (!id)
+ return NT_STATUS_INVALID_PARAMETER;
/* Get current high water mark */
switch (id_type & ID_TYPEMASK) {
case ID_USERID:
+
if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
return NT_STATUS_INTERNAL_DB_ERROR;
}
+ /* check it is in the range */
if (hwm > idmap_state.uid_high) {
DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %u)\n", idmap_state.uid_high));
return NT_STATUS_UNSUCCESSFUL;
}
- (*id).uid = hwm++;
+ /* fetch a new id and increment it */
+ ret = tdb_change_uint32_atomic(idmap_tdb, HWM_USER, &hwm, 1);
+ if (!ret) {
+ DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* recheck it is in the range */
+ if (hwm > idmap_state.uid_high) {
+ DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %u)\n", idmap_state.uid_high));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ (*id).uid = hwm;
+ DEBUG(10,("db_allocate_id: ID_USERID (*id).uid = %d\n", (unsigned int)hwm));
- /* Store new high water mark */
- tdb_store_int32(idmap_tdb, HWM_USER, hwm);
break;
case ID_GROUPID:
if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
return NT_STATUS_INTERNAL_DB_ERROR;
}
+ /* check it is in the range */
if (hwm > idmap_state.gid_high) {
DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %u)\n", idmap_state.gid_high));
return NT_STATUS_UNSUCCESSFUL;
}
- (*id).gid = hwm++;
+ /* fetch a new id and increment it */
+ ret = tdb_change_uint32_atomic(idmap_tdb, HWM_GROUP, &hwm, 1);
+
+ if (!ret) {
+ DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* recheck it is in the range */
+ if (hwm > idmap_state.gid_high) {
+ DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %u)\n", idmap_state.gid_high));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ (*id).gid = hwm;
+ DEBUG(10,("db_allocate_id: ID_GROUPID (*id).gid = %d\n", (unsigned int)hwm));
- /* Store new high water mark */
- tdb_store_int32(idmap_tdb, HWM_GROUP, hwm);
break;
default:
return NT_STATUS_INVALID_PARAMETER;
@@ -92,13 +174,14 @@ static NTSTATUS db_allocate_id(unid_t *id, int id_type)
}
/* Get a sid from an id */
-static NTSTATUS db_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
+static NTSTATUS internal_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
{
TDB_DATA key, data;
fstring keystr;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
- if (!sid) return NT_STATUS_INVALID_PARAMETER;
+ if (!sid)
+ return NT_STATUS_INVALID_PARAMETER;
switch (id_type & ID_TYPEMASK) {
case ID_USERID:
@@ -114,10 +197,13 @@ static NTSTATUS db_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
key.dptr = keystr;
key.dsize = strlen(keystr) + 1;
+ DEBUG(10,("internal_get_sid_from_id: fetching record %s\n", keystr ));
+
data = tdb_fetch(idmap_tdb, key);
if (data.dptr) {
if (string_to_sid(sid, data.dptr)) {
+ DEBUG(10,("internal_get_sid_from_id: fetching record %s -> %s\n", keystr, data.dptr ));
ret = NT_STATUS_OK;
}
SAFE_FREE(data.dptr);
@@ -126,14 +212,15 @@ static NTSTATUS db_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
return ret;
}
-/* Get an id from a sid */
-static NTSTATUS db_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
+/* Error codes for get_id_from_sid */
+enum getidfromsiderr { GET_ID_FROM_SID_OK = 0, GET_ID_FROM_SID_NOTFOUND, GET_ID_FROM_SID_WRONG_TYPE, GET_ID_FROM_SID_ERR };
+
+static enum getidfromsiderr internal_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
{
- TDB_DATA data, key;
+ enum getidfromsiderr ret = GET_ID_FROM_SID_ERR;
fstring keystr;
- NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-
- if (!sid || !id || !id_type) return NT_STATUS_INVALID_PARAMETER;
+ TDB_DATA key, data;
+ int type = *id_type & ID_TYPEMASK;
/* Check if sid is present in database */
sid_to_string(keystr, sid);
@@ -141,71 +228,186 @@ static NTSTATUS db_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
key.dptr = keystr;
key.dsize = strlen(keystr) + 1;
+ DEBUG(10,("internal_get_id_from_sid: fetching record %s of type 0x%x\n", keystr, type ));
+
data = tdb_fetch(idmap_tdb, key);
+ if (!data.dptr) {
+ DEBUG(10,("internal_get_id_from_sid: record %s not found\n", keystr ));
+ return GET_ID_FROM_SID_NOTFOUND;
+ } else {
+ DEBUG(10,("internal_get_id_from_sid: record %s -> %s\n", keystr, data.dptr ));
+ }
- if (data.dptr) {
- int type = *id_type & ID_TYPEMASK;
+ if (type == ID_EMPTY || type == ID_USERID) {
fstring scanstr;
+ /* Parse and return existing uid */
+ fstrcpy(scanstr, "UID %d");
+
+ if (sscanf(data.dptr, scanstr, &((*id).uid)) == 1) {
+ /* uid ok? */
+ if (type == ID_EMPTY) {
+ *id_type = ID_USERID;
+ }
+ DEBUG(10,("internal_get_id_from_sid: %s fetching record %s -> %s \n",
+ (type == ID_EMPTY) ? "ID_EMPTY" : "ID_USERID",
+ keystr, data.dptr ));
+ ret = GET_ID_FROM_SID_OK;
+ } else {
+ ret = GET_ID_FROM_SID_WRONG_TYPE;
+ }
+ }
+
+ if ((ret != GET_ID_FROM_SID_OK) && (type == ID_EMPTY || type == ID_GROUPID)) {
+ fstring scanstr;
+ /* Parse and return existing gid */
+ fstrcpy(scanstr, "GID %d");
+
+ if (sscanf(data.dptr, scanstr, &((*id).gid)) == 1) {
+ /* gid ok? */
+ if (type == ID_EMPTY) {
+ *id_type = ID_GROUPID;
+ }
+ DEBUG(10,("internal_get_id_from_sid: %s fetching record %s -> %s \n",
+ (type == ID_EMPTY) ? "ID_EMPTY" : "ID_GROUPID",
+ keystr, data.dptr ));
+ ret = GET_ID_FROM_SID_OK;
+ } else {
+ ret = GET_ID_FROM_SID_WRONG_TYPE;
+ }
+ }
+
+ SAFE_FREE(data.dptr);
- if (type == ID_EMPTY || type == ID_USERID) {
- /* Parse and return existing uid */
- fstrcpy(scanstr, "UID %d");
+ return ret;
+}
- if (sscanf(data.dptr, scanstr, &((*id).uid)) == 1) {
- /* uid ok? */
- if (type == ID_EMPTY) {
- *id_type = ID_USERID;
- }
- ret = NT_STATUS_OK;
- goto idok;
- }
+/* Get a sid from an id */
+static NTSTATUS db_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type_in)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ enum getidfromsiderr iderr;
+ int id_type = id_type_in & ID_TYPEMASK;
+ unid_t id_tmp = id;
+ int id_type_tmp = id_type;
+
+ DEBUG(10,("db_get_sid_from_id: id_type_in = 0x%x\n", id_type_in));
+
+ ret = internal_get_sid_from_id(sid, id, id_type);
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+
+ iderr = internal_get_id_from_sid(&id_tmp, &id_type_tmp, sid);
+ if (iderr != GET_ID_FROM_SID_OK) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (id_type_tmp != id_type) {
+ return NT_STATUS_UNSUCCESSFUL;
+ } else if (id_type == ID_USERID) {
+ if (id_tmp.uid != id.uid) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ } else if (id_type == ID_GROUPID) {
+ if (id_tmp.gid != id.gid) {
+ return NT_STATUS_UNSUCCESSFUL;
}
+ } else {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return ret;
+}
+/* Get an id from a sid */
+static NTSTATUS db_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ enum getidfromsiderr iderr;
- if (type == ID_EMPTY || type == ID_GROUPID) {
- /* Parse and return existing gid */
- fstrcpy(scanstr, "GID %d");
+ DEBUG(10,("db_get_id_from_sid\n"));
- if (sscanf(data.dptr, scanstr, &((*id).gid)) == 1) {
- /* gid ok? */
- if (type == ID_EMPTY) {
- *id_type = ID_GROUPID;
- }
- ret = NT_STATUS_OK;
+ if (!sid || !id || !id_type)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ iderr = internal_get_id_from_sid(id, id_type, sid);
+ if (iderr == GET_ID_FROM_SID_OK) {
+ DOM_SID sid_tmp;
+ ret = internal_get_sid_from_id(&sid_tmp, *id, *id_type);
+ if (NT_STATUS_IS_OK(ret)) {
+ if (!sid_equal(&sid_tmp, sid)) {
+ return NT_STATUS_UNSUCCESSFUL;
}
}
-idok:
- SAFE_FREE(data.dptr);
+ } else if (iderr == GET_ID_FROM_SID_WRONG_TYPE) {
+ /* We found a record but not the type we wanted.
+ * This is an error, not an opportunity to overwrite...
+ * JRA.
+ */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- } else if (!(*id_type & ID_NOMAP) &&
+ if (!(*id_type & ID_QUERY_ONLY) && (iderr != GET_ID_FROM_SID_OK) &&
(((*id_type & ID_TYPEMASK) == ID_USERID)
|| (*id_type & ID_TYPEMASK) == ID_GROUPID)) {
+ TDB_DATA sid_data;
+ TDB_DATA ugid_data;
+ fstring sid_string;
+
+ sid_to_string(sid_string, sid);
+
+ sid_data.dptr = sid_string;
+ sid_data.dsize = strlen(sid_string)+1;
+
+ /* Lock the record for this SID. */
+ if (tdb_chainlock(idmap_tdb, sid_data) != 0) {
+ DEBUG(10,("db_get_id_from_sid: failed to lock record %s. Error %s\n",
+ sid_string, tdb_errorstr(idmap_tdb) ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- /* Allocate a new id for this sid */
- ret = db_allocate_id(id, *id_type);
- if (NT_STATUS_IS_OK(ret)) {
- fstring keystr2;
+ do {
+ fstring ugid_str;
+ /* Allocate a new id for this sid */
+ ret = db_allocate_id(id, *id_type);
+ if (!NT_STATUS_IS_OK(ret))
+ break;
+
+ /* Store the UID side */
/* Store new id */
if (*id_type & ID_USERID) {
- slprintf(keystr2, sizeof(keystr2), "UID %d", (*id).uid);
+ slprintf(ugid_str, sizeof(ugid_str), "UID %d", (*id).uid);
} else {
- slprintf(keystr2, sizeof(keystr2), "GID %d", (*id).gid);
+ slprintf(ugid_str, sizeof(ugid_str), "GID %d", (*id).gid);
}
+
+ ugid_data.dptr = ugid_str;
+ ugid_data.dsize = strlen(ugid_str) + 1;
- data.dptr = keystr2;
- data.dsize = strlen(keystr2) + 1;
+ DEBUG(10,("db_get_id_from_sid: storing %s -> %s\n",
+ ugid_data.dptr, sid_data.dptr ));
- if (tdb_store(idmap_tdb, key, data, TDB_REPLACE) == -1) {
- /* TODO: print tdb error !! */
- return NT_STATUS_UNSUCCESSFUL;
+ if (tdb_store(idmap_tdb, ugid_data, sid_data, TDB_INSERT) != -1) {
+ ret = NT_STATUS_OK;
+ break;
}
- if (tdb_store(idmap_tdb, data, key, TDB_REPLACE) == -1) {
+ if (tdb_error(idmap_tdb) != TDB_ERR_EXISTS)
+ DEBUG(10,("db_get_id_from_sid: error %s\n", tdb_errorstr(idmap_tdb) ));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ } while (tdb_error(idmap_tdb) == TDB_ERR_EXISTS);
+
+ if (NT_STATUS_IS_OK(ret)) {
+
+ DEBUG(10,("db_get_id_from_sid: storing %s -> %s\n",
+ sid_data.dptr, ugid_data.dptr ));
+
+ if (tdb_store(idmap_tdb, sid_data, ugid_data, TDB_REPLACE) == -1) {
+ DEBUG(10,("db_get_id_from_sid: error %s\n", tdb_errorstr(idmap_tdb) ));
/* TODO: print tdb error !! */
+ tdb_chainunlock(idmap_tdb, sid_data);
return NT_STATUS_UNSUCCESSFUL;
}
-
- ret = NT_STATUS_OK;
}
+
+ tdb_chainunlock(idmap_tdb, sid_data);
}
return ret;
@@ -217,7 +419,10 @@ static NTSTATUS db_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
fstring ksidstr;
fstring kidstr;
- if (!sid) return NT_STATUS_INVALID_PARAMETER;
+ DEBUG(10,("db_set_mapping: id_type = 0x%x\n", id_type));
+
+ if (!sid)
+ return NT_STATUS_INVALID_PARAMETER;
sid_to_string(ksidstr, sid);
@@ -238,32 +443,51 @@ static NTSTATUS db_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
/* *DELETE* prevoius mappings if any.
* This is done both SID and [U|G]ID passed in */
+ /* Lock the record for this SID. */
+ if (tdb_chainlock(idmap_tdb, ksid) != 0) {
+ DEBUG(10,("db_set_mapping: failed to lock record %s. Error %s\n",
+ ksidstr, tdb_errorstr(idmap_tdb) ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(10,("db_set_mapping: fetching %s\n", ksid.dptr));
+
data = tdb_fetch(idmap_tdb, ksid);
if (data.dptr) {
+ DEBUG(10,("db_set_mapping: deleting %s and %s\n", data.dptr, ksid.dptr ));
tdb_delete(idmap_tdb, data);
tdb_delete(idmap_tdb, ksid);
+ SAFE_FREE(data.dptr);
}
data = tdb_fetch(idmap_tdb, kid);
if (data.dptr) {
+ DEBUG(10,("db_set_mapping: deleting %s and %s\n", data.dptr, kid.dptr ));
tdb_delete(idmap_tdb, data);
tdb_delete(idmap_tdb, kid);
+ SAFE_FREE(data.dptr);
}
if (tdb_store(idmap_tdb, ksid, kid, TDB_INSERT) == -1) {
DEBUG(0, ("idb_set_mapping: tdb_store 1 error: %s\n", tdb_errorstr(idmap_tdb)));
+ tdb_chainunlock(idmap_tdb, ksid);
return NT_STATUS_UNSUCCESSFUL;
}
if (tdb_store(idmap_tdb, kid, ksid, TDB_INSERT) == -1) {
DEBUG(0, ("idb_set_mapping: tdb_store 2 error: %s\n", tdb_errorstr(idmap_tdb)));
+ tdb_chainunlock(idmap_tdb, ksid);
return NT_STATUS_UNSUCCESSFUL;
}
+
+ tdb_chainunlock(idmap_tdb, ksid);
+ DEBUG(10,("db_set_mapping: stored %s -> %s and %s -> %s\n", ksid.dptr, kid.dptr, kid.dptr, ksid.dptr ));
return NT_STATUS_OK;
}
/*****************************************************************************
Initialise idmap database.
*****************************************************************************/
-static NTSTATUS db_idmap_init(void)
+
+static NTSTATUS db_idmap_init( char *params )
{
SMB_STRUCT_STAT stbuf;
char *tdbfile = NULL;
@@ -271,30 +495,22 @@ static NTSTATUS db_idmap_init(void)
BOOL tdb_is_new = False;
/* use the old database if present */
- if (!file_exist(lock_path("idmap.tdb"), &stbuf)) {
- if (file_exist(lock_path("winbindd_idmap.tdb"), &stbuf)) {
- DEBUG(0, ("idmap_init: using winbindd_idmap.tdb file!\n"));
- tdbfile = strdup(lock_path("winbindd_idmap.tdb"));
- if (!tdbfile) {
- DEBUG(0, ("idmap_init: out of memory!\n"));
- return NT_STATUS_NO_MEMORY;
- }
- } else {
- tdb_is_new = True;
- }
- }
+ tdbfile = strdup(lock_path("winbindd_idmap.tdb"));
if (!tdbfile) {
- tdbfile = strdup(lock_path("idmap.tdb"));
- if (!tdbfile) {
- DEBUG(0, ("idmap_init: out of memory!\n"));
- return NT_STATUS_NO_MEMORY;
- }
+ DEBUG(0, ("idmap_init: out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!file_exist(tdbfile, &stbuf)) {
+ tdb_is_new = True;
}
- /* Open tdb cache */
+ DEBUG(10,("db_idmap_init: Opening tdbfile %s\n", tdbfile ));
+
+ /* Open idmap repository */
if (!(idmap_tdb = tdb_open_log(tdbfile, 0,
TDB_DEFAULT, O_RDWR | O_CREAT,
- 0600))) {
+ 0644))) {
DEBUG(0, ("idmap_init: Unable to open idmap database\n"));
SAFE_FREE(tdbfile);
return NT_STATUS_UNSUCCESSFUL;
@@ -302,16 +518,20 @@ static NTSTATUS db_idmap_init(void)
SAFE_FREE(tdbfile);
- /* check against earlier versions */
if (tdb_is_new) {
- /* TODO: delete the file if this fail */
+ /* the file didn't existed before opening it, let's
+ * store idmap version as nobody else yet opened and
+ * stored it. I do not like this method but didn't
+ * found a way to understand if an opened tdb have
+ * been just created or not --- SSS */
tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION);
- } else {
- version = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
- if (version != IDMAP_VERSION) {
- DEBUG(0, ("idmap_init: Unable to open idmap database, it's in an old format!\n"));
- return NT_STATUS_INTERNAL_DB_ERROR;
- }
+ }
+
+ /* check against earlier versions */
+ version = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
+ if (version != IDMAP_VERSION) {
+ DEBUG(0, ("idmap_init: Unable to open idmap database, it's in an old format!\n"));
+ return NT_STATUS_INTERNAL_DB_ERROR;
}
/* Create high water marks for group and user id */
@@ -424,9 +644,11 @@ static void db_idmap_status(void)
/* Display complete mapping of users and groups to rids */
}
-struct idmap_methods db_methods = {
+static struct idmap_methods db_methods = {
db_idmap_init,
+ db_allocate_rid,
+ db_allocate_id,
db_get_sid_from_id,
db_get_id_from_sid,
db_set_mapping,
@@ -435,9 +657,7 @@ struct idmap_methods db_methods = {
};
-NTSTATUS idmap_reg_tdb(struct idmap_methods **meth)
+NTSTATUS idmap_tdb_init(void)
{
- *meth = &db_methods;
-
- return NT_STATUS_OK;
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);
}
diff --git a/source3/sam/idmap_util.c b/source3/sam/idmap_util.c
index 8c3a378832..f767cc898c 100644
--- a/source3/sam/idmap_util.c
+++ b/source3/sam/idmap_util.c
@@ -22,10 +22,54 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
+/**********************************************************************
+**********************************************************************/
+
+BOOL idmap_get_free_ugid_range(uint32 *low, uint32 *high)
+{
+ uid_t u_low, u_high;
+ gid_t g_low, g_high;
+
+ if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) {
+ return False;
+ }
+
+ *low = (u_low < g_low) ? u_low : g_low;
+ *high = (u_high < g_high) ? u_high : g_high;
+
+ return True;
+}
/******************************************************************
- * Get the free RID base if idmap is configured, otherwise return 0
- ******************************************************************/
+ Get the the non-algorithmic RID range if idmap range are defined
+******************************************************************/
+
+BOOL idmap_get_free_rid_range(uint32 *low, uint32 *high)
+{
+ uint32 id_low, id_high;
+
+ if (!lp_enable_rid_algorithm()) {
+ *low = BASE_RID;
+ *high = (uint32)-1;
+ }
+
+ if (!idmap_get_free_ugid_range(&id_low, &id_high)) {
+ return False;
+ }
+
+ *low = fallback_pdb_uid_to_user_rid(id_low);
+ if (fallback_pdb_user_rid_to_uid((uint32)-1) < id_high) {
+ *high = (uint32)-1;
+ } else {
+ *high = fallback_pdb_uid_to_user_rid(id_high);
+ }
+
+ return True;
+}
+
+/**********************************************************************
+ Get the free RID base if idmap is configured, otherwise return 0
+**********************************************************************/
uint32 idmap_get_free_rid_base(void)
{
@@ -36,6 +80,9 @@ uint32 idmap_get_free_rid_base(void)
return 0;
}
+/**********************************************************************
+**********************************************************************/
+
BOOL idmap_check_ugid_is_in_free_range(uint32 id)
{
uint32 low, high;
@@ -49,6 +96,9 @@ BOOL idmap_check_ugid_is_in_free_range(uint32 id)
return True;
}
+/**********************************************************************
+**********************************************************************/
+
BOOL idmap_check_rid_is_in_free_range(uint32 rid)
{
uint32 low, high;
@@ -56,13 +106,20 @@ BOOL idmap_check_rid_is_in_free_range(uint32 rid)
if (!idmap_get_free_rid_range(&low, &high)) {
return False;
}
+ if (rid < algorithmic_rid_base()) {
+ return True;
+ }
+
if (rid < low || rid > high) {
return False;
}
+
return True;
}
-/* if it is a foreign SID or if the SID is in the free range, return true */
+/**********************************************************************
+ if it is a foreign SID or if the SID is in the free range, return true
+**********************************************************************/
BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid)
{
@@ -80,182 +137,70 @@ BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid)
return True;
}
-/******************************************************************
- * Get the the non-algorithmic RID range if idmap range are defined
- ******************************************************************/
-
-BOOL idmap_get_free_rid_range(uint32 *low, uint32 *high)
-{
- uint32 id_low, id_high;
-
- if (lp_idmap_only()) {
- *low = BASE_RID;
- *high = (uint32)-1;
- }
-
- if (!idmap_get_free_ugid_range(&id_low, &id_high)) {
- return False;
- }
-
- *low = fallback_pdb_uid_to_user_rid(id_low);
- if (fallback_pdb_user_rid_to_uid((uint32)-1) < id_high) {
- *high = (uint32)-1;
- } else {
- *high = fallback_pdb_uid_to_user_rid(id_high);
- }
-
- return True;
-}
-
-BOOL idmap_get_free_ugid_range(uint32 *low, uint32 *high)
-{
- uid_t u_low, u_high;
- gid_t g_low, g_high;
-
- if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) {
- return False;
- }
- if (u_low < g_low) {
- *low = u_low;
- } else {
- *low = g_low;
- }
- if (u_high < g_high) {
- *high = g_high;
- } else {
- *high = u_high;
- }
- return True;
-}
-
/*****************************************************************
- *THE CANONICAL* convert uid_t to SID function.
- check idmap if uid is in idmap range, otherwise falls back to
- the legacy algorithmic mapping.
- A special cache is used for uids that maps to Wellknown SIDs
Returns SID pointer.
*****************************************************************/
-NTSTATUS uid_to_sid(DOM_SID *sid, uid_t uid)
+NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid)
{
- NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
unid_t id;
int flags;
- DEBUG(10,("uid_to_sid: uid = [%d]\n", uid));
+ DEBUG(10,("idmap_uid_to_sid: uid = [%d]\n", uid));
flags = ID_USERID;
- if (!lp_idmap_only() && !idmap_check_ugid_is_in_free_range(uid)) {
- flags |= ID_NOMAP;
- }
-
id.uid = uid;
- if (NT_STATUS_IS_ERR(ret = idmap_get_sid_from_id(sid, id, flags))) {
- DEBUG(10, ("uid_to_sid: Failed to map uid = [%u]\n", (unsigned int)uid));
- if (flags & ID_NOMAP) {
- sid_copy(sid, get_global_sam_sid());
- sid_append_rid(sid, fallback_pdb_uid_to_user_rid(uid));
-
- DEBUG(10,("uid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", (unsigned int)uid, sid_string_static(sid)));
- ret = NT_STATUS_OK;
- }
- }
-
- return ret;
+
+ return idmap_get_sid_from_id(sid, id, flags);
}
/*****************************************************************
- *THE CANONICAL* convert gid_t to SID function.
- check idmap if gid is in idmap range, otherwise falls back to
- the legacy algorithmic mapping.
Group mapping is used for gids that maps to Wellknown SIDs
Returns SID pointer.
*****************************************************************/
-NTSTATUS gid_to_sid(DOM_SID *sid, gid_t gid)
+NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid)
{
- NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
unid_t id;
int flags;
- DEBUG(10,("gid_to_sid: gid = [%d]\n", gid));
+ DEBUG(10,("idmap_gid_to_sid: gid = [%d]\n", gid));
flags = ID_GROUPID;
- if (!lp_idmap_only() && !idmap_check_ugid_is_in_free_range(gid)) {
- flags |= ID_NOMAP;
+#if 0 /* JERRY */
+ if (!idmap_check_ugid_is_in_free_range(gid)) {
+ flags |= ID_QUERY_ONLY;
}
-
+#endif
id.gid = gid;
- if (NT_STATUS_IS_ERR(ret = idmap_get_sid_from_id(sid, id, flags))) {
- DEBUG(10, ("gid_to_sid: Failed to map gid = [%u]\n", (unsigned int)gid));
- if (flags & ID_NOMAP) {
- sid_copy(sid, get_global_sam_sid());
- sid_append_rid(sid, pdb_gid_to_group_rid(gid));
-
- DEBUG(10,("gid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", (unsigned int)gid, sid_string_static(sid)));
- ret = NT_STATUS_OK;
- }
- }
-
- return ret;
+ return idmap_get_sid_from_id(sid, id, flags);
}
/*****************************************************************
- *THE CANONICAL* convert SID to uid function.
if it is a foreign sid or it is in idmap rid range check idmap,
otherwise falls back to the legacy algorithmic mapping.
- A special cache is used for uids that maps to Wellknown SIDs
Returns True if this name is a user sid and the conversion
was done correctly, False if not.
*****************************************************************/
-NTSTATUS sid_to_uid(const DOM_SID *sid, uid_t *uid)
+NTSTATUS idmap_sid_to_uid(const DOM_SID *sid, uid_t *uid, uint32 flags)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
- BOOL fallback = False;
unid_t id;
- int flags;
-
- DEBUG(10,("sid_to_uid: sid = [%s]\n", sid_string_static(sid)));
-
- flags = ID_USERID;
- if (!lp_idmap_only()) {
- if (!idmap_check_sid_is_in_free_range(sid)) {
- flags |= ID_NOMAP;
- fallback = True;
- }
- }
- if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&id, &flags, sid))) {
+ DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_static(sid)));
- DEBUG(10,("sid_to_uid: uid = [%d]\n", id.uid));
+ flags |= ID_USERID;
+ ret = idmap_get_id_from_sid(&id, &flags, sid);
+
+ if ( NT_STATUS_IS_OK(ret) ) {
+ DEBUG(10,("idmap_sid_to_uid: uid = [%d]\n", id.uid));
*uid = id.uid;
- ret = NT_STATUS_OK;
-
- } else if (fallback) {
- uint32 rid;
-
- if (!sid_peek_rid(sid, &rid)) {
- DEBUG(10,("sid_to_uid: invalid SID!\n"));
- ret = NT_STATUS_INVALID_PARAMETER;
- goto done;
- }
-
- DEBUG(10,("sid_to_uid: Fall back to algorithmic mapping\n"));
-
- if (!fallback_pdb_rid_is_user(rid)) {
- DEBUG(3, ("sid_to_uid: SID %s is *NOT* a user\n", sid_string_static(sid)));
- ret = NT_STATUS_UNSUCCESSFUL;
- } else {
- *uid = fallback_pdb_user_rid_to_uid(rid);
- DEBUG(10,("sid_to_uid: mapping: %s -> %u\n", sid_string_static(sid), (unsigned int)(*uid)));
- ret = NT_STATUS_OK;
- }
- }
+ }
-done:
return ret;
+
}
/*****************************************************************
@@ -267,56 +212,59 @@ done:
was done correctly, False if not.
*****************************************************************/
-NTSTATUS sid_to_gid(const DOM_SID *sid, gid_t *gid)
+NTSTATUS idmap_sid_to_gid(const DOM_SID *sid, gid_t *gid, uint32 flags)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
- BOOL fallback = False;
unid_t id;
- int flags;
DEBUG(10,("sid_to_gid: sid = [%s]\n", sid_string_static(sid)));
- flags = ID_GROUPID;
- if (!lp_idmap_only()) {
- if (!idmap_check_sid_is_in_free_range(sid)) {
- flags |= ID_NOMAP;
- fallback = True;
- }
- }
+ flags |= ID_GROUPID;
- if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&id, &flags, sid))) {
-
- DEBUG(10,("sid_to_gid: gid = [%d]\n", id.gid));
+ ret = idmap_get_id_from_sid(&id, &flags, sid);
+
+ if ( NT_STATUS_IS_OK(ret) )
+ {
+ DEBUG(10,("idmap_sid_to_gid: gid = [%d]\n", id.gid));
*gid = id.gid;
- ret = NT_STATUS_OK;
+ }
- } else if (fallback) {
- uint32 rid;
+ return ret;
+}
- if (!sid_peek_rid(sid, &rid)) {
- DEBUG(10,("sid_to_uid: invalid SID!\n"));
- ret = NT_STATUS_INVALID_PARAMETER;
- goto done;
- }
- DEBUG(10,("sid_to_gid: Fall back to algorithmic mapping\n"));
+/***************************************************************************
+ Check first, call set_mapping if it doesn't already exist.
+***************************************************************************/
- if (fallback_pdb_rid_is_user(rid)) {
- DEBUG(3, ("sid_to_gid: SID %s is *NOT* a group\n", sid_string_static(sid)));
- ret = NT_STATUS_UNSUCCESSFUL;
- } else {
- *gid = pdb_group_rid_to_gid(rid);
- DEBUG(10,("sid_to_gid: mapping: %s -> %u\n", sid_string_static(sid), (unsigned int)(*gid)));
- ret = NT_STATUS_OK;
+static NTSTATUS wellknown_id_init(DOM_SID *sid, unid_t id, int flags)
+{
+ unid_t storedid;
+ int qflags = flags | ID_QUERY_ONLY;
+
+ if (!NT_STATUS_IS_OK(idmap_get_id_from_sid(&storedid, &qflags, sid))) {
+ return idmap_set_mapping(sid, id, flags);
+ } else {
+ if (flags == ID_USERID && id.uid != storedid.uid) {
+ DEBUG(0,("wellknown_id_init: WARNING ! Stored uid %u for SID %s is not the same as the requested uid %u\n",
+ (unsigned int)storedid.uid, sid_string_static(sid), (unsigned int)id.uid ));
+ DEBUG(0,("wellknown_id_init: Attempting to overwrite old mapping with new.\n"));
+ return idmap_set_mapping(sid, id, flags);
+ } else if (flags == ID_GROUPID && id.gid != storedid.gid) {
+ DEBUG(0,("wellknown_id_init: WARNING ! Stored gid %u for SID %s is not the same as the requested gid %u\n",
+ (unsigned int)storedid.gid, sid_string_static(sid), (unsigned int)id.gid ));
+ DEBUG(0,("wellknown_id_init: Attempting to overwrite old mapping with new.\n"));
+ return idmap_set_mapping(sid, id, flags);
}
}
-
-done:
- return ret;
+ return NT_STATUS_OK;
}
-/* Initialize idmap withWellknown SIDs like Guest, that are necessary
- * to make samba run properly */
+/***************************************************************************
+ Initialize idmap withWellknown SIDs like Guest, that are necessary
+ to make samba run properly.
+***************************************************************************/
+
BOOL idmap_init_wellknown_sids(void)
{
const char *guest_account = lp_guestaccount();
@@ -325,7 +273,7 @@ BOOL idmap_init_wellknown_sids(void)
int num_entries=0;
DOM_SID sid;
unid_t id;
- int flags;
+ fstring sid_string;
if (!(guest_account && *guest_account)) {
DEBUG(1, ("NULL guest account!?!?\n"));
@@ -337,39 +285,52 @@ BOOL idmap_init_wellknown_sids(void)
return False;
}
- flags = ID_USERID;
+ /* Fill in the SID for the guest account. */
id.uid = pass->pw_uid;
sid_copy(&sid, get_global_sam_sid());
sid_append_rid(&sid, DOMAIN_USER_RID_GUEST);
- if (NT_STATUS_IS_ERR(idmap_set_mapping(&sid, id, flags))) {
+
+ if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_USERID))) {
+ DEBUG(0, ("Failed to setup UID mapping for GUEST (%s) to (%u)\n",
+ sid_to_string(sid_string, &sid), (unsigned int)id.uid));
+ passwd_free(&pass);
+ return False;
+ }
+
+ /* check if DOMAIN_GROUP_RID_GUESTS SID is set, if not store the
+ * guest account gid as mapping */
+ id.gid = pass->pw_gid;
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, DOMAIN_GROUP_RID_GUESTS);
+ if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_GROUPID))) {
+ DEBUG(0, ("Failed to setup GID mapping for Group DOMAIN GUESTS (%s) to (%u)\n",
+ sid_to_string(sid_string, &sid), (unsigned int)id.gid));
passwd_free(&pass);
return False;
}
+ passwd_free(&pass);
/* now fill in group mappings */
- if(pdb_enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries, ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV)) {
+ if(pdb_enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries, ENUM_ONLY_MAPPED)) {
int i;
for (i = 0; i < num_entries; i++) {
id.gid = map[i].gid;
- idmap_set_mapping(&(map[i].sid), id, ID_GROUPID);
+ wellknown_id_init(&map[i].sid, id, ID_GROUPID);
}
+ SAFE_FREE(map);
}
- /* check if DOMAIN_GROUP_RID_GUESTS SID is set, if not store the
- * guest account gid as mapping */
- flags = ID_GROUPID | ID_NOMAP;
+ /* Fill in the SID for the administrator account. */
+ id.uid = 0;
sid_copy(&sid, get_global_sam_sid());
- sid_append_rid(&sid, DOMAIN_GROUP_RID_GUESTS);
- if (NT_STATUS_IS_ERR(idmap_get_id_from_sid(&id, &flags, &sid))) {
- flags = ID_GROUPID;
- id.gid = pass->pw_gid;
- if (NT_STATUS_IS_ERR(idmap_set_mapping(&sid, id, flags))) {
- passwd_free(&pass);
- return False;
- }
+ sid_append_rid(&sid, DOMAIN_USER_RID_ADMIN);
+
+ if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_USERID))) {
+ DEBUG(0, ("Failed to setup UID mapping for ADMINISTRATOR (%s) to (%u)\n",
+ sid_to_string(sid_string, &sid), (unsigned int)id.uid));
+ return False;
}
- passwd_free(&pass);
return True;
}