diff options
author | Andrew Tridgell <tridge@samba.org> | 2002-07-23 09:22:29 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2002-07-23 09:22:29 +0000 |
commit | fef9d6187ece53ae12670cc56b360e913e08f3bb (patch) | |
tree | e02543ae6ff6e09e26018abd740566309fea36f5 /source3/lib | |
parent | 5b513407c21e6e77d495fafa49a7a5d380087667 (diff) | |
download | samba-fef9d6187ece53ae12670cc56b360e913e08f3bb.tar.gz samba-fef9d6187ece53ae12670cc56b360e913e08f3bb.tar.bz2 samba-fef9d6187ece53ae12670cc56b360e913e08f3bb.zip |
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 used to be commit 44e92b6523ca2c119c2562df22eb71138dca9d9d)
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/replace.c | 66 | ||||
-rw-r--r-- | source3/lib/util_getent.c | 56 |
2 files changed, 101 insertions, 21 deletions
diff --git a/source3/lib/replace.c b/source3/lib/replace.c index 2cc7d48adb..e2664accfa 100644 --- a/source3/lib/replace.c +++ b/source3/lib/replace.c @@ -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 diff --git a/source3/lib/util_getent.c b/source3/lib/util_getent.c index 2e76121aae..5d2fcd7652 100644 --- a/source3/lib/util_getent.c +++ b/source3/lib/util_getent.c @@ -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; +} |