This fixes a number of ADS problems, particularly with netbiosless
authorAndrew Tridgell <tridge@samba.org>
Mon, 5 Aug 2002 02:47:46 +0000 (02:47 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 5 Aug 2002 02:47:46 +0000 (02:47 +0000)
setups.

- split up the ads structure into logical pieces. This makes it much
  easier to keep things like the authentication realm and the server
  realm separate (they can be different).

- allow ads callers to specify that no sasl bind should be performed
(used by "net ads info" for example)

- fix an error with handing ADS_ERROR_SYSTEM() when errno is 0

- completely rewrote the code for finding the LDAP server. Now try DNS
  methods first, and try all DNS servers returned from the SRV DNS
  query, sorted by closeness to our interfaces (using the same sort code
  as we use in replies from WINS servers). This allows us to cope with
  ADS DCs that are down, and ensures we don't pick one that is on the
  other side of the country unless absolutely necessary.

- recognise dnsRecords as binary when displaying them

- cope with the realm not being configured in smb.conf (work it out
  from the LDAP server)

- look at the trustDirection when looking up trusted domains and don't
  include trusts that trust our domains but we don't trust
  theirs.

- use LDAP to query the alternate (netbios) name for a realm, and make
  sure that both and long and short forms of the name are accepted by
  winbindd. Use the short form by default for listing users/groups.

- rescan the list of trusted domains every 5 minutes in case new trust
  relationships are added while winbindd is running

- include transient trust relationships (ie. C trusts B, B trusts A,
  so C trusts A) in winbindd.

- don't do a gratuituous node status lookup when finding an ADS DC (we
  don't need it and it could fail)

- remove unused sid_to_distinguished_name function

- make sure we find the allternate name of our primary domain when
  operating with a netbiosless ADS DC (using LDAP to do the lookup)

- fixed the rpc trusted domain enumeration to support up to approx
  2000 trusted domains (the old limit was 3)

- use the IP for the remote_machine (%m) macro when the client doesn't
  supply us with a name via a netbios session request (eg. port 445)

- if the client uses SPNEGO then use the machine name from the SPNEGO
  auth packet for remote_machine (%m) macro

- add new 'net ads workgroup' command to find the netbios workgroup
  name for a realm
(This used to be commit e358d7b24c86a46d8c361b9e32a25d4f71a6dc00)

24 files changed:
source3/auth/auth_domain.c
source3/include/ads.h
source3/libads/ads_struct.c
source3/libads/kerberos.c
source3/libads/kerberos_verify.c
source3/libads/ldap.c
source3/libads/ldap_user.c
source3/libads/sasl.c
source3/libads/util.c
source3/libsmb/namequery.c
source3/nsswitch/winbindd.h
source3/nsswitch/winbindd_ads.c
source3/nsswitch/winbindd_cache.c
source3/nsswitch/winbindd_cm.c
source3/nsswitch/winbindd_rpc.c
source3/nsswitch/winbindd_util.c
source3/rpc_client/cli_lsarpc.c
source3/rpcclient/cmd_lsarpc.c
source3/smbd/negprot.c
source3/smbd/server.c
source3/smbd/sesssetup.c
source3/utils/net_ads.c
source3/utils/net_lookup.c
source3/utils/net_rpc.c

index b37ce2cc91eea2ebb59e10aceac5656360d8a6ec..d48cec5b2932444b7e102f90410bf7c7c6614501 100644 (file)
@@ -46,7 +46,9 @@ static NTSTATUS ads_resolve_dc(fstring remote_machine,
                return NT_STATUS_NO_LOGON_SERVERS;              
        }
 
-       DEBUG(4,("ads_resolve_dc: realm=%s\n", ads->realm));
+       DEBUG(4,("ads_resolve_dc: realm=%s\n", ads->config.realm));
+
+       ads->auth.no_bind = 1;
 
 #ifdef HAVE_ADS
        /* a full ads_connect() is actually overkill, as we don't srictly need
@@ -55,7 +57,7 @@ static NTSTATUS ads_resolve_dc(fstring remote_machine,
        ads_connect(ads);
 #endif
 
-       fstrcpy(remote_machine, ads->ldap_server_name);
+       fstrcpy(remote_machine, ads->config.ldap_server_name);
        strupper(remote_machine);
        *dest_ip = ads->ldap_ip;
        ads_destroy(&ads);
index 78d2fcf4b52dbcdeca5220321feb01e3e14a84f6..9305b7167107f49f81648bd3501fa5e2aaa10a7c 100644 (file)
@@ -5,19 +5,34 @@
 */
 
 typedef struct {
-       void *ld;
-       char *realm;
-       char *workgroup;
-       char *ldap_server;
-       char *ldap_server_name;
-       char *kdc_server;
+       void *ld; /* the active ldap structure */
+       struct in_addr ldap_ip; /* the ip of the active connection, if any */
+       time_t last_attempt; /* last attempt to reconnect */
        int ldap_port;
-       char *bind_path;
-       time_t last_attempt;
-       char *password;
-       char *user_name;
-       char *server_realm;
-       struct in_addr ldap_ip;
+       
+       /* info needed to find the server */
+       struct {
+               char *realm;
+               char *workgroup;
+               char *ldap_server;
+               int foreign; /* set to 1 if connecting to a foreign realm */
+       } server;
+
+       /* info needed to authenticate */
+       struct {
+               char *realm;
+               char *password;
+               char *user_name;
+               char *kdc_server;
+               int no_bind;
+       } auth;
+
+       /* info derived from the servers config */
+       struct {
+               char *realm;
+               char *bind_path;
+               char *ldap_server_name;
+       } config;
 } ADS_STRUCT;
 
 typedef struct {
@@ -95,7 +110,7 @@ typedef void **ADS_MODLIST;
 
 /* macros to simplify error returning */
 #define ADS_ERROR(rc) ads_build_error(ADS_ERROR_LDAP, rc, 0)
-#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc, 0)
+#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc?rc:EINVAL, 0)
 #define ADS_ERROR_KRB5(rc) ads_build_error(ADS_ERROR_KRB5, rc, 0)
 #define ADS_ERROR_GSS(rc, minor) ads_build_error(ADS_ERROR_GSS, rc, minor)
 
index af0b5d4143100ac95c1ba8f600c427428b2c3de0..b68c822ce3519513e8160b42e0f8918201a4396d 100644 (file)
@@ -72,47 +72,6 @@ char *ads_build_dn(const char *realm)
 }
 
 
-#ifdef HAVE_LDAP
-/*
-  find the ldap server from DNS
-*/
-static char *find_ldap_server(ADS_STRUCT *ads)
-{
-       char *list = NULL;
-       struct in_addr ip;
-
-       if (ads->realm &&
-           strcasecmp(ads->workgroup, lp_workgroup()) == 0 &&
-           ldap_domain2hostlist(ads->realm, &list) == LDAP_SUCCESS) {
-               char *p;
-               p = strchr(list, ':');
-               if (p) *p = 0;
-               return list;
-       }
-
-       /* get desperate, find the domain controller IP */
-       if (resolve_name(ads->workgroup, &ip, 0x1B)) {
-               return strdup(inet_ntoa(ip));
-       }
-       
-       /* or a BDC ... */
-       if (resolve_name(ads->workgroup, &ip, 0x1C)) {
-               return strdup(inet_ntoa(ip));
-       }
-
-       return NULL;
-}
-
-#else 
-
-static char *find_ldap_server(ADS_STRUCT *ads)
-{
-       /* Without LDAP this doesn't make much sense */
-       return NULL;
-}
-
-#endif 
-
 #ifndef LDAP_PORT
 #define LDAP_PORT 389
 #endif
@@ -122,58 +81,24 @@ static char *find_ldap_server(ADS_STRUCT *ads)
 */
 ADS_STRUCT *ads_init(const char *realm, 
                     const char *workgroup,
-                    const char *ldap_server,
-                    const char *bind_path,
-                    const char *password)
+                    const char *ldap_server)
 {
        ADS_STRUCT *ads;
        
        ads = (ADS_STRUCT *)smb_xmalloc(sizeof(*ads));
        ZERO_STRUCTP(ads);
        
-       if (!workgroup) {
-               workgroup = lp_workgroup();
+       ads->server.realm = realm? strdup(realm) : NULL;
+       ads->server.workgroup = workgroup ? strdup(workgroup) : NULL;
+       ads->server.ldap_server = ldap_server? strdup(ldap_server) : NULL;
+
+       /* we need to know if this is a foreign realm to know if we can
+          use lp_ads_server() */
+       if (realm && strcasecmp(lp_realm(), realm) != 0) {
+               ads->server.foreign = 1;
        }
-
-       ads->realm = realm? strdup(realm) : NULL;
-       ads->workgroup = strdup(workgroup);
-       ads->ldap_server = ldap_server? strdup(ldap_server) : NULL;
-       ads->bind_path = bind_path? strdup(bind_path) : NULL;
-       ads->ldap_port = LDAP_PORT;
-       if (password) ads->password = strdup(password);
-
-       if (!ads->realm) {
-               ads->realm = strdup(lp_realm());
-               if (!ads->realm[0]) {
-                       SAFE_FREE(ads->realm);
-               }
-       }
-
-       if (!ads->realm && strchr_m(ads->workgroup, '.')) {
-               /* the smb.conf has specified the realm in 'workgroup =' */
-               ads->realm = strdup(ads->workgroup);
-       }
-
-       if (!ads->bind_path && ads->realm) {
-               ads->bind_path = ads_build_dn(ads->realm);
-       }
-       if (!ads->ldap_server) {
-               if (strcasecmp(ads->workgroup, lp_workgroup()) == 0) {
-                       ads->ldap_server = strdup(lp_ads_server());
-               }
-               if (!ads->ldap_server || !ads->ldap_server[0]) {
-                       SAFE_FREE(ads->ldap_server);
-                       ads->ldap_server = find_ldap_server(ads);
-               }
-       }
-       if (!ads->kdc_server) {
-               /* assume its the same as LDAP */
-               ads->kdc_server = ads->ldap_server? strdup(ads->ldap_server) : NULL;
-       }
-
-       if (ads->ldap_server) {
-               /* its very useful knowing the IP of the ldap server */
-               ads->ldap_ip = *interpret_addr2(ads->ldap_server);
+       if (workgroup && strcasecmp(lp_workgroup(), workgroup) != 0) {
+               ads->server.foreign = 1;
        }
 
        return ads;
@@ -182,7 +107,7 @@ ADS_STRUCT *ads_init(const char *realm,
 /* a simpler ads_init() interface using all defaults */
 ADS_STRUCT *ads_init_simple(void)
 {
-       return ads_init(NULL, NULL, NULL, NULL, NULL);
+       return ads_init(NULL, NULL, NULL);
 }
 
 /*
@@ -194,13 +119,19 @@ void ads_destroy(ADS_STRUCT **ads)
 #if HAVE_LDAP
                if ((*ads)->ld) ldap_unbind((*ads)->ld);
 #endif
-               SAFE_FREE((*ads)->realm);
-               SAFE_FREE((*ads)->ldap_server);
-               SAFE_FREE((*ads)->ldap_server_name);
-               SAFE_FREE((*ads)->kdc_server);
-               SAFE_FREE((*ads)->bind_path);
-               SAFE_FREE((*ads)->password);
-               SAFE_FREE((*ads)->user_name);
+               SAFE_FREE((*ads)->server.realm);
+               SAFE_FREE((*ads)->server.workgroup);
+               SAFE_FREE((*ads)->server.ldap_server);
+
+               SAFE_FREE((*ads)->auth.realm);
+               SAFE_FREE((*ads)->auth.password);
+               SAFE_FREE((*ads)->auth.user_name);
+               SAFE_FREE((*ads)->auth.kdc_server);
+
+               SAFE_FREE((*ads)->config.realm);
+               SAFE_FREE((*ads)->config.bind_path);
+               SAFE_FREE((*ads)->config.ldap_server_name);
+
                ZERO_STRUCTP(*ads);
                SAFE_FREE(*ads);
        }
index 1ba5d978e8c7203add7015a78159638b49f6db0c..9a486237c9fe9a65c198bd924f96aab0b8163a50 100644 (file)
@@ -110,16 +110,8 @@ int ads_kinit_password(ADS_STRUCT *ads)
        char *s;
        int ret;
 
-       if (!ads->user_name) {
-               /* by default use the machine account */
-               extern pstring global_myname;
-               fstring myname;
-               fstrcpy(myname, global_myname);
-               strlower(myname);
-               asprintf(&ads->user_name, "HOST/%s", global_myname);
-       }
-       asprintf(&s, "%s@%s", ads->user_name, ads->realm);
-       ret = kerberos_kinit_password(s, ads->password);
+       asprintf(&s, "%s@%s", ads->auth.user_name, ads->auth.realm);
+       ret = kerberos_kinit_password(s, ads->auth.password);
 
        if (ret) {
                DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
index dac90908c456ab4d5a5885a8e08bd4cbd3866f04..22b58f47dd90ed646b6515f035b1faf9af1c5345 100644 (file)
@@ -67,7 +67,7 @@ NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket,
                return NT_STATUS_LOGON_FAILURE;
        }
 
-       ret = krb5_set_default_realm(context, ads->realm);
+       ret = krb5_set_default_realm(context, ads->auth.realm);
        if (ret) {
                DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));
                ads_destroy(&ads);
index 1753d7d3ade24d139c3703184fbb0808c46a9c17..a8126faffe41b05b6fb883dfa74eccceb59f9a34 100644 (file)
  * codepoints in UTF-8).  This may have to change at some point
  **/
 
+
+/*
+  try a connection to a given ldap server, returning True and setting the servers IP
+  in the ads struct if successful
+ */
+static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
+{
+       char *srv;
+
+       if (!server || !*server) {
+               return False;
+       }
+
+       DEBUG(5,("ads_try_connect: trying ldap server '%s' port %u\n", server, port));
+
+       /* this copes with inet_ntoa brokenness */
+       srv = strdup(server);
+
+       ads->ld = ldap_open(srv, port);
+       if (!ads->ld) {
+               free(srv);
+               return False;
+       }
+       ads->ldap_port = port;
+       ads->ldap_ip = *interpret_addr2(srv);
+       free(srv);
+       return True;
+}
+
+/* used by the IP comparison function */
+struct ldap_ip {
+       struct in_addr ip;
+       unsigned port;
+};
+
+/* compare 2 ldap IPs by nearness to our interfaces - used in qsort */
+static int ldap_ip_compare(struct ldap_ip *ip1, struct ldap_ip *ip2)
+{
+       return ip_compare(&ip1->ip, &ip2->ip);
+}
+
+/* try connecting to a ldap server via DNS */
+static BOOL ads_try_dns(ADS_STRUCT *ads)
+{
+       char *realm, *ptr;
+       char *list = NULL;
+       pstring tok;
+       struct ldap_ip *ip_list;
+       int count, i=0;
+
+       realm = ads->server.realm;
+       if (!realm || !*realm) {
+               SAFE_FREE(realm);
+               realm = lp_realm();
+       }
+       if (!realm || !*realm) {
+               SAFE_FREE(realm);
+               realm = ads->server.workgroup;
+       }
+       if (!realm || !*realm) {
+               SAFE_FREE(realm);
+               realm = lp_workgroup();
+       }
+       if (!realm) {
+               return False;
+       }
+
+       DEBUG(6,("ads_try_dns: looking for realm '%s'\n", realm));
+       if (ldap_domain2hostlist(realm, &list) != LDAP_SUCCESS) {
+               return False;
+       }
+
+       DEBUG(6,("ads_try_dns: ldap realm '%s' host list '%s'\n", realm, list));
+
+       count = count_chars(list, ' ') + 1;
+       ip_list = malloc(count * sizeof(struct ldap_ip));
+       if (!ip_list) {
+               return False;
+       }
+
+       ptr = list;
+       while (next_token(&ptr, tok, " ", sizeof(tok))) {
+               unsigned port = LDAP_PORT;
+               char *p = strchr(tok, ':');
+               if (p) {
+                       *p = 0;
+                       port = atoi(p+1);
+               }
+               ip_list[i].ip = *interpret_addr2(tok);
+               ip_list[i].port = port;
+               if (!is_zero_ip(ip_list[i].ip)) {
+                       i++;
+               }
+       }
+       free(list);
+
+       count = i;
+
+       /* we sort the list of addresses by closeness to our interfaces. This
+          tries to prevent us using a DC on the other side of the country */
+       if (count > 1) {
+               qsort(ip_list, count, sizeof(struct ldap_ip), 
+                     QSORT_CAST ldap_ip_compare);      
+       }
+
+       for (i=0;i<count;i++) {
+               if (ads_try_connect(ads, inet_ntoa(ip_list[i].ip), ip_list[i].port)) {
+                       free(ip_list);
+                       return True;
+               }
+       }
+
+       SAFE_FREE(ip_list);
+       return False;
+}
+
+/* try connecting to a ldap server via netbios */
+static BOOL ads_try_netbios(ADS_STRUCT *ads)
+{
+       struct in_addr *ip_list;
+       int count;
+       int i;
+       char *workgroup = ads->server.workgroup;
+
+       if (!workgroup) {
+               workgroup = lp_workgroup();
+       }
+
+       DEBUG(6,("ads_try_netbios: looking for workgroup '%s'\n", workgroup));
+
+       if (!get_dc_list(True, workgroup, &ip_list, &count) &&
+           !get_dc_list(False, workgroup, &ip_list, &count)) {
+               return False;
+       }
+
+       for (i=0;i<count;i++) {
+               DEBUG(6,("ads_try_netbios: trying server '%s'\n", inet_ntoa(ip_list[i])));
+               if (ads_try_connect(ads, inet_ntoa(ip_list[i]), LDAP_PORT)) {
+                       free(ip_list);
+                       return True;
+               }
+       }
+
+       free(ip_list);
+       return False;
+}
+
 /**
  * Connect to the LDAP server
  * @param ads Pointer to an existing ADS_STRUCT
@@ -49,38 +196,35 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
        ADS_STATUS status;
 
        ads->last_attempt = time(NULL);
-
        ads->ld = NULL;
 
-       if (ads->ldap_server) {
-               ads->ld = ldap_open(ads->ldap_server, ads->ldap_port);
+       /* try with a user specified server */
+       if (ads->server.ldap_server && 
+           ads_try_connect(ads, ads->server.ldap_server, LDAP_PORT)) {
+               goto got_connection;
        }
 
-       /* if that failed then try each of the BDC's in turn */
-       if (!ads->ld) {
-               struct in_addr *ip_list;
-               int count;
-
-               if (get_dc_list(False, ads->workgroup, &ip_list, &count)) {
-                       int i;
-                       for (i=0;i<count;i++) {
-                               ads->ld = ldap_open(inet_ntoa(ip_list[i]),
-                                                   ads->ldap_port);
-                               if (ads->ld) break;
-                       }
-                       if (ads->ld) {
-                               SAFE_FREE(ads->ldap_server);
-                               ads->ldap_server = strdup(inet_ntoa(ip_list[i]));
-                       }
-                       free(ip_list);
-               }
+       /* try with a smb.conf ads server setting if we are connecting
+           to the primary workgroup or realm */
+       if (!ads->server.foreign &&
+           ads_try_connect(ads, lp_ads_server(), LDAP_PORT)) {
+               goto got_connection;
        }
 
-       if (!ads->ld) {
-               return ADS_ERROR_SYSTEM(errno);
+       /* try via DNS */
+       if (ads_try_dns(ads)) {
+               goto got_connection;
+               }
+
+       /* try via netbios lookups */
+       if (!lp_disable_netbios() && ads_try_netbios(ads)) {
+               goto got_connection;
        }
 
-       DEBUG(3,("Connected to LDAP server %s\n", ads->ldap_server));
+       return ADS_ERROR_SYSTEM(errno?errno:ENOENT);
+
+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)) {
@@ -90,22 +234,43 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
 
        ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
 
+       if (!ads->auth.user_name) {
+               /* by default use the machine account */
+               extern pstring global_myname;
+               fstring myname;
+               fstrcpy(myname, global_myname);
+               strlower(myname);
+               asprintf(&ads->auth.user_name, "HOST/%s", myname);
+       }
+
+       if (!ads->auth.realm) {
+               ads->auth.realm = strdup(ads->config.realm);
+       }
+
+       if (!ads->auth.kdc_server) {
+               ads->auth.kdc_server = strdup(inet_ntoa(ads->ldap_ip));
+       }
+
 #if KRB5_DNS_HACK
        /* this is a really nasty hack to avoid ADS DNS problems. It needs a patch
           to MIT kerberos to work (tridge) */
        {
                char *env;
-               asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->server_realm);
-               setenv(env, inet_ntoa(*interpret_addr2(ads->ldap_server)), 1);
+               asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->config.realm);
+               setenv(env, ads->auth.kdc_server, 1);
                free(env);
        }
 #endif
 
