mirror of
https://github.com/samba-team/samba.git
synced 2025-01-26 10:04:02 +03:00
fix for BUG #267 (problem with supplementary groups).
Use winbindd to get the group list if possible since we already know it from netsamlogon_cache.tdb. More effecient than letting libc call getgrent() to get seconary groups. Tested by Ken Cross. (This used to be commit 3c537c906f29a08e75895c8c8e3ed5c5abaaa940)
This commit is contained in:
parent
722ce0eb95
commit
c1bc3a7841
@ -646,43 +646,66 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups,
|
||||
* of groups.
|
||||
******************************************************************************/
|
||||
|
||||
static NTSTATUS get_user_groups_from_local_sam(const char *username, uid_t uid, gid_t gid,
|
||||
int *n_groups, DOM_SID **groups, gid_t **unix_groups)
|
||||
static NTSTATUS get_user_groups(const char *username, uid_t uid, gid_t gid,
|
||||
int *n_groups, DOM_SID **groups, gid_t **unix_groups)
|
||||
{
|
||||
int n_unix_groups;
|
||||
int i;
|
||||
int n_unix_groups;
|
||||
int i;
|
||||
|
||||
*n_groups = 0;
|
||||
*groups = NULL;
|
||||
|
||||
n_unix_groups = groups_max();
|
||||
if ((*unix_groups = malloc( sizeof(gid_t) * n_unix_groups ) ) == NULL) {
|
||||
DEBUG(0, ("get_user_groups_from_local_sam: Out of memory allocating unix group list\n"));
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (sys_getgrouplist(username, gid, *unix_groups, &n_unix_groups) == -1) {
|
||||
gid_t *groups_tmp;
|
||||
groups_tmp = Realloc(*unix_groups, sizeof(gid_t) * n_unix_groups);
|
||||
if (!groups_tmp) {
|
||||
SAFE_FREE(*unix_groups);
|
||||
/* Try winbind first */
|
||||
|
||||
if ( strchr(username, *lp_winbind_separator()) ) {
|
||||
n_unix_groups = winbind_getgroups( username, unix_groups );
|
||||
|
||||
DEBUG(10,("get_user_groups: winbind_getgroups(%s): result = %s\n", username,
|
||||
n_unix_groups == -1 ? "FAIL" : "SUCCESS"));
|
||||
|
||||
if ( n_unix_groups == -1 )
|
||||
return NT_STATUS_NO_SUCH_USER; /* what should this return value be? */
|
||||
}
|
||||
else {
|
||||
/* fallback to getgrouplist() */
|
||||
|
||||
n_unix_groups = groups_max();
|
||||
|
||||
if ((*unix_groups = malloc( sizeof(gid_t) * n_unix_groups ) ) == NULL) {
|
||||
DEBUG(0, ("get_user_groups: Out of memory allocating unix group list\n"));
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
*unix_groups = groups_tmp;
|
||||
|
||||
|
||||
if (sys_getgrouplist(username, gid, *unix_groups, &n_unix_groups) == -1) {
|
||||
DEBUG(0, ("get_user_groups_from_local_sam: failed to get the unix group list\n"));
|
||||
SAFE_FREE(*unix_groups);
|
||||
return NT_STATUS_NO_SUCH_USER; /* what should this return value be? */
|
||||
|
||||
gid_t *groups_tmp;
|
||||
|
||||
groups_tmp = Realloc(*unix_groups, sizeof(gid_t) * n_unix_groups);
|
||||
|
||||
if (!groups_tmp) {
|
||||
SAFE_FREE(*unix_groups);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
*unix_groups = groups_tmp;
|
||||
|
||||
if (sys_getgrouplist(username, gid, *unix_groups, &n_unix_groups) == -1) {
|
||||
DEBUG(0, ("get_user_groups: failed to get the unix group list\n"));
|
||||
SAFE_FREE(*unix_groups);
|
||||
return NT_STATUS_NO_SUCH_USER; /* what should this return value be? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_unix_user_token(DBGC_CLASS, 5, uid, gid, n_unix_groups, *unix_groups);
|
||||
|
||||
/* now setup the space for storing the SIDS */
|
||||
|
||||
if (n_unix_groups > 0) {
|
||||
|
||||
*groups = malloc(sizeof(DOM_SID) * n_unix_groups);
|
||||
|
||||
if (!*groups) {
|
||||
DEBUG(0, ("get_user_group_from_local_sam: malloc() failed for DOM_SID list!\n"));
|
||||
DEBUG(0, ("get_user_group: malloc() failed for DOM_SID list!\n"));
|
||||
SAFE_FREE(*unix_groups);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
@ -692,7 +715,8 @@ static NTSTATUS get_user_groups_from_local_sam(const char *username, uid_t uid,
|
||||
|
||||
for (i = 0; i < *n_groups; i++) {
|
||||
if (!NT_STATUS_IS_OK(gid_to_sid(&(*groups)[i], (*unix_groups)[i]))) {
|
||||
DEBUG(1, ("get_user_groups_from_local_sam: failed to convert gid %ld to a sid!\n", (long int)(*unix_groups)[i+1]));
|
||||
DEBUG(1, ("get_user_groups: failed to convert gid %ld to a sid!\n",
|
||||
(long int)(*unix_groups)[i+1]));
|
||||
SAFE_FREE(*groups);
|
||||
SAFE_FREE(*unix_groups);
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
@ -743,10 +767,9 @@ static NTSTATUS add_user_groups(auth_serversupplied_info **server_info,
|
||||
BOOL is_guest;
|
||||
uint32 rid;
|
||||
|
||||
nt_status = get_user_groups_from_local_sam(pdb_get_username(sampass),
|
||||
uid, gid,
|
||||
&n_groupSIDs, &groupSIDs,
|
||||
&unix_groups);
|
||||
nt_status = get_user_groups(pdb_get_username(sampass), uid, gid,
|
||||
&n_groupSIDs, &groupSIDs, &unix_groups);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(4,("get_user_groups_from_local_sam failed\n"));
|
||||
free_server_info(server_info);
|
||||
@ -1068,11 +1091,11 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
|
||||
/* Store the user group information in the server_info
|
||||
returned to the caller. */
|
||||
|
||||
nt_status = get_user_groups_from_local_sam((*server_info)->unix_name,
|
||||
nt_status = get_user_groups((*server_info)->unix_name,
|
||||
uid, gid, &n_lgroupSIDs, &lgroupSIDs, &unix_groups);
|
||||
if ( !NT_STATUS_IS_OK(nt_status) )
|
||||
{
|
||||
DEBUG(4,("get_user_groups_from_local_sam failed\n"));
|
||||
|
||||
if ( !NT_STATUS_IS_OK(nt_status) ) {
|
||||
DEBUG(4,("get_user_groups failed\n"));
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
@ -1080,9 +1103,9 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
|
||||
(*server_info)->n_groups = n_lgroupSIDs;
|
||||
|
||||
/* Create a 'combined' list of all SIDs we might want in the SD */
|
||||
all_group_SIDs = malloc(sizeof(DOM_SID) *
|
||||
(n_lgroupSIDs + info3->num_groups2 +
|
||||
info3->num_other_sids));
|
||||
|
||||
all_group_SIDs = malloc(sizeof(DOM_SID) * (info3->num_groups2 +info3->num_other_sids));
|
||||
|
||||
if (!all_group_SIDs) {
|
||||
DEBUG(0, ("malloc() failed for DOM_SID list!\n"));
|
||||
SAFE_FREE(lgroupSIDs);
|
||||
@ -1090,20 +1113,30 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
#if 0 /* JERRY -- no such thing as local groups in current code */
|
||||
/* Copy the 'local' sids */
|
||||
memcpy(all_group_SIDs, lgroupSIDs, sizeof(DOM_SID) * n_lgroupSIDs);
|
||||
SAFE_FREE(lgroupSIDs);
|
||||
#endif
|
||||
|
||||
/* and create (by appending rids) the 'domain' sids */
|
||||
|
||||
for (i = 0; i < info3->num_groups2; i++) {
|
||||
sid_copy(&all_group_SIDs[i+n_lgroupSIDs], &(info3->dom_sid.sid));
|
||||
if (!sid_append_rid(&all_group_SIDs[i+n_lgroupSIDs], info3->gids[i].g_rid)) {
|
||||
|
||||
sid_copy(&all_group_SIDs[i], &(info3->dom_sid.sid));
|
||||
|
||||
if (!sid_append_rid(&all_group_SIDs[i], info3->gids[i].g_rid)) {
|
||||
|
||||
nt_status = NT_STATUS_INVALID_PARAMETER;
|
||||
|
||||
DEBUG(3,("could not append additional group rid 0x%x\n",
|
||||
info3->gids[i].g_rid));
|
||||
|
||||
SAFE_FREE(lgroupSIDs);
|
||||
free_server_info(server_info);
|
||||
|
||||
return nt_status;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1113,19 +1146,20 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
|
||||
http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
|
||||
*/
|
||||
|
||||
for (i = 0; i < info3->num_other_sids; i++)
|
||||
sid_copy(&all_group_SIDs[
|
||||
n_lgroupSIDs + info3->num_groups2 + i],
|
||||
for (i = 0; i < info3->num_other_sids; i++) {
|
||||
sid_copy(&all_group_SIDs[info3->num_groups2 + i],
|
||||
&info3->other_sids[i].sid);
|
||||
}
|
||||
|
||||
/* Where are the 'global' sids... */
|
||||
|
||||
/* can the user be guest? if yes, where is it stored? */
|
||||
if (!NT_STATUS_IS_OK(
|
||||
nt_status = create_nt_user_token(
|
||||
&user_sid, &group_sid,
|
||||
n_lgroupSIDs + info3->num_groups2 + info3->num_other_sids,
|
||||
all_group_SIDs, False, &token))) {
|
||||
|
||||
nt_status = create_nt_user_token(&user_sid, &group_sid,
|
||||
info3->num_groups2 + info3->num_other_sids,
|
||||
all_group_SIDs, False, &token);
|
||||
|
||||
if ( !NT_STATUS_IS_OK(nt_status) ) {
|
||||
DEBUG(4,("create_nt_user_token failed\n"));
|
||||
SAFE_FREE(all_group_SIDs);
|
||||
free_server_info(server_info);
|
||||
|
@ -264,6 +264,80 @@ static int wb_getgroups(const char *user, gid_t **groups)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Call winbindd to initialise group membership. This is necessary for
|
||||
some systems (i.e RH5.2) that do not have an initgroups function as part
|
||||
of the nss extension. In RH5.2 this is implemented using getgrent()
|
||||
which can be amazingly inefficient as well as having problems with
|
||||
username case. */
|
||||
|
||||
int winbind_initgroups(char *user, gid_t gid)
|
||||
{
|
||||
gid_t *tgr, *groups = NULL;
|
||||
int result;
|
||||
|
||||
/* Call normal initgroups if we are a local user */
|
||||
|
||||
if (!strchr(user, *lp_winbind_separator())) {
|
||||
return initgroups(user, gid);
|
||||
}
|
||||
|
||||
result = wb_getgroups(user, &groups);
|
||||
|
||||
DEBUG(10,("winbind_getgroups: %s: result = %s\n", user,
|
||||
result == -1 ? "FAIL" : "SUCCESS"));
|
||||
|
||||
if (result != -1) {
|
||||
int ngroups = result, i;
|
||||
BOOL is_member = False;
|
||||
|
||||
/* Check to see if the passed gid is already in the list */
|
||||
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
if (groups[i] == gid) {
|
||||
is_member = True;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add group to list if necessary */
|
||||
|
||||
if (!is_member) {
|
||||
tgr = (gid_t *)Realloc(groups, sizeof(gid_t) * ngroups + 1);
|
||||
|
||||
if (!tgr) {
|
||||
errno = ENOMEM;
|
||||
result = -1;
|
||||
goto done;
|
||||
}
|
||||
else groups = tgr;
|
||||
|
||||
groups[ngroups] = gid;
|
||||
ngroups++;
|
||||
}
|
||||
|
||||
/* Set the groups */
|
||||
|
||||
if (sys_setgroups(ngroups, groups) == -1) {
|
||||
errno = EPERM;
|
||||
result = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* The call failed. Set errno to something so we don't get
|
||||
a bogus value from the last failed system call. */
|
||||
|
||||
errno = EIO;
|
||||
}
|
||||
|
||||
/* Free response data if necessary */
|
||||
|
||||
done:
|
||||
SAFE_FREE(groups);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return a list of groups the user is a member of. This function is
|
||||
useful for large systems where inverting the group database would be too
|
||||
time consuming. If size is zero, list is not modified and the total
|
||||
|
@ -199,7 +199,7 @@ BOOL initialise_groups(char *user, uid_t uid, gid_t gid)
|
||||
|
||||
/* Call initgroups() to get user groups */
|
||||
|
||||
if (initgroups(user,gid) == -1) {
|
||||
if (winbind_initgroups(user,gid) == -1) {
|
||||
DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) ));
|
||||
if (getuid() == 0) {
|
||||
if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user