2002-08-17 11:09:22 +04:00
/*
Unix SMB / CIFS implementation .
system call wrapper interface .
Copyright ( C ) Andrew Tridgell 2002
Copyright ( C ) Andrew Barteltt 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 Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
This file may assume linkage with smbd - for things like become_root ( )
etc .
*/
# include "includes.h"
# 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 !
*/
static int getgrouplist_internals ( const char * user , gid_t gid , gid_t * groups , int * grpcnt )
{
gid_t * gids_saved ;
2003-02-19 15:31:16 +03:00
int ret , ngrp_saved , num_gids ;
2002-08-17 11:09:22 +04:00
2002-09-25 19:19:00 +04:00
if ( non_root_mode ( ) ) {
* grpcnt = 0 ;
return 0 ;
}
2002-08-17 11:09:22 +04:00
/* 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 ) {
2002-09-25 19:19:00 +04:00
SAFE_FREE ( gids_saved ) ;
2002-08-17 11:09:22 +04:00
/* very strange! */
return - 1 ;
}
if ( initgroups ( user , gid ) ! = 0 ) {
2002-09-25 19:19:00 +04:00
DEBUG ( 0 , ( " getgrouplist_internals: initgroups() failed! \n " ) ) ;
SAFE_FREE ( gids_saved ) ;
2002-08-17 11:09:22 +04:00
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 ) ;
2003-02-19 15:31:16 +03:00
num_gids = getgroups ( 0 , NULL ) ;
if ( num_gids + 1 > * grpcnt ) {
* grpcnt = num_gids + 1 ;
ret = - 1 ;
} else {
ret = getgroups ( * grpcnt - 1 , & groups [ 1 ] ) ;
if ( ret > = 0 ) {
groups [ 0 ] = gid ;
* grpcnt = ret + 1 ;
}
2002-08-17 11:09:22 +04:00
}
restore_re_gid ( ) ;
if ( setgroups ( ngrp_saved , gids_saved ) ! = 0 ) {
/* yikes! */
DEBUG ( 0 , ( " ERROR: getgrouplist: failed to reset group list! \n " ) ) ;
smb_panic ( " getgrouplist: failed to reset group list! \n " ) ;
free ( gids_saved ) ;
return - 1 ;
}
free ( gids_saved ) ;
return ret ;
}
# endif
int sys_getgrouplist ( const char * user , gid_t gid , gid_t * groups , int * grpcnt )
{
# ifdef HAVE_GETGROUPLIST
return getgrouplist ( user , gid , groups , grpcnt ) ;
# else
int retval ;
become_root ( ) ;
retval = getgrouplist_internals ( user , gid , groups , grpcnt ) ;
unbecome_root ( ) ;
2002-09-25 19:19:00 +04:00
return retval ;
2002-08-17 11:09:22 +04:00
# endif
}