-       if (ads->password) {
+       if (ads->auth.password) {
                if ((code = ads_kinit_password(ads)))
                        return ADS_ERROR_KRB5(code);
        }
 
+       if (ads->auth.no_bind) {
+               return ADS_SUCCESS;
+       }
+
        return ads_sasl_bind(ads);
 }
 
@@ -494,7 +659,7 @@ ADS_STATUS ads_search(ADS_STRUCT *ads, void **res,
                      const char *exp, 
                      const char **attrs)
 {
-       return ads_do_search(ads, ads->bind_path, LDAP_SCOPE_SUBTREE, 
+       return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE, 
                             exp, attrs, res);
 }
 
@@ -805,11 +970,11 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
 
        if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname)))
                goto done;
-       if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->realm)))
+       if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm)))
                goto done;
        ou_str = ads_ou_string(org_unit);
        new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str, 
-                                ads->bind_path);
+                                ads->config.bind_path);
        free(ou_str);
        if (!new_dn)
                goto done;
@@ -925,6 +1090,7 @@ static BOOL ads_dump_field(char *field, void **values, void *data_area)
        } handlers[] = {
                {"objectGUID", False, dump_binary},
                {"nTSecurityDescriptor", False, dump_sd},
+               {"dnsRecord", False, dump_binary},
                {"objectSid", False, dump_sid},
                {NULL, True, NULL}
        };
