root/source4/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_element
  36. ldb_msg_remove_attr
  37. ldb_timestring
  38. ldb_string_to_time
  39. ldb_timestring_utc
  40. ldb_string_utc_to_time
  41. ldb_dump_results
  42. 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 "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)
     /* [<][>][^][v][top][bottom][index][help] */
  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, 
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
  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, 
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

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