mirror of
https://github.com/samba-team/samba.git
synced 2025-03-08 04:58:40 +03:00
implemented getgrouplist() for systems that don't have it and use it
in get_alias_user_groups(). The old method used getgrent() which is extremely slow when the number of groups is large
This commit is contained in:
parent
88f0e68bc6
commit
44e92b6523
@ -746,7 +746,7 @@ AC_CHECK_FUNCS(setpriv setgidx setuidx setgroups sysconf mktime rename ftruncate
|
||||
AC_CHECK_FUNCS(lstat64 fopen64 atexit grantpt dup2 lseek64 ftruncate64 readdir64)
|
||||
AC_CHECK_FUNCS(fseek64 fseeko64 ftell64 ftello64 setluid getpwanam setlinebuf)
|
||||
AC_CHECK_FUNCS(srandom random srand rand setenv usleep strcasecmp fcvt fcvtl symlink readlink)
|
||||
AC_CHECK_FUNCS(syslog vsyslog)
|
||||
AC_CHECK_FUNCS(syslog vsyslog getgrouplist)
|
||||
# setbuffer is needed for smbtorture
|
||||
AC_CHECK_FUNCS(setbuffer)
|
||||
|
||||
|
@ -428,3 +428,69 @@ char *rep_inet_ntoa(struct in_addr ip)
|
||||
}
|
||||
#endif /* HAVE_SYSLOG */
|
||||
#endif /* HAVE_VSYSLOG */
|
||||
|
||||
|
||||
#ifndef HAVE_GETGROUPLIST
|
||||
/*
|
||||
This is a *much* faster way of getting the list of groups for a user
|
||||
without changing the current supplemenrary group list. The old
|
||||
method used getgrent() which could take 20 minutes on a really big
|
||||
network with hundeds of thousands of groups and users. The new method
|
||||
takes a couple of seconds.
|
||||
|
||||
NOTE!! this function only works if it is called as root!
|
||||
*/
|
||||
int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
|
||||
{
|
||||
gid_t *gids_saved;
|
||||
int ret, ngrp_saved;
|
||||
|
||||
/* work out how many groups we need to save */
|
||||
ngrp_saved = getgroups(0, NULL);
|
||||
if (ngrp_saved == -1) {
|
||||
/* this shouldn't happen */
|
||||
return -1;
|
||||
}
|
||||
|
||||
gids_saved = (gid_t *)malloc(sizeof(gid_t) * (ngrp_saved+1));
|
||||
if (!gids_saved) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngrp_saved = getgroups(ngrp_saved, gids_saved);
|
||||
if (ngrp_saved == -1) {
|
||||
free(gids_saved);
|
||||
/* very strange! */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (initgroups(user, gid) != 0) {
|
||||
free(gids_saved);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* this must be done to cope with systems that put the current egid in the
|
||||
return from getgroups() */
|
||||
save_re_gid();
|
||||
set_effective_gid(gid);
|
||||
setgid(gid);
|
||||
|
||||
ret = getgroups(*grpcnt, groups);
|
||||
if (ret >= 0) {
|
||||
*grpcnt = ret;
|
||||
}
|
||||
|
||||
restore_re_gid();
|
||||
|
||||
if (setgroups(ngrp_saved, gids_saved) != 0) {
|
||||
/* yikes! */
|
||||
DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
|
||||
free(gids_saved);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(gids_saved);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
@ -21,27 +21,6 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#if 0
|
||||
static void print_grent_list(struct sys_grent *glist)
|
||||
{
|
||||
DEBUG(100, ("print_grent_list: %x\n", glist ));
|
||||
while (glist) {
|
||||
DEBUG(100,("glist: %x ", glist));
|
||||
if (glist->gr_name)
|
||||
DEBUG(100,(": gr_name = (%x) %s ", glist->gr_name, glist->gr_name));
|
||||
if (glist->gr_passwd)
|
||||
DEBUG(100,(": gr_passwd = (%x) %s ", glist->gr_passwd, glist->gr_passwd));
|
||||
if (glist->gr_mem) {
|
||||
int i;
|
||||
for (i = 0; glist->gr_mem[i]; i++)
|
||||
DEBUG(100,(" : gr_mem[%d] = (%x) %s ", i, glist->gr_mem[i], glist->gr_mem[i]));
|
||||
}
|
||||
DEBUG(100,(": gr_next = %x\n", glist->next ));
|
||||
glist = glist->next;
|
||||
}
|
||||
DEBUG(100,("FINISHED !\n\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************
|
||||
Returns a single linked list of group entries.
|
||||
@ -320,3 +299,38 @@ void free_userlist(struct sys_userlist *list_head)
|
||||
SAFE_FREE(old_head);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
return a full list of groups for a user
|
||||
|
||||
returns the number of groups the user is a member of. The return will include the
|
||||
users primary group.
|
||||
|
||||
remember to free the resulting gid_t array
|
||||
|
||||
NOTE! you must be root to call this function on some systems
|
||||
*/
|
||||
int getgroups_user(const char *user, gid_t **groups)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
int ngrp, max_grp;
|
||||
|
||||
pwd = getpwnam(user);
|
||||
if (!pwd) return -1;
|
||||
|
||||
max_grp = groups_max();
|
||||
(*groups) = (gid_t *)malloc(sizeof(gid_t) * max_grp);
|
||||
if (! *groups) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngrp = getgrouplist(user, pwd->pw_gid, *groups, &max_grp);
|
||||
if (ngrp <= 0) {
|
||||
free(*groups);
|
||||
return ngrp;
|
||||
}
|
||||
|
||||
return ngrp;
|
||||
}
|
||||
|
@ -84,10 +84,10 @@ rid_name domain_group_rids[] =
|
||||
NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, uint32 **prids, DOM_SID *q_sid)
|
||||
{
|
||||
SAM_ACCOUNT *sam_pass=NULL;
|
||||
struct sys_grent *glist;
|
||||
struct sys_grent *grp;
|
||||
int i, num, cur_rid=0;
|
||||
int i, cur_rid=0;
|
||||
gid_t gid;
|
||||
gid_t *groups = NULL;
|
||||
int num_groups;
|
||||
GROUP_MAP map;
|
||||
DOM_SID tmp_sid;
|
||||
fstring user_name;
|
||||
@ -130,16 +130,21 @@ NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, ui
|
||||
fstrcpy(user_name, pdb_get_username(sam_pass));
|
||||
grid=pdb_get_group_rid(sam_pass);
|
||||
gid=pdb_get_gid(sam_pass);
|
||||
|
||||
grp = glist = getgrent_list();
|
||||
if (grp == NULL) {
|
||||
|
||||
become_root();
|
||||
/* on some systems this must run as root */
|
||||
num_groups = getgroups_user(user_name, &groups);
|
||||
unbecome_root();
|
||||
if (num_groups == -1) {
|
||||
/* this should never happen */
|
||||
DEBUG(2,("get_alias_user_groups: getgroups_user failed\n"));
|
||||
pdb_free_sam(&sam_pass);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
for (; grp != NULL; grp = grp->next) {
|
||||
if(!get_group_from_gid(grp->gr_gid, &map, MAPPING_WITHOUT_PRIV)) {
|
||||
DEBUG(10,("get_alias_user_groups: gid %d. not found\n", (int)grp->gr_gid));
|
||||
|
||||
for (i=0;i<num_groups;i++) {
|
||||
if(!get_group_from_gid(groups[i], &map, MAPPING_WITHOUT_PRIV)) {
|
||||
DEBUG(10,("get_alias_user_groups: gid %d. not found\n", (int)groups[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -159,7 +164,7 @@ NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, ui
|
||||
}
|
||||
|
||||
/* Don't return winbind groups as they are not local! */
|
||||
if (winbind_groups_exist && (grp->gr_gid >= winbind_gid_low) && (grp->gr_gid <= winbind_gid_high)) {
|
||||
if (winbind_groups_exist && (groups[i] >= winbind_gid_low) && (groups[i] <= winbind_gid_high)) {
|
||||
DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name));
|
||||
continue;
|
||||
}
|
||||
@ -170,30 +175,21 @@ NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, ui
|
||||
continue;
|
||||
}
|
||||
|
||||
/* the group is fine, we can check if there is the user we're looking for */
|
||||
DEBUG(10,("get_alias_user_groups: checking if the user is a member of %s.\n", map.nt_name));
|
||||
|
||||
for(num=0; grp->gr_mem[num]!=NULL; num++) {
|
||||
if(strcmp(grp->gr_mem[num], user_name)==0) {
|
||||
/* we found the user, add the group to the list */
|
||||
|
||||
new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
|
||||
if (new_rids==NULL) {
|
||||
DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
|
||||
pdb_free_sam(&sam_pass);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
rids=new_rids;
|
||||
|
||||
sid_peek_rid(&map.sid, &(rids[cur_rid]));
|
||||
DEBUG(10,("get_alias_user_groups: user found in group %s\n", map.nt_name));
|
||||
cur_rid++;
|
||||
break;
|
||||
}
|
||||
new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
|
||||
if (new_rids==NULL) {
|
||||
DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
|
||||
pdb_free_sam(&sam_pass);
|
||||
free(groups);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
rids=new_rids;
|
||||
|
||||
sid_peek_rid(&map.sid, &(rids[cur_rid]));
|
||||
cur_rid++;
|
||||
break;
|
||||
}
|
||||
|
||||
grent_free(glist);
|
||||
free(groups);
|
||||
|
||||
/* now check for the user's gid (the primary group rid) */
|
||||
for (i=0; i<cur_rid && grid!=rids[i]; i++)
|
||||
|
Loading…
x
Reference in New Issue
Block a user