2001-11-20 11:54:15 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-11-20 11:54:15 +03:00
ads ( active directory ) utility library
Copyright ( C ) Andrew Tridgell 2001
2001-12-20 06:54:52 +03:00
Copyright ( C ) Remus Koos 2001
2002-02-01 19:14:33 +03:00
Copyright ( C ) Jim McDonough 2002
2001-11-20 11:54:15 +03:00
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 "includes.h"
# ifdef HAVE_ADS
/*
connect to the LDAP server
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_connect ( ADS_STRUCT * ads )
2001-11-20 11:54:15 +03:00
{
int version = LDAP_VERSION3 ;
2002-01-26 01:07:46 +03:00
int code ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-11-20 11:54:15 +03:00
2001-12-05 12:19:25 +03:00
ads - > last_attempt = time ( NULL ) ;
2001-11-20 11:54:15 +03:00
ads - > ld = ldap_open ( ads - > ldap_server , ads - > ldap_port ) ;
if ( ! ads - > ld ) {
2002-02-03 01:06:10 +03:00
return ADS_ERROR_SYSTEM ( errno ) ;
2001-11-20 11:54:15 +03:00
}
2001-12-19 15:21:12 +03:00
status = ads_server_info ( ads ) ;
if ( ! ADS_ERR_OK ( status ) ) {
2001-12-08 14:18:56 +03:00
DEBUG ( 1 , ( " Failed to get ldap server info \n " ) ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-12-08 14:18:56 +03:00
}
2001-11-20 11:54:15 +03:00
ldap_set_option ( ads - > ld , LDAP_OPT_PROTOCOL_VERSION , & version ) ;
2001-12-05 12:46:53 +03:00
if ( ads - > password ) {
2002-01-26 01:07:46 +03:00
if ( ( code = ads_kinit_password ( ads ) ) )
return ADS_ERROR_KRB5 ( code ) ;
2001-12-05 12:46:53 +03:00
}
2001-12-19 15:21:12 +03:00
return ads_sasl_bind ( ads ) ;
2001-11-20 11:54:15 +03:00
}
2001-12-05 12:19:25 +03:00
/*
2001-12-08 14:18:56 +03:00
do a search with a timeout
2001-12-05 12:19:25 +03:00
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_do_search ( ADS_STRUCT * ads , const char * bind_path , int scope ,
const char * exp ,
const char * * attrs , void * * res )
2001-12-05 12:19:25 +03:00
{
struct timeval timeout ;
2001-12-19 15:21:12 +03:00
int rc ;
2001-12-05 12:19:25 +03:00
2001-12-08 14:18:56 +03:00
timeout . tv_sec = ADS_SEARCH_TIMEOUT ;
timeout . tv_usec = 0 ;
* res = NULL ;
2001-12-05 12:19:25 +03:00
2001-12-19 15:21:12 +03:00
rc = ldap_search_ext_s ( ads - > ld ,
bind_path , scope ,
2002-02-06 05:28:46 +03:00
exp , ( char * * ) attrs , 0 , NULL , NULL ,
2001-12-19 15:21:12 +03:00
& timeout , LDAP_NO_LIMIT , ( LDAPMessage * * ) res ) ;
return ADS_ERROR ( rc ) ;
2001-12-05 12:19:25 +03:00
}
2001-11-25 04:31:07 +03:00
/*
do a general ADS search
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_search ( ADS_STRUCT * ads , void * * res ,
const char * exp ,
const char * * attrs )
2001-11-25 04:31:07 +03:00
{
2001-12-08 14:18:56 +03:00
return ads_do_search ( ads , ads - > bind_path , LDAP_SCOPE_SUBTREE ,
exp , attrs , res ) ;
2001-11-25 04:31:07 +03:00
}
2001-12-04 15:08:16 +03:00
/*
do a search on a specific DistinguishedName
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_search_dn ( ADS_STRUCT * ads , void * * res ,
const char * dn ,
const char * * attrs )
2001-12-04 15:08:16 +03:00
{
2001-12-08 14:18:56 +03:00
return ads_do_search ( ads , dn , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs, res) ;
2001-12-04 15:08:16 +03:00
}
2001-12-05 09:26:56 +03:00
/*
free up memory from a ads_search
*/
void ads_msgfree ( ADS_STRUCT * ads , void * msg )
{
if ( ! msg ) return ;
ldap_msgfree ( msg ) ;
}
2001-11-25 04:31:07 +03:00
2002-02-02 05:04:01 +03:00
/*
free up memory from various ads requests
*/
void ads_memfree ( ADS_STRUCT * ads , void * mem )
{
if ( ! mem ) return ;
ldap_memfree ( mem ) ;
}
/*
get a dn from search results
*/
char * ads_get_dn ( ADS_STRUCT * ads , void * res )
{
return ldap_get_dn ( ads - > ld , res ) ;
}
2001-11-20 11:54:15 +03:00
/*
find a machine account given a hostname
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_find_machine_acct ( ADS_STRUCT * ads , void * * res , const char * host )
2001-11-20 11:54:15 +03:00
{
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-11-20 11:54:15 +03:00
char * exp ;
2002-01-03 14:59:33 +03:00
const char * attrs [ ] = { " * " , " nTSecurityDescriptor " , NULL } ;
2001-11-20 11:54:15 +03:00
/* the easiest way to find a machine account anywhere in the tree
is to look for hostname $ */
asprintf ( & exp , " (samAccountName=%s$) " , host ) ;
2002-01-03 14:59:33 +03:00
status = ads_search ( ads , res , exp , attrs ) ;
2001-11-20 11:54:15 +03:00
free ( exp ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-11-20 11:54:15 +03:00
}
2002-02-02 05:04:01 +03:00
/*
duplicate an already - assembled list of values so that it can be
freed as part of the standard msgfree call
*/
2002-02-12 21:22:33 +03:00
static char * * ads_dup_values ( TALLOC_CTX * ctx , char * * values )
2002-02-02 05:04:01 +03:00
{
char * * newvals ;
int i ;
# define ADS_MAX_NUM_VALUES 32
for ( i = 0 ; values [ i ] & & i < ADS_MAX_NUM_VALUES ; i + + ) ;
2002-02-12 21:22:33 +03:00
if ( ! ( newvals = talloc_zero ( ctx , ( i + 1 ) * sizeof ( char * ) ) ) )
2002-02-03 01:06:10 +03:00
return NULL ;
2002-02-02 05:04:01 +03:00
for ( i = 0 ; values [ i ] & & i < ADS_MAX_NUM_VALUES ; i + + )
newvals [ i ] = values [ i ] ;
newvals [ i ] = NULL ;
return newvals ;
}
2002-02-01 19:14:33 +03:00
/*
2002-02-12 21:22:33 +03:00
initialize a list of mods
2002-02-01 19:14:33 +03:00
*/
2002-02-12 21:22:33 +03:00
ADS_MODLIST ads_init_mods ( TALLOC_CTX * ctx )
2002-02-01 19:14:33 +03:00
{
2002-02-11 18:47:02 +03:00
# define ADS_MODLIST_ALLOC_SIZE 10
2002-02-01 19:14:33 +03:00
LDAPMod * * mods ;
2002-02-12 21:22:33 +03:00
if ( ( mods = ( LDAPMod * * ) talloc_zero ( ctx , sizeof ( LDAPMod * ) *
( ADS_MODLIST_ALLOC_SIZE + 1 ) ) ) )
2002-02-03 01:06:10 +03:00
/* -1 is safety to make sure we don't go over the end.
need to reset it to NULL before doing ldap modify */
2002-02-11 18:47:02 +03:00
mods [ ADS_MODLIST_ALLOC_SIZE ] = ( LDAPMod * ) - 1 ;
2002-02-01 19:14:33 +03:00
2002-02-11 18:47:02 +03:00
return mods ;
2002-02-01 19:14:33 +03:00
}
/*
add an attribute to the list , with values list already constructed
*/
2002-02-12 21:22:33 +03:00
static ADS_STATUS ads_modlist_add ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
int mod_op , char * name , char * * values )
2002-02-01 19:14:33 +03:00
{
int curmod ;
2002-02-11 18:47:02 +03:00
LDAPMod * * modlist = ( LDAPMod * * ) * mods ;
2002-02-01 19:14:33 +03:00
/* find the first empty slot */
2002-02-06 05:28:46 +03:00
for ( curmod = 0 ; modlist [ curmod ] & & modlist [ curmod ] ! = ( LDAPMod * ) - 1 ;
curmod + + ) ;
2002-02-11 18:47:02 +03:00
if ( modlist [ curmod ] = = ( LDAPMod * ) - 1 ) {
2002-02-12 21:22:33 +03:00
if ( ! ( modlist = talloc_realloc ( ctx , modlist ,
( curmod + ADS_MODLIST_ALLOC_SIZE + 1 ) * sizeof ( LDAPMod * ) ) ) )
2002-02-11 18:47:02 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
memset ( & modlist [ curmod ] , 0 ,
ADS_MODLIST_ALLOC_SIZE * sizeof ( LDAPMod * ) ) ;
modlist [ curmod + ADS_MODLIST_ALLOC_SIZE ] = ( LDAPMod * ) - 1 ;
* mods = modlist ;
}
2002-02-06 05:28:46 +03:00
2002-02-12 21:22:33 +03:00
if ( ! ( modlist [ curmod ] = talloc_zero ( ctx , sizeof ( LDAPMod ) ) ) )
2002-02-03 01:06:10 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-02-01 20:13:39 +03:00
modlist [ curmod ] - > mod_type = name ;
2002-02-12 21:22:33 +03:00
if ( mod_op & LDAP_MOD_BVALUES )
modlist [ curmod ] - > mod_bvalues = ( struct berval * * ) values ;
else
modlist [ curmod ] - > mod_values = values ;
2002-02-01 20:13:39 +03:00
modlist [ curmod ] - > mod_op = mod_op ;
2002-02-03 01:06:10 +03:00
return ADS_ERROR ( LDAP_SUCCESS ) ;
2002-02-01 19:14:33 +03:00
}
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_mod_add_list ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
char * name , char * * values )
2002-02-01 19:14:33 +03:00
{
2002-02-12 21:22:33 +03:00
char * * newvals = ads_dup_values ( ctx , values ) ;
2002-02-03 01:06:10 +03:00
if ( newvals )
2002-02-12 21:22:33 +03:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_ADD , name , newvals ) ;
2002-02-03 01:06:10 +03:00
else
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-02-01 19:14:33 +03:00
}
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_mod_repl_list ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
char * name , char * * values )
2002-02-01 19:14:33 +03:00
{
2002-02-02 05:04:01 +03:00
char * * newvals ;
if ( values & & * values ) {
2002-02-12 21:22:33 +03:00
if ( ! ( newvals = ads_dup_values ( ctx , values ) ) )
2002-02-03 01:06:10 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
else
2002-02-12 21:22:33 +03:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_REPLACE ,
2002-02-03 01:06:10 +03:00
name , newvals ) ;
2002-02-02 05:04:01 +03:00
}
2002-02-01 19:14:33 +03:00
else
2002-02-12 21:22:33 +03:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_DELETE , name , NULL ) ;
2002-02-01 19:14:33 +03:00
}
/*
add an attribute to the list , with values list to be built from args
*/
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_mod_add_var ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
int mod_op , char * name , . . . )
2002-02-01 19:14:33 +03:00
{
va_list ap ;
2002-02-03 01:06:10 +03:00
int num_vals , i , do_op ;
2002-02-01 19:14:33 +03:00
char * value , * * values ;
/* count the number of values */
va_start ( ap , name ) ;
for ( num_vals = 0 ; va_arg ( ap , char * ) ; num_vals + + ) ;
va_end ( ap ) ;
2002-02-03 01:06:10 +03:00
if ( num_vals ) {
2002-02-12 21:22:33 +03:00
if ( ! ( values = talloc_zero ( ctx , sizeof ( char * ) * ( num_vals + 1 ) ) ) )
2002-02-03 01:06:10 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
va_start ( ap , name ) ;
for ( i = 0 ; ( value = ( char * ) va_arg ( ap , char * ) ) & &
i < num_vals ; i + + )
values [ i ] = value ;
va_end ( ap ) ;
values [ i ] = NULL ;
do_op = mod_op ;
} else {
do_op = LDAP_MOD_DELETE ;
values = NULL ;
}
2002-02-12 21:22:33 +03:00
return ads_modlist_add ( ctx , mods , do_op , name , values ) ;
2002-02-03 01:06:10 +03:00
}
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_mod_add_ber ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
int mod_op , char * name , . . . )
2002-02-03 01:06:10 +03:00
{
va_list ap ;
int num_vals , i , do_op ;
char * value , * * values ;
/* count the number of values */
va_start ( ap , name ) ;
for ( num_vals = 0 ; va_arg ( ap , struct berval * ) ; num_vals + + ) ;
va_end ( ap ) ;
2002-02-01 19:14:33 +03:00
if ( num_vals ) {
2002-02-12 21:22:33 +03:00
if ( ! ( values = talloc_zero ( ctx , sizeof ( struct berval ) *
( num_vals + 1 ) ) ) )
2002-02-03 01:06:10 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-02-01 19:14:33 +03:00
va_start ( ap , name ) ;
for ( i = 0 ; ( value = ( char * ) va_arg ( ap , char * ) ) & &
i < num_vals ; i + + )
values [ i ] = value ;
va_end ( ap ) ;
values [ i ] = NULL ;
2002-02-03 01:06:10 +03:00
do_op = mod_op ;
} else {
do_op = LDAP_MOD_DELETE ;
2002-02-01 19:14:33 +03:00
values = NULL ;
2002-02-03 01:06:10 +03:00
}
do_op | = LDAP_MOD_BVALUES ;
2002-02-12 21:22:33 +03:00
return ads_modlist_add ( ctx , mods , do_op , name , values ) ;
2002-02-01 19:14:33 +03:00
}
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_mod_repl ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
char * name , char * val )
2002-02-01 19:14:33 +03:00
{
2002-02-02 05:04:01 +03:00
if ( val )
2002-02-12 21:22:33 +03:00
return ads_mod_add_var ( ctx , mods , LDAP_MOD_REPLACE ,
name , val , NULL ) ;
2002-02-02 05:04:01 +03:00
else
2002-02-12 21:22:33 +03:00
return ads_mod_add_var ( ctx , mods , LDAP_MOD_DELETE , name , NULL ) ;
2002-02-01 19:14:33 +03:00
}
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_mod_add ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
char * name , char * val )
2002-02-01 19:14:33 +03:00
{
2002-02-12 21:22:33 +03:00
return ads_mod_add_var ( ctx , mods , LDAP_MOD_ADD , name , val , NULL ) ;
2002-02-01 19:14:33 +03:00
}
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_mod_add_len ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
char * name , size_t size , char * val )
2002-02-01 19:14:33 +03:00
{
2002-02-12 21:22:33 +03:00
struct berval * bval = NULL ;
if ( ! ( bval = talloc_zero ( ctx , sizeof ( struct berval * ) ) ) )
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
if ( ! ( bval - > bv_val = talloc_zero ( ctx , sizeof ( char * ) ) ) )
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
bval - > bv_val = val ;
bval - > bv_len = size ;
return ads_mod_add_ber ( ctx , mods , LDAP_MOD_ADD , name , bval , NULL ) ;
}
ADS_STATUS ads_mod_repl_len ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
char * name , size_t size , char * val )
{
struct berval * bval = NULL ;
if ( ! ( bval = talloc_zero ( ctx , sizeof ( struct berval * ) ) ) )
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
if ( ! val )
return ads_mod_add_ber ( ctx , mods , LDAP_MOD_DELETE , name , NULL ) ;
else {
if ( ! ( bval - > bv_val = talloc_zero ( ctx , sizeof ( char * ) ) ) )
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
bval - > bv_val = val ;
bval - > bv_len = size ;
return ads_mod_add_ber ( ctx , mods , LDAP_MOD_ADD , name ,
bval , NULL ) ;
2002-02-01 19:14:33 +03:00
}
}
2002-02-11 18:47:02 +03:00
ADS_STATUS ads_gen_mod ( ADS_STRUCT * ads , const char * mod_dn , ADS_MODLIST mods )
2002-02-01 19:14:33 +03:00
{
int ret , i ;
2002-02-03 01:06:10 +03:00
/*
2002-02-06 05:28:46 +03:00
this control is needed to modify that contains a currently
non - existent attribute ( but allowable for the object ) to run
2002-02-03 01:06:10 +03:00
*/
2002-02-06 05:28:46 +03:00
LDAPControl PermitModify = {
" 1.2.840.113556.1.4.1413 " ,
{ 0 , NULL } ,
( char ) 1 } ;
LDAPControl * controls [ 2 ] = {
& PermitModify ,
NULL } ;
2002-02-03 01:06:10 +03:00
2002-02-01 19:14:33 +03:00
/* find the end of the list, marked by NULL or -1 */
2002-02-11 18:47:02 +03:00
for ( i = 0 ; ( mods [ i ] ! = 0 ) & & ( mods [ i ] ! = ( LDAPMod * ) - 1 ) ; i + + ) ;
2002-02-01 19:14:33 +03:00
/* make sure the end of the list is NULL */
mods [ i ] = NULL ;
2002-02-03 01:06:10 +03:00
ret = ldap_modify_ext_s ( ads - > ld , mod_dn , ( LDAPMod * * ) mods ,
controls , NULL ) ;
2002-02-01 19:14:33 +03:00
return ADS_ERROR ( ret ) ;
}
2001-11-20 11:54:15 +03:00
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_gen_add ( ADS_STRUCT * ads , const char * new_dn , ADS_MODLIST mods )
2001-11-20 11:54:15 +03:00
{
int i ;
2002-02-12 21:22:33 +03:00
/* find the end of the list, marked by NULL or -1 */
for ( i = 0 ; ( mods [ i ] ! = 0 ) & & ( mods [ i ] ! = ( LDAPMod * ) - 1 ) ; i + + ) ;
/* make sure the end of the list is NULL */
2001-11-20 11:54:15 +03:00
mods [ i ] = NULL ;
2002-02-12 21:22:33 +03:00
return ADS_ERROR ( ldap_add_s ( ads - > ld , new_dn , mods ) ) ;
2001-11-20 11:54:15 +03:00
}
2002-02-02 05:04:01 +03:00
ADS_STATUS ads_del_dn ( ADS_STRUCT * ads , char * del_dn )
{
return ADS_ERROR ( ldap_delete ( ads - > ld , del_dn ) ) ;
}
2002-01-16 05:22:30 +03:00
/*
build an org unit string
if org unit is Computers or blank then assume a container , otherwise
assume a \ separated list of organisational units
caller must free
*/
char * ads_ou_string ( const char * org_unit )
{
if ( ! org_unit | | ! * org_unit | | strcasecmp ( org_unit , " Computers " ) = = 0 ) {
return strdup ( " cn=Computers " ) ;
}
return ads_build_path ( org_unit , " \\ / " , " ou= " , 1 ) ;
}
2001-11-20 11:54:15 +03:00
/*
add a machine account to the ADS server
*/
2001-12-19 15:21:12 +03:00
static ADS_STATUS ads_add_machine_acct ( ADS_STRUCT * ads , const char * hostname ,
const char * org_unit )
2001-11-20 11:54:15 +03:00
{
2001-12-19 15:21:12 +03:00
ADS_STATUS ret ;
2001-11-20 11:54:15 +03:00
char * host_spn , * host_upn , * new_dn , * samAccountName , * controlstr ;
2002-01-16 05:22:30 +03:00
char * ou_str ;
2002-02-12 21:22:33 +03:00
TALLOC_CTX * ctx ;
ADS_MODLIST mods ;
2001-11-20 11:54:15 +03:00
2002-02-12 21:22:33 +03:00
if ( ! ( ctx = talloc_init_named ( " machine_account " ) ) )
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
if ( ! ( host_spn = talloc_asprintf ( ctx , " HOST/%s " , hostname ) ) )
goto done ;
if ( ! ( host_upn = talloc_asprintf ( ctx , " %s@%s " , host_spn , ads - > realm ) ) )
goto done ;
2002-01-16 05:22:30 +03:00
ou_str = ads_ou_string ( org_unit ) ;
2002-02-12 21:22:33 +03:00
new_dn = talloc_asprintf ( ctx , " cn=%s,%s,%s " , hostname , ou_str ,
ads - > bind_path ) ;
2002-01-16 05:22:30 +03:00
free ( ou_str ) ;
2002-02-12 21:22:33 +03:00
if ( ! new_dn )
goto done ;
if ( ! ( samAccountName = talloc_asprintf ( ctx , " %s$ " , hostname ) ) )
goto done ;
if ( ! ( controlstr = talloc_asprintf ( ctx , " %u " ,
UF_DONT_EXPIRE_PASSWD | UF_WORKSTATION_TRUST_ACCOUNT |
UF_TRUSTED_FOR_DELEGATION | UF_USE_DES_KEY_ONLY ) ) )
goto done ;
if ( ! ( mods = ads_init_mods ( ctx ) ) )
goto done ;
ads_mod_add ( ctx , & mods , " cn " , hostname ) ;
ads_mod_add ( ctx , & mods , " sAMAccountName " , samAccountName ) ;
ads_mod_add_var ( ctx , & mods , LDAP_MOD_ADD , " objectClass " ,
" top " , " person " , " organizationalPerson " ,
" user " , " computer " , NULL ) ;
ads_mod_add ( ctx , & mods , " userPrincipalName " , host_upn ) ;
ads_mod_add ( ctx , & mods , " servicePrincipalName " , host_spn ) ;
ads_mod_add ( ctx , & mods , " dNSHostName " , hostname ) ;
ads_mod_add ( ctx , & mods , " userAccountControl " , controlstr ) ;
ads_mod_add ( ctx , & mods , " operatingSystem " , " Samba " ) ;
ads_mod_add ( ctx , & mods , " operatingSystemVersion " , VERSION ) ;
ret = ads_gen_add ( ads , new_dn , mods ) ;
done :
talloc_destroy ( ctx ) ;
2001-11-20 11:54:15 +03:00
return ret ;
}
2001-11-25 04:06:56 +03:00
/*
dump a binary result from ldap
*/
static void dump_binary ( const char * field , struct berval * * values )
{
int i , j ;
for ( i = 0 ; values [ i ] ; i + + ) {
printf ( " %s: " , field ) ;
for ( j = 0 ; j < values [ i ] - > bv_len ; j + + ) {
printf ( " %02X " , ( unsigned char ) values [ i ] - > bv_val [ j ] ) ;
}
printf ( " \n " ) ;
}
}
2001-12-19 11:44:23 +03:00
/*
dump a sid result from ldap
*/
static void dump_sid ( const char * field , struct berval * * values )
{
int i ;
for ( i = 0 ; values [ i ] ; i + + ) {
DOM_SID sid ;
sid_parse ( values [ i ] - > bv_val , values [ i ] - > bv_len , & sid ) ;
printf ( " %s: %s \n " , field , sid_string_static ( & sid ) ) ;
}
}
2001-11-25 04:06:56 +03:00
/*
dump a string result from ldap
*/
static void dump_string ( const char * field , struct berval * * values )
{
int i ;
for ( i = 0 ; values [ i ] ; i + + ) {
printf ( " %s: %s \n " , field , values [ i ] - > bv_val ) ;
}
}
2001-11-20 11:54:15 +03:00
/*
dump a record from LDAP on stdout
used for debugging
*/
void ads_dump ( ADS_STRUCT * ads , void * res )
{
char * field ;
2001-12-03 09:04:18 +03:00
void * msg ;
2001-11-20 11:54:15 +03:00
BerElement * b ;
2001-11-25 04:06:56 +03:00
struct {
char * name ;
void ( * handler ) ( const char * , struct berval * * ) ;
} handlers [ ] = {
{ " objectGUID " , dump_binary } ,
2002-01-03 14:59:33 +03:00
{ " nTSecurityDescriptor " , dump_binary } ,
2001-12-19 11:44:23 +03:00
{ " objectSid " , dump_sid } ,
2001-11-25 04:06:56 +03:00
{ NULL , NULL }
} ;
2001-11-20 11:54:15 +03:00
2001-12-03 09:04:18 +03:00
for ( msg = ads_first_entry ( ads , res ) ; msg ; msg = ads_next_entry ( ads , msg ) ) {
for ( field = ldap_first_attribute ( ads - > ld , ( LDAPMessage * ) msg , & b ) ;
2001-11-20 11:54:15 +03:00
field ;
2001-12-03 09:04:18 +03:00
field = ldap_next_attribute ( ads - > ld , ( LDAPMessage * ) msg , b ) ) {
2001-11-25 04:06:56 +03:00
struct berval * * values ;
int i ;
2001-12-03 09:04:18 +03:00
values = ldap_get_values_len ( ads - > ld , ( LDAPMessage * ) msg , field ) ;
2001-11-25 04:06:56 +03:00
for ( i = 0 ; handlers [ i ] . name ; i + + ) {
if ( StrCaseCmp ( handlers [ i ] . name , field ) = = 0 ) {
handlers [ i ] . handler ( field , values ) ;
break ;
}
}
if ( ! handlers [ i ] . name ) {
dump_string ( field , values ) ;
2001-11-20 11:54:15 +03:00
}
2001-11-25 04:06:56 +03:00
ldap_value_free_len ( values ) ;
2001-11-20 11:54:15 +03:00
ldap_memfree ( field ) ;
}
ber_free ( b , 1 ) ;
printf ( " \n " ) ;
}
}
/*
count how many replies are in a LDAPMessage
*/
int ads_count_replies ( ADS_STRUCT * ads , void * res )
{
return ldap_count_entries ( ads - > ld , ( LDAPMessage * ) res ) ;
}
/*
join a machine to a realm , creating the machine account
and setting the machine password
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_join_realm ( ADS_STRUCT * ads , const char * hostname , const char * org_unit )
2001-11-20 11:54:15 +03:00
{
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-11-20 11:54:15 +03:00
LDAPMessage * res ;
2001-11-25 04:06:56 +03:00
char * host ;
/* hostname must be lowercase */
host = strdup ( hostname ) ;
strlower ( host ) ;
2001-11-20 11:54:15 +03:00
2001-12-19 15:21:12 +03:00
status = ads_find_machine_acct ( ads , ( void * * ) & res , host ) ;
if ( ADS_ERR_OK ( status ) & & ads_count_replies ( ads , res ) = = 1 ) {
2002-01-11 07:50:45 +03:00
DEBUG ( 0 , ( " Host account for %s already exists - deleting for readd \n " , host ) ) ;
status = ads_leave_realm ( ads , host ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to delete host '%s' from the '%s' realm. \n " ,
host , ads - > realm ) ) ;
return status ;
}
2001-11-20 11:54:15 +03:00
}
2001-12-19 15:21:12 +03:00
status = ads_add_machine_acct ( ads , host , org_unit ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 0 , ( " ads_add_machine_acct: %s \n " , ads_errstr ( status ) ) ) ;
return status ;
2001-11-20 11:54:15 +03:00
}
2001-12-19 15:21:12 +03:00
status = ads_find_machine_acct ( ads , ( void * * ) & res , host ) ;
if ( ! ADS_ERR_OK ( status ) ) {
2001-11-20 11:54:15 +03:00
DEBUG ( 0 , ( " Host account test failed \n " ) ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-11-20 11:54:15 +03:00
}
2001-11-25 04:06:56 +03:00
free ( host ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-11-24 17:16:41 +03:00
}
2001-11-20 11:54:15 +03:00
2001-11-24 17:16:41 +03:00
/*
delete a machine from the realm
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_leave_realm ( ADS_STRUCT * ads , const char * hostname )
2001-11-24 17:16:41 +03:00
{
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-11-24 17:16:41 +03:00
void * res ;
2001-11-25 04:06:56 +03:00
char * hostnameDN , * host ;
2001-12-19 15:21:12 +03:00
int rc ;
2001-11-25 04:06:56 +03:00
/* hostname must be lowercase */
host = strdup ( hostname ) ;
strlower ( host ) ;
2001-11-24 17:16:41 +03:00
2001-12-19 15:21:12 +03:00
status = ads_find_machine_acct ( ads , & res , host ) ;
if ( ! ADS_ERR_OK ( status ) ) {
2001-11-25 04:06:56 +03:00
DEBUG ( 0 , ( " Host account for %s does not exist. \n " , host ) ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-11-24 17:16:41 +03:00
}
2002-02-02 05:04:01 +03:00
hostnameDN = ads_get_dn ( ads , ( LDAPMessage * ) res ) ;
2001-11-24 17:16:41 +03:00
rc = ldap_delete_s ( ads - > ld , hostnameDN ) ;
2002-02-02 05:04:01 +03:00
ads_memfree ( ads , hostnameDN ) ;
2001-11-24 17:16:41 +03:00
if ( rc ! = LDAP_SUCCESS ) {
2001-12-19 15:21:12 +03:00
return ADS_ERROR ( rc ) ;
2001-11-24 17:16:41 +03:00
}
2001-12-19 15:21:12 +03:00
status = ads_find_machine_acct ( ads , & res , host ) ;
if ( ADS_ERR_OK ( status ) & & ads_count_replies ( ads , res ) = = 1 ) {
DEBUG ( 0 , ( " Failed to remove host account. \n " ) ) ;
return status ;
2001-11-24 17:16:41 +03:00
}
2001-11-25 04:06:56 +03:00
free ( host ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-11-20 11:54:15 +03:00
}
2001-11-24 17:16:41 +03:00
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_set_machine_password ( ADS_STRUCT * ads ,
const char * hostname ,
const char * password )
2001-11-24 17:16:41 +03:00
{
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-11-25 04:06:56 +03:00
char * host = strdup ( hostname ) ;
2001-12-20 06:54:52 +03:00
char * principal ;
2001-11-25 04:06:56 +03:00
strlower ( host ) ;
2001-12-20 06:54:52 +03:00
asprintf ( & principal , " %s@%s " , host , ads - > realm ) ;
status = krb5_set_password ( ads - > kdc_server , principal , password ) ;
2001-11-25 04:06:56 +03:00
free ( host ) ;
2001-12-20 06:54:52 +03:00
free ( principal ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-11-24 17:16:41 +03:00
}
2001-12-03 09:04:18 +03:00
/*
pull the first entry from a ADS result
*/
void * ads_first_entry ( ADS_STRUCT * ads , void * res )
{
return ( void * ) ldap_first_entry ( ads - > ld , ( LDAPMessage * ) res ) ;
}
/*
pull the next entry from a ADS result
*/
void * ads_next_entry ( ADS_STRUCT * ads , void * res )
{
return ( void * ) ldap_next_entry ( ads - > ld , ( LDAPMessage * ) res ) ;
}
/*
pull a single string from a ADS result
*/
char * ads_pull_string ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx , void * msg , const char * field )
{
char * * values ;
2001-12-05 10:35:57 +03:00
char * ret = NULL ;
2001-12-03 09:04:18 +03:00
values = ldap_get_values ( ads - > ld , msg , field ) ;
2001-12-05 10:35:57 +03:00
if ( ! values ) return NULL ;
if ( values [ 0 ] ) {
ret = talloc_strdup ( mem_ctx , values [ 0 ] ) ;
}
2001-12-03 09:04:18 +03:00
ldap_value_free ( values ) ;
return ret ;
}
/*
pull a single uint32 from a ADS result
*/
BOOL ads_pull_uint32 ( ADS_STRUCT * ads ,
void * msg , const char * field , uint32 * v )
{
char * * values ;
values = ldap_get_values ( ads - > ld , msg , field ) ;
2001-12-05 10:35:57 +03:00
if ( ! values ) return False ;
if ( ! values [ 0 ] ) {
ldap_value_free ( values ) ;
return False ;
}
2001-12-03 09:04:18 +03:00
* v = atoi ( values [ 0 ] ) ;
ldap_value_free ( values ) ;
return True ;
}
/*
pull a single DOM_SID from a ADS result
*/
BOOL ads_pull_sid ( ADS_STRUCT * ads ,
void * msg , const char * field , DOM_SID * sid )
{
struct berval * * values ;
2001-12-05 10:35:57 +03:00
BOOL ret = False ;
2001-12-03 09:04:18 +03:00
values = ldap_get_values_len ( ads - > ld , msg , field ) ;
2001-12-05 10:35:57 +03:00
if ( ! values ) return False ;
2001-12-03 09:04:18 +03:00
2001-12-05 10:35:57 +03:00
if ( values [ 0 ] ) {
ret = sid_parse ( values [ 0 ] - > bv_val , values [ 0 ] - > bv_len , sid ) ;
}
2001-12-03 09:04:18 +03:00
ldap_value_free_len ( values ) ;
return ret ;
}
2001-12-04 15:08:16 +03:00
/*
pull an array of DOM_SIDs from a ADS result
return the count of SIDs pulled
*/
int ads_pull_sids ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
void * msg , const char * field , DOM_SID * * sids )
{
struct berval * * values ;
BOOL ret ;
int count , i ;
values = ldap_get_values_len ( ads - > ld , msg , field ) ;
if ( ! values ) return 0 ;
for ( i = 0 ; values [ i ] ; i + + ) /* nop */ ;
( * sids ) = talloc ( mem_ctx , sizeof ( DOM_SID ) * i ) ;
count = 0 ;
for ( i = 0 ; values [ i ] ; i + + ) {
ret = sid_parse ( values [ i ] - > bv_val , values [ i ] - > bv_len , & ( * sids ) [ count ] ) ;
if ( ret ) count + + ;
}
ldap_value_free_len ( values ) ;
return count ;
}
2001-12-03 09:04:18 +03:00
2001-11-28 06:56:30 +03:00
/* find the update serial number - this is the core of the ldap cache */
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_USN ( ADS_STRUCT * ads , uint32 * usn )
2001-11-28 06:56:30 +03:00
{
const char * attrs [ ] = { " highestCommittedUSN " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-11-28 06:56:30 +03:00
void * res ;
2001-12-19 15:21:12 +03:00
status = ads_do_search ( ads , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
if ( ads_count_replies ( ads , res ) ! = 1 ) {
return ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
}
ads_pull_uint32 ( ads , res , " highestCommittedUSN " , usn ) ;
2001-12-05 12:19:25 +03:00
ads_msgfree ( ads , res ) ;
2001-12-19 15:21:12 +03:00
return ADS_SUCCESS ;
2001-11-28 06:56:30 +03:00
}
2001-12-03 09:04:18 +03:00
2001-12-08 14:18:56 +03:00
/* find the servers name and realm - this can be done before authentication
The ldapServiceName field on w2k looks like this :
vnet3 . home . samba . org : win2000 - vnet3 $ @ VNET3 . HOME . SAMBA . ORG
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_server_info ( ADS_STRUCT * ads )
2001-12-08 14:18:56 +03:00
{
const char * attrs [ ] = { " ldapServiceName " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-12-08 14:18:56 +03:00
void * res ;
char * * values ;
2001-12-08 15:00:27 +03:00
char * p ;
2001-12-08 14:18:56 +03:00
2001-12-19 15:21:12 +03:00
status = ads_do_search ( ads , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
2001-12-08 14:18:56 +03:00
values = ldap_get_values ( ads - > ld , res , " ldapServiceName " ) ;
2001-12-19 15:21:12 +03:00
if ( ! values | | ! values [ 0 ] ) return ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
2001-12-08 14:18:56 +03:00
p = strchr ( values [ 0 ] , ' : ' ) ;
if ( ! p ) {
ldap_value_free ( values ) ;
ldap_msgfree ( res ) ;
2001-12-19 15:21:12 +03:00
return ADS_ERROR ( LDAP_DECODING_ERROR ) ;
2001-12-08 14:18:56 +03:00
}
SAFE_FREE ( ads - > ldap_server_name ) ;
ads - > ldap_server_name = strdup ( p + 1 ) ;
p = strchr ( ads - > ldap_server_name , ' $ ' ) ;
if ( ! p | | p [ 1 ] ! = ' @ ' ) {
ldap_value_free ( values ) ;
ldap_msgfree ( res ) ;
SAFE_FREE ( ads - > ldap_server_name ) ;
2001-12-19 15:21:12 +03:00
return ADS_ERROR ( LDAP_DECODING_ERROR ) ;
2001-12-08 14:18:56 +03:00
}
* p = 0 ;
2001-12-19 11:44:23 +03:00
SAFE_FREE ( ads - > server_realm ) ;
SAFE_FREE ( ads - > bind_path ) ;
ads - > server_realm = strdup ( p + 2 ) ;
ads - > bind_path = ads_build_dn ( ads - > server_realm ) ;
2001-12-08 14:18:56 +03:00
/* in case the realm isn't configured in smb.conf */
if ( ! ads - > realm | | ! ads - > realm [ 0 ] ) {
SAFE_FREE ( ads - > realm ) ;
2001-12-19 11:44:23 +03:00
ads - > realm = strdup ( ads - > server_realm ) ;
2001-12-08 14:18:56 +03:00
}
2001-12-08 15:00:27 +03:00
DEBUG ( 3 , ( " got ldap server name %s@%s \n " ,
ads - > ldap_server_name , ads - > realm ) ) ;
2001-12-08 14:18:56 +03:00
2001-12-19 15:21:12 +03:00
return ADS_SUCCESS ;
2001-12-08 14:18:56 +03:00
}
2001-12-03 09:04:18 +03:00
2001-12-19 11:44:23 +03:00
/*
find the list of trusted domains
*/
2001-12-19 15:21:12 +03:00
ADS_STATUS ads_trusted_domains ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
int * num_trusts , char * * * names , DOM_SID * * sids )
2001-12-19 11:44:23 +03:00
{
const char * attrs [ ] = { " flatName " , " securityIdentifier " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2001-12-19 11:44:23 +03:00
void * res , * msg ;
int count , i ;
* num_trusts = 0 ;
2001-12-19 15:21:12 +03:00
status = ads_search ( ads , & res , " (objectcategory=trustedDomain) " , attrs ) ;
if ( ! ADS_ERR_OK ( status ) ) return status ;
2001-12-19 11:44:23 +03:00
count = ads_count_replies ( ads , res ) ;
if ( count = = 0 ) {
ads_msgfree ( ads , res ) ;
2001-12-19 15:21:12 +03:00
return ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
2001-12-19 11:44:23 +03:00
}
( * names ) = talloc ( mem_ctx , sizeof ( char * ) * count ) ;
( * sids ) = talloc ( mem_ctx , sizeof ( DOM_SID ) * count ) ;
2001-12-19 15:21:12 +03:00
if ( ! * names | | ! * sids ) return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2001-12-19 11:44:23 +03:00
for ( i = 0 , msg = ads_first_entry ( ads , res ) ; msg ; msg = ads_next_entry ( ads , msg ) ) {
( * names ) [ i ] = ads_pull_string ( ads , mem_ctx , msg , " flatName " ) ;
2002-02-07 05:44:37 +03:00
if ( ads_pull_sid ( ads , msg , " securityIdentifier " , & ( * sids ) [ i ] ) ) {
i + + ;
}
2001-12-19 11:44:23 +03:00
}
ads_msgfree ( ads , res ) ;
* num_trusts = i ;
2001-12-19 15:21:12 +03:00
return ADS_SUCCESS ;
2001-12-19 11:44:23 +03:00
}
2001-12-21 02:35:14 +03:00
/* find the domain sid for our domain */
ADS_STATUS ads_domain_sid ( ADS_STRUCT * ads , DOM_SID * sid )
{
const char * attrs [ ] = { " objectSid " , NULL } ;
void * res ;
ADS_STATUS rc ;
rc = ads_do_search ( ads , ads - > bind_path , LDAP_SCOPE_BASE , " (objectclass=*) " ,
attrs , & res ) ;
if ( ! ADS_ERR_OK ( rc ) ) return rc ;
if ( ! ads_pull_sid ( ads , res , " objectSid " , sid ) ) {
return ADS_ERROR_SYSTEM ( ENOENT ) ;
}
ads_msgfree ( ads , res ) ;
return ADS_SUCCESS ;
}
2001-11-20 11:54:15 +03:00
# endif