mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
3d18997afd
I know this isn't pretty, but neither was our assumption that all strings
from the directory fit inside a pstring. There was no way this worked
before will all versions of usrmgr (for example, the only version of
mine that has the TS Confic button).
(This used to be commit d275c0e384
)
791 lines
22 KiB
C
791 lines
22 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
|
|
idmap LDAP backend
|
|
|
|
Copyright (C) Tim Potter 2000
|
|
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#undef DBGC_CLASS
|
|
#define DBGC_CLASS DBGC_IDMAP
|
|
|
|
|
|
#include <lber.h>
|
|
#include <ldap.h>
|
|
|
|
#include "smbldap.h"
|
|
|
|
struct ldap_idmap_state {
|
|
struct smbldap_state *smbldap_state;
|
|
TALLOC_CTX *mem_ctx;
|
|
};
|
|
|
|
static struct ldap_idmap_state ldap_state;
|
|
|
|
/* number tries while allocating new id */
|
|
#define LDAP_MAX_ALLOC_ID 128
|
|
|
|
|
|
/***********************************************************************
|
|
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)
|
|
{
|
|
pstring dn;
|
|
pstring id_str;
|
|
fstring type;
|
|
LDAPMod **mods = NULL;
|
|
int rc = -1;
|
|
int ldap_op;
|
|
fstring sid_string;
|
|
LDAPMessage *entry = NULL;
|
|
|
|
sid_to_string( sid_string, sid );
|
|
|
|
ldap_op = LDAP_MOD_ADD;
|
|
pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
|
|
sid_string, lp_ldap_idmap_suffix());
|
|
|
|
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 ) );
|
|
|
|
pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
|
|
(unsigned long)id.gid));
|
|
|
|
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) {
|
|
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
|
|
rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
|
|
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 %lu [%s]\n",
|
|
(ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
|
|
sid_string, (unsigned long)((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 %lu [%s]\n",
|
|
sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
|
|
(unsigned long)id.gid), type));
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/**********************************************************************
|
|
Even if the sambaDomain attribute in LDAP tells us that this RID is
|
|
safe to use, always check before use.
|
|
*********************************************************************/
|
|
|
|
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};
|
|
|
|
slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
|
|
|
|
rc = smbldap_search_suffix(state->smbldap_state,
|
|
filter, sid_attr, &result);
|
|
|
|
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);
|
|
|
|
*error = rc;
|
|
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;
|
|
}
|
|
|
|
/**********************************************************************
|
|
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)
|
|
{
|
|
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;
|
|
|
|
while (attempts < 10) {
|
|
if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state,
|
|
&domain_result, get_global_sam_name(), True))) {
|
|
return ret;
|
|
}
|
|
|
|
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 ((dn = smbldap_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 (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
|
|
get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
|
|
algorithmic_rid_base_string)) {
|
|
|
|
alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
|
|
} else {
|
|
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);
|
|
}
|
|
|
|
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_pstring(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) {
|
|
ldap_msgfree(domain_result);
|
|
return NT_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
if (!next_rid) { /* not got one already */
|
|
switch (rid_type) {
|
|
case USER_RID_TYPE:
|
|
if (smbldap_get_single_pstring(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);
|
|
}
|
|
break;
|
|
case GROUP_RID_TYPE:
|
|
if (smbldap_get_single_pstring(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);
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* This is the core of the whole routine. If we had
|
|
scheme-style closures, there would be a *lot* less code
|
|
duplication... */
|
|
|
|
next_rid = *rid+RID_MULTIPLIER;
|
|
slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
|
|
|
|
switch (rid_type) {
|
|
case USER_RID_TYPE:
|
|
/* 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:
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
if ((rc = smbldap_modify(state->smbldap_state, dn, mods)) == LDAP_SUCCESS) {
|
|
DOM_SID dom_sid;
|
|
DOM_SID sid;
|
|
pstring domain_sid_string;
|
|
int error = 0;
|
|
|
|
if (!smbldap_get_single_pstring(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);
|
|
SAFE_FREE(dn);
|
|
ldap_msgfree(domain_result);
|
|
return ret;
|
|
}
|
|
|
|
if (!string_to_sid(&dom_sid, domain_sid_string)) {
|
|
ldap_mods_free(mods, True);
|
|
SAFE_FREE(dn);
|
|
ldap_msgfree(domain_result);
|
|
return ret;
|
|
}
|
|
|
|
ldap_mods_free(mods, True);
|
|
mods = NULL;
|
|
SAFE_FREE(dn);
|
|
ldap_msgfree(domain_result);
|
|
|
|
sid_copy(&sid, &dom_sid);
|
|
sid_append_rid(&sid, *rid);
|
|
|
|
/* check RID is not in use */
|
|
if (sid_in_use(state, &sid, &error)) {
|
|
if (error) {
|
|
return ret;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
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);
|
|
|
|
ldap_mods_free(mods, True);
|
|
mods = NULL;
|
|
|
|
SAFE_FREE(dn);
|
|
|
|
ldap_msgfree(domain_result);
|
|
domain_result = NULL;
|
|
|
|
{
|
|
/* Sleep for a random timeout */
|
|
unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
|
|
attempts += 1;
|
|
|
|
sleeptime %= 100;
|
|
smb_msleep(sleeptime);
|
|
}
|
|
}
|
|
|
|
DEBUG(0, ("Failed to set new RID\n"));
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Allocate a new RID
|
|
*****************************************************************************/
|
|
|
|
static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
|
|
{
|
|
return ldap_next_rid( &ldap_state, rid, rid_type );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
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 = NULL;
|
|
LDAPMessage *entry = NULL;
|
|
pstring id_str, new_id_str;
|
|
LDAPMod **mods = NULL;
|
|
const char *type;
|
|
char *dn = NULL;
|
|
char **attr_list;
|
|
pstring filter;
|
|
uid_t luid, huid;
|
|
gid_t lgid, hgid;
|
|
|
|
|
|
type = (id_type & ID_USERID) ?
|
|
get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
|
|
get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
|
|
|
|
pstr_sprintf(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) {
|
|
DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
|
|
goto out;
|
|
}
|
|
|
|
count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
|
|
if (count != 1) {
|
|
DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
|
|
goto out;
|
|
}
|
|
|
|
dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
|
|
if (!dn) {
|
|
goto out;
|
|
}
|
|
entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
|
|
|
|
if (!smbldap_get_single_pstring(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);
|
|
if (id->uid > huid ) {
|
|
DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
|
|
(unsigned long)huid));
|
|
goto out;
|
|
}
|
|
}
|
|
else {
|
|
id->gid = strtoul(id_str, NULL, 10);
|
|
if (id->gid > hgid ) {
|
|
DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
|
|
(unsigned long)hgid));
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
pstr_sprintf(new_id_str, "%lu",
|
|
((id_type & ID_USERID) ? (unsigned long)id->uid :
|
|
(unsigned long)id->gid) + 1);
|
|
|
|
smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
|
|
smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
|
|
|
|
if (mods == NULL) {
|
|
DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
|
|
goto out;
|
|
}
|
|
|
|
rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
|
|
|
|
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:
|
|
SAFE_FREE(dn);
|
|
if (result != NULL)
|
|
ldap_msgfree(result);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
get a sid from an id
|
|
*****************************************************************************/
|
|
|
|
static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
|
|
{
|
|
LDAPMessage *result = NULL;
|
|
LDAPMessage *entry = NULL;
|
|
pstring sid_str;
|
|
pstring filter;
|
|
pstring suffix;
|
|
const char *type;
|
|
int rc;
|
|
int count;
|
|
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
|
|
char **attr_list;
|
|
|
|
if ( id_type & ID_USERID )
|
|
type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
|
|
else
|
|
type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
|
|
|
|
pstrcpy( suffix, lp_ldap_idmap_suffix() );
|
|
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
|
|
LDAP_OBJ_IDMAP_ENTRY, type,
|
|
((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
|
|
|
|
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) {
|
|
DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
|
|
ldap_err2string(rc) ));
|
|
goto out;
|
|
}
|
|
|
|
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 %s: %lu\n",
|
|
type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
|
|
(unsigned long)id.gid)));
|
|
goto out;
|
|
}
|
|
|
|
entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
|
|
|
|
if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
|
|
goto out;
|
|
|
|
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)
|
|
{
|
|
LDAPMessage *result = NULL;
|
|
LDAPMessage *entry = NULL;
|
|
pstring sid_str;
|
|
pstring filter;
|
|
pstring id_str;
|
|
const char *suffix;
|
|
const char *type;
|
|
int rc;
|
|
int count;
|
|
char **attr_list;
|
|
char *dn = NULL;
|
|
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
|
|
|
|
sid_to_string(sid_str, sid);
|
|
|
|
DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
|
|
(*id_type & ID_GROUPID ? "group" : "user") ));
|
|
|
|
suffix = lp_ldap_idmap_suffix();
|
|
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
|
|
LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
|
|
|
|
if ( *id_type & ID_GROUPID )
|
|
type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
|
|
else
|
|
type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
|
|
|
|
/* do the search and check for errors */
|
|
|
|
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) {
|
|
DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
|
|
ldap_err2string(rc) ));
|
|
goto out;
|
|
}
|
|
|
|
/* check for the number of entries returned */
|
|
|
|
count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
|
|
|
|
if ( count > 1 ) {
|
|
DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
|
|
filter, count));
|
|
goto out;
|
|
}
|
|
|
|
/* try to allocate a new id if we still haven't found one */
|
|
|
|
if ( !count ) {
|
|
int i;
|
|
|
|
if (*id_type & ID_QUERY_ONLY) {
|
|
DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
|
|
goto out;
|
|
}
|
|
|
|
DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
|
|
|
|
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;
|
|
}
|
|
|
|
DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
|
|
(*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
|
|
|
|
ret = ldap_set_mapping(sid, *id, *id_type);
|
|
|
|
/* all done */
|
|
|
|
goto out;
|
|
}
|
|
|
|
DEBUG(10,("ldap_get_id_from_sid: success\n"));
|
|
|
|
entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
|
|
|
|
dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
|
|
if (!dn)
|
|
goto out;
|
|
|
|
DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
|
|
|
|
if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
|
|
if ( (*id_type & ID_USERID) )
|
|
id->uid = strtoul(id_str, NULL, 10);
|
|
else
|
|
id->gid = strtoul(id_str, NULL, 10);
|
|
|
|
ret = NT_STATUS_OK;
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
free_attr_list( attr_list );
|
|
if (result)
|
|
ldap_msgfree(result);
|
|
SAFE_FREE(dn);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**********************************************************************
|
|
Verify the sambaUnixIdPool entry in the directiry.
|
|
**********************************************************************/
|
|
|
|
static NTSTATUS verify_idpool( void )
|
|
{
|
|
fstring filter;
|
|
int rc;
|
|
char **attr_list;
|
|
LDAPMessage *result = NULL;
|
|
LDAPMod **mods = NULL;
|
|
int count;
|
|
|
|
fstr_sprintf( 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);
|
|
|
|
ldap_msgfree(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;
|
|
}
|
|
|
|
fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
|
|
fstr_sprintf( gid_str, "%lu", (unsigned long)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 ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Initialise idmap database.
|
|
*****************************************************************************/
|
|
|
|
static NTSTATUS ldap_idmap_init( char *params )
|
|
{
|
|
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 */
|
|
|
|
nt_status = verify_idpool();
|
|
if ( !NT_STATUS_IS_OK(nt_status) )
|
|
return nt_status;
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
End the LDAP session
|
|
*****************************************************************************/
|
|
|
|
static NTSTATUS ldap_idmap_close(void)
|
|
{
|
|
|
|
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 */
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
|
|
/* This function doesn't make as much sense in an LDAP world since the calling
|
|
node doesn't really control the ID ranges */
|
|
static void ldap_idmap_status(void)
|
|
{
|
|
DEBUG(0, ("LDAP IDMAP Status not available\n"));
|
|
}
|
|
|
|
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,
|
|
ldap_idmap_close,
|
|
ldap_idmap_status
|
|
|
|
};
|
|
|
|
NTSTATUS idmap_ldap_init(void)
|
|
{
|
|
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
|
|
}
|