2005-05-12 12:28:07 +04:00
/*
Unix SMB / CIFS implementation .
CLDAP server - netlogon handling
Copyright ( C ) Andrew Tridgell 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
2005-05-12 12:28:07 +04: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/>.
2005-05-12 12:28:07 +04:00
*/
# include "includes.h"
2006-06-15 03:32:19 +04:00
# include "lib/ldb/include/ldb.h"
# include "lib/ldb/include/ldb_errors.h"
2005-05-12 12:28:07 +04:00
# include "lib/events/events.h"
# include "lib/socket/socket.h"
# include "smbd/service_task.h"
# include "cldap_server/cldap_server.h"
2006-03-18 18:42:57 +03:00
# include "librpc/gen_ndr/ndr_misc.h"
2008-04-14 13:54:50 +04:00
# include "libcli/ldap/ldap_ndr.h"
2005-12-28 18:38:36 +03:00
# include "dsdb/samdb/samdb.h"
# include "auth/auth.h"
2007-11-16 22:12:00 +03:00
# include "ldb_wrap.h"
2006-03-07 14:07:23 +03:00
# include "system/network.h"
2006-08-17 17:37:04 +04:00
# include "lib/socket/netif.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2005-05-12 12:28:07 +04:00
/*
fill in the cldap netlogon union for a given version
*/
2005-05-18 08:18:19 +04:00
static NTSTATUS cldapd_netlogon_fill ( struct cldapd_server * cldapd ,
2005-05-12 12:28:07 +04:00
TALLOC_CTX * mem_ctx ,
const char * domain ,
2005-05-16 15:17:57 +04:00
const char * domain_guid ,
2005-05-12 13:03:14 +04:00
const char * user ,
2005-05-12 12:28:07 +04:00
const char * src_address ,
uint32_t version ,
2007-12-02 18:20:25 +03:00
struct loadparm_context * lp_ctx ,
2005-05-12 12:28:07 +04:00
union nbt_cldap_netlogon * netlogon )
{
2006-08-19 02:20:13 +04:00
const char * ref_attrs [ ] = { " nETBIOSName " , " dnsRoot " , " ncName " , NULL } ;
const char * dom_attrs [ ] = { " objectGUID " , NULL } ;
2007-11-14 00:30:33 +03:00
struct ldb_result * ref_res = NULL , * dom_res = NULL ;
int ret ;
2007-12-02 18:20:25 +03:00
const char * * services = lp_server_services ( lp_ctx ) ;
2005-05-12 12:28:07 +04:00
uint32_t server_type ;
const char * pdc_name ;
struct GUID domain_uuid ;
const char * realm ;
const char * dns_domain ;
const char * pdc_dns_name ;
const char * flatname ;
2006-11-13 22:12:47 +03:00
const char * server_site ;
const char * client_site ;
2005-05-12 12:28:07 +04:00
const char * pdc_ip ;
2006-11-22 03:59:34 +03:00
struct ldb_dn * partitions_basedn ;
2007-12-12 00:23:14 +03:00
struct interface * ifaces ;
2005-05-12 12:28:07 +04:00
2006-08-25 11:32:18 +04:00
partitions_basedn = samdb_partitions_dn ( cldapd - > samctx , mem_ctx ) ;
2005-05-12 13:03:14 +04:00
/* the domain has an optional trailing . */
2005-05-16 15:17:57 +04:00
if ( domain & & domain [ strlen ( domain ) - 1 ] = = ' . ' ) {
2005-05-12 13:03:14 +04:00
domain = talloc_strndup ( mem_ctx , domain , strlen ( domain ) - 1 ) ;
}
2006-06-15 03:32:19 +04:00
if ( domain ) {
struct ldb_dn * dom_dn ;
/* try and find the domain */
2007-11-14 00:30:33 +03:00
ret = ldb_search_exp_fmt ( cldapd - > samctx , mem_ctx , & ref_res ,
partitions_basedn , LDB_SCOPE_ONELEVEL ,
ref_attrs ,
" (&(&(objectClass=crossRef)(dnsRoot=%s))(nETBIOSName=*)) " ,
domain ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 2 , ( " Unable to find referece to '%s' in sam: %s \n " ,
domain ,
ldb_errstring ( cldapd - > samctx ) ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
} else if ( ref_res - > count = = 1 ) {
talloc_steal ( mem_ctx , dom_res ) ;
dom_dn = ldb_msg_find_attr_as_dn ( cldapd - > samctx , mem_ctx , ref_res - > msgs [ 0 ] , " ncName " ) ;
2006-06-15 03:32:19 +04:00
if ( ! dom_dn ) {
return NT_STATUS_NO_SUCH_DOMAIN ;
}
ret = ldb_search ( cldapd - > samctx , dom_dn ,
LDB_SCOPE_BASE , " objectClass=domain " ,
2007-11-14 00:30:33 +03:00
dom_attrs , & dom_res ) ;
2006-06-15 03:32:19 +04:00
if ( ret ! = LDB_SUCCESS ) {
2006-11-22 05:05:19 +03:00
DEBUG ( 2 , ( " Error finding domain '%s'/'%s' in sam: %s \n " , domain , ldb_dn_get_linearized ( dom_dn ) , ldb_errstring ( cldapd - > samctx ) ) ) ;
2006-06-15 03:32:19 +04:00
return NT_STATUS_NO_SUCH_DOMAIN ;
}
2007-11-14 00:30:33 +03:00
talloc_steal ( mem_ctx , dom_res ) ;
if ( dom_res - > count ! = 1 ) {
2006-11-22 05:05:19 +03:00
DEBUG ( 2 , ( " Error finding domain '%s'/'%s' in sam \n " , domain , ldb_dn_get_linearized ( dom_dn ) ) ) ;
2006-06-15 03:32:19 +04:00
return NT_STATUS_NO_SUCH_DOMAIN ;
}
2007-11-14 00:30:33 +03:00
} else if ( ref_res - > count > 1 ) {
talloc_free ( ref_res ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
2006-06-15 03:32:19 +04:00
}
}
2007-11-14 00:30:33 +03:00
if ( ( dom_res = = NULL | | dom_res - > count = = 0 ) & & domain_guid ) {
ref_res = NULL ;
ret = ldb_search_exp_fmt ( cldapd - > samctx , mem_ctx , & dom_res ,
NULL , LDB_SCOPE_SUBTREE ,
dom_attrs ,
" (&(objectClass=domainDNS)(objectGUID=%s)) " ,
domain_guid ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 2 , ( " Unable to find referece to GUID '%s' in sam: %s \n " ,
domain_guid ,
ldb_errstring ( cldapd - > samctx ) ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
} else if ( dom_res - > count = = 1 ) {
2006-06-15 03:32:19 +04:00
/* try and find the domain */
2007-11-14 00:30:33 +03:00
ret = ldb_search_exp_fmt ( cldapd - > samctx , mem_ctx , & ref_res ,
partitions_basedn , LDB_SCOPE_ONELEVEL ,
ref_attrs ,
" (&(objectClass=crossRef)(ncName=%s)) " ,
ldb_dn_get_linearized ( dom_res - > msgs [ 0 ] - > dn ) ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 2 , ( " Unable to find referece to '%s' in sam: %s \n " ,
ldb_dn_get_linearized ( dom_res - > msgs [ 0 ] - > dn ) ,
ldb_errstring ( cldapd - > samctx ) ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
} else if ( ref_res - > count ! = 1 ) {
2006-06-15 03:32:19 +04:00
DEBUG ( 2 , ( " Unable to find referece to '%s' in sam \n " ,
2007-11-14 00:30:33 +03:00
ldb_dn_get_linearized ( dom_res - > msgs [ 0 ] - > dn ) ) ) ;
2006-06-15 03:32:19 +04:00
return NT_STATUS_NO_SUCH_DOMAIN ;
}
2007-11-14 00:30:33 +03:00
} else if ( dom_res - > count > 1 ) {
talloc_free ( ref_res ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
2006-06-15 03:32:19 +04:00
}
2005-05-12 12:28:07 +04:00
}
2007-11-14 00:30:33 +03:00
if ( ( ref_res = = NULL | | ref_res - > count = = 0 ) ) {
DEBUG ( 2 , ( " Unable to find domain reference with name %s or GUID {%s} \n " , domain , domain_guid ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
}
if ( ( dom_res = = NULL | | dom_res - > count = = 0 ) ) {
2006-06-15 03:32:19 +04:00
DEBUG ( 2 , ( " Unable to find domain with name %s or GUID {%s} \n " , domain , domain_guid ) ) ;
2005-08-03 22:30:21 +04:00
return NT_STATUS_NO_SUCH_DOMAIN ;
}
2005-05-12 12:28:07 +04:00
server_type =
NBT_SERVER_DS | NBT_SERVER_TIMESERV |
NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE |
NBT_SERVER_GOOD_TIMESERV ;
2008-01-03 15:00:38 +03:00
if ( samdb_is_pdc ( cldapd - > samctx ) ) {
server_type | = NBT_SERVER_PDC ;
}
2008-01-07 09:47:01 +03:00
if ( samdb_is_gc ( cldapd - > samctx ) ) {
server_type | = NBT_SERVER_GC ;
}
2005-05-12 12:28:07 +04:00
if ( str_list_check ( services , " ldap " ) ) {
server_type | = NBT_SERVER_LDAP ;
}
2005-06-08 03:06:24 +04:00
if ( str_list_check ( services , " kdc " ) ) {
server_type | = NBT_SERVER_KDC ;
}
2007-12-02 18:20:25 +03:00
pdc_name = talloc_asprintf ( mem_ctx , " \\ \\ %s " , lp_netbios_name ( lp_ctx ) ) ;
2007-11-14 00:30:33 +03:00
domain_uuid = samdb_result_guid ( dom_res - > msgs [ 0 ] , " objectGUID " ) ;
2007-12-02 18:20:25 +03:00
realm = samdb_result_string ( ref_res - > msgs [ 0 ] , " dnsRoot " , lp_realm ( lp_ctx ) ) ;
dns_domain = samdb_result_string ( ref_res - > msgs [ 0 ] , " dnsRoot " , lp_realm ( lp_ctx ) ) ;
2005-05-12 12:28:07 +04:00
pdc_dns_name = talloc_asprintf ( mem_ctx , " %s.%s " ,
2007-09-28 05:17:46 +04:00
strlower_talloc ( mem_ctx ,
2007-12-02 18:20:25 +03:00
lp_netbios_name ( lp_ctx ) ) ,
2005-06-08 03:06:24 +04:00
dns_domain ) ;
2005-08-03 22:30:21 +04:00
2007-11-14 00:30:33 +03:00
flatname = samdb_result_string ( ref_res - > msgs [ 0 ] , " nETBIOSName " ,
2007-12-02 18:20:25 +03:00
lp_workgroup ( lp_ctx ) ) ;
2006-11-13 22:12:47 +03:00
server_site = " Default-First-Site-Name " ;
client_site = " Default-First-Site-Name " ;
2007-12-12 00:23:20 +03:00
load_interfaces ( mem_ctx , lp_interfaces ( lp_ctx ) , & ifaces ) ;
2007-12-12 00:23:14 +03:00
pdc_ip = iface_best_ip ( ifaces , src_address ) ;
2005-05-12 12:28:07 +04:00
ZERO_STRUCTP ( netlogon ) ;
switch ( version & 0xF ) {
case 0 :
case 1 :
2005-07-12 13:40:34 +04:00
netlogon - > logon1 . type = ( user ? 19 + 2 : 19 ) ;
2005-05-12 12:28:07 +04:00
netlogon - > logon1 . pdc_name = pdc_name ;
2005-05-16 14:30:51 +04:00
netlogon - > logon1 . user_name = user ;
2005-05-12 12:28:07 +04:00
netlogon - > logon1 . domain_name = flatname ;
netlogon - > logon1 . nt_version = 1 ;
netlogon - > logon1 . lmnt_token = 0xFFFF ;
netlogon - > logon1 . lm20_token = 0xFFFF ;
break ;
case 2 :
case 3 :
2005-07-12 13:40:34 +04:00
netlogon - > logon3 . type = ( user ? 19 + 2 : 19 ) ;
2005-07-08 09:10:02 +04:00
netlogon - > logon3 . pdc_name = pdc_name ;
netlogon - > logon3 . user_name = user ;
netlogon - > logon3 . domain_name = flatname ;
2005-05-12 12:28:07 +04:00
netlogon - > logon3 . domain_uuid = domain_uuid ;
netlogon - > logon3 . forest = realm ;
netlogon - > logon3 . dns_domain = dns_domain ;
netlogon - > logon3 . pdc_dns_name = pdc_dns_name ;
2005-07-08 09:10:02 +04:00
netlogon - > logon3 . pdc_ip = pdc_ip ;
netlogon - > logon3 . server_type = server_type ;
2005-05-12 12:28:07 +04:00
netlogon - > logon3 . lmnt_token = 0xFFFF ;
netlogon - > logon3 . lm20_token = 0xFFFF ;
break ;
2005-07-08 09:10:02 +04:00
case 4 :
case 5 :
case 6 :
case 7 :
2008-01-07 12:14:51 +03:00
netlogon - > logon5 . type = ( user ? NETLOGON_RESPONSE_FROM_PDC_USER : NETLOGON_RESPONSE_FROM_PDC2 ) ;
2005-07-08 09:10:02 +04:00
netlogon - > logon5 . server_type = server_type ;
netlogon - > logon5 . domain_uuid = domain_uuid ;
netlogon - > logon5 . forest = realm ;
netlogon - > logon5 . dns_domain = dns_domain ;
netlogon - > logon5 . pdc_dns_name = pdc_dns_name ;
netlogon - > logon5 . domain = flatname ;
2007-12-02 18:20:25 +03:00
netlogon - > logon5 . pdc_name = lp_netbios_name ( lp_ctx ) ;
2005-07-08 09:10:02 +04:00
netlogon - > logon5 . user_name = user ;
2006-11-13 22:12:47 +03:00
netlogon - > logon5 . server_site = server_site ;
netlogon - > logon5 . client_site = client_site ;
2005-07-08 09:10:02 +04:00
netlogon - > logon5 . lmnt_token = 0xFFFF ;
netlogon - > logon5 . lm20_token = 0xFFFF ;
break ;
2005-05-12 12:28:07 +04:00
default :
2008-01-07 12:14:51 +03:00
netlogon - > logon13 . type = ( user ? NETLOGON_RESPONSE_FROM_PDC_USER : NETLOGON_RESPONSE_FROM_PDC2 ) ;
2005-07-08 09:10:02 +04:00
netlogon - > logon13 . server_type = server_type ;
netlogon - > logon13 . domain_uuid = domain_uuid ;
netlogon - > logon13 . forest = realm ;
netlogon - > logon13 . dns_domain = dns_domain ;
netlogon - > logon13 . pdc_dns_name = pdc_dns_name ;
netlogon - > logon13 . domain = flatname ;
2007-12-02 18:20:25 +03:00
netlogon - > logon13 . pdc_name = lp_netbios_name ( lp_ctx ) ;
2005-07-08 09:10:02 +04:00
netlogon - > logon13 . user_name = user ;
2006-11-13 22:12:47 +03:00
netlogon - > logon13 . server_site = server_site ;
netlogon - > logon13 . client_site = client_site ;
2005-07-08 09:10:02 +04:00
netlogon - > logon13 . unknown = 10 ;
netlogon - > logon13 . unknown2 = 2 ;
netlogon - > logon13 . pdc_ip = pdc_ip ;
netlogon - > logon13 . lmnt_token = 0xFFFF ;
netlogon - > logon13 . lm20_token = 0xFFFF ;
2005-05-12 12:28:07 +04:00
break ;
}
return NT_STATUS_OK ;
}
/*
handle incoming cldap requests
*/
void cldapd_netlogon_request ( struct cldap_socket * cldap ,
uint32_t message_id ,
2005-06-13 13:10:17 +04:00
struct ldb_parse_tree * tree ,
2006-01-10 01:12:53 +03:00
struct socket_address * src )
2005-05-12 12:28:07 +04:00
{
2005-05-18 08:18:19 +04:00
struct cldapd_server * cldapd = talloc_get_type ( cldap - > incoming . private , struct cldapd_server ) ;
2005-05-12 12:28:07 +04:00
int i ;
const char * domain = NULL ;
const char * host = NULL ;
2005-07-12 13:40:34 +04:00
const char * user = NULL ;
2005-05-13 09:29:41 +04:00
const char * domain_guid = NULL ;
const char * domain_sid = NULL ;
int acct_control = - 1 ;
2005-05-12 12:28:07 +04:00
int version = - 1 ;
union nbt_cldap_netlogon netlogon ;
NTSTATUS status = NT_STATUS_INVALID_PARAMETER ;
TALLOC_CTX * tmp_ctx = talloc_new ( cldap ) ;
2005-06-13 10:06:29 +04:00
if ( tree - > operation ! = LDB_OP_AND ) goto failed ;
2005-05-12 12:28:07 +04:00
/* extract the query elements */
for ( i = 0 ; i < tree - > u . list . num_elements ; i + + ) {
2005-06-13 10:06:29 +04:00
struct ldb_parse_tree * t = tree - > u . list . elements [ i ] ;
2005-07-19 13:09:00 +04:00
if ( t - > operation ! = LDB_OP_EQUALITY ) goto failed ;
if ( strcasecmp ( t - > u . equality . attr , " DnsDomain " ) = = 0 ) {
2005-05-12 12:28:07 +04:00
domain = talloc_strndup ( tmp_ctx ,
2006-03-15 13:28:35 +03:00
( const char * ) t - > u . equality . value . data ,
2005-07-19 13:09:00 +04:00
t - > u . equality . value . length ) ;
2005-05-12 12:28:07 +04:00
}
2005-07-19 13:09:00 +04:00
if ( strcasecmp ( t - > u . equality . attr , " Host " ) = = 0 ) {
2005-05-12 12:28:07 +04:00
host = talloc_strndup ( tmp_ctx ,
2006-03-15 13:28:35 +03:00
( const char * ) t - > u . equality . value . data ,
2005-07-19 13:09:00 +04:00
t - > u . equality . value . length ) ;
2005-05-12 12:28:07 +04:00
}
2005-07-19 13:09:00 +04:00
if ( strcasecmp ( t - > u . equality . attr , " DomainGuid " ) = = 0 ) {
2005-05-16 15:17:57 +04:00
NTSTATUS enc_status ;
struct GUID guid ;
enc_status = ldap_decode_ndr_GUID ( tmp_ctx ,
2005-07-19 13:09:00 +04:00
t - > u . equality . value , & guid ) ;
2005-05-16 15:17:57 +04:00
if ( NT_STATUS_IS_OK ( enc_status ) ) {
domain_guid = GUID_string ( tmp_ctx , & guid ) ;
}
2005-05-13 09:29:41 +04:00
}
2005-07-19 13:09:00 +04:00
if ( strcasecmp ( t - > u . equality . attr , " DomainSid " ) = = 0 ) {
2005-05-13 09:29:41 +04:00
domain_sid = talloc_strndup ( tmp_ctx ,
2006-03-15 13:28:35 +03:00
( const char * ) t - > u . equality . value . data ,
2005-07-19 13:09:00 +04:00
t - > u . equality . value . length ) ;
2005-05-13 09:29:41 +04:00
}
2005-07-19 13:09:00 +04:00
if ( strcasecmp ( t - > u . equality . attr , " User " ) = = 0 ) {
2005-05-12 13:03:14 +04:00
user = talloc_strndup ( tmp_ctx ,
2006-03-15 13:28:35 +03:00
( const char * ) t - > u . equality . value . data ,
2005-07-19 13:09:00 +04:00
t - > u . equality . value . length ) ;
2005-05-12 13:03:14 +04:00
}
2005-07-19 13:09:00 +04:00
if ( strcasecmp ( t - > u . equality . attr , " NtVer " ) = = 0 & &
t - > u . equality . value . length = = 4 ) {
version = IVAL ( t - > u . equality . value . data , 0 ) ;
2005-05-12 12:28:07 +04:00
}
2005-07-19 13:09:00 +04:00
if ( strcasecmp ( t - > u . equality . attr , " AAC " ) = = 0 & &
t - > u . equality . value . length = = 4 ) {
acct_control = IVAL ( t - > u . equality . value . data , 0 ) ;
2005-05-13 09:29:41 +04:00
}
2005-05-12 12:28:07 +04:00
}
2005-05-16 15:17:57 +04:00
if ( domain_guid = = NULL & & domain = = NULL ) {
2007-12-04 01:33:16 +03:00
domain = lp_realm ( cldapd - > task - > lp_ctx ) ;
2005-05-16 15:17:57 +04:00
}
if ( version = = - 1 ) {
2005-05-12 12:28:07 +04:00
goto failed ;
}
2005-05-18 08:18:19 +04:00
DEBUG ( 5 , ( " cldap netlogon query domain=%s host=%s user=%s version=%d guid=%s \n " ,
2005-05-16 15:17:57 +04:00
domain , host , user , version , domain_guid ) ) ;
2005-05-12 12:28:07 +04:00
2005-05-18 08:18:19 +04:00
status = cldapd_netlogon_fill ( cldapd , tmp_ctx , domain , domain_guid ,
2006-01-10 01:12:53 +03:00
user , src - > addr ,
2007-12-04 01:33:16 +03:00
version , cldapd - > task - > lp_ctx , & netlogon ) ;
2005-05-12 12:28:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
2006-01-10 01:12:53 +03:00
status = cldap_netlogon_reply ( cldap , message_id , src , version ,
2005-05-12 12:28:07 +04:00
& netlogon ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
talloc_free ( tmp_ctx ) ;
return ;
failed :
2005-06-19 00:32:21 +04:00
DEBUG ( 2 , ( " cldap netlogon query failed domain=%s host=%s version=%d - %s \n " ,
2005-05-12 12:28:07 +04:00
domain , host , version , nt_errstr ( status ) ) ) ;
talloc_free ( tmp_ctx ) ;
2006-01-10 01:12:53 +03:00
cldap_empty_reply ( cldap , message_id , src ) ;
2005-05-12 12:28:07 +04:00
}