samba-technical@lists.samba.org
[Top] [All Lists]

Add support for searching GC in v3-3-test

Subject: Add support for searching GC in v3-3-test
From: "Gerald (Jerry) Carter"
Date: Thu, 19 Jun 2008 13:48:31 -0500
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Folks,

Here is a patch to add support for search global catalog.
Pretty trivial.  The first patch is the API change.  The second
patch is just junk toi show how it can be used.  It changes
"net ads search" to use GC rather than a DC.

First patch is up for discussion.  Second patch is just for
your enjoy and hsould not be considered for inclusion upstream.




cheers, jerry
- --
=====================================================================
Samba                                    ------- http://www.samba.org
Likewise Software          ---------  http://www.likewisesoftware.com
"What man is a man who does not make the world better?"      --Balian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFIWqn/IR7qMdg1EfYRAj+FAJ4nTXAsIX2DEQI03VokWn87w9rUewCgm6Lh
85IvsSCF8N3eH9ybH76b34w=
=xXWQ
-----END PGP SIGNATURE-----
>From 17ab073eeb885909e941f672b7ac7b5fe9366eef Mon Sep 17 00:00:00 2001
From: Gerald Carter <coffeedude@xxxxxxxxxxxx>
Date: Thu, 19 Jun 2008 13:29:38 -0500
Subject: [PATCH] libads: Add API call to connect to a global catalog server.

Extends ads_connect() to a new call ads_connect_gc() which connects on port
3268 rather than port 389.
---
 source/include/ads.h          |    4 +-
 source/include/proto.h        |    3 +-
 source/include/smb.h          |    1 +
 source/libads/ldap.c          |  148 +++++++++++++++++++++++++++++++++++++++--
 source/utils/net.h            |    5 ++
 source/winbindd/winbindd_cm.c |    2 +-
 6 files changed, 155 insertions(+), 8 deletions(-)

diff --git a/source/include/ads.h b/source/include/ads.h
index d5ce88b..3bc85f3 100644
--- a/source/include/ads.h
+++ b/source/include/ads.h
@@ -53,7 +53,9 @@ typedef struct ads_struct {
                char *realm;
                char *workgroup;
                char *ldap_server;
-               int foreign; /* set to 1 if connecting to a foreign realm */
+               int foreign; /* set to 1 if connecting to a foreign
+                             * realm */
+               bool gc;     /* Is this a global catalog server? */
        } server;
 
        /* info needed to authenticate */
diff --git a/source/include/proto.h b/source/include/proto.h
index 3064267..a6ea385 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -2060,8 +2060,9 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
 
 bool ads_sitename_match(ADS_STRUCT *ads);
 bool ads_closest_dc(ADS_STRUCT *ads);
-bool ads_try_connect(ADS_STRUCT *ads, const char *server );
+bool ads_try_connect(ADS_STRUCT *ads, const char *server, bool gc);
 ADS_STATUS ads_connect(ADS_STRUCT *ads);
+ADS_STATUS ads_connect_gc(ADS_STRUCT *ads);
 void ads_disconnect(ADS_STRUCT *ads);
 ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
                                int scope, const char *expr, const char **attrs,