@@ -1061,7 +1227,7 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
                status = ads_leave_realm(ads, host);
                if (!ADS_ERR_OK(status)) {
                        DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n", 
-                                 host, ads->realm));
+                                 host, ads->config.realm));
                        return status;
                }
        }
@@ -1224,20 +1390,15 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
        char *host = strdup(hostname);
        char *principal; 
 
-        if (!ads->kdc_server) {
-               DEBUG(0, ("Unable to find KDC server\n"));
-               return ADS_ERROR(LDAP_SERVER_DOWN);
-       }
-
        strlower(host);
 
        /*
          we need to use the '$' form of the name here, as otherwise the
          server might end up setting the password for a user instead
         */
-       asprintf(&principal, "%s$@%s", host, ads->realm);
+       asprintf(&principal, "%s$@%s", host, ads->auth.realm);
        
-       status = krb5_set_password(ads->kdc_server, principal, password);
+       status = krb5_set_password(ads->auth.kdc_server, principal, password);
        
        free(host);
        free(principal);
@@ -1472,33 +1633,27 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
                return ADS_ERROR(LDAP_DECODING_ERROR);
        }
 
-       SAFE_FREE(ads->ldap_server_name);
+       SAFE_FREE(ads->config.ldap_server_name);
 
-       ads->ldap_server_name = strdup(p+1);
-       p = strchr(ads->ldap_server_name, '$');
+       ads->config.ldap_server_name = strdup(p+1);
+       p = strchr(ads->config.ldap_server_name, '$');
        if (!p || p[1] != '@') {
                ldap_value_free(values);
                ldap_msgfree(res);
-               SAFE_FREE(ads->ldap_server_name);
+               SAFE_FREE(ads->config.ldap_server_name);
                return ADS_ERROR(LDAP_DECODING_ERROR);
        }
 
        *p = 0;
 
-       SAFE_FREE(ads->server_realm);
-       SAFE_FREE(ads->bind_path);
+       SAFE_FREE(ads->config.realm);
+       SAFE_FREE(ads->config.bind_path);
 
