From: Todd C. Miller Date: Wed, 7 Dec 2011 20:12:22 +0000 (-0500) Subject: Escape values in the search expression as per RFC 4515. X-Git-Tag: SUDO_1_8_4~111^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=666d8d635919fd9de4cc3dcd5913f4d5a0a598df;p=sudo Escape values in the search expression as per RFC 4515. --- diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index a1942de94..04afd87bb 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -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++) {