~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/lib/ldb/common/ldb_msg.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 3 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, see <http://www.gnu.org/licenses/>.
 
22
*/
 
23
 
 
24
/*
 
25
 *  Name: ldb
 
26
 *
 
27
 *  Component: ldb message component utility functions
 
28
 *
 
29
 *  Description: functions for manipulating ldb_message structures
 
30
 *
 
31
 *  Author: Andrew Tridgell
 
32
 */
 
33
 
 
34
#include "ldb_private.h"
 
35
 
 
36
/*
 
37
  create a new ldb_message in a given memory context (NULL for top level)
 
38
*/
 
39
struct ldb_message *ldb_msg_new(void *mem_ctx)
 
40
{
 
41
        return talloc_zero(mem_ctx, struct ldb_message);
 
42
}
 
43
 
 
44
/*
 
45
  find an element in a message by attribute name
 
46
*/
 
47
struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, 
 
48
                                                 const char *attr_name)
 
49
{
 
50
        unsigned int i;
 
51
        for (i=0;i<msg->num_elements;i++) {
 
52
                if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
 
53
                        return &msg->elements[i];
 
54
                }
 
55
        }
 
56
        return NULL;
 
57
}
 
58
 
 
59
/*
 
60
  see if two ldb_val structures contain exactly the same data
 
61
  return 1 for a match, 0 for a mis-match
 
62
*/
 
63
int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
 
64
{
 
65
        if (v1->length != v2->length) return 0;
 
66
 
 
67
        if (v1->length == 0) return 1;
 
68
 
 
69
        if (memcmp(v1->data, v2->data, v1->length) == 0) {
 
70
                return 1;
 
71
        }
 
72
 
 
73
        return 0;
 
74
}
 
75
 
 
76
/*
 
77
  find a value in an element
 
78
  assumes case sensitive comparison
 
79
*/
 
80
struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, 
 
81
                                 struct ldb_val *val)
 
82
{
 
83
        unsigned int i;
 
84
        for (i=0;i<el->num_values;i++) {
 
85
                if (ldb_val_equal_exact(val, &el->values[i])) {
 
86
                        return &el->values[i];
 
87
                }
 
88
        }
 
89
        return NULL;
 
90
}
 
91
 
 
92
/*
 
93
  duplicate a ldb_val structure
 
94
*/
 
95
struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
 
96
{
 
97
        struct ldb_val v2;
 
98
        v2.length = v->length;
 
99
        if (v->data == NULL) {
 
100
                v2.data = NULL;
 
101
                return v2;
 
102
        }
 
103
 
 
104
        /* the +1 is to cope with buggy C library routines like strndup
 
105
           that look one byte beyond */
 
106
        v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
 
107
        if (!v2.data) {
 
108
                v2.length = 0;
 
109
                return v2;
 
110
        }
 
111
 
 
112
        memcpy(v2.data, v->data, v->length);
 
113
        ((char *)v2.data)[v->length] = 0;
 
114
        return v2;
 
115
}
 
116
 
 
117
/*
 
118
  add an empty element to a message
 
119
*/
 
120
int ldb_msg_add_empty(  struct ldb_message *msg,
 
121
                        const char *attr_name,
 
122
                        int flags,
 
123
                        struct ldb_message_element **return_el)
 
124
{
 
125
        struct ldb_message_element *els;
 
126
 
 
127
        els = talloc_realloc(msg, msg->elements, 
 
128
                             struct ldb_message_element, msg->num_elements+1);
 
129
        if (!els) {
 
130
                errno = ENOMEM;
 
131
                return LDB_ERR_OPERATIONS_ERROR;
 
132
        }
 
133
 
 
134
        els[msg->num_elements].values = NULL;
 
135
        els[msg->num_elements].num_values = 0;
 
136
        els[msg->num_elements].flags = flags;
 
137
        els[msg->num_elements].name = talloc_strdup(els, attr_name);
 
138
        if (!els[msg->num_elements].name) {
 
139
                errno = ENOMEM;
 
140
                return LDB_ERR_OPERATIONS_ERROR;
 
141
        }
 
142
 
 
143
        msg->elements = els;
 
144
        msg->num_elements++;
 
145
 
 
146
        if (return_el) {
 
147
                *return_el = &els[msg->num_elements-1];
 
148
        }
 
149
 
 
150
        return LDB_SUCCESS;
 
151
}
 
