summaryrefslogtreecommitdiff
path: root/source4/libcli/ldap/ldap_ldif.c
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2004-08-20 07:39:19 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:58:13 -0500
commit333aaf01e8dc1aba8cb7bba3e8fa792ff136e647 (patch)
treef27c526273e584a4d3b6f4c93e3eb0647812d779 /source4/libcli/ldap/ldap_ldif.c
parent5a5f9c8aa792a586350ec8c9f2754679eb857b8a (diff)
downloadsamba-333aaf01e8dc1aba8cb7bba3e8fa792ff136e647.tar.gz
samba-333aaf01e8dc1aba8cb7bba3e8fa792ff136e647.tar.bz2
samba-333aaf01e8dc1aba8cb7bba3e8fa792ff136e647.zip
r1944: put ldif functions in a separate file
(This used to be commit 8be31e5c854e4462163b97b897ff41de95f181c4)
Diffstat (limited to 'source4/libcli/ldap/ldap_ldif.c')
-rw-r--r--source4/libcli/ldap/ldap_ldif.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/source4/libcli/ldap/ldap_ldif.c b/source4/libcli/ldap/ldap_ldif.c
new file mode 100644
index 0000000000..2f23dd16a6
--- /dev/null
+++ b/source4/libcli/ldap/ldap_ldif.c
@@ -0,0 +1,409 @@
+/*
+ Unix SMB/CIFS mplementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ *
+ * LDIF parser
+ *
+ * Shamelessly stolen and adapted from ldb.
+ *
+ ***************************************************************************/
+
+/*
+ pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
+ this routine removes any RFC2849 continuations and comments
+
+ caller frees
+*/
+static char *next_chunk(TALLOC_CTX *mem_ctx,
+ int (*fgetc_fn)(void *), void *private_data)
+{
+ size_t alloc_size=0, chunk_size = 0;
+ char *chunk = NULL;
+ int c;
+ int in_comment = 0;
+
+ while ((c = fgetc_fn(private_data)) != EOF) {
+ if (chunk_size+1 >= alloc_size) {
+ char *c2;
+ alloc_size += 1024;
+ c2 = talloc_realloc(mem_ctx, chunk, alloc_size);
+ if (!c2) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ chunk = c2;
+ }
+
+ if (in_comment) {
+ if (c == '\n') {
+ in_comment = 0;
+ }
+ continue;
+ }
+
+ /* handle continuation lines - see RFC2849 */
+ if (c == ' ' && chunk_size > 1 &&
+ chunk[chunk_size-1] == '\n') {
+ chunk_size--;
+ continue;
+ }
+
+ /* chunks are terminated by a double line-feed */
+ if (c == '\n' && chunk_size > 0 &&
+ chunk[chunk_size-1] == '\n') {
+ chunk[chunk_size-1] = 0;
+ return chunk;
+ }
+
+ if (c == '#' &&
+ (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
+ in_comment = 1;
+ continue;
+ }
+
+ /* ignore leading blank lines */
+ if (chunk_size == 0 && c == '\n') {
+ continue;
+ }
+
+ chunk[chunk_size++] = c;
+ }
+
+ if (chunk) {
+ chunk[chunk_size] = 0;
+ }
+
+ return chunk;
+}
+
+/* simple ldif attribute parser */
+static int next_attr(char **s, const char **attr, struct ldap_val *value)
+{
+ char *p;
+ int base64_encoded = 0;
+
+ if (strncmp(*s, "-\n", 2) == 0) {
+ value->length = 0;
+ *attr = "-";
+ *s += 2;
+ return 0;
+ }
+
+ p = strchr(*s, ':');
+ if (!p) {
+ return -1;
+ }
+
+ *p++ = 0;
+
+ if (*p == ':') {
+ base64_encoded = 1;
+ p++;
+ }
+
+ *attr = *s;
+
+ while (isspace(*p)) {
+ p++;
+ }
+
+ value->data = p;
+
+ p = strchr(p, '\n');
+
+ if (!p) {
+ value->length = strlen((char *)value->data);
+ *s = ((char *)value->data) + value->length;
+ } else {
+ value->length = p - (char *)value->data;
+ *s = p+1;
+ *p = 0;
+ }
+
+ if (base64_encoded) {
+ DATA_BLOB blob = base64_decode_data_blob(value->data);
+ memcpy(value->data, blob.data, blob.length);
+ value->length = blob.length;
+ ((char *)value->data)[value->length] = '\0';
+ }
+
+ return 0;
+}
+
+BOOL add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldap_val *value,
+ struct ldap_attribute *attrib)
+{
+ attrib->values = talloc_realloc(mem_ctx, attrib->values,
+ sizeof(*attrib->values) *
+ (attrib->num_values+1));
+ if (attrib->values == NULL)
+ return False;
+
+ attrib->values[attrib->num_values] =
+ data_blob_talloc(mem_ctx, value->data, value->length);
+ attrib->num_values += 1;
+ return True;
+}
+
+BOOL add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
+ const struct ldap_attribute *attrib,
+ struct ldap_attribute **attribs,
+ int *num_attribs)
+{
+ *attribs = talloc_realloc(mem_ctx, *attribs,
+ sizeof(**attribs) * (*num_attribs+1));
+
+ if (*attribs == NULL)
+ return False;
+
+ (*attribs)[*num_attribs] = *attrib;
+ *num_attribs += 1;
+ return True;
+}
+
+static BOOL fill_add_attributes(struct ldap_message *msg, char **chunk)
+{
+ struct ldap_AddRequest *r = &msg->r.AddRequest;
+ const char *attr_name;
+ struct ldap_val value;
+
+ r->num_attributes = 0;
+ r->attributes = NULL;
+
+ while (next_attr(chunk, &attr_name, &value) == 0) {
+ int i;
+ struct ldap_attribute *attrib = NULL;
+
+ for (i=0; i<r->num_attributes; i++) {
+ if (strequal(r->attributes[i].name, attr_name)) {
+ attrib = &r->attributes[i];
+ break;
+ }
+ }
+
+ if (attrib == NULL) {
+ r->attributes = talloc_realloc(msg->mem_ctx,
+ r->attributes,
+ sizeof(*r->attributes) *
+ (r->num_attributes+1));
+ if (r->attributes == NULL)
+ return False;
+
+ attrib = &(r->attributes[r->num_attributes]);
+ r->num_attributes += 1;
+ ZERO_STRUCTP(attrib);
+ attrib->name = talloc_strdup(msg->mem_ctx,
+ attr_name);
+ }
+
+ if (!add_value_to_attrib(msg->mem_ctx, &value, attrib))
+ return False;
+ }
+ return True;
+}
+
+BOOL add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
+ struct ldap_mod *mod,
+ struct ldap_mod **mods,
+ int *num_mods)
+{
+ *mods = talloc_realloc(mem_ctx, *mods,
+ sizeof(**mods) * ((*num_mods)+1));
+
+ if (*mods == NULL)
+ return False;
+
+ (*mods)[*num_mods] = *mod;
+ *num_mods += 1;
+ return True;
+}
+
+static BOOL fill_mods(struct ldap_message *msg, char **chunk)
+{
+ struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
+ const char *attr_name;
+ struct ldap_val value;
+
+ r->num_mods = 0;
+ r->mods = NULL;
+
+ while (next_attr(chunk, &attr_name, &value) == 0) {
+
+ struct ldap_mod mod;
+ mod.type = LDAP_MODIFY_NONE;
+
+ mod.attrib.name = talloc_strdup(msg->mem_ctx, value.data);
+
+ if (strequal(attr_name, "add"))
+ mod.type = LDAP_MODIFY_ADD;
+
+ if (strequal(attr_name, "delete"))
+ mod.type = LDAP_MODIFY_DELETE;
+
+ if (strequal(attr_name, "replace"))
+ mod.type = LDAP_MODIFY_REPLACE;
+
+ if (mod.type == LDAP_MODIFY_NONE) {
+ DEBUG(2, ("ldif modification type %s unsupported\n",
+ attr_name));
+ return False;
+ }
+
+ mod.attrib.num_values = 0;
+ mod.attrib.values = NULL;
+
+ while (next_attr(chunk, &attr_name, &value) == 0) {
+ if (strequal(attr_name, "-"))
+ break;
+ if (!strequal(attr_name, mod.attrib.name)) {
+ DEBUG(3, ("attrib name %s does not "
+ "match %s\n", attr_name,
+ mod.attrib.name));
+ return False;
+ }
+ if (!add_value_to_attrib(msg->mem_ctx, &value,
+ &mod.attrib)) {
+ DEBUG(3, ("Could not add value\n"));
+ return False;
+ }
+ }
+
+ if (!add_mod_to_array_talloc(msg->mem_ctx, &mod, &r->mods,
+ &r->num_mods))
+ return False;
+ }
+
+ return True;
+}
+
+/*
+ read from a LDIF source, creating a ldap_message
+*/
+static struct ldap_message *ldif_read(int (*fgetc_fn)(void *),
+ void *private_data)
+{
+ struct ldap_message *msg;
+ const char *attr=NULL;
+ const char *dn;
+ char *chunk=NULL, *s;
+ struct ldap_val value;
+
+ value.data = NULL;
+
+ msg = new_ldap_message();
+ if (msg == NULL)
+ return NULL;
+
+ chunk = next_chunk(msg->mem_ctx, fgetc_fn, private_data);
+ if (!chunk) {
+ goto failed;
+ }
+
+ s = chunk;
+
+ if (next_attr(&s, &attr, &value) != 0) {
+ goto failed;
+ }
+
+ /* first line must be a dn */
+ if (!strequal(attr, "dn")) {
+ DEBUG(5, ("Error: First line of ldif must be a dn not '%s'\n",
+ attr));
+ goto failed;
+ }
+
+ dn = talloc_strdup(msg->mem_ctx, value.data);
+
+ if (next_attr(&s, &attr, &value) != 0) {
+ goto failed;
+ }
+
+ if (!strequal(attr, "changetype")) {
+ DEBUG(5, ("Error: Second line of ldif must be a changetype "
+ "not '%s'\n", attr));
+ goto failed;
+ }
+
+ if (strequal(value.data, "delete")) {
+ msg->type = LDAP_TAG_DelRequest;
+ msg->r.DelRequest.dn = dn;
+ return msg;
+ }
+
+ if (strequal(value.data, "add")) {
+ msg->type = LDAP_TAG_AddRequest;
+
+ msg->r.AddRequest.dn = dn;
+
+ if (!fill_add_attributes(msg, &s))
+ goto failed;
+
+ return msg;
+ }
+
+ if (strequal(value.data, "modify")) {
+ msg->type = LDAP_TAG_ModifyRequest;
+
+ msg->r.ModifyRequest.dn = dn;
+
+ if (!fill_mods(msg, &s))
+ goto failed;
+
+ return msg;
+ }
+
+ DEBUG(3, ("changetype %s not supported\n", (char *)value.data));
+
+failed:
+ destroy_ldap_message(msg);
+ return NULL;
+}
+
+/*
+ a wrapper around ldif_read() for reading from const char*
+*/
+struct ldif_read_string_state {
+ const char *s;
+};
+
+static int fgetc_string(void *private_data)
+{
+ struct ldif_read_string_state *state = private_data;
+ if (state->s[0] != 0) {
+ return *state->s++;
+ }
+ return EOF;
+}
+
+struct ldap_message *ldap_ldif2msg(const char *s)
+{
+ struct ldif_read_string_state state;
+ state.s = s;
+ return ldif_read(fgetc_string, &state);
+}
+