2001-12-03 09:04:18 +03:00
/*
Unix SMB / Netbios implementation .
Winbind ADS backend functions
Copyright ( C ) Andrew Tridgell 2001
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 .
*/
# include "winbindd.h"
# ifdef HAVE_ADS
2001-12-19 11:44:23 +03:00
/* the realm of our primary LDAP server */
static char * primary_realm ;
2001-12-05 10:05:53 +03:00
2001-12-08 14:18:56 +03:00
/*
a wrapper around ldap_search_s that retries depending on the error code
this is supposed to catch dropped connections and auto - reconnect
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_do_search_retry ( ADS_STRUCT * ads , const char * bind_path , int scope ,
const char * exp ,
const char * * attrs , void * * res )
2001-12-08 14:18:56 +03:00
{
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-12-08 14:18:56 +03:00
int count = 3 ;
if ( ! ads - > ld & &
time ( NULL ) - ads - > last_attempt < ADS_RECONNECT_TIME ) {
2001-12-19 15:21:12 +03:00
return ADS_ERROR ( LDAP_SERVER_DOWN ) ;
2001-12-08 14:18:56 +03:00
}
while ( count - - ) {
2001-12-19 15:21:12 +03:00
status = ads_do_search ( ads , bind_path , scope , exp , attrs , res ) ;
if ( ADS_ERR_OK ( status ) ) {
2001-12-09 09:10:02 +03:00
DEBUG ( 5 , ( " Search for %s gave %d replies \n " ,
exp , ads_count_replies ( ads , * res ) ) ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-12-09 09:10:02 +03:00
}
2001-12-08 14:18:56 +03:00
if ( * res ) ads_msgfree ( ads , * res ) ;
* res = NULL ;
2001-12-19 15:21:12 +03:00
DEBUG ( 1 , ( " Reopening ads connection after error %s \n " ,
ads_errstr ( status ) ) ) ;
2001-12-08 14:18:56 +03:00
if ( ads - > ld ) {
/* we should unbind here, but that seems to trigger openldap bugs :(
ldap_unbind ( ads - > ld ) ;
*/
}
ads - > ld = NULL ;
2001-12-19 15:21:12 +03:00
status = ads_connect ( ads ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 1 , ( " ads_search_retry: failed to reconnect (%s) \n " ,
ads_errstr ( status ) ) ) ;
ads_destroy ( & ads ) ;
return status ;
2001-12-08 14:18:56 +03:00
}
}
2001-12-19 15:21:12 +03:00
DEBUG ( 1 , ( " ads reopen failed after error %s \n " , ads_errstr ( status ) ) ) ;
return status ;
2001-12-08 14:18:56 +03:00
}
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_search_retry ( ADS_STRUCT * ads , void * * res ,
const char * exp ,
const char * * attrs )
2001-12-08 14:18:56 +03:00
{
return ads_do_search_retry ( ads , ads - > bind_path , LDAP_SCOPE_SUBTREE ,
exp , attrs , res ) ;
}
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_search_retry_dn ( ADS_STRUCT * ads , void * * res ,
const char * dn ,
const char * * attrs )
2001-12-08 14:18:56 +03:00
{
return ads_do_search_retry ( ads , dn , LDAP_SCOPE_BASE ,
" (objectclass=*) " , attrs , res ) ;
}
2001-12-05 10:05:53 +03:00
/*
return our ads connections structure for a domain . We keep the connection
open to make things faster
*/
static ADS_STRUCT * ads_cached_connection ( struct winbindd_domain * domain )
{
ADS_STRUCT * ads ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-12-11 01:10:16 +03:00
char * ccache ;
2001-12-19 11:44:23 +03:00
struct in_addr server_ip ;
2001-12-19 16:33:08 +03:00
char * sname ;
2001-12-05 10:05:53 +03:00
if ( domain - > private ) {
return ( ADS_STRUCT * ) domain - > private ;
}
2001-12-11 01:10:16 +03:00
/* we don't want this to affect the users ccache */
ccache = lock_path ( " winbindd_ccache " ) ;
2001-12-11 09:17:01 +03:00
SETENV ( " KRB5CCNAME " , ccache , 1 ) ;
2001-12-11 01:10:16 +03:00
unlink ( ccache ) ;
2001-12-19 16:33:08 +03:00
if ( resolve_name ( domain - > name , & server_ip , 0x1b ) ) {
sname = inet_ntoa ( server_ip ) ;
} else {
if ( strcasecmp ( domain - > name , lp_workgroup ( ) ) ! = 0 ) {
DEBUG ( 1 , ( " can't find domain controller for %s \n " , domain - > name ) ) ;
return NULL ;
}
sname = NULL ;
2001-12-19 11:44:23 +03:00
}
2001-12-19 16:33:08 +03:00
ads = ads_init ( primary_realm , sname , NULL , NULL ) ;
2001-12-05 10:05:53 +03:00
if ( ! ads ) {
DEBUG ( 1 , ( " ads_init for domain %s failed \n " , domain - > name ) ) ;
return NULL ;
}
2001-12-08 14:18:56 +03:00
/* the machine acct password might have change - fetch it every time */
SAFE_FREE ( ads - > password ) ;
ads - > password = secrets_fetch_machine_password ( ) ;
2001-12-19 15:21:12 +03:00
status = ads_connect ( ads ) ;
if ( ! ADS_ERR_OK ( status ) ) {
2001-12-19 15:38:52 +03:00
extern struct winbindd_methods msrpc_methods ;
2001-12-19 15:21:12 +03:00
DEBUG ( 1 , ( " ads_connect for domain %s failed: %s \n " ,
domain - > name , ads_errstr ( status ) ) ) ;
2001-12-05 10:05:53 +03:00
ads_destroy ( & ads ) ;
2001-12-19 15:38:52 +03:00
/* if we get ECONNREFUSED then it might be a NT4
server , fall back to MSRPC */
if ( status . error_type = = ADS_ERROR_SYSTEM & &
status . rc = = ECONNREFUSED ) {
DEBUG ( 1 , ( " Trying MSRPC methods \n " ) ) ;
domain - > methods = & msrpc_methods ;
}
2001-12-05 10:05:53 +03:00
return NULL ;
}
2001-12-19 11:44:23 +03:00
/* remember our primary realm for trusted domain support */
if ( ! primary_realm ) {
primary_realm = strdup ( ads - > realm ) ;
}
2001-12-19 12:53:30 +03:00
fstrcpy ( domain - > full_name , ads - > server_realm ) ;
2001-12-05 10:05:53 +03:00
domain - > private = ( void * ) ads ;
return ads ;
}
2001-12-05 07:48:51 +03:00
/* useful utility */
static void sid_from_rid ( struct winbindd_domain * domain , uint32 rid , DOM_SID * sid )
{
sid_copy ( sid , & domain - > sid ) ;
sid_append_rid ( sid , rid ) ;
}
/* turn a sAMAccountType into a SID_NAME_USE */
static enum SID_NAME_USE ads_atype_map ( uint32 atype )
{
switch ( atype & 0xF0000000 ) {
case ATYPE_GROUP :
return SID_NAME_DOM_GRP ;
case ATYPE_USER :
return SID_NAME_USER ;
default :
DEBUG ( 1 , ( " hmm, need to map account type 0x%x \n " , atype ) ) ;
}
return SID_NAME_UNKNOWN ;
}
2001-12-03 09:04:18 +03:00
/* Query display info for a realm. This is the basic user list fn */
2001-12-03 14:32:55 +03:00
static NTSTATUS query_user_list ( struct winbindd_domain * domain ,
2001-12-03 09:04:18 +03:00
TALLOC_CTX * mem_ctx ,
2001-12-11 03:03:58 +03:00
uint32 * num_entries ,
2001-12-03 14:32:55 +03:00
WINBIND_USERINFO * * info )
2001-12-03 09:04:18 +03:00
{
2001-12-05 09:16:33 +03:00
ADS_STRUCT * ads = NULL ;
2001-12-03 09:04:18 +03:00
const char * attrs [ ] = { " sAMAccountName " , " name " , " objectSid " , " primaryGroupID " ,
2001-12-09 09:10:02 +03:00
" sAMAccountType " , NULL } ;
2001-12-19 15:21:12 +03:00
int i , count ;
ADS_STATUS rc ;
2001-12-05 09:16:33 +03:00
void * res = NULL ;
void * msg = NULL ;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2001-12-03 09:04:18 +03:00
2001-12-11 01:10:16 +03:00
* num_entries = 0 ;
2001-12-03 14:32:55 +03:00
DEBUG ( 3 , ( " ads: query_user_list \n " ) ) ;
2001-12-03 09:04:18 +03:00
2001-12-05 10:05:53 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
2001-12-03 09:04:18 +03:00
2001-12-10 09:21:44 +03:00
rc = ads_search_retry ( ads , & res , " (objectCategory=user) " , attrs ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-03 14:32:55 +03:00
DEBUG ( 1 , ( " query_user_list ads_search: %s \n " , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 09:04:18 +03:00
}
count = ads_count_replies ( ads , res ) ;
if ( count = = 0 ) {
2001-12-03 14:32:55 +03:00
DEBUG ( 1 , ( " query_user_list: No users found \n " ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 09:04:18 +03:00
}
( * info ) = talloc ( mem_ctx , count * sizeof ( * * info ) ) ;
2001-12-05 09:16:33 +03:00
if ( ! * info ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
2001-12-03 09:04:18 +03:00
i = 0 ;
for ( msg = ads_first_entry ( ads , res ) ; msg ; msg = ads_next_entry ( ads , msg ) ) {
char * name , * gecos ;
DOM_SID sid ;
uint32 rid , group ;
2001-12-09 09:10:02 +03:00
uint32 atype ;
2001-12-03 09:04:18 +03:00
2001-12-09 09:10:02 +03:00
if ( ! ads_pull_uint32 ( ads , msg , " sAMAccountType " , & atype ) | |
ads_atype_map ( atype ) ! = SID_NAME_USER ) {
DEBUG ( 1 , ( " Not a user account? atype=0x%x \n " , atype ) ) ;
continue ;
}
2001-12-03 09:04:18 +03:00
name = ads_pull_string ( ads , mem_ctx , msg , " sAMAccountName " ) ;
gecos = ads_pull_string ( ads , mem_ctx , msg , " name " ) ;
if ( ! ads_pull_sid ( ads , msg , " objectSid " , & sid ) ) {
DEBUG ( 1 , ( " No sid for %s !? \n " , name ) ) ;
continue ;
}
if ( ! ads_pull_uint32 ( ads , msg , " primaryGroupID " , & group ) ) {
DEBUG ( 1 , ( " No primary group for %s !? \n " , name ) ) ;
continue ;
}
if ( ! sid_peek_rid ( & sid , & rid ) ) {
DEBUG ( 1 , ( " No rid for %s !? \n " , name ) ) ;
continue ;
}
( * info ) [ i ] . acct_name = name ;
( * info ) [ i ] . full_name = gecos ;
( * info ) [ i ] . user_rid = rid ;
( * info ) [ i ] . group_rid = group ;
i + + ;
}
( * num_entries ) = i ;
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
2001-12-03 09:04:18 +03:00
2001-12-09 09:10:02 +03:00
DEBUG ( 3 , ( " ads query_user_list gave %d entries \n " , ( * num_entries ) ) ) ;
2001-12-05 09:16:33 +03:00
done :
if ( res ) ads_msgfree ( ads , res ) ;
2001-12-03 09:04:18 +03:00
2001-12-05 09:16:33 +03:00
return status ;
2001-12-03 09:04:18 +03:00
}
/* list all domain groups */
static NTSTATUS enum_dom_groups ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2001-12-11 04:04:13 +03:00
uint32 * num_entries ,
2001-12-03 09:04:18 +03:00
struct acct_info * * info )
{
2001-12-05 09:16:33 +03:00
ADS_STRUCT * ads = NULL ;
2001-12-03 09:04:18 +03:00
const char * attrs [ ] = { " sAMAccountName " , " name " , " objectSid " ,
" sAMAccountType " , NULL } ;
2001-12-19 15:21:12 +03:00
int i , count ;
ADS_STATUS rc ;
2001-12-05 09:16:33 +03:00
void * res = NULL ;
void * msg = NULL ;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2001-12-03 09:04:18 +03:00
2001-12-11 01:10:16 +03:00
* num_entries = 0 ;
2001-12-03 09:04:18 +03:00
DEBUG ( 3 , ( " ads: enum_dom_groups \n " ) ) ;
2001-12-05 10:05:53 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
2001-12-03 09:04:18 +03:00
2001-12-10 09:21:44 +03:00
rc = ads_search_retry ( ads , & res , " (objectCategory=group) " , attrs ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-03 14:32:55 +03:00
DEBUG ( 1 , ( " query_user_list ads_search: %s \n " , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 09:04:18 +03:00
}
count = ads_count_replies ( ads , res ) ;
if ( count = = 0 ) {
2001-12-03 14:32:55 +03:00
DEBUG ( 1 , ( " query_user_list: No users found \n " ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 09:04:18 +03:00
}
( * info ) = talloc ( mem_ctx , count * sizeof ( * * info ) ) ;
2001-12-05 09:16:33 +03:00
if ( ! * info ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
2001-12-03 09:04:18 +03:00
i = 0 ;
for ( msg = ads_first_entry ( ads , res ) ; msg ; msg = ads_next_entry ( ads , msg ) ) {
char * name , * gecos ;
DOM_SID sid ;
uint32 rid ;
uint32 account_type ;
if ( ! ads_pull_uint32 ( ads , msg , " sAMAccountType " ,
& account_type ) | |
2001-12-03 11:17:46 +03:00
! ( account_type & ATYPE_GROUP ) ) continue ;
2001-12-03 09:04:18 +03:00
name = ads_pull_string ( ads , mem_ctx , msg , " sAMAccountName " ) ;
gecos = ads_pull_string ( ads , mem_ctx , msg , " name " ) ;
if ( ! ads_pull_sid ( ads , msg , " objectSid " , & sid ) ) {
DEBUG ( 1 , ( " No sid for %s !? \n " , name ) ) ;
continue ;
}
if ( ! sid_peek_rid ( & sid , & rid ) ) {
DEBUG ( 1 , ( " No rid for %s !? \n " , name ) ) ;
continue ;
}
fstrcpy ( ( * info ) [ i ] . acct_name , name ) ;
fstrcpy ( ( * info ) [ i ] . acct_desc , gecos ) ;
( * info ) [ i ] . rid = rid ;
i + + ;
}
( * num_entries ) = i ;
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
2001-12-09 09:10:02 +03:00
DEBUG ( 3 , ( " ads enum_dom_groups gave %d entries \n " , ( * num_entries ) ) ) ;
2001-12-05 09:16:33 +03:00
done :
if ( res ) ads_msgfree ( ads , res ) ;
2001-12-03 09:04:18 +03:00
2001-12-05 09:16:33 +03:00
return status ;
2001-12-03 09:04:18 +03:00
}
2001-12-03 11:17:46 +03:00
/* convert a single name to a sid in a domain */
static NTSTATUS name_to_sid ( struct winbindd_domain * domain ,
const char * name ,
DOM_SID * sid ,
enum SID_NAME_USE * type )
{
2001-12-05 09:16:33 +03:00
ADS_STRUCT * ads = NULL ;
2001-12-03 11:17:46 +03:00
const char * attrs [ ] = { " objectSid " , " sAMAccountType " , NULL } ;
2001-12-19 15:21:12 +03:00
int count ;
ADS_STATUS rc ;
2001-12-05 09:16:33 +03:00
void * res = NULL ;
2001-12-03 11:17:46 +03:00
char * exp ;
uint32 t ;
2001-12-11 22:27:40 +03:00
fstring name2 , dom2 , fullname2 ;
2001-12-05 09:16:33 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2001-12-03 11:17:46 +03:00
/* sigh. Need to fix interface to give us a raw name */
2001-12-11 22:27:40 +03:00
fstrcpy ( fullname2 , name ) ;
fstring_sub ( fullname2 , " \\ " , lp_winbind_separator ( ) ) ;
if ( ! parse_domain_user ( fullname2 , dom2 , name2 ) ) {
2001-12-05 09:16:33 +03:00
goto done ;
}
2001-12-03 11:17:46 +03:00
DEBUG ( 3 , ( " ads: name_to_sid \n " ) ) ;
2001-12-05 10:05:53 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
2001-12-03 11:17:46 +03:00
asprintf ( & exp , " (sAMAccountName=%s) " , name2 ) ;
2001-12-08 14:18:56 +03:00
rc = ads_search_retry ( ads , & res , exp , attrs ) ;
2001-12-03 11:17:46 +03:00
free ( exp ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-03 11:17:46 +03:00
DEBUG ( 1 , ( " name_to_sid ads_search: %s \n " , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 11:17:46 +03:00
}
count = ads_count_replies ( ads , res ) ;
if ( count ! = 1 ) {
DEBUG ( 1 , ( " name_to_sid: %s not found \n " , name ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 11:17:46 +03:00
}
if ( ! ads_pull_sid ( ads , res , " objectSid " , sid ) ) {
DEBUG ( 1 , ( " No sid for %s !? \n " , name ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 11:17:46 +03:00
}
if ( ! ads_pull_uint32 ( ads , res , " sAMAccountType " , & t ) ) {
DEBUG ( 1 , ( " No sAMAccountType for %s !? \n " , name ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 11:17:46 +03:00
}
2001-12-05 07:48:51 +03:00
* type = ads_atype_map ( t ) ;
2001-12-03 11:17:46 +03:00
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
2001-12-03 11:17:46 +03:00
2001-12-09 09:10:02 +03:00
DEBUG ( 3 , ( " ads name_to_sid mapped %s \n " , name ) ) ;
2001-12-05 09:16:33 +03:00
done :
if ( res ) ads_msgfree ( ads , res ) ;
2001-12-05 07:48:51 +03:00
2001-12-05 09:16:33 +03:00
return status ;
2001-12-05 07:48:51 +03:00
}
/* convert a sid to a user or group name */
static NTSTATUS sid_to_name ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
DOM_SID * sid ,
char * * name ,
enum SID_NAME_USE * type )
{
2001-12-05 09:16:33 +03:00
ADS_STRUCT * ads = NULL ;
2001-12-05 07:48:51 +03:00
const char * attrs [ ] = { " sAMAccountName " , " sAMAccountType " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
2001-12-05 09:16:33 +03:00
void * msg = NULL ;
2001-12-05 07:48:51 +03:00
char * exp ;
char * sidstr ;
uint32 atype ;
char * s ;
2001-12-05 09:16:33 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2001-12-05 07:48:51 +03:00
DEBUG ( 3 , ( " ads: sid_to_name \n " ) ) ;
2001-12-05 10:05:53 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
2001-12-05 07:48:51 +03:00
2001-12-10 03:39:01 +03:00
sidstr = sid_binstring ( sid ) ;
2001-12-05 07:48:51 +03:00
asprintf ( & exp , " (objectSid=%s) " , sidstr ) ;
2001-12-08 14:18:56 +03:00
rc = ads_search_retry ( ads , & msg , exp , attrs ) ;
2001-12-05 07:48:51 +03:00
free ( exp ) ;
free ( sidstr ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " sid_to_name ads_search: %s \n " , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-05 07:48:51 +03:00
}
if ( ! ads_pull_uint32 ( ads , msg , " sAMAccountType " , & atype ) ) {
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-05 07:48:51 +03:00
}
s = ads_pull_string ( ads , mem_ctx , msg , " sAMAccountName " ) ;
* name = talloc_asprintf ( mem_ctx , " %s%s%s " , domain - > name , lp_winbind_separator ( ) , s ) ;
* type = ads_atype_map ( atype ) ;
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
2001-12-09 09:10:02 +03:00
DEBUG ( 3 , ( " ads sid_to_name mapped %s \n " , * name ) ) ;
2001-12-05 09:16:33 +03:00
done :
if ( msg ) ads_msgfree ( ads , msg ) ;
return status ;
2001-12-03 11:17:46 +03:00
}
2001-12-05 07:48:51 +03:00
/* Lookup user information from a rid */
2001-12-04 09:17:39 +03:00
static NTSTATUS query_user ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2001-12-05 07:48:51 +03:00
uint32 user_rid ,
2001-12-04 09:17:39 +03:00
WINBIND_USERINFO * info )
{
2001-12-05 09:16:33 +03:00
ADS_STRUCT * ads = NULL ;
2001-12-09 09:10:02 +03:00
const char * attrs [ ] = { " sAMAccountName " , " name " , " objectSid " ,
" primaryGroupID " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
int count ;
2001-12-05 09:16:33 +03:00
void * msg = NULL ;
2001-12-04 09:17:39 +03:00
char * exp ;
DOM_SID sid ;
2001-12-05 07:48:51 +03:00
char * sidstr ;
2001-12-05 09:16:33 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2001-12-04 09:17:39 +03:00
DEBUG ( 3 , ( " ads: query_user \n " ) ) ;
2001-12-05 07:48:51 +03:00
sid_from_rid ( domain , user_rid , & sid ) ;
2001-12-05 10:05:53 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
2001-12-04 09:17:39 +03:00
2001-12-10 03:39:01 +03:00
sidstr = sid_binstring ( & sid ) ;
2001-12-05 07:48:51 +03:00
asprintf ( & exp , " (objectSid=%s) " , sidstr ) ;
2001-12-08 14:18:56 +03:00
rc = ads_search_retry ( ads , & msg , exp , attrs ) ;
2001-12-04 09:17:39 +03:00
free ( exp ) ;
2001-12-05 07:48:51 +03:00
free ( sidstr ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " query_user(rid=%d) ads_search: %s \n " , user_rid , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 09:17:39 +03:00
}
count = ads_count_replies ( ads , msg ) ;
if ( count ! = 1 ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " query_user(rid=%d): Not found \n " , user_rid ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 09:17:39 +03:00
}
info - > acct_name = ads_pull_string ( ads , mem_ctx , msg , " sAMAccountName " ) ;
info - > full_name = ads_pull_string ( ads , mem_ctx , msg , " name " ) ;
if ( ! ads_pull_sid ( ads , msg , " objectSid " , & sid ) ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " No sid for %d !? \n " , user_rid ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 09:17:39 +03:00
}
if ( ! ads_pull_uint32 ( ads , msg , " primaryGroupID " , & info - > group_rid ) ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " No primary group for %d !? \n " , user_rid ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 09:17:39 +03:00
}
if ( ! sid_peek_rid ( & sid , & info - > user_rid ) ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " No rid for %d !? \n " , user_rid ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 09:17:39 +03:00
}
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
2001-12-09 09:10:02 +03:00
DEBUG ( 3 , ( " ads query_user gave %s \n " , info - > acct_name ) ) ;
2001-12-05 09:16:33 +03:00
done :
if ( msg ) ads_msgfree ( ads , msg ) ;
2001-12-04 09:17:39 +03:00
2001-12-05 09:16:33 +03:00
return status ;
2001-12-04 09:17:39 +03:00
}
2001-12-05 09:16:33 +03:00
2001-12-04 09:46:53 +03:00
/* Lookup groups a user is a member of. */
static NTSTATUS lookup_usergroups ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2001-12-05 07:48:51 +03:00
uint32 user_rid ,
2001-12-04 15:10:05 +03:00
uint32 * num_groups , uint32 * * user_gids )
2001-12-04 09:46:53 +03:00
{
2001-12-05 09:16:33 +03:00
ADS_STRUCT * ads = NULL ;
2001-12-04 15:10:05 +03:00
const char * attrs [ ] = { " distinguishedName " , NULL } ;
const char * attrs2 [ ] = { " tokenGroups " , " primaryGroupID " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
int count ;
2001-12-05 09:16:33 +03:00
void * msg = NULL ;
2001-12-04 15:10:05 +03:00
char * exp ;
char * user_dn ;
DOM_SID * sids ;
int i ;
uint32 primary_group ;
2001-12-05 07:48:51 +03:00
DOM_SID sid ;
char * sidstr ;
2001-12-05 09:16:33 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2001-12-04 15:10:05 +03:00
2001-12-11 01:10:16 +03:00
* num_groups = 0 ;
2001-12-04 15:10:05 +03:00
DEBUG ( 3 , ( " ads: lookup_usergroups \n " ) ) ;
( * num_groups ) = 0 ;
2001-12-05 07:48:51 +03:00
sid_from_rid ( domain , user_rid , & sid ) ;
2001-12-05 10:05:53 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
2001-12-04 15:10:05 +03:00
2001-12-10 03:39:01 +03:00
sidstr = sid_binstring ( & sid ) ;
2001-12-05 07:48:51 +03:00
asprintf ( & exp , " (objectSid=%s) " , sidstr ) ;
2001-12-08 14:18:56 +03:00
rc = ads_search_retry ( ads , & msg , exp , attrs ) ;
2001-12-04 15:10:05 +03:00
free ( exp ) ;
2001-12-05 07:48:51 +03:00
free ( sidstr ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " lookup_usergroups(rid=%d) ads_search: %s \n " , user_rid , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 15:10:05 +03:00
}
user_dn = ads_pull_string ( ads , mem_ctx , msg , " distinguishedName " ) ;
2001-12-05 10:11:26 +03:00
if ( msg ) ads_msgfree ( ads , msg ) ;
2001-12-08 14:18:56 +03:00
rc = ads_search_retry_dn ( ads , & msg , user_dn , attrs2 ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-05 07:48:51 +03:00
DEBUG ( 1 , ( " lookup_usergroups(rid=%d) ads_search tokenGroups: %s \n " , user_rid , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 15:10:05 +03:00
}
if ( ! ads_pull_uint32 ( ads , msg , " primaryGroupID " , & primary_group ) ) {
2001-12-19 11:44:23 +03:00
DEBUG ( 1 , ( " %s: No primary group for rid=%d !? \n " , domain - > name , user_rid ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-04 15:10:05 +03:00
}
count = ads_pull_sids ( ads , mem_ctx , msg , " tokenGroups " , & sids ) + 1 ;
( * user_gids ) = ( uint32 * ) talloc ( mem_ctx , sizeof ( uint32 ) * count ) ;
( * user_gids ) [ ( * num_groups ) + + ] = primary_group ;
for ( i = 1 ; i < count ; i + + ) {
uint32 rid ;
if ( ! sid_peek_rid ( & sids [ i - 1 ] , & rid ) ) continue ;
( * user_gids ) [ * num_groups ] = rid ;
( * num_groups ) + + ;
}
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
2001-12-09 09:10:02 +03:00
DEBUG ( 3 , ( " ads lookup_usergroups for rid=%d \n " , user_rid ) ) ;
2001-12-05 09:16:33 +03:00
done :
if ( msg ) ads_msgfree ( ads , msg ) ;
return status ;
2001-12-04 09:46:53 +03:00
}
2001-12-05 07:48:51 +03:00
static NTSTATUS lookup_groupmem ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
uint32 group_rid , uint32 * num_names ,
uint32 * * rid_mem , char * * * names ,
uint32 * * name_types )
{
2001-12-05 08:35:45 +03:00
DOM_SID group_sid ;
char * sidstr ;
const char * attrs [ ] = { " sAMAccountName " , " objectSid " , " sAMAccountType " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
int count ;
2001-12-05 09:16:33 +03:00
void * res = NULL , * msg = NULL ;
ADS_STRUCT * ads = NULL ;
2001-12-05 08:35:45 +03:00
char * exp ;
2001-12-05 09:16:33 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2001-12-05 08:35:45 +03:00
* num_names = 0 ;
2001-12-05 10:05:53 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
2001-12-05 08:35:45 +03:00
sid_from_rid ( domain , group_rid , & group_sid ) ;
2001-12-10 03:39:01 +03:00
sidstr = sid_binstring ( & group_sid ) ;
2001-12-05 08:35:45 +03:00
/* search for all users who have that group sid as primary group or as member */
2001-12-10 09:21:44 +03:00
asprintf ( & exp , " (&(objectCategory=user)(|(primaryGroupID=%d)(memberOf=%s))) " ,
2001-12-05 08:35:45 +03:00
group_rid , sidstr ) ;
2001-12-08 14:18:56 +03:00
rc = ads_search_retry ( ads , & res , exp , attrs ) ;
2001-12-05 09:16:33 +03:00
free ( exp ) ;
free ( sidstr ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
2001-12-05 08:35:45 +03:00
DEBUG ( 1 , ( " query_user_list ads_search: %s \n " , ads_errstr ( rc ) ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-05 08:35:45 +03:00
}
count = ads_count_replies ( ads , res ) ;
if ( count = = 0 ) {
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
goto done ;
2001-12-05 08:35:45 +03:00
}
( * rid_mem ) = talloc ( mem_ctx , sizeof ( uint32 ) * count ) ;
( * name_types ) = talloc ( mem_ctx , sizeof ( uint32 ) * count ) ;
( * names ) = talloc ( mem_ctx , sizeof ( char * ) * count ) ;
for ( msg = ads_first_entry ( ads , res ) ; msg ; msg = ads_next_entry ( ads , msg ) ) {
uint32 atype , rid ;
DOM_SID sid ;
( * names ) [ * num_names ] = ads_pull_string ( ads , mem_ctx , msg , " sAMAccountName " ) ;
if ( ! ads_pull_uint32 ( ads , msg , " sAMAccountType " , & atype ) ) {
continue ;
}
( * name_types ) [ * num_names ] = ads_atype_map ( atype ) ;
if ( ! ads_pull_sid ( ads , msg , " objectSid " , & sid ) ) {
DEBUG ( 1 , ( " No sid for %s !? \n " , ( * names ) [ * num_names ] ) ) ;
continue ;
}
if ( ! sid_peek_rid ( & sid , & rid ) ) {
DEBUG ( 1 , ( " No rid for %s !? \n " , ( * names ) [ * num_names ] ) ) ;
continue ;
}
( * rid_mem ) [ * num_names ] = rid ;
( * num_names ) + + ;
}
2001-12-05 09:16:33 +03:00
status = NT_STATUS_OK ;
2001-12-09 09:10:02 +03:00
DEBUG ( 3 , ( " ads lookup_groupmem for rid=%d \n " , group_rid ) ) ;
2001-12-05 09:16:33 +03:00
done :
if ( res ) ads_msgfree ( ads , res ) ;
2001-12-05 08:35:45 +03:00
2001-12-05 09:16:33 +03:00
return status ;
2001-12-05 07:48:51 +03:00
}
2001-12-05 10:52:44 +03:00
/* find the sequence number for a domain */
2001-12-10 02:59:42 +03:00
static NTSTATUS sequence_number ( struct winbindd_domain * domain , uint32 * seq )
2001-12-05 10:52:44 +03:00
{
ADS_STRUCT * ads = NULL ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
2001-12-05 10:52:44 +03:00
2001-12-10 02:59:42 +03:00
* seq = DOM_SEQUENCE_NONE ;
2001-12-05 10:52:44 +03:00
ads = ads_cached_connection ( domain ) ;
2001-12-10 02:59:42 +03:00
if ( ! ads ) return NT_STATUS_UNSUCCESSFUL ;
2001-12-05 10:52:44 +03:00
2001-12-19 15:21:12 +03:00
rc = ads_USN ( ads , seq ) ;
return ads_ntstatus ( rc ) ;
2001-12-05 10:52:44 +03:00
}
2001-12-10 05:25:19 +03:00
/* get a list of trusted domains */
static NTSTATUS trusted_domains ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
uint32 * num_domains ,
char * * * names ,
DOM_SID * * dom_sids )
{
2001-12-19 11:44:23 +03:00
ADS_STRUCT * ads = NULL ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
2001-12-19 11:44:23 +03:00
2001-12-10 05:25:19 +03:00
* num_domains = 0 ;
2001-12-19 11:44:23 +03:00
* names = NULL ;
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) return NT_STATUS_UNSUCCESSFUL ;
2001-12-19 15:21:12 +03:00
rc = ads_trusted_domains ( ads , mem_ctx , num_domains , names , dom_sids ) ;
2001-12-19 11:44:23 +03:00
2001-12-19 15:21:12 +03:00
return ads_ntstatus ( rc ) ;
2001-12-10 05:25:19 +03:00
}
/* find the domain sid for a domain */
static NTSTATUS domain_sid ( struct winbindd_domain * domain , DOM_SID * sid )
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
const char * attrs [ ] = { " objectSid " , NULL } ;
ADS_STRUCT * ads = NULL ;
void * res ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
2001-12-10 05:25:19 +03:00
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) goto done ;
rc = ads_do_search ( ads , ads - > bind_path , LDAP_SCOPE_BASE , " (objectclass=*) " ,
attrs , & res ) ;
2001-12-19 15:21:12 +03:00
if ( ! ADS_ERR_OK ( rc ) ) goto done ;
2001-12-10 05:25:19 +03:00
if ( ads_pull_sid ( ads , res , " objectSid " , sid ) ) {
status = NT_STATUS_OK ;
}
ads_msgfree ( ads , res ) ;
done :
return status ;
}
2001-12-03 14:11:14 +03:00
/* the ADS backend methods are exposed via this structure */
2001-12-03 09:04:18 +03:00
struct winbindd_methods ads_methods = {
2001-12-10 09:05:21 +03:00
True ,
2001-12-03 14:32:55 +03:00
query_user_list ,
2001-12-03 11:17:46 +03:00
enum_dom_groups ,
2001-12-03 14:11:14 +03:00
name_to_sid ,
2001-12-05 07:48:51 +03:00
sid_to_name ,
2001-12-04 09:46:53 +03:00
query_user ,
2001-12-05 07:48:51 +03:00
lookup_usergroups ,
2001-12-05 10:52:44 +03:00
lookup_groupmem ,
2001-12-10 05:25:19 +03:00
sequence_number ,
trusted_domains ,
domain_sid
2001-12-03 09:04:18 +03:00
} ;
# endif