-       ads->server_realm = strdup(p+2);
-       ads->bind_path = ads_build_dn(ads->server_realm);
-
-       /* in case the realm isn't configured in smb.conf */
-       if (!ads->realm || !ads->realm[0]) {
-               SAFE_FREE(ads->realm);
-               ads->realm = strdup(ads->server_realm);
-       }
+       ads->config.realm = strdup(p+2);
+       ads->config.bind_path = ads_build_dn(ads->config.realm);
 
        DEBUG(3,("got ldap server name %s@%s\n", 
-                ads->ldap_server_name, ads->realm));
+                ads->config.ldap_server_name, ads->config.realm));
 
        return ADS_SUCCESS;
 }
@@ -1514,9 +1669,13 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
  * @return the count of SIDs pulled
  **/
 ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, 
-                              int *num_trusts, char ***names, DOM_SID **sids)
+                              int *num_trusts, 
+                              char ***names, 
+                              char ***alt_names,
+                              DOM_SID **sids)
 {
-       const char *attrs[] = {"flatName", "securityIdentifier", NULL};
+       const char *attrs[] = {"name", "flatname", "securityIdentifier", 
+                              "trustDirection", NULL};
        ADS_STATUS status;
        void *res, *msg;
        int count, i;
@@ -1533,11 +1692,31 @@ ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
        }
 
        (*names) = talloc(mem_ctx, sizeof(char *) * count);
+       (*alt_names) = talloc(mem_ctx, sizeof(char *) * count);
        (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);
        if (! *names || ! *sids) return ADS_ERROR(LDAP_NO_MEMORY);
 
        for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
-               (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatName");
+               uint32 direction;
+
+               /* direction is a 2 bit bitfield, 1 means they trust us 
+                  but we don't trust them, so we should not list them
+                  as users from that domain can't login */
+               if (ads_pull_uint32(ads, msg, "trustDirection", &direction) &&
+                   direction == 1) {
+                       continue;
+               }
+               
+               (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "name");
+               (*alt_names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatname");
+
+               if ((*alt_names)[i] && (*alt_names)[i][0]) {
+                       /* we prefer the flatname as the primary name
+                          for consistency with RPC */
+                       char *name = (*alt_names)[i];
+                       (*alt_names)[i] = (*names)[i];
+                       (*names)[i] = name;
+               }
                if (ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i])) {
                        i++;
                }
@@ -1562,7 +1741,7 @@ ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
        void *res;
        ADS_STATUS rc;
 
-       rc = ads_do_search(ads, ads->bind_path, LDAP_SCOPE_BASE, "(objectclass=*)", 
+       rc = ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)", 
                           attrs, &res);
        if (!ADS_ERR_OK(rc)) return rc;
        if (!ads_pull_sid(ads, res, "objectSid", sid)) {
@@ -1573,4 +1752,66 @@ 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
+*/
+ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workgroup)
+{
+       char *exp;
+       ADS_STATUS rc;
+       char **principles;
+       char *prefix;
+       int prefix_length;
+       int i;
+       void *res;
+       const char *attrs[] = {"servicePrincipalName", NULL};
+
+       (*workgroup) = NULL;
+
+       asprintf(&exp, "(&(objectclass=computer)(dnshostname=%s.%s))", 
+                ads->config.ldap_server_name, ads->config.realm);
+       rc = ads_search(ads, &res, exp, attrs);
+       free(exp);
+
+       if (!ADS_ERR_OK(rc)) {
+               return rc;
+       }
+
+       principles = ads_pull_strings(ads, mem_ctx, res, "servicePrincipalName");
+
+       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 (strncasecmp(principles[i], prefix, prefix_length) == 0 &&
+                   strcasecmp(ads->config.realm, principles[i]+prefix_length) != 0 &&
+                   !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;
+}
+
 #endif
index b6e3d189c514e0146182558d496d9e922f44b9d4..b6fef24b5c19573ccbd37ea61025c1c5d1d94df2 100644 (file)
@@ -55,10 +55,10 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user,
 
        status = ADS_ERROR(LDAP_NO_MEMORY);
 
-       if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->realm)))
+       if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->config.realm)))
                goto done;
        if (!(new_dn = talloc_asprintf(ctx, "cn=%s,cn=Users,%s", name, 
-                                      ads->bind_path)))
+                                      ads->config.bind_path)))
                goto done;
        if (!(controlstr = talloc_asprintf(ctx, "%u", UF_NORMAL_ACCOUNT)))
                goto done;
@@ -94,7 +94,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group,
        status = ADS_ERROR(LDAP_NO_MEMORY);
 
        if (!(new_dn = talloc_asprintf(ctx, "cn=%s,cn=Users,%s", group, 
-                                      ads->bind_path)))
+                                      ads->config.bind_path)))
                goto done;
        if (!(mods = ads_init_mods(ctx)))
                goto done;
index 1b55453cac9f2d780715a177c26eca74c37983b2..81dedb0a81e7c257c2fd27bef5fcad5157c6c634 100644 (file)
@@ -77,7 +77,7 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
 
        /* we need to fetch a service ticket as the ldap user in the
           servers realm, regardless of our realm */
-       asprintf(&sname, "ldap/%s@%s", ads->ldap_server_name, ads->server_realm);
+       asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);
        krb5_init_context(&ctx);
        krb5_set_default_tgs_ktypes(ctx, enc_types);
        krb5_parse_name(ctx, sname, &principal);
@@ -163,7 +163,7 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
 
        gss_release_buffer(&minor_status, &output_token);
 
-       output_token.value = malloc(strlen(ads->bind_path) + 8);
+       output_token.value = malloc(strlen(ads->config.bind_path) + 8);
        p = output_token.value;
 
        *p++ = 1; /* no sign or seal */
@@ -171,9 +171,10 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
        *p++ = max_msg_size>>16;
        *p++ = max_msg_size>>8;
        *p++ = max_msg_size;
