Always escape ldap filter strings. Escaping code was from pam_ldap, but I'm to
authorAndrew Bartlett <abartlet@samba.org>
Sat, 1 Feb 2003 05:20:11 +0000 (05:20 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 1 Feb 2003 05:20:11 +0000 (05:20 +0000)
blame for the realloc() stuff.

Plus a couple of minor updates to libads.

Andrew Bartlett
(This used to be commit 34b2e558a4b3cfd753339bb228a9799e27ed8170)

source3/lib/ldap_escape.c [new file with mode: 0644]
source3/libads/ads_ldap.c
source3/libads/ldap.c
source3/libads/ldap_user.c
source3/nsswitch/winbindd_ads.c
source3/passdb/pdb_ldap.c
source3/utils/net_ads.c

diff --git a/source3/lib/ldap_escape.c b/source3/lib/ldap_escape.c
new file mode 100644 (file)
index 0000000..9e88b49
--- /dev/null
@@ -0,0 +1,90 @@
+/* 
+   Unix SMB/CIFS implementation.
+   ldap filter argument escaping
+
+   Copyright (C) 1998, 1999, 2000 Luke Howard <lukeh@padl.com>,
+   Copyright (C) 2003 Andrew Bartlett <abartlet@samba.org>
+
+  
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/**
+ * Escape a parameter to an LDAP filter string, so they cannot contain
+ * embeded ( ) * or \ chars which may cause it not to parse correctly. 
+ *
+ * @param s The input string
+ *
+ * @return A string allocated with malloc(), containing the escaped string, 
+ * and to be free()ed by the caller.
+ **/
+
+char *escape_ldap_string_alloc(const char *s)
+{
+       size_t len = strlen(s)+1;
+       char *output = malloc(len);
+       char *output_tmp;
+       const char *sub;
+       int i = 0;
+       char *p = output;
+       
+       while (*s)
+       {
+               switch (*s)
+               {
+               case '*':
+                       sub = "\\2a";
+                       break;
+               case '(':
+                       sub = "\\28";
+                       break;
+               case ')':
+                       sub = "\\29";
+                       break;
+               case '\\':
+                       sub = "\\5c";
+                       break;
+               default:
+                       sub = NULL;
+                       break;
+               }
+               
+               if (sub) {
+                       len = len + 3;
+                       output_tmp = realloc(output, len);
+                       if (!output_tmp) { 
+                               SAFE_FREE(output);
+                               return NULL;
+                       }
+                       output = output_tmp;
+                       
+                       p = &output[i];
+                       strncpy (p, sub, 3);
+                       p += 3;
+                       i += 3;
+
+               } else {
+                       *p = *s;
+                       p++;
+                       i++;
+               }
+               s++;
+       }
+       
+       *p = '\0';
+       return output;
+}
index 05b016539e20bb1ac27bb566d2bccf3249112494..97f12de0f7f82be6a7084dbcf1cb6f62105a44ac 100644 (file)
@@ -37,9 +37,16 @@ NTSTATUS ads_name_to_sid(ADS_STRUCT *ads,
        char *exp;
        uint32 t;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       char *escaped_name = escape_ldap_string_alloc(name);
+       char *escaped_realm = escape_ldap_string_alloc(ads->config.realm);
+
+       if (!escaped_name || !escaped_realm) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
 
        if (asprintf(&exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))", 
-                    name, name, ads->config.realm) == -1) {
+                    escaped_name, escaped_name, escaped_realm) == -1) {
                DEBUG(1,("ads_name_to_sid: asprintf failed!\n"));
                status = NT_STATUS_NO_MEMORY;
                goto done;
@@ -77,6 +84,9 @@ NTSTATUS ads_name_to_sid(ADS_STRUCT *ads,
 done:
        if (res) ads_msgfree(ads, res);
 
+       SAFE_FREE(escaped_name);
+       SAFE_FREE(escaped_realm);
+
        return status;
 }
 
index 0a95e019bfb5b7317a04365a6acb307a8d86e994..603f17c9948ad14d52d2e9b224219d33196b3d5b 100644 (file)
@@ -974,7 +974,7 @@ ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
        /* make sure the end of the list is NULL */
        mods[i] = NULL;
 
-       ret = ldap_add_s(ads->ld, utf8_dn ? utf8_dn : new_dn, mods);
+       ret = ldap_add_s(ads->ld, utf8_dn, mods);
        SAFE_FREE(utf8_dn);
        return ADS_ERROR(ret);
 }
@@ -994,7 +994,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 ? utf8_dn : del_dn);
+       ret = ldap_delete(ads->ld, utf8_dn);
        return ADS_ERROR(ret);
 }
 
@@ -1029,8 +1029,8 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
        ADS_MODLIST mods;
        const char *objectClass[] = {"top", "person", "organizationalPerson",
                                     "user", "computer", NULL};
-       const char *servicePrincipalName[3] = {NULL, NULL, NULL};
-       char *psp;
+       const char *servicePrincipalName[5] = {NULL, NULL, NULL, NULL, NULL};
+       char *psp, *psp2;
        unsigned acct_control;
 
        if (!(ctx = talloc_init("machine_account")))
@@ -1051,10 +1051,16 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
                                 ads->config.bind_path);
        servicePrincipalName[0] = talloc_asprintf(ctx, "HOST/%s", hostname);
        psp = talloc_asprintf(ctx, "HOST/%s.%s", 
-                                                 hostname, 
-                                                 ads->config.realm);
+                             hostname, 
+                             ads->config.realm);
        strlower(&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]);