152
 
 
153
/*
 
154
  add an empty element to a message
 
155
*/
 
156
int ldb_msg_add(struct ldb_message *msg, 
 
157
                const struct ldb_message_element *el, 
 
158
                int flags)
 
159
{
 
160
        /* We have to copy this, just in case *el is a pointer into
 
161
         * what ldb_msg_add_empty() is about to realloc() */
 
162
        struct ldb_message_element el_copy = *el;
 
163
        if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
 
164
                return LDB_ERR_OPERATIONS_ERROR;
 
165
        }
 
166
 
 
167
        msg->elements[msg->num_elements-1] = el_copy;
 
168
        msg->elements[msg->num_elements-1].flags = flags;
 
169
 
 
170
        return LDB_SUCCESS;
 
171
}
 
172
 
 
173
/*
 
174
  add a value to a message
 
175
*/
 
176
int ldb_msg_add_value(struct ldb_message *msg, 
 
177
                      const char *attr_name,
 
178
                      const struct ldb_val *val,
 
179
                      struct ldb_message_element **return_el)
 
180
{
 
181
        struct ldb_message_element *el;
 
182
        struct ldb_val *vals;
 
183
        int ret;
 
184
 
 
185
        el = ldb_msg_find_element(msg, attr_name);
 
186
        if (!el) {
 
187
                ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
 
188
                if (ret != LDB_SUCCESS) {
 
189
                        return ret;
 
190
                }
 
191
        }
 
192
 
 
193
        vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
 
194
        if (!vals) {
 
195
                errno = ENOMEM;
 
196
                return LDB_ERR_OPERATIONS_ERROR;
 
197
        }
 
198
        el->values = vals;
 
199
        el->values[el->num_values] = *val;
 
200
        el->num_values++;
 
201
 
 
202
        if (return_el) {
 
203
                *return_el = el;
 
204
        }
 
205
 
 
206
        return LDB_SUCCESS;
 
207
}
 
208
 
 
209
 
 
210
/*
 
211
  add a value to a message, stealing it into the 'right' place
 
212
*/
 
213
int ldb_msg_add_steal_value(struct ldb_message *msg, 
 
214
                            const char *attr_name,
 
215
                            struct ldb_val *val)
 
216
{
 
217
        int ret;
 
218
        struct ldb_message_element *el;
 
219
 
 
220
        ret = ldb_msg_add_value(msg, attr_name, val, &el);
 
221
        if (ret == LDB_SUCCESS) {
 
222
                talloc_steal(el->values, val->data);
 
223
        }
 
224
        return ret;
 
225
}
 
226
 
 
227
 
 
228
/*
 
229
  add a string element to a message
 
230
*/
 
231
int ldb_msg_add_string(struct ldb_message *msg, 
 
232
                       const char *attr_name, const char *str)
 
233
{
 
234
        struct ldb_val val;
 
235
 
 
236
        val.data = discard_const_p(uint8_t, str);
 
237
        val.length = strlen(str);
 
238
 
 
239
        if (val.length == 0) {
 
240
                /* allow empty strings as non-existant attributes */
 
241
                return LDB_SUCCESS;
 
242
        }
 
243
 
 
244
        return ldb_msg_add_value(msg, attr_name, &val, NULL);
 
245
}
 
246
 
 
247
/*
 
248
  add a string element to a message, stealing it into the 'right' place
 
249
*/
 
250
int ldb_msg_add_steal_string(struct ldb_message *msg, 
 
251
                             const char *attr_name, char *str)
 
252
{
 
253
        struct ldb_val val;
 
254
 
 
255
        val.data = (uint8_t *)str;
 
256
        val.length = strlen(str);
 
257
 
 
258
        return ldb_msg_add_steal_value(msg, attr_name, &val);
 
259
}
 
260
 
 
261
/*
 
262
  add a printf formatted element to a message
 
263
*/
 
264
int ldb_msg_add_fmt(struct ldb_message *msg, 
 
265
                    const char *attr_name, const char *fmt, ...)
 
