r15543: New implementation of 'net ads join' to be more like Windows XP.
authorGerald Carter <jerry@samba.org>
Fri, 12 May 2006 15:17:35 +0000 (15:17 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:16:57 +0000 (11:16 -0500)
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)

16 files changed:
source3/Makefile.in
source3/include/ads.h
source3/include/ads_cldap.h [new file with mode: 0644]
source3/include/includes.h
source3/libads/ads_struct.c
source3/libads/cldap.c [moved from source3/utils/net_ads_cldap.c with 68% similarity]
source3/libads/ldap.c
source3/libsmb/namequery.c
source3/nsswitch/winbindd_cm.c
source3/printing/nt_printing.c
source3/sam/idmap_ad.c
source3/utils/net.c
source3/utils/net.h
source3/utils/net_ads.c
source3/utils/net_rpc.c
source3/utils/net_rpc_join.c

index 32c8429cdfe044e460eed1d827b3e4d898e79578..2d0ac9ab7a92ee60df037fe8914e86d17cae5a3f 100644 (file)
@@ -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 \
index f29c94bb9019a8eebb35d30c77fdb2795efcb065..48b9bbffa02d44f41d23ab46c6c9ba6ec0c3be98 100644 (file)
@@ -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 (file)
index 0000000..65feb07
--- /dev/null
@@ -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 */
+
+
index 998a0715e29c6d2b34723328407895f5fbe69c90..a13cffea1408447d9bc8a4efe63eda25654e547f 100644 (file)
@@ -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"
 
 /*
index 9b2179ad3167023ff769d48f8471a9f2a14a1ba8..48533c7ffb22d5a3f9e8346f6f3528944523f7ce 100644 (file)
@@ -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);
similarity index 68%
rename from source3/utils/net_ads_cldap.c
rename to source3/libads/cldap.c
index 2e7a28b3222ff28b350e9f11dfbefa9b31385e71..6a62f573c93941d4a08b9b6c1c73a02dd9afe700 100644 (file)
 */
 
 #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
index a8877b56970ce6fd722113f1b1236e5352f595c5..6f698dc3a937fa6c76032b298e3030bbb8fb83e0 100644 (file)
@@ -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
index 99a2e7ebdb300ff0cc7c0e09263584d8f144e4a1..1033a375c56d674061dcf606d61fc6be8223e4bf 100644 (file)
@@ -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;
index 9e450d9de74c9d441e3f692a8b0cb81564ccd453..6322a33c029457b60db33ea9c56150eb63a7f050 100644 (file)
@@ -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;
                }
index 54d7e8040cd357fb16ee92bc8b65e528ac2e761d..b0bac86dadc516ec1336965f81f0202d9d8e9056 100644 (file)
@@ -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;
index f9a959e7ec0c2e6c8d805a82b1d81f437f61da19..0803f2a7abb0d04cab1a49edbe907cf26713583b 100644 (file)
@@ -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)) {
index 1389885ba1776b2d0ff9a4fe7903ddaf87896e31..4c7a6280f46f66f021c67c6698678c52208cb29e 100644 (file)
@@ -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) {
index fc3167012d6d41d011ba5a3ddc82077ac4effb8b..b1af230a659699870e16b56b881dcba577194b5d 100644 (file)
@@ -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
index f00bf0e5277748a818f7f9a7235878af4f2733ff..a514b6c4e6e7357ffe9c61b6e819fa6cb6fc8c18 100644 (file)
 #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)
@@ -64,6 +78,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},
index 0c9f41191556c892732af587e6887b386d5b8dfd..c9e435069216993a54a34ea8da0df2e4294666aa 100644 (file)
@@ -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);
index d611940e656b3c459ae2bc204263fbcf1eec320f..2c55b0e9462f6bb3df92aa25ad2bd12ca1189803 100644 (file)
@@ -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;