summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2006-05-12 15:17:35 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:16:57 -0500
commit2c029a8b96ae476f1d5c2abe14ee25f98a1513d8 (patch)
treed256cef6a5f4802549a599477c6bc8b4897d4ff0
parentfc5f948260477e4c43e844be1abb09056174d69e (diff)
downloadsamba-2c029a8b96ae476f1d5c2abe14ee25f98a1513d8.tar.gz
samba-2c029a8b96ae476f1d5c2abe14ee25f98a1513d8.tar.bz2
samba-2c029a8b96ae476f1d5c2abe14ee25f98a1513d8.zip
r15543: New implementation of 'net ads join' to be more like Windows XP.
The motivating factor is to not require more privileges for the user account than Windows does when joining a domain. The points of interest are * net_ads_join() uses same rpc mechanisms as net_rpc_join() * Enable CLDAP queries for filling in the majority of the ADS_STRUCT->config information * Remove ldap_initialized() from sam/idmap_ad.c and libads/ldap.c * Remove some unnecessary fields from ADS_STRUCT * Manually set the dNSHostName and servicePrincipalName attribute using the machine account after the join Thanks to Guenther and Simo for the review. Still to do: * Fix the userAccountControl for DES only systems * Set the userPrincipalName in order to support things like 'kinit -k' (although we might be able to just use the sAMAccountName instead) * Re-add support for pre-creating the machine account in a specific OU (This used to be commit 4c4ea7b20f44cd200cef8c7b389d51b72eccc39b)
-rw-r--r--source3/Makefile.in4
-rw-r--r--source3/include/ads.h15
-rw-r--r--source3/include/ads_cldap.h58
-rw-r--r--source3/include/includes.h34
-rw-r--r--source3/libads/ads_struct.c6
-rw-r--r--source3/libads/cldap.c (renamed from source3/utils/net_ads_cldap.c)115
-rw-r--r--source3/libads/ldap.c363
-rw-r--r--source3/libsmb/namequery.c97
-rw-r--r--source3/nsswitch/winbindd_cm.c9
-rw-r--r--source3/printing/nt_printing.c2
-rw-r--r--source3/sam/idmap_ad.c38
-rw-r--r--source3/utils/net.c53
-rw-r--r--source3/utils/net.h27
-rw-r--r--source3/utils/net_ads.c669
-rw-r--r--source3/utils/net_rpc.c2
-rw-r--r--source3/utils/net_rpc_join.c8
16 files changed, 897 insertions, 603 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 32c8429cdf..2d0ac9ab7a 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -241,7 +241,7 @@ LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \
libads/krb5_setpw.o libads/ldap_user.o \
libads/ads_struct.o libads/kerberos_keytab.o \
libads/disp_sec.o libads/ads_utils.o libads/ldap_utils.o \
- libads/authdata.o
+ libads/authdata.o libads/cldap.o
LIBADS_SERVER_OBJ = libads/util.o libads/kerberos_verify.o
@@ -567,7 +567,7 @@ TOOL_OBJ = client/smbctool.o client/clitar.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
$(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \
$(READLINE_OBJ) $(POPT_LIB_OBJ) $(SECRETS_OBJ)
-NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_ads_cldap.o utils/net_help.o \
+NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_help.o \
utils/net_rap.o utils/net_rpc.o utils/net_rpc_samsync.o \
utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \
utils/net_cache.o utils/net_groupmap.o utils/net_idmap.o \
diff --git a/source3/include/ads.h b/source3/include/ads.h
index f29c94bb90..48b9bbffa0 100644
--- a/source3/include/ads.h
+++ b/source3/include/ads.h
@@ -17,7 +17,6 @@ typedef struct {
char *realm;
char *workgroup;
char *ldap_server;
- char *ldap_uri;
int foreign; /* set to 1 if connecting to a foreign realm */
} server;
@@ -37,7 +36,6 @@ typedef struct {
struct {
char *realm;
char *bind_path;
- char *schema_path;
char *ldap_server_name;
time_t current_time;
} config;
@@ -219,19 +217,6 @@ typedef void **ADS_MODLIST;
#define GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP 0x00000004 /* 4 */
#define GTYPE_DISTRIBUTION_UNIVERSAL_GROUP 0x00000008 /* 8 */
-/* Mailslot or cldap getdcname response flags */
-#define ADS_PDC 0x00000001 /* DC is PDC */
-#define ADS_GC 0x00000004 /* DC is a GC of forest */
-#define ADS_LDAP 0x00000008 /* DC is an LDAP server */
-#define ADS_DS 0x00000010 /* DC supports DS */
-#define ADS_KDC 0x00000020 /* DC is running KDC */
-#define ADS_TIMESERV 0x00000040 /* DC is running time services */
-#define ADS_CLOSEST 0x00000080 /* DC is closest to client */
-#define ADS_WRITABLE 0x00000100 /* DC has writable DS */
-#define ADS_GOOD_TIMESERV 0x00000200 /* DC has hardware clock
- (and running time) */
-#define ADS_NDNC 0x00000400 /* DomainName is non-domain NC serviced
- by LDAP server */
#define ADS_PINGS 0x0000FFFF /* Ping response */
#define ADS_DNS_CONTROLLER 0x20000000 /* DomainControllerName is a DNS name*/
#define ADS_DNS_DOMAIN 0x40000000 /* DomainName is a DNS name */
diff --git a/source3/include/ads_cldap.h b/source3/include/ads_cldap.h
new file mode 100644
index 0000000000..65feb072e0
--- /dev/null
+++ b/source3/include/ads_cldap.h
@@ -0,0 +1,58 @@
+/*
+ Samba Unix/Linux SMB client library
+ net ads cldap functions
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
+
+ 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 02139, USA.
+*/
+
+#define MAX_DNS_LABEL 255 + 1
+
+struct cldap_netlogon_reply {
+ uint32 type;
+ uint32 flags;
+ UUID_FLAT guid;
+
+ char forest[MAX_DNS_LABEL];
+ char domain[MAX_DNS_LABEL];
+ char hostname[MAX_DNS_LABEL];
+
+ char netbios_domain[MAX_DNS_LABEL];
+ char netbios_hostname[MAX_DNS_LABEL];
+
+ char unk[MAX_DNS_LABEL];
+ char user_name[MAX_DNS_LABEL];
+ char site_name[MAX_DNS_LABEL];
+ char site_name_2[MAX_DNS_LABEL];
+
+ uint32 version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+};
+
+/* Mailslot or cldap getdcname response flags */
+#define ADS_PDC 0x00000001 /* DC is PDC */
+#define ADS_GC 0x00000004 /* DC is a GC of forest */
+#define ADS_LDAP 0x00000008 /* DC is an LDAP server */
+#define ADS_DS 0x00000010 /* DC supports DS */
+#define ADS_KDC 0x00000020 /* DC is running KDC */
+#define ADS_TIMESERV 0x00000040 /* DC is running time services */
+#define ADS_CLOSEST 0x00000080 /* DC is closest to client */
+#define ADS_WRITABLE 0x00000100 /* DC has writable DS */
+#define ADS_GOOD_TIMESERV 0x00000200 /* DC has hardware clock (and running time) */
+#define ADS_NDNC 0x00000400 /* DomainName is non-domain NC serviced by LDAP server */
+
+
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 998a0715e2..a13cffea14 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -911,50 +911,29 @@ extern int errno;
#include "messages.h"
#include "charset.h"
#include "dynconfig.h"
-
#include "util_getent.h"
-
#include "debugparse.h"
-
#include "version.h"
-
#include "privileges.h"
-
#include "smb.h"
-
+#include "ads_cldap.h"
#include "nameserv.h"
-
#include "secrets.h"
-
#include "byteorder.h"
-
#include "privileges.h"
-
#include "rpc_misc.h"
-
#include "rpc_dce.h"
-
#include "mapping.h"
-
#include "passdb.h"
-
#include "rpc_secdes.h"
-
#include "authdata.h"
-
#include "msdfs.h"
-
#include "rap.h"
-
#include "md5.h"
#include "hmacmd5.h"
-
#include "ntlmssp.h"
-
#include "auth.h"
-
#include "ntdomain.h"
-
#include "rpc_svcctl.h"
#include "rpc_ntsvcs.h"
#include "rpc_lsa.h"
@@ -972,11 +951,8 @@ extern int errno;
#include "rpc_shutdown.h"
#include "rpc_perfcount.h"
#include "rpc_perfcount_defs.h"
-
#include "nt_printing.h"
-
#include "idmap.h"
-
#include "client.h"
#ifdef WITH_SMBWRAPPER
@@ -984,21 +960,13 @@ extern int errno;
#endif
#include "session.h"
-
#include "asn_1.h"
-
#include "popt.h"
-
#include "mangle.h"
-
#include "module.h"
-
#include "nsswitch/winbind_client.h"
-
#include "spnego.h"
-
#include "rpc_client.h"
-
#include "event.h"
/*
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c
index 9b2179ad31..48533c7ffb 100644
--- a/source3/libads/ads_struct.c
+++ b/source3/libads/ads_struct.c
@@ -118,12 +118,13 @@ void ads_destroy(ADS_STRUCT **ads)
is_mine = (*ads)->is_mine;
#if HAVE_LDAP
- if ((*ads)->ld) ldap_unbind((*ads)->ld);
+ if ((*ads)->ld) {
+ ldap_unbind((*ads)->ld);
+ }
#endif
SAFE_FREE((*ads)->server.realm);
SAFE_FREE((*ads)->server.workgroup);
SAFE_FREE((*ads)->server.ldap_server);
- SAFE_FREE((*ads)->server.ldap_uri);
SAFE_FREE((*ads)->auth.realm);
SAFE_FREE((*ads)->auth.password);
@@ -132,7 +133,6 @@ void ads_destroy(ADS_STRUCT **ads)
SAFE_FREE((*ads)->config.realm);
SAFE_FREE((*ads)->config.bind_path);
- SAFE_FREE((*ads)->config.schema_path);
SAFE_FREE((*ads)->config.ldap_server_name);
SAFE_FREE((*ads)->schema.sfu_uidnumber_attr);
diff --git a/source3/utils/net_ads_cldap.c b/source3/libads/cldap.c
index 2e7a28b322..6a62f573c9 100644
--- a/source3/utils/net_ads_cldap.c
+++ b/source3/libads/cldap.c
@@ -20,33 +20,6 @@
*/
#include "includes.h"
-#include "utils/net.h"
-
-#ifdef HAVE_ADS
-
-#define MAX_DNS_LABEL 255 + 1
-
-struct cldap_netlogon_reply {
- uint32 type;
- uint32 flags;
- UUID_FLAT guid;
-
- char forest[MAX_DNS_LABEL];
- char domain[MAX_DNS_LABEL];
- char hostname[MAX_DNS_LABEL];
-
- char netbios_domain[MAX_DNS_LABEL];
- char netbios_hostname[MAX_DNS_LABEL];
-
- char unk[MAX_DNS_LABEL];
- char user_name[MAX_DNS_LABEL];
- char site_name[MAX_DNS_LABEL];
- char site_name_2[MAX_DNS_LABEL];
-
- uint32 version;
- uint16 lmnt_token;
- uint16 lm20_token;
-};
/*
These seem to be strings as described in RFC1035 4.1.4 and can be:
@@ -272,94 +245,34 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
return 0;
}
-/*
- do a cldap netlogon query
-*/
-int ads_cldap_netlogon(ADS_STRUCT *ads)
+/*******************************************************************
+ do a cldap netlogon query. Always 389/udp
+*******************************************************************/
+
+BOOL ads_cldap_netlogon(const char *server, const char *realm, struct cldap_netlogon_reply *reply)
{
int sock;
int ret;
- struct cldap_netlogon_reply reply;
- const char *target = opt_host ? opt_host : inet_ntoa(ads->ldap_ip);
- sock = open_udp_socket(target, ads->ldap_port);
+ sock = open_udp_socket(server, LDAP_PORT );
if (sock == -1) {
- d_fprintf(stderr, "Failed to open udp socket to %s:%u\n",
- inet_ntoa(ads->ldap_ip),
- ads->ldap_port);
- return -1;
-
+ DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
+ server));
+ return False;
}
- ret = send_cldap_netlogon(sock, ads->config.realm, global_myname(), 6);
+ ret = send_cldap_netlogon(sock, realm, global_myname(), 6);
if (ret != 0) {
- return ret;
+ return False;
}
- ret = recv_cldap_netlogon(sock, &reply);
+ ret = recv_cldap_netlogon(sock, reply);
close(sock);
if (ret == -1) {
- return -1;
+ return False;
}
- d_printf("Information for Domain Controller: %s\n\n",
- ads->config.ldap_server_name);
-
- d_printf("Response Type: ");
- switch (reply.type) {
- case SAMLOGON_AD_UNK_R:
- d_printf("SAMLOGON\n");
- break;
- case SAMLOGON_AD_R:
- d_printf("SAMLOGON_USER\n");
- break;
- default:
- d_printf("0x%x\n", reply.type);
- break;
- }
- d_printf("GUID: %s\n",
- smb_uuid_string_static(smb_uuid_unpack_static(reply.guid)));
- d_printf("Flags:\n"
- "\tIs a PDC: %s\n"
- "\tIs a GC of the forest: %s\n"
- "\tIs an LDAP server: %s\n"
- "\tSupports DS: %s\n"
- "\tIs running a KDC: %s\n"
- "\tIs running time services: %s\n"
- "\tIs the closest DC: %s\n"
- "\tIs writable: %s\n"
- "\tHas a hardware clock: %s\n"
- "\tIs a non-domain NC serviced by LDAP server: %s\n",
- (reply.flags & ADS_PDC) ? "yes" : "no",
- (reply.flags & ADS_GC) ? "yes" : "no",
- (reply.flags & ADS_LDAP) ? "yes" : "no",
- (reply.flags & ADS_DS) ? "yes" : "no",
- (reply.flags & ADS_KDC) ? "yes" : "no",
- (reply.flags & ADS_TIMESERV) ? "yes" : "no",
- (reply.flags & ADS_CLOSEST) ? "yes" : "no",
- (reply.flags & ADS_WRITABLE) ? "yes" : "no",
- (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
- (reply.flags & ADS_NDNC) ? "yes" : "no");
-
- printf("Forest:\t\t\t%s\n", reply.forest);
- printf("Domain:\t\t\t%s\n", reply.domain);
- printf("Domain Controller:\t%s\n", reply.hostname);
-
- printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
- printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
-
- if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
- if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
-
- printf("Site Name:\t\t%s\n", reply.site_name);
- printf("Site Name (2):\t\t%s\n", reply.site_name_2);
-
- d_printf("NT Version: %d\n", reply.version);
- d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
- d_printf("LM20 Token: %.2x\n", reply.lm20_token);
-
- return ret;
+ return True;
}
-#endif
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index a8877b5697..6f698dc3a9 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -112,31 +112,52 @@ static int ldap_search_with_timeout(LDAP *ld,
/*
try a connection to a given ldap server, returning True and setting the servers IP
in the ads struct if successful
-
- TODO : add a negative connection cache in here leveraged off of the one
- found in the rpc code. --jerry
*/
-BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
+BOOL ads_try_connect(ADS_STRUCT *ads, const char *server )
{
char *srv;
+ struct cldap_netlogon_reply cldap_reply;
if (!server || !*server) {
return False;
}
-
- DEBUG(5,("ads_try_connect: trying ldap server '%s' port %u\n", server, port));
+
+ DEBUG(5,("ads_try_connect: sending CLDAP request to %s\n", server));
/* this copes with inet_ntoa brokenness */
+
srv = SMB_STRDUP(server);
- ads->ld = ldap_open_with_timeout(srv, port, lp_ldap_timeout());
- if (!ads->ld) {
- free(srv);
+ ZERO_STRUCT( cldap_reply );
+
+ if ( !ads_cldap_netlogon( srv, ads->server.realm, &cldap_reply ) ) {
+ DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", srv));
return False;
}
- ads->ldap_port = port;
+
+ /* Check the CLDAP reply flags */
+
+ if ( !(cldap_reply.flags & ADS_LDAP) ) {
+ DEBUG(1,("ads_try_connect: %s's CLDAP reply says it is not an LDAP server!\n",
+ srv));
+ SAFE_FREE( srv );
+ return False;
+ }
+
+ /* Fill in the ads->config values */
+
+ SAFE_FREE(ads->config.realm);
+ SAFE_FREE(ads->config.bind_path);
+ SAFE_FREE(ads->config.ldap_server_name);
+
+ ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.hostname);
+ strupper_m(cldap_reply.domain);
+ ads->config.realm = SMB_STRDUP(cldap_reply.domain);
+ ads->config.bind_path = ads_build_dn(ads->config.realm);
+
+ ads->ldap_port = LDAP_PORT;
ads->ldap_ip = *interpret_addr2(srv);
- free(srv);
+ SAFE_FREE(srv);
/* cache the successful connection */
@@ -145,29 +166,6 @@ BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
return True;
}
-/*
- try a connection to a given ldap server, based on URL, returning True if successful
- */
-static BOOL ads_try_connect_uri(ADS_STRUCT *ads)
-{
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
- DEBUG(5,("ads_try_connect: trying ldap server at URI '%s'\n",
- ads->server.ldap_uri));
-
-
- if (ldap_initialize((LDAP**)&(ads->ld), ads->server.ldap_uri) == LDAP_SUCCESS) {
- return True;
- }
- DEBUG(0, ("ldap_initialize: %s\n", strerror(errno)));
-
-#else
-
- DEBUG(1, ("no URL support in LDAP libs!\n"));
-#endif
-
- return False;
-}
-
/**********************************************************************
Try to find an AD dc using our internal name resolution routines
Try the realm first and then then workgroup name if netbios is not
@@ -233,8 +231,6 @@ again:
/* if we fail this loop, then giveup since all the IP addresses returned were dead */
for ( i=0; i<count; i++ ) {
- /* since this is an ads conection request, default to LDAP_PORT is not set */
- int port = (ip_list[i].port!=PORT_NONE) ? ip_list[i].port : LDAP_PORT;
fstring server;
fstrcpy( server, inet_ntoa(ip_list[i].ip) );
@@ -242,7 +238,7 @@ again:
if ( !NT_STATUS_IS_OK(check_negative_conn_cache(realm, server)) )
continue;
- if ( ads_try_connect(ads, server, port) ) {
+ if ( ads_try_connect(ads, server) ) {
SAFE_FREE(ip_list);
return True;
}
@@ -270,16 +266,10 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
ads->last_attempt = time(NULL);
ads->ld = NULL;
- /* try with a URL based server */
-
- if (ads->server.ldap_uri &&
- ads_try_connect_uri(ads)) {
- goto got_connection;
- }
-
/* try with a user specified server */
+
if (ads->server.ldap_server &&
- ads_try_connect(ads, ads->server.ldap_server, LDAP_PORT)) {
+ ads_try_connect(ads, ads->server.ldap_server)) {
goto got_connection;
}
@@ -292,22 +282,12 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
got_connection:
DEBUG(3,("Connected to LDAP server %s\n", inet_ntoa(ads->ldap_ip)));
- status = ads_server_info(ads);
- if (!ADS_ERR_OK(status)) {
- DEBUG(1,("Failed to get ldap server info\n"));
- return status;
- }
-
- ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
-
- status = ADS_ERROR(smb_ldap_start_tls(ads->ld, version));
- if (!ADS_ERR_OK(status)) {
- return status;
- }
-
if (!ads->auth.user_name) {
/* have to use the userPrincipalName value here and
- not servicePrincipalName; found by Guenther Deschner @ Sernet */
+ not servicePrincipalName; found by Guenther Deschner @ Sernet.
+
+ Is this still correct? The comment does not match
+ the code. --jerry */
asprintf(&ads->auth.user_name, "host/%s", global_myname() );
}
@@ -331,10 +311,35 @@ got_connection:
}
#endif
+ /* If the caller() requested no LDAP bind, then we are done */
+
if (ads->auth.flags & ADS_AUTH_NO_BIND) {
return ADS_SUCCESS;
}
+
+ /* Otherwise setup the TCP LDAP session */
+
+ if ( (ads->ld = ldap_open_with_timeout(ads->config.ldap_server_name,
+ LDAP_PORT, lp_ldap_timeout())) == NULL )
+ {
+ return ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ }
+ ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ status = ADS_ERROR(smb_ldap_start_tls(ads->ld, version));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* fill in the current time and offsets */
+
+ status = ads_current_time( ads );
+ if ( !ADS_ERR_OK(status) ) {
+ return status;
+ }
+ /* Now do the bind */
+
if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
return ADS_ERROR(ldap_simple_bind_s( ads->ld, NULL, NULL));
}
@@ -2464,7 +2469,7 @@ static time_t ads_parse_time(const char *str)
}
-const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char * OID)
+const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, const char *schema_path, TALLOC_CTX *mem_ctx, const char * OID)
{
ADS_STATUS rc;
int count = 0;
@@ -2482,8 +2487,8 @@ const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const
goto failed;
}
- rc = ads_do_search_retry(ads, ads->config.schema_path,
- LDAP_SCOPE_SUBTREE, expr, attrs, &res);
+ rc = ads_do_search_retry(ads, schema_path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, &res);
if (!ADS_ERR_OK(rc)) {
goto failed;
}
@@ -2513,97 +2518,94 @@ failed:
* @param ads connection to ads server
* @return status of search
**/
-ADS_STATUS ads_server_info(ADS_STRUCT *ads)
+ADS_STATUS ads_current_time(ADS_STRUCT *ads)
{
- const char *attrs[] = {"ldapServiceName",
- "currentTime",
- "schemaNamingContext", NULL};
+ const char *attrs[] = {"currentTime", NULL};
ADS_STATUS status;
void *res;
- char *value;
- char *p;
char *timestr;
- char *schema_path;
TALLOC_CTX *ctx;
+ ADS_STRUCT *ads_s = ads;
if (!(ctx = talloc_init("ads_server_info"))) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
- status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
- if (!ADS_ERR_OK(status)) {
- talloc_destroy(ctx);
- return status;
- }
+ /* establish a new ldap tcp session if necessary */
- value = ads_pull_string(ads, ctx, res, "ldapServiceName");
- if (!value) {
- ads_msgfree(ads, res);
- talloc_destroy(ctx);
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ if ( !ads->ld ) {
+ if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
+ ads->server.ldap_server )) == NULL )
+ {
+ goto done;
+ }
+ ads_s->auth.flags = ADS_AUTH_ANON_BIND;
+ status = ads_connect( ads_s );
+ if ( !ADS_ERR_OK(status))
+ goto done;
}
- timestr = ads_pull_string(ads, ctx, res, "currentTime");
- if (!timestr) {
- ads_msgfree(ads, res);
+ status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
talloc_destroy(ctx);
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto done;
}
- schema_path = ads_pull_string(ads, ctx, res, "schemaNamingContext");
- if (!schema_path) {
+ timestr = ads_pull_string(ads_s, ctx, res, "currentTime");
+ if (!timestr) {
ads_msgfree(ads, res);
talloc_destroy(ctx);
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto done;
}
- SAFE_FREE(ads->config.schema_path);
- ads->config.schema_path = SMB_STRDUP(schema_path);
-
- ads_msgfree(ads, res);
+ /* but save the time and offset in the original ADS_STRUCT */
+
+ ads->config.current_time = ads_parse_time(timestr);
- p = strchr(value, ':');
- if (!p) {
- talloc_destroy(ctx);
- DEBUG(1, ("ads_server_info: returned ldap server name did not contain a ':' "
- "so was deemed invalid\n"));
- return ADS_ERROR(LDAP_DECODING_ERROR);
+ if (ads->config.current_time != 0) {
+ ads->auth.time_offset = ads->config.current_time - time(NULL);
+ DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
}
- SAFE_FREE(ads->config.ldap_server_name);
+ status = ADS_SUCCESS;
- ads->config.ldap_server_name = SMB_STRDUP(p+1);
- p = strchr(ads->config.ldap_server_name, '$');
- if (!p || p[1] != '@') {
- talloc_destroy(ctx);
- DEBUG(1, ("ads_server_info: returned ldap server name (%s) does not contain '$@'"
- " so was deemed invalid\n", ads->config.ldap_server_name));
- SAFE_FREE(ads->config.ldap_server_name);
- return ADS_ERROR(LDAP_DECODING_ERROR);
+done:
+ /* free any temporary ads connections */
+ if ( ads_s != ads ) {
+ ads_destroy( &ads_s );
}
+ talloc_destroy(ctx);
- *p = 0;
+ return status;
+}
- SAFE_FREE(ads->config.realm);
- SAFE_FREE(ads->config.bind_path);
+/*********************************************************************
+*********************************************************************/
- ads->config.realm = SMB_STRDUP(p+2);
- ads->config.bind_path = ads_build_dn(ads->config.realm);
+static ADS_STATUS ads_schema_path(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **schema_path)
+{
+ ADS_STATUS status;
+ void *res;
+ const char *schema;
+ const char *attrs[] = { "schemaNamingContext", NULL };
- DEBUG(3,("got ldap server name %s@%s, using bind path: %s\n",
- ads->config.ldap_server_name, ads->config.realm,
- ads->config.bind_path));
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
- ads->config.current_time = ads_parse_time(timestr);
+ if ( (schema = ads_pull_string(ads, mem_ctx, res, "schemaNamingContext")) == NULL ) {
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
- if (ads->config.current_time != 0) {
- ads->auth.time_offset = ads->config.current_time - time(NULL);
- DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
+ if ( (*schema_path = talloc_strdup(mem_ctx, schema)) == NULL ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
}
- talloc_destroy(ctx);
+ ads_msgfree(ads, res);
- return ADS_SUCCESS;
+ return status;
}
/**
@@ -2617,41 +2619,71 @@ BOOL ads_check_sfu_mapping(ADS_STRUCT *ads)
BOOL ret = False;
TALLOC_CTX *ctx = NULL;
const char *gidnumber, *uidnumber, *homedir, *shell, *gecos;
+ char *schema_path;
+ ADS_STRUCT *ads_s = ads;
+ ADS_STATUS status;
+
+ if ( (ctx = talloc_init("ads_check_sfu_mapping")) == NULL ) {
+ goto done;
+ }
+
+ /* establish a new ldap tcp session if necessary */
- ctx = talloc_init("ads_check_sfu_mapping");
- if (ctx == NULL)
+ if ( !ads->ld ) {
+ if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
+ ads->server.ldap_server )) == NULL )
+ {
+ goto done;
+ }
+
+ ads_s->auth.flags = ADS_AUTH_ANON_BIND;
+ status = ads_connect( ads_s );
+ if ( !ADS_ERR_OK(status))
+ goto done;
+ }
+
+ status = ads_schema_path( ads, ctx, &schema_path );
+ if ( !ADS_ERR_OK(status) ) {
+ DEBUG(3,("ads_check_sfu_mapping: Unable to retrieve schema DN!\n"));
goto done;
+ }
- gidnumber = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_GIDNUMBER_OID);
+ gidnumber = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_GIDNUMBER_OID);
if (gidnumber == NULL)
goto done;
ads->schema.sfu_gidnumber_attr = SMB_STRDUP(gidnumber);
- uidnumber = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_UIDNUMBER_OID);
+ uidnumber = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_UIDNUMBER_OID);
if (uidnumber == NULL)
goto done;
ads->schema.sfu_uidnumber_attr = SMB_STRDUP(uidnumber);
- homedir = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_HOMEDIR_OID);
+ homedir = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_HOMEDIR_OID);
if (homedir == NULL)
goto done;
ads->schema.sfu_homedir_attr = SMB_STRDUP(homedir);
- shell = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_SHELL_OID);
+ shell = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_SHELL_OID);
if (shell == NULL)
goto done;
ads->schema.sfu_shell_attr = SMB_STRDUP(shell);
- gecos = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_GECOS_OID);
+ gecos = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_GECOS_OID);
if (gecos == NULL)
goto done;
ads->schema.sfu_gecos_attr = SMB_STRDUP(gecos);
ret = True;
done:
- if (ctx)
+ /* free any temporary ads connections */
+ if ( ads_s != ads ) {
+ ads_destroy( &ads_s );
+ }
+
+ if (ctx) {
talloc_destroy(ctx);
-
+ }
+
return ret;
}
@@ -2679,81 +2711,6 @@ ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
return ADS_SUCCESS;
}
-/* this is rather complex - we need to find the allternate (netbios) name
- for the domain, but there isn't a simple query to do this. Instead
- we look for the principle names on the DCs account and find one that has
- the right form, then extract the netbios name of the domain from that
-
- NOTE! better method is this:
-
-bin/net -Uadministrator%XXXXX ads search '(&(objectclass=crossref)(dnsroot=VNET3.HOME.SAMBA.ORG))' nETBIOSName
-
-but you need to force the bind path to match the configurationNamingContext from the rootDSE
-
-*/
-ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **workgroup)
-{
- char *expr;
- ADS_STATUS rc;
- char **principles;
- char *prefix;
- int prefix_length;
- int i;
- void *res;
- const char *attrs[] = {"servicePrincipalName", NULL};
- size_t num_principals;
-
- (*workgroup) = NULL;
-
- asprintf(&expr, "(&(objectclass=computer)(dnshostname=%s.%s))",
- ads->config.ldap_server_name, ads->config.realm);
- if (expr == NULL) {
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- rc = ads_search(ads, &res, expr, attrs);
- free(expr);
-
- if (!ADS_ERR_OK(rc)) {
- return rc;
- }
-
- principles = ads_pull_strings(ads, mem_ctx, res,
- "servicePrincipalName", &num_principals);
-
- ads_msgfree(ads, res);
-
- if (!principles) {
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
- }
-
- asprintf(&prefix, "HOST/%s.%s/",
- ads->config.ldap_server_name,
- ads->config.realm);
-
- prefix_length = strlen(prefix);
-
- for (i=0;principles[i]; i++) {
- if (strnequal(principles[i], prefix, prefix_length) &&
- !strequal(ads->config.realm, principles[i]+prefix_length) &&
- !strchr(principles[i]+prefix_length, '.')) {
- /* found an alternate (short) name for the domain. */
- DEBUG(3,("Found alternate name '%s' for realm '%s'\n",
- principles[i]+prefix_length,
- ads->config.realm));
- (*workgroup) = talloc_strdup(mem_ctx, principles[i]+prefix_length);
- break;
- }
- }
- free(prefix);
-
- if (!*workgroup) {
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
- }
-
- return ADS_SUCCESS;
-}
-
/**
* find our site name
* @param ads connection to ads server
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 99a2e7ebdb..1033a375c5 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -1024,70 +1024,62 @@ static BOOL resolve_hosts(const char *name, int name_type,
static BOOL resolve_ads(const char *name, int name_type,
struct ip_service **return_iplist, int *return_count)
{
-#ifdef HAVE_ADS
- if ( name_type == 0x1c ) {
- int count, i = 0;
- NTSTATUS status;
- TALLOC_CTX *ctx;
- struct dns_rr_srv *dcs = NULL;
- int numdcs = 0;
+ int count, i = 0;
+ NTSTATUS status;
+ TALLOC_CTX *ctx;
+ struct dns_rr_srv *dcs = NULL;
+ int numdcs = 0;
+
+ if ( name_type != 0x1c )
+ return False;
- /* try to lookup the _ldap._tcp.<domain> if we are using ADS */
- if ( lp_security() != SEC_ADS )
- return False;
+ DEBUG(5,("resolve_hosts: Attempting to resolve DC's for %s using DNS\n",
+ name));
- DEBUG(5,("resolve_hosts: Attempting to resolve DC's for %s using DNS\n",
- name));
-
- if ( (ctx = talloc_init("resolve_ads")) == NULL ) {
- DEBUG(0,("resolve_ads: talloc_init() failed!\n"));
- return False;
- }
+ if ( (ctx = talloc_init("resolve_ads")) == NULL ) {
+ DEBUG(0,("resolve_ads: talloc_init() failed!\n"));
+ return False;
+ }
- status = ads_dns_query_dcs( ctx, name, &dcs, &numdcs );
- if ( !NT_STATUS_IS_OK( status ) ) {
- return False;
- }
+ status = ads_dns_query_dcs( ctx, name, &dcs, &numdcs );
+ if ( !NT_STATUS_IS_OK( status ) ) {
+ return False;
+ }
- if ( (*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numdcs)) == NULL ) {
- DEBUG(0,("resolve_ads: malloc failed for %d entries\n", count ));
- return False;
- }
+ if ( (*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numdcs)) == NULL ) {
+ DEBUG(0,("resolve_ads: malloc failed for %d entries\n", count ));
+ return False;
+ }
- i = 0;
- while ( i < numdcs ) {
+ i = 0;
+ while ( i < numdcs ) {
- /* use the IP address from the SRV structure if we have one */
- if ( is_zero_ip( dcs[i].ip ) )
- (*return_iplist)[i].ip = *interpret_addr2(dcs[i].hostname);
- else
- (*return_iplist)[i].ip = dcs[i].ip;
+ /* use the IP address from the SRV structure if we have one */
+ if ( is_zero_ip( dcs[i].ip ) )
+ (*return_iplist)[i].ip = *interpret_addr2(dcs[i].hostname);
+ else
+ (*return_iplist)[i].ip = dcs[i].ip;
- (*return_iplist)[i].port = dcs[i].port;
+ (*return_iplist)[i].port = dcs[i].port;
- /* make sure it is a valid IP. I considered checking the negative
- connection cache, but this is the wrong place for it. Maybe only
- as a hac. After think about it, if all of the IP addresses retuend
- from DNS are dead, what hope does a netbios name lookup have?
- The standard reason for falling back to netbios lookups is that
- our DNS server doesn't know anything about the DC's -- jerry */
+ /* make sure it is a valid IP. I considered checking the negative
+ connection cache, but this is the wrong place for it. Maybe only
+ as a hac. After think about it, if all of the IP addresses retuend
+ from DNS are dead, what hope does a netbios name lookup have?
+ The standard reason for falling back to netbios lookups is that
+ our DNS server doesn't know anything about the DC's -- jerry */
- if ( is_zero_ip((*return_iplist)[i].ip) )
- continue;
+ if ( is_zero_ip((*return_iplist)[i].ip) )
+ continue;
- i++;
- }
+ i++;
+ }
- TALLOC_FREE( dcs );
+ TALLOC_FREE( dcs );
- *return_count = i;
+ *return_count = i;
- return True;
- } else
-#endif /* HAVE_ADS */
- {
- return False;
- }
+ return True;
}
/*******************************************************************
@@ -1178,8 +1170,7 @@ BOOL internal_resolve_name(const char *name, int name_type,
}
} else if(strequal( tok, "ads")) {
/* deal with 0x1c names here. This will result in a
- SRV record lookup for _ldap._tcp.<domain> if we
- are using 'security = ads' */
+ SRV record lookup */
if (resolve_ads(name, name_type, return_iplist, return_count)) {
result = True;
goto done;
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index 9e450d9de7..6322a33c02 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -618,18 +618,11 @@ static void dcip_to_name( const char *domainname, const char *realm,
if ( lp_security() == SEC_ADS )
{
ADS_STRUCT *ads;
- ADS_STATUS status;
ads = ads_init( realm, domainname, NULL );
ads->auth.flags |= ADS_AUTH_NO_BIND;
- if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) ) {
- ads_destroy( &ads );
- return;
- }
-
- status = ads_server_info(ads);
- if ( !ADS_ERR_OK(status) ) {
+ if ( !ads_try_connect( ads, inet_ntoa(ip) ) ) {
ads_destroy( &ads );
return;
}
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index 54d7e8040c..b0bac86dad 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -3158,7 +3158,7 @@ WERROR check_published_printers(void)
int n_services = lp_numservices();
NT_PRINTER_INFO_LEVEL *printer = NULL;
- ads = ads_init(NULL, NULL, NULL);
+ ads = ads_init(lp_realm(), lp_workgroup(), NULL);
if (!ads) {
DEBUG(3, ("ads_init() failed\n"));
return WERR_SERVER_UNAVAILABLE;
diff --git a/source3/sam/idmap_ad.c b/source3/sam/idmap_ad.c
index f9a959e7ec..0803f2a7ab 100644
--- a/source3/sam/idmap_ad.c
+++ b/source3/sam/idmap_ad.c
@@ -78,10 +78,6 @@ static ADS_STRUCT *ad_idmap_cached_connection(void)
ADS_STATUS status;
BOOL local = False;
-#ifdef ADS_AUTH_EXTERNAL_BIND
- local = ((strncmp(ad_idmap_uri, "ldapi://", sizeof("ldapi://") - 1)) == 0);
-#endif /* ADS_AUTH_EXTERNAL_BIND */
-
if (ad_idmap_ads != NULL) {
ads = ad_idmap_ads;
@@ -105,40 +101,18 @@ static ADS_STRUCT *ad_idmap_cached_connection(void)
setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
}
- ads = ads_init(NULL, NULL, NULL);
+ ads = ads_init(lp_realm(), lp_workgroup(), NULL);
if (!ads) {
DEBUG(1,("ads_init failed\n"));
return NULL;
}
- /* if ad_imap_uri is not empty we try to connect to
- * the given URI in smb.conf. Else try to connect to
- * one of the DCs
- */
- if (*ad_idmap_uri != '\0') {
- ads->server.ldap_uri = SMB_STRDUP(ad_idmap_uri);
- if (ads->server.ldap_uri == NULL) {
- return NULL;
- }
- }
- else {
- ads->server.ldap_uri = NULL;
- ads->server.ldap_server = NULL;
- }
+ /* the machine acct password might have change - fetch it every time */
+ SAFE_FREE(ads->auth.password);
+ ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
-#ifdef ADS_AUTH_EXTERNAL_BIND
- if (local)
- ads->auth.flags |= ADS_AUTH_EXTERNAL_BIND;
- else
-#endif
- {
- /* the machine acct password might have change - fetch it every time */
- SAFE_FREE(ads->auth.password);
- ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
-
- SAFE_FREE(ads->auth.realm);
- ads->auth.realm = SMB_STRDUP(lp_realm());
- }
+ SAFE_FREE(ads->auth.realm);
+ ads->auth.realm = SMB_STRDUP(lp_realm());
status = ads_connect(ads);
if (!ADS_ERR_OK(status)) {
diff --git a/source3/utils/net.c b/source3/utils/net.c
index 1389885ba1..4c7a6280f4 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -233,6 +233,29 @@ NTSTATUS connect_to_ipc_anonymous(struct cli_state **c,
}
}
+/****************************************************************************
+connect to \\server\ipc$ using KRB5
+****************************************************************************/
+NTSTATUS connect_to_ipc_krb5(struct cli_state **c,
+ struct in_addr *server_ip, const char *server_name)
+{
+ NTSTATUS nt_status;
+
+ nt_status = cli_full_connection(c, NULL, server_name,
+ server_ip, opt_port,
+ "IPC$", "IPC",
+ opt_user_name, opt_workgroup,
+ opt_password, CLI_FULL_CONNECTION_USE_KERBEROS,
+ Undefined, NULL);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ } else {
+ DEBUG(1,("Cannot connect to server using kerberos. Error was %s\n", nt_errstr(nt_status)));
+ return nt_status;
+ }
+}
+
/**
* Connect a server and open a given pipe
*
@@ -304,8 +327,9 @@ int net_use_machine_password(void)
return 0;
}
-BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_name)
+BOOL net_find_server(const char *domain, unsigned flags, struct in_addr *server_ip, char **server_name)
{
+ const char *d = domain ? domain : opt_target_workgroup;
if (opt_host) {
*server_name = SMB_STRDUP(opt_host);
@@ -325,23 +349,22 @@ BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_na
} else if (flags & NET_FLAGS_PDC) {
struct in_addr pdc_ip;
- if (get_pdc_ip(opt_target_workgroup, &pdc_ip)) {
+ if (get_pdc_ip(d, &pdc_ip)) {
fstring dc_name;
if (is_zero_ip(pdc_ip))
return False;
- if ( !name_status_find(opt_target_workgroup, 0x1b, 0x20, pdc_ip, dc_name) )
+ if ( !name_status_find(d, 0x1b, 0x20, pdc_ip, dc_name) )
return False;
*server_name = SMB_STRDUP(dc_name);
*server_ip = pdc_ip;
}
-
} else if (flags & NET_FLAGS_DMB) {
struct in_addr msbrow_ip;
/* if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */
- if (!resolve_name(opt_target_workgroup, &msbrow_ip, 0x1B)) {
+ if (!resolve_name(d, &msbrow_ip, 0x1B)) {
DEBUG(1,("Unable to resolve domain browser via name lookup\n"));
return False;
} else {
@@ -350,7 +373,7 @@ BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_na
*server_name = SMB_STRDUP(inet_ntoa(opt_dest_ip));
} else if (flags & NET_FLAGS_MASTER) {
struct in_addr brow_ips;
- if (!resolve_name(opt_target_workgroup, &brow_ips, 0x1D)) {
+ if (!resolve_name(d, &brow_ips, 0x1D)) {
/* go looking for workgroups */
DEBUG(1,("Unable to resolve master browser via name lookup\n"));
return False;
@@ -387,17 +410,27 @@ BOOL net_find_pdc(struct in_addr *server_ip, fstring server_name, const char *do
return False;
}
+struct cli_state *net_make_ipc_connection( unsigned flags )
+{
+ return net_make_ipc_connection_ex( NULL, NULL, NULL, flags );
+}
-struct cli_state *net_make_ipc_connection(unsigned flags)
+struct cli_state *net_make_ipc_connection_ex( const char *domain, const char *server,
+ struct in_addr *ip, unsigned flags)
{
char *server_name = NULL;
struct in_addr server_ip;
struct cli_state *cli = NULL;
NTSTATUS nt_status;
- if (!net_find_server(flags, &server_ip, &server_name)) {
- d_fprintf(stderr, "\nUnable to find a suitable server\n");
- return NULL;
+ if ( !server || !ip ) {
+ if (!net_find_server(domain, flags, &server_ip, &server_name)) {
+ d_fprintf(stderr, "Unable to find a suitable server\n");
+ return NULL;
+ }
+ } else {
+ server_name = SMB_STRDUP( server );
+ server_ip = *ip;
}
if (flags & NET_FLAGS_ANONYMOUS) {
diff --git a/source3/utils/net.h b/source3/utils/net.h
index fc3167012d..b1af230a65 100644
--- a/source3/utils/net.h
+++ b/source3/utils/net.h
@@ -68,24 +68,15 @@ struct rpc_sh_cmd {
/* MACROS & DEFINES */
-#define NET_FLAGS_MASTER 1
-#define NET_FLAGS_DMB 2
-
-/* Would it be insane to set 'localhost' as the default
- remote host for this operation?
-
- For example, localhost is insane for a 'join' operation.
-*/
-#define NET_FLAGS_LOCALHOST_DEFAULT_INSANE 4
-
-/* We want to find the PDC only */
-#define NET_FLAGS_PDC 8
-
-/* We want an anonymous connection */
-#define NET_FLAGS_ANONYMOUS 16
-
-/* don't open an RPC pipe */
-#define NET_FLAGS_NO_PIPE 32
+#define NET_FLAGS_MASTER 0x00000001
+#define NET_FLAGS_DMB 0x00000002
+#define NET_FLAGS_LOCALHOST_DEFAULT_INSANE 0x00000004 /* Would it be insane to set 'localhost'
+ as the default remote host for this
+ operation? For example, localhost
+ is insane for a 'join' operation. */
+#define NET_FLAGS_PDC 0x00000008 /* PDC only */
+#define NET_FLAGS_ANONYMOUS 0x00000010 /* use an anonymous connection */
+#define NET_FLAGS_NO_PIPE 0x00000020 /* don't open an RPC pipe */
/* net share operation modes */
#define NET_MODE_SHARE_MIGRATE 1
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index f00bf0e527..a514b6c4e6 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -23,6 +23,20 @@
#include "includes.h"
#include "utils/net.h"
+/* Macro for checking RPC error codes to make things more readable */
+
+#define CHECK_RPC_ERR(rpc, msg) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
+ goto done; \
+ }
+
+#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, debug_args); \
+ goto done; \
+ }
+
#ifdef HAVE_ADS
int net_ads_usage(int argc, const char **argv)
@@ -65,6 +79,79 @@ int net_ads_usage(int argc, const char **argv)
/*
+ do a cldap netlogon query
+*/
+static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
+{
+ int ret;
+ struct cldap_netlogon_reply reply;
+
+ if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
+ d_fprintf(stderr, "CLDAP query failed!\n");
+ return -1;
+ }
+
+ d_printf("Information for Domain Controller: %s\n\n",
+ inet_ntoa(ads->ldap_ip));
+
+ d_printf("Response Type: ");
+ switch (reply.type) {
+ case SAMLOGON_AD_UNK_R:
+ d_printf("SAMLOGON\n");
+ break;
+ case SAMLOGON_AD_R:
+ d_printf("SAMLOGON_USER\n");
+ break;
+ default:
+ d_printf("0x%x\n", reply.type);
+ break;
+ }
+ d_printf("GUID: %s\n",
+ smb_uuid_string_static(smb_uuid_unpack_static(reply.guid)));
+ d_printf("Flags:\n"
+ "\tIs a PDC: %s\n"
+ "\tIs a GC of the forest: %s\n"
+ "\tIs an LDAP server: %s\n"
+ "\tSupports DS: %s\n"
+ "\tIs running a KDC: %s\n"
+ "\tIs running time services: %s\n"
+ "\tIs the closest DC: %s\n"
+ "\tIs writable: %s\n"
+ "\tHas a hardware clock: %s\n"
+ "\tIs a non-domain NC serviced by LDAP server: %s\n",
+ (reply.flags & ADS_PDC) ? "yes" : "no",
+ (reply.flags & ADS_GC) ? "yes" : "no",
+ (reply.flags & ADS_LDAP) ? "yes" : "no",
+ (reply.flags & ADS_DS) ? "yes" : "no",
+ (reply.flags & ADS_KDC) ? "yes" : "no",
+ (reply.flags & ADS_TIMESERV) ? "yes" : "no",
+ (reply.flags & ADS_CLOSEST) ? "yes" : "no",
+ (reply.flags & ADS_WRITABLE) ? "yes" : "no",
+ (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
+ (reply.flags & ADS_NDNC) ? "yes" : "no");
+
+ printf("Forest:\t\t\t%s\n", reply.forest);
+ printf("Domain:\t\t\t%s\n", reply.domain);
+ printf("Domain Controller:\t%s\n", reply.hostname);
+
+ printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
+ printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
+
+ if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
+ if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
+
+ printf("Site Name:\t\t%s\n", reply.site_name);
+ printf("Site Name (2):\t\t%s\n", reply.site_name_2);
+
+ d_printf("NT Version: %d\n", reply.version);
+ d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
+ d_printf("LM20 Token: %.2x\n", reply.lm20_token);
+
+ return ret;
+}
+
+
+/*
this implements the CLDAP based netlogon lookup requests
for finding the domain controller of a ADS domain
*/
@@ -93,7 +180,7 @@ static int net_ads_lookup(int argc, const char **argv)
ads->ldap_port = 389;
}
- return ads_cldap_netlogon(ads);
+ return net_ads_cldap_netlogon(ads);
}
@@ -102,14 +189,7 @@ static int net_ads_info(int argc, const char **argv)
{
ADS_STRUCT *ads;
- /* if netbios is disabled we have to default to the realm from smb.conf */
-
- if ( lp_disable_netbios() && *lp_realm() )
- ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
- else
- ads = ads_init(NULL, opt_target_workgroup, opt_host);
-
- if (ads) {
+ if ( (ads = ads_init(lp_realm(), opt_target_workgroup, opt_host)) != NULL ) {
ads->auth.flags |= ADS_AUTH_NO_BIND;
}
@@ -120,6 +200,13 @@ static int net_ads_info(int argc, const char **argv)
return -1;
}
+ /* Try to set the server's current time since we didn't do a full
+ TCP LDAP session initially */
+
+ if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
+ d_fprintf( stderr, "Failed to get server's current time!\n");
+ }
+
d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
d_printf("Realm: %s\n", ads->config.realm);
@@ -212,10 +299,19 @@ retry:
int net_ads_check(void)
{
ADS_STRUCT *ads;
+ ADS_STATUS status;
- ads = ads_startup();
- if (!ads)
+ if ( (ads = ads_init( lp_realm(), lp_workgroup(), NULL )) == NULL ) {
return -1;
+ }
+
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
+
+ status = ads_connect(ads);
+ if ( !ADS_ERR_OK(status) ) {
+ return -1;
+ }
+
ads_destroy(&ads);
return 0;
}
@@ -226,28 +322,38 @@ int net_ads_check(void)
static int net_ads_workgroup(int argc, const char **argv)
{
ADS_STRUCT *ads;
- TALLOC_CTX *ctx;
- const char *workgroup;
+ ADS_STATUS status;
+ const char *realm = NULL;
+ struct cldap_netlogon_reply reply;
- if (!(ads = ads_startup())) return -1;
+ if ( strequal(lp_workgroup(), opt_target_workgroup ) )
+ realm = lp_realm();
- if (!(ctx = talloc_init("net_ads_workgroup"))) {
- ads_destroy(&ads);
- return -1;
+ ads = ads_init(realm, opt_target_workgroup, opt_host);
+ if (ads) {
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
}
- if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
- d_fprintf(stderr, "Failed to find workgroup for realm '%s'\n",
- ads->config.realm);
- talloc_destroy(ctx);
- ads_destroy(&ads);
+ status = ads_connect(ads);
+ if (!ADS_ERR_OK(status) || !ads) {
+ d_fprintf(stderr, "Didn't find the cldap server!\n");
+ return -1;
+ }
+
+ if (!ads->config.realm) {
+ ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
+ ads->ldap_port = 389;
+ }
+
+ if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
+ d_fprintf(stderr, "CLDAP query failed!\n");
return -1;
}
- d_printf("Workgroup: %s\n", workgroup);
+ d_printf("Workgroup: %s\n", reply.netbios_domain);
- talloc_destroy(ctx);
ads_destroy(&ads);
+
return 0;
}
@@ -707,28 +813,14 @@ int net_ads_testjoin(int argc, const char **argv)
return 0;
}
-/*
- join a domain using ADS
- */
-int net_ads_join(int argc, const char **argv)
-{
- ADS_STRUCT *ads;
- ADS_STATUS rc;
- char *password;
- char *machine_account = NULL;
- char *tmp_password;
- const char *org_unit = NULL;
- char *dn;
- void *res;
- DOM_SID dom_sid;
- char *ou_str;
- uint32 sec_channel_type = SEC_CHAN_WKSTA;
- uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
- const char *short_domain_name = NULL;
- TALLOC_CTX *ctx = NULL;
+/*******************************************************************
+ Simple configu checks before beginning the join
+ ********************************************************************/
- if (lp_server_role() == ROLE_STANDALONE) {
- d_printf("cannot join as standalone machine\n");
+static int check_ads_config( void )
+{
+ if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
+ d_printf("Host is not configured as a member server.\n");
return -1;
}
@@ -739,92 +831,397 @@ int net_ads_join(int argc, const char **argv)
return -1;
}
- if (argc > 0) {
- org_unit = argv[0];
+ if ( lp_security() == SEC_ADS && !*lp_realm()) {
+ d_fprintf(stderr, "realm must be set in in smb.conf for ADS "
+ "join to succeed.\n");
+ return -1;
}
if (!secrets_init()) {
DEBUG(1,("Failed to initialise secrets database\n"));
return -1;
}
+
+ return 0;
+}
- tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
- password = SMB_STRDUP(tmp_password);
+/*******************************************************************
+ Store the machine password and domain SID
+ ********************************************************************/
- if (!(ads = ads_startup())) {
+static int store_domain_account( const char *domain, DOM_SID *sid, const char *pw )
+{
+ if (!secrets_store_domain_sid(domain, sid)) {
+ DEBUG(1,("Failed to save domain sid\n"));
return -1;
}
- if (!*lp_realm()) {
- d_fprintf(stderr, "realm must be set in in smb.conf for ADS join to succeed.\n");
- ads_destroy(&ads);
+ if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
+ DEBUG(1,("Failed to save machine password\n"));
return -1;
}
- if (strcmp(ads->config.realm, lp_realm()) != 0) {
- d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm());
- ads_destroy(&ads);
- return -1;
+ return 0;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static NTSTATUS join_fetch_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID **sid )
+{
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND lsa_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *domain = NULL;
+
+ if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
+ DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
+ nt_errstr(status) ));
+ return status;
}
- ou_str = ads_ou_string(ads,org_unit);
- asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
- free(ou_str);
+ status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
- rc = ads_search_dn(ads, &res, dn, NULL);
- ads_msgfree(ads, res);
+ status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx,
+ &lsa_pol, 5, &domain, sid);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
- if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
- d_fprintf(stderr, "ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
- org_unit, dn);
- ads_destroy(&ads);
- return -1;
+ rpccli_lsa_close(pipe_hnd, mem_ctx, &lsa_pol);
+ cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
+
+ /* Bail out if domain didn't get set. */
+ if (!domain) {
+ DEBUG(0, ("Could not get domain name.\n"));
+ return NT_STATUS_UNSUCCESSFUL;
}
- free(dn);
+
+ return NT_STATUS_OK;
+}
- if (!ADS_ERR_OK(rc)) {
- d_fprintf(stderr, "ads_join_realm: %s\n", ads_errstr(rc));
- ads_destroy(&ads);
- return -1;
- }
+/*******************************************************************
+ Do the domain join
+ ********************************************************************/
+
+static NTSTATUS join_create_machine( TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ DOM_SID *dom_sid, const char *clear_pw )
+{
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND sam_pol, domain_pol, user_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ const char *const_acct_name;
+ uint32 user_rid;
+ uint32 num_rids, *name_types, *user_rids;
+ uint32 flags = 0x3e8;
+ uint32 acb_info = ACB_WSTRUST;
+ uchar pwbuf[516];
+ SAM_USERINFO_CTR ctr;
+ SAM_USER_INFO_24 p24;
+ SAM_USER_INFO_16 p16;
+ uchar md4_trust_password[16];
+
+ /* Open the domain */
+
+ if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
+ DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
+ nt_errstr(status) ));
+ return status;
+ }
- rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
- if (!ADS_ERR_OK(rc)) {
- d_fprintf(stderr, "ads_join_realm: %s\n", ads_errstr(rc));
- ads_destroy(&ads);
+ status = rpccli_samr_connect(pipe_hnd, mem_ctx,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+
+ status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ /* Create domain user */
+
+ acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
+ strlower_m(acct_name);
+ const_acct_name = acct_name;
+
+ status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
+ acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
+
+ if ( !NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
+ {
+ d_fprintf(stderr, "Creation of workstation account failed\n");
+
+ /* If NT_STATUS_ACCESS_DENIED then we have a valid
+ username/password combo but the user does not have
+ administrator access. */
+
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
+ d_fprintf(stderr, "User specified does not have administrator privileges\n");
+
+ return status;
+ }
+
+ /* We *must* do this.... don't ask... */
+
+ if (NT_STATUS_IS_OK(status)) {
+ rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
+ }
+
+ status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
+ &domain_pol, flags, 1, &const_acct_name,
+ &num_rids, &user_rids, &name_types);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ if ( name_types[0] != SID_NAME_USER) {
+ DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
+ return NT_STATUS_INVALID_WORKSTATION;
+ }
+
+ user_rid = user_rids[0];
+
+ /* Open handle on user */
+
+ status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
+
+ /* Create a random machine account password */
+
+ E_md4hash( clear_pw, md4_trust_password);
+ encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
+
+ /* Set password on machine account */
+
+ ZERO_STRUCT(ctr);
+ ZERO_STRUCT(p24);
+
+ init_sam_user_info24(&p24, (char *)pwbuf,24);
+
+ ctr.switch_value = 24;
+ ctr.info.id24 = &p24;
+
+ status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol,
+ 24, &cli->user_session_key, &ctr);
+
+ /* Why do we have to try to (re-)set the ACB to be the same as what
+ we passed in the samr_create_dom_user() call? When a NT
+ workstation is joined to a domain by an administrator the
+ acb_info is set to 0x80. For a normal user with "Add
+ workstations to the domain" rights the acb_info is 0x84. I'm
+ not sure whether it is supposed to make a difference or not. NT
+ seems to cope with either value so don't bomb out if the set
+ userinfo2 level 0x10 fails. -tpot */
+
+ ZERO_STRUCT(ctr);
+ ctr.switch_value = 16;
+ ctr.info.id16 = &p16;
+
+ init_sam_user_info16(&p16, acb_info);
+
+ /* Ignoring the return value is necessary for joining a domain
+ as a normal user with "Add workstation to domain" privilege. */
+
+ status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
+ &cli->user_session_key, &ctr);
+
+ rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
+ cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
+
+ return status;
+}
+
+/*******************************************************************
+ Do the domain join
+ ********************************************************************/
+
+static int net_join_domain( TALLOC_CTX *ctx, const char *servername,
+ struct in_addr *ip, DOM_SID **dom_sid, const char *password )
+{
+ int ret = -1;
+ struct cli_state *cli = NULL;
+
+ if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, ip, servername)) )
+ goto done;
+
+ saf_store( cli->server_domain, cli->desthost );
+
+ if ( !NT_STATUS_IS_OK(join_fetch_domain_sid( ctx, cli, dom_sid )) )
+ goto done;
+
+ if ( !NT_STATUS_IS_OK(join_create_machine( ctx, cli, *dom_sid, password )) )
+ goto done;
+
+ ret = 0;
+
+done:
+ if ( cli )
+ cli_shutdown(cli);
+
+ return ret;
+}
+
+/*******************************************************************
+ Set a machines dNSHostName and servicePrincipalName attributes
+ ********************************************************************/
+
+static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
+{
+ ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
+ char *host_upn, *new_dn, *controlstr;
+ ADS_MODLIST mods;
+ const char *servicePrincipalName[3] = {NULL, NULL, NULL};
+ char *psp;
+ unsigned acct_control;
+ fstring my_fqdn;
+ LDAPMessage *res = NULL;
+ char *dn_string = NULL;
+ const char *machine_name = global_myname();
+ int count;
+ uint32 account_type;
+
+ if ( !machine_name ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* Find our DN */
+
+ status = ads_find_machine_acct(ads_s, (void **)(void *)&res, machine_name);
+ if (!ADS_ERR_OK(status))
+ return status;
+
+ if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
+ DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
+ DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
+ goto done;
+ }
+
+ new_dn = talloc_strdup(ctx, dn_string);
+ ads_memfree(ads_s, dn_string);
+ if (!new_dn) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* Windows only creates HOST/shortname & HOST/fqdn. We create
+ the UPN as well so that 'kinit -k' will work. You can only
+ request a TGT for entries with a UPN in AD. */
+
+ if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
+ goto done;
+ strupper_m(psp);
+ servicePrincipalName[0] = psp;
+
+ name_to_fqdn(my_fqdn, machine_name);
+ strlower_m(my_fqdn);
+ if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
+ goto done;
+ servicePrincipalName[1] = psp;
+
+ if (!(host_upn = talloc_asprintf(ctx, "%s@%s", servicePrincipalName[0], ads_s->config.realm)))
+ goto done;
+
+ /* set the account control string now */
+
+ acct_control = account_type | UF_DONT_EXPIRE_PASSWD;
+#ifndef ENCTYPE_ARCFOUR_HMAC
+ acct_control |= UF_USE_DES_KEY_ONLY;
+#endif
+ if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) {
+ goto done;
+ }
+
+ /* now do the mods */
+
+ if (!(mods = ads_init_mods(ctx))) {
+ goto done;
+ }
+
+ /* fields of primary importance */
+
+ ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
+ ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
+#if 0
+ ads_mod_str(ctx, &mods, "userPrincipalName", host_upn);
+ ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
+ ads_mod_str(ctx, &mods, "operatingSystemVersion", SAMBA_VERSION_STRING);
+ ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
+#endif
+
+ status = ads_gen_mod(ads_s, new_dn, mods);
+
+done:
+ ads_msgfree(ads_s, res);
+
+ return status;
+}
+
+/*******************************************************************
+ join a domain using ADS (LDAP mods)
+ ********************************************************************/
+
+int net_ads_join(int argc, const char **argv)
+{
+ ADS_STRUCT *ads, *ads_s;
+ ADS_STATUS status;
+ char *machine_account = NULL;
+ const char *short_domain_name = NULL;
+ char *tmp_password, *password;
+ struct cldap_netlogon_reply cldap_reply;
+ TALLOC_CTX *ctx;
+ DOM_SID *domain_sid = NULL;
+
+ if ( check_ads_config() != 0 ) {
+ d_fprintf(stderr, "Invalid configuration. Exiting....\n");
return -1;
}
- rc = ads_domain_sid(ads, &dom_sid);
- if (!ADS_ERR_OK(rc)) {
- d_fprintf(stderr, "ads_domain_sid: %s\n", ads_errstr(rc));
- ads_destroy(&ads);
+ if (!(ads = ads_init(lp_realm(), NULL, NULL ))) {
return -1;
}
+ ads->auth.flags = ADS_AUTH_NO_BIND;
+ status = ads_connect(ads);
- if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
- d_fprintf(stderr, "asprintf failed\n");
+ if (strcmp(ads->config.realm, lp_realm()) != 0) {
+ d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
+ "(%s) DO NOT match. Aborting join\n", ads->config.realm,
+ lp_realm());
ads_destroy(&ads);
return -1;
}
- rc = ads_set_machine_password(ads, machine_account, password);
- if (!ADS_ERR_OK(rc)) {
- d_fprintf(stderr, "ads_set_machine_password: %s\n", ads_errstr(rc));
- ads_destroy(&ads);
+
+ if (!(ctx = talloc_init("net_join_domain"))) {
+ DEBUG(0, ("Could not initialise talloc context\n"));
return -1;
}
+
+ /* Do the domain join here */
+
+ tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ password = talloc_strdup(ctx, tmp_password);
- /* make sure we get the right workgroup */
-
- if ( !(ctx = talloc_init("net ads join")) ) {
- d_fprintf(stderr, "talloc_init() failed!\n");
- ads_destroy(&ads);
+ if ( net_join_domain( ctx, ads->config.ldap_server_name, &ads->ldap_ip, &domain_sid, password ) != 0 ) {
+ d_fprintf(stderr, "Failed to join domain!\n");
return -1;
}
- rc = ads_workgroup_name(ads, ctx, &short_domain_name);
- if ( ADS_ERR_OK(rc) ) {
+ /* Check the short name of the domain */
+
+ ZERO_STRUCT( cldap_reply );
+
+ if ( ads_cldap_netlogon( ads->config.ldap_server_name,
+ ads->server.realm, &cldap_reply ) )
+ {
+ short_domain_name = talloc_strdup( ctx, cldap_reply.netbios_domain );
if ( !strequal(lp_workgroup(), short_domain_name) ) {
d_printf("The workgroup in smb.conf does not match the short\n");
d_printf("domain name obtained from the server.\n");
@@ -836,46 +1233,74 @@ int net_ads_join(int argc, const char **argv)
}
d_printf("Using short domain name -- %s\n", short_domain_name);
-
- /* HACK ALRET! Store the sid and password under bother the lp_workgroup()
+
+ /* HACK ALERT! Store the sid and password under both the lp_workgroup()
value from smb.conf and the string returned from the server. The former is
neede to bootstrap winbindd's first connection to the DC to get the real
short domain name --jerry */
-
- if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
- DEBUG(1,("Failed to save domain sid\n"));
+
+ if ( (store_domain_account( lp_workgroup(), domain_sid, password ) == -1)
+ || (store_domain_account( short_domain_name, domain_sid, password ) == -1) )
+ {
ads_destroy(&ads);
return -1;
}
- if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
- DEBUG(1,("Failed to save machine password\n"));
- ads_destroy(&ads);
- return -1;
- }
+ /* Verify that everything is ok */
-#ifdef HAVE_KRB5
- if (!kerberos_derive_salting_principal(machine_account)) {
- DEBUG(1,("Failed to determine salting principal\n"));
- ads_destroy(&ads);
+ if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
+ d_fprintf(stderr, "Failed to verify membership in domain!\n");
return -1;
+ }
+
+ /* From here on out, use the machine account. But first delete any
+ existing tickets based on the user's creds. */
+
+ ads_kdestroy( NULL );
+
+ status = ADS_ERROR(LDAP_SERVER_DOWN);
+ ads_s = ads_init( ads->server.realm, ads->server.workgroup, ads->server.ldap_server );
+
+ if ( ads_s ) {
+ asprintf( &ads_s->auth.user_name, "%s$", global_myname() );
+ ads_s->auth.password = secrets_fetch_machine_password( short_domain_name, NULL, NULL );
+ ads_s->auth.realm = SMB_STRDUP( lp_realm() );
+ ads_kinit_password( ads_s );
+ status = ads_connect( ads_s );
+ }
+ if ( !ADS_ERR_OK(status) ) {
+ d_fprintf( stderr, "LDAP bind using machine credentials failed!\n");
+ d_fprintf(stderr, "Only NTLM authentication will be possible.\n");
+ } else {
+ /* create the dNSHostName & servicePrincipalName values */
+
+ status = net_set_machine_spn( ctx, ads_s );
+ if ( !ADS_ERR_OK(status) ) {
+ d_fprintf(stderr, "Failed to set servicePrincipalNames.\n");
+ d_fprintf(stderr, "Only NTLM authentication will be possible.\n");
+
+ /* don't fail */
+ }
}
+
+ ads_destroy( &ads_s );
+
- if (!kerberos_derive_cifs_salting_principals()) {
- DEBUG(1,("Failed to determine salting principals\n"));
+#if defined(HAVE_KRB5)
+ if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
+ d_fprintf(stderr, "asprintf failed\n");
ads_destroy(&ads);
return -1;
}
-#endif
- if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
- DEBUG(1,("Failed to save domain sid\n"));
+ if (!kerberos_derive_salting_principal(machine_account)) {
+ DEBUG(1,("Failed to determine salting principal\n"));
ads_destroy(&ads);
return -1;
}
- if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
- DEBUG(1,("Failed to save machine password\n"));
+ if (!kerberos_derive_cifs_salting_principals()) {
+ DEBUG(1,("Failed to determine salting principals\n"));
ads_destroy(&ads);
return -1;
}
@@ -884,18 +1309,20 @@ int net_ads_join(int argc, const char **argv)
if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
DEBUG(1,("Error creating host keytab!\n"));
}
+#endif
d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
- SAFE_FREE(password);
SAFE_FREE(machine_account);
- if ( ctx ) {
- talloc_destroy(ctx);
- }
+ TALLOC_FREE( ctx );
ads_destroy(&ads);
+
return 0;
}
+/*******************************************************************
+ ********************************************************************/
+
int net_ads_printer_usage(int argc, const char **argv)
{
d_printf(
@@ -913,6 +1340,9 @@ int net_ads_printer_usage(int argc, const char **argv)
return -1;
}
+/*******************************************************************
+ ********************************************************************/
+
static int net_ads_printer_search(int argc, const char **argv)
{
ADS_STRUCT *ads;
@@ -1549,6 +1979,7 @@ int net_ads_help(int argc, const char **argv)
#if 0
{"INFO", net_ads_info},
{"JOIN", net_ads_join},
+ {"JOIN2", net_ads_join2},
{"LEAVE", net_ads_leave},
{"STATUS", net_ads_status},
{"PASSWORD", net_ads_password},
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 0c9f411915..c9e4350692 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -6197,7 +6197,7 @@ BOOL net_rpc_check(unsigned flags)
char *server_name = NULL;
/* flags (i.e. server type) may depend on command */
- if (!net_find_server(flags, &server_ip, &server_name))
+ if (!net_find_server(NULL, flags, &server_ip, &server_name))
return False;
ZERO_STRUCT(cli);
diff --git a/source3/utils/net_rpc_join.c b/source3/utils/net_rpc_join.c
index d611940e65..2c55b0e946 100644
--- a/source3/utils/net_rpc_join.c
+++ b/source3/utils/net_rpc_join.c
@@ -41,7 +41,7 @@
* @return A shell status integer (0 for success)
*
**/
-static int net_rpc_join_ok(const char *domain)
+int net_rpc_join_ok(const char *domain, const char *server, struct in_addr *ip )
{
uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
struct cli_state *cli = NULL;
@@ -50,7 +50,7 @@ static int net_rpc_join_ok(const char *domain)
NTSTATUS ntret = NT_STATUS_UNSUCCESSFUL;
/* Connect to remote machine */
- if (!(cli = net_make_ipc_connection(NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC))) {
+ if (!(cli = net_make_ipc_connection_ex(domain, server, ip, (NET_FLAGS_ANONYMOUS|NET_FLAGS_PDC)))) {
return -1;
}
@@ -402,7 +402,7 @@ int net_rpc_join_newstyle(int argc, const char **argv)
}
/* double-check, connection from scratch */
- retval = net_rpc_join_ok(domain);
+ retval = net_rpc_join_ok(domain, cli->desthost, &cli->dest_ip);
done:
@@ -434,7 +434,7 @@ int net_rpc_testjoin(int argc, const char **argv)
char *domain = smb_xstrdup(opt_target_workgroup);
/* Display success or failure */
- if (net_rpc_join_ok(domain) != 0) {
+ if (net_rpc_join_ok(domain, NULL, NULL) != 0) {
fprintf(stderr,"Join to domain '%s' is not valid\n",domain);
free(domain);
return -1;