266
{
 
267
        struct ldb_val val;
 
268
        va_list ap;
 
269
        char *str;
 
270
 
 
271
        va_start(ap, fmt);
 
272
        str = talloc_vasprintf(msg, fmt, ap);
 
273
        va_end(ap);
 
274
 
 
275
        if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
 
276
 
 
277
        val.data   = (uint8_t *)str;
 
278
        val.length = strlen(str);
 
279
 
 
280
        return ldb_msg_add_steal_value(msg, attr_name, &val);
 
281
}
 
282
 
 
283
/*
 
284
  compare two ldb_message_element structures
 
285
  assumes case senistive comparison
 
286
*/
 
287
int ldb_msg_element_compare(struct ldb_message_element *el1, 
 
288
                            struct ldb_message_element *el2)
 
289
{
 
290
        unsigned int i;
 
291
 
 
292
        if (el1->num_values != el2->num_values) {
 
293
                return el1->num_values - el2->num_values;
 
294
        }
 
295
 
 
296
        for (i=0;i<el1->num_values;i++) {
 
297
                if (!ldb_msg_find_val(el2, &el1->values[i])) {
 
298
                        return -1;
 
299
                }
 
300
        }
 
301
 
 
302
        return 0;
 
303
}
 
304
 
 
305
/*
 
306
  compare two ldb_message_element structures
 
307
  comparing by element name
 
308
*/
 
309
int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
 
310
                                 struct ldb_message_element *el2)
 
311
{
 
312
        return ldb_attr_cmp(el1->name, el2->name);
 
313
}
 
314
 
 
315
/*
 
316
  convenience functions to return common types from a message
 
317
  these return the first value if the attribute is multi-valued
 
318
*/
 
319
const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, 
 
320
                                           const char *attr_name)
 
321
{
 
322
        struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
 
323
        if (!el || el->num_values == 0) {
 
324
                return NULL;
 
325
        }
 
326
        return &el->values[0];
 
327
}
 
328
 
 
329
int ldb_msg_find_attr_as_int(const struct ldb_message *msg, 
 
330
                             const char *attr_name,
 
331
                             int default_value)
 
332
{
 
333
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
 
334
        if (!v || !v->data) {
 
335
                return default_value;
 
336
        }
 
337
        return strtol((const char *)v->data, NULL, 0);
 
338
}
 
339
 
 
340
unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, 
 
341
                                       const char *attr_name,
 
342
                                       unsigned int default_value)
 
343
{
 
344
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
 
345
        if (!v || !v->data) {
 
346
                return default_value;
 
347
        }
 
348
        return strtoul((const char *)v->data, NULL, 0);
 
349
}
 
350
 
 
351
int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
 
352
                                   const char *attr_name,
 
353
                                   int64_t default_value)
 
354
{
 
355
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
 
356
        if (!v || !v->data) {
 
357
                return default_value;
 
358
        }
 
359
        return strtoll((const char *)v->data, NULL, 0);
 
360
}
 
361
 
 
362
uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, 
 
363
                                     const char *attr_name,
 
364
                                     uint64_t default_value)
 
365
{
 
366
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
 
367
        if (!v || !v->data) {
 
368
                return default_value;
 
369
        }
 
370
        return strtoull((const char *)v->data, NULL, 0);
 
371
}
 
372
 
 
373
double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
 
374
                                   const char *attr_name,
 
375
                                   double default_value)
 
376
{
 
377
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
 
378
        if (!v || !v->data) {
 
379
                return default_value;
 
380
        }
 
381
        return strtod((const char *)v->data, NULL);
 
382
}
 
383
 
 
384
int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
 
385
                              const char *attr_name,
 
386
                              int default_value)
 
387
{
 
388
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
 
389
        if (!v || !v->data) {
 
390
                return default_value;
 
391
        }
 
392
        if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
 
393
                return 0;
 
394
        }
 
395
        if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
 
396
                return 1;
 
397
        }
 
398
        return default_value;
 
399
}
 
400
 
 
401
const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, 
 
402
                                        const char *attr_name,
 
403
                                        const char *default_value)
 
404
{
 
405
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
 
406
        if (!v || !v->data) {
 
407
                return default_value;
 
408
        }
 
409
        return (const char *)v->data;
 
410
}
 
