diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | src/back-sch.c | 82 | ||||
-rwxr-xr-x | tests/test31-schema-weird-rdn/after.sh | 4 | ||||
-rw-r--r-- | tests/test31-schema-weird-rdn/after.txt | 13 | ||||
-rwxr-xr-x | tests/test31-schema-weird-rdn/before.sh | 4 | ||||
-rw-r--r-- | tests/test31-schema-weird-rdn/before.txt | 5 | ||||
-rwxr-xr-x | tests/test31-schema-weird-rdn/change.sh | 91 | ||||
-rw-r--r-- | tests/test31-schema-weird-rdn/description.txt | 1 | ||||
-rw-r--r-- | tests/test31-schema-weird-rdn/dse.ldif | 13 |
9 files changed, 205 insertions, 9 deletions
@@ -1,3 +1,4 @@ +0.38 * Properly escape RDN values when building compat entries (#796509). 0.37 * Fix a compile error on systems which don't define LDAP_SCOPE_SUBORDINATE, reported by Christian Neuhold. 0.36 * Stop yp_first/yp_next from looping indefinitely when keys get diff --git a/src/back-sch.c b/src/back-sch.c index ac6ff17..2e2d195 100644 --- a/src/back-sch.c +++ b/src/back-sch.c @@ -287,7 +287,8 @@ void backend_set_entry(Slapi_PBlock *pb, Slapi_Entry *e, struct backend_set_data *data) { - char *dn, *rdn, *ndn, *ldif, *plugin_id, *keys[2], *values[2], **ava; + const char *hexchars = "0123456789ABCDEF"; + char *rdn, *ndn, *ldif, *plugin_id, *keys[2], *values[2], **ava, *p, *q; char *attr, *val; unsigned int rdn_len, value_len, *ava_lens; const char *rdnstr; @@ -317,21 +318,68 @@ backend_set_entry(Slapi_PBlock *pb, Slapi_Entry *e, &data->common.ref_attr_list, &data->common.inref_attr_list, &rdn_len); - if (rdn == NULL) { - slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id, - "no RDN for %s, unsetting domain/map/id" + if ((rdn == NULL) || (strlen(rdn) == 0) || (strchr(rdn, '=') == NULL)) { + slapi_log_error(SLAPI_LOG_FATAL, plugin_id, + "no RDN for %s, unsetting domain/map/id " "\"%s\"/\"%s\"/(\"%s\")\n", ndn, data->common.group, data->common.set, ndn); map_data_unset_entry(data->common.state, data->common.group, data->common.set, ndn); + return; + } + /* Assume attribute=value and hex-escape the whole value to build the + * new entry's RDN. The server functions will un-escape whatever they + * can when we build the resulting DN. */ + q = malloc(strlen(rdn) * 3 + 1); + p = strchr(rdn, '=') + 1; + i = p - rdn; + memcpy(q, rdn, i); + while (*p != '\0') { + j = ((unsigned int) *p++) & 0xff; + q[i++] = '\\'; + q[i++] = hexchars[(j & 0xf0) >> 4]; + q[i++] = hexchars[j & 0xf]; + } + q[i] = '\0'; + srdn = slapi_rdn_new_dn(q); + free(q); + /* Now build the SDN. Check it for validity. */ + sdn = slapi_sdn_add_rdn(slapi_sdn_dup(data->container_sdn), srdn); + slapi_rdn_free(&srdn); + if ((sdn == NULL) || + (slapi_sdn_get_dn(sdn) == NULL) || + (slapi_sdn_get_ndn(sdn) == NULL)) { + slapi_log_error(SLAPI_LOG_FATAL, plugin_id, + "would generate an invalid DN (1), " + "unsetting domain/map/id " + "\"%s\"/\"%s\"/(\"%s\")\n", + data->common.group, data->common.set, ndn); + map_data_unset_entry(data->common.state, + data->common.group, data->common.set, ndn); + if (sdn != NULL) { + slapi_sdn_free(&sdn); + } + format_free_data(rdn); + return; } - /* Now build the entry itself, and set the DN first. */ + /* Now build the entry itself. Set the DN first, and make sure it took + * the value. */ entry = slapi_entry_alloc(); - dn = slapi_dn_plus_rdn(slapi_sdn_get_ndn(data->container_sdn), rdn); - sdn = slapi_sdn_new_dn_byval(dn); slapi_entry_set_sdn(entry, sdn); slapi_sdn_free(&sdn); - slapi_ch_free((void **) &dn); + if ((slapi_entry_get_dn(entry) == NULL) || + (slapi_entry_get_ndn(entry) == NULL)) { + slapi_log_error(SLAPI_LOG_FATAL, plugin_id, + "would generate an invalid DN (2), " + "unsetting domain/map/id " + "\"%s\"/\"%s\"/(\"%s\")\n", + data->common.group, data->common.set, ndn); + map_data_unset_entry(data->common.state, + data->common.group, data->common.set, ndn); + slapi_entry_free(entry); + format_free_data(rdn); + return; + } /* Set operational attributes here so that they can be overridden. */ backend_set_operational_attributes(entry, data->common.state, time(NULL), 0); @@ -457,8 +505,24 @@ backend_set_entry(Slapi_PBlock *pb, Slapi_Entry *e, backend_entry_make_entry_data(e_dn, entry), backend_entry_free_entry_data); } else { + if (rdnstr == NULL) { + slapi_log_error(SLAPI_LOG_FATAL, plugin_id, + "would generate an invalid RDN, " + "unsetting domain/map/id " + "\"%s\"/\"%s\"/(\"%s\")\n", + data->common.group, data->common.set, + ndn); + } + if (slapi_entry_get_ndn(entry) == NULL) { + slapi_log_error(SLAPI_LOG_FATAL, plugin_id, + "would generate an invalid entry DN, " + "unsetting domain/map/id " + "\"%s\"/\"%s\"/(\"%s\")\n", + data->common.group, data->common.set, + ndn); + } slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id, - "no value for %s, unsetting domain/map/id" + "no value for %s, unsetting domain/map/id " "\"%s\"/\"%s\"/(\"%s\")\n", ndn, data->common.group, data->common.set, ndn); map_data_unset_entry(data->common.state, diff --git a/tests/test31-schema-weird-rdn/after.sh b/tests/test31-schema-weird-rdn/after.sh new file mode 100755 index 0000000..32c64be --- /dev/null +++ b/tests/test31-schema-weird-rdn/after.sh @@ -0,0 +1,4 @@ +#!/bin/sh +{ search -b cn=compat,cn=accounts,dc=example,dc=com dn ; \ + search -b cn=compat2,cn=accounts,dc=example,dc=com dn; } |\ +grep ^dn: | env LANG=C sort diff --git a/tests/test31-schema-weird-rdn/after.txt b/tests/test31-schema-weird-rdn/after.txt new file mode 100644 index 0000000..4536f9b --- /dev/null +++ b/tests/test31-schema-weird-rdn/after.txt @@ -0,0 +1,13 @@ +dn: cn=-User 1 E,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=CRON\2C the destroyer,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1 A,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1 B,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1 C,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1 F\2B,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1 G-,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1\2BH,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1\5C\2BI,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=You \2B Me \3D We,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=\2BUser 1 D,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=compat,cn=accounts,dc=example,dc=com +dn: ou=passwd,cn=compat,cn=accounts,dc=example,dc=com diff --git a/tests/test31-schema-weird-rdn/before.sh b/tests/test31-schema-weird-rdn/before.sh new file mode 100755 index 0000000..32c64be --- /dev/null +++ b/tests/test31-schema-weird-rdn/before.sh @@ -0,0 +1,4 @@ +#!/bin/sh +{ search -b cn=compat,cn=accounts,dc=example,dc=com dn ; \ + search -b cn=compat2,cn=accounts,dc=example,dc=com dn; } |\ +grep ^dn: | env LANG=C sort diff --git a/tests/test31-schema-weird-rdn/before.txt b/tests/test31-schema-weird-rdn/before.txt new file mode 100644 index 0000000..07e162b --- /dev/null +++ b/tests/test31-schema-weird-rdn/before.txt @@ -0,0 +1,5 @@ +dn: cn=User 1 A,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1 B,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=User 1 C,ou=passwd,cn=compat,cn=accounts,dc=example,dc=com +dn: cn=compat,cn=accounts,dc=example,dc=com +dn: ou=passwd,cn=compat,cn=accounts,dc=example,dc=com diff --git a/tests/test31-schema-weird-rdn/change.sh b/tests/test31-schema-weird-rdn/change.sh new file mode 100755 index 0000000..b5ffd76 --- /dev/null +++ b/tests/test31-schema-weird-rdn/change.sh @@ -0,0 +1,91 @@ +#!/bin/sh +add << EOF +dn: uid=user1d,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1d +uidNumber: 1004 +gidNumber: 1004 +cn: +User 1 D +gecos: User 1 D +loginShell: /bin/sh +homeDirectory: /home/user1d + +dn: uid=user1e,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1e +uidNumber: 1005 +gidNumber: 1005 +cn: -User 1 E +gecos: User 1 E +loginShell: /bin/sh +homeDirectory: /home/user1e + +dn: uid=user1f,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1f +uidNumber: 1006 +gidNumber: 1006 +cn: User 1 F+ +gecos: User 1 F +loginShell: /bin/sh +homeDirectory: /home/user1f + +dn: uid=user1g,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1g +uidNumber: 1007 +gidNumber: 1007 +cn: User 1 G- +gecos: User 1 G +loginShell: /bin/sh +homeDirectory: /home/user1g + +dn: uid=user1h,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1h +uidNumber: 1008 +gidNumber: 1008 +cn: User 1+H +gecos: User 1 H +loginShell: /bin/sh +homeDirectory: /home/user1h + +dn: uid=user1i,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1i +uidNumber: 1009 +gidNumber: 1009 +cn: User 1\+I +gecos: User 1 I +loginShell: /bin/sh +homeDirectory: /home/user1i + +dn: uid=user1j,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1j +uidNumber: 1010 +gidNumber: 1010 +cn: CRON, the destroyer +gecos: User 1 J +loginShell: /bin/sh +homeDirectory: /home/user1j + +dn: uid=user1k,cn=Users1,cn=Accounts,dc=example,dc=com +objectClass: posixAccount +objectClass: inetUser +uid: user1k +uidNumber: 1011 +gidNumber: 1011 +cn: You + Me = We +gecos: User 1 K +loginShell: /bin/sh +homeDirectory: /home/user1k + +EOF diff --git a/tests/test31-schema-weird-rdn/description.txt b/tests/test31-schema-weird-rdn/description.txt new file mode 100644 index 0000000..c3b091d --- /dev/null +++ b/tests/test31-schema-weird-rdn/description.txt @@ -0,0 +1 @@ +an RDN that needs escaping diff --git a/tests/test31-schema-weird-rdn/dse.ldif b/tests/test31-schema-weird-rdn/dse.ldif new file mode 100644 index 0000000..0897534 --- /dev/null +++ b/tests/test31-schema-weird-rdn/dse.ldif @@ -0,0 +1,13 @@ +dn: cn=compat-passwd,cn=Schema Compatibility,cn=plugins,cn=config +objectClass: top +objectClass: extensibleObject +cn: compat-passwd +schema-compat-container-group: cn=compat,cn=Accounts,dc=example,dc=com +schema-compat-container-rdn: ou=passwd +schema-compat-check-access: yes +schema-compat-search-base: cn=Users1,cn=Accounts,dc=example,dc=com +schema-compat-search-filter: (objectClass=posixAccount) +schema-compat-entry-rdn: cn=%{cn} +schema-compat-entry-attribute: objectclass=extensibleobject +schema-compat-entry-attribute: uidNumber=%{uidNumber} + |