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"
29 /****************************************************************************
33 * Shamelessly stolen and adapted from ldb.
35 ***************************************************************************/
38 pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
39 this routine removes any RFC2849 continuations and comments
43 static char *next_chunk(TALLOC_CTX *mem_ctx,
44 int (*fgetc_fn)(void *), void *private_data)
46 size_t alloc_size=0, chunk_size = 0;
51 while ((c = fgetc_fn(private_data)) != EOF) {
52 if (chunk_size+1 >= alloc_size) {
55 c2 = talloc_realloc(mem_ctx, chunk, char, alloc_size);
70 /* handle continuation lines - see RFC2849 */
71 if (c == ' ' && chunk_size > 1 &&
72 chunk[chunk_size-1] == '\n') {
77 /* chunks are terminated by a double line-feed */
78 if (c == '\n' && chunk_size > 0 &&
79 chunk[chunk_size-1] == '\n') {
80 chunk[chunk_size-1] = 0;
85 (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
90 /* ignore leading blank lines */
91 if (chunk_size == 0 && c == '\n') {
95 chunk[chunk_size++] = c;
99 chunk[chunk_size] = 0;
105 /* simple ldif attribute parser */
106 static int next_attr(char **s, const char **attr, struct ldap_val *value)
109 int base64_encoded = 0;
111 if (strncmp(*s, "-\n", 2) == 0) {
132 while (isspace(*p)) {
141 value->length = strlen((char *)value->data);
142 *s = ((char *)value->data) + value->length;
144 value->length = p - (char *)value->data;
149 if (base64_encoded) {
150 DATA_BLOB blob = base64_decode_data_blob(value->data);
151 memcpy(value->data, blob.data, blob.length);
152 value->length = blob.length;
153 ((char *)value->data)[value->length] = '\0';
159 BOOL add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldap_val *value,
160 struct ldap_attribute *attrib)
162 attrib->values = talloc_realloc(mem_ctx,
165 attrib->num_values+1);
166 if (attrib->values == NULL)
169 attrib->values[attrib->num_values] =
170 data_blob_talloc(mem_ctx, value->data, value->length);
171 attrib->num_values += 1;
175 BOOL add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
176 const struct ldap_attribute *attrib,
177 struct ldap_attribute **attribs,
180 *attribs = talloc_realloc(mem_ctx,
182 struct ldap_attribute,
185 if (*attribs == NULL)
188 (*attribs)[*num_attribs] = *attrib;
193 static BOOL fill_add_attributes(struct ldap_message *msg, char **chunk)
195 struct ldap_AddRequest *r = &msg->r.AddRequest;
196 const char *attr_name;
197 struct ldap_val value;
199 r->num_attributes = 0;
200 r->attributes = NULL;
202 while (next_attr(chunk, &attr_name, &value) == 0) {
204 struct ldap_attribute *attrib = NULL;
206 for (i=0; i<r->num_attributes; i++) {
207 if (strequal(r->attributes[i].name, attr_name)) {
208 attrib = &r->attributes[i];
213 if (attrib == NULL) {
214 r->attributes = talloc_realloc(msg->mem_ctx,
216 struct ldap_attribute,
217 r->num_attributes+1);
218 if (r->attributes == NULL)
221 attrib = &(r->attributes[r->num_attributes]);
222 r->num_attributes += 1;
223 ZERO_STRUCTP(attrib);
224 attrib->name = talloc_strdup(msg->mem_ctx,
228 if (!add_value_to_attrib(msg->mem_ctx, &value, attrib))
234 BOOL add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
235 struct ldap_mod *mod,
236 struct ldap_mod **mods,
239 *mods = talloc_realloc(mem_ctx, *mods, struct ldap_mod, (*num_mods)+1);
244 (*mods)[*num_mods] = *mod;
249 static BOOL fill_mods(struct ldap_message *msg, char **chunk)
251 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
252 const char *attr_name;
253 struct ldap_val value;
258 while (next_attr(chunk, &attr_name, &value) == 0) {
261 mod.type = LDAP_MODIFY_NONE;
263 mod.attrib.name = talloc_strdup(msg->mem_ctx, value.data);
265 if (strequal(attr_name, "add"))
266 mod.type = LDAP_MODIFY_ADD;
268 if (strequal(attr_name, "delete"))
269 mod.type = LDAP_MODIFY_DELETE;
271 if (strequal(attr_name, "replace"))
272 mod.type = LDAP_MODIFY_REPLACE;
274 if (mod.type == LDAP_MODIFY_NONE) {
275 DEBUG(2, ("ldif modification type %s unsupported\n",
280 mod.attrib.num_values = 0;
281 mod.attrib.values = NULL;
283 while (next_attr(chunk, &attr_name, &value) == 0) {
284 if (strequal(attr_name, "-"))
286 if (!strequal(attr_name, mod.attrib.name)) {
287 DEBUG(3, ("attrib name %s does not "
288 "match %s\n", attr_name,
292 if (!add_value_to_attrib(msg->mem_ctx, &value,
294 DEBUG(3, ("Could not add value\n"));
299 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod, &r->mods,
308 read from a LDIF source, creating a ldap_message
310 static struct ldap_message *ldif_read(TALLOC_CTX *mem_ctx, int (*fgetc_fn)(void *),
313 struct ldap_message *msg;
314 const char *attr=NULL;
316 char *chunk=NULL, *s;
317 struct ldap_val value;
321 msg = new_ldap_message(mem_ctx);
325 chunk = next_chunk(msg->mem_ctx, fgetc_fn, private_data);
332 if (next_attr(&s, &attr, &value) != 0) {
336 /* first line must be a dn */
337 if (!strequal(attr, "dn")) {
338 DEBUG(5, ("Error: First line of ldif must be a dn not '%s'\n",
343 dn = talloc_strdup(msg->mem_ctx, value.data);
345 if (next_attr(&s, &attr, &value) != 0) {
349 if (!strequal(attr, "changetype")) {
350 DEBUG(5, ("Error: Second line of ldif must be a changetype "
351 "not '%s'\n", attr));
355 if (strequal(value.data, "delete")) {
356 msg->type = LDAP_TAG_DelRequest;
357 msg->r.DelRequest.dn = dn;
361 if (strequal(value.data, "add")) {
362 msg->type = LDAP_TAG_AddRequest;
364 msg->r.AddRequest.dn = dn;
366 if (!fill_add_attributes(msg, &s))
372 if (strequal(value.data, "modify")) {
373 msg->type = LDAP_TAG_ModifyRequest;
375 msg->r.ModifyRequest.dn = dn;
377 if (!fill_mods(msg, &s))
383 DEBUG(3, ("changetype %s not supported\n", (char *)value.data));
391 a wrapper around ldif_read() for reading from const char*
393 struct ldif_read_string_state {
397 static int fgetc_string(void *private_data)
399 struct ldif_read_string_state *state = private_data;
400 if (state->s[0] != 0) {
406 struct ldap_message *ldap_ldif2msg(TALLOC_CTX *mem_ctx, const char *s)
408 struct ldif_read_string_state state;
410 return ldif_read(mem_ctx, fgetc_string, &state);