2001-12-03 09:04:18 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-12-03 09:04:18 +03:00
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
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
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 ;
2002-03-12 23:17:34 +03:00
char * bp ;
2001-12-08 14:18:56 +03:00
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
}
2002-03-12 23:17:34 +03:00
bp = strdup ( bind_path ) ;
2001-12-08 14:18:56 +03:00
while ( count - - ) {
2002-03-20 01:15:32 +03:00
status = ads_do_search_all ( ads , bp , scope , exp , attrs , res ) ;
2001-12-19 15:21:12 +03:00
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 ) ) ) ;
2002-03-12 23:17:34 +03:00
free ( bp ) ;
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 ;
2002-08-17 21:00:51 +04:00
DEBUG ( 3 , ( " Reopening ads connection to realm '%s' after error %s \n " ,
ads - > config . realm , ads_errstr ( status ) ) ) ;
2001-12-08 14:18:56 +03:00
if ( ads - > ld ) {
2002-03-12 23:17:34 +03:00
ldap_unbind ( ads - > ld ) ;
2001-12-08 14:18:56 +03:00
}
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 ) ;
2002-03-12 23:17:34 +03:00
free ( bp ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-12-08 14:18:56 +03:00
}
}
2002-03-12 23:17:34 +03:00
free ( bp ) ;
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
{
2002-08-17 21:00:51 +04:00
return ads_do_search_retry ( ads , ads - > config . bind_path , LDAP_SCOPE_SUBTREE ,
2001-12-08 14:18:56 +03:00
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-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 ) ;
2002-08-17 21:00:51 +04:00
ads = ads_init ( domain - > alt_name , domain - > name , 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 */
2002-08-17 21:00:51 +04:00
SAFE_FREE ( ads - > auth . password ) ;
ads - > auth . password = secrets_fetch_machine_password ( ) ;
if ( primary_realm ) {
SAFE_FREE ( ads - > auth . realm ) ;
ads - > auth . realm = strdup ( primary_realm ) ;
}
2001-12-08 14:18:56 +03:00
2001-12-19 15:21:12 +03:00
status = ads_connect ( ads ) ;
2002-08-17 21:00:51 +04:00
if ( ! ADS_ERR_OK ( status ) | | ! ads - > config . realm ) {
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 & &
2002-09-25 19:19:00 +04:00
status . err . rc = = ECONNREFUSED ) {
2001-12-19 15:38:52 +03:00
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 ) {
2002-08-17 21:00:51 +04:00
primary_realm = strdup ( ads - > config . realm ) ;
2001-12-19 11:44:23 +03:00
}
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 ) {
2002-09-25 19:19:00 +04:00
case ATYPE_GLOBAL_GROUP :
2001-12-05 07:48:51 +03:00
return SID_NAME_DOM_GRP ;
2002-09-25 19:19:00 +04:00
case ATYPE_ACCOUNT :
2001-12-05 07:48:51 +03:00
return SID_NAME_USER ;
default :
DEBUG ( 1 , ( " hmm, need to map account type 0x%x \n " , atype ) ) ;
}
return SID_NAME_UNKNOWN ;
}
2002-07-15 14:35:28 +04:00
/*
in order to support usernames longer than 21 characters we need to
use both the sAMAccountName and the userPrincipalName attributes
It seems that not all users have the userPrincipalName attribute set
*/
static char * pull_username ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx , void * msg )
{
char * ret , * p ;
ret = ads_pull_string ( ads , mem_ctx , msg , " userPrincipalName " ) ;
if ( ret & & ( p = strchr ( ret , ' @ ' ) ) ) {
* p = 0 ;
return ret ;
}
return ads_pull_string ( ads , mem_ctx , msg , " sAMAccountName " ) ;
}
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 ;
2002-07-15 14:35:28 +04:00
const char * attrs [ ] = { " userPrincipalName " ,
" 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
}
2002-04-11 18:30:31 +04:00
( * info ) = talloc_zero ( 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
2002-07-15 14:35:28 +04:00
name = pull_username ( ads , mem_ctx , msg ) ;
2001-12-03 09:04:18 +03:00
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 ;
}
2002-07-15 14:35:28 +04:00
if ( ! sid_peek_check_rid ( & domain - > sid , & sid , & rid ) ) {
2001-12-03 09:04:18 +03:00
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 ;
2002-07-15 14:35:28 +04:00
const char * attrs [ ] = { " userPrincipalName " , " sAMAccountName " ,
" name " , " objectSid " ,
2001-12-03 09:04:18 +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 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 ) ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 1 , ( " enum_dom_groups 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 ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 1 , ( " enum_dom_groups: No groups found \n " ) ) ;
2001-12-05 09:16:33 +03:00
goto done ;
2001-12-03 09:04:18 +03:00
}
2002-04-11 18:30:31 +04:00
( * info ) = talloc_zero ( 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 ) | |
2002-09-25 19:19:00 +04:00
! ( account_type & ATYPE_GLOBAL_GROUP ) ) continue ;
2001-12-03 09:04:18 +03:00
2002-07-15 14:35:28 +04:00
name = pull_username ( ads , mem_ctx , msg ) ;
2001-12-03 09:04:18 +03:00
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 ;
}
2002-07-15 14:35:28 +04:00
if ( ! sid_peek_check_rid ( & domain - > sid , & sid , & rid ) ) {
2001-12-03 09:04:18 +03:00
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-05 09:16:33 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
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
2002-07-15 14:35:28 +04:00
/* accept either the win2000 or the pre-win2000 username */
asprintf ( & exp , " (|(sAMAccountName=%s)(userPrincipalName=%s@%s)) " ,
2002-08-17 21:00:51 +04:00
name , name , ads - > config . realm ) ;
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 ;
2002-07-15 14:35:28 +04:00
const char * attrs [ ] = { " userPrincipalName " ,
" 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 ;
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
}
2002-07-15 14:35:28 +04:00
* name = pull_username ( ads , mem_ctx , msg ) ;
2001-12-05 07:48:51 +03:00
* 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
2002-07-15 14:35:28 +04:00
/* convert a DN to a name, rid and name type
this might become a major speed bottleneck if groups have
lots of users , in which case we could cache the results
*/
static BOOL dn_lookup ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
const char * dn ,
char * * name , uint32 * name_type , uint32 * rid )
{
char * exp ;
void * res = NULL ;
const char * attrs [ ] = { " userPrincipalName " , " sAMAccountName " ,
" objectSid " , " sAMAccountType " , NULL } ;
ADS_STATUS rc ;
uint32 atype ;
DOM_SID sid ;
asprintf ( & exp , " (distinguishedName=%s) " , dn ) ;
rc = ads_search_retry ( ads , & res , exp , attrs ) ;
free ( exp ) ;
if ( ! ADS_ERR_OK ( rc ) ) {
goto failed ;
}
( * name ) = pull_username ( ads , mem_ctx , res ) ;
if ( ! ads_pull_uint32 ( ads , res , " sAMAccountType " , & atype ) ) {
goto failed ;
}
( * name_type ) = ads_atype_map ( atype ) ;
if ( ! ads_pull_sid ( ads , res , " objectSid " , & sid ) | |
! sid_peek_rid ( & sid , rid ) ) {
goto failed ;
}
if ( res ) ads_msgfree ( ads , res ) ;
return True ;
failed :
if ( res ) ads_msgfree ( ads , res ) ;
return False ;
}
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 ;
2002-07-15 14:35:28 +04:00
const char * attrs [ ] = { " userPrincipalName " ,
" sAMAccountName " ,
" name " , " objectSid " ,
2001-12-09 09:10:02 +03:00
" 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
}
2002-07-15 14:35:28 +04:00
info - > acct_name = pull_username ( ads , mem_ctx , msg ) ;
2001-12-04 09:17:39 +03:00
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
}
2002-07-15 14:35:28 +04:00
if ( ! sid_peek_check_rid ( & domain - > sid , & 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 ;
2002-04-11 18:30:31 +04:00
( * user_gids ) = ( uint32 * ) talloc_zero ( mem_ctx , sizeof ( uint32 ) * count ) ;
2001-12-04 15:10:05 +03:00
( * user_gids ) [ ( * num_groups ) + + ] = primary_group ;
for ( i = 1 ; i < count ; i + + ) {
uint32 rid ;
2002-07-15 14:35:28 +04:00
if ( ! sid_peek_check_rid ( & domain - > sid , & sids [ i - 1 ] , & rid ) ) continue ;
2001-12-04 15:10:05 +03:00
( * 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
}
2002-07-15 14:35:28 +04:00
/*
find the members of a group , given a group rid and domain
*/
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 ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
int count ;
2002-07-15 14:35:28 +04:00
void * res = NULL ;
2001-12-05 09:16:33 +03:00
ADS_STRUCT * ads = NULL ;
2002-07-15 14:35:28 +04:00
char * exp ;
2001-12-05 09:16:33 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2002-07-15 14:35:28 +04:00
char * sidstr ;
const char * attrs [ ] = { " member " , NULL } ;
char * * members ;
int i , num_members ;
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 ) ;
2002-07-15 14:35:28 +04:00
sidstr = sid_binstring ( & group_sid ) ;
2002-03-21 05:28:23 +03:00
2002-07-15 14:35:28 +04:00
/* search for all members of the group */
asprintf ( & exp , " (objectSid=%s) " , 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 ) ;
2002-07-15 14:35:28 +04:00
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
}
2002-07-15 14:35:28 +04:00
members = ads_pull_strings ( ads , mem_ctx , res , " member " ) ;
if ( ! members ) {
/* no members? ok ... */
status = NT_STATUS_OK ;
goto done ;
}
2001-12-05 08:35:45 +03:00
2002-07-15 14:35:28 +04:00
/* now we need to turn a list of members into rids, names and name types
the problem is that the members are in the form of distinguised names
*/
for ( i = 0 ; members [ i ] ; i + + ) /* noop */ ;
num_members = i ;
2001-12-05 08:35:45 +03:00
2002-07-15 14:35:28 +04:00
( * rid_mem ) = talloc_zero ( mem_ctx , sizeof ( uint32 ) * num_members ) ;
( * name_types ) = talloc_zero ( mem_ctx , sizeof ( uint32 ) * num_members ) ;
( * names ) = talloc_zero ( mem_ctx , sizeof ( char * ) * num_members ) ;
for ( i = 0 ; i < num_members ; i + + ) {
uint32 name_type , rid ;
char * name ;
if ( dn_lookup ( ads , mem_ctx , members [ i ] , & name , & name_type , & rid ) ) {
( * names ) [ * num_names ] = name ;
( * name_types ) [ * num_names ] = name_type ;
( * rid_mem ) [ * num_names ] = rid ;
( * num_names ) + + ;
2001-12-05 08:35:45 +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 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
}
2002-07-15 14:35:28 +04: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 ) ;
2002-03-21 05:28:23 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
/* its a dead connection */
ads_destroy ( & ads ) ;
domain - > private = NULL ;
}
2001-12-19 15:21:12 +03:00
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 ,
2002-08-17 21:00:51 +04:00
char * * * alt_names ,
2001-12-10 05:25:19 +03:00
DOM_SID * * dom_sids )
{
2001-12-21 02:35:14 +03:00
ADS_STRUCT * ads ;
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 ;
2002-08-17 21:00:51 +04:00
rc = ads_trusted_domains ( ads , mem_ctx , num_domains , names , alt_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 )
{
2001-12-21 02:35:14 +03:00
ADS_STRUCT * ads ;
2001-12-19 15:21:12 +03:00
ADS_STATUS rc ;
2001-12-10 05:25:19 +03:00
ads = ads_cached_connection ( domain ) ;
2001-12-21 02:35:14 +03:00
if ( ! ads ) return NT_STATUS_UNSUCCESSFUL ;
2001-12-10 05:25:19 +03:00
2001-12-21 02:35:14 +03:00
rc = ads_domain_sid ( ads , sid ) ;
2001-12-10 05:25:19 +03:00
2002-03-09 22:36:53 +03:00
if ( ! ADS_ERR_OK ( rc ) ) {
/* its a dead connection */
2002-03-12 23:17:34 +03:00
ads_destroy ( & ads ) ;
2002-03-09 22:36:53 +03:00
domain - > private = NULL ;
}
2001-12-21 02:35:14 +03:00
return ads_ntstatus ( rc ) ;
2001-12-10 05:25:19 +03:00
}
2002-08-17 21:00:51 +04:00
/* find alternate names list for the domain - for ADS this is the
netbios name */
static NTSTATUS alternate_name ( struct winbindd_domain * domain )
{
ADS_STRUCT * ads ;
ADS_STATUS rc ;
TALLOC_CTX * ctx ;
char * workgroup ;
ads = ads_cached_connection ( domain ) ;
if ( ! ads ) return NT_STATUS_UNSUCCESSFUL ;
if ( ! ( ctx = talloc_init_named ( " alternate_name " ) ) ) {
return NT_STATUS_NO_MEMORY ;
}
rc = ads_workgroup_name ( ads , ctx , & workgroup ) ;
if ( ADS_ERR_OK ( rc ) ) {
fstrcpy ( domain - > name , workgroup ) ;
fstrcpy ( domain - > alt_name , ads - > config . realm ) ;
strupper ( domain - > alt_name ) ;
strupper ( domain - > name ) ;
}
talloc_destroy ( ctx ) ;
return ads_ntstatus ( rc ) ;
}
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 ,
2002-08-17 21:00:51 +04:00
domain_sid ,
alternate_name
2001-12-03 09:04:18 +03:00
} ;
# endif