2006-01-17 06:44:37 +03:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Brad Henry 2005
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-01-17 06:44:37 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-01-17 06:44:37 +03:00
*/
# include "includes.h"
# include "libnet/libnet.h"
# include "libcli/cldap/cldap.h"
2011-02-10 06:12:51 +03:00
# include <ldb.h>
# include <ldb_errors.h>
2007-04-27 18:31:26 +04:00
# include "libcli/resolve/resolve.h"
2007-12-03 20:47:35 +03:00
# include "param/param.h"
2010-02-25 14:47:38 +03:00
# include "lib/tsocket/tsocket.h"
2006-01-17 06:44:37 +03:00
2007-12-03 20:47:35 +03:00
/**
2006-01-17 06:44:37 +03:00
* 1. Setup a CLDAP socket .
* 2. Lookup the default Site - Name .
*/
2008-04-22 01:58:23 +04:00
NTSTATUS libnet_FindSite ( TALLOC_CTX * ctx , struct libnet_context * lctx , struct libnet_JoinSite * r )
2006-01-17 06:44:37 +03:00
{
NTSTATUS status ;
TALLOC_CTX * tmp_ctx ;
char * site_name_str ;
char * config_dn_str ;
char * server_dn_str ;
struct cldap_socket * cldap = NULL ;
struct cldap_netlogon search ;
2010-02-25 14:47:38 +03:00
int ret ;
struct tsocket_address * dest_address ;
2006-01-17 06:44:37 +03:00
tmp_ctx = talloc_named ( ctx , 0 , " libnet_FindSite temp context " ) ;
if ( ! tmp_ctx ) {
r - > out . error_string = NULL ;
return NT_STATUS_NO_MEMORY ;
}
/* Resolve the site name. */
ZERO_STRUCT ( search ) ;
2010-02-25 14:47:38 +03:00
search . in . dest_address = NULL ;
search . in . dest_port = 0 ;
2006-01-17 06:44:37 +03:00
search . in . acct_control = - 1 ;
2008-05-16 07:03:01 +04:00
search . in . version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX ;
search . in . map_response = true ;
2006-01-17 06:44:37 +03:00
2010-02-25 14:47:38 +03:00
ret = tsocket_address_inet_from_strings ( tmp_ctx , " ip " ,
r - > in . dest_address ,
r - > in . cldap_port ,
& dest_address ) ;
if ( ret ! = 0 ) {
r - > out . error_string = NULL ;
2011-06-20 08:55:32 +04:00
status = map_nt_error_from_unix_common ( errno ) ;
2013-09-04 10:50:14 +04:00
talloc_free ( tmp_ctx ) ;
2010-02-25 14:47:38 +03:00
return status ;
}
2009-02-13 15:13:54 +03:00
/* we want to use non async calls, so we're not passing an event context */
2011-10-10 17:58:24 +04:00
status = cldap_socket_init ( tmp_ctx , NULL , dest_address , & cldap ) ;
2009-02-13 15:13:54 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
r - > out . error_string = NULL ;
return status ;
}
2010-05-09 19:20:01 +04:00
status = cldap_netlogon ( cldap , tmp_ctx , & search ) ;
2008-10-02 10:09:25 +04:00
if ( ! NT_STATUS_IS_OK ( status )
2013-01-03 18:40:49 +04:00
| | search . out . netlogon . data . nt5_ex . client_site = = NULL
| | search . out . netlogon . data . nt5_ex . client_site [ 0 ] = = ' \0 ' ) {
2006-01-17 06:44:37 +03:00
/*
If cldap_netlogon ( ) returns in error ,
default to using Default - First - Site - Name .
*/
site_name_str = talloc_asprintf ( tmp_ctx , " %s " ,
" Default-First-Site-Name " ) ;
if ( ! site_name_str ) {
r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
} else {
site_name_str = talloc_asprintf ( tmp_ctx , " %s " ,
2008-10-02 10:09:25 +04:00
search . out . netlogon . data . nt5_ex . client_site ) ;
2006-01-17 06:44:37 +03:00
if ( ! site_name_str ) {
r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
}
/* Generate the CN=Configuration,... DN. */
2006-11-29 18:40:26 +03:00
/* TODO: look it up! */
2006-01-17 06:44:37 +03:00
config_dn_str = talloc_asprintf ( tmp_ctx , " CN=Configuration,%s " , r - > in . domain_dn_str ) ;
if ( ! config_dn_str ) {
r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
/* Generate the CN=Servers,... DN. */
server_dn_str = talloc_asprintf ( tmp_ctx , " CN=%s,CN=Servers,CN=%s,CN=Sites,%s " ,
r - > in . netbios_name , site_name_str , config_dn_str ) ;
if ( ! server_dn_str ) {
r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
r - > out . site_name_str = site_name_str ;
talloc_steal ( r , site_name_str ) ;
r - > out . config_dn_str = config_dn_str ;
talloc_steal ( r , config_dn_str ) ;
r - > out . server_dn_str = server_dn_str ;
talloc_steal ( r , server_dn_str ) ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
/*
* find out Site specific stuff :
* 1. Lookup the Site name .
* 2. Add entry CN = < netbios name > , CN = Servers , CN = < site name > , CN = Sites , CN = Configuration , < domain dn > .
* TODO : 3. ) use DsAddEntry ( ) to create CN = NTDS Settings , CN = < netbios name > , CN = Servers , CN = < site name > , . . .
*/
2007-12-12 04:15:29 +03:00
NTSTATUS libnet_JoinSite ( struct libnet_context * ctx ,
struct ldb_context * remote_ldb ,
2006-01-17 06:44:37 +03:00
struct libnet_JoinDomain * libnet_r )
{
NTSTATUS status ;
TALLOC_CTX * tmp_ctx ;
struct libnet_JoinSite * r ;
struct ldb_dn * server_dn ;
struct ldb_message * msg ;
int rtn ;
const char * server_dn_str ;
2014-02-04 15:14:37 +04:00
const char * host ;
2007-04-27 18:31:26 +04:00
struct nbt_name name ;
const char * dest_addr = NULL ;
2006-01-17 06:44:37 +03:00
tmp_ctx = talloc_named ( libnet_r , 0 , " libnet_JoinSite temp context " ) ;
if ( ! tmp_ctx ) {
libnet_r - > out . error_string = NULL ;
return NT_STATUS_NO_MEMORY ;
}
r = talloc ( tmp_ctx , struct libnet_JoinSite ) ;
if ( ! r ) {
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2014-02-04 15:14:37 +04:00
host = dcerpc_binding_get_string_option ( libnet_r - > out . samr_binding , " host " ) ;
make_nbt_name_client ( & name , host ) ;
2011-05-02 10:36:48 +04:00
status = resolve_name_ex ( lpcfg_resolve_context ( ctx - > lp_ctx ) ,
0 , 0 ,
& name , r , & dest_addr , ctx - > event_ctx ) ;
2007-04-27 18:31:26 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return status ;
}
2006-01-17 06:44:37 +03:00
/* Resolve the site name and AD DN's. */
2007-04-27 18:31:26 +04:00
r - > in . dest_address = dest_addr ;
2006-01-17 06:44:37 +03:00
r - > in . netbios_name = libnet_r - > in . netbios_name ;
r - > in . domain_dn_str = libnet_r - > out . domain_dn_str ;
2010-07-16 08:32:42 +04:00
r - > in . cldap_port = lpcfg_cldap_port ( ctx - > lp_ctx ) ;
2006-01-17 06:44:37 +03:00
2008-04-22 01:58:23 +04:00
status = libnet_FindSite ( tmp_ctx , ctx , r ) ;
2006-01-17 06:44:37 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
libnet_r - > out . error_string =
talloc_steal ( libnet_r , r - > out . error_string ) ;
talloc_free ( tmp_ctx ) ;
2007-04-27 18:31:26 +04:00
return status ;
2006-01-17 06:44:37 +03:00
}
server_dn_str = r - > out . server_dn_str ;
/*
Add entry CN = < netbios name > , CN = Servers , CN = < site name > , CN = Sites , CN = Configuration , < domain dn > .
*/
msg = ldb_msg_new ( tmp_ctx ) ;
if ( ! msg ) {
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
rtn = ldb_msg_add_string ( msg , " objectClass " , " server " ) ;
2011-03-04 12:40:27 +03:00
if ( rtn ! = LDB_SUCCESS ) {
2006-01-17 06:44:37 +03:00
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
rtn = ldb_msg_add_string ( msg , " systemFlags " , " 50000000 " ) ;
2011-03-04 12:40:27 +03:00
if ( rtn ! = LDB_SUCCESS ) {
2006-01-17 06:44:37 +03:00
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
rtn = ldb_msg_add_string ( msg , " serverReference " , libnet_r - > out . account_dn_str ) ;
2011-03-04 12:40:27 +03:00
if ( rtn ! = LDB_SUCCESS ) {
2006-01-17 06:44:37 +03:00
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-11-22 03:59:34 +03:00
server_dn = ldb_dn_new ( tmp_ctx , remote_ldb , server_dn_str ) ;
if ( ! ldb_dn_validate ( server_dn ) ) {
2006-01-17 06:44:37 +03:00
libnet_r - > out . error_string = talloc_asprintf ( libnet_r ,
" Invalid server dn: %s " ,
server_dn_str ) ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
msg - > dn = server_dn ;
rtn = ldb_add ( remote_ldb , msg ) ;
if ( rtn = = LDB_ERR_ENTRY_ALREADY_EXISTS ) {
2010-03-10 22:23:43 +03:00
unsigned int i ;
2006-01-17 06:44:37 +03:00
/* make a 'modify' msg, and only for serverReference */
msg = ldb_msg_new ( tmp_ctx ) ;
if ( ! msg ) {
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
msg - > dn = server_dn ;
rtn = ldb_msg_add_string ( msg , " serverReference " , libnet_r - > out . account_dn_str ) ;
2011-03-04 12:40:27 +03:00
if ( rtn ! = LDB_SUCCESS ) {
2006-01-17 06:44:37 +03:00
libnet_r - > out . error_string = NULL ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
/* mark all the message elements (should be just one)
as LDB_FLAG_MOD_REPLACE */
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
msg - > elements [ i ] . flags = LDB_FLAG_MOD_REPLACE ;
}
rtn = ldb_modify ( remote_ldb , msg ) ;
2011-03-04 12:40:27 +03:00
if ( rtn ! = LDB_SUCCESS ) {
2006-01-17 06:44:37 +03:00
libnet_r - > out . error_string
= talloc_asprintf ( libnet_r ,
" Failed to modify server entry %s: %s: %d " ,
server_dn_str ,
ldb_errstring ( remote_ldb ) , rtn ) ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2011-03-04 12:40:27 +03:00
} else if ( rtn ! = LDB_SUCCESS ) {
2006-01-17 06:44:37 +03:00
libnet_r - > out . error_string
= talloc_asprintf ( libnet_r ,
" Failed to add server entry %s: %s: %d " ,
server_dn_str , ldb_errstring ( remote_ldb ) ,
rtn ) ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
DEBUG ( 0 , ( " We still need to perform a DsAddEntry() so that we can create the CN=NTDS Settings container. \n " ) ) ;
/* Store the server DN in libnet_r */
libnet_r - > out . server_dn_str = server_dn_str ;
talloc_steal ( libnet_r , server_dn_str ) ;
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}