root/source3/lib/ldb/common/ldb_msg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ldb_msg_new
  2. ldb_msg_find_element
  3. ldb_val_equal_exact
  4. ldb_msg_find_val
  5. ldb_val_dup
  6. ldb_msg_add_empty
  7. ldb_msg_add
  8. ldb_msg_add_value
  9. ldb_msg_add_steal_value
  10. ldb_msg_add_string
  11. ldb_msg_add_steal_string
  12. ldb_msg_add_fmt
  13. ldb_msg_element_compare
  14. ldb_msg_element_compare_name
  15. ldb_msg_find_ldb_val
  16. ldb_msg_find_attr_as_int
  17. ldb_msg_find_attr_as_uint
  18. ldb_msg_find_attr_as_int64
  19. ldb_msg_find_attr_as_uint64
  20. ldb_msg_find_attr_as_double
  21. ldb_msg_find_attr_as_bool
  22. ldb_msg_find_attr_as_string
  23. ldb_msg_find_attr_as_dn
  24. ldb_msg_sort_elements
  25. ldb_msg_copy_shallow
  26. ldb_msg_copy
  27. ldb_msg_canonicalize
  28. ldb_msg_diff
  29. ldb_msg_sanity_check
  30. ldb_attr_list_copy
  31. ldb_attr_list_copy_add
  32. ldb_attr_in_list
  33. ldb_msg_rename_attr
  34. ldb_msg_copy_attr
  35. ldb_msg_remove_attr
  36. ldb_msg_remove_element
  37. ldb_timestring
  38. ldb_string_to_time
  39. ldb_dump_results
  40. ldb_msg_check_string_attribute

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

/* [<][>][^][v][top][bottom][index][help] */