-       snprintf(p, strlen(ads->bind_path)+4, "dn:%s", ads->bind_path);
+       snprintf(p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
+       p += strlen(ads->config.bind_path);
 
-       output_token.length = strlen(ads->bind_path) + 8;
+       output_token.length = strlen(ads->config.bind_path) + 8;
 
        gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
                          &output_token, &conf_state,
index d48eb10b710857b13172a3448872be84b5a79b56..b10b130a313bea604c90aca6cabea30d4b69f83f 100644 (file)
@@ -39,7 +39,7 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
     new_password = strdup(tmp_password);
     asprintf(&service_principal, "HOST/%s", host_principal);
     
-    ret = kerberos_set_password(ads->kdc_server, host_principal, password, 
+    ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password, 
                                service_principal, new_password);
 
     if (!secrets_store_machine_password(new_password)) {
index 141581e2617c6440b071d9d5a2d37571904eb2f0..3382ce4f4a01e96d09da32f059b7c231723a747f 100644 (file)
@@ -216,7 +216,7 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
 /*
   comparison function used by sort_ip_list
 */
-static int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
+int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
 {
        int max_bits1=0, max_bits2=0;
        int num_interfaces = iface_count();
index 11d399be49a101792dfa5ccb8c1198eef05acb54..dd92ecefe61c3a411b32bd1c4b2d1842f9cf1a75 100644 (file)
@@ -88,7 +88,7 @@ typedef struct {
 
 struct winbindd_domain {
        fstring name;                          /* Domain name */        
-       fstring full_name;                     /* full Domain name (realm) */   
+       fstring alt_name;                      /* alt Domain name (if any) */
        DOM_SID sid;                           /* SID for this domain */
 
        /* Lookup methods for this domain (LDAP or RPC) */
@@ -170,11 +170,15 @@ struct winbindd_methods {
                                    TALLOC_CTX *mem_ctx,
                                    uint32 *num_domains,
                                    char ***names,
+                                   char ***alt_names,
                                    DOM_SID **dom_sids);
 
        /* find the domain sid */
        NTSTATUS (*domain_sid)(struct winbindd_domain *domain,
                               DOM_SID *sid);
+
+       /* setup the list of alternate names for the domain, if any */
+       NTSTATUS (*alternate_name)(struct winbindd_domain *domain);
 };
 
 /* Used to glue a policy handle and cli_state together */
@@ -190,6 +194,8 @@ typedef struct {
 #include "rpc_client.h"
 
 #define WINBINDD_ESTABLISH_LOOP 30
+#define WINBINDD_RESCAN_FREQ 300
+
 #define DOM_SEQUENCE_NONE ((uint32)-1)
 
 /* SETENV */
index b61348adfe76ab801e087f672917849f67d7d782..b0b70178a45ca9ea2e07cfbd5111fdc5ff1a3524 100644 (file)
@@ -61,8 +61,8 @@ ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope
 
                if (*res) ads_msgfree(ads, *res);
                *res = NULL;
-               DEBUG(3,("Reopening ads connection to %s after error %s\n", 
-                        ads->ldap_server, ads_errstr(status)));
+               DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n", 
+                        ads->config.realm, ads_errstr(status)));
                if (ads->ld) {
                        ldap_unbind(ads->ld); 
                }
@@ -87,7 +87,7 @@ ADS_STATUS ads_search_retry(ADS_STRUCT *ads, void **res,
                            const char *exp, 
                            const char **attrs)
 {
-       return ads_do_search_retry(ads, ads->bind_path, LDAP_SCOPE_SUBTREE,
+       return ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
                                   exp, attrs, res);
 }
 
@@ -108,8 +108,6 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
        ADS_STRUCT *ads;
        ADS_STATUS status;
        char *ccache;
-       struct in_addr server_ip;
-       char *sname;
 
        if (domain->private) {
                return (ADS_STRUCT *)domain->private;
@@ -120,30 +118,23 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
        SETENV("KRB5CCNAME", ccache, 1);
        unlink(ccache);
 
-       if (resolve_name(domain->name, &server_ip, 0x1b)) {
-               sname = inet_ntoa(server_ip);
-       } else if (resolve_name(domain->name, &server_ip, 0x1c)) {
-               sname = inet_ntoa(server_ip);
-       } else {
-               if (strcasecmp(domain->name, lp_workgroup()) != 0) {
-                       DEBUG(1,("can't find domain controller for %s\n", domain->name));
-                       return NULL;
-               }
-               sname = NULL;
-       }
-
-       ads = ads_init(primary_realm, domain->name, NULL, NULL, NULL);
+       ads = ads_init(domain->alt_name, domain->name, NULL);
        if (!ads) {
                DEBUG(1,("ads_init for domain %s failed\n", domain->name));
                return NULL;
        }
 
        /* the machine acct password might have change - fetch it every time */
-       SAFE_FREE(ads->password);
-       ads->password = secrets_fetch_machine_password();
+       SAFE_FREE(ads->auth.password);
+       ads->auth.password = secrets_fetch_machine_password();
+
+       if (primary_realm) {
+               SAFE_FREE(ads->auth.realm);
+               ads->auth.realm = strdup(primary_realm);
+       }
 
        status = ads_connect(ads);
-       if (!ADS_ERR_OK(status) || !ads->realm) {
+       if (!ADS_ERR_OK(status) || !ads->config.realm) {
                extern struct winbindd_methods msrpc_methods;
                DEBUG(1,("ads_connect for domain %s failed: %s\n", 
                         domain->name, ads_errstr(status)));
@@ -161,11 +152,9 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
 
        /* remember our primary realm for trusted domain support */
        if (!primary_realm) {
-               primary_realm = strdup(ads->realm);
+               primary_realm = strdup(ads->config.realm);
        }
 
-       fstrcpy(domain->full_name, ads->server_realm);
-
        domain->private = (void *)ads;
        return ads;
 }
@@ -405,7 +394,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
 
        /* accept either the win2000 or the pre-win2000 username */
        asprintf(&exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))", 
-                name, name, ads->realm);
+                name, name, ads->config.realm);
        rc = ads_search_retry(ads, &res, exp, attrs);
        free(exp);
        if (!ADS_ERR_OK(rc)) {
@@ -535,49 +524,6 @@ failed:
        return False;
 }
 
-
-/* convert a sid to a distnguished name */
-static NTSTATUS sid_to_distinguished_name(struct winbindd_domain *domain,
-                                         TALLOC_CTX *mem_ctx,
-                                         DOM_SID *sid,
-                                         char **dn)
-{
-       ADS_STRUCT *ads = NULL;
-       const char *attrs[] = {"distinguishedName", NULL};
-       ADS_STATUS rc;
-       void *msg = NULL;
-       char *exp;
-       char *sidstr;
-       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-
-       DEBUG(3,("ads: sid_to_distinguished_name\n"));
-
-       ads = ads_cached_connection(domain);
-       if (!ads) goto done;
-
-       sidstr = sid_binstring(sid);
-       asprintf(&exp, "(objectSid=%s)", sidstr);
-       rc = ads_search_retry(ads, &msg, exp, attrs);
-       free(exp);
-       free(sidstr);
-       if (!ADS_ERR_OK(rc)) {
-               DEBUG(1,("sid_to_distinguished_name ads_search: %s\n", ads_errstr(rc)));
-               goto done;
-       }
-
-       *dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName");
-
-       status = NT_STATUS_OK;
-
-       DEBUG(3,("ads sid_to_distinguished_name mapped %s\n", *dn));
-
-done:
-       if (msg) ads_msgfree(ads, msg);
-
-       return status;
-}
-
-
 /* Lookup user information from a rid */
 static NTSTATUS query_user(struct winbindd_domain *domain, 
                           TALLOC_CTX *mem_ctx, 
@@ -831,6 +777,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                uint32 *num_domains,
                                char ***names,
+                               char ***alt_names,
                                DOM_SID **dom_sids)
 {
        ADS_STRUCT *ads;
@@ -842,7 +789,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        ads = ads_cached_connection(domain);
        if (!ads) return NT_STATUS_UNSUCCESSFUL;
 
-       rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, dom_sids);
+       rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, alt_names, dom_sids);
 
        return ads_ntstatus(rc);
 }
@@ -867,6 +814,37 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
        return ads_ntstatus(rc);
 }
 
+
+/* find alternate names list for the domain - for ADS this is the
+   netbios name */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+       ADS_STRUCT *ads;
+       ADS_STATUS rc;
+       TALLOC_CTX *ctx;
+       char *workgroup;
+
+       ads = ads_cached_connection(domain);
+       if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+       if (!(ctx = talloc_init_named("alternate_name"))) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       rc = ads_workgroup_name(ads, ctx, &workgroup);
+
+       if (ADS_ERR_OK(rc)) {
+               fstrcpy(domain->name, workgroup);
+               fstrcpy(domain->alt_name, ads->config.realm);
+               strupper(domain->alt_name);
+               strupper(domain->name);
+       }
+
+       talloc_destroy(ctx);
+
+       return ads_ntstatus(rc);        
+}
+
 /* the ADS backend methods are exposed via this structure */
 struct winbindd_methods ads_methods = {
        True,
@@ -879,7 +857,8 @@ struct winbindd_methods ads_methods = {
        lookup_groupmem,
        sequence_number,
        trusted_domains,
-       domain_sid
+       domain_sid,
+       alternate_name
 };
 
 #endif
index a607727867fd86140c95b98d4fac6e0998bd739f..060139af3ed1b0101203a7ac67bc70b606d40c05 100644 (file)
@@ -873,13 +873,14 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                uint32 *num_domains,
                                char ***names,
+                               char ***alt_names,
                                DOM_SID **dom_sids)
 {
        struct winbind_cache *cache = get_cache(domain);
 
        /* we don't cache this call */
        return cache->backend->trusted_domains(domain, mem_ctx, num_domains, 
-                                              names, dom_sids);
+                                              names, alt_names, dom_sids);
 }
 
 /* find the domain sid */
@@ -891,6 +892,15 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
        return cache->backend->domain_sid(domain, sid);
 }
 