411
 
 
412
struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
 
413
                                       void *mem_ctx,
 
414
                                       const struct ldb_message *msg,
 
415
                                       const char *attr_name)
 
416
{
 
417
        struct ldb_dn *res_dn;
 
418
        const struct ldb_val *v;
 
419
 
 
420
        v = ldb_msg_find_ldb_val(msg, attr_name);
 
421
        if (!v || !v->data) {
 
422
                return NULL;
 
423
        }
 
424
        res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
 
425
        if ( ! ldb_dn_validate(res_dn)) {
 
426
                talloc_free(res_dn);
 
427
                return NULL;
 
428
        }
 
429
        return res_dn;
 
430
}
 
431
 
 
432
/*
 
433
  sort the elements of a message by name
 
434
*/
 
435
void ldb_msg_sort_elements(struct ldb_message *msg)
 
436
{
 
437
        qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), 
 
438
              (comparison_fn_t)ldb_msg_element_compare_name);
 
439
}
 
440
 
 
441
/*
 
442
  shallow copy a message - copying only the elements array so that the caller
 
443
  can safely add new elements without changing the message
 
444
*/
 
445
struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, 
 
446
                                         const struct ldb_message *msg)
 
447
{
 
448
        struct ldb_message *msg2;
 
449
        int i;
 
450
 
 
451
        msg2 = talloc(mem_ctx, struct ldb_message);
 
452
        if (msg2 == NULL) return NULL;
 
453
 
 
454
        *msg2 = *msg;
 
455
 
 
456
        msg2->elements = talloc_array(msg2, struct ldb_message_element, 
 
457
                                      msg2->num_elements);
 
458
        if (msg2->elements == NULL) goto failed;
 
459
 
 
460
        for (i=0;i<msg2->num_elements;i++) {
 
461
                msg2->elements[i] = msg->elements[i];
 
462
        }
 
463
 
 
464
        return msg2;
 
465
 
 
466
failed:
 
467
        talloc_free(msg2);
 
468
        return NULL;
 
469
}
 
470
 
 
471
 
 
472
/*
 
473
  copy a message, allocating new memory for all parts
 
474
*/
 
475
struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
 
476
                                 const struct ldb_message *msg)
 
477
{
 
478
        struct ldb_message *msg2;
 
479
        int i, j;
 
480
 
 
481
        msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
 
482
        if (msg2 == NULL) return NULL;
 
483
 
 
484
        msg2->dn = ldb_dn_copy(msg2, msg2->dn);
 
485
        if (msg2->dn == NULL) goto failed;
 
486
 
 
487
        for (i=0;i<msg2->num_elements;i++) {
 
488
                struct ldb_message_element *el = &msg2->elements[i];
 
489
                struct ldb_val *values = el->values;
 
490
                el->name = talloc_strdup(msg2->elements, el->name);
 
491
                if (el->name == NULL) goto failed;
 
492
                el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
 
493
                for (j=0;j<el->num_values;j++) {
 
494
                        el->values[j] = ldb_val_dup(el->values, &values[j]);
 
495
                        if (el->values[j].data == NULL && values[j].length != 0) {
 
496
                                goto failed;
 
497
                        }
 
498
                }
 
499
        }
 
500
 
 
501
        return msg2;
 
502
 
 
503
failed:
 
504
        talloc_free(msg2);
 
505
        return NULL;
 
506
}
 
507
 
 
508
 
 
509
/*
 
510
  canonicalise a message, merging elements of the same name
 
511
*/
 
512
struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
 
513
                                         const struct ldb_message *msg)
 