diff --git a/source/include/smb.h b/source/include/smb.h
index 7ae66f1..7fcae51 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -1847,6 +1847,7 @@ typedef struct _smb_iconv_t {
 #ifndef LDAP_PORT
 #define LDAP_PORT      389
 #endif
+#define LDAP_GC_PORT    3268
 
 /* used by the IP comparison function */
 struct ip_service {
diff --git a/source/libads/ldap.c b/source/libads/ldap.c
index 7b9e510..276cfe8 100644
--- a/source/libads/ldap.c
+++ b/source/libads/ldap.c
@@ -173,7 +173,7 @@ bool ads_closest_dc(ADS_STRUCT *ads)
   try a connection to a given ldap server, returning True and setting the 
servers IP
   in the ads struct if successful
  */
-bool ads_try_connect(ADS_STRUCT *ads, const char *server )
+bool ads_try_connect(ADS_STRUCT *ads, const char *server, bool gc)
 {
        char *srv;
        struct nbt_cldap_netlogon_5 cldap_reply;
@@ -238,7 +238,7 @@ bool ads_try_connect(ADS_STRUCT *ads, const char *server )
        }
        ads->server.workgroup          = SMB_STRDUP(cldap_reply.domain);
 
-       ads->ldap.port = LDAP_PORT;
+       ads->ldap.port = gc ? LDAP_GC_PORT : LDAP_PORT;
        if (!interpret_string_addr(&ads->ldap.ss, srv, 0)) {
                DEBUG(1,("ads_try_connect: unable to convert %s "
                        "to an address\n",
@@ -358,7 +358,7 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
                        }
                }
 
-               if ( ads_try_connect(ads, server) ) {
+               if ( ads_try_connect(ads, server, false) ) {
                        SAFE_FREE(ip_list);
                        SAFE_FREE(sitename);
                        return NT_STATUS_OK;
@@ -385,6 +385,144 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
        return NT_STATUS_NO_LOGON_SERVERS;
 }
 
+/*********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ads_lookup_site(void)
+{
+       ADS_STRUCT *ads = NULL;
+       ADS_STATUS ads_status;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       struct nbt_cldap_netlogon_5 cldap_reply;
+
+       ZERO_STRUCT(cldap_reply);
+
+       ads = ads_init(lp_realm(), NULL, NULL);
+       if (!ads) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* The NO_BIND here will find a DC and set the client site
+          but not establish the TCP connection */
+
+       ads->auth.flags = ADS_AUTH_NO_BIND;
+       ads_status = ads_connect(ads);
+       if (!ADS_ERR_OK(ads_status)) {
+               DEBUG(4, ("ads_lookup_site: ads_connect to our realm failed! 
(%s)\n",
+                         ads_errstr(ads_status)));
+       }
+       nt_status = ads_ntstatus(ads_status);
+
+       if (ads) {
+               ads_destroy(&ads);
+       }
+
+       return nt_status;
+}
+
+/*********************************************************************
+ *********************************************************************/
+
+static const char* host_dns_domain(const char *fqdn)
+{
+       const char *p = fqdn;
+
+       while (p && *p != '.') {
+               p++;
+       }
+
+       /* go to next char following '.' */
+
+       if (p)
+               p++;
+
+       return p;
+}
+
+
+/**
+ * Connect to the Global Catalog server
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ *
+ * Simple wrapper around ads_connect() that fills in the
+ * GC ldap server information
+ **/
+
+ADS_STATUS ads_connect_gc(ADS_STRUCT *ads)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct dns_rr_srv *gcs_list;
+       int num_gcs;
+       char *realm = ads->server.realm;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+       int i;
+       bool done = false;
+       char *sitename = NULL;
+
+       if (!realm)
+               realm = lp_realm();
+
+       if ((sitename = sitename_fetch(realm)) == NULL) {
+               ads_lookup_site();
+               sitename = sitename_fetch(realm);
+       }
+
+       do {
+               /* We try once with a sitename and once without
+                  (unless we don't have a sitename and then we're
+                  done */
+
+               if (sitename == NULL)
+                       done = true;
+
+               nt_status = ads_dns_query_gcs(frame, realm, sitename,
+                                             &gcs_list, &num_gcs);
+
+               SAFE_FREE(sitename);
+
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       ads_status = ADS_ERROR_NT(nt_status);
+                       goto done;
+               }
+
+               /* Loop until we get a successful connection or have gone
+                  through them all.  When connecting a GC server, make sure 
that
+                  the realm is the server's DNS name and not the forest root */
+
+               for (i=0; i<num_gcs; i++) {
+                       ads->server.gc = true;
+                       ads->server.ldap_server = 
SMB_STRDUP(gcs_list[i].hostname);
+                       ads->server.realm = 
SMB_STRDUP(host_dns_domain(ads->server.ldap_server));
+                       ads_status = ads_connect(ads);
+                       if (ADS_ERR_OK(ads_status)) {
+                               /* Reset the bind_dn to "".  A Global Catalog 
server
+                                  may host  multiple domain trees in a forest.
+                                  Windows 2003 GC server will accept "" as the 
search
+                                  path to imply search all domain trees in the 
forest */
+
+                               SAFE_FREE(ads->config.bind_path);
+                               ads->config.bind_path = SMB_STRDUP("");
+
+
+                               goto done;
+                       }
+                       SAFE_FREE(ads->server.ldap_server);
+                       SAFE_FREE(ads->server.realm);
+               }
+
+               TALLOC_FREE(gcs_list);
+               num_gcs = 0;
+       } while (!done);
+
+done:
+       SAFE_FREE(sitename);
+       talloc_destroy(frame);
+
+       return ads_status;
+}
+
 
 /**
  * Connect to the LDAP server
@@ -412,7 +550,7 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
        }
 
        if (ads->server.ldap_server &&
-           ads_try_connect(ads, ads->server.ldap_server)) {
+           ads_try_connect(ads, ads->server.ldap_server, ads->server.gc)) {
                goto got_connection;
        }
 
@@ -472,7 +610,7 @@ got_connection:
        /* Otherwise setup the TCP LDAP session */
 
        ads->ldap.ld = ldap_open_with_timeout(ads->config.ldap_server_name,
-                                             LDAP_PORT, lp_ldap_timeout());
+                                             ads->ldap.port, 
lp_ldap_timeout());
        if (ads->ldap.ld == NULL) {
                status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
                goto out;
diff --git a/source/utils/net.h b/source/utils/net.h
index aa4f3db..a400282 100644
--- a/source/utils/net.h
+++ b/source/utils/net.h
@@ -145,3 +145,8 @@ enum netdom_domain_t { ND_TYPE_NT4, ND_TYPE_AD };
 /* net share operation modes */
 #define NET_MODE_SHARE_MIGRATE 1
 
+
+/* ADS Startup Flags */
+
+#define ADS_STARTUP_DC                          0x00000001
+#define ADS_STARTUP_GLOBAL_CATALOG              0x00000002
diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c
index 1f1544e..15025b0 100644
--- a/source/winbindd/winbindd_cm.c
+++ b/source/winbindd/winbindd_cm.c
@@ -1050,7 +1050,7 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
                ads = ads_init(domain->alt_name, domain->name, NULL);
                ads->auth.flags |= ADS_AUTH_NO_BIND;
 
-               if (ads_try_connect(ads, addr)) {
+               if (ads_try_connect(ads, addr, false)) {
                        /* We got a cldap packet. */
                        fstrcpy(name, ads->config.ldap_server_name);
                        namecache_store(name, 0x20, 1, &ip_list);
-- 
1.5.3.7

>From 0dc3ec0a6b15422b288810e4b3cc4c297a3c0f99 Mon Sep 17 00:00:00 2001
From: Gerald Carter <coffeedude@xxxxxxxxxxxx>
Date: Thu, 19 Jun 2008 13:37:12 -0500
Subject: [PATCH] net: Throwaway patch just to show how to use ads_connect_gc() 
to search Global Catalog

---
 source/utils/net_ads.c |   40 +++++++++++++++++++++++++++-------------
 1 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c
index c0d04ac..5de5a80 100644
--- a/source/utils/net_ads.c
+++ b/source/utils/net_ads.c
@@ -196,8 +196,11 @@ static void use_in_memory_ccache(void) {
        setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
 }
 
-static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
-                                 uint32 auth_flags, ADS_STRUCT **ads_ret)
+static ADS_STATUS ads_startup_int(struct net_context *c,
+                                 bool only_own_domain,
+                                 uint32 auth_flags,
+                                 uint32 conn_flags,
+                                 ADS_STRUCT **ads_ret)
 {
        ADS_STRUCT *ads = NULL;
        ADS_STATUS status;
@@ -250,19 +253,23 @@ retry:
        SAFE_FREE(ads->auth.user_name);
        ads->auth.user_name = smb_xstrdup(c->opt_user_name);
 
-       /*
-        * If the username is of the form "name@realm",
-        * extract the realm and convert to upper case.
-        * This is only used to establish the connection.
-        */
-       if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
+       /*
+        * If the username is of the form "name@realm",
+        * extract the realm and convert to upper case.
+        * This is only used to establish the connection.
+        */
+       if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
                *cp++ = '\0';
                SAFE_FREE(ads->auth.realm);
                ads->auth.realm = smb_xstrdup(cp);
                strupper_m(ads->auth.realm);
-       }
+       }
 
-       status = ads_connect(ads);
+       if (conn_flags & ADS_STARTUP_GLOBAL_CATALOG) {
+               status = ads_connect_gc(ads);
+       } else {
+               status = ads_connect(ads);
+       }
 
        if (!ADS_ERR_OK(status)) {
 
@@ -309,12 +316,19 @@ retry:
 
 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT 
**ads)
 {
-       return ads_startup_int(c, only_own_domain, 0, ads);
+       return ads_startup_int(c, only_own_domain, 0, ADS_STARTUP_DC, ads);
 }
 
 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, 
ADS_STRUCT **ads)
 {
-       return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
+       return ads_startup_int(c, only_own_domain,
+                              ADS_AUTH_NO_BIND, ADS_STARTUP_DC, ads);
+}
+
+ADS_STATUS ads_startup_gc(struct net_context *c, bool only_own_domain, 
ADS_STRUCT **ads)
+{
+       return ads_startup_int(c, only_own_domain, 0,
+                              ADS_STARTUP_GLOBAL_CATALOG, ads);
 }
 
 /*
@@ -1936,7 +1950,7 @@ static int net_ads_search(struct net_context *c, int 
argc, const char **argv)
                return net_ads_search_usage(c, argc, argv);
        }
 
-       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+       if (!ADS_ERR_OK(ads_startup_gc(c, false, &ads))) {
                return -1;
        }
 
-- 
1.5.3.7

<Prev in Thread] Current Thread [Next in Thread>