+/* find the alternate names for the domain, if any */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+       struct winbind_cache *cache = get_cache(domain);
+
+       /* we don't cache this call */
+       return cache->backend->alternate_name(domain);
+}
+
 /* the ADS backend methods are exposed via this structure */
 struct winbindd_methods cache_methods = {
        True,
@@ -903,5 +913,6 @@ struct winbindd_methods cache_methods = {
        lookup_groupmem,
        sequence_number,
        trusted_domains,
-       domain_sid
+       domain_sid,
+       alternate_name
 };
index 3175860a79a6c8daa406454a6e54ef3721c97d7a..be289847912a1c84429292ebcb5e5625995e4da2 100644 (file)
@@ -97,12 +97,15 @@ struct get_dc_name_cache {
 static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)
 {
        ADS_STRUCT *ads;
-       ads = ads_init_simple();
+       ads = ads_init(domain, domain, NULL);
        if (!ads) {
                return False;
        }
 
-       DEBUG(4,("cm_ads_find_dc: realm=%s\n", ads->realm));
+       /* we don't need to bind, just connect */
+       ads->auth.no_bind = 1;
+
+       DEBUG(4,("cm_ads_find_dc: domain=%s\n", domain));
 
 #ifdef HAVE_ADS
        /* a full ads_connect() is actually overkill, as we don't srictly need
@@ -111,15 +114,15 @@ static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr
        ads_connect(ads);
 #endif
 
-       fstrcpy(srv_name, ads->ldap_server_name);
+       if (!ads->config.realm) {
+               return False;
+       }
+
+       fstrcpy(srv_name, ads->config.ldap_server_name);
        strupper(srv_name);
        *dc_ip = ads->ldap_ip;
        ads_destroy(&ads);
        
-       if (!*srv_name || is_zero_ip(*dc_ip)) {
-               return False;
-       }
-
        DEBUG(4,("cm_ads_find_dc: using server='%s' IP=%s\n",
                 srv_name, inet_ntoa(*dc_ip)));
        
@@ -247,9 +250,12 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr
 
        zero_ip(&dc_ip);
 
+       ret = False;
        if (lp_security() == SEC_ADS) {
                ret = cm_ads_find_dc(domain, &dc_ip, srv_name);
-       } else {
+       }
+       if (!ret) {
+               /* fall back on rpc methods if the ADS methods fail */
                ret = cm_rpc_find_dc(domain, &dc_ip, srv_name);
        }
 
index 2bb0e8c49f46d6661f5d0e3ad966658fbc1f9c63..5ec34f663d8ee583020f28da821a279fa49402a5 100644 (file)
@@ -575,22 +575,23 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                uint32 *num_domains,
                                char ***names,
+                               char ***alt_names,
                                DOM_SID **dom_sids)
 {
        CLI_POLICY_HND *hnd;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        uint32 enum_ctx = 0;
-       uint32 pref_num_domains = 5;
 
        DEBUG(3,("rpc: trusted_domains\n"));
 
        *num_domains = 0;
+       *alt_names = NULL;
 
        if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
                goto done;
 
        result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
-                                       &hnd->pol, &enum_ctx, &pref_num_domains,
+                                       &hnd->pol, &enum_ctx,
                                        num_domains, names, dom_sids);
 done:
        return result;
@@ -621,6 +622,13 @@ done:
        return status;
 }
 
+/* find alternate names list for the domain - none for rpc */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+       return NT_STATUS_OK;
+}
+
+
 /* the rpc backend methods are exposed via this structure */
 struct winbindd_methods msrpc_methods = {
        False,
@@ -633,5 +641,6 @@ struct winbindd_methods msrpc_methods = {
        lookup_groupmem,
        sequence_number,
        trusted_domains,
-       domain_sid
+       domain_sid,
+       alternate_name
 };
index b927380af87107506e39f5af2ad40bb4c3bc19df..daa3abb3400529179ca1fdb3f21b462df6c15bea 100644 (file)
@@ -74,19 +74,17 @@ void free_domain_list(void)
 }
 
 /* Add a trusted domain to our list of domains */
-
-static struct winbindd_domain *add_trusted_domain(char *domain_name,
-                                                 struct winbindd_methods *methods)
+static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
+                                                 struct winbindd_methods *methods,
+                                                 DOM_SID *sid)
 {
        struct winbindd_domain *domain;
         
        /* We can't call domain_list() as this function is called from
           init_domain_list() and we'll get stuck in a loop. */
-
        for (domain = _domain_list; domain; domain = domain->next) {
-               if (strcmp(domain_name, domain->name) == 0) {
-                       DEBUG(3, ("domain %s already in domain list\n", 
-                                 domain_name));
+               if (strcmp(domain_name, domain->name) == 0 ||
+                   strcmp(domain_name, domain->alt_name) == 0) {
                        return domain;
                }
        }
@@ -101,40 +99,95 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name,
         
        ZERO_STRUCTP(domain);
 
+       /* prioritise the short name */
+       if (strchr_m(domain_name, '.') && alt_name && *alt_name) {
+               fstrcpy(domain->name, alt_name);
+               fstrcpy(domain->alt_name, domain_name);
+       } else {
        fstrcpy(domain->name, domain_name);
+               if (alt_name) {
+                       fstrcpy(domain->alt_name, alt_name);
+               }
+       }
+
         domain->methods = methods;
        domain->sequence_number = DOM_SEQUENCE_NONE;
        domain->last_seq_check = 0;
+       if (sid) {
+               sid_copy(&domain->sid, sid);
+       }
 
        /* Link to domain list */
-        
        DLIST_ADD(_domain_list, domain);
         
+       DEBUG(1,("Added domain %s %s %s\n", 
+                domain->name, domain->alt_name,
+                sid?sid_string_static(&domain->sid):""));
+        
        return domain;
 }
 
-/* Look up global info for the winbind daemon */
 
+/*
+  rescan our domains looking for new trusted domains
+ */
+void rescan_trusted_domains(void)
+{
+       struct winbindd_domain *domain;
+       TALLOC_CTX *mem_ctx;
+       static time_t last_scan;
+       time_t t = time(NULL);
+
+       /* ony rescan every few minutes */
+       if ((unsigned)(t - last_scan) < WINBINDD_RESCAN_FREQ) {
+               return;
+       }
+       last_scan = time(NULL);
+       
+       DEBUG(1, ("scanning trusted domain list\n"));
+
+       if (!(mem_ctx = talloc_init_named("init_domain_list")))
+               return;
+
+       for (domain = _domain_list; domain; domain = domain->next) {
+               NTSTATUS result;
+               char **names;
+               char **alt_names;
+               int num_domains = 0;
+               DOM_SID *dom_sids;
+               int i;
+
+               result = domain->methods->trusted_domains(domain, mem_ctx, &num_domains,
+                                                         &names, &alt_names, &dom_sids);
+               if (!NT_STATUS_IS_OK(result)) {
+                       continue;
+               }
+
+               /* Add each domain to the trusted domain list. Each domain inherits
+                  the access methods of its parent */
+               for(i = 0; i < num_domains; i++) {
+                       DEBUG(10,("Found domain %s\n", names[i]));
+                       add_trusted_domain(names[i], 
+                                          alt_names?alt_names[i]:NULL, 
+                                          domain->methods, &dom_sids[i]);
+               }
+       }
+
+       talloc_destroy(mem_ctx);
+}
+
+/* Look up global info for the winbind daemon */
 BOOL init_domain_list(void)
 {
        NTSTATUS result;
-       TALLOC_CTX *mem_ctx;
        extern struct winbindd_methods cache_methods;
        struct winbindd_domain *domain;
-       DOM_SID *dom_sids;
-       char **names;
-       uint32 num_domains = 0;
-
-       if (!(mem_ctx = talloc_init_named("init_domain_list")))
-               return False;
 
        /* Free existing list */
-
        free_domain_list();
 
        /* Add ourselves as the first entry */
-
-       domain = add_trusted_domain(lp_workgroup(), &cache_methods);
+       domain = add_trusted_domain(lp_workgroup(), NULL, &cache_methods, NULL);
 
        /* Now we *must* get the domain sid for our primary domain. Go into
           a holding pattern until that is available */
@@ -147,29 +200,12 @@ BOOL init_domain_list(void)
                result = cache_methods.domain_sid(domain, &domain->sid);
        }
        
-       DEBUG(1,("Added domain %s (%s)\n", 
-                domain->name, 
-                sid_string_static(&domain->sid)));
-
-       DEBUG(1, ("getting trusted domain list\n"));
+       /* get any alternate name for the primary domain */
+       cache_methods.alternate_name(domain);
 
-       result = cache_methods.trusted_domains(domain, mem_ctx, &num_domains,
-                                              &names, &dom_sids);
+       /* do an initial scan for trusted domains */
+       rescan_trusted_domains();
 
-       /* Add each domain to the trusted domain list */
-       if (NT_STATUS_IS_OK(result)) {
-               int i;
-               for(i = 0; i < num_domains; i++) {
-                       domain = add_trusted_domain(names[i], &cache_methods);
-                       if (!domain) continue;
-                       sid_copy(&domain->sid, &dom_sids[i]);
-                       DEBUG(1,("Added domain %s (%s)\n", 
-                                domain->name, 
-                                sid_string_static(&domain->sid)));
-               }
-       }
-
-       talloc_destroy(mem_ctx);
        return True;
 }
 
