r502: modified ldb to allow the use of an external pool memory
[kai/samba.git] / source / lib / ldb / common / ldb_ldif.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library 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 GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldif routines
29  *
30  *  Description: ldif pack/unpack routines
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 /*
36   see RFC2849 for the LDIF format definition
37 */
38
39 #include "includes.h"
40
41
42 /*
43   this base64 decoder was taken from jitterbug (written by tridge).
44   we might need to replace it with a new version
45 */
46 static int base64_decode(char *s)
47 {
48         const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
49         int bit_offset, byte_offset, idx, i, n;
50         unsigned char *d = (unsigned char *)s;
51         char *p;
52
53         n=i=0;
54
55         while (*s && (p=strchr(b64,*s))) {
56                 idx = (int)(p - b64);
57                 byte_offset = (i*6)/8;
58                 bit_offset = (i*6)%8;
59                 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
60                 if (bit_offset < 3) {
61                         d[byte_offset] |= (idx << (2-bit_offset));
62                         n = byte_offset+1;
63                 } else {
64                         d[byte_offset] |= (idx >> (bit_offset-2));
65                         d[byte_offset+1] = 0;
66                         d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
67                         n = byte_offset+2;
68                 }
69                 s++; i++;
70         }
71
72         if (*s && !p) {
73                 /* the only termination allowed */
74                 if (*s != '=') {
75                         return -1;
76                 }
77         }
78
79         /* null terminate */
80         d[n] = 0;
81         return n;
82 }
83
84
85 /*
86   encode as base64
87   caller frees
88 */
89 char *ldb_base64_encode(struct ldb_context *ldb, const char *buf, int len)
90 {
91         const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
92         int bit_offset, byte_offset, idx, i;
93         const unsigned char *d = (const unsigned char *)buf;
94         int bytes = (len*8 + 5)/6;
95         char *out;
96
97         out = ldb_malloc(ldb, bytes+2);
98         if (!out) return NULL;
99
100         for (i=0;i<bytes;i++) {
101                 byte_offset = (i*6)/8;
102                 bit_offset = (i*6)%8;
103                 if (bit_offset < 3) {
104                         idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
105                 } else {
106                         idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
107                         if (byte_offset+1 < len) {
108                                 idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
109                         }
110                 }
111                 out[i] = b64[idx];
112         }
113
114         out[i++] = '=';
115         out[i] = 0;
116
117         return out;
118 }
119
120 /*
121   see if a buffer should be base64 encoded
122 */
123 int ldb_should_b64_encode(const struct ldb_val *val)
124 {
125         int i;
126         unsigned char *p = val->data;
127
128         if (val->length == 0 || p[0] == ' ' || p[0] == ':') {
129                 return 1;
130         }
131
132         for (i=0; i<val->length; i++) {
133                 if (!isprint(p[i]) || p[i] == '\n') {
134                         return 1;
135                 }
136         }
137         return 0;
138 }
139
140 /* this macro is used to handle the return checking on fprintf_fn() */
141 #define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
142
143 /*
144   write a line folded string onto a file
145 */
146 static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data,
147                         const char *buf, size_t length, int start_pos)
148 {
149         int i;
150         int total=0, ret;
151
152         for (i=0;i<length;i++) {
153                 ret = fprintf_fn(private_data, "%c", buf[i]);
154                 CHECK_RET;
155                 if (i != (length-1) && (i + start_pos) % 77 == 0) {
156                         ret = fprintf_fn(private_data, "\n ");
157                         CHECK_RET;
158                 }
159         }
160
161         return total;
162 }
163
164 /*
165   encode as base64 to a file
166 */
167 static int base64_encode_f(struct ldb_context *ldb,
168                            int (*fprintf_fn)(void *, const char *, ...), 
169                            void *private_data,
170                            const char *buf, int len, int start_pos)
171 {
172         char *b = ldb_base64_encode(ldb, buf, len);
173         int ret;
174
175         if (!b) {
176                 return -1;
177         }
178
179         ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
180
181         ldb_free(ldb, b);
182         return ret;
183 }
184
185
186 static const struct {
187         const char *name;
188         enum ldb_changetype changetype;
189 } ldb_changetypes[] = {
190         {"add",    LDB_CHANGETYPE_ADD},
191         {"delete", LDB_CHANGETYPE_DELETE},
192         {"modify", LDB_CHANGETYPE_MODIFY},
193         {NULL, 0}
194 };
195
196 /*
197   write to ldif, using a caller supplied write method
198 */
199 int ldif_write(struct ldb_context *ldb,
200                int (*fprintf_fn)(void *, const char *, ...), 
201                void *private_data,
202                const struct ldb_ldif *ldif)
203 {
204         int i, j;
205         int total=0, ret;
206         const struct ldb_message *msg;
207
208         msg = &ldif->msg;
209
210         ret = fprintf_fn(private_data, "dn: %s\n", msg->dn);
211         CHECK_RET;
212
213         if (ldif->changetype != LDB_CHANGETYPE_NONE) {
214                 for (i=0;ldb_changetypes[i].name;i++) {
215                         if (ldb_changetypes[i].changetype == ldif->changetype) {
216                                 break;
217                         }
218                 }
219                 if (!ldb_changetypes[i].name) {
220                         fprintf(stderr,"Invalid changetype\n");
221                         return -1;
222                 }
223                 ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name);
224                 CHECK_RET;
225         }
226
227         for (i=0;i<msg->num_elements;i++) {
228                 if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
229                         switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
230                         case LDB_FLAG_MOD_ADD:
231                                 fprintf_fn(private_data, "add: %s\n", 
232                                            msg->elements[i].name);
233                                 break;
234                         case LDB_FLAG_MOD_DELETE:
235                                 fprintf_fn(private_data, "delete: %s\n", 
236                                            msg->elements[i].name);
237                                 break;
238                         case LDB_FLAG_MOD_REPLACE:
239                                 fprintf_fn(private_data, "replace: %s\n", 
240                                            msg->elements[i].name);
241                                 break;
242                         }
243                 }
244
245                 for (j=0;j<msg->elements[i].num_values;j++) {
246                         if (ldb_should_b64_encode(&msg->elements[i].values[j])) {
247                                 ret = fprintf_fn(private_data, "%s:: ", 
248                                                  msg->elements[i].name);
249                                 CHECK_RET;
250                                 ret = base64_encode_f(ldb, fprintf_fn, private_data, 
251                                                       msg->elements[i].values[j].data, 
252                                                       msg->elements[i].values[j].length,
253                                                       strlen(msg->elements[i].name)+3);
254                                 CHECK_RET;
255                                 ret = fprintf_fn(private_data, "\n");
256                                 CHECK_RET;
257                         } else {
258                                 ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
259                                 CHECK_RET;
260                                 ret = fold_string(fprintf_fn, private_data,
261                                                   msg->elements[i].values[j].data,
262                                                   msg->elements[i].values[j].length,
263                                                   strlen(msg->elements[i].name)+2);
264                                 CHECK_RET;
265                                 ret = fprintf_fn(private_data, "\n");
266                                 CHECK_RET;
267                         }
268                 }
269                 if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
270                         fprintf_fn(private_data, "-\n");
271                 }
272         }
273         ret = fprintf_fn(private_data,"\n");
274         CHECK_RET;
275
276         return total;
277 }
278
279 #undef CHECK_RET
280
281
282 /*
283   pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
284   this routine removes any RFC2849 continuations and comments
285
286   caller frees
287 */
288 static char *next_chunk(struct ldb_context *ldb, 
289                         int (*fgetc_fn)(void *), void *private_data)
290 {
291         size_t alloc_size=0, chunk_size = 0;
292         char *chunk = NULL;
293         int c;
294         int in_comment = 0;
295
296         while ((c = fgetc_fn(private_data)) != EOF) {
297                 if (chunk_size+1 >= alloc_size) {
298                         char *c2;
299                         alloc_size += 1024;
300                         c2 = ldb_realloc_p(ldb, chunk, char, alloc_size);
301                         if (!c2) {
302                                 ldb_free(ldb, chunk);
303                                 errno = ENOMEM;
304                                 return NULL;
305                         }
306                         chunk = c2;
307                 }
308
309                 if (in_comment) {
310                         if (c == '\n') {
311                                 in_comment = 0;
312                         }
313                         continue;                       
314                 }
315                 
316                 /* handle continuation lines - see RFC2849 */
317                 if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
318                         chunk_size--;
319                         continue;
320                 }
321                 
322                 /* chunks are terminated by a double line-feed */
323                 if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
324                         chunk[chunk_size-1] = 0;
325                         return chunk;
326                 }
327
328                 if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
329                         in_comment = 1;
330                         continue;
331                 }
332
333                 /* ignore leading blank lines */
334                 if (chunk_size == 0 && c == '\n') {
335                         continue;
336                 }
337
338                 chunk[chunk_size++] = c;
339         }
340
341         if (chunk) {
342                 chunk[chunk_size] = 0;
343         }
344
345         return chunk;
346 }
347
348
349 /* simple ldif attribute parser */
350 static int next_attr(char **s, const char **attr, struct ldb_val *value)
351 {
352         char *p;
353         int base64_encoded = 0;
354
355         if (strncmp(*s, "-\n", 2) == 0) {
356                 value->length = 0;
357                 *attr = "-";
358                 *s += 2;
359                 return 0;
360         }
361
362         p = strchr(*s, ':');
363         if (!p) {
364                 return -1;
365         }
366
367         *p++ = 0;
368
369         if (*p == ':') {
370                 base64_encoded = 1;
371                 p++;
372         }
373
374         *attr = *s;
375
376         while (isspace(*p)) {
377                 p++;
378         }
379
380         value->data = p;
381
382         p = strchr(p, '\n');
383
384         if (!p) {
385                 value->length = strlen((char *)value->data);
386                 *s = ((char *)value->data) + value->length;
387         } else {
388                 value->length = p - (char *)value->data;
389                 *s = p+1;
390                 *p = 0;
391         }
392
393         if (base64_encoded) {
394                 int len = base64_decode(value->data);
395                 if (len == -1) {
396                         /* it wasn't valid base64 data */
397                         return -1;
398                 }
399                 value->length = len;
400         }
401
402         return 0;
403 }
404
405
406 /*
407   free a message from a ldif_read
408 */
409 void ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
410 {
411         struct ldb_message *msg = &ldif->msg;
412         int i;
413         for (i=0;i<msg->num_elements;i++) {
414                 if (msg->elements[i].name) ldb_free(ldb, msg->elements[i].name);
415                 if (msg->elements[i].values) ldb_free(ldb, msg->elements[i].values);
416         }
417         if (msg->elements) ldb_free(ldb, msg->elements);
418         if (msg->private_data) ldb_free(ldb, msg->private_data);
419         ldb_free(ldb, ldif);
420 }
421
422 /*
423   add an empty element
424 */
425 static int msg_add_empty(struct ldb_context *ldb,
426                          struct ldb_message *msg, const char *name, unsigned flags)
427 {
428         struct ldb_message_element *el2, *el;
429
430         el2 = ldb_realloc_p(ldb, msg->elements, 
431                             struct ldb_message_element, msg->num_elements+1);
432         if (!el2) {
433                 errno = ENOMEM;
434                 return -1;
435         }
436         
437         msg->elements = el2;
438
439         el = &msg->elements[msg->num_elements];
440         
441         el->name = ldb_strdup(ldb, name);
442         el->num_values = 0;
443         el->values = NULL;
444         el->flags = flags;
445
446         if (!el->name) {
447                 errno = ENOMEM;
448                 return -1;
449         }
450
451         msg->num_elements++;
452
453         return 0;
454 }
455
456 /*
457  read from a LDIF source, creating a ldb_message
458 */
459 struct ldb_ldif *ldif_read(struct ldb_context *ldb,
460                            int (*fgetc_fn)(void *), void *private_data)
461 {
462         struct ldb_ldif *ldif;
463         struct ldb_message *msg;
464         const char *attr=NULL;
465         char *chunk=NULL, *s;
466         struct ldb_val value;
467         unsigned flags = 0;
468
469         value.data = NULL;
470
471         ldif = ldb_malloc_p(ldb, struct ldb_ldif);
472         if (!ldif) return NULL;
473
474         ldif->changetype = LDB_CHANGETYPE_NONE;
475         msg = &ldif->msg;
476
477         msg->dn = NULL;
478         msg->elements = NULL;
479         msg->num_elements = 0;
480         msg->private_data = NULL;
481
482         chunk = next_chunk(ldb, fgetc_fn, private_data);
483         if (!chunk) {
484                 goto failed;
485         }
486
487         msg->private_data = chunk;
488         s = chunk;
489
490         if (next_attr(&s, &attr, &value) != 0) {
491                 goto failed;
492         }
493         
494         /* first line must be a dn */
495         if (ldb_attr_cmp(attr, "dn") != 0) {
496                 fprintf(stderr, "First line must be a dn not '%s'\n", attr);
497                 goto failed;
498         }
499
500         msg->dn = value.data;
501
502         while (next_attr(&s, &attr, &value) == 0) {
503                 struct ldb_message_element *el;
504                 int empty = 0;
505
506                 if (ldb_attr_cmp(attr, "changetype") == 0) {
507                         int i;
508                         for (i=0;ldb_changetypes[i].name;i++) {
509                                 if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) {
510                                         ldif->changetype = ldb_changetypes[i].changetype;
511                                         break;
512                                 }
513                         }
514                         if (!ldb_changetypes[i].name) {
515                                 fprintf(stderr,"Bad changetype '%s'\n",
516                                         (char *)value.data);
517                         }
518                         flags = 0;
519                         continue;
520                 }
521
522                 if (ldb_attr_cmp(attr, "add") == 0) {
523                         flags = LDB_FLAG_MOD_ADD;
524                         empty = 1;
525                 }
526                 if (ldb_attr_cmp(attr, "delete") == 0) {
527                         flags = LDB_FLAG_MOD_DELETE;
528                         empty = 1;
529                 }
530                 if (ldb_attr_cmp(attr, "replace") == 0) {
531                         flags = LDB_FLAG_MOD_REPLACE;
532                         empty = 1;
533                 }
534                 if (ldb_attr_cmp(attr, "-") == 0) {
535                         flags = 0;
536                         continue;
537                 }
538
539                 if (empty) {
540                         if (msg_add_empty(ldb, msg, (char *)value.data, flags) != 0) {
541                                 goto failed;
542                         }
543                         continue;
544                 }
545                 
546                 el = &msg->elements[msg->num_elements-1];
547
548                 if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
549                     flags == el->flags) {
550                         /* its a continuation */
551                         el->values = 
552                                 ldb_realloc_p(ldb, el->values, 
553                                               struct ldb_val, el->num_values+1);
554                         if (!el->values) {
555                                 goto failed;
556                         }
557                         el->values[el->num_values] = value;
558                         el->num_values++;
559                 } else {
560                         /* its a new attribute */
561                         msg->elements = ldb_realloc_p(ldb, msg->elements, 
562                                                       struct ldb_message_element, 
563                                                       msg->num_elements+1);
564                         if (!msg->elements) {
565                                 goto failed;
566                         }
567                         el = &msg->elements[msg->num_elements];
568                         el->flags = flags;
569                         el->name = ldb_strdup(ldb, attr);
570                         el->values = ldb_malloc_p(ldb, struct ldb_val);
571                         if (!el->values || !el->name) {
572                                 goto failed;
573                         }
574                         el->num_values = 1;
575                         el->values[0] = value;
576                         msg->num_elements++;
577                 }
578         }
579
580         return ldif;
581
582 failed:
583         if (ldif) ldif_read_free(ldb, ldif);
584         return NULL;
585 }
586
587
588
589 /*
590   a wrapper around ldif_read() for reading from FILE*
591 */
592 struct ldif_read_file_state {
593         FILE *f;
594 };
595
596 static int fgetc_file(void *private_data)
597 {
598         struct ldif_read_file_state *state = private_data;
599         return fgetc(state->f);
600 }
601
602 struct ldb_ldif *ldif_read_file(struct ldb_context *ldb, FILE *f)
603 {
604         struct ldif_read_file_state state;
605         state.f = f;
606         return ldif_read(ldb, fgetc_file, &state);
607 }
608
609
610 /*
611   a wrapper around ldif_read() for reading from const char*
612 */
613 struct ldif_read_string_state {
614         const char *s;
615 };
616
617 static int fgetc_string(void *private_data)
618 {
619         struct ldif_read_string_state *state = private_data;
620         if (state->s[0] != 0) {
621                 return *state->s++;
622         }
623         return EOF;
624 }
625
626 struct ldb_ldif *ldif_read_string(struct ldb_context *ldb, const char *s)
627 {
628         struct ldif_read_string_state state;
629         state.s = s;
630         return ldif_read(ldb, fgetc_string, &state);
631 }
632
633
634 /*
635   wrapper around ldif_write() for a file
636 */
637 struct ldif_write_file_state {
638         FILE *f;
639 };
640
641 static int fprintf_file(void *private_data, const char *fmt, ...)
642 {
643         struct ldif_write_file_state *state = private_data;
644         int ret;
645         va_list ap;
646
647         va_start(ap, fmt);
648         ret = vfprintf(state->f, fmt, ap);
649         va_end(ap);
650         return ret;
651 }
652
653 int ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif)
654 {
655         struct ldif_write_file_state state;
656         state.f = f;
657         return ldif_write(ldb, fprintf_file, &state, ldif);
658 }