514
{
 
515
        int i;
 
516
        struct ldb_message *msg2;
 
517
 
 
518
        msg2 = ldb_msg_copy(ldb, msg);
 
519
        if (msg2 == NULL) return NULL;
 
520
 
 
521
        ldb_msg_sort_elements(msg2);
 
522
 
 
523
        for (i=1;i<msg2->num_elements;i++) {
 
524
                struct ldb_message_element *el1 = &msg2->elements[i-1];
 
525
                struct ldb_message_element *el2 = &msg2->elements[i];
 
526
                if (ldb_msg_element_compare_name(el1, el2) == 0) {
 
527
                        el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
 
528
                                                       el1->num_values + el2->num_values);
 
529
                        if (el1->values == NULL) {
 
530
                                return NULL;
 
531
                        }
 
532
                        memcpy(el1->values + el1->num_values,
 
533
                               el2->values,
 
534
                               sizeof(struct ldb_val) * el2->num_values);
 
535
                        el1->num_values += el2->num_values;
 
536
                        talloc_free(discard_const_p(char, el2->name));
 
537
                        if (i+1<msg2->num_elements) {
 
538
                                memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
 
539
                                        (msg2->num_elements - (i+1)));
 
540
                        }
 
541
                        msg2->num_elements--;
 
542
                        i--;
 
543
                }
 
544
        }
 
545
 
 
546
        return msg2;
 
547
}
 
548
 
 
549
 
 
550
/*
 
551
  return a ldb_message representing the differences between msg1 and msg2. If you
 
552
  then use this in a ldb_modify() call it can be used to save edits to a message
 
553
*/
 
554
struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
 
555
                                 struct ldb_message *msg1,
 
556
                                 struct ldb_message *msg2)
 
557
{
 
558
        struct ldb_message *mod;
 
559
        struct ldb_message_element *el;
 
560
        unsigned int i;
 
561
 
 
562
        mod = ldb_msg_new(ldb);
 
563
 
 
564
        mod->dn = msg1->dn;
 
565
        mod->num_elements = 0;
 
566
        mod->elements = NULL;
 
567
 
 
568
        msg2 = ldb_msg_canonicalize(ldb, msg2);
 
569
        if (msg2 == NULL) {
 
570
                return NULL;
 
571
        }
 
572
        
 
573
        /* look in msg2 to find elements that need to be added
 
574
           or modified */
 
575
        for (i=0;i<msg2->num_elements;i++) {
 
576
                el = ldb_msg_find_element(msg1, msg2->elements[i].name);
 
577
 
 
578
                if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
 
579
                        continue;
 
580
                }
 
581
 
 
582
                if (ldb_msg_add(mod, 
 
583
                                &msg2->elements[i],
 
584
                                el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
 
585
                        return NULL;
 
586
                }
 
587
        }
 
588
 
 
589
        /* look in msg1 to find elements that need to be deleted */
 
590
        for (i=0;i<msg1->num_elements;i++) {
 
591
                el = ldb_msg_find_element(msg2, msg1->elements[i].name);
 
592
                if (!el) {
 
593
                        if (ldb_msg_add_empty(mod, 
 
594
                                              msg1->elements[i].name,
 
595
                                              LDB_FLAG_MOD_DELETE, NULL) != 0) {
 
596
                                return NULL;
 
597
                        }
 
598
                }
 
599
        }
 
600
 
 
601
        return mod;
 
602
}
 
603
 
 
604
int ldb_msg_sanity_check(struct ldb_context *ldb, 
 
605
                         const struct ldb_message *msg)
 
606
{
 
607
        int i, j;
 
608
 
 
609
        /* basic check on DN */
 
610
        if (msg->dn == NULL) {
 
611
                /* TODO: return also an error string */
 
612
                ldb_set_errstring(ldb, "ldb message lacks a DN!");
 
613
                return LDB_ERR_INVALID_DN_SYNTAX;
 
614
        }
 
615
 
 
616
        /* basic syntax checks */
 
617
        for (i = 0; i < msg->num_elements; i++) {
 
618
                for (j = 0; j < msg->elements[i].num_values; j++) {
 
619
                        if (msg->elements[i].values[j].length == 0) {
 
620
                                TALLOC_CTX *mem_ctx = talloc_new(ldb);
 
621
                                /* an attribute cannot be empty */
 
622
                                /* TODO: return also an error string */
 
623
                                ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
 
624
                                                            msg->elements[i].name, 
 
625
                                                            ldb_dn_get_linearized(msg->dn));
 
626
                                talloc_free(mem_ctx);
 
627
                                return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
 
628
                        }
 
629
                }
 
630
        }
 
631
 
 
632
        return LDB_SUCCESS;
 
633
}
 
634
 
 
635
 
 
636
 
 
637
 
 
638
/*
 
639
  copy an attribute list. This only copies the array, not the elements
 
640
  (ie. the elements are left as the same pointers)
 
641
*/
 
