Update my copyrights according to my agreement with IBM
[bbaumbach/samba-autobuild/.git] / source3 / libads / ldap.c
index 47a94f0a08d364696ef55906d5433c487828d805..5a12288b167308247d16f23397d5aee891f108d5 100644 (file)
@@ -3,7 +3,7 @@
    ads (active directory) utility library
    Copyright (C) Andrew Tridgell 2001
    Copyright (C) Remus Koos 2001
-   Copyright (C) Jim McDonough 2002
+   Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
    
    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
@@ -41,6 +41,9 @@
 /*
   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
  */
 static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
 {
@@ -90,133 +93,94 @@ static BOOL ads_try_connect_uri(ADS_STRUCT *ads)
        return False;
 }
 
-/* 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 to find an AD dc using our internal name resolution routines
+ Try the realm first and then then workgroup name if netbios is not 
+ disabled
+**********************************************************************/
 
-/* try connecting to a ldap server via DNS */
-static BOOL ads_try_dns(ADS_STRUCT *ads)
+static BOOL ads_find_dc(ADS_STRUCT *ads)
 {
        const char *c_realm;
-       const char *ptr;
-       char *realm;
-       char *list = NULL;
-       pstring tok;
-       struct ldap_ip *ip_list;
        int count, i=0;
+       struct ip_service *ip_list;
+       pstring realm;
+       BOOL got_realm = False;
+       BOOL use_own_domain = False;
 
+       /* if the realm and workgroup are both empty, assume they are ours */
+
+       /* realm */
        c_realm = ads->server.realm;
-       if (!c_realm || !*c_realm) {
-               c_realm = lp_realm();
+       
+       if ( !c_realm || !*c_realm ) {
+               /* special case where no realm and no workgroup means our own */
+               if ( !ads->server.workgroup || !*ads->server.workgroup ) {
+                       use_own_domain = True;
+                       c_realm = lp_realm();
+               }
        }
-       if (!c_realm || !*c_realm) {
+       
+       if (c_realm && *c_realm) 
+               got_realm = True;
+                  
+again:
+       /* we need to try once with the realm name and fallback to the 
+          netbios domain name if we fail (if netbios has not been disabled */
+          
+       if ( !got_realm && !lp_disable_netbios() ) {
                c_realm = ads->server.workgroup;
-       }
-       if (!c_realm || !*c_realm) {
-               c_realm = lp_workgroup();
-       }
-       if (!c_realm) {
-               return False;
-       }
-       realm = smb_xstrdup(c_realm);
-
-       DEBUG(6,("ads_try_dns: looking for realm '%s'\n", realm));
-       if (ldap_domain2hostlist(realm, &list) != LDAP_SUCCESS) {
-               SAFE_FREE(realm);
-               return False;
-       }
-
-       DEBUG(6,("ads_try_dns: ldap realm '%s' host list '%s'\n", realm, list));
-       SAFE_FREE(realm);
-
-       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);
+               if (!c_realm || !*c_realm) {
+                       if ( use_own_domain )
+                               c_realm = lp_workgroup();
                }
-               ip_list[i].ip = *interpret_addr2(tok);
-               ip_list[i].port = port;
-               if (!is_zero_ip(ip_list[i].ip)) {
-                       i++;
+               
+               if ( !c_realm || !*c_realm ) {
+                       DEBUG(0,("ads_find_dc: no realm or workgroup!  Don't know what to do\n"));
+                       return False;
                }
        }
-       free(list);
+       
+       pstrcpy( realm, c_realm );
 
-       count = i;
+       DEBUG(6,("ads_find_dc: looking for %s '%s'\n", 
+               (got_realm ? "realm" : "domain"), realm));
 
-       /* 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);      
+       if ( !get_sorted_dc_list(realm, &ip_list, &count, got_realm) ) {
+               /* fall back to netbios if we can */
+               if ( got_realm && !lp_disable_netbios() ) {
+                       got_realm = False;
+                       goto again;
+               }
+               
+               return False;
        }
-
-       for (i=0;i<count;i++) {
-               if (ads_try_connect(ads, inet_ntoa(ip_list[i].ip), ip_list[i].port)) {
-                       free(ip_list);
+                       
+       /* 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) );
+               
+               if ( !NT_STATUS_IS_OK(check_negative_conn_cache(realm, server)) )
+                       continue;
+                       
+               if ( ads_try_connect(ads, server, port) ) {
+                       SAFE_FREE(ip_list);
                        return True;
                }
+               
+               /* keep track of failures */
+               add_failed_connection_entry( realm, server, NT_STATUS_UNSUCCESSFUL );
        }
 
        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, pdc_ip;
-       int count;
-       int i;
-       const char *workgroup = ads->server.workgroup;
-       BOOL list_ordered;
-
-       if (!workgroup) {
-               workgroup = lp_workgroup();
-       }
-
-       DEBUG(6,("ads_try_netbios: looking for workgroup '%s'\n", workgroup));
-
-       /* try the PDC first */
-       if (get_pdc_ip(workgroup, &pdc_ip)) { 
-               DEBUG(6,("ads_try_netbios: trying server '%s'\n", 
-                        inet_ntoa(pdc_ip)));
-               if (ads_try_connect(ads, inet_ntoa(pdc_ip), LDAP_PORT))
-                       return True;
-       }
-
-       /* now any DC, including backups */
-       if (get_dc_list(workgroup, &ip_list, &count, &list_ordered)) { 
-               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
@@ -244,20 +208,7 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
                goto got_connection;
        }
 
-       /* 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;
-       }
-
-       /* try via DNS */
-       if (ads_try_dns(ads)) {
-               goto got_connection;
-       }
-
-       /* try via netbios lookups */
-       if (!lp_disable_netbios() && ads_try_netbios(ads)) {
+       if (ads_find_dc(ads)) {
                goto got_connection;
        }
 
@@ -278,7 +229,7 @@ got_connection:
                /* by default use the machine account */
                fstring myname;
                fstrcpy(myname, global_myname());
-               strlower(myname);
+               strlower_m(myname);
                asprintf(&ads->auth.user_name, "HOST/%s", myname);
        }
 
@@ -400,8 +351,8 @@ static char **ads_pull_strvals(TALLOC_CTX *ctx, const char **in_vals)
  *  again when the entire search is complete 
  * @param ads connection to ads server 
  * @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression - specified in local charset
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression - specified in local charset
  * @param attrs Attributes to retrieve - specified in utf8 or ascii
  * @param res ** which will contain results - free res* with ads_msgfree()
  * @param count Number of entries retrieved on this page
@@ -409,12 +360,12 @@ static char **ads_pull_strvals(TALLOC_CTX *ctx, const char **in_vals)
  * @return status of search
  **/
 ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
-                              int scope, const char *exp,
+                              int scope, const char *expr,
                               const char **attrs, void **res, 
                               int *count, void **cookie)
 {
        int rc, i, version;
-       char *utf8_exp, *utf8_path, **search_attrs;
+       char *utf8_expr, *utf8_path, **search_attrs;
        LDAPControl PagedResults, NoReferrals, *controls[3], **rcontrols; 
        BerElement *cookie_be = NULL;
        struct berval *cookie_bv= NULL;
@@ -426,10 +377,10 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
                return ADS_ERROR(LDAP_NO_MEMORY);
 
        /* 0 means the conversion worked but the result was empty 
-          so we only fail if it's negative.  In any case, it always 
+          so we only fail if it's -1.  In any case, it always 
           at least nulls out the dest */
-       if ((push_utf8_talloc(ctx, &utf8_exp, exp) < 0) ||
-           (push_utf8_talloc(ctx, &utf8_path, bind_path) < 0)) {
+       if ((push_utf8_talloc(ctx, &utf8_expr, expr) == (size_t)-1) ||
+           (push_utf8_talloc(ctx, &utf8_path, bind_path) == (size_t)-1)) {
                rc = LDAP_NO_MEMORY;
                goto done;
        }
@@ -489,7 +440,7 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
        */
        ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
 
-       rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_exp, 
+       rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_expr
                               search_attrs, 0, controls,
                               NULL, NULL, LDAP_NO_LIMIT, (LDAPMessage **)res);
 
@@ -497,7 +448,7 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
        ber_bvfree(cookie_bv);
 
        if (rc) {
-               DEBUG(3,("ldap_search_ext_s(%s) -> %s\n", exp, ldap_err2string(rc)));
+               DEBUG(3,("ldap_search_ext_s(%s) -> %s\n", expr, ldap_err2string(rc)));
                goto done;
        }
 
@@ -540,21 +491,21 @@ done:
  * all entries in a large search.
  * @param ads connection to ads server 
  * @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression
  * @param attrs Attributes to retrieve
  * @param res ** which will contain results - free res* with ads_msgfree()
  * @return status of search
  **/
 ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
-                            int scope, const char *exp,
+                            int scope, const char *expr,
                             const char **attrs, void **res)
 {
        void *cookie = NULL;
        int count = 0;
        ADS_STATUS status;
 
-       status = ads_do_paged_search(ads, bind_path, scope, exp, attrs, res,
+       status = ads_do_paged_search(ads, bind_path, scope, expr, attrs, res,
                                     &count, &cookie);
 
        if (!ADS_ERR_OK(status)) return status;
@@ -564,7 +515,7 @@ ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
                ADS_STATUS status2;
                LDAPMessage *msg, *next;
 
-               status2 = ads_do_paged_search(ads, bind_path, scope, exp, 
+               status2 = ads_do_paged_search(ads, bind_path, scope, expr
                                              attrs, &res2, &count, &cookie);
 
                if (!ADS_ERR_OK(status2)) break;
@@ -587,15 +538,15 @@ ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
  *  runs the function as each page is returned, using ads_process_results()
  * @param ads connection to ads server
  * @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression - specified in local charset
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression - specified in local charset
  * @param attrs Attributes to retrieve - specified in UTF-8 or ascii
  * @param fn Function which takes attr name, values list, and data_area
  * @param data_area Pointer which is passed to function on each call
  * @return status of search
  **/
 ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
-                               int scope, const char *exp, const char **attrs,
+                               int scope, const char *expr, const char **attrs,
                                BOOL(*fn)(char *, void **, void *), 
                                void *data_area)
 {
@@ -604,7 +555,7 @@ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
        ADS_STATUS status;
        void *res;
 
-       status = ads_do_paged_search(ads, bind_path, scope, exp, attrs, &res,
+       status = ads_do_paged_search(ads, bind_path, scope, expr, attrs, &res,
                                     &count, &cookie);
 
        if (!ADS_ERR_OK(status)) return status;
@@ -613,7 +564,7 @@ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
        ads_msgfree(ads, res);
 
        while (cookie) {
-               status = ads_do_paged_search(ads, bind_path, scope, exp, attrs,
+               status = ads_do_paged_search(ads, bind_path, scope, expr, attrs,
                                             &res, &count, &cookie);
 
                if (!ADS_ERR_OK(status)) break;
@@ -629,19 +580,19 @@ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
  * Do a search with a timeout.
  * @param ads connection to ads server
  * @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression
  * @param attrs Attributes to retrieve
  * @param res ** which will contain results - free res* with ads_msgfree()
  * @return status of search
  **/
 ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope, 
-                        const char *exp,
+                        const char *expr,
                         const char **attrs, void **res)
 {
        struct timeval timeout;
        int rc;
-       char *utf8_exp, *utf8_path, **search_attrs = NULL;
+       char *utf8_expr, *utf8_path, **search_attrs = NULL;
        TALLOC_CTX *ctx;
 
        if (!(ctx = talloc_init("ads_do_search"))) {
@@ -652,8 +603,8 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
        /* 0 means the conversion worked but the result was empty 
           so we only fail if it's negative.  In any case, it always 
           at least nulls out the dest */
-       if ((push_utf8_talloc(ctx, &utf8_exp, exp) < 0) ||
-           (push_utf8_talloc(ctx, &utf8_path, bind_path) < 0)) {
+       if ((push_utf8_talloc(ctx, &utf8_expr, expr) == (size_t)-1) ||
+           (push_utf8_talloc(ctx, &utf8_path, bind_path) == (size_t)-1)) {
                DEBUG(1,("ads_do_search: push_utf8_talloc() failed!"));
                rc = LDAP_NO_MEMORY;
                goto done;
@@ -679,7 +630,7 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
        /* see the note in ads_do_paged_search - we *must* disable referrals */
        ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
 
-       rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_exp,
+       rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_expr,
                               search_attrs, 0, NULL, NULL, 
                               &timeout, LDAP_NO_LIMIT, (LDAPMessage **)res);
 
@@ -698,16 +649,16 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
  * Do a general ADS search
  * @param ads connection to ads server
  * @param res ** which will contain results - free res* with ads_msgfree()
- * @param exp Search expression
+ * @param expr Search expression
  * @param attrs Attributes to retrieve
  * @return status of search
  **/
 ADS_STATUS ads_search(ADS_STRUCT *ads, void **res, 
-                     const char *exp, 
+                     const char *expr
                      const char **attrs)
 {
        return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE, 
-                            exp, attrs, res);
+                            expr, attrs, res);
 }
 
 /**
@@ -749,14 +700,15 @@ void ads_memfree(ADS_STRUCT *ads, void *mem)
 /**
  * Get a dn from search results
  * @param ads connection to ads server
- * @param res Search results
+ * @param msg Search result
  * @return dn string
  **/
-char *ads_get_dn(ADS_STRUCT *ads, void *res)
+char *ads_get_dn(ADS_STRUCT *ads, void *msg)
 {
        char *utf8_dn, *unix_dn;
 
-       utf8_dn = ldap_get_dn(ads->ld, res);
+       utf8_dn = ldap_get_dn(ads->ld, msg);
+
        pull_utf8_allocate((void **) &unix_dn, utf8_dn);
        ldap_memfree(utf8_dn);
        return unix_dn;
@@ -772,18 +724,18 @@ char *ads_get_dn(ADS_STRUCT *ads, void *res)
 ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
 {
        ADS_STATUS status;
-       char *exp;
+       char *expr;
        const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
 
        /* the easiest way to find a machine account anywhere in the tree
           is to look for hostname$ */
-       if (asprintf(&exp, "(samAccountName=%s$)", host) == -1) {
+       if (asprintf(&expr, "(samAccountName=%s$)", host) == -1) {
                DEBUG(1, ("asprintf failed!\n"));
                return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
        }
        
-       status = ads_search(ads, res, exp, attrs);
-       free(exp);
+       status = ads_search(ads, res, expr, attrs);
+       free(expr);
        return status;
 }
 
@@ -816,18 +768,18 @@ static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
 {
        int curmod;
        LDAPMod **modlist = (LDAPMod **) *mods;
-       void **values;
+       struct berval **ber_values = NULL;
+       char **char_values = NULL;
 
        if (!invals) {
-               values = NULL;
                mod_op = LDAP_MOD_DELETE;
        } else {
                if (mod_op & LDAP_MOD_BVALUES)
-                       values = (void **) ads_dup_values(ctx, 
-                                          (const struct berval **)invals);
+                       ber_values = ads_dup_values(ctx, 
+                                               (const struct berval **)invals);
                else
-                       values = (void **) ads_push_strvals(ctx, 
-                                                  (const char **) invals);
+                       char_values = ads_push_strvals(ctx, 
+                                                 (const char **) invals);
        }
 
        /* find the first empty slot */
@@ -846,10 +798,14 @@ static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
        if (!(modlist[curmod] = talloc_zero(ctx, sizeof(LDAPMod))))
                return ADS_ERROR(LDAP_NO_MEMORY);
        modlist[curmod]->mod_type = talloc_strdup(ctx, name);
-       if (mod_op & LDAP_MOD_BVALUES)
-               modlist[curmod]->mod_bvalues = (struct berval **) values;
-       else
-               modlist[curmod]->mod_values = (char **) values;
+       if (mod_op & LDAP_MOD_BVALUES) {
+               modlist[curmod]->mod_bvalues = ber_values;
+       } else if (mod_op & LDAP_MOD_DELETE) {
+               modlist[curmod]->mod_values = NULL;
+       } else {
+               modlist[curmod]->mod_values = char_values;
+       }
+
        modlist[curmod]->mod_op = mod_op;
        return ADS_ERROR(LDAP_SUCCESS);
 }
@@ -994,7 +950,7 @@ ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
                return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
        }
        
-       ret = ldap_delete(ads->ld, utf8_dn);
+       ret = ldap_delete_s(ads->ld, utf8_dn);
        return ADS_ERROR(ret);
 }
 
@@ -1020,9 +976,10 @@ char *ads_ou_string(const char *org_unit)
   add a machine account to the ADS server
 */
 static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, 
+                                      uint32 account_type,
                                       const char *org_unit)
 {
-       ADS_STATUS ret;
+       ADS_STATUS ret, status;
        char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
        char *ou_str;
        TALLOC_CTX *ctx;
@@ -1053,13 +1010,13 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
        psp = talloc_asprintf(ctx, "HOST/%s.%s", 
                              hostname, 
                              ads->config.realm);
-       strlower(&psp[5]);
+       strlower_m(&psp[5]);
        servicePrincipalName[1] = psp;
        servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", hostname);
        psp2 = talloc_asprintf(ctx, "CIFS/%s.%s", 
                               hostname, 
                               ads->config.realm);
-       strlower(&psp2[5]);
+       strlower_m(&psp2[5]);
        servicePrincipalName[3] = psp2;
 
        free(ou_str);
@@ -1069,10 +1026,11 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
        if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname)))
                goto done;
 
-       acct_control = UF_WORKSTATION_TRUST_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
+       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;
 
@@ -1089,9 +1047,21 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
        ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
        ads_mod_str(ctx, &mods, "operatingSystemVersion", VERSION);
 
-       ads_gen_add(ads, new_dn, mods);
-       ret = ads_set_machine_sd(ads, hostname, new_dn);
+       ret = ads_gen_add(ads, new_dn, mods);
 
+       if (!ADS_ERR_OK(ret))
+               goto done;
+
+       /* Do not fail if we can't set security descriptor
+        * it shouldn't be mandatory and probably we just 
+        * don't have enough rights to do it.
+        */
+       status = ads_set_machine_sd(ads, hostname, new_dn);
+
+       if (!ADS_ERR_OK(status)) {
+               DEBUG(0, ("Warning: ads_set_machine_sd: %s\n",
+                               ads_errstr(status)));
+       }
 done:
        talloc_destroy(ctx);
        return ret;
@@ -1125,7 +1095,7 @@ static void dump_guid(const char *field, struct berval **values)
        GUID guid;
        for (i=0; values[i]; i++) {
                memcpy(guid.info, values[i]->bv_val, sizeof(guid.info));
-               printf("%s: %s\n", field, uuid_string_static(guid));
+               printf("%s: %s\n", field, smb_uuid_string_static(guid));
        }
 }
 
@@ -1199,6 +1169,7 @@ static BOOL ads_dump_field(char *field, void **values, void *data_area)
                {"nTSecurityDescriptor", False, dump_sd},
                {"dnsRecord", False, dump_binary},
                {"objectSid", False, dump_sid},
+               {"tokenGroups", False, dump_sid},
                {NULL, True, NULL}
        };
        int i;
@@ -1318,7 +1289,8 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
  * @param org_unit Organizational unit to place machine in
  * @return status of join
  **/
-ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org_unit)
+ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, 
+                         uint32 account_type, const char *org_unit)
 {
        ADS_STATUS status;
        LDAPMessage *res;
@@ -1326,7 +1298,7 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
 
        /* hostname must be lowercase */
        host = strdup(hostname);
-       strlower(host);
+       strlower_m(host);
 
        status = ads_find_machine_acct(ads, (void **)&res, host);
        if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
@@ -1339,7 +1311,7 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
                }
        }
 
-       status = ads_add_machine_acct(ads, host, org_unit);
+       status = ads_add_machine_acct(ads, host, account_type, org_unit);
        if (!ADS_ERR_OK(status)) {
                DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(status)));
                return status;
@@ -1365,13 +1337,13 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
 ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
 {
        ADS_STATUS status;
-       void *res;
+       void *res, *msg;
        char *hostnameDN, *host; 
        int rc;
 
        /* hostname must be lowercase */
        host = strdup(hostname);
-       strlower(host);
+       strlower_m(host);
 
        status = ads_find_machine_acct(ads, &res, host);
        if (!ADS_ERR_OK(status)) {
@@ -1379,7 +1351,12 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
            return status;
        }
 
-       hostnameDN = ads_get_dn(ads, (LDAPMessage *)res);
+       msg = ads_first_entry(ads, res);
+       if (!msg) {
+               return ADS_ERROR_SYSTEM(ENOENT);
+       }
+
+       hostnameDN = ads_get_dn(ads, (LDAPMessage *)msg);
        rc = ldap_delete_s(ads->ld, hostnameDN);
        ads_memfree(ads, hostnameDN);
        if (rc != LDAP_SUCCESS) {
@@ -1406,8 +1383,8 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
  **/
 ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
 {
-       const char     *attrs[] = {"ntSecurityDescriptor", "objectSid", 0};
-       char           *exp     = 0;
+       const char     *attrs[] = {"nTSecurityDescriptor", "objectSid", 0};
+       char           *expr     = 0;
        size_t          sd_size = 0;
        struct berval   bval = {0, NULL};
        prs_struct      ps_wire;
@@ -1420,8 +1397,12 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
        NTSTATUS    status;
        ADS_STATUS  ret;
        DOM_SID     sid;
-       SEC_DESC   *psd = 0;
-       TALLOC_CTX *ctx = 0;    
+       SEC_DESC   *psd = NULL;
+       TALLOC_CTX *ctx = NULL; 
+
+       /* Avoid segmentation fault in prs_mem_free if
+        * we have to bail out before prs_init */
+       ps_wire.is_dynamic = False;
 
        if (!ads) return ADS_ERROR(LDAP_SERVER_DOWN);
 
@@ -1431,7 +1412,7 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
                return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
        }
 
-       if (asprintf(&exp, "(samAccountName=%s$)", escaped_hostname) == -1) {
+       if (asprintf(&expr, "(samAccountName=%s$)", escaped_hostname) == -1) {
                DEBUG(1, ("ads_set_machine_sd: asprintf failed!\n"));
                SAFE_FREE(escaped_hostname);
                return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
@@ -1439,7 +1420,7 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
 
        SAFE_FREE(escaped_hostname);
 
-       ret = ads_search(ads, (void *) &res, exp, attrs);
+       ret = ads_search(ads, (void *) &res, expr, attrs);
 
        if (!ADS_ERR_OK(ret)) return ret;
 
@@ -1448,7 +1429,11 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
                goto ads_set_sd_error;
        }
 
-       ads_pull_sid(ads, msg, attrs[1], &sid); 
+       if (!ads_pull_sid(ads, msg, attrs[1], &sid)) {
+               ret = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               goto ads_set_sd_error;
+       }
+
        if (!(ctx = talloc_init("sec_io_desc"))) {
                ret =  ADS_ERROR(LDAP_NO_MEMORY);
                goto ads_set_sd_error;
@@ -1466,7 +1451,10 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
                goto ads_set_sd_error;
        }
 
-       prs_init(&ps_wire, sd_size, ctx, MARSHALL);
+       if (!prs_init(&ps_wire, sd_size, ctx, MARSHALL)) {
+               ret = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
+
        if (!sec_io_desc("sd_wire", &psd, &ps_wire, 1)) {
                ret = ADS_ERROR(LDAP_NO_MEMORY);
                goto ads_set_sd_error;
@@ -1477,16 +1465,24 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
 #endif
        if (!(mods = ads_init_mods(ctx))) return ADS_ERROR(LDAP_NO_MEMORY);
 
-       bval.bv_len = sd_size;
-       bval.bv_val = talloc(ctx, sd_size);
+       bval.bv_len = prs_offset(&ps_wire);
+       bval.bv_val = talloc(ctx, bval.bv_len);
        if (!bval.bv_val) {
                ret = ADS_ERROR(LDAP_NO_MEMORY);
                goto ads_set_sd_error;
        }
-       prs_copy_all_data_out((char *)&bval.bv_val, &ps_wire);
 
-       ads_mod_ber(ctx, &mods, attrs[0], &bval);
-       ret = ads_gen_mod(ads, dn, mods);
+       prs_set_offset(&ps_wire, 0);
+
+       if (!prs_copy_data_out(bval.bv_val, &ps_wire, bval.bv_len)) {
+               ret = ADS_ERROR(LDAP_NO_MEMORY);
+               goto ads_set_sd_error;          
+       }
+
+       ret = ads_mod_ber(ctx, &mods, attrs[0], &bval);
+       if (ADS_ERR_OK(ret)) {
+               ret = ads_gen_mod(ads, dn, mods);
+       }
 
 ads_set_sd_error:
        ads_msgfree(ads, res);
@@ -1531,7 +1527,7 @@ char *ads_pull_string(ADS_STRUCT *ads,
        char **values;
        char *ret = NULL;
        char *ux_string;
-       int rc;
+       size_t rc;
 
        values = ldap_get_values(ads->ld, msg, field);
        if (!values)
@@ -1540,7 +1536,7 @@ char *ads_pull_string(ADS_STRUCT *ads,
        if (values[0]) {
                rc = pull_utf8_talloc(mem_ctx, &ux_string, 
                                      values[0]);
-               if (rc != -1)
+               if (rc != (size_t)-1)
                        ret = ux_string;
                
        }
@@ -1702,8 +1698,11 @@ int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
        count = 0;
        for (i=0; values[i]; i++) {
                ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
-               if (ret)
+               if (ret) {
+                       fstring sid;
+                       DEBUG(10, ("pulling SID: %s\n", sid_to_string(sid, &(*sids)[count])));
                        count++;
+               }
        }
        
        ldap_value_free_len(values);
@@ -1889,77 +1888,6 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
        return ADS_SUCCESS;
 }
 
-
-/**
- * find the list of trusted domains
- * @param ads connection to ads server
- * @param mem_ctx TALLOC_CTX for allocating results
- * @param num_trusts pointer to number of trusts
- * @param names pointer to trusted domain name list
- * @param sids pointer to list of sids of trusted domains
- * @return the count of SIDs pulled
- **/
-ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, 
-                              int *num_trusts, 
-                              char ***names, 
-                              char ***alt_names,
-                              DOM_SID **sids)
-{
-       const char *attrs[] = {"name", "flatname", "securityIdentifier", 
-                              "trustDirection", NULL};
-       ADS_STATUS status;
-       void *res, *msg;
-       int count, i;
-
-       *num_trusts = 0;
-
-       status = ads_search(ads, &res, "(objectcategory=trustedDomain)", attrs);
-       if (!ADS_ERR_OK(status)) return status;
-
-       count = ads_count_replies(ads, res);
-       if (count == 0) {
-               ads_msgfree(ads, res);
-               return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
-       }
-
-       (*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)) {
-               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++;
-               }
-       }
-
-       ads_msgfree(ads, res);
-
-       *num_trusts = i;
-
-       return ADS_SUCCESS;
-}
-
 /**
  * find the domain sid for our domain
  * @param ads connection to ads server
@@ -1997,7 +1925,7 @@ but you need to force the bind path to match the configurationNamingContext from
 */
 ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workgroup)
 {
-       char *exp;
+       char *expr;
        ADS_STATUS rc;
        char **principles;
        char *prefix;
@@ -2008,10 +1936,10 @@ ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workg
 
        (*workgroup) = NULL;
 
-       asprintf(&exp, "(&(objectclass=computer)(dnshostname=%s.%s))", 
+       asprintf(&expr, "(&(objectclass=computer)(dnshostname=%s.%s))", 
                 ads->config.ldap_server_name, ads->config.realm);
-       rc = ads_search(ads, &res, exp, attrs);
-       free(exp);
+       rc = ads_search(ads, &res, expr, attrs);
+       free(expr);
 
        if (!ADS_ERR_OK(rc)) {
                return rc;