2 Unix SMB/CIFS mplementation.
3 LDAP protocol helper functions for SAMBA
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Simo Sorce 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "system/iconv.h"
28 #include "libcli/ldap/ldap.h"
30 /****************************************************************************
34 * Shamelessly stolen and adapted from ldb.
36 ***************************************************************************/
39 pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
40 this routine removes any RFC2849 continuations and comments
44 static char *next_chunk(TALLOC_CTX *mem_ctx,
45 int (*fgetc_fn)(void *), void *private_data)
47 size_t alloc_size=0, chunk_size = 0;
52 while ((c = fgetc_fn(private_data)) != EOF) {
53 if (chunk_size+1 >= alloc_size) {
56 c2 = talloc_realloc(mem_ctx, chunk, char, alloc_size);
71 /* handle continuation lines - see RFC2849 */
72 if (c == ' ' && chunk_size > 1 &&
73 chunk[chunk_size-1] == '\n') {
78 /* chunks are terminated by a double line-feed */
79 if (c == '\n' && chunk_size > 0 &&
80 chunk[chunk_size-1] == '\n') {
81 chunk[chunk_size-1] = 0;
86 (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
91 /* ignore leading blank lines */
92 if (chunk_size == 0 && c == '\n') {
96 chunk[chunk_size++] = c;
100 chunk[chunk_size] = 0;
106 /* simple ldif attribute parser */
107 static int next_attr(char **s, const char **attr, struct ldap_val *value)
110 int base64_encoded = 0;
112 if (strncmp(*s, "-\n", 2) == 0) {
133 while (isspace(*p)) {
142 value->length = strlen((char *)value->data);
143 *s = ((char *)value->data) + value->length;
145 value->length = p - (char *)value->data;
150 if (base64_encoded) {
151 DATA_BLOB blob = base64_decode_data_blob(value->data);
152 memcpy(value->data, blob.data, blob.length);
153 value->length = blob.length;
154 ((char *)value->data)[value->length] = '\0';
160 BOOL add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldap_val *value,
161 struct ldap_attribute *attrib)
163 attrib->values = talloc_realloc(mem_ctx,
166 attrib->num_values+1);
167 if (attrib->values == NULL)
170 attrib->values[attrib->num_values] =
171 data_blob_talloc(mem_ctx, value->data, value->length);
172 attrib->num_values += 1;
176 BOOL add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
177 const struct ldap_attribute *attrib,
178 struct ldap_attribute **attribs,
181 *attribs = talloc_realloc(mem_ctx,
183 struct ldap_attribute,
186 if (*attribs == NULL)
189 (*attribs)[*num_attribs] = *attrib;
194 static BOOL fill_add_attributes(struct ldap_message *msg, char **chunk)
196 struct ldap_AddRequest *r = &msg->r.AddRequest;
197 const char *attr_name;
198 struct ldap_val value;
200 r->num_attributes = 0;
201 r->attributes = NULL;
203 while (next_attr(chunk, &attr_name, &value) == 0) {
205 struct ldap_attribute *attrib = NULL;
207 for (i=0; i<r->num_attributes; i++) {
208 if (strequal(r->attributes[i].name, attr_name)) {
209 attrib = &r->attributes[i];
214 if (attrib == NULL) {
215 r->attributes = talloc_realloc(msg->mem_ctx,
217 struct ldap_attribute,
218 r->num_attributes+1);
219 if (r->attributes == NULL)
222 attrib = &(r->attributes[r->num_attributes]);
223 r->num_attributes += 1;
224 ZERO_STRUCTP(attrib);
225 attrib->name = talloc_strdup(msg->mem_ctx,
229 if (!add_value_to_attrib(msg->mem_ctx, &value, attrib))
235 BOOL add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
236 struct ldap_mod *mod,
237 struct ldap_mod **mods,
240 *mods = talloc_realloc(mem_ctx, *mods, struct ldap_mod, (*num_mods)+1);
245 (*mods)[*num_mods] = *mod;
250 static BOOL fill_mods(struct ldap_message *msg, char **chunk)
252 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
253 const char *attr_name;
254 struct ldap_val value;
259 while (next_attr(chunk, &attr_name, &value) == 0) {
262 mod.type = LDAP_MODIFY_NONE;
264 mod.attrib.name = talloc_strdup(msg->mem_ctx, value.data);
266 if (strequal(attr_name, "add"))
267 mod.type = LDAP_MODIFY_ADD;
269 if (strequal(attr_name, "delete"))
270 mod.type = LDAP_MODIFY_DELETE;
272 if (strequal(attr_name, "replace"))
273 mod.type = LDAP_MODIFY_REPLACE;
275 if (mod.type == LDAP_MODIFY_NONE) {
276 DEBUG(2, ("ldif modification type %s unsupported\n",
281 mod.attrib.num_values = 0;
282 mod.attrib.values = NULL;
284 while (next_attr(chunk, &attr_name, &value) == 0) {
285 if (strequal(attr_name, "-"))
287 if (!strequal(attr_name, mod.attrib.name)) {
288 DEBUG(3, ("attrib name %s does not "
289 "match %s\n", attr_name,
293 if (!add_value_to_attrib(msg->mem_ctx, &value,
295 DEBUG(3, ("Could not add value\n"));
300 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod, &r->mods,
309 read from a LDIF source, creating a ldap_message
311 static struct ldap_message *ldif_read(TALLOC_CTX *mem_ctx, int (*fgetc_fn)(void *),
314 struct ldap_message *msg;
315 const char *attr=NULL;
317 char *chunk=NULL, *s;
318 struct ldap_val value;
322 msg = new_ldap_message(mem_ctx);
326 chunk = next_chunk(msg->mem_ctx, fgetc_fn, private_data);
333 if (next_attr(&s, &attr, &value) != 0) {
337 /* first line must be a dn */
338 if (!strequal(attr, "dn")) {
339 DEBUG(5, ("Error: First line of ldif must be a dn not '%s'\n",
344 dn = talloc_strdup(msg->mem_ctx, value.data);
346 if (next_attr(&s, &attr, &value) != 0) {
350 if (!strequal(attr, "changetype")) {
351 DEBUG(5, ("Error: Second line of ldif must be a changetype "
352 "not '%s'\n", attr));
356 if (strequal(value.data, "delete")) {
357 msg->type = LDAP_TAG_DelRequest;
358 msg->r.DelRequest.dn = dn;
362 if (strequal(value.data, "add")) {
363 msg->type = LDAP_TAG_AddRequest;
365 msg->r.AddRequest.dn = dn;
367 if (!fill_add_attributes(msg, &s))
373 if (strequal(value.data, "modify")) {
374 msg->type = LDAP_TAG_ModifyRequest;
376 msg->r.ModifyRequest.dn = dn;
378 if (!fill_mods(msg, &s))
384 DEBUG(3, ("changetype %s not supported\n", (char *)value.data));
392 a wrapper around ldif_read() for reading from const char*
394 struct ldif_read_string_state {
398 static int fgetc_string(void *private_data)
400 struct ldif_read_string_state *state = private_data;
401 if (state->s[0] != 0) {
407 struct ldap_message *ldap_ldif2msg(TALLOC_CTX *mem_ctx, const char *s)
409 struct ldif_read_string_state state;
411 return ldif_read(mem_ctx, fgetc_string, &state);