642
const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
 
643
{
 
644
        const char **ret;
 
645
        int i;
 
646
        for (i=0;attrs[i];i++) /* noop */ ;
 
647
        ret = talloc_array(mem_ctx, const char *, i+1);
 
648
        if (ret == NULL) {
 
649
                return NULL;
 
650
        }
 
651
        for (i=0;attrs[i];i++) {
 
652
                ret[i] = attrs[i];
 
653
        }
 
654
        ret[i] = attrs[i];
 
655
        return ret;
 
656
}
 
657
 
 
658
 
 
659
/*
 
660
  copy an attribute list. This only copies the array, not the elements
 
661
  (ie. the elements are left as the same pointers).  The new attribute is added to the list.
 
662
*/
 
663
const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
 
664
{
 
665
        const char **ret;
 
666
        int i;
 
667
        bool found = false;
 
668
        for (i=0;attrs[i];i++) {
 
669
                if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
 
670
                        found = true;
 
671
                }
 
672
        }
 
673
        if (found) {
 
674
                return ldb_attr_list_copy(mem_ctx, attrs);
 
675
        }
 
676
        ret = talloc_array(mem_ctx, const char *, i+2);
 
677
        if (ret == NULL) {
 
678
                return NULL;
 
679
        }
 
680
        for (i=0;attrs[i];i++) {
 
681
                ret[i] = attrs[i];
 
682
        }
 
683
        ret[i] = new_attr;
 
684
        ret[i+1] = NULL;
 
685
        return ret;
 
686
}
 
687
 
 
688
 
 
689
/*
 
690
  return 1 if an attribute is in a list of attributes, or 0 otherwise
 
691
*/
 
692
int ldb_attr_in_list(const char * const *attrs, const char *attr)
 
693
{
 
694
        int i;
 
695
        for (i=0;attrs && attrs[i];i++) {
 
696
                if (ldb_attr_cmp(attrs[i], attr) == 0) {
 
697
                        return 1;
 
698
                }
 
699
        }
 
700
        return 0;
 
701
}
 
702
 
 
703
 
 
704
/*
 
705
  rename the specified attribute in a search result
 
706
*/
 
707
int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
 
708
{
 
709
        struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
 
710
        if (el == NULL) {
 
711
                return LDB_SUCCESS;
 
712
        }
 
713
        el->name = talloc_strdup(msg->elements, replace);
 
714
        if (el->name == NULL) {
 
715
                return LDB_ERR_OPERATIONS_ERROR;
 
716
        }
 
717
        return LDB_SUCCESS;
 
718
}
 
719
 
 
720
 
 
721
/*
 
722
  copy the specified attribute in a search result to a new attribute
 
723
*/
 
724
int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
 
725
{
 
726
        struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
 
727
        if (el == NULL) {
 
728
                return LDB_SUCCESS;
 
729
        }
 
730
        if (ldb_msg_add(msg, el, 0) != 0) {
 
731
                return LDB_ERR_OPERATIONS_ERROR;
 
732
        }
 
733
        return ldb_msg_rename_attr(msg, attr, replace);
 
734
}
 
735
 
 
736
/*
 
737
  remove the specified element in a search result
 
738
*/
 
739
void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
 
740
{
 
741
        int n = (el - msg->elements);
 
742
        if (n != msg->num_elements-1) {
 
743
                memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
 
744
        }
 
745
        msg->num_elements--;
 
746
}
 
747
 
 
748
 
 
749
/*
 
750
  remove the specified attribute in a search result
 
751
*/
 
752
void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
 
753
{
 
754
        struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
 
755
        if (el) {
 
756
                ldb_msg_remove_element(msg, el);
 
757
        }
 
758
}
 
759
 
 
760
/*
 
761
  return a LDAP formatted GeneralizedTime string
 
762
*/
 
763
char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
 