@@ -184,7 +220,7 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
 
        for (domain = domain_list(); domain != NULL; domain = domain->next) {
                if (strequal(domain_name, domain->name) ||
-                   strequal(domain_name, domain->full_name))
+                   (domain->alt_name[0] && strequal(domain_name, domain->alt_name)))
                        return domain;
        }
 
index 542fad311c0edcb8bf8a7fcc9ad6c34da2d86a14..14227a349a4a7f0caa1aeec969e0699f45f866e0 100644 (file)
@@ -542,7 +542,7 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
                                 POLICY_HND *pol, uint32 *enum_ctx, 
-                                uint32 *pref_num_domains, uint32 *num_domains,
+                                uint32 *num_domains,
                                 char ***domain_names, DOM_SID **domain_sids)
 {
        prs_struct qbuf, rbuf;
@@ -561,7 +561,8 @@ NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
        /* Marshall data and send request */
 
-        init_q_enum_trust_dom(&q, pol, *enum_ctx, *pref_num_domains);
+       /* 64k is enough for about 2000 trusted domains */
+        init_q_enum_trust_dom(&q, pol, *enum_ctx, 0x10000);
 
        if (!lsa_io_q_enum_trust_dom("", &q, &qbuf, 0) ||
            !rpc_api_pipe_req(cli, LSA_ENUMTRUSTDOM, &qbuf, &rbuf)) {
index 067325c06e66e1c5dcacb449777fac908d3a1b5d..51b260cceb87c77c41d4d3dde29c51b4666bc9d8 100644 (file)
@@ -191,23 +191,15 @@ static NTSTATUS cmd_lsa_enum_trust_dom(struct cli_state *cli,
 
        /* defaults, but may be changed using params */
        uint32 enum_ctx = 0;
-       uint32 preferred_maxnum = 5;
        uint32 num_domains = 0;
        int i;
 
-       if (argc > 3) {
-               printf("Usage: %s [preferred max number (%d)] [enum context (0)]\n",
-                       argv[0], preferred_maxnum);
+       if (argc > 2) {
+               printf("Usage: %s [enum context (0)]\n", argv[0]);
                return NT_STATUS_OK;
        }
 
-       /* enumeration context */
-       if (argc >= 2 && argv[1]) {
-               preferred_maxnum = atoi(argv[1]);
-       }       
-
-       /* preferred maximum number */
-       if (argc == 3 && argv[2]) {
+       if (argc == 2 && argv[1]) {
                enum_ctx = atoi(argv[2]);
        }       
 
@@ -221,8 +213,8 @@ static NTSTATUS cmd_lsa_enum_trust_dom(struct cli_state *cli,
        /* Lookup list of trusted domains */
 
        result = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
-                                               &preferred_maxnum, &num_domains,
-                                               &domain_names, &domain_sids);
+                                       &num_domains,
+                                       &domain_names, &domain_sids);
        if (!NT_STATUS_IS_OK(result) &&
            !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) &&
            !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
index d8aea624be3f34a27282fa47dff4f40df0b9f420..1d79cbd5d00b9b22a733555fdb79873d7a6acb99 100644 (file)
@@ -200,14 +200,11 @@ static int negprot_spnego(char *p)
        if (lp_security() != SEC_ADS) {
                blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
        } else {
-               ADS_STRUCT *ads;
-               ads = ads_init_simple();
                /* win2000 uses host$@REALM, which we will probably use eventually,
                   but for now this works */
-               asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
+               asprintf(&principal, "HOST/%s@%s", guid, lp_realm());
                blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
                free(principal);
-               ads_destroy(&ads);
        }
        memcpy(p, blob.data, blob.length);
        len = blob.length;
index 1eef3d98e8f80bcf6205deec43de85d1452c5c9d..d173fec00e4b29cb46f6fa30797984a8668ea9f6 100644 (file)
@@ -364,6 +364,10 @@ static BOOL open_sockets_smbd(BOOL is_daemon,const char *smb_ports)
                                set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
                                set_socket_options(smbd_server_fd(),user_socket_options);
                                
+                               /* this is needed so that we get decent entries
+                                  in smbstatus for port 445 connects */
+                               fstrcpy(remote_machine, get_socket_addr(smbd_server_fd()));
+                               
                                /* Reset global variables in util.c so
                                   that client substitutions will be
                                   done correctly in the process.  */
index a00554e6389b2775892275b43865de9a0072904a..2e9e54b8d93f37285deea932f6f25943def0971a 100644 (file)
@@ -122,6 +122,12 @@ static int reply_spnego_kerberos(connection_struct *conn,
 
        ads = ads_init_simple();
 
+       if (!ads) {
+               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+       }
+
+       ads->auth.realm = strdup(lp_realm());
+
        ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(1,("Failed to verify incoming ticket!\n"));       
@@ -139,7 +145,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
        }
 
        *p = 0;
-       if (strcasecmp(p+1, ads->realm) != 0) {
+       if (strcasecmp(p+1, ads->auth.realm) != 0) {
                DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
                if (!lp_allow_trusted_domains()) {
                        return ERROR_NT(NT_STATUS_LOGON_FAILURE);
@@ -379,6 +385,7 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
        uint32 auth_flags = AUTH_FLAG_NONE;
        auth_usersupplied_info *user_info = NULL;
        auth_serversupplied_info *server_info = NULL;
+       extern fstring remote_machine;
 
        /* we must have setup the auth context by now */
        if (!ntlmssp_auth_context) {
@@ -413,6 +420,11 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
        DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
                 user, workgroup, machine, lmhash.length, nthash.length));
 
+       /* the client has given us its machine name (which we otherwise would not get on port 445).
+          we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+       fstrcpy(remote_machine, machine);
+       reload_services(True);
+
 #if 0
        file_save("nthash1.dat", nthash.data, nthash.length);
        file_save("lmhash1.dat", lmhash.data, lmhash.length);
index ef4de3d76f9b271283b4f969d7523453ec95d6a9..f74f633cf98c48b61f31df6a32d3060c390f09ed 100644 (file)
@@ -58,23 +58,23 @@ static int net_ads_info(int argc, const char **argv)
 {
        ADS_STRUCT *ads;
 
-       ads = ads_init(NULL, NULL, opt_host, NULL, NULL);
+       ads = ads_init(NULL, NULL, opt_host);
 
-       /* we want this servers realm, not our realm */
-       SAFE_FREE(ads->realm);
+       if (ads) {
+               ads->auth.no_bind = 1;
+       }
 
        ads_connect(ads);
 
-       if (!ads) {
+       if (!ads || !ads->config.realm) {
                d_printf("Didn't find the ldap server!\n");
                return -1;
        }
 
-       d_printf("LDAP server: %s\n", ads->ldap_server);
-       d_printf("LDAP server IP: %s\n", inet_ntoa(ads->ldap_ip));
-       d_printf("LDAP server name: %s\n", ads->ldap_server_name);
-       d_printf("Realm: %s\n", ads->realm);
-       d_printf("Bind Path: %s\n", ads->bind_path);
+       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);
+       d_printf("Bind Path: %s\n", ads->config.bind_path);
        d_printf("LDAP port: %d\n", ads->ldap_port);
 
        return 0;
@@ -88,7 +88,7 @@ static ADS_STRUCT *ads_startup(void)
        BOOL need_password = False;
        BOOL second_time = False;
        
-       ads = ads_init(NULL, NULL, opt_host, NULL, NULL);
+       ads = ads_init(NULL, NULL, opt_host);
 
        if (!opt_user_name) {
                opt_user_name = "administrator";
@@ -106,9 +106,9 @@ retry:
        }
 
        if (opt_password)
-               ads->password = strdup(opt_password);
+               ads->auth.password = strdup(opt_password);
 
-       ads->user_name = strdup(opt_user_name);
+       ads->auth.user_name = strdup(opt_user_name);
 
        status = ads_connect(ads);
        if (!ADS_ERR_OK(status)) {
@@ -141,8 +141,38 @@ int net_ads_check(void)
        return 0;
 }
 
+/* 
+   determine the netbios workgroup name for a domain
+ */
+static int net_ads_workgroup(int argc, const char **argv)
+{
+       ADS_STRUCT *ads;
+       TALLOC_CTX *ctx;
+       char *workgroup;
+
+       if (!(ads = ads_startup())) return -1;
+
+       if (!(ctx = talloc_init_named("net_ads_workgroup"))) {
+               return -1;
+       }
+
+       if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
+               d_printf("Failed to find workgroup for realm '%s'\n", 
+                        ads->config.realm);
+               talloc_destroy(ctx);
+               return -1;
+       }
+
+       d_printf("Workgroup: %s\n", workgroup);
+
+       talloc_destroy(ctx);
+
+       return 0;
+}
+
+
 
-static BOOL usergrp_display(char *field, void **values, void *data_area)
+static void usergrp_display(char *field, void **values, void *data_area)
 {
        char **disp_fields = (char **) data_area;
 
@@ -156,16 +186,15 @@ static BOOL usergrp_display(char *field, void **values, void *data_area)
                }
                SAFE_FREE(disp_fields[0]);
                SAFE_FREE(disp_fields[1]);
-               return True;
+               return;
        }
        if (!values) /* must be new field, indicate string field */
-               return True;
+               return;
        if (StrCaseCmp(field, "sAMAccountName") == 0) {
                disp_fields[0] = strdup((char *) values[0]);
        }
        if (StrCaseCmp(field, "description") == 0)
                disp_fields[1] = strdup((char *) values[0]);
-       return True; /* always strings here */
 }
 
 static int net_ads_user_usage(int argc, const char **argv)
@@ -213,8 +242,8 @@ static int ads_user_add(int argc, const char **argv)
        }
 
        /* try setting the password */
-       asprintf(&upn, "%s@%s", argv[0], ads->realm);
-       status = krb5_set_password(ads->kdc_server, upn, argv[1]);
+       asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
+       status = krb5_set_password(ads->auth.kdc_server, upn, argv[1]);
        safe_free(upn);
        if (ADS_ERR_OK(status)) {
                d_printf("User %s added\n", argv[0]);
@@ -331,7 +360,7 @@ int net_ads_user(int argc, const char **argv)
                        d_printf("\nUser name             Comment"\
                                 "\n-----------------------------\n");
 
-               rc = ads_do_search_all_fn(ads, ads->bind_path, 
+               rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
                                          LDAP_SCOPE_SUBTREE,
                                          "(objectclass=user)", 
                                          opt_long_list_entries ? longattrs :
@@ -438,7 +467,7 @@ int net_ads_group(int argc, const char **argv)
                if (opt_long_list_entries)
                        d_printf("\nGroup name            Comment"\
                                 "\n-----------------------------\n");
-               rc = ads_do_search_all_fn(ads, ads->bind_path, 
+               rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
                                          LDAP_SCOPE_SUBTREE, 
                                          "(objectclass=group)", 
                                          opt_long_list_entries ? longattrs : 
@@ -499,11 +528,11 @@ static int net_ads_leave(int argc, const char **argv)
        rc = ads_leave_realm(ads, global_myname);
        if (!ADS_ERR_OK(rc)) {
            d_printf("Failed to delete host '%s' from the '%s' realm.\n", 
-                    global_myname, ads->realm);
+                    global_myname, ads->config.realm);
            return -1;
        }
 
-       d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->realm);
+       d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->config.realm);
 
        return 0;
 }
@@ -534,7 +563,7 @@ int net_ads_join(int argc, const char **argv)
        if (!(ads = ads_startup())) return -1;
 
        ou_str = ads_ou_string(org_unit);
-       asprintf(&dn, "%s,%s", ou_str, ads->bind_path);
+       asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
        free(ou_str);
 
        rc = ads_search_dn(ads, &res, dn, NULL);
@@ -580,7 +609,7 @@ int net_ads_join(int argc, const char **argv)
                return -1;
        }
 
