2003-03-31 08:36:01 +04:00
/*
Unix SMB / CIFS implementation .
Windows NT Domain nsswitch module
Copyright ( C ) Tim Potter 2000
2006-05-04 04:45:31 +04:00
Copyright ( C ) James Peach 2006
2003-03-31 08:36:01 +04:00
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 .
*/
# include "winbind_client.h"
2006-05-04 04:45:31 +04:00
# ifndef PRINTF_ATTRIBUTE
# define PRINTF_ATTRIBUTE(m, n)
# endif
# ifndef HAVE_ASPRINTF_DECL
/*PRINTFLIKE2 */
int asprintf ( char * * , const char * , . . . ) PRINTF_ATTRIBUTE ( 2 , 3 ) ;
# endif
2003-03-31 08:36:01 +04:00
# ifdef HAVE_NS_API_H
# undef VOLATILE
2006-05-04 04:45:31 +04:00
# undef STATIC
# undef DYNAMIC
2003-03-31 08:36:01 +04:00
# include <ns_daemon.h>
# endif
/* Maximum number of users to pass back over the unix domain socket
per call . This is not a static limit on the total number of users
or groups returned in total . */
# define MAX_GETPWENT_USERS 250
# define MAX_GETGRENT_USERS 250
/* Prototypes from wb_common.c */
extern int winbindd_fd ;
# ifdef HAVE_NS_API_H
/* IRIX version */
static int send_next_request ( nsd_file_t * , struct winbindd_request * ) ;
static int do_list ( int state , nsd_file_t * rq ) ;
static nsd_file_t * current_rq = NULL ;
static int current_winbind_xid = 0 ;
static int next_winbind_xid = 0 ;
typedef struct winbind_xid {
int xid ;
nsd_file_t * rq ;
struct winbindd_request * request ;
struct winbind_xid * next ;
} winbind_xid_t ;
static winbind_xid_t * winbind_xids = ( winbind_xid_t * ) 0 ;
static int
winbind_xid_new ( int xid , nsd_file_t * rq , struct winbindd_request * request )
{
winbind_xid_t * new ;
nsd_logprintf ( NSD_LOG_LOW ,
" entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x \n " ,
xid , rq , request ) ;
new = ( winbind_xid_t * ) nsd_calloc ( 1 , sizeof ( winbind_xid_t ) ) ;
if ( ! new ) {
nsd_logprintf ( NSD_LOG_RESOURCE , " winbind_xid_new: failed malloc \n " ) ;
return NSD_ERROR ;
}
new - > xid = xid ;
new - > rq = rq ;
new - > request = request ;
new - > next = winbind_xids ;
winbind_xids = new ;
return NSD_CONTINUE ;
}
/*
* * This routine will look down the xid list and return the request
* * associated with an xid . We remove the record if it is found .
*/
nsd_file_t *
winbind_xid_lookup ( int xid , struct winbindd_request * * requestp )
{
winbind_xid_t * * last , * dx ;
nsd_file_t * result = 0 ;
for ( last = & winbind_xids , dx = winbind_xids ; dx & & ( dx - > xid ! = xid ) ;
last = & dx - > next , dx = dx - > next ) ;
if ( dx ) {
* last = dx - > next ;
result = dx - > rq ;
* requestp = dx - > request ;
SAFE_FREE ( dx ) ;
}
nsd_logprintf ( NSD_LOG_LOW ,
" entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x \n " ,
xid , result , dx - > request ) ;
return result ;
}
static int
winbind_startnext_timeout ( nsd_file_t * * rqp , nsd_times_t * to )
{
nsd_file_t * rq ;
struct winbindd_request * request ;
nsd_logprintf ( NSD_LOG_MIN , " timeout (winbind startnext) \n " ) ;
rq = to - > t_file ;
* rqp = rq ;
nsd_timeout_remove ( rq ) ;
request = to - > t_clientdata ;
return ( send_next_request ( rq , request ) ) ;
}
static void
2005-05-07 19:03:00 +04:00
dequeue_request ( void )
2003-03-31 08:36:01 +04:00
{
nsd_file_t * rq ;
struct winbindd_request * request ;
/*
* Check for queued requests
*/
if ( winbind_xids ) {
nsd_logprintf ( NSD_LOG_MIN , " timeout (winbind) unqueue xid %d \n " ,
current_winbind_xid ) ;
rq = winbind_xid_lookup ( current_winbind_xid + + , & request ) ;
/* cause a timeout on the queued request so we can send it */
nsd_timeout_new ( rq , 1 , winbind_startnext_timeout , request ) ;
}
}
static int
do_request ( nsd_file_t * rq , struct winbindd_request * request )
{
if ( winbind_xids = = NULL ) {
/*
* No outstanding requests .
* Send off the request to winbindd
*/
nsd_logprintf ( NSD_LOG_MIN , " lookup (winbind) sending request \n " ) ;
return ( send_next_request ( rq , request ) ) ;
} else {
/*
* Just queue it up for now - previous callout or timout
* will start it up
*/
nsd_logprintf ( NSD_LOG_MIN ,
" lookup (winbind): queue request xid = %d \n " ,
next_winbind_xid ) ;
return ( winbind_xid_new ( next_winbind_xid + + , rq , request ) ) ;
}
}
static int
winbind_callback ( nsd_file_t * * rqp , int fd )
{
struct winbindd_response response ;
nsd_file_t * rq ;
NSS_STATUS status ;
2006-05-04 04:45:31 +04:00
char * result = NULL ;
size_t rlen ;
2003-03-31 08:36:01 +04:00
dequeue_request ( ) ;
nsd_logprintf ( NSD_LOG_MIN , " entering callback (winbind) \n " ) ;
rq = current_rq ;
* rqp = rq ;
nsd_timeout_remove ( rq ) ;
nsd_callback_remove ( fd ) ;
ZERO_STRUCT ( response ) ;
status = winbindd_get_response ( & response ) ;
if ( status ! = NSS_STATUS_SUCCESS ) {
/* free any extra data area in response structure */
free_response ( & response ) ;
nsd_logprintf ( NSD_LOG_MIN ,
" callback (winbind) returning not found, status = %d \n " ,
status ) ;
2006-05-04 04:45:31 +04:00
switch ( status ) {
case NSS_STATUS_UNAVAIL :
rq - > f_status = NS_UNAVAIL ;
break ;
case NSS_STATUS_TRYAGAIN :
rq - > f_status = NS_TRYAGAIN ;
break ;
case NSS_STATUS_NOTFOUND :
/* FALLTHRU */
default :
rq - > f_status = NS_NOTFOUND ;
}
2003-03-31 08:36:01 +04:00
return NSD_NEXT ;
}
switch ( ( int ) rq - > f_cmd_data ) {
case WINBINDD_WINS_BYNAME :
case WINBINDD_WINS_BYIP :
2006-05-04 04:45:31 +04:00
nsd_logprintf ( NSD_LOG_MIN ,
" callback (winbind) WINS_BYNAME | WINS_BYIP \n " ) ;
rlen = asprintf ( & result , " %s \n " , response . data . winsresp ) ;
if ( rlen = = 0 | | result = = NULL ) {
return NSD_ERROR ;
}
free_response ( & response ) ;
nsd_logprintf ( NSD_LOG_MIN , " %s \n " , result ) ;
nsd_set_result ( rq , NS_SUCCESS , result , rlen , DYNAMIC ) ;
return NSD_OK ;
2003-03-31 08:36:01 +04:00
case WINBINDD_GETPWUID :
case WINBINDD_GETPWNAM :
2006-05-04 04:45:31 +04:00
{
struct winbindd_pw * pw = & response . data . pw ;
nsd_logprintf ( NSD_LOG_MIN ,
" callback (winbind) GETPWUID | GETPWUID \n " ) ;
rlen = asprintf ( & result , " %s:%s:%d:%d:%s:%s:%s \n " ,
pw - > pw_name ,
pw - > pw_passwd ,
pw - > pw_uid ,
pw - > pw_gid ,
pw - > pw_gecos ,
pw - > pw_dir ,
pw - > pw_shell ) ;
if ( rlen = = 0 | | result = = NULL )
return NSD_ERROR ;
free_response ( & response ) ;
nsd_logprintf ( NSD_LOG_MIN , " %s \n " , result ) ;
nsd_set_result ( rq , NS_SUCCESS , result , rlen , DYNAMIC ) ;
return NSD_OK ;
}
2003-03-31 08:36:01 +04:00
case WINBINDD_GETGRNAM :
case WINBINDD_GETGRGID :
2006-05-04 04:45:31 +04:00
{
const struct winbindd_gr * gr = & response . data . gr ;
const char * members ;
nsd_logprintf ( NSD_LOG_MIN ,
" callback (winbind) GETGRNAM | GETGRGID \n " ) ;
if ( gr - > num_gr_mem & & response . extra_data . data ) {
members = response . extra_data . data ;
} else {
members = " " ;
}
rlen = asprintf ( & result , " %s:%s:%d:%s \n " ,
gr - > gr_name , gr - > gr_passwd , gr - > gr_gid , members ) ;
if ( rlen = = 0 | | result = = NULL )
return NSD_ERROR ;
free_response ( & response ) ;
nsd_logprintf ( NSD_LOG_MIN , " %s \n " , result ) ;
nsd_set_result ( rq , NS_SUCCESS , result , rlen , DYNAMIC ) ;
return NSD_OK ;
}
2003-03-31 08:36:01 +04:00
case WINBINDD_SETGRENT :
case WINBINDD_SETPWENT :
2006-05-04 04:45:31 +04:00
nsd_logprintf ( NSD_LOG_MIN ,
" callback (winbind) SETGRENT | SETPWENT \n " ) ;
2003-03-31 08:36:01 +04:00
free_response ( & response ) ;
return ( do_list ( 1 , rq ) ) ;
2006-05-04 04:45:31 +04:00
2003-03-31 08:36:01 +04:00
case WINBINDD_GETGRENT :
case WINBINDD_GETGRLST :
2006-05-04 04:45:31 +04:00
{
int entries ;
nsd_logprintf ( NSD_LOG_MIN ,
" callback (winbind) GETGRENT | GETGRLIST %d responses \n " ,
response . data . num_entries ) ;
if ( response . data . num_entries ) {
const struct winbindd_gr * gr = & response . data . gr ;
const char * members ;
fstring grp_name ;
int i ;
gr = ( struct winbindd_gr * ) response . extra_data . data ;
if ( ! gr ) {
nsd_logprintf ( NSD_LOG_MIN , " no extra_data \n " ) ;
free_response ( & response ) ;
return NSD_ERROR ;
}
members = ( char * ) response . extra_data . data +
( response . data . num_entries * sizeof ( struct winbindd_gr ) ) ;
for ( i = 0 ; i < response . data . num_entries ; i + + ) {
snprintf ( grp_name , sizeof ( grp_name ) - 1 , " %s:%s:%d: " ,
gr - > gr_name , gr - > gr_passwd , gr - > gr_gid ) ;
nsd_append_element ( rq , NS_SUCCESS , result , rlen ) ;
nsd_append_result ( rq , NS_SUCCESS ,
& members [ gr - > gr_mem_ofs ] ,
strlen ( & members [ gr - > gr_mem_ofs ] ) ) ;
/* Don't log the whole list, because it might be
* _really_ long and we probably don ' t want to clobber
* the log with it .
*/
nsd_logprintf ( NSD_LOG_MIN , " %s (...) \n " , grp_name ) ;
gr + + ;
}
}
entries = response . data . num_entries ;
free_response ( & response ) ;
if ( entries < MAX_GETPWENT_USERS )
return ( do_list ( 2 , rq ) ) ;
else
return ( do_list ( 1 , rq ) ) ;
}
2003-03-31 08:36:01 +04:00
case WINBINDD_GETPWENT :
2006-05-04 04:45:31 +04:00
{
int entries ;
nsd_logprintf ( NSD_LOG_MIN ,
" callback (winbind) GETPWENT %d responses \n " ,
2003-03-31 08:36:01 +04:00
response . data . num_entries ) ;
2006-05-04 04:45:31 +04:00
2003-03-31 08:36:01 +04:00
if ( response . data . num_entries ) {
2006-05-04 04:45:31 +04:00
struct winbindd_pw * pw = & response . data . pw ;
int i ;
2006-04-12 18:10:39 +04:00
pw = ( struct winbindd_pw * ) response . extra_data . data ;
2003-03-31 08:36:01 +04:00
if ( ! pw ) {
nsd_logprintf ( NSD_LOG_MIN , " no extra_data \n " ) ;
free_response ( & response ) ;
return NSD_ERROR ;
}
for ( i = 0 ; i < response . data . num_entries ; i + + ) {
2006-05-04 04:45:31 +04:00
result = NULL ;
rlen = asprintf ( & result , " %s:%s:%d:%d:%s:%s:%s " ,
pw - > pw_name ,
pw - > pw_passwd ,
pw - > pw_uid ,
pw - > pw_gid ,
pw - > pw_gecos ,
pw - > pw_dir ,
pw - > pw_shell ) ;
if ( rlen ! = 0 & & result ! = NULL ) {
nsd_logprintf ( NSD_LOG_MIN , " %s \n " , result ) ;
nsd_append_element ( rq , NS_SUCCESS , result , rlen ) ;
free ( result ) ;
}
2003-03-31 08:36:01 +04:00
pw + + ;
}
}
2006-05-04 04:45:31 +04:00
entries = response . data . num_entries ;
2003-03-31 08:36:01 +04:00
free_response ( & response ) ;
2006-05-04 04:45:31 +04:00
if ( entries < MAX_GETPWENT_USERS )
2003-03-31 08:36:01 +04:00
return ( do_list ( 2 , rq ) ) ;
else
return ( do_list ( 1 , rq ) ) ;
2006-05-04 04:45:31 +04:00
}
2003-03-31 08:36:01 +04:00
case WINBINDD_ENDGRENT :
case WINBINDD_ENDPWENT :
2006-05-04 04:45:31 +04:00
nsd_logprintf ( NSD_LOG_MIN , " callback (winbind) ENDGRENT | ENDPWENT \n " ) ;
nsd_append_element ( rq , NS_SUCCESS , " \n " , 1 ) ;
2003-03-31 08:36:01 +04:00
free_response ( & response ) ;
return NSD_NEXT ;
2006-05-04 04:45:31 +04:00
2003-03-31 08:36:01 +04:00
default :
free_response ( & response ) ;
2006-05-04 04:45:31 +04:00
nsd_logprintf ( NSD_LOG_MIN , " callback (winbind) invalid command %d \n " , ( int ) rq - > f_cmd_data ) ;
2003-03-31 08:36:01 +04:00
return NSD_NEXT ;
}
}
static int
winbind_timeout ( nsd_file_t * * rqp , nsd_times_t * to )
{
nsd_file_t * rq ;
dequeue_request ( ) ;
nsd_logprintf ( NSD_LOG_MIN , " timeout (winbind) \n " ) ;
rq = to - > t_file ;
* rqp = rq ;
/* Remove the callback and timeout */
nsd_callback_remove ( winbindd_fd ) ;
nsd_timeout_remove ( rq ) ;
rq - > f_status = NS_NOTFOUND ;
return NSD_NEXT ;
}
static int
send_next_request ( nsd_file_t * rq , struct winbindd_request * request )
{
NSS_STATUS status ;
long timeout ;
2005-08-13 12:49:50 +04:00
switch ( rq - > f_index ) {
case LOOKUP :
timeout = nsd_attr_fetch_long ( rq - > f_attrs ,
2006-04-18 10:26:23 +04:00
" lookup_timeout " , 10 , 10 ) ;
2005-08-13 12:49:50 +04:00
break ;
case LIST :
timeout = nsd_attr_fetch_long ( rq - > f_attrs ,
2006-04-18 10:26:23 +04:00
" list_timeout " , 10 , 10 ) ;
2005-08-13 12:49:50 +04:00
break ;
default :
nsd_logprintf ( NSD_LOG_OPER ,
" send_next_request (winbind) "
" invalid request type %d \n " , rq - > f_index ) ;
rq - > f_status = NS_BADREQ ;
return NSD_NEXT ;
}
2003-03-31 08:36:01 +04:00
2006-05-04 04:45:31 +04:00
nsd_logprintf ( NSD_LOG_MIN ,
" send_next_request (winbind) %d, timeout = %d sec \n " ,
2003-03-31 08:36:01 +04:00
rq - > f_cmd_data , timeout ) ;
2007-03-23 01:00:48 +03:00
status = winbindd_send_request ( ( int ) rq - > f_cmd_data , 0 , request ) ;
2003-03-31 08:36:01 +04:00
SAFE_FREE ( request ) ;
if ( status ! = NSS_STATUS_SUCCESS ) {
nsd_logprintf ( NSD_LOG_MIN ,
2006-05-04 04:45:31 +04:00
" send_next_request (winbind) error status = %d \n " ,
status ) ;
2003-03-31 08:36:01 +04:00
rq - > f_status = status ;
return NSD_NEXT ;
}
current_rq = rq ;
/*
* Set up callback and timeouts
*/
2006-04-18 10:26:23 +04:00
nsd_logprintf ( NSD_LOG_MIN , " send_next_request (winbind) fd = %d \n " ,
winbindd_fd ) ;
nsd_callback_new ( winbindd_fd , winbind_callback , NSD_READ ) ;
nsd_timeout_new ( rq , timeout * 1000 , winbind_timeout , NULL ) ;
2003-03-31 08:36:01 +04:00
return NSD_CONTINUE ;
}
int init ( void )
{
nsd_logprintf ( NSD_LOG_MIN , " entering init (winbind) \n " ) ;
return ( NSD_OK ) ;
}
int lookup ( nsd_file_t * rq )
{
char * map ;
char * key ;
struct winbindd_request * request ;
nsd_logprintf ( NSD_LOG_MIN , " entering lookup (winbind) \n " ) ;
if ( ! rq )
return NSD_ERROR ;
map = nsd_attr_fetch_string ( rq - > f_attrs , " table " , ( char * ) 0 ) ;
key = nsd_attr_fetch_string ( rq - > f_attrs , " key " , ( char * ) 0 ) ;
if ( ! map | | ! key ) {
nsd_logprintf ( NSD_LOG_MIN , " lookup (winbind) table or key not defined \n " ) ;
rq - > f_status = NS_BADREQ ;
return NSD_ERROR ;
}
nsd_logprintf ( NSD_LOG_MIN , " lookup (winbind %s) \n " , map ) ;
request = ( struct winbindd_request * ) nsd_calloc ( 1 , sizeof ( struct winbindd_request ) ) ;
if ( ! request ) {
nsd_logprintf ( NSD_LOG_RESOURCE ,
" lookup (winbind): failed malloc \n " ) ;
return NSD_ERROR ;
}
if ( strcasecmp ( map , " passwd.byuid " ) = = 0 ) {
request - > data . uid = atoi ( key ) ;
rq - > f_cmd_data = ( void * ) WINBINDD_GETPWUID ;
} else if ( strcasecmp ( map , " passwd.byname " ) = = 0 ) {
strncpy ( request - > data . username , key ,
sizeof ( request - > data . username ) - 1 ) ;
request - > data . username [ sizeof ( request - > data . username ) - 1 ] = ' \0 ' ;
rq - > f_cmd_data = ( void * ) WINBINDD_GETPWNAM ;
} else if ( strcasecmp ( map , " group.byname " ) = = 0 ) {
strncpy ( request - > data . groupname , key ,
sizeof ( request - > data . groupname ) - 1 ) ;
request - > data . groupname [ sizeof ( request - > data . groupname ) - 1 ] = ' \0 ' ;
rq - > f_cmd_data = ( void * ) WINBINDD_GETGRNAM ;
} else if ( strcasecmp ( map , " group.bygid " ) = = 0 ) {
request - > data . gid = atoi ( key ) ;
rq - > f_cmd_data = ( void * ) WINBINDD_GETGRGID ;
} else if ( strcasecmp ( map , " hosts.byname " ) = = 0 ) {
strncpy ( request - > data . winsreq , key , sizeof ( request - > data . winsreq ) - 1 ) ;
request - > data . winsreq [ sizeof ( request - > data . winsreq ) - 1 ] = ' \0 ' ;
rq - > f_cmd_data = ( void * ) WINBINDD_WINS_BYNAME ;
} else if ( strcasecmp ( map , " hosts.byaddr " ) = = 0 ) {
strncpy ( request - > data . winsreq , key , sizeof ( request - > data . winsreq ) - 1 ) ;
request - > data . winsreq [ sizeof ( request - > data . winsreq ) - 1 ] = ' \0 ' ;
rq - > f_cmd_data = ( void * ) WINBINDD_WINS_BYIP ;
} else {
/*
* Don ' t understand this map - just return not found
*/
nsd_logprintf ( NSD_LOG_MIN , " lookup (winbind) unknown table \n " ) ;
SAFE_FREE ( request ) ;
rq - > f_status = NS_NOTFOUND ;
return NSD_NEXT ;
}
return ( do_request ( rq , request ) ) ;
}
int list ( nsd_file_t * rq )
{
char * map ;
nsd_logprintf ( NSD_LOG_MIN , " entering list (winbind) \n " ) ;
if ( ! rq )
return NSD_ERROR ;
map = nsd_attr_fetch_string ( rq - > f_attrs , " table " , ( char * ) 0 ) ;
if ( ! map ) {
nsd_logprintf ( NSD_LOG_MIN , " list (winbind) table not defined \n " ) ;
rq - > f_status = NS_BADREQ ;
return NSD_ERROR ;
}
nsd_logprintf ( NSD_LOG_MIN , " list (winbind %s) \n " , map ) ;
return ( do_list ( 0 , rq ) ) ;
}
static int
do_list ( int state , nsd_file_t * rq )
{
char * map ;
struct winbindd_request * request ;
nsd_logprintf ( NSD_LOG_MIN , " entering do_list (winbind) state = %d \n " , state ) ;
map = nsd_attr_fetch_string ( rq - > f_attrs , " table " , ( char * ) 0 ) ;
request = ( struct winbindd_request * ) nsd_calloc ( 1 , sizeof ( struct winbindd_request ) ) ;
if ( ! request ) {
nsd_logprintf ( NSD_LOG_RESOURCE ,
" do_list (winbind): failed malloc \n " ) ;
return NSD_ERROR ;
}
if ( strcasecmp ( map , " passwd.byname " ) = = 0 ) {
switch ( state ) {
case 0 :
rq - > f_cmd_data = ( void * ) WINBINDD_SETPWENT ;
break ;
case 1 :
request - > data . num_entries = MAX_GETPWENT_USERS ;
rq - > f_cmd_data = ( void * ) WINBINDD_GETPWENT ;
break ;
case 2 :
rq - > f_cmd_data = ( void * ) WINBINDD_ENDPWENT ;
break ;
default :
nsd_logprintf ( NSD_LOG_MIN , " do_list (winbind) unknown state \n " ) ;
SAFE_FREE ( request ) ;
rq - > f_status = NS_NOTFOUND ;
return NSD_NEXT ;
}
} else if ( strcasecmp ( map , " group.byname " ) = = 0 ) {
switch ( state ) {
case 0 :
rq - > f_cmd_data = ( void * ) WINBINDD_SETGRENT ;
break ;
case 1 :
request - > data . num_entries = MAX_GETGRENT_USERS ;
rq - > f_cmd_data = ( void * ) WINBINDD_GETGRENT ;
break ;
case 2 :
rq - > f_cmd_data = ( void * ) WINBINDD_ENDGRENT ;
break ;
default :
nsd_logprintf ( NSD_LOG_MIN , " do_list (winbind) unknown state \n " ) ;
SAFE_FREE ( request ) ;
rq - > f_status = NS_NOTFOUND ;
return NSD_NEXT ;
}
} else {
/*
* Don ' t understand this map - just return not found
*/
nsd_logprintf ( NSD_LOG_MIN , " do_list (winbind) unknown table \n " ) ;
SAFE_FREE ( request ) ;
rq - > f_status = NS_NOTFOUND ;
return NSD_NEXT ;
}
return ( do_request ( rq , request ) ) ;
}
# endif /* HAVE_NS_API_H */