diff options
Diffstat (limited to 'source4/libcli/ldap')
-rw-r--r-- | source4/libcli/ldap/config.mk | 3 | ||||
-rw-r--r-- | source4/libcli/ldap/ldap.c | 411 | ||||
-rw-r--r-- | source4/libcli/ldap/ldap.h | 29 | ||||
-rw-r--r-- | source4/libcli/ldap/ldap_ldif.c | 409 |
4 files changed, 440 insertions, 412 deletions
diff --git a/source4/libcli/ldap/config.mk b/source4/libcli/ldap/config.mk index 397cfe0b72..ac047214ca 100644 --- a/source4/libcli/ldap/config.mk +++ b/source4/libcli/ldap/config.mk @@ -1,6 +1,7 @@ ################################# # Start SUBSYSTEM LIBCLI_LDAP [SUBSYSTEM::LIBCLI_LDAP] -ADD_OBJ_FILES = libcli/ldap/ldap.o +ADD_OBJ_FILES = libcli/ldap/ldap.o \ + libcli/ldap/ldap_ldif.o # End SUBSYSTEM LIBCLI_LDAP ################################# diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c index b319299b1e..123def9416 100644 --- a/source4/libcli/ldap/ldap.c +++ b/source4/libcli/ldap/ldap.c @@ -33,35 +33,6 @@ * ***************************************************************************/ -/* Hmm. A blob might be more appropriate here :-) */ - -struct ldap_val { - unsigned int length; - void *data; -}; - -enum ldap_parse_op {LDAP_OP_SIMPLE, LDAP_OP_AND, LDAP_OP_OR, LDAP_OP_NOT}; - -struct ldap_parse_tree { - enum ldap_parse_op operation; - union { - struct { - char *attr; - struct ldap_val value; - } simple; - struct { - unsigned int num_elements; - struct ldap_parse_tree **elements; - } list; - struct { - struct ldap_parse_tree *child; - } not; - } u; -}; - -#define LDAP_ALL_SEP "()&|=!" -#define LDAP_CONNECTION_TIMEOUT 10000 - /* return next token element. Caller frees */ @@ -379,372 +350,6 @@ static BOOL ldap_push_filter(ASN1_DATA *data, struct ldap_parse_tree *tree) return !data->has_error; } -/**************************************************************************** - * - * LDIF parser - * - * Shamelessly stolen and adapted from Samba 4. - * - ***************************************************************************/ - -/* - 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; -} - -static 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; -} - -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; -} - -static 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); -} - static void ldap_encode_response(enum ldap_request_tag tag, struct ldap_Result *result, ASN1_DATA *data) @@ -1072,22 +677,6 @@ static void ldap_decode_response(TALLOC_CTX *mem_ctx, asn1_end_tag(data); } -static 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 ldap_decode_filter(TALLOC_CTX *mem_ctx, ASN1_DATA *data, char **filter) { diff --git a/source4/libcli/ldap/ldap.h b/source4/libcli/ldap/ldap.h index da844afa3e..449be9e015 100644 --- a/source4/libcli/ldap/ldap.h +++ b/source4/libcli/ldap/ldap.h @@ -254,4 +254,33 @@ struct ldap_connection { struct gensec_security *gensec; }; +/* Hmm. A blob might be more appropriate here :-) */ + +struct ldap_val { + unsigned int length; + void *data; +}; + +enum ldap_parse_op {LDAP_OP_SIMPLE, LDAP_OP_AND, LDAP_OP_OR, LDAP_OP_NOT}; + +struct ldap_parse_tree { + enum ldap_parse_op operation; + union { + struct { + char *attr; + struct ldap_val value; + } simple; + struct { + unsigned int num_elements; + struct ldap_parse_tree **elements; + } list; + struct { + struct ldap_parse_tree *child; + } not; + } u; +}; + +#define LDAP_ALL_SEP "()&|=!" +#define LDAP_CONNECTION_TIMEOUT 10000 + #endif 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); +} + |