mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
moving more code around.
* move rid allocation into IDMAP. See comments in _api_samr_create_user()
* add winbind delete user/group functions
I'm checking this in to sync up with everyone. But I'm going to split
the add a separate winbindd_allocate_rid() function for systems
that have an 'add user script' but need idmap to give them a RID.
Life would be so much simplier without 'enable rid algorithm'.
The current RID allocation is horrible due to this one fact.
Tested idmap_tdb but not idmap_ldap yet. Will do that tomorrow.
Nothing has changed in the way a samba domain is represented, stored,
or search in the directory so things should be ok with previous installations.
going to bed now.
(This used to be commit 0463045cc7
)
This commit is contained in:
parent
d117c83ca9
commit
03d5867d52
@ -56,10 +56,12 @@ static int smb_create_user(const char *domain, const char *unix_username, const
|
||||
|
||||
/****************************************************************************
|
||||
Add and Delete UNIX users on demand, based on NTSTATUS codes.
|
||||
We don't care about RID's here so ignore.
|
||||
****************************************************************************/
|
||||
|
||||
void auth_add_user_script(const char *domain, const char *username)
|
||||
{
|
||||
uint32 rid;
|
||||
/*
|
||||
* User validated ok against Domain controller.
|
||||
* If the admin wants us to try and create a UNIX
|
||||
@ -75,8 +77,10 @@ void auth_add_user_script(const char *domain, const char *username)
|
||||
However, a host set for 'security = server' might run winbindd for
|
||||
account allocation */
|
||||
|
||||
if ( !winbind_create_user(username) )
|
||||
if ( !winbind_create_user(username, NULL) ) {
|
||||
DEBUG(5,("auth_add_user_script: winbindd_create_user() failed\n"));
|
||||
rid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -756,7 +756,7 @@ int smb_create_group(char *unix_group, gid_t *new_gid)
|
||||
|
||||
/* Try winbindd */
|
||||
|
||||
if ( winbind_create_group( unix_group ) ) {
|
||||
if ( winbind_create_group( unix_group, NULL ) ) {
|
||||
DEBUG(3,("smb_create_group: winbindd created the group (%s)\n",
|
||||
unix_group));
|
||||
return 0;
|
||||
@ -783,15 +783,13 @@ int smb_delete_group(char *unix_group)
|
||||
DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
|
||||
return ret;
|
||||
}
|
||||
#if 0
|
||||
|
||||
if ( winbind_delete_group( unix_group ) ) {
|
||||
DEBUG(3,("smb_delete_group: winbindd deleted the group (%s)\n",
|
||||
unix_group));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ struct idmap_methods {
|
||||
/* Called when backend is first loaded */
|
||||
NTSTATUS (*init)( char *params );
|
||||
|
||||
NTSTATUS (*allocate_rid)(uint32 *rid, int rid_type);
|
||||
NTSTATUS (*allocate_id)(unid_t *id, int id_type);
|
||||
NTSTATUS (*get_sid_from_id)(DOM_SID *sid, unid_t id, int id_type);
|
||||
NTSTATUS (*get_id_from_sid)(unid_t *id, int *id_type, const DOM_SID *sid);
|
||||
|
@ -1110,3 +1110,151 @@ NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, const char *location, struct smbldap_
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Add the sambaDomain to LDAP, so we don't have to search for this stuff
|
||||
again. This is a once-add operation for now.
|
||||
|
||||
TODO: Add other attributes, and allow modification.
|
||||
*********************************************************************/
|
||||
static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state,
|
||||
const char *domain_name)
|
||||
{
|
||||
fstring sid_string;
|
||||
fstring algorithmic_rid_base_string;
|
||||
pstring filter, dn;
|
||||
LDAPMod **mods = NULL;
|
||||
int rc;
|
||||
int ldap_op;
|
||||
LDAPMessage *result = NULL;
|
||||
int num_result;
|
||||
char **attr_list;
|
||||
|
||||
slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))",
|
||||
get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
domain_name, LDAP_OBJ_DOMINFO);
|
||||
|
||||
attr_list = get_attr_list( dominfo_attr_list );
|
||||
rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result);
|
||||
free_attr_list( attr_list );
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
num_result = ldap_count_entries(ldap_state->ldap_struct, result);
|
||||
|
||||
if (num_result > 1) {
|
||||
DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
|
||||
ldap_msgfree(result);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Check if we need to add an entry */
|
||||
DEBUG(3,("Adding new domain\n"));
|
||||
ldap_op = LDAP_MOD_ADD;
|
||||
|
||||
snprintf(dn, sizeof(dn), "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
domain_name, lp_ldap_suffix());
|
||||
|
||||
/* Free original search */
|
||||
ldap_msgfree(result);
|
||||
|
||||
/* make the changes - the entry *must* not already have samba attributes */
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
domain_name);
|
||||
|
||||
/* If we don't have an entry, then ask secrets.tdb for what it thinks.
|
||||
It may choose to make it up */
|
||||
|
||||
sid_to_string(sid_string, get_global_sam_sid());
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string);
|
||||
|
||||
slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base());
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
|
||||
algorithmic_rid_base_string);
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
|
||||
|
||||
switch(ldap_op)
|
||||
{
|
||||
case LDAP_MOD_ADD:
|
||||
rc = smbldap_add(ldap_state, dn, mods);
|
||||
break;
|
||||
case LDAP_MOD_REPLACE:
|
||||
rc = smbldap_modify(ldap_state, dn, mods);
|
||||
break;
|
||||
default:
|
||||
DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (rc!=LDAP_SUCCESS) {
|
||||
char *ld_error = NULL;
|
||||
ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
|
||||
DEBUG(1,("failed to %s domain dn= %s with: %s\n\t%s\n",
|
||||
ldap_op == LDAP_MOD_ADD ? "add" : "modify",
|
||||
dn, ldap_err2string(rc),
|
||||
ld_error?ld_error:"unknown"));
|
||||
SAFE_FREE(ld_error);
|
||||
|
||||
ldap_mods_free(mods, True);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
DEBUG(2,("added: domain = %s in the LDAP database\n", domain_name));
|
||||
ldap_mods_free(mods, True);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Search for the domain info entry
|
||||
*********************************************************************/
|
||||
NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
|
||||
LDAPMessage ** result, const char *domain_name,
|
||||
BOOL try_add)
|
||||
{
|
||||
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
|
||||
pstring filter;
|
||||
int rc;
|
||||
char **attr_list;
|
||||
int count;
|
||||
|
||||
snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
|
||||
LDAP_OBJ_DOMINFO,
|
||||
get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
domain_name);
|
||||
|
||||
DEBUG(2, ("Searching for:[%s]\n", filter));
|
||||
|
||||
|
||||
attr_list = get_attr_list( dominfo_attr_list );
|
||||
rc = smbldap_search_suffix(ldap_state, filter, attr_list , result);
|
||||
free_attr_list( attr_list );
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
|
||||
DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
|
||||
} else if (ldap_count_entries(ldap_state->ldap_struct, *result) < 1) {
|
||||
DEBUG(3, ("Got no domain info entries for domain\n"));
|
||||
ldap_msgfree(*result);
|
||||
*result = NULL;
|
||||
if (try_add && NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state, domain_name))) {
|
||||
return smbldap_search_domain_info(ldap_state, result, domain_name, False);
|
||||
}
|
||||
else {
|
||||
DEBUG(0, ("Adding domain info for %s failed with %s\n",
|
||||
domain_name, nt_errstr(ret)));
|
||||
return ret;
|
||||
}
|
||||
} else if ((count = ldap_count_entries(ldap_state->ldap_struct, *result)) > 1) {
|
||||
DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
|
||||
count, domain_name));
|
||||
ldap_msgfree(*result);
|
||||
*result = NULL;
|
||||
return ret;
|
||||
} else {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@ BOOL winbind_ping( void )
|
||||
Ask winbindd to create a local user
|
||||
**********************************************************************/
|
||||
|
||||
BOOL winbind_create_user( const char *name )
|
||||
BOOL winbind_create_user( const char *name, uint32 *rid )
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
@ -384,6 +384,11 @@ BOOL winbind_create_user( const char *name )
|
||||
return False;
|
||||
|
||||
DEBUG(10,("winbind_create_user: %s\n", name));
|
||||
|
||||
/* see if the caller wants a new RID returned */
|
||||
|
||||
if ( rid )
|
||||
request.flags = WBFLAG_ALLOCATE_RID;
|
||||
|
||||
fstrcpy( request.data.acct_mgt.username, name );
|
||||
fstrcpy( request.data.acct_mgt.groupname, "" );
|
||||
@ -392,6 +397,9 @@ BOOL winbind_create_user( const char *name )
|
||||
|
||||
result = winbindd_request( WINBINDD_CREATE_USER, &request, &response);
|
||||
|
||||
if ( rid )
|
||||
*rid = response.data.rid;
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -399,7 +407,7 @@ BOOL winbind_create_user( const char *name )
|
||||
Ask winbindd to create a local group
|
||||
**********************************************************************/
|
||||
|
||||
BOOL winbind_create_group( const char *name )
|
||||
BOOL winbind_create_group( const char *name, uint32 *rid )
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
@ -413,12 +421,20 @@ BOOL winbind_create_group( const char *name )
|
||||
|
||||
DEBUG(10,("winbind_create_group: %s\n", name));
|
||||
|
||||
/* see if the caller wants a new RID returned */
|
||||
|
||||
if ( rid )
|
||||
request.flags = WBFLAG_ALLOCATE_RID;
|
||||
|
||||
fstrcpy( request.data.acct_mgt.groupname, name );
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
result = winbindd_request( WINBINDD_CREATE_GROUP, &request, &response);
|
||||
|
||||
if ( rid )
|
||||
*rid = response.data.rid;
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -510,4 +526,58 @@ BOOL winbind_set_user_primary_group( const char *user, const char *group )
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Ask winbindd to remove a user from its lists of accounts
|
||||
**********************************************************************/
|
||||
|
||||
BOOL winbind_delete_user( const char *user )
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
|
||||
if ( !lp_winbind_enable_local_accounts() )
|
||||
return False;
|
||||
|
||||
if ( !user )
|
||||
return False;
|
||||
|
||||
DEBUG(10,("winbind_delete_user: user (%s)\n", user));
|
||||
|
||||
fstrcpy( request.data.acct_mgt.username, user );
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
result = winbindd_request( WINBINDD_DELETE_USER, &request, &response);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Ask winbindd to remove a group from its lists of accounts
|
||||
**********************************************************************/
|
||||
|
||||
BOOL winbind_delete_group( const char *group )
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
|
||||
if ( !lp_winbind_enable_local_accounts() )
|
||||
return False;
|
||||
|
||||
if ( !group )
|
||||
return False;
|
||||
|
||||
DEBUG(10,("winbind_delete_group: group (%s)\n", group));
|
||||
|
||||
fstrcpy( request.data.acct_mgt.groupname, group );
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
result = winbindd_request( WINBINDD_DELETE_GROUP, &request, &response);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -526,16 +526,36 @@ static BOOL wbinfo_create_user(char *username)
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
request.flags = WBFLAG_ALLOCATE_RID;
|
||||
fstrcpy(request.data.acct_mgt.username, username);
|
||||
|
||||
result = winbindd_request(WINBINDD_CREATE_USER, &request, &response);
|
||||
|
||||
if (response.data.auth.nt_status)
|
||||
d_printf("error code was %s (0x%x)\nerror messsage was: %s\n",
|
||||
response.data.auth.nt_status_string,
|
||||
response.data.auth.nt_status,
|
||||
response.data.auth.error_string);
|
||||
if ( result == NSS_STATUS_SUCCESS )
|
||||
d_printf("New RID is %d\n", response.data.rid);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
remove a winbindd user
|
||||
******************************************************************/
|
||||
|
||||
static BOOL wbinfo_delete_user(char *username)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
|
||||
/* Send off request */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.data.acct_mgt.username, username);
|
||||
|
||||
result = winbindd_request(WINBINDD_DELETE_USER, &request, &response);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -558,12 +578,28 @@ static BOOL wbinfo_create_group(char *groupname)
|
||||
|
||||
result = winbindd_request(WINBINDD_CREATE_GROUP, &request, &response);
|
||||
|
||||
if (response.data.auth.nt_status)
|
||||
d_printf("error code was %s (0x%x)\nerror messsage was: %s\n",
|
||||
response.data.auth.nt_status_string,
|
||||
response.data.auth.nt_status,
|
||||
response.data.auth.error_string);
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
remove a winbindd group
|
||||
******************************************************************/
|
||||
|
||||
static BOOL wbinfo_delete_group(char *groupname)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
|
||||
/* Send off request */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.data.acct_mgt.groupname, groupname);
|
||||
|
||||
result = winbindd_request(WINBINDD_DELETE_GROUP, &request, &response);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -614,12 +650,6 @@ static BOOL wbinfo_add_user_to_group(char *string)
|
||||
|
||||
result = winbindd_request(WINBINDD_ADD_USER_TO_GROUP, &request, &response);
|
||||
|
||||
if (response.data.auth.nt_status)
|
||||
d_printf("error code was %s (0x%x)\nerror messsage was: %s\n",
|
||||
response.data.auth.nt_status_string,
|
||||
response.data.auth.nt_status,
|
||||
response.data.auth.error_string);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -647,12 +677,6 @@ static BOOL wbinfo_remove_user_from_group(char *string)
|
||||
|
||||
result = winbindd_request(WINBINDD_REMOVE_USER_FROM_GROUP, &request, &response);
|
||||
|
||||
if (response.data.auth.nt_status)
|
||||
d_printf("error code was %s (0x%x)\nerror messsage was: %s\n",
|
||||
response.data.auth.nt_status_string,
|
||||
response.data.auth.nt_status,
|
||||
response.data.auth.error_string);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -851,7 +875,9 @@ int main(int argc, char **argv)
|
||||
{ "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" },
|
||||
{ "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" },
|
||||
{ "create-user", 'c', POPT_ARG_STRING, &string_arg, 'c', "Create a local user account", "name" },
|
||||
{ "delete-user", 'x', POPT_ARG_STRING, &string_arg, 'x', "Delete a local user account", "name" },
|
||||
{ "create-group", 'C', POPT_ARG_STRING, &string_arg, 'C', "Create a local group", "name" },
|
||||
{ "delete-group", 'X', POPT_ARG_STRING, &string_arg, 'X', "Delete a local group", "name" },
|
||||
{ "add-to-group", 'o', POPT_ARG_STRING, &string_arg, 'o', "Add user to group", "user:group" },
|
||||
{ "del-from-group", 'O', POPT_ARG_STRING, &string_arg, 'O', "Remove user from group", "user:group" },
|
||||
{ "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
|
||||
@ -1036,6 +1062,18 @@ int main(int argc, char **argv)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
if ( !wbinfo_delete_user(string_arg) ) {
|
||||
d_printf("Could not delete user account\n");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
if ( !wbinfo_delete_group(string_arg) ) {
|
||||
d_printf("Could not delete group\n");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
if (!wbinfo_ping()) {
|
||||
d_printf("could not ping winbindd!\n");
|
||||
|
@ -37,6 +37,29 @@ static TDB_CONTEXT *account_tdb;
|
||||
|
||||
extern userdom_struct current_user_info;
|
||||
|
||||
struct _check_primary_grp {
|
||||
gid_t gid;
|
||||
BOOL found;
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
static void free_winbindd_gr( WINBINDD_GR *grp )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( !grp )
|
||||
return;
|
||||
|
||||
for ( i=0; i<grp->num_gr_mem; i++ )
|
||||
SAFE_FREE( grp->gr_mem[i] );
|
||||
|
||||
SAFE_FREE( grp->gr_mem );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Initialise auto-account database.
|
||||
*****************************************************************************/
|
||||
@ -649,8 +672,17 @@ static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user )
|
||||
if ( !found )
|
||||
return False;
|
||||
|
||||
memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) );
|
||||
grp->num_gr_mem--;
|
||||
/* still some remaining members */
|
||||
|
||||
if ( grp->num_gr_mem > 1 ) {
|
||||
memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) );
|
||||
grp->num_gr_mem--;
|
||||
}
|
||||
else { /* last one */
|
||||
free_winbindd_gr( grp );
|
||||
grp->gr_mem = NULL;
|
||||
grp->num_gr_mem = 0;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
@ -658,34 +690,59 @@ static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user )
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
static void free_winbindd_gr( WINBINDD_GR *grp )
|
||||
static int cleangroups_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
|
||||
void *state)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( !grp )
|
||||
return;
|
||||
|
||||
for ( i=0; i<grp->num_gr_mem; i++ )
|
||||
SAFE_FREE( grp->gr_mem[i] );
|
||||
|
||||
SAFE_FREE( grp->gr_mem );
|
||||
int len;
|
||||
fstring key;
|
||||
char *name = (char*)state;
|
||||
|
||||
return;
|
||||
snprintf( key, sizeof(key), "%s/NAME", WBKEY_GROUP );
|
||||
len = strlen(key);
|
||||
|
||||
/* if this is a group entry then, check the members */
|
||||
|
||||
if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) {
|
||||
WINBINDD_GR *grp;
|
||||
|
||||
if ( !(grp = string2group( dbuf.dptr )) ) {
|
||||
DEBUG(0,("cleangroups_traverse_fn: Failure to parse [%s]\n",
|
||||
dbuf.dptr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* just try to delete the user and rely on wb_delgrpmember()
|
||||
to tell you whether or not the group changed. This is more
|
||||
effecient than testing group membership first since the
|
||||
checks for deleting a user from a group is essentially the
|
||||
same as checking if he/she is a member */
|
||||
|
||||
if ( wb_delgrpmember( grp, name ) ) {
|
||||
DEBUG(10,("cleanupgroups_traverse_fn: Removed user (%s) from group (%s)\n",
|
||||
name, grp->gr_name));
|
||||
wb_storegrnam( grp );
|
||||
}
|
||||
|
||||
free_winbindd_gr( grp );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
static BOOL wb_delete_user( const char *name)
|
||||
static BOOL wb_delete_user( WINBINDD_PW *pw)
|
||||
{
|
||||
char *namekey;
|
||||
char *uidkey;
|
||||
|
||||
if ( !account_tdb && !winbindd_accountdb_init() ) {
|
||||
DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
|
||||
DEBUG(0,("wb_delete_user: Failed to open winbindd account db\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
namekey = acct_userkey_byname( name );
|
||||
namekey = acct_userkey_byname( pw->pw_name );
|
||||
|
||||
/* lock the main entry first */
|
||||
|
||||
@ -694,20 +751,101 @@ static BOOL wb_delete_user( const char *name)
|
||||
return False;
|
||||
}
|
||||
|
||||
/* remove user from all groups */
|
||||
|
||||
tdb_traverse(account_tdb, cleangroups_traverse_fn, (void *)pw->pw_name);
|
||||
|
||||
/* remove the user */
|
||||
uidkey = acct_userkey_byuid( pw->pw_uid );
|
||||
|
||||
tdb_delete_bystring( account_tdb, namekey );
|
||||
tdb_delete_bystring( account_tdb, uidkey );
|
||||
|
||||
tdb_unlock_bystring( account_tdb, namekey );
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
static int isprimarygroup_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
|
||||
TDB_DATA dbuf, void *params)
|
||||
{
|
||||
int len;
|
||||
fstring key;
|
||||
struct _check_primary_grp *check = (struct _check_primary_grp*)params;
|
||||
|
||||
snprintf( key, sizeof(key), "%s/NAME", WBKEY_PASSWD );
|
||||
len = strlen(key);
|
||||
|
||||
/* if this is a group entry then, check the members */
|
||||
|
||||
if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) {
|
||||
WINBINDD_PW *pw;;
|
||||
|
||||
if ( !(pw = string2passwd( dbuf.dptr )) ) {
|
||||
DEBUG(0,("isprimarygroup_traverse_fn: Failure to parse [%s]\n",
|
||||
dbuf.dptr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( check->gid == pw->pw_gid ) {
|
||||
check->found = True;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
static BOOL wb_delete_group( const char *name)
|
||||
static BOOL wb_delete_group( WINBINDD_GR *grp )
|
||||
{
|
||||
return False;
|
||||
struct _check_primary_grp check;
|
||||
char *namekey;
|
||||
char *gidkey;
|
||||
|
||||
if ( !account_tdb && !winbindd_accountdb_init() ) {
|
||||
DEBUG(0,("wb_delete_group: Failed to open winbindd account db\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* lock the main entry first */
|
||||
|
||||
namekey = acct_groupkey_byname( grp->gr_name );
|
||||
if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
|
||||
DEBUG(0,("wb_delete_group: Failed to lock %s\n", namekey));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* is this group the primary group for any user? If
|
||||
so deny delete */
|
||||
|
||||
check.found = False;
|
||||
tdb_traverse(account_tdb, isprimarygroup_traverse_fn, (void *)&check);
|
||||
|
||||
if ( check.found ) {
|
||||
DEBUG(4,("wb_delete_group: Cannot delete group (%s) since it "
|
||||
"is the primary group for some users\n", grp->gr_name));
|
||||
return False;
|
||||
}
|
||||
|
||||
/* We're clear. Delete the group */
|
||||
|
||||
DEBUG(5,("wb_delete_group: Removing group (%s)\n", grp->gr_name));
|
||||
|
||||
gidkey = acct_groupkey_bygid( grp->gr_gid );
|
||||
|
||||
tdb_delete_bystring( account_tdb, namekey );
|
||||
tdb_delete_bystring( account_tdb, gidkey );
|
||||
|
||||
tdb_unlock_bystring( account_tdb, namekey );
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
@ -722,6 +860,8 @@ enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state)
|
||||
WINBINDD_GR *wb_grp;
|
||||
struct group *unix_grp;
|
||||
gid_t primary_gid;
|
||||
uint32 flags = state->request.flags;
|
||||
uint32 rid;
|
||||
|
||||
if ( !state->privileged ) {
|
||||
DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n"));
|
||||
@ -781,8 +921,27 @@ enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state)
|
||||
|
||||
pw.pw_uid = id.uid;
|
||||
pw.pw_gid = primary_gid;
|
||||
|
||||
/* store the new entry */
|
||||
|
||||
if ( !wb_storepwnam(&pw) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* do we need a new RID? */
|
||||
|
||||
if ( flags & WBFLAG_ALLOCATE_RID ) {
|
||||
if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, USER_RID_TYPE)) ) {
|
||||
DEBUG(0,("winbindd_create_user: RID allocation failure! Cannot create user (%s)\n",
|
||||
user));
|
||||
wb_delete_user( &pw );
|
||||
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
state->response.data.rid = rid;
|
||||
}
|
||||
|
||||
return ( wb_storepwnam(&pw) ? WINBINDD_OK : WINBINDD_ERROR );
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
@ -794,6 +953,8 @@ enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state)
|
||||
char *group;
|
||||
unid_t id;
|
||||
WINBINDD_GR grp;
|
||||
uint32 flags = state->request.flags;
|
||||
uint32 rid;
|
||||
|
||||
if ( !state->privileged ) {
|
||||
DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n"));
|
||||
@ -821,8 +982,25 @@ enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state)
|
||||
grp.gr_gid = id.gid;
|
||||
grp.gr_mem = NULL; /* start with no members */
|
||||
grp.num_gr_mem = 0;
|
||||
|
||||
if ( !wb_storegrnam(&grp) )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
/* do we need a new RID? */
|
||||
|
||||
if ( flags & WBFLAG_ALLOCATE_RID ) {
|
||||
if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, GROUP_RID_TYPE)) ) {
|
||||
DEBUG(0,("winbindd_create_group: RID allocation failure! Cannot create group (%s)\n",
|
||||
group));
|
||||
wb_delete_group( &grp );
|
||||
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
state->response.data.rid = rid;
|
||||
}
|
||||
|
||||
return ( wb_storegrnam(&grp) ? WINBINDD_OK : WINBINDD_ERROR );
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
@ -989,8 +1167,7 @@ enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state)
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
|
||||
return ( wb_delete_user(user) ? WINBINDD_OK : WINBINDD_ERROR );
|
||||
return ( wb_delete_user(pw) ? WINBINDD_OK : WINBINDD_ERROR );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
@ -1001,6 +1178,7 @@ enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state)
|
||||
{
|
||||
WINBINDD_GR *grp;
|
||||
char *group;
|
||||
BOOL ret;
|
||||
|
||||
if ( !state->privileged ) {
|
||||
DEBUG(2, ("winbindd_delete_group: non-privileged access denied!\n"));
|
||||
@ -1016,13 +1194,15 @@ enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state)
|
||||
/* make sure it is a valid group */
|
||||
|
||||
if ( !(grp = wb_getgrnam( group )) ) {
|
||||
DEBUG(4,("winbindd_delete_user: Cannot delete a non-existent group\n"));
|
||||
DEBUG(4,("winbindd_delete_group: Cannot delete a non-existent group\n"));
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
ret = wb_delete_group(grp);
|
||||
|
||||
free_winbindd_gr( grp );
|
||||
|
||||
return ( wb_delete_group(group) ? WINBINDD_OK : WINBINDD_ERROR );
|
||||
return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
|
||||
}
|
||||
|
||||
|
||||
|
@ -148,6 +148,7 @@ typedef struct winbindd_gr {
|
||||
#define WBFLAG_PAM_LMKEY 0x0008
|
||||
#define WBFLAG_PAM_CONTACT_TRUSTDOM 0x0010
|
||||
#define WBFLAG_QUERY_ONLY 0x0020
|
||||
#define WBFLAG_ALLOCATE_RID 0x0040
|
||||
|
||||
/* Winbind request structure */
|
||||
|
||||
@ -257,6 +258,7 @@ struct winbindd_response {
|
||||
char nt_session_key[16];
|
||||
char first_8_lm_hash[8];
|
||||
} auth;
|
||||
uint32 rid; /* create user or group */
|
||||
} data;
|
||||
|
||||
/* Variable length return data */
|
||||
|
@ -308,6 +308,19 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
|
||||
free_getent_state(state->getpwent_state);
|
||||
state->getpwent_state = NULL;
|
||||
}
|
||||
|
||||
#if 0 /* JERRY */
|
||||
/* add any local users we have */
|
||||
|
||||
if ( (domain_state = (struct getent_state *)malloc(sizeof(struct getent_state))) == NULL )
|
||||
return WINBINDD_ERROR;
|
||||
|
||||
ZERO_STRUCTP(domain_state);
|
||||
|
||||
/* Add to list of open domains */
|
||||
|
||||
DLIST_ADD(state->getpwent_state, domain_state);
|
||||
#endif
|
||||
|
||||
/* Create sam pipes for each domain we know about */
|
||||
|
||||
|
@ -290,41 +290,37 @@ NTSTATUS pdb_init_sam_pw(SAM_ACCOUNT **new_sam_acct, const struct passwd *pwd)
|
||||
|
||||
/*************************************************************
|
||||
Initialises a SAM_ACCOUNT ready to add a new account, based
|
||||
on the unix user if possible.
|
||||
on the UNIX user. Pass in a RID if you have one
|
||||
************************************************************/
|
||||
|
||||
NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username)
|
||||
NTSTATUS pdb_init_sam_new(SAM_ACCOUNT **new_sam_acct, const char *username,
|
||||
uint32 rid)
|
||||
{
|
||||
NTSTATUS nt_status = NT_STATUS_NO_MEMORY;
|
||||
|
||||
struct passwd *pwd;
|
||||
NTSTATUS nt_status = NT_STATUS_NO_MEMORY;
|
||||
struct passwd *pwd;
|
||||
BOOL ret;
|
||||
|
||||
pwd = Get_Pwnam(username);
|
||||
|
||||
if (pwd) {
|
||||
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) {
|
||||
*new_sam_acct = NULL;
|
||||
return nt_status;
|
||||
}
|
||||
} else {
|
||||
DOM_SID g_sid;
|
||||
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(new_sam_acct))) {
|
||||
*new_sam_acct = NULL;
|
||||
return nt_status;
|
||||
}
|
||||
if (!pdb_set_username(*new_sam_acct, username, PDB_SET)) {
|
||||
pdb_free_sam(new_sam_acct);
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
pdb_set_domain (*new_sam_acct, get_global_sam_name(), PDB_DEFAULT);
|
||||
|
||||
/* set Domain Users by default ! */
|
||||
sid_copy(&g_sid, get_global_sam_sid());
|
||||
sid_append_rid(&g_sid, DOMAIN_GROUP_RID_USERS);
|
||||
pdb_set_group_sid(*new_sam_acct, &g_sid, PDB_SET);
|
||||
if (!pwd)
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_pw(new_sam_acct, pwd))) {
|
||||
*new_sam_acct = NULL;
|
||||
return nt_status;
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
|
||||
/* see if we need to generate a new rid using the 2.2 algorithm */
|
||||
if ( rid == 0 && lp_enable_rid_algorithm() ) {
|
||||
DEBUG(10,("pdb_init_sam_new: no RID specified. Generating one via old algorithm\n"));
|
||||
rid = fallback_pdb_uid_to_user_rid(pwd->pw_uid);
|
||||
}
|
||||
|
||||
/* set the new SID */
|
||||
|
||||
ret = pdb_set_user_sid_from_rid( *new_sam_acct, rid, PDB_SET );
|
||||
|
||||
return (ret ? NT_STATUS_OK : NT_STATUS_NO_SUCH_USER);
|
||||
}
|
||||
|
||||
|
||||
@ -920,8 +916,8 @@ BOOL local_password_change(const char *user_name, int local_flags,
|
||||
pdb_free_sam(&sam_pass);
|
||||
|
||||
if ((local_flags & LOCAL_ADD_USER) || (local_flags & LOCAL_DELETE_USER)) {
|
||||
/* Might not exist in /etc/passwd */
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pass, user_name))) {
|
||||
/* Might not exist in /etc/passwd. Use rid algorithm here */
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pass, user_name, 0))) {
|
||||
slprintf(err_str, err_str_len-1, "Failed initialise SAM_ACCOUNT for user %s.\n", user_name);
|
||||
return False;
|
||||
}
|
||||
@ -1247,121 +1243,6 @@ BOOL local_sid_to_gid(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE *name_
|
||||
return True;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
BOOL pdb_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 the non-algorithmic RID range if idmap range are defined
|
||||
******************************************************************/
|
||||
|
||||
BOOL pdb_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 (!pdb_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 pdb_get_free_rid_base(void)
|
||||
{
|
||||
uint32 low, high;
|
||||
if (pdb_get_free_rid_range(&low, &high)) {
|
||||
return low;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
BOOL pdb_check_ugid_is_in_free_range(uint32 id)
|
||||
{
|
||||
uint32 low, high;
|
||||
|
||||
if (!pdb_get_free_ugid_range(&low, &high)) {
|
||||
return False;
|
||||
}
|
||||
if (id < low || id > high) {
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
BOOL pdb_check_rid_is_in_free_range(uint32 rid)
|
||||
{
|
||||
uint32 low, high;
|
||||
|
||||
if (!pdb_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
|
||||
**********************************************************************/
|
||||
|
||||
BOOL pdb_check_sid_is_in_free_range(const DOM_SID *sid)
|
||||
{
|
||||
if (sid_compare_domain(get_global_sam_sid(), sid) == 0) {
|
||||
|
||||
uint32 rid;
|
||||
|
||||
if (sid_peek_rid(sid, &rid)) {
|
||||
return pdb_check_rid_is_in_free_range(rid);
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Marshall/unmarshall SAM_ACCOUNT structs.
|
||||
*********************************************************************/
|
||||
|
@ -96,15 +96,6 @@ struct ldapsam_privates {
|
||||
|
||||
/* configuration items */
|
||||
int schema_ver;
|
||||
|
||||
BOOL permit_non_unix_accounts;
|
||||
|
||||
uint32 low_allocated_user_rid;
|
||||
uint32 high_allocated_user_rid;
|
||||
|
||||
uint32 low_allocated_group_rid;
|
||||
uint32 high_allocated_group_rid;
|
||||
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
@ -338,423 +329,7 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state,
|
||||
ldap_memfree(dn);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Add the sambaDomain to LDAP, so we don't have to search for this stuff
|
||||
again. This is a once-add operation for now.
|
||||
|
||||
TODO: Add other attributes, and allow modification.
|
||||
*********************************************************************/
|
||||
static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state)
|
||||
{
|
||||
fstring sid_string;
|
||||
fstring algorithmic_rid_base_string;
|
||||
pstring filter, dn;
|
||||
LDAPMod **mods = NULL;
|
||||
int rc;
|
||||
int ldap_op;
|
||||
LDAPMessage *result = NULL;
|
||||
int num_result;
|
||||
char **attr_list;
|
||||
|
||||
slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))",
|
||||
get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
ldap_state->domain_name, LDAP_OBJ_DOMINFO);
|
||||
|
||||
attr_list = get_attr_list( dominfo_attr_list );
|
||||
rc = smbldap_search_suffix(ldap_state->smbldap_state, filter,
|
||||
attr_list, &result);
|
||||
free_attr_list( attr_list );
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
|
||||
|
||||
if (num_result > 1) {
|
||||
DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
|
||||
ldap_msgfree(result);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Check if we need to add an entry */
|
||||
DEBUG(3,("Adding new domain\n"));
|
||||
ldap_op = LDAP_MOD_ADD;
|
||||
|
||||
snprintf(dn, sizeof(dn), "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
ldap_state->domain_name, lp_ldap_suffix());
|
||||
|
||||
/* Free original search */
|
||||
ldap_msgfree(result);
|
||||
|
||||
/* make the changes - the entry *must* not already have samba attributes */
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
ldap_state->domain_name);
|
||||
|
||||
/* If we don't have an entry, then ask secrets.tdb for what it thinks.
|
||||
It may choose to make it up */
|
||||
|
||||
sid_to_string(sid_string, get_global_sam_sid());
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string);
|
||||
|
||||
slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base());
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
|
||||
algorithmic_rid_base_string);
|
||||
smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
|
||||
|
||||
switch(ldap_op)
|
||||
{
|
||||
case LDAP_MOD_ADD:
|
||||
rc = smbldap_add(ldap_state->smbldap_state, dn, mods);
|
||||
break;
|
||||
case LDAP_MOD_REPLACE:
|
||||
rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
|
||||
break;
|
||||
default:
|
||||
DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (rc!=LDAP_SUCCESS) {
|
||||
char *ld_error = NULL;
|
||||
ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
|
||||
&ld_error);
|
||||
DEBUG(1,
|
||||
("failed to %s domain dn= %s with: %s\n\t%s\n",
|
||||
ldap_op == LDAP_MOD_ADD ? "add" : "modify",
|
||||
dn, ldap_err2string(rc),
|
||||
ld_error?ld_error:"unknown"));
|
||||
SAFE_FREE(ld_error);
|
||||
|
||||
ldap_mods_free(mods, True);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
DEBUG(2,("added: domain = %s in the LDAP database\n", ldap_state->domain_name));
|
||||
ldap_mods_free(mods, True);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Search for the domain info entry
|
||||
*********************************************************************/
|
||||
static NTSTATUS ldapsam_search_domain_info(struct ldapsam_privates *ldap_state,
|
||||
LDAPMessage ** result, BOOL try_add)
|
||||
{
|
||||
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
|
||||
pstring filter;
|
||||
int rc;
|
||||
char **attr_list;
|
||||
int count;
|
||||
|
||||
snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
|
||||
LDAP_OBJ_DOMINFO,
|
||||
get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
|
||||
ldap_state->domain_name);
|
||||
|
||||
DEBUG(2, ("Searching for:[%s]\n", filter));
|
||||
|
||||
|
||||
attr_list = get_attr_list( dominfo_attr_list );
|
||||
rc = smbldap_search_suffix(ldap_state->smbldap_state, filter,
|
||||
attr_list , result);
|
||||
free_attr_list( attr_list );
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
|
||||
DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
|
||||
} else if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, *result) < 1) {
|
||||
DEBUG(3, ("Got no domain info entries for domain %s\n",
|
||||
ldap_state->domain_name));
|
||||
ldap_msgfree(*result);
|
||||
*result = NULL;
|
||||
if (try_add && NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state))) {
|
||||
return ldapsam_search_domain_info(ldap_state, result, False);
|
||||
} else {
|
||||
DEBUG(0, ("Adding domain info failed with %s\n", nt_errstr(ret)));
|
||||
return ret;
|
||||
}
|
||||
} else if ((count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, *result)) > 1) {
|
||||
DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
|
||||
count, ldap_state->domain_name));
|
||||
ldap_msgfree(*result);
|
||||
*result = NULL;
|
||||
return ret;
|
||||
} else {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
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 ldapsam_privates *ldap_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(ldap_state->smbldap_state,
|
||||
filter, sid_attr, &result);
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
char *ld_error = NULL;
|
||||
ldap_get_option(ldap_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(ldap_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 ldapsam_next_rid(struct ldapsam_privates *ldap_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;
|
||||
|
||||
if ( ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT ) {
|
||||
DEBUG(0, ("Allocated RIDs require the %s objectclass used by 'ldapsam'\n",
|
||||
LDAP_OBJ_SAMBASAMACCOUNT));
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
while (attempts < 10)
|
||||
{
|
||||
if (!NT_STATUS_IS_OK(ret = ldapsam_search_domain_info(ldap_state, &domain_result, True))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
entry = ldap_first_entry(ldap_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 = ldap_get_dn(ldap_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_attribute(ldap_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(ldap_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_attribute(ldap_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;
|
||||
}
|
||||
|
||||
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(ldap_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_attribute(ldap_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 = ldap_state->low_allocated_user_rid;
|
||||
}
|
||||
break;
|
||||
case GROUP_RID_TYPE:
|
||||
if (smbldap_get_single_attribute(ldap_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 = ldap_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... */
|
||||
|
||||
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 > ldap_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(ldap_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 > ldap_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(ldap_state->smbldap_state->ldap_struct, entry, &mods,
|
||||
get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
|
||||
next_rid_string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = ldap_modify_s(ldap_state->smbldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
|
||||
DOM_SID dom_sid;
|
||||
DOM_SID sid;
|
||||
pstring domain_sid_string;
|
||||
int error = 0;
|
||||
|
||||
if (!smbldap_get_single_attribute(ldap_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;
|
||||
}
|
||||
|
||||
if (!string_to_sid(&dom_sid, domain_sid_string)) {
|
||||
ldap_mods_free(mods, True);
|
||||
ldap_memfree(dn);
|
||||
ldap_msgfree(domain_result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ldap_mods_free(mods, True);
|
||||
mods = NULL;
|
||||
ldap_memfree(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(ldap_state, &sid, &error)) {
|
||||
if (error) {
|
||||
return ret;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
ld_error = NULL;
|
||||
ldap_get_option(ldap_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;
|
||||
|
||||
ldap_memfree(dn);
|
||||
dn = NULL;
|
||||
|
||||
ldap_msgfree(domain_result);
|
||||
domain_result = NULL;
|
||||
|
||||
{
|
||||
/* Sleep for a random timeout */
|
||||
unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
|
||||
attempts += 1;
|
||||
|
||||
sleeptime %= 100;
|
||||
msleep(sleeptime);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(0, ("Failed to set new RID\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* New Interface is being implemented here */
|
||||
|
||||
@ -1192,34 +767,6 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
|
||||
|
||||
DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
|
||||
|
||||
if (pdb_get_init_flags(sampass, PDB_USERSID) == PDB_DEFAULT) {
|
||||
if (ldap_state->permit_non_unix_accounts) {
|
||||
if (!NT_STATUS_IS_OK(ldapsam_next_rid(ldap_state, &rid, USER_RID_TYPE))) {
|
||||
DEBUG(0, ("NO user RID specified on account %s, and "
|
||||
"finding next available NUA RID failed, "
|
||||
"cannot store!\n",
|
||||
pdb_get_username(sampass)));
|
||||
ldap_mods_free(*mods, True);
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
DEBUG(0, ("NO user RID specified on account %s, "
|
||||
"cannot store!\n", pdb_get_username(sampass)));
|
||||
ldap_mods_free(*mods, True);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* now that we have figured out the RID, always store it, as
|
||||
the schema requires it (either as a SID or a RID) */
|
||||
|
||||
if (!pdb_set_user_sid_from_rid(sampass, rid, PDB_CHANGED)) {
|
||||
DEBUG(0, ("Could not store RID back onto SAM_ACCOUNT for user %s!\n",
|
||||
pdb_get_username(sampass)));
|
||||
ldap_mods_free(*mods, True);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
/* only update the RID if we actually need to */
|
||||
if (need_update(sampass, PDB_USERSID))
|
||||
{
|
||||
@ -2733,10 +2280,8 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met
|
||||
struct ldapsam_privates *ldap_state;
|
||||
uint32 alg_rid_base;
|
||||
pstring alg_rid_base_string;
|
||||
uint32 low_idmap_uid, high_idmap_uid;
|
||||
uint32 low_idmap_gid, high_idmap_gid;
|
||||
LDAPMessage *result;
|
||||
LDAPMessage *entry;
|
||||
LDAPMessage *result = NULL;
|
||||
LDAPMessage *entry = NULL;
|
||||
DOM_SID ldap_domain_sid;
|
||||
DOM_SID secrets_domain_sid;
|
||||
pstring domain_sid_string;
|
||||
@ -2748,14 +2293,17 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met
|
||||
(*pdb_method)->name = "ldapsam";
|
||||
|
||||
ldap_state = (*pdb_method)->private_data;
|
||||
ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;
|
||||
ldap_state->permit_non_unix_accounts = False;
|
||||
ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;
|
||||
|
||||
/* Try to setup the Domain Name, Domain SID, algorithmic rid base */
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status = ldapsam_search_domain_info(ldap_state, &result, True))) {
|
||||
|
||||
nt_status = smbldap_search_domain_info(ldap_state->smbldap_state, &result,
|
||||
ldap_state->domain_name, True);
|
||||
|
||||
if ( !NT_STATUS_IS_OK(nt_status) ) {
|
||||
DEBUG(2, ("WARNING: Could not get domain info, nor add one to the domain\n"));
|
||||
DEBUGADD(2, ("Continuing on regardless, will be unable to allocate new users/groups, and will risk BDCs having inconsistant SIDs\n"));
|
||||
DEBUGADD(2, ("Continuing on regardless, will be unable to allocate new users/groups, "
|
||||
"and will risk BDCs having inconsistant SIDs\n"));
|
||||
sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@ -2796,21 +2344,6 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met
|
||||
}
|
||||
}
|
||||
ldap_msgfree(result);
|
||||
|
||||
/* check for non-unix account ranges */
|
||||
|
||||
if (lp_idmap_uid(&low_idmap_uid, &high_idmap_uid)
|
||||
&& lp_idmap_gid(&low_idmap_gid, &high_idmap_gid))
|
||||
{
|
||||
DEBUG(2, ("Enabling non-unix account ranges\n"));
|
||||
|
||||
ldap_state->permit_non_unix_accounts = True;
|
||||
|
||||
ldap_state->low_allocated_user_rid = fallback_pdb_uid_to_user_rid(low_idmap_uid);
|
||||
ldap_state->high_allocated_user_rid = fallback_pdb_uid_to_user_rid(high_idmap_uid);
|
||||
ldap_state->low_allocated_group_rid = pdb_gid_to_group_rid(low_idmap_gid);
|
||||
ldap_state->high_allocated_group_rid = pdb_gid_to_group_rid(high_idmap_gid);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
* SMB parameters and setup
|
||||
* Copyright (C) Andrew Tridgell 1992-1998
|
||||
* Modified by Jeremy Allison 1995.
|
||||
* Modified by Gerald (Jerry) Carter 2000-2001
|
||||
* Modified by Andrew Bartlett 2002.
|
||||
* Copyright (C) Andrew Tridgell 1992-1998
|
||||
* Modified by Jeremy Allison 1995.
|
||||
* Modified by Gerald (Jerry) Carter 2000-2001,2003
|
||||
* Modified by Andrew Bartlett 2002.
|
||||
*
|
||||
* 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
|
||||
@ -34,14 +34,13 @@
|
||||
|
||||
struct smb_passwd
|
||||
{
|
||||
BOOL smb_userid_set; /* this is actually the unix uid_t */
|
||||
uint32 smb_userid; /* this is actually the unix uid_t */
|
||||
uint32 smb_userid; /* this is actually the unix uid_t */
|
||||
const char *smb_name; /* username string */
|
||||
|
||||
const unsigned char *smb_passwd; /* Null if no password */
|
||||
const unsigned char *smb_passwd; /* Null if no password */
|
||||
const unsigned char *smb_nt_passwd; /* Null if no password */
|
||||
|
||||
uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
|
||||
uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
|
||||
time_t pass_last_set_time; /* password last set time */
|
||||
};
|
||||
|
||||
@ -61,12 +60,6 @@ struct smbpasswd_privates
|
||||
|
||||
/* retrive-once info */
|
||||
const char *smbpasswd_file;
|
||||
|
||||
BOOL permit_non_unix_accounts;
|
||||
|
||||
uid_t low_nua_userid;
|
||||
uid_t high_nua_userid;
|
||||
|
||||
};
|
||||
|
||||
enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
|
||||
@ -591,28 +584,6 @@ static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, str
|
||||
|
||||
/* Ok - entry doesn't exist. We can add it */
|
||||
|
||||
/* Account not in /etc/passwd hack!!! */
|
||||
if (!newpwd->smb_userid_set) {
|
||||
if (!smbpasswd_state->permit_non_unix_accounts) {
|
||||
DEBUG(0, ("add_smbfilepwd_entry: cannot add account %s without unix identity\n", newpwd->smb_name));
|
||||
endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (max_found_uid < smbpasswd_state->low_nua_userid) {
|
||||
newpwd->smb_userid = smbpasswd_state->low_nua_userid;
|
||||
newpwd->smb_userid_set = True;
|
||||
} else if (max_found_uid >= smbpasswd_state->high_nua_userid) {
|
||||
DEBUG(0, ("add_smbfilepwd_entry: cannot add machine %s, no uids are free! \n", newpwd->smb_name));
|
||||
endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
|
||||
return False;
|
||||
} else {
|
||||
newpwd->smb_userid = max_found_uid + 1;
|
||||
newpwd->smb_userid_set = True;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Create a new smb passwd entry and set it to the given password. */
|
||||
/*
|
||||
* The add user write needs to be atomic - so get the fd from
|
||||
@ -1149,12 +1120,10 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas
|
||||
DEBUG(0, ("Could not find gest account via getpwnam()! (%s)\n", lp_guestaccount()));
|
||||
return False;
|
||||
}
|
||||
smb_pw->smb_userid_set = True;
|
||||
smb_pw->smb_userid=passwd->pw_uid;
|
||||
passwd_free(&passwd);
|
||||
|
||||
} else if (fallback_pdb_rid_is_user(rid)) {
|
||||
smb_pw->smb_userid_set = True;
|
||||
smb_pw->smb_userid=fallback_pdb_user_rid_to_uid(rid);
|
||||
} else {
|
||||
DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
|
||||
@ -1170,25 +1139,6 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas
|
||||
smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
|
||||
smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* ifdef'out by JFM on 11/29/2001.
|
||||
* this assertion is no longer valid
|
||||
* and I don't understand the goal
|
||||
* and doing the same thing with the group mapping code
|
||||
* is hairy !
|
||||
*
|
||||
* We just have the RID, in which SID is it valid ?
|
||||
* our domain SID ? well known SID ? local SID ?
|
||||
*/
|
||||
|
||||
if (gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) {
|
||||
DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n"));
|
||||
DEBUG(0,("build_sam_pass: %d %d %d. \n", *gid, pdb_group_rid_to_gid(pdb_get_group_rid(sampass)), pdb_get_group_rid(sampass)));
|
||||
return False;
|
||||
}
|
||||
#endif
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -1204,49 +1154,28 @@ static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state,
|
||||
DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
pwfile = getpwnam_alloc(pw_buf->smb_name);
|
||||
if (pwfile == NULL) {
|
||||
if ((smbpasswd_state->permit_non_unix_accounts)
|
||||
&& (pw_buf->smb_userid >= smbpasswd_state->low_nua_userid)
|
||||
&& (pw_buf->smb_userid <= smbpasswd_state->high_nua_userid)) {
|
||||
|
||||
pdb_set_user_sid_from_rid(sam_pass, fallback_pdb_uid_to_user_rid (pw_buf->smb_userid), PDB_SET);
|
||||
/* verify the user account exists */
|
||||
|
||||
/* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here.
|
||||
|
||||
This was down the bottom for machines, but it looks pretty good as
|
||||
a general default for non-unix users. --abartlet 2002-01-08
|
||||
*/
|
||||
pdb_set_group_sid_from_rid (sam_pass, DOMAIN_GROUP_RID_USERS, PDB_SET);
|
||||
pdb_set_username (sam_pass, pw_buf->smb_name, PDB_SET);
|
||||
pdb_set_domain (sam_pass, get_global_sam_name(), PDB_DEFAULT);
|
||||
|
||||
} else {
|
||||
DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid %u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
|
||||
if ( !(pwfile = getpwnam_alloc(pw_buf->smb_name)) ) {
|
||||
DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid "
|
||||
"%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
passwd_free(&pwfile);
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile)))
|
||||
return False;
|
||||
|
||||
passwd_free(&pwfile);
|
||||
|
||||
/* set remaining fields */
|
||||
|
||||
pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET);
|
||||
pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET);
|
||||
pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET);
|
||||
pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
|
||||
pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
|
||||
|
||||
#if 0 /* JERRY */
|
||||
/* the smbpasswd format doesn't have a must change time field, so
|
||||
we can't get this right. The best we can do is to set this to
|
||||
some time in the future. 21 days seems as reasonable as any other value :)
|
||||
*/
|
||||
pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE, PDB_DEFAULT);
|
||||
#endif
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -1558,11 +1487,6 @@ static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_m
|
||||
|
||||
(*pdb_method)->free_private_data = free_private_data;
|
||||
|
||||
if (lp_idmap_uid(&privates->low_nua_userid, &privates->high_nua_userid)) {
|
||||
DEBUG(3, ("idmap uid range defined, non unix accounts enabled\n"));
|
||||
privates->permit_non_unix_accounts = True;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
* SMB parameters and setup
|
||||
* Copyright (C) Andrew Tridgell 1992-1998
|
||||
* Copyright (C) Simo Sorce 2000-2002
|
||||
* Copyright (C) Gerald Carter 2000
|
||||
* Copyright (C) Jeremy Allison 2001
|
||||
* Copyright (C) Andrew Bartlett 2002
|
||||
* Copyright (C) Andrew Tridgell 1992-1998
|
||||
* Copyright (C) Simo Sorce 2000-2002
|
||||
* Copyright (C) Gerald Carter 2000
|
||||
* Copyright (C) Jeremy Allison 2001
|
||||
* Copyright (C) Andrew Bartlett 2002
|
||||
*
|
||||
* 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
|
||||
@ -48,13 +48,6 @@ struct tdbsam_privates {
|
||||
|
||||
/* retrive-once info */
|
||||
const char *tdbsam_location;
|
||||
|
||||
BOOL permit_non_unix_accounts;
|
||||
|
||||
BOOL algorithmic_rids;
|
||||
|
||||
uint32 low_nua_rid;
|
||||
uint32 high_nua_rid;
|
||||
};
|
||||
|
||||
/***************************************************************
|
||||
@ -342,61 +335,31 @@ static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd,
|
||||
fstring name;
|
||||
BOOL ret = True;
|
||||
uint32 user_rid;
|
||||
BOOL tdb_ret;
|
||||
|
||||
/* invalidate the existing TDB iterator if it is open */
|
||||
|
||||
if (tdb_state->passwd_tdb) {
|
||||
tdb_close(tdb_state->passwd_tdb);
|
||||
tdb_state->passwd_tdb = NULL;
|
||||
}
|
||||
|
||||
/* open the account TDB passwd*/
|
||||
|
||||
pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
|
||||
if (!pwd_tdb)
|
||||
{
|
||||
DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location));
|
||||
|
||||
if (!pwd_tdb) {
|
||||
DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n",
|
||||
tdb_state->tdbsam_location));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!pdb_get_group_rid(newpwd)) {
|
||||
DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",pdb_get_username(newpwd)));
|
||||
DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",
|
||||
pdb_get_username(newpwd)));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* if flag == TDB_INSERT then make up a new RID else throw an error. */
|
||||
if (!(user_rid = pdb_get_user_rid(newpwd))) {
|
||||
if ((flag & TDB_INSERT) && tdb_state->permit_non_unix_accounts) {
|
||||
uint32 lowrid, highrid;
|
||||
if (!pdb_get_free_rid_range(&lowrid, &highrid)) {
|
||||
/* should never happen */
|
||||
DEBUG(0, ("tdbsam: something messed up, no high/low rids but nua enabled ?!\n"));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
user_rid = lowrid;
|
||||
tdb_ret = tdb_change_uint32_atomic(pwd_tdb, "RID_COUNTER", &user_rid, RID_MULTIPLIER);
|
||||
if (!tdb_ret) {
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
if (user_rid > highrid) {
|
||||
DEBUG(0, ("tdbsam: no NUA rids available, cannot add user %s!\n", pdb_get_username(newpwd)));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
if (!pdb_set_user_sid_from_rid(newpwd, user_rid, PDB_CHANGED)) {
|
||||
DEBUG(0, ("tdbsam: not able to set new allocated user RID into sam account!\n"));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a RID\n",pdb_get_username(newpwd)));
|
||||
ret = False;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
|
||||
if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) {
|
||||
DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
|
||||
@ -531,7 +494,6 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth
|
||||
{
|
||||
NTSTATUS nt_status;
|
||||
struct tdbsam_privates *tdb_state;
|
||||
uid_t low_nua_uid, high_nua_uid;
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
|
||||
return nt_status;
|
||||
@ -569,19 +531,6 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth
|
||||
|
||||
(*pdb_method)->free_private_data = free_private_data;
|
||||
|
||||
if (lp_idmap_uid(&low_nua_uid, &high_nua_uid)) {
|
||||
DEBUG(3, ("idmap uid range defined, non unix accounts enabled\n"));
|
||||
|
||||
tdb_state->permit_non_unix_accounts = True;
|
||||
|
||||
tdb_state->low_nua_rid=fallback_pdb_uid_to_user_rid(low_nua_uid);
|
||||
|
||||
tdb_state->high_nua_rid=fallback_pdb_uid_to_user_rid(high_nua_uid);
|
||||
|
||||
} else {
|
||||
tdb_state->algorithmic_rids = True;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
@ -2204,6 +2204,7 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_
|
||||
uint32 acc_granted;
|
||||
SEC_DESC *psd;
|
||||
size_t sd_size;
|
||||
uint32 new_rid = 0;
|
||||
/* check this, when giving away 'add computer to domain' privs */
|
||||
uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS;
|
||||
|
||||
@ -2272,6 +2273,17 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_
|
||||
|
||||
pw = Get_Pwnam(account);
|
||||
|
||||
/*********************************************************************
|
||||
* HEADS UP! If we have to create a new user account, we have to get
|
||||
* a new RID from somewhere. This used to be done by the passdb
|
||||
* backend. It has been moved into idmap now. Since idmap is now
|
||||
* wrapped up behind winbind, this means you have to run winbindd if you
|
||||
* want new accounts to get a new RID when "enable rid algorithm = no".
|
||||
* Tough. We now have a uniform way of allocating RIDs regardless
|
||||
* of what ever passdb backend people may use.
|
||||
* --jerry (2003-07-10)
|
||||
*********************************************************************/
|
||||
|
||||
if ( !pw ) {
|
||||
/*
|
||||
* we can't check both the ending $ and the acb_info.
|
||||
@ -2293,15 +2305,17 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_
|
||||
}
|
||||
else /* no add user script -- ask winbindd to do it */
|
||||
{
|
||||
if ( !winbind_create_user( account ) )
|
||||
DEBUG(3,("_api_samr_create_user: winbind_create_user(%s) failed\n", account));
|
||||
if ( !winbind_create_user( account, &new_rid ) ) {
|
||||
DEBUG(3,("_api_samr_create_user: winbind_create_user(%s) failed\n",
|
||||
account));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* implicit call to getpwnam() next */
|
||||
/* implicit call to getpwnam() next. we have a valid SID coming out of this call */
|
||||
|
||||
if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account)) )
|
||||
if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account, new_rid)) )
|
||||
return nt_status;
|
||||
|
||||
pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED);
|
||||
@ -3711,12 +3725,25 @@ static int smb_delete_user(const char *unix_user)
|
||||
pstring del_script;
|
||||
int ret;
|
||||
|
||||
/* try winbindd first since it is impossible to determine where
|
||||
a user came from via NSS. Try the delete user script if this fails
|
||||
meaning the user did not exist in winbindd's list of accounts */
|
||||
|
||||
if ( winbind_delete_user( unix_user ) ) {
|
||||
DEBUG(3,("winbind_delete_user: removed user (%s)\n", unix_user));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* fall back to 'delete user script' */
|
||||
|
||||
pstrcpy(del_script, lp_deluser_script());
|
||||
if (! *del_script)
|
||||
return -1;
|
||||
all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
|
||||
ret = smbrun(del_script,NULL);
|
||||
DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Get ID from SID. This can create a mapping for a SID to a POSIX id.
|
||||
Alloocate a new UNIX uid/gid
|
||||
**************************************************************************/
|
||||
|
||||
NTSTATUS idmap_allocate_id(unid_t *id, int id_type)
|
||||
@ -265,6 +265,19 @@ NTSTATUS idmap_allocate_id(unid_t *id, int 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.
|
||||
|
@ -42,7 +42,11 @@ struct ldap_idmap_state {
|
||||
struct smbldap_state *smbldap_state;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
/* struct ldap_idmap_state *prev, *next; */
|
||||
uint32 low_allocated_user_rid;
|
||||
uint32 high_allocated_user_rid;
|
||||
uint32 low_allocated_group_rid;
|
||||
uint32 high_allocated_group_rid;
|
||||
|
||||
};
|
||||
|
||||
#define LDAP_MAX_ALLOC_ID 128 /* number tries while allocating
|
||||
@ -56,6 +60,282 @@ static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, int id
|
||||
static NTSTATUS ldap_idmap_close(void);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
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 = 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 (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))
|
||||
{
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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_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... */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 (!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;
|
||||
}
|
||||
|
||||
if (!string_to_sid(&dom_sid, domain_sid_string)) {
|
||||
ldap_mods_free(mods, True);
|
||||
ldap_memfree(dn);
|
||||
ldap_msgfree(domain_result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ldap_mods_free(mods, True);
|
||||
mods = NULL;
|
||||
ldap_memfree(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;
|
||||
|
||||
ldap_memfree(dn);
|
||||
dn = NULL;
|
||||
|
||||
ldap_msgfree(domain_result);
|
||||
domain_result = NULL;
|
||||
|
||||
{
|
||||
/* Sleep for a random timeout */
|
||||
unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
|
||||
attempts += 1;
|
||||
|
||||
sleeptime %= 100;
|
||||
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
|
||||
*****************************************************************************/
|
||||
@ -675,6 +955,7 @@ 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,
|
||||
|
@ -59,7 +59,45 @@ TDB_CONTEXT *idmap_tdb_handle( void )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate either a user or group id from the pool */
|
||||
/**********************************************************************
|
||||
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;
|
||||
@ -609,6 +647,7 @@ static void db_idmap_status(void)
|
||||
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,
|
||||
|
@ -22,6 +22,120 @@
|
||||
#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 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)
|
||||
{
|
||||
uint32 low, high;
|
||||
if (idmap_get_free_rid_range(&low, &high)) {
|
||||
return low;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
BOOL idmap_check_ugid_is_in_free_range(uint32 id)
|
||||
{
|
||||
uint32 low, high;
|
||||
|
||||
if (!idmap_get_free_ugid_range(&low, &high)) {
|
||||
return False;
|
||||
}
|
||||
if (id < low || id > high) {
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
|
||||
BOOL idmap_check_rid_is_in_free_range(uint32 rid)
|
||||
{
|
||||
uint32 low, high;
|
||||
|
||||
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
|
||||
**********************************************************************/
|
||||
|
||||
BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid)
|
||||
{
|
||||
if (sid_compare_domain(get_global_sam_sid(), sid) == 0) {
|
||||
|
||||
uint32 rid;
|
||||
|
||||
if (sid_peek_rid(sid, &rid)) {
|
||||
return idmap_check_rid_is_in_free_range(rid);
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Returns SID pointer.
|
||||
|
@ -444,7 +444,9 @@ fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta)
|
||||
}
|
||||
else {
|
||||
DEBUG(8,("fetch_account_info: no add user/machine script. Asking winbindd\n"));
|
||||
if ( !winbind_create_user( account ) )
|
||||
|
||||
/* don't need a RID allocated since the user already has a SID */
|
||||
if ( !winbind_create_user( account, NULL ) )
|
||||
DEBUG(4,("fetch_account_info: winbind_create_user() failed\n"));
|
||||
}
|
||||
|
||||
|
@ -350,7 +350,7 @@ static int new_user (struct pdb_context *in, const char *username,
|
||||
NTSTATUS nt_status;
|
||||
char *password1, *password2, *staticpass;
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pwent, username))) {
|
||||
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pwent, username, 0))) {
|
||||
DEBUG(0, ("could not create account to add new user %s\n", username));
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user