764
{
 
765
        struct tm *tm = gmtime(&t);
 
766
        char *ts;
 
767
        int r;
 
768
 
 
769
        if (!tm) {
 
770
                return NULL;
 
771
        }
 
772
 
 
773
        /* we now excatly how long this string will be */
 
774
        ts = talloc_array(mem_ctx, char, 18);
 
775
 
 
776
        /* formatted like: 20040408072012.0Z */
 
777
        r = snprintf(ts, 18,
 
778
                        "%04u%02u%02u%02u%02u%02u.0Z",
 
779
                        tm->tm_year+1900, tm->tm_mon+1,
 
780
                        tm->tm_mday, tm->tm_hour, tm->tm_min,
 
781
                        tm->tm_sec);
 
782
 
 
783
        if (r != 17) {
 
784
                talloc_free(ts);
 
785
                return NULL;
 
786
        }
 
787
 
 
788
        return ts;
 
789
}
 
790
 
 
791
/*
 
792
  convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
 
793
*/
 
794
time_t ldb_string_to_time(const char *s)
 
795
{
 
796
        struct tm tm;
 
797
        
 
798
        if (s == NULL) return 0;
 
799
        
 
800
        memset(&tm, 0, sizeof(tm));
 
801
        if (sscanf(s, "%04u%02u%02u%02u%02u%02u", 
 
802
                   &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
 
803
                   &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
 
804
                return 0;
 
805
        }
 
806
        tm.tm_year -= 1900;
 
807
        tm.tm_mon -= 1;
 
808
        
 
809
        return timegm(&tm);
 
810
}
 
811
 
 
812
/*
 
813
  return a LDAP formatted UTCTime string
 
814
*/
 
815
char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
 
816
{
 
817
        struct tm *tm = gmtime(&t);
 
818
        char *ts;
 
819
        int r;
 
820
 
 
821
        if (!tm) {
 
822
                return NULL;
 
823
        }
 
824
 
 
825
        /* we now excatly how long this string will be */
 
826
        ts = talloc_array(mem_ctx, char, 14);
 
827
 
 
828
        /* formatted like: 20040408072012.0Z => 040408072012Z */
 
829
        r = snprintf(ts, 14,
 
830
                        "%02u%02u%02u%02u%02u%02uZ",
 
831
                        (tm->tm_year+1900)%100, tm->tm_mon+1,
 
832
                        tm->tm_mday, tm->tm_hour, tm->tm_min,
 
833
                        tm->tm_sec);
 
834
 
 
835
        if (r != 13) {
 
836
                talloc_free(ts);
 
837
                return NULL;
 
838
        }
 
839
 
 
840
        return ts;
 
841
}
 
842
 
 
843
/*
 
844
  convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
 
845
*/
 
846
time_t ldb_string_utc_to_time(const char *s)
 
847
{
 
848
        struct tm tm;
 
849
        
 
850
        if (s == NULL) return 0;
 
851
        
 
852
        memset(&tm, 0, sizeof(tm));
 
853
        if (sscanf(s, "%02u%02u%02u%02u%02u%02u", 
 
854
                   &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
 
855
                   &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
 
856
                return 0;
 
857
        }
 
858
        if (tm.tm_year < 50) {
 
859
                tm.tm_year += 100;
 
860
        }
 
861
        tm.tm_mon -= 1;
 
862
        
 
863
        return timegm(&tm);
 
864
}
 
865
 
 
866
 
 
867
/*
 
868
  dump a set of results to a file. Useful from within gdb
 
869
*/
 
870
void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
 
871
{
 
872
        int i;
 
873
 
 
874
        for (i = 0; i < result->count; i++) {
 
875
                struct ldb_ldif ldif;
 
876
                fprintf(f, "# record %d\n", i+1);
 
877
                ldif.changetype = LDB_CHANGETYPE_NONE;
 
878
                ldif.msg = result->msgs[i];
 
879
                ldb_ldif_write_file(ldb, f, &ldif);
 
880
        }
 
881
}
 
882
 
 
883
int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
 
884
{
 
885
        struct ldb_message_element *el;
 
886
        struct ldb_val val;
 
887
        
 
888
        el = ldb_msg_find_element(msg, name);
 
889
        if (el == NULL)
 
890
                return 0;
 
891
 
 
892
        val.data = discard_const_p(uint8_t, value);
 
893
        val.length = strlen(value);
 
894
 
 
895
        if (ldb_msg_find_val(el, &val))
 
896
                return 1;
 
897
 
 
898
        return 0;
 
899
}