2008-12-16 11:30:16 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-05-09 15:43:00 +04:00
winbind client common code
Copyright ( C ) Tim Potter 2000
Copyright ( C ) Andrew Tridgell 2000
2002-09-25 19:19:00 +04:00
Copyright ( C ) Andrew Bartlett 2002
2008-12-16 11:30:16 +03:00
2000-05-09 15:43:00 +04:00
This library is free software ; you can redistribute it and / or
2007-07-10 08:04:46 +04:00
modify it under the terms of the GNU Lesser General Public
2000-05-09 15:43:00 +04:00
License as published by the Free Software Foundation ; either
2007-07-10 06:31:50 +04:00
version 3 of the License , or ( at your option ) any later version .
2008-12-16 11:30:16 +03:00
2000-05-09 15:43:00 +04:00
This library 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
Library General Public License for more details .
2008-12-16 11:30:16 +03:00
2007-07-10 08:04:46 +04:00
You should have received a copy of the GNU Lesser General Public License
2007-07-10 06:31:50 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-05-09 15:43:00 +04:00
*/
2011-02-18 15:57:35 +03:00
# include "replace.h"
# include "system/select.h"
2002-12-20 04:37:39 +03:00
# include "winbind_client.h"
2000-05-09 15:43:00 +04:00
/* Global variables. These are effectively the client state information */
2001-12-22 03:51:32 +03:00
int winbindd_fd = - 1 ; /* fd for winbindd socket */
2007-03-23 00:41:36 +03:00
static int is_privileged = 0 ;
2001-07-10 06:28:17 +04:00
2001-12-22 03:51:32 +03:00
/* Free a response structure */
2007-09-14 11:07:59 +04:00
void winbindd_free_response ( struct winbindd_response * response )
2001-12-22 03:51:32 +03:00
{
/* Free any allocated extra_data */
if ( response )
2006-04-12 18:10:39 +04:00
SAFE_FREE ( response - > extra_data . data ) ;
2001-12-22 03:51:32 +03:00
}
2000-07-17 06:37:11 +04:00
/* Initialise a request structure */
2000-05-09 15:43:00 +04:00
2010-01-23 20:06:53 +03:00
static void winbindd_init_request ( struct winbindd_request * request ,
int request_type )
2000-05-09 15:43:00 +04:00
{
2002-01-11 02:45:29 +03:00
request - > length = sizeof ( struct winbindd_request ) ;
2001-08-25 00:32:01 +04:00
request - > cmd = ( enum winbindd_cmd ) request_type ;
2000-07-17 06:37:11 +04:00
request - > pid = getpid ( ) ;
2000-05-09 15:43:00 +04:00
}
2000-07-17 06:37:11 +04:00
/* Initialise a response structure */
2006-12-20 04:10:04 +03:00
static void init_response ( struct winbindd_response * response )
2000-07-17 06:37:11 +04:00
{
/* Initialise return value */
2001-04-25 09:47:50 +04:00
response - > result = WINBINDD_ERROR ;
2000-07-17 06:37:11 +04:00
}
2000-05-09 15:43:00 +04:00
/* Close established socket */
2010-05-10 14:05:01 +04:00
# if HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR
__attribute__ ( ( destructor ) )
# endif
2010-01-23 20:06:53 +03:00
static void winbind_close_sock ( void )
2000-05-09 15:43:00 +04:00
{
2001-12-22 03:51:32 +03:00
if ( winbindd_fd ! = - 1 ) {
close ( winbindd_fd ) ;
winbindd_fd = - 1 ;
2000-06-30 10:48:47 +04:00
}
2000-05-09 15:43:00 +04:00
}
2004-05-12 02:09:09 +04:00
# define CONNECT_TIMEOUT 30
2002-09-25 19:19:00 +04:00
/* Make sure socket handle isn't stdin, stdout or stderr */
# define RECURSION_LIMIT 3
2008-12-16 11:30:16 +03:00
static int make_nonstd_fd_internals ( int fd , int limit /* Recursion limiter */ )
2002-09-25 19:19:00 +04:00
{
int new_fd ;
if ( fd > = 0 & & fd < = 2 ) {
2008-12-16 11:30:16 +03:00
# ifdef F_DUPFD
2002-09-25 19:19:00 +04:00
if ( ( new_fd = fcntl ( fd , F_DUPFD , 3 ) ) = = - 1 ) {
return - 1 ;
}
2003-10-21 08:38:23 +04:00
/* Paranoia */
2002-09-25 19:19:00 +04:00
if ( new_fd < 3 ) {
close ( new_fd ) ;
return - 1 ;
}
close ( fd ) ;
return new_fd ;
# else
if ( limit < = 0 )
return - 1 ;
2008-12-16 11:30:16 +03:00
2002-09-25 19:19:00 +04:00
new_fd = dup ( fd ) ;
2008-12-16 11:30:16 +03:00
if ( new_fd = = - 1 )
2002-09-25 19:19:00 +04:00
return - 1 ;
/* use the program stack to hold our list of FDs to close */
new_fd = make_nonstd_fd_internals ( new_fd , limit - 1 ) ;
close ( fd ) ;
return new_fd ;
# endif
}
return fd ;
}
2004-05-12 02:09:09 +04:00
/****************************************************************************
Set a fd into blocking / nonblocking mode . Uses POSIX O_NONBLOCK if available ,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
Set close on exec also .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-16 11:30:16 +03:00
static int make_safe_fd ( int fd )
2002-09-25 19:19:00 +04:00
{
int result , flags ;
int new_fd = make_nonstd_fd_internals ( fd , RECURSION_LIMIT ) ;
if ( new_fd = = - 1 ) {
close ( fd ) ;
return - 1 ;
}
2004-05-12 02:09:09 +04:00
/* Socket should be nonblocking. */
# ifdef O_NONBLOCK
# define FLAG_TO_SET O_NONBLOCK
# else
# ifdef SYSV
# define FLAG_TO_SET O_NDELAY
# else /* BSD */
# define FLAG_TO_SET FNDELAY
# endif
# endif
if ( ( flags = fcntl ( new_fd , F_GETFL ) ) = = - 1 ) {
close ( new_fd ) ;
return - 1 ;
}
flags | = FLAG_TO_SET ;
if ( fcntl ( new_fd , F_SETFL , flags ) = = - 1 ) {
close ( new_fd ) ;
return - 1 ;
}
# undef FLAG_TO_SET
2002-09-25 19:19:00 +04:00
/* Socket should be closed on exec() */
# ifdef FD_CLOEXEC
result = flags = fcntl ( new_fd , F_GETFD , 0 ) ;
if ( flags > = 0 ) {
flags | = FD_CLOEXEC ;
result = fcntl ( new_fd , F_SETFD , flags ) ;
}
if ( result < 0 ) {
close ( new_fd ) ;
return - 1 ;
}
# endif
return new_fd ;
}
2000-05-09 15:43:00 +04:00
/* Connect to winbindd socket */
2003-03-24 12:54:13 +03:00
static int winbind_named_pipe_sock ( const char * dir )
2000-05-09 15:43:00 +04:00
{
2000-06-30 10:48:47 +04:00
struct sockaddr_un sunaddr ;
struct stat st ;
2007-11-27 04:24:56 +03:00
char * path = NULL ;
2002-09-25 19:19:00 +04:00
int fd ;
2004-05-12 02:09:09 +04:00
int wait_time ;
int slept ;
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* Check permissions on unix socket directory */
2007-11-27 04:24:56 +03:00
2003-03-24 12:54:13 +03:00
if ( lstat ( dir , & st ) = = - 1 ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
if ( ! S_ISDIR ( st . st_mode ) | |
2001-07-08 22:25:19 +04:00
( st . st_uid ! = 0 & & st . st_uid ! = geteuid ( ) ) ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* Connect to socket */
2007-11-27 04:24:56 +03:00
if ( asprintf ( & path , " %s/%s " , dir , WINBINDD_SOCKET_NAME ) < 0 ) {
return - 1 ;
}
2000-06-30 10:48:47 +04:00
ZERO_STRUCT ( sunaddr ) ;
sunaddr . sun_family = AF_UNIX ;
strncpy ( sunaddr . sun_path , path , sizeof ( sunaddr . sun_path ) - 1 ) ;
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* If socket file doesn't exist, don't bother trying to connect
with retry . This is an attempt to make the system usable when
the winbindd daemon is not running . */
2000-05-09 15:43:00 +04:00
2000-06-30 10:48:47 +04:00
if ( lstat ( path , & st ) = = - 1 ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2007-11-27 04:24:56 +03:00
SAFE_FREE ( path ) ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
SAFE_FREE ( path ) ;
2000-06-30 10:48:47 +04:00
/* Check permissions on unix socket file */
2007-11-27 04:24:56 +03:00
if ( ! S_ISSOCK ( st . st_mode ) | |
2001-07-08 22:25:19 +04:00
( st . st_uid ! = 0 & & st . st_uid ! = geteuid ( ) ) ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* Connect to socket */
2007-11-27 04:24:56 +03:00
2002-09-25 19:19:00 +04:00
if ( ( fd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ) = = - 1 ) {
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2002-09-25 19:19:00 +04:00
2004-05-12 02:09:09 +04:00
/* Set socket non-blocking and close on exec. */
2003-03-24 12:54:13 +03:00
if ( ( fd = make_safe_fd ( fd ) ) = = - 1 ) {
return fd ;
2002-09-25 19:19:00 +04:00
}
2004-05-12 02:09:09 +04:00
for ( wait_time = 0 ; connect ( fd , ( struct sockaddr * ) & sunaddr , sizeof ( sunaddr ) ) = = - 1 ;
wait_time + = slept ) {
2011-02-18 15:57:35 +03:00
struct pollfd pfd ;
2004-05-12 02:09:09 +04:00
int ret ;
2005-10-18 07:24:00 +04:00
int connect_errno = 0 ;
socklen_t errnosize ;
2004-05-12 02:09:09 +04:00
if ( wait_time > = CONNECT_TIMEOUT )
goto error_out ;
switch ( errno ) {
case EINPROGRESS :
2011-02-18 15:57:35 +03:00
pfd . fd = fd ;
pfd . events = POLLOUT ;
2004-05-12 02:09:09 +04:00
2011-02-18 15:57:35 +03:00
ret = poll ( & pfd , 1 , ( CONNECT_TIMEOUT - wait_time ) * 1000 ) ;
2004-05-12 02:09:09 +04:00
if ( ret > 0 ) {
errnosize = sizeof ( connect_errno ) ;
ret = getsockopt ( fd , SOL_SOCKET ,
SO_ERROR , & connect_errno , & errnosize ) ;
if ( ret > = 0 & & connect_errno = = 0 ) {
/* Connect succeed */
goto out ;
}
}
slept = CONNECT_TIMEOUT ;
break ;
case EAGAIN :
slept = rand ( ) % 3 + 1 ;
sleep ( slept ) ;
break ;
default :
goto error_out ;
}
}
out :
return fd ;
error_out :
close ( fd ) ;
return - 1 ;
2003-03-24 12:54:13 +03:00
}
2007-09-15 22:55:04 +04:00
static const char * winbindd_socket_dir ( void )
{
# ifdef SOCKET_WRAPPER
const char * env_dir ;
env_dir = getenv ( WINBINDD_SOCKET_DIR_ENVVAR ) ;
if ( env_dir ) {
return env_dir ;
}
# endif
return WINBINDD_SOCKET_DIR ;
}
2003-03-24 12:54:13 +03:00
/* Connect to winbindd socket */
2007-03-23 00:41:36 +03:00
static int winbind_open_pipe_sock ( int recursing , int need_priv )
2003-03-24 12:54:13 +03:00
{
# ifdef HAVE_UNIXSOCKET
static pid_t our_pid ;
struct winbindd_request request ;
struct winbindd_response response ;
ZERO_STRUCT ( request ) ;
ZERO_STRUCT ( response ) ;
if ( our_pid ! = getpid ( ) ) {
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2003-03-24 12:54:13 +03:00
our_pid = getpid ( ) ;
}
2007-03-23 00:41:36 +03:00
if ( ( need_priv ! = 0 ) & & ( is_privileged = = 0 ) ) {
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2007-03-23 00:41:36 +03:00
}
2008-10-28 09:36:36 +03:00
2003-03-24 12:54:13 +03:00
if ( winbindd_fd ! = - 1 ) {
return winbindd_fd ;
}
2005-09-19 22:49:18 +04:00
if ( recursing ) {
return - 1 ;
}
2007-09-15 22:55:04 +04:00
if ( ( winbindd_fd = winbind_named_pipe_sock ( winbindd_socket_dir ( ) ) ) = = - 1 ) {
2003-03-24 12:54:13 +03:00
return - 1 ;
}
2007-03-23 00:41:36 +03:00
is_privileged = 0 ;
2003-03-24 12:54:13 +03:00
/* version-check the socket */
2007-08-28 19:16:42 +04:00
request . wb_flags = WBFLAG_RECURSE ;
2005-06-25 00:25:18 +04:00
if ( ( winbindd_request_response ( WINBINDD_INTERFACE_VERSION , & request , & response ) ! = NSS_STATUS_SUCCESS ) | | ( response . data . interface_version ! = WINBIND_INTERFACE_VERSION ) ) {
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2003-03-24 12:54:13 +03:00
return - 1 ;
}
/* try and get priv pipe */
2007-08-28 19:16:42 +04:00
request . wb_flags = WBFLAG_RECURSE ;
2005-06-25 00:25:18 +04:00
if ( winbindd_request_response ( WINBINDD_PRIV_PIPE_DIR , & request , & response ) = = NSS_STATUS_SUCCESS ) {
2003-03-24 12:54:13 +03:00
int fd ;
2006-08-01 00:51:55 +04:00
if ( ( fd = winbind_named_pipe_sock ( ( char * ) response . extra_data . data ) ) ! = - 1 ) {
2003-03-24 12:54:13 +03:00
close ( winbindd_fd ) ;
winbindd_fd = fd ;
2007-03-23 00:41:36 +03:00
is_privileged = 1 ;
2003-03-24 12:54:13 +03:00
}
}
2007-03-23 00:41:36 +03:00
if ( ( need_priv ! = 0 ) & & ( is_privileged = = 0 ) ) {
return - 1 ;
}
2006-04-12 18:10:39 +04:00
SAFE_FREE ( response . extra_data . data ) ;
2003-08-01 11:46:42 +04:00
2001-12-22 03:51:32 +03:00
return winbindd_fd ;
2002-09-25 19:19:00 +04:00
# else
return - 1 ;
# endif /* HAVE_UNIXSOCKET */
2000-05-09 15:43:00 +04:00
}
2002-07-15 14:35:28 +04:00
/* Write data to winbindd socket */
2000-05-09 15:43:00 +04:00
2010-01-23 20:06:53 +03:00
static int winbind_write_sock ( void * buffer , int count , int recursing ,
int need_priv )
2000-05-09 15:43:00 +04:00
{
2000-06-30 10:48:47 +04:00
int result , nwritten ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Open connection to winbind daemon */
2008-12-16 11:30:16 +03:00
2000-05-09 15:43:00 +04:00
restart :
2008-12-16 11:30:16 +03:00
2007-03-23 00:41:36 +03:00
if ( winbind_open_pipe_sock ( recursing , need_priv ) = = - 1 ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Write data to socket */
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
nwritten = 0 ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
while ( nwritten < count ) {
2011-02-18 15:57:35 +03:00
struct pollfd pfd ;
int ret ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Catch pipe close on other end by checking if a read()
2011-02-18 15:57:35 +03:00
call would not block by calling poll ( ) . */
2000-06-30 10:48:47 +04:00
2011-02-18 15:57:35 +03:00
pfd . fd = winbindd_fd ;
pfd . events = POLLIN | POLLHUP ;
2008-12-16 11:30:16 +03:00
2011-02-18 15:57:35 +03:00
ret = poll ( & pfd , 1 , 0 ) ;
if ( ret = = - 1 ) {
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2011-02-18 15:57:35 +03:00
return - 1 ; /* poll error */
2000-06-30 10:48:47 +04:00
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Write should be OK if fd not available for reading */
2008-12-16 11:30:16 +03:00
2011-02-18 15:57:35 +03:00
if ( ( ret = = 1 ) & & ( pfd . revents & ( POLLIN | POLLHUP | POLLERR ) ) ) {
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
/* Pipe has closed on remote end */
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
winbind_close_sock ( ) ;
goto restart ;
}
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
/* Do the write */
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
result = write ( winbindd_fd ,
( char * ) buffer + nwritten ,
count - nwritten ) ;
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
if ( ( result = = - 1 ) | | ( result = = 0 ) ) {
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
/* Write failed */
2008-12-16 11:30:16 +03:00
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2011-02-10 16:59:39 +03:00
return - 1 ;
2000-06-30 10:48:47 +04:00
}
2011-02-10 16:59:39 +03:00
nwritten + = result ;
2000-06-30 10:48:47 +04:00
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
return nwritten ;
2000-05-09 15:43:00 +04:00
}
2002-07-15 14:35:28 +04:00
/* Read data from winbindd socket */
2000-05-09 15:43:00 +04:00
2010-01-23 20:06:53 +03:00
static int winbind_read_sock ( void * buffer , int count )
2000-05-09 15:43:00 +04:00
{
2007-08-22 17:51:44 +04:00
int nread = 0 ;
2011-02-18 15:57:35 +03:00
int total_time = 0 ;
2000-05-09 15:43:00 +04:00
2006-03-29 22:55:39 +04:00
if ( winbindd_fd = = - 1 ) {
return - 1 ;
}
2000-06-30 10:48:47 +04:00
/* Read data from socket */
while ( nread < count ) {
2011-02-18 15:57:35 +03:00
struct pollfd pfd ;
int ret ;
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
/* Catch pipe close on other end by checking if a read()
2011-02-18 15:57:35 +03:00
call would not block by calling poll ( ) . */
pfd . fd = winbindd_fd ;
pfd . events = POLLIN | POLLHUP ;
2004-05-13 22:37:54 +04:00
/* Wait for 5 seconds for a reply. May need to parameterise this... */
2011-02-18 15:57:35 +03:00
ret = poll ( & pfd , 1 , 5000 ) ;
if ( ret = = - 1 ) {
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2011-02-18 15:57:35 +03:00
return - 1 ; /* poll error */
2004-05-13 22:37:54 +04:00
}
2008-12-16 11:30:16 +03:00
2011-02-18 15:57:35 +03:00
if ( ret = = 0 ) {
2004-05-13 22:37:54 +04:00
/* Not ready for read yet... */
if ( total_time > = 30 ) {
/* Timeout */
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2004-05-13 22:37:54 +04:00
return - 1 ;
}
total_time + = 5 ;
continue ;
}
2011-02-18 15:57:35 +03:00
if ( ( ret = = 1 ) & & ( pfd . revents & ( POLLIN | POLLHUP | POLLERR ) ) ) {
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
/* Do the Read */
2008-12-16 11:30:16 +03:00
int result = read ( winbindd_fd , ( char * ) buffer + nread ,
2004-05-13 22:37:54 +04:00
count - nread ) ;
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
if ( ( result = = - 1 ) | | ( result = = 0 ) ) {
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
/* Read failed. I think the only useful thing we
can do here is just return - 1 and fail since the
transaction has failed half way through . */
2008-12-16 11:30:16 +03:00
2007-09-14 11:07:59 +04:00
winbind_close_sock ( ) ;
2004-05-13 22:37:54 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
nread + = result ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
}
}
2008-12-16 11:30:16 +03:00
2007-08-22 17:51:44 +04:00
return nread ;
2000-05-09 15:43:00 +04:00
}
/* Read reply */
2010-01-23 20:06:53 +03:00
static int winbindd_read_reply ( struct winbindd_response * response )
2000-05-09 15:43:00 +04:00
{
2000-06-30 10:48:47 +04:00
int result1 , result2 = 0 ;
2000-05-09 15:43:00 +04:00
2000-06-30 10:48:47 +04:00
if ( ! response ) {
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Read fixed length response */
2008-12-16 11:30:16 +03:00
2007-09-14 11:07:59 +04:00
result1 = winbind_read_sock ( response ,
sizeof ( struct winbindd_response ) ) ;
if ( result1 = = - 1 ) {
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2011-03-09 12:58:47 +03:00
if ( response - > length < sizeof ( struct winbindd_response ) ) {
return - 1 ;
}
2000-06-30 10:48:47 +04:00
/* We actually send the pointer value of the extra_data field from
the server . This has no meaning in the client ' s address space
so we clear it out . */
2000-05-09 15:43:00 +04:00
2006-04-12 18:10:39 +04:00
response - > extra_data . data = NULL ;
2000-05-09 15:43:00 +04:00
2000-06-30 10:48:47 +04:00
/* Read variable length response */
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
if ( response - > length > sizeof ( struct winbindd_response ) ) {
2008-12-16 11:30:16 +03:00
int extra_data_len = response - > length -
2000-06-30 10:48:47 +04:00
sizeof ( struct winbindd_response ) ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Mallocate memory for extra data */
2008-12-16 11:30:16 +03:00
2007-02-16 23:02:13 +03:00
if ( ! ( response - > extra_data . data = malloc ( extra_data_len ) ) ) {
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2007-09-14 11:07:59 +04:00
result2 = winbind_read_sock ( response - > extra_data . data ,
extra_data_len ) ;
if ( result2 = = - 1 ) {
winbindd_free_response ( response ) ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Return total amount of data read */
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
return result1 + result2 ;
2000-05-09 15:43:00 +04:00
}
2008-12-16 11:30:16 +03:00
/*
* send simple types of requests
2001-12-22 03:51:32 +03:00
*/
2000-06-14 13:58:12 +04:00
2007-03-23 00:41:36 +03:00
NSS_STATUS winbindd_send_request ( int req_type , int need_priv ,
struct winbindd_request * request )
2000-06-14 13:58:12 +04:00
{
struct winbindd_request lrequest ;
2006-10-20 02:34:58 +04:00
2000-06-14 13:58:12 +04:00
/* Check for our tricky environment variable */
2006-10-20 02:34:58 +04:00
if ( winbind_env_set ( ) ) {
return NSS_STATUS_NOTFOUND ;
2000-06-14 13:58:12 +04:00
}
2000-06-30 10:48:47 +04:00
if ( ! request ) {
ZERO_STRUCT ( lrequest ) ;
request = & lrequest ;
}
2008-12-16 11:30:16 +03:00
2000-06-14 13:58:12 +04:00
/* Fill in request and send down pipe */
2000-07-17 06:37:11 +04:00
2007-09-14 11:07:59 +04:00
winbindd_init_request ( request , req_type ) ;
2008-12-16 11:30:16 +03:00
2007-09-14 11:07:59 +04:00
if ( winbind_write_sock ( request , sizeof ( * request ) ,
request - > wb_flags & WBFLAG_RECURSE ,
2008-12-16 11:30:16 +03:00
need_priv ) = = - 1 )
2008-08-20 22:00:40 +04:00
{
/* Set ENOENT for consistency. Required by some apps */
errno = ENOENT ;
2008-12-16 11:30:16 +03:00
2000-06-14 13:58:12 +04:00
return NSS_STATUS_UNAVAIL ;
}
2005-09-30 21:13:37 +04:00
if ( ( request - > extra_len ! = 0 ) & &
2007-09-14 11:07:59 +04:00
( winbind_write_sock ( request - > extra_data . data ,
2008-12-16 11:30:16 +03:00
request - > extra_len ,
2007-09-14 11:07:59 +04:00
request - > wb_flags & WBFLAG_RECURSE ,
2008-12-16 11:30:16 +03:00
need_priv ) = = - 1 ) )
2008-08-20 22:00:40 +04:00
{
/* Set ENOENT for consistency. Required by some apps */
errno = ENOENT ;
2005-09-30 21:13:37 +04:00
return NSS_STATUS_UNAVAIL ;
}
2008-12-16 11:30:16 +03:00
2001-12-22 03:51:32 +03:00
return NSS_STATUS_SUCCESS ;
}
/*
* Get results from winbindd request
*/
NSS_STATUS winbindd_get_response ( struct winbindd_response * response )
{
struct winbindd_response lresponse ;
if ( ! response ) {
ZERO_STRUCT ( lresponse ) ;
response = & lresponse ;
}
init_response ( response ) ;
2000-06-14 13:58:12 +04:00
/* Wait for reply */
2007-09-14 11:07:59 +04:00
if ( winbindd_read_reply ( response ) = = - 1 ) {
2008-08-20 22:00:40 +04:00
/* Set ENOENT for consistency. Required by some apps */
errno = ENOENT ;
2000-06-14 13:58:12 +04:00
return NSS_STATUS_UNAVAIL ;
}
/* Throw away extra data if client didn't request it */
if ( response = = & lresponse ) {
2007-09-14 11:07:59 +04:00
winbindd_free_response ( response ) ;
2000-06-14 13:58:12 +04:00
}
/* Copy reply data from socket */
if ( response - > result ! = WINBINDD_OK ) {
return NSS_STATUS_NOTFOUND ;
}
2008-12-16 11:30:16 +03:00
2000-06-14 13:58:12 +04:00
return NSS_STATUS_SUCCESS ;
}
2001-12-22 03:51:32 +03:00
/* Handle simple types of requests */
2008-12-16 11:30:16 +03:00
NSS_STATUS winbindd_request_response ( int req_type ,
2002-09-25 19:19:00 +04:00
struct winbindd_request * request ,
struct winbindd_response * response )
2001-12-22 03:51:32 +03:00
{
2005-05-31 22:36:38 +04:00
NSS_STATUS status = NSS_STATUS_UNAVAIL ;
int count = 0 ;
2001-12-22 03:51:32 +03:00
2005-05-31 22:36:38 +04:00
while ( ( status = = NSS_STATUS_UNAVAIL ) & & ( count < 10 ) ) {
2007-03-23 00:41:36 +03:00
status = winbindd_send_request ( req_type , 0 , request ) ;
2008-12-16 11:30:16 +03:00
if ( status ! = NSS_STATUS_SUCCESS )
2007-03-23 00:41:36 +03:00
return ( status ) ;
status = winbindd_get_response ( response ) ;
count + = 1 ;
}
return status ;
}
2008-12-16 11:30:16 +03:00
NSS_STATUS winbindd_priv_request_response ( int req_type ,
2007-03-23 00:41:36 +03:00
struct winbindd_request * request ,
struct winbindd_response * response )
{
NSS_STATUS status = NSS_STATUS_UNAVAIL ;
int count = 0 ;
while ( ( status = = NSS_STATUS_UNAVAIL ) & & ( count < 10 ) ) {
status = winbindd_send_request ( req_type , 1 , request ) ;
2008-12-16 11:30:16 +03:00
if ( status ! = NSS_STATUS_SUCCESS )
2005-05-31 22:36:38 +04:00
return ( status ) ;
status = winbindd_get_response ( response ) ;
count + = 1 ;
}
return status ;
2001-12-22 03:51:32 +03:00
}