admserv/cgi-src40/htmladmin.c | 15 ++++-
include/libadmin/libadmin.h | 13 ++++
lib/libadmin/util.c | 121 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 147 insertions(+), 2 deletions(-)
New commits:
commit 43f94dea635ca155a8a14c2dd1b4367b33a865ed
Author: Noriko Hosoi <nhosoi(a)jiji.sjc.redhat.com>
Date: Thu Feb 11 17:53:29 2010 -0800
560827 - Admin Server: DistinguishName validation fails
https://bugzilla.redhat.com/show_bug.cgi?id=560827
Description: get_all_users_views was generating an invalid DN
which included nested DN surrounded by unescaped double quotes.
Instead of escaping the double quotes, introduced a escape_for_dn
function which escape special characters in the nested DN.
diff --git a/admserv/cgi-src40/htmladmin.c b/admserv/cgi-src40/htmladmin.c
index 4ce4dbe..e6d9eee 100644
--- a/admserv/cgi-src40/htmladmin.c
+++ b/admserv/cgi-src40/htmladmin.c
@@ -590,6 +590,7 @@ char **get_all_users_views(LDAP *server, char *binddn, AdmldapInfo
ldapInfo) {
char **return_array = NULL;
int i;
+ char *escaped_binddn = NULL;
if(!binddn)
return NULL; /* anonymous bind, no user prefs, no views */
@@ -607,8 +608,18 @@ char **get_all_users_views(LDAP *server, char *binddn, AdmldapInfo
ldapInfo) {
ptr3++; /* remove spaces */
/* First, search private views */
-
- PR_snprintf(dn, BIG_LINE, "ou=\"%s\", ou=UserPreferences, %s",
binddn, ptr3);
+ ldapError = escape_for_dn(binddn, &escaped_binddn);
+ if (ldapError) {
+ return NULL; /* failed to escape binddn; bail */
+ }
+ if (NULL == escaped_binddn) {
+ PR_snprintf(dn, BIG_LINE, "ou=%s, ou=UserPreferences, %s",
+ binddn, ptr3);
+ } else {
+ PR_snprintf(dn, BIG_LINE, "ou=%s, ou=UserPreferences, %s",
+ escaped_binddn, ptr3);
+ PR_Free(escaped_binddn);
+ }
PR_snprintf(filter, BIG_LINE, "(&(objectclass=nscustomview))");
ldapError = ldap_search_s(server, dn, LDAP_SCOPE_SUBTREE,
diff --git a/include/libadmin/libadmin.h b/include/libadmin/libadmin.h
index 051bd47..3914fce 100644
--- a/include/libadmin/libadmin.h
+++ b/include/libadmin/libadmin.h
@@ -383,6 +383,19 @@ NSAPI_PUBLIC int perform_request(char *req, int whichsrv, char *auth,
char *succ
/* util.c */
NSAPI_PUBLIC void escape_for_shell(char *cmd);
+/*
+ * Escape src DN string (RFC 4514)
+ * Result
+ * Success:
+ * return value: 0
+ * src includes dn special characters
+ * --> *dist returns escaped string; caller needs to free it.
+ * src does not include dn special characters --> *dist == NULL
+ * Failure
+ * return value: -1
+ */
+int escape_for_dn(char *src, char **dist);
+
/* Lists all files in a directory. If dashA list .files except . and .. */
/* util.c */
NSAPI_PUBLIC char **list_directory(char *path, int dashA);
diff --git a/lib/libadmin/util.c b/lib/libadmin/util.c
index 6016466..52cd726 100644
--- a/lib/libadmin/util.c
+++ b/lib/libadmin/util.c
@@ -79,6 +79,127 @@ void escape_for_shell(char *cmd) {
}
}
+char dnspecial[] = {
+ '"', '+', ',', ';', '<', '>',
'=', '#', '\0'
+};
+
+static void
+put_dnescaped_char(char **distp, char **srcp)
+{
+ if (**srcp == '#') {
+ char c1 = *((*srcp)+1);
+ char c2 = *((*srcp)+2);
+ if (isxdigit(c1) && isxdigit(c2)) {
+ char *dn = NULL;
+ char c;
+ int n1 = 0, n2 = 0;
+ if ('0' <= c1 && c1 <= '9') {
+ n1 = c1 - '0';
+ } else if ('a' <= c1 && c1 <= 'f') {
+ n1 = c1 - 'a' + 10;
+ } else if ('A' <= c1 && c1 <= 'F') {
+ n1 = c1 - 'A' + 10;
+ }
+ if ('0' <= c2 && c2 <= '9') {
+ n2 = c2 - '0';
+ } else if ('a' <= c2 && c2 <= 'f') {
+ n2 = c2 - 'a' + 10;
+ } else if ('A' <= c2 && c2 <= 'F') {
+ n2 = c2 - 'A' + 10;
+ }
+ c = n1 * 16 + n2;
+ for (dn = dnspecial; dn && *dn; dn++) {
+ if (c == *dn) {
+ *((*distp)++) = '\\'; /* escape the char with '\\' */
+ *((*distp)++) = c;
+ break;
+ }
+ }
+ if (c != *dn) {
+ *((*distp)++) = c;
+ }
+ *srcp += 3;
+ } else {
+ *((*distp)++) = *((*srcp)++); /* Just copy '#' */
+ }
+ } else {
+ *((*distp)++) = '\\'; /* escape the char with '\\' */
+ *((*distp)++) = *((*srcp)++);
+ }
+}
+
+/*
+ * Escape src DN string (RFC 4514)
+ * Result
+ * Success:
+ * return value: 0
+ * src includes dn special characters
+ * --> *dist returns escaped string; caller needs to free it.
+ * src does not include dn special characters --> *dist == NULL
+ * Failure
+ * return value: -1
+ */
+int
+escape_for_dn(char *src, char **dist)
+{
+ char *srcp = NULL;
+ char *distp = NULL;
+ char *dn = NULL;
+ char *end = NULL;
+ int rc = -1;
+
+ if (NULL == dist) {
+ return rc;
+ }
+ *dist = NULL;
+ if (NULL == src) {
+ return rc;
+ }
+ end = src + strlen(src);
+
+ for (srcp = src; srcp && *srcp; srcp++) {
+ for (dn = dnspecial; dn && *dn; dn++) {
+ if (*srcp == *dn) {
+ goto out;
+ }
+ }
+ }
+out:
+ rc = 0;
+ if (*srcp && (*srcp == *dn)) { /* src includes a dn special character */
+ char *distend = NULL;
+ int maxdistlen = ((srcp - src) + (end - srcp) * 2) + 1;
+ /* max necessary length */
+ *dist = (char *)PR_Calloc(sizeof(char), maxdistlen);
+ if (NULL == *dist) {
+ rc = -1;
+ goto bail;
+ }
+ distend = *dist + maxdistlen;
+ memcpy(*dist, src, srcp - src); /* copy non escaped part */
+ distp = *dist + (srcp - src);
+ put_dnescaped_char(&distp, &srcp);
+ while (srcp && *srcp && distp && distp < distend) {
+ for (dn = dnspecial; dn && *dn; dn++) {
+ if (*srcp == *dn) {
+ put_dnescaped_char(&distp, &srcp);
+ break;
+ }
+ }
+ if ('\0' == *dn) {
+ *distp++ = *srcp++;
+ }
+ }
+ if (distp == distend) {
+ PR_Free(*dist);
+ *dist = NULL;
+ rc = -1;
+ }
+ }
+bail:
+ return rc;
+}
+
int _admin_dumbsort(const void *s1, const void *s2)
{
return strcmp(*((char **)s1), *((char **)s2));