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.
*/
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])
/* 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);
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++) {