2000-05-09 15:43:00 +04:00
/*
Unix SMB / Netbios implementation .
Version 2.0
Windows NT Domain nsswitch module
Copyright ( C ) Tim Potter 2000
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
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 .
You should have received a copy of the GNU Library General Public
License along with this library ; if not , write to the
Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
Boston , MA 02111 - 1307 , USA .
*/
2000-05-10 18:17:21 +04:00
# include "winbind_nss_config.h"
# include "winbindd_nss.h"
2000-05-09 15:43:00 +04:00
/* prototypes from common.c */
void init_request ( struct winbindd_request * req , int rq_type ) ;
int write_sock ( void * buffer , int count ) ;
int read_reply ( struct winbindd_response * response ) ;
/* Allocate some space from the nss static buffer. The buffer and buflen
are the pointers passed in by the C library to the _nss_ntdom_ *
functions . */
static char * get_static ( char * * buffer , int * buflen , int len )
{
char * result ;
/* Error check. We return false if things aren't set up right, or
there isn ' t enough buffer space left . */
if ( ( buffer = = NULL ) | | ( buflen = = NULL ) | | ( * buflen < len ) ) {
return NULL ;
}
/* Return an index into the static buffer */
result = * buffer ;
* buffer + = len ;
* buflen - = len ;
return result ;
}
/* I've copied the strtok() replacement function next_token() from
lib / util_str . c as I really don ' t want to have to link in any other
objects if I can possibly avoid it . */
# ifdef strchr /* Aargh! This points at multibyte_strchr(). )-: */
# undef strchr
# endif
static char * last_ptr = NULL ;
BOOL next_token ( char * * ptr , char * buff , char * sep , size_t bufsize )
{
char * s ;
BOOL quoted ;
size_t len = 1 ;
if ( ! ptr ) ptr = & last_ptr ;
if ( ! ptr ) return ( False ) ;
s = * ptr ;
/* default to simple separators */
if ( ! sep ) sep = " \t \n \r " ;
/* find the first non sep char */
while ( * s & & strchr ( sep , * s ) ) s + + ;
/* nothing left? */
if ( ! * s ) return ( False ) ;
/* copy over the token */
for ( quoted = False ;
len < bufsize & & * s & & ( quoted | | ! strchr ( sep , * s ) ) ;
s + + ) {
if ( * s = = ' \" ' ) {
quoted = ! quoted ;
} else {
len + + ;
* buff + + = * s ;
}
}
* ptr = ( * s ) ? s + 1 : s ;
* buff = 0 ;
last_ptr = * ptr ;
return ( True ) ;
}
/* handle simple types of requests */
static enum nss_status generic_request ( int req_type ,
struct winbindd_request * request ,
struct winbindd_response * response )
{
struct winbindd_request lrequest ;
struct winbindd_response lresponse ;
if ( ! response ) response = & lresponse ;
if ( ! request ) request = & lrequest ;
/* Fill in request and send down pipe */
init_request ( request , req_type ) ;
if ( write_sock ( request , sizeof ( * request ) ) = = - 1 ) {
return NSS_STATUS_UNAVAIL ;
}
/* Wait for reply */
if ( read_reply ( response ) = = - 1 ) {
return NSS_STATUS_UNAVAIL ;
}
/* Copy reply data from socket */
if ( response - > result ! = WINBINDD_OK ) {
return NSS_STATUS_NOTFOUND ;
}
return NSS_STATUS_SUCCESS ;
}
/* Fill a pwent structure from a winbindd_response structure. We use
the static data passed to us by libc to put strings and stuff in .
Return errno = ERANGE and NSS_STATUS_TRYAGAIN if we run out of
memory . */
static enum nss_status fill_pwent ( struct passwd * result ,
struct winbindd_response * response ,
char * * buffer , int * buflen , int * errnop )
{
struct winbindd_pw * pw = & response - > data . pw ;
/* User name */
if ( ( result - > pw_name =
get_static ( buffer , buflen , strlen ( pw - > pw_name ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( result - > pw_name , pw - > pw_name ) ;
/* Password */
if ( ( result - > pw_passwd =
get_static ( buffer , buflen , strlen ( pw - > pw_passwd ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( result - > pw_passwd , pw - > pw_passwd ) ;
/* [ug]id */
result - > pw_uid = pw - > pw_uid ;
result - > pw_gid = pw - > pw_gid ;
/* GECOS */
if ( ( result - > pw_gecos =
get_static ( buffer , buflen , strlen ( pw - > pw_gecos ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( result - > pw_gecos , pw - > pw_gecos ) ;
/* Home directory */
if ( ( result - > pw_dir =
get_static ( buffer , buflen , strlen ( pw - > pw_dir ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( result - > pw_dir , pw - > pw_dir ) ;
/* Logon shell */
if ( ( result - > pw_shell =
get_static ( buffer , buflen , strlen ( pw - > pw_shell ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( result - > pw_shell , pw - > pw_shell ) ;
return NSS_STATUS_SUCCESS ;
}
/* Fill a grent structure from a winbindd_response structure. We use
the static data passed to us by libc to put strings and stuff in .
Return errno = ERANGE and NSS_STATUS_TRYAGAIN if we run out of
memory . */
static int fill_grent ( struct group * result ,
struct winbindd_response * response ,
char * * buffer , int * buflen , int * errnop )
{
struct winbindd_gr * gr = & response - > data . gr ;
fstring name ;
int i ;
/* Group name */
if ( ( result - > gr_name =
get_static ( buffer , buflen , strlen ( gr - > gr_name ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( result - > gr_name , gr - > gr_name ) ;
/* Password */
if ( ( result - > gr_passwd =
get_static ( buffer , buflen , strlen ( gr - > gr_passwd ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( result - > gr_passwd , gr - > gr_passwd ) ;
/* gid */
result - > gr_gid = gr - > gr_gid ;
/* Group membership */
if ( ( gr - > num_gr_mem < 0 ) | | ! response - > extra_data ) {
gr - > num_gr_mem = 0 ;
}
if ( ( result - > gr_mem =
( char * * ) get_static ( buffer , buflen , ( gr - > num_gr_mem + 1 ) *
sizeof ( char * ) ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
if ( gr - > num_gr_mem = = 0 ) {
/* Group is empty */
* ( result - > gr_mem ) = NULL ;
return NSS_STATUS_SUCCESS ;
}
/* Start looking at extra data */
i = 0 ;
while ( next_token ( & response - > extra_data , name , " , " , sizeof ( fstring ) ) ) {
/* Allocate space for member */
if ( ( ( result - > gr_mem ) [ i ] =
get_static ( buffer , buflen , strlen ( name ) + 1 ) ) = = NULL ) {
/* Out of memory */
* errnop = ERANGE ;
return NSS_STATUS_TRYAGAIN ;
}
strcpy ( ( result - > gr_mem ) [ i ] , name ) ;
i + + ;
}
/* Terminate list */
( result - > gr_mem ) [ i ] = NULL ;
return NSS_STATUS_SUCCESS ;
}
/*
* NSS user functions
*/
/* Rewind "file pointer" to start of ntdom password database */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_setpwent ( void )
2000-05-09 15:43:00 +04:00
{
return generic_request ( WINBINDD_SETPWENT , NULL , NULL ) ;
}
/* Close ntdom password database "file pointer" */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_endpwent ( void )
2000-05-09 15:43:00 +04:00
{
return generic_request ( WINBINDD_ENDPWENT , NULL , NULL ) ;
}
/* Fetch the next password entry from ntdom password database */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_getpwent_r ( struct passwd * result , char * buffer ,
2000-05-09 15:43:00 +04:00
size_t buflen , int * errnop )
{
enum nss_status ret ;
struct winbindd_response response ;
ret = generic_request ( WINBINDD_GETPWENT , NULL , & response ) ;
if ( ret ! = NSS_STATUS_SUCCESS ) return ret ;
return fill_pwent ( result , & response , & buffer , & buflen , errnop ) ;
}
/* Return passwd struct from uid */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_getpwuid_r ( uid_t uid , struct passwd * result , char * buffer ,
2000-05-09 15:43:00 +04:00
size_t buflen , int * errnop )
{
enum nss_status ret ;
struct winbindd_response response ;
struct winbindd_request request ;
request . data . uid = uid ;
ret = generic_request ( WINBINDD_GETPWNAM_FROM_UID , & request , & response ) ;
if ( ret ! = NSS_STATUS_SUCCESS ) return ret ;
return fill_pwent ( result , & response , & buffer , & buflen , errnop ) ;
}
/* Return passwd struct from username */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_getpwnam_r ( const char * name , struct passwd * result , char * buffer ,
2000-05-09 15:43:00 +04:00
size_t buflen , int * errnop )
{
enum nss_status ret ;
struct winbindd_response response ;
struct winbindd_request request ;
strncpy ( request . data . username , name , sizeof ( request . data . username ) - 1 ) ;
request . data . username [ sizeof ( request . data . username ) - 1 ] = ' \0 ' ;
ret = generic_request ( WINBINDD_GETPWNAM_FROM_USER , & request , & response ) ;
if ( ret ! = NSS_STATUS_SUCCESS ) return ret ;
return fill_pwent ( result , & response , & buffer , & buflen , errnop ) ;
}
/*
* NSS group functions
*/
/* Rewind "file pointer" to start of ntdom group database */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_setgrent ( void )
2000-05-09 15:43:00 +04:00
{
return generic_request ( WINBINDD_SETGRENT , NULL , NULL ) ;
}
/* Close "file pointer" for ntdom group database */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_endgrent ( void )
2000-05-09 15:43:00 +04:00
{
return generic_request ( WINBINDD_ENDGRENT , NULL , NULL ) ;
}
/* Get next entry from ntdom group database */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_getgrent_r ( struct group * result ,
2000-05-09 15:43:00 +04:00
char * buffer , size_t buflen , int * errnop )
{
enum nss_status ret ;
struct winbindd_response response ;
ret = generic_request ( WINBINDD_GETGRENT , NULL , & response ) ;
if ( ret ! = NSS_STATUS_SUCCESS ) return ret ;
return fill_grent ( result , & response , & buffer , & buflen , errnop ) ;
}
/* Return group struct from group name */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_getgrnam_r ( const char * name ,
2000-05-09 15:43:00 +04:00
struct group * result , char * buffer ,
size_t buflen , int * errnop )
{
enum nss_status ret ;
struct winbindd_response response ;
struct winbindd_request request ;
strncpy ( request . data . groupname , name , sizeof ( request . data . groupname ) ) ;
request . data . groupname [ sizeof ( request . data . groupname ) - 1 ] = ' \0 ' ;
ret = generic_request ( WINBINDD_GETGRNAM_FROM_GROUP , & request , & response ) ;
if ( ret ! = NSS_STATUS_SUCCESS ) return ret ;
return fill_grent ( result , & response , & buffer , & buflen , errnop ) ;
}
/* Return group struct from gid */
enum nss_status
2000-05-10 18:48:33 +04:00
_nss_winbind_getgrgid_r ( gid_t gid ,
2000-05-09 15:43:00 +04:00
struct group * result , char * buffer ,
size_t buflen , int * errnop )
{
enum nss_status ret ;
struct winbindd_response response ;
struct winbindd_request request ;
request . data . gid = gid ;
ret = generic_request ( WINBINDD_GETGRNAM_FROM_GID , & request , & response ) ;
if ( ret ! = NSS_STATUS_SUCCESS ) return ret ;
return fill_grent ( result , & response , & buffer , & buflen , errnop ) ;
}