]> granicus.if.org Git - sudo/commitdiff
Escape values in the search expression as per RFC 4515.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 7 Dec 2011 20:12:22 +0000 (15:12 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 7 Dec 2011 20:12:22 +0000 (15:12 -0500)
plugins/sudoers/ldap.c

index a1942de94dd35092be6b3d789309ebc7c47f89d8..04afd87bb27c27291688fce400d3b805ab4de8c9 100644 (file)
@@ -993,6 +993,99 @@ sudo_ldap_build_default_filter(void)
     debug_return_str(filt);
 }
 
+/*
+ * Determine length of query value after escaping characters
+ * as per RFC 4515.
+ */
+static size_t
+sudo_ldap_value_len(const char *value)
+{
+    const char *s;
+    size_t len = 0;
+
+    for (s = value; *s != '\0'; s++) {
+       switch (*s) {
+       case '\\':
+       case '(':
+       case ')':
+       case '*':
+           len += 2;
+           break;
+       }
+    }
+    len += (size_t)(s - value);
+    return len;
+}
+
+/*
+ * Like strlcat() but escapes characters as per RFC 4515.
+ */
+static size_t
+sudo_ldap_value_cat(char *dst, const char *src, size_t size)
+{
+    char *d = dst;
+    const char *s = src;
+    size_t n = size;
+    size_t dlen;
+
+    /* Find the end of dst and adjust bytes left but don't go past end */
+    while (n-- != 0 && *d != '\0')
+       d++;
+    dlen = d - dst;
+    n = size - dlen;
+
+    if (n == 0)
+       return dlen + strlen(s);
+    while (*s != '\0') {
+       switch (*s) {
+       case '\\':
+           if (n < 3)
+               goto done;
+           *d++ = '\\';
+           *d++ = '5';
+           *d++ = 'c';
+           n -= 3;
+           break;
+       case '(':
+           if (n < 3)
+               goto done;
+           *d++ = '\\';
+           *d++ = '2';
+           *d++ = '8';
+           n -= 3;
+           break;
+       case ')':
+           if (n < 3)
+               goto done;
+           *d++ = '\\';
+           *d++ = '2';
+           *d++ = '9';
+           n -= 3;
+           break;
+       case '*':
+           if (n < 3)
+               goto done;
+           *d++ = '\\';
+           *d++ = '2';
+           *d++ = 'a';
+           n -= 3;
+           break;
+       default:
+           if (n < 1)
+               goto done;
+           *d++ = *s;
+           n--;
+           break;
+       }
+       s++;
+    }
+done:
+    *d = '\0';
+    while (*s != '\0')
+       s++;
+    return dlen + (s - src);   /* count does not include NUL */
+}
+
 /*
  * Builds up a filter to check against LDAP.
  */
@@ -1011,18 +1104,18 @@ sudo_ldap_build_pass1(struct passwd *pw)
        sz += strlen(ldap_conf.search_filter) + 3;
 
     /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
-    sz += 29 + strlen(pw->pw_name);
+    sz += 29 + sudo_ldap_value_len(pw->pw_name);
 
     /* Add space for primary and supplementary groups and gids */
     if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
-       sz += 12 + strlen(grp->gr_name);
+       sz += 12 + sudo_ldap_value_len(grp->gr_name);
     }
     sz += 13 + MAX_UID_T_LEN;
     if ((grlist = get_group_list(pw)) != NULL) {
        for (i = 0; i < grlist->ngroups; i++) {
            if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
                continue;
-           sz += 12 + strlen(grlist->groups[i]);
+           sz += 12 + sudo_ldap_value_len(grlist->groups[i]);
        }
        for (i = 0; i < grlist->ngids; i++) {
            if (pw->pw_gid == grlist->gids[i])
@@ -1049,13 +1142,13 @@ sudo_ldap_build_pass1(struct passwd *pw)
 
     /* Global OR + sudoUser=user_name filter */
     (void) strlcat(buf, "(|(sudoUser=", sz);
-    (void) strlcat(buf, pw->pw_name, sz);
+    (void) sudo_ldap_value_cat(buf, pw->pw_name, sz);
     (void) strlcat(buf, ")", sz);
 
     /* Append primary group and gid */
     if (grp != NULL) {
        (void) strlcat(buf, "(sudoUser=%", sz);
-       (void) strlcat(buf, grp->gr_name, sz);
+       (void) sudo_ldap_value_cat(buf, grp->gr_name, sz);
        (void) strlcat(buf, ")", sz);
     }
     (void) snprintf(gidbuf, sizeof(gidbuf), "%u", (unsigned int)pw->pw_gid);
@@ -1069,7 +1162,7 @@ sudo_ldap_build_pass1(struct passwd *pw)
            if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
                continue;
            (void) strlcat(buf, "(sudoUser=%", sz);
-           (void) strlcat(buf, grlist->groups[i], sz);
+           (void) sudo_ldap_value_cat(buf, grlist->groups[i], sz);
            (void) strlcat(buf, ")", sz);
        }
        for (i = 0; i < grlist->ngids; i++) {