-       d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->realm);
+       d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->config.realm);
 
        free(password);
 
@@ -675,7 +704,7 @@ static int net_ads_printer_publish(int argc, const char **argv)
           get_a_printer, because the server name might be
           localhost or an ip address */
        prt.printerName = argv[0];
-       asprintf(&servername, "%s.%s", global_myname, ads->realm);
+       asprintf(&servername, "%s.%s", global_myname, ads->config.realm);
        prt.serverName = servername;
        prt.shortServerName = global_myname;
        prt.versionNumber = "4";
@@ -779,13 +808,13 @@ static int net_ads_password(int argc, const char **argv)
 
     /* use the realm so we can eventually change passwords for users 
     in realms other than default */
-    if (!(ads = ads_init(realm, NULL, NULL, NULL, NULL))) return -1;
+    if (!(ads = ads_init(realm, NULL, NULL))) return -1;
 
     asprintf(&prompt, "Enter new password for %s:", argv[0]);
 
     new_password = getpass(prompt);
 
-    ret = kerberos_set_password(ads->kdc_server, auth_principal, 
+    ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
                                auth_password, argv[0], new_password);
     if (!ADS_ERR_OK(ret)) {
        d_printf("Password change failed :-( ...\n");
@@ -814,7 +843,7 @@ static int net_ads_change_localhost_pass(int argc, const char **argv)
 
     hostname = strdup(global_myname);
     strlower(hostname);
-    asprintf(&host_principal, "%s@%s", hostname, ads->realm);
+    asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
     SAFE_FREE(hostname);
     d_printf("Changing password for principal: HOST/%s\n", host_principal);
     
@@ -873,7 +902,7 @@ static int net_ads_search(int argc, const char **argv)
        exp = argv[0];
        attrs = (argv + 1);
 
-       rc = ads_do_search_all(ads, ads->bind_path, 
+       rc = ads_do_search_all(ads, ads->config.bind_path, 
                               LDAP_SCOPE_SUBTREE,
                               exp, attrs, &res);
        if (!ADS_ERR_OK(rc)) {
@@ -927,6 +956,7 @@ int net_ads(int argc, const char **argv)
                {"CHOSTPASS", net_ads_change_localhost_pass},
                {"PRINTER", net_ads_printer},
                {"SEARCH", net_ads_search},
+               {"WORKGROUP", net_ads_workgroup},
                {"HELP", net_ads_help},
                {NULL, NULL}
        };
index a9aa08005490c29cff0f153dc380a67d3b9b1463..f76b18625187625cad424912764510b1b5dcc667 100644 (file)
@@ -215,6 +215,8 @@ static int net_lookup_kdc(int argc, const char **argv)
        DEBUG(1, ("No kerberos support\n"));
        return -1;
 }
+
+
 /* lookup hosts or IP addresses using internal samba lookup fns */
 int net_lookup(int argc, const char **argv)
 {
index 9b3248cf63346d88e70768003818f713f42a7183..ae956076d524872c396c61356c499b2a50f6bf41 100644 (file)
@@ -1824,7 +1824,7 @@ static int rpc_trustdom_list(int argc, const char **argv)
        POLICY_HND connect_hnd;
        
        /* trusted domains listing variables */
-       int enum_ctx = 0, pref_num_domains = 5;
+       int enum_ctx = 0;
        int num_domains, i, pad_len, col_len = 20;
        DOM_SID *domain_sids;
        char **trusted_dom_names;
@@ -1894,7 +1894,7 @@ static int rpc_trustdom_list(int argc, const char **argv)
 
        do {
                nt_status = cli_lsa_enum_trust_dom(cli, mem_ctx, &connect_hnd, &enum_ctx,
-                                                  &pref_num_domains, &num_domains,
+                                                  &num_domains,
                                                   &trusted_dom_names, &domain_sids);
                
                if (NT_STATUS_IS_ERR(nt_status)) {