+       servicePrincipalName[3] = psp2;
 
        free(ou_str);
        if (!new_dn)
@@ -1405,6 +1411,7 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
        size_t          sd_size = 0;
        struct berval   bval = {0, NULL};
        prs_struct      ps_wire;
+       char           *escaped_hostname = escape_ldap_string_alloc(hostname);
 
        LDAPMessage *res  = 0;
        LDAPMessage *msg  = 0;
@@ -1420,11 +1427,18 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
 
        ret = ADS_ERROR(LDAP_SUCCESS);
 
-       if (asprintf(&exp, "(samAccountName=%s$)", hostname) == -1) {
+       if (!escaped_hostname) {
+               return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
+
+       if (asprintf(&exp, "(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);
        }
 
+       SAFE_FREE(escaped_hostname);
+
        ret = ads_search(ads, (void *) &res, exp, attrs);
 
        if (!ADS_ERR_OK(ret)) return ret;
index 2e38e7a00d1dae74a578cb1709e37f683babcc2c..7efe5338f371bb7e8b81a6a3a3e0cad3dfbc0511 100644 (file)
@@ -30,10 +30,15 @@ ADS_STATUS ads_find_user_acct(ADS_STRUCT *ads, void **res, const char *user)
        ADS_STATUS status;
        char *exp;
        const char *attrs[] = {"*", NULL};
+       char *escaped_user = escape_ldap_string_alloc(user);
+       if (!escaped_user) {
+               return ADS_ERROR(LDAP_NO_MEMORY);
+       }
 
-       asprintf(&exp, "(samAccountName=%s)", user);
+       asprintf(&exp, "(samAccountName=%s)", escaped_user);
        status = ads_search(ads, res, exp, attrs);
-       free(exp);
+       SAFE_FREE(exp);
+       SAFE_FREE(escaped_user);
        return status;
 }
 
index 261c2f2237ae0c92cdc3ba0430a5beaa4c929e9d..7cea4aa716ee61b3d0d1f99299235056b8f9538d 100644 (file)
@@ -346,10 +346,17 @@ static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
        ADS_STATUS rc;
        uint32 atype;
        DOM_SID sid;
+       char *escaped_dn = escape_ldap_string_alloc(dn);
+
+       if (!escaped_dn) {
+               return False;
+       }
 
        asprintf(&exp, "(distinguishedName=%s)", dn);
        rc = ads_search_retry(ads, &res, exp, attrs);
-       free(exp);
+       SAFE_FREE(exp);
+       SAFE_FREE(escaped_dn);
+
        if (!ADS_ERR_OK(rc)) {
                goto failed;
        }
index e98a2cf04ffec5a8a310b98a39f951b46bff2298..6f46201d8dd1518d7f85372f93b39b99cb8e0716 100644 (file)
@@ -666,7 +666,12 @@ static int ldapsam_search_one_user_by_name (struct ldapsam_privates *ldap_state,
                             LDAPMessage ** result)
 {
        pstring filter;
-       
+       char *escape_user = escape_ldap_string_alloc(user);
+
+       if (!escape_user) {
+               return LDAP_NO_MEMORY;
+       }
+
        /*
         * in the filter expression, replace %u with the real name
         * so in ldap filter, %u MUST exist :-)
@@ -677,7 +682,10 @@ static int ldapsam_search_one_user_by_name (struct ldapsam_privates *ldap_state,
         * have to use this here because $ is filtered out
           * in pstring_sub
         */
-       all_string_sub(filter, "%u", user, sizeof(pstring));
+       
+
+       all_string_sub(filter, "%u", escape_user, sizeof(pstring));
+       SAFE_FREE(escape_user);
 
        return ldapsam_search_one_user(ldap_state, filter, result);
 }
@@ -691,6 +699,7 @@ static int ldapsam_search_one_user_by_uid(struct ldapsam_privates *ldap_state,
 {
        struct passwd *user;
        pstring filter;
+       char *escape_user;
 
        /* Get the username from the system and look that up in the LDAP */
        
@@ -701,9 +710,16 @@ static int ldapsam_search_one_user_by_uid(struct ldapsam_privates *ldap_state,
        
        pstrcpy(filter, lp_ldap_filter());
        
-       all_string_sub(filter, "%u", user->pw_name, sizeof(pstring));
+       escape_user = escape_ldap_string_alloc(user->pw_name);
+       if (!escape_user) {
+               passwd_free(&user);
+               return LDAP_NO_MEMORY;
+       }
+
+       all_string_sub(filter, "%u", escape_user, sizeof(pstring));
 
        passwd_free(&user);
+       SAFE_FREE(escape_user);
 
        return ldapsam_search_one_user(ldap_state, filter, result);
 }
index 29abc33fdf53347987231b63e8db86c48245bf29..867252c95f2ac9743b1d44ad0e7e271510892eae 100644 (file)
@@ -308,12 +308,18 @@ static int ads_user_info(int argc, const char **argv)
        const char *attrs[] = {"memberOf", NULL};
        char *searchstring=NULL;
        char **grouplist;
+       char *escaped_user = escape_ldap_string_alloc(argv[0]);
 
        if (argc < 1) return net_ads_user_usage(argc, argv);
        
        if (!(ads = ads_startup())) return -1;
 
-       asprintf(&searchstring, "(sAMAccountName=%s)", argv[0]);
+       if (!escaped_user) {
+               d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
+               return -1;
+       }
+
+       asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
        rc = ads_search(ads, &res, searchstring, attrs);
        safe_free(searchstring);