LCOV - code coverage report
Current view: top level - lib/ldb/common - ldb_msg.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 655 795 82.4 %
Date: 2024-02-28 12:06:22 Functions: 65 70 92.9 %

          Line data    Source code
       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   774157842 : struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
      40             : {
      41   774157842 :         return talloc_zero(mem_ctx, struct ldb_message);
      42             : }
      43             : 
      44             : /*
      45             :   find an element in a message by attribute name
      46             : */
      47  6825340100 : struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
      48             :                                                  const char *attr_name)
      49             : {
      50   185966110 :         unsigned int i;
      51 >10281*10^7 :         for (i=0;i<msg->num_elements;i++) {
      52 98707051478 :                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
      53  2714743792 :                         return &msg->elements[i];
      54             :                 }
      55             :         }
      56  3999690835 :         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 mismatch
      62             : */
      63   368624883 : int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
      64             : {
      65   368624883 :         if (v1->length != v2->length) return 0;
      66    59175280 :         if (v1->data == v2->data) return 1;
      67    59073823 :         if (v1->length == 0) return 1;
      68             : 
      69    59073823 :         if (memcmp(v1->data, v2->data, v1->length) == 0) {
      70    35855500 :                 return 1;
      71             :         }
      72             : 
      73    22132677 :         return 0;
      74             : }
      75             : 
      76             : /*
      77             :   find a value in an element
      78             :   assumes case sensitive comparison
      79             : */
      80    28298715 : struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
      81             :                                  struct ldb_val *val)
      82             : {
      83      930794 :         unsigned int i;
      84   347012950 :         for (i=0;i<el->num_values;i++) {
      85   346680246 :                 if (ldb_val_equal_exact(val, &el->values[i])) {
      86    27966011 :                         return &el->values[i];
      87             :                 }
      88             :         }
      89      321811 :         return NULL;
      90             : }
      91             : 
      92             : 
      93     8680054 : static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
      94             : {
      95     8680030 :         if (v1->length != v2->length) {
      96     7277412 :                 return v1->length - v2->length;
      97             :         }
      98     1402642 :         return memcmp(v1->data, v2->data, v1->length);
      99             : }
     100             : 
     101             : 
     102             : /*
     103             :   ldb_msg_find_duplicate_val() will set the **duplicate pointer to the first
     104             :   duplicate value it finds. It does a case sensitive comparison (memcmp).
     105             : 
     106             :   LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown
     107             :   options flag, otherwise LDB_SUCCESS.
     108             : */
     109             : #define LDB_DUP_QUADRATIC_THRESHOLD 10
     110             : 
     111    30936215 : int ldb_msg_find_duplicate_val(struct ldb_context *ldb,
     112             :                                TALLOC_CTX *mem_ctx,
     113             :                                const struct ldb_message_element *el,
     114             :                                struct ldb_val **duplicate,
     115             :                                uint32_t options)
     116             : {
     117     2173167 :         unsigned int i, j;
     118     2173167 :         struct ldb_val *val;
     119             : 
     120    30936215 :         if (options != 0) {
     121           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     122             :         }
     123             : 
     124    30936215 :         *duplicate = NULL;
     125             : 
     126             :         /*
     127             :            If there are not many values, it is best to avoid the talloc
     128             :            overhead and just do a brute force search.
     129             :          */
     130    30936215 :         if (el->num_values < LDB_DUP_QUADRATIC_THRESHOLD) {
     131    64335651 :                 for (j = 0; j < el->num_values; j++) {
     132    33455993 :                         val = &el->values[j];
     133    38359338 :                         for ( i = j + 1; i < el->num_values; i++) {
     134     4903349 :                                 if (ldb_val_equal_exact(val, &el->values[i])) {
     135           4 :                                         *duplicate = val;
     136           4 :                                         return LDB_SUCCESS;
     137             :                                 }
     138             :                         }
     139             :                 }
     140             :         } else {
     141        5677 :                 struct ldb_val *values;
     142       56553 :                 values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
     143       56553 :                 if (values == NULL) {
     144           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     145             :                 }
     146             : 
     147       56553 :                 memcpy(values, el->values,
     148       56553 :                        el->num_values * sizeof(struct ldb_val));
     149       56553 :                 TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
     150     2027153 :                 for (i = 1; i < el->num_values; i++) {
     151     1970601 :                         if (ldb_val_equal_exact(&values[i],
     152     1970601 :                                                 &values[i - 1])) {
     153             :                                 /* find the original location */
     154           3 :                                 for (j = 0; j < el->num_values; j++) {
     155           3 :                                         if (ldb_val_equal_exact(&values[i],
     156           3 :                                                                 &el->values[j])
     157             :                                                 ) {
     158           1 :                                                 *duplicate = &el->values[j];
     159           1 :                                                 break;
     160             :                                         }
     161             :                                 }
     162           1 :                                 talloc_free(values);
     163           1 :                                 if (*duplicate == NULL) {
     164             :                                         /* how we got here, I don't know */
     165           0 :                                         return LDB_ERR_OPERATIONS_ERROR;
     166             :                                 }
     167           1 :                                 return LDB_SUCCESS;
     168             :                         }
     169             :                 }
     170       56552 :                 talloc_free(values);
     171             :         }
     172    28763043 :         return LDB_SUCCESS;
     173             : }
     174             : 
     175             : 
     176             : /*
     177             :   Determine whether the values in an element are also in another element.
     178             : 
     179             :   Without any flags, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS if the elements
     180             :   share values, or LDB_SUCCESS if they don't. In this case, the function
     181             :   simply determines the set intersection and it doesn't matter in which order
     182             :   the elements are provided.
     183             : 
     184             :   With the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, any values in common are
     185             :   removed from the first element and LDB_SUCCESS is returned.
     186             : 
     187             :   LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown option.
     188             :   LDB_ERR_INAPPROPRIATE_MATCHING is returned if the elements differ in name.
     189             : */
     190             : 
     191        5234 : int ldb_msg_find_common_values(struct ldb_context *ldb,
     192             :                                TALLOC_CTX *mem_ctx,
     193             :                                struct ldb_message_element *el,
     194             :                                struct ldb_message_element *el2,
     195             :                                uint32_t options)
     196             : {
     197         482 :         struct ldb_val *values;
     198         482 :         struct ldb_val *values2;
     199         482 :         unsigned int i, j, k, n_values;
     200             : 
     201        5234 :         bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
     202             : 
     203        5234 :         if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
     204           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     205             :         }
     206             : 
     207        5234 :         if (strcmp(el->name, el2->name) != 0) {
     208           1 :                 return LDB_ERR_INAPPROPRIATE_MATCHING;
     209             :         }
     210        5233 :         if (el->num_values == 0 || el2->num_values == 0) {
     211          12 :                 return LDB_SUCCESS;
     212             :         }
     213             :         /*
     214             :            With few values, it is better to do the brute-force search than the
     215             :            clever search involving tallocs, memcpys, sorts, etc.
     216             :         */
     217        5221 :         if (MIN(el->num_values, el2->num_values) == 1 ||
     218         224 :             MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
     219       22779 :                 for (i = 0; i < el2->num_values; i++) {
     220       36170 :                         for (j = 0; j < el->num_values; j++) {
     221       18494 :                                 if (ldb_val_equal_exact(&el->values[j],
     222       18494 :                                                         &el2->values[i])) {
     223          21 :                                         if (! remove_duplicates) {
     224             :                                             return                      \
     225          19 :                                               LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
     226             :                                         }
     227             :                                         /*
     228             :                                           With the remove_duplicates flag, we
     229             :                                           resolve the intersection by removing
     230             :                                           the offending one from el.
     231             :                                         */
     232           2 :                                         el->num_values--;
     233           3 :                                         for (k = j; k < el->num_values; k++) {
     234           1 :                                                 el->values[k] = \
     235           1 :                                                         el->values[k + 1];
     236             :                                         }
     237           2 :                                         j--; /* rewind */
     238             :                                 }
     239             :                         }
     240             :                 }
     241        4604 :                 return LDB_SUCCESS;
     242             :         }
     243             : 
     244         118 :         values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
     245         118 :         if (values == NULL) {
     246           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     247             :         }
     248         118 :         values2 = talloc_array(mem_ctx, struct ldb_val,
     249             :                                     el2->num_values);
     250         118 :         if (values2 == NULL) {
     251           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     252             :         }
     253             : 
     254         118 :         memcpy(values, el->values,
     255         118 :                el->num_values * sizeof(struct ldb_val));
     256         118 :         memcpy(values2, el2->values,
     257         118 :                el2->num_values * sizeof(struct ldb_val));
     258         118 :         TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
     259         118 :         TYPESAFE_QSORT(values2, el2->num_values, ldb_val_cmp);
     260             : 
     261             :         /*
     262             :            el->n_values may diverge from the number of values in the sorted
     263             :            list when the remove_duplicates flag is used.
     264             :         */
     265         118 :         n_values = el->num_values;
     266         118 :         i = 0;
     267         118 :         j = 0;
     268        3634 :         while (i != n_values && j < el2->num_values) {
     269        3520 :                 int ret = ldb_val_cmp(&values[i], &values2[j]);
     270        3520 :                 if (ret < 0) {
     271         845 :                         i++;
     272        2675 :                 } else if (ret > 0) {
     273        2657 :                         j++;
     274             :                 } else {
     275             :                         /* we have a collision */
     276          18 :                         if (! remove_duplicates) {
     277           4 :                                 TALLOC_FREE(values);
     278           4 :                                 TALLOC_FREE(values2);
     279           4 :                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
     280             :                         }
     281             :                         /*
     282             :                            With the remove_duplicates flag we need to find
     283             :                            this in the original list and remove it, which is
     284             :                            inefficient but hopefully rare.
     285             :                         */
     286          23 :                         for (k = 0; k < el->num_values; k++) {
     287          23 :                                 if (ldb_val_equal_exact(&el->values[k],
     288          23 :                                                         &values[i])) {
     289          14 :                                         break;
     290             :                                 }
     291             :                         }
     292          14 :                         el->num_values--;
     293          76 :                         for (; k < el->num_values; k++) {
     294          62 :                                 el->values[k] = el->values[k + 1];
     295             :                         }
     296          14 :                         i++;
     297             :                 }
     298             :         }
     299         114 :         TALLOC_FREE(values);
     300         114 :         TALLOC_FREE(values2);
     301             : 
     302         114 :         return LDB_SUCCESS;
     303             : }
     304             : 
     305             : /*
     306             :   duplicate a ldb_val structure
     307             : */
     308  3127965373 : struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
     309             : {
     310   105159540 :         struct ldb_val v2;
     311  3127965373 :         v2.length = v->length;
     312  3127965373 :         if (v->data == NULL) {
     313      158410 :                 v2.data = NULL;
     314      158410 :                 return v2;
     315             :         }
     316             : 
     317             :         /* the +1 is to cope with buggy C library routines like strndup
     318             :            that look one byte beyond */
     319  3127806963 :         v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
     320  3127806963 :         if (!v2.data) {
     321           0 :                 v2.length = 0;
     322           0 :                 return v2;
     323             :         }
     324             : 
     325  3127806963 :         memcpy(v2.data, v->data, v->length);
     326  3127806963 :         ((char *)v2.data)[v->length] = 0;
     327  3127806963 :         return v2;
     328             : }
     329             : 
     330             : /**
     331             :  * Adds new empty element to msg->elements
     332             :  */
     333   238901814 : static int _ldb_msg_add_el(struct ldb_message *msg,
     334             :                            struct ldb_message_element **return_el)
     335             : {
     336     8093816 :         struct ldb_message_element *els;
     337             : 
     338             :         /*
     339             :          * TODO: Find out a way to assert on input parameters.
     340             :          * msg and return_el must be valid
     341             :          */
     342             : 
     343   238901814 :         els = talloc_realloc(msg, msg->elements,
     344             :                              struct ldb_message_element, msg->num_elements + 1);
     345   238901814 :         if (!els) {
     346           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     347             :         }
     348             : 
     349   238901814 :         els[msg->num_elements] = (struct ldb_message_element) {};
     350             : 
     351   238901814 :         msg->elements = els;
     352   238901814 :         msg->num_elements++;
     353             : 
     354   238901814 :         *return_el = &els[msg->num_elements-1];
     355             : 
     356   238901814 :         return LDB_SUCCESS;
     357             : }
     358             : 
     359             : /**
     360             :  * Add an empty element with a given name to a message
     361             :  */
     362   236853387 : int ldb_msg_add_empty(struct ldb_message *msg,
     363             :                       const char *attr_name,
     364             :                       int flags,
     365             :                       struct ldb_message_element **return_el)
     366             : {
     367     8039616 :         int ret;
     368     8039616 :         struct ldb_message_element *el;
     369             : 
     370   236853387 :         ret = _ldb_msg_add_el(msg, &el);
     371   236853387 :         if (ret != LDB_SUCCESS) {
     372           0 :                 return ret;
     373             :         }
     374             : 
     375             :         /* initialize newly added element */
     376   236853387 :         el->flags = flags;
     377   236853387 :         el->name = talloc_strdup(msg->elements, attr_name);
     378   236853387 :         if (!el->name) {
     379           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     380             :         }
     381             : 
     382   236853387 :         if (return_el) {
     383   235686346 :                 *return_el = el;
     384             :         }
     385             : 
     386   228813771 :         return LDB_SUCCESS;
     387             : }
     388             : 
     389             : /**
     390             :  * Adds an element to a message.
     391             :  *
     392             :  * NOTE: Ownership of ldb_message_element fields
     393             :  *       is NOT transferred. Thus, if *el pointer
     394             :  *       is invalidated for some reason, this will
     395             :  *       corrupt *msg contents also
     396             :  */
     397     2048427 : int ldb_msg_add(struct ldb_message *msg,
     398             :                 const struct ldb_message_element *el,
     399             :                 int flags)
     400             : {
     401       54200 :         int ret;
     402       54200 :         struct ldb_message_element *el_new;
     403             :         /* We have to copy this, just in case *el is a pointer into
     404             :          * what ldb_msg_add_empty() is about to realloc() */
     405     2048427 :         struct ldb_message_element el_copy = *el;
     406             : 
     407     2048427 :         ret = _ldb_msg_add_el(msg, &el_new);
     408     2048427 :         if (ret != LDB_SUCCESS) {
     409           0 :                 return ret;
     410             :         }
     411             : 
     412     2048427 :         el_new->flags      = flags;
     413     2048427 :         el_new->name       = el_copy.name;
     414     2048427 :         el_new->num_values = el_copy.num_values;
     415     2048427 :         el_new->values     = el_copy.values;
     416             : 
     417     2048427 :         return LDB_SUCCESS;
     418             : }
     419             : 
     420             : /*
     421             :  * add a value to a message element
     422             :  */
     423   229742561 : int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
     424             :                               struct ldb_message_element *el,
     425             :                               const struct ldb_val *val)
     426             : {
     427     7473899 :         struct ldb_val *vals;
     428             : 
     429   229742561 :         if (el->flags & LDB_FLAG_INTERNAL_SHARED_VALUES) {
     430             :                 /*
     431             :                  * Another message is using this message element's values array,
     432             :                  * so we don't want to make any modifications to the original
     433             :                  * message, or potentially invalidate its own values by calling
     434             :                  * talloc_realloc(). Make a copy instead.
     435             :                  */
     436          38 :                 el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
     437             : 
     438          38 :                 vals = talloc_array(mem_ctx, struct ldb_val,
     439             :                                     el->num_values + 1);
     440          38 :                 if (vals == NULL) {
     441           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     442             :                 }
     443             : 
     444          38 :                 if (el->values != NULL) {
     445          38 :                         memcpy(vals, el->values, el->num_values * sizeof(struct ldb_val));
     446             :                 }
     447             :         } else {
     448   229742523 :                 vals = talloc_realloc(mem_ctx, el->values, struct ldb_val,
     449             :                                       el->num_values + 1);
     450   229742523 :                 if (vals == NULL) {
     451           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     452             :                 }
     453             :         }
     454   229742561 :         el->values = vals;
     455   229742561 :         el->values[el->num_values] = *val;
     456   229742561 :         el->num_values++;
     457             : 
     458   229742561 :         return LDB_SUCCESS;
     459             : }
     460             : 
     461             : /*
     462             :   add a value to a message
     463             : */
     464   229392492 : int ldb_msg_add_value(struct ldb_message *msg,
     465             :                       const char *attr_name,
     466             :                       const struct ldb_val *val,
     467             :                       struct ldb_message_element **return_el)
     468             : {
     469     7468936 :         struct ldb_message_element *el;
     470     7468936 :         int ret;
     471             : 
     472   229392492 :         el = ldb_msg_find_element(msg, attr_name);
     473   229392492 :         if (!el) {
     474   223522391 :                 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
     475   223522391 :                 if (ret != LDB_SUCCESS) {
     476           0 :                         return ret;
     477             :                 }
     478             :         }
     479             : 
     480   229392492 :         ret = ldb_msg_element_add_value(msg->elements, el, val);
     481   229392492 :         if (ret != LDB_SUCCESS) {
     482           0 :                 return ret;
     483             :         }
     484             : 
     485   229392492 :         if (return_el) {
     486   226838804 :                 *return_el = el;
     487             :         }
     488             : 
     489   221923556 :         return LDB_SUCCESS;
     490             : }
     491             : 
     492             : 
     493             : /*
     494             :   add a value to a message, stealing it into the 'right' place
     495             : */
     496   190953323 : int ldb_msg_add_steal_value(struct ldb_message *msg,
     497             :                             const char *attr_name,
     498             :                             struct ldb_val *val)
     499             : {
     500     5629271 :         int ret;
     501     5629271 :         struct ldb_message_element *el;
     502             : 
     503   190953323 :         ret = ldb_msg_add_value(msg, attr_name, val, &el);
     504   190953323 :         if (ret == LDB_SUCCESS) {
     505   190953323 :                 talloc_steal(el->values, val->data);
     506             :         }
     507   190953323 :         return ret;
     508             : }
     509             : 
     510             : 
     511             : /*
     512             :   add a string element to a message, specifying flags
     513             : */
     514    35328330 : int ldb_msg_add_string_flags(struct ldb_message *msg,
     515             :                              const char *attr_name, const char *str,
     516             :                              int flags)
     517             : {
     518     1619213 :         struct ldb_val val;
     519     1619213 :         int ret;
     520    35328330 :         struct ldb_message_element *el = NULL;
     521             : 
     522    35328330 :         val.data = discard_const_p(uint8_t, str);
     523    35328330 :         val.length = strlen(str);
     524             : 
     525    35328330 :         if (val.length == 0) {
     526             :                 /* allow empty strings as non-existent attributes */
     527         284 :                 return LDB_SUCCESS;
     528             :         }
     529             : 
     530    35328024 :         ret = ldb_msg_add_value(msg, attr_name, &val, &el);
     531    35328024 :         if (ret != LDB_SUCCESS) {
     532           0 :                 return ret;
     533             :         }
     534             : 
     535    35328024 :         if (flags != 0) {
     536       88969 :                 el->flags = flags;
     537             :         }
     538             : 
     539    33708833 :         return LDB_SUCCESS;
     540             : }
     541             : 
     542             : /*
     543             :   add a string element to a message
     544             : */
     545    35239361 : int ldb_msg_add_string(struct ldb_message *msg,
     546             :                        const char *attr_name, const char *str)
     547             : {
     548    35239361 :         return ldb_msg_add_string_flags(msg, attr_name, str, 0);
     549             : }
     550             : 
     551             : /*
     552             :   add a string element to a message, stealing it into the 'right' place
     553             : */
     554   173308362 : int ldb_msg_add_steal_string(struct ldb_message *msg,
     555             :                              const char *attr_name, char *str)
     556             : {
     557     4670196 :         struct ldb_val val;
     558             : 
     559   173308362 :         val.data = (uint8_t *)str;
     560   173308362 :         val.length = strlen(str);
     561             : 
     562   173308362 :         if (val.length == 0) {
     563             :                 /* allow empty strings as non-existent attributes */
     564           0 :                 return LDB_SUCCESS;
     565             :         }
     566             : 
     567   173308362 :         return ldb_msg_add_steal_value(msg, attr_name, &val);
     568             : }
     569             : 
     570             : /*
     571             :   add a DN element to a message
     572             : */
     573        1987 : int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
     574             :                               struct ldb_dn *dn)
     575             : {
     576        1987 :         char *str = ldb_dn_alloc_linearized(msg, dn);
     577             : 
     578        1987 :         if (str == NULL) {
     579             :                 /* we don't want to have unknown DNs added */
     580           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     581             :         }
     582             : 
     583        1987 :         return ldb_msg_add_steal_string(msg, attr_name, str);
     584             : }
     585             : 
     586             : /*
     587             :   add a printf formatted element to a message
     588             : */
     589    10443169 : int ldb_msg_add_fmt(struct ldb_message *msg,
     590             :                     const char *attr_name, const char *fmt, ...)
     591             : {
     592      721039 :         struct ldb_val val;
     593      721039 :         va_list ap;
     594      721039 :         char *str;
     595             : 
     596    10443169 :         va_start(ap, fmt);
     597    10443169 :         str = talloc_vasprintf(msg, fmt, ap);
     598    10443169 :         va_end(ap);
     599             : 
     600    10443169 :         if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
     601             : 
     602    10443169 :         val.data   = (uint8_t *)str;
     603    10443169 :         val.length = strlen(str);
     604             : 
     605    10443169 :         return ldb_msg_add_steal_value(msg, attr_name, &val);
     606             : }
     607             : 
     608      349423 : static int ldb_msg_append_value_impl(struct ldb_message *msg,
     609             :                                      const char *attr_name,
     610             :                                      const struct ldb_val *val,
     611             :                                      int flags,
     612             :                                      struct ldb_message_element **return_el)
     613             : {
     614      349423 :         struct ldb_message_element *el = NULL;
     615        4957 :         int ret;
     616             : 
     617      349423 :         ret = ldb_msg_add_empty(msg, attr_name, flags, &el);
     618      349423 :         if (ret != LDB_SUCCESS) {
     619           0 :                 return ret;
     620             :         }
     621             : 
     622      349423 :         ret = ldb_msg_element_add_value(msg->elements, el, val);
     623      349423 :         if (ret != LDB_SUCCESS) {
     624           0 :                 return ret;
     625             :         }
     626             : 
     627      349423 :         if (return_el != NULL) {
     628        2088 :                 *return_el = el;
     629             :         }
     630             : 
     631      344466 :         return LDB_SUCCESS;
     632             : }
     633             : 
     634             : /*
     635             :   append a value to a message
     636             : */
     637      347335 : int ldb_msg_append_value(struct ldb_message *msg,
     638             :                          const char *attr_name,
     639             :                          const struct ldb_val *val,
     640             :                          int flags)
     641             : {
     642      347335 :         return ldb_msg_append_value_impl(msg, attr_name, val, flags, NULL);
     643             : }
     644             : 
     645             : /*
     646             :   append a value to a message, stealing it into the 'right' place
     647             : */
     648        2088 : int ldb_msg_append_steal_value(struct ldb_message *msg,
     649             :                                const char *attr_name,
     650             :                                struct ldb_val *val,
     651             :                                int flags)
     652             : {
     653         136 :         int ret;
     654        2088 :         struct ldb_message_element *el = NULL;
     655             : 
     656        2088 :         ret = ldb_msg_append_value_impl(msg, attr_name, val, flags, &el);
     657        2088 :         if (ret == LDB_SUCCESS) {
     658        2088 :                 talloc_steal(el->values, val->data);
     659             :         }
     660        2088 :         return ret;
     661             : }
     662             : 
     663             : /*
     664             :   append a string element to a message, stealing it into the 'right' place
     665             : */
     666         981 : int ldb_msg_append_steal_string(struct ldb_message *msg,
     667             :                                 const char *attr_name, char *str,
     668             :                                 int flags)
     669             : {
     670         110 :         struct ldb_val val;
     671             : 
     672         981 :         val.data = (uint8_t *)str;
     673         981 :         val.length = strlen(str);
     674             : 
     675         981 :         if (val.length == 0) {
     676             :                 /* allow empty strings as non-existent attributes */
     677           0 :                 return LDB_SUCCESS;
     678             :         }
     679             : 
     680         981 :         return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
     681             : }
     682             : 
     683             : /*
     684             :   append a string element to a message
     685             : */
     686       88750 : int ldb_msg_append_string(struct ldb_message *msg,
     687             :                           const char *attr_name, const char *str, int flags)
     688             : {
     689         412 :         struct ldb_val val;
     690             : 
     691       88750 :         val.data = discard_const_p(uint8_t, str);
     692       88750 :         val.length = strlen(str);
     693             : 
     694       88750 :         if (val.length == 0) {
     695             :                 /* allow empty strings as non-existent attributes */
     696           0 :                 return LDB_SUCCESS;
     697             :         }
     698             : 
     699       88750 :         return ldb_msg_append_value(msg, attr_name, &val, flags);
     700             : }
     701             : 
     702             : /*
     703             :   append a DN element to a message
     704             : */
     705           2 : int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
     706             :                                  struct ldb_dn *dn, int flags)
     707             : {
     708           2 :         char *str = ldb_dn_alloc_linearized(msg, dn);
     709             : 
     710           2 :         if (str == NULL) {
     711             :                 /* we don't want to have unknown DNs added */
     712           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     713             :         }
     714             : 
     715           2 :         return ldb_msg_append_steal_string(msg, attr_name, str, flags);
     716             : }
     717             : 
     718             : /*
     719             :   append a printf formatted element to a message
     720             : */
     721        1107 : int ldb_msg_append_fmt(struct ldb_message *msg, int flags,
     722             :                        const char *attr_name, const char *fmt, ...)
     723             : {
     724          26 :         struct ldb_val val;
     725          26 :         va_list ap;
     726        1107 :         char *str = NULL;
     727             : 
     728        1107 :         va_start(ap, fmt);
     729        1107 :         str = talloc_vasprintf(msg, fmt, ap);
     730        1107 :         va_end(ap);
     731             : 
     732        1107 :         if (str == NULL) {
     733           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     734             :         }
     735             : 
     736        1107 :         val.data   = (uint8_t *)str;
     737        1107 :         val.length = strlen(str);
     738             : 
     739        1107 :         return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
     740             : }
     741             : 
     742             : /*
     743             :   compare two ldb_message_element structures
     744             :   assumes case sensitive comparison
     745             : */
     746    21636443 : int ldb_msg_element_compare(struct ldb_message_element *el1,
     747             :                             struct ldb_message_element *el2)
     748             : {
     749      727192 :         unsigned int i;
     750             : 
     751    21636443 :         if (el1->num_values != el2->num_values) {
     752         244 :                 return el1->num_values - el2->num_values;
     753             :         }
     754             : 
     755    47920127 :         for (i=0;i<el1->num_values;i++) {
     756    26340388 :                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
     757       54520 :                         return -1;
     758             :                 }
     759             :         }
     760             : 
     761    20854488 :         return 0;
     762             : }
     763             : 
     764             : /*
     765             :   compare two ldb_message_element structures.
     766             :   Different ordering is considered a mismatch
     767             : */
     768    11915619 : bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
     769             :                                    const struct ldb_message_element *el2)
     770             : {
     771      404775 :         unsigned i;
     772    11915619 :         if (el1->num_values != el2->num_values) {
     773     1065308 :                 return false;
     774             :         }
     775    16343431 :         for (i=0;i<el1->num_values;i++) {
     776    11339623 :                 if (ldb_val_equal_exact(&el1->values[i],
     777    11339623 :                                         &el2->values[i]) != 1) {
     778     5645159 :                         return false;
     779             :                 }
     780             :         }
     781     4800377 :         return true;
     782             : }
     783             : 
     784             : /*
     785             :   compare two ldb_message_element structures
     786             :   comparing by element name
     787             : */
     788   253712390 : int ldb_msg_element_compare_name(struct ldb_message_element *el1,
     789             :                                  struct ldb_message_element *el2)
     790             : {
     791   253712390 :         if (el1->name == el2->name) {
     792           0 :                 return 0;
     793             :         }
     794             : 
     795   253712390 :         if (el1->name == NULL) {
     796           0 :                 return -1;
     797             :         }
     798             : 
     799   253712390 :         if (el2->name == NULL) {
     800           0 :                 return 1;
     801             :         }
     802             : 
     803   253712390 :         return ldb_attr_cmp(el1->name, el2->name);
     804             : }
     805             : 
     806     5067267 : void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el)
     807             : {
     808     5067267 :         el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
     809     5067267 : }
     810             : 
     811   209948358 : bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el)
     812             : {
     813   209948358 :         return (el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE) != 0;
     814             : }
     815             : 
     816     1482037 : void ldb_msg_remove_inaccessible(struct ldb_message *msg)
     817             : {
     818         268 :         unsigned i;
     819     1482037 :         unsigned num_del = 0;
     820             : 
     821    10624371 :         for (i = 0; i < msg->num_elements; ++i) {
     822     9142334 :                 if (ldb_msg_element_is_inaccessible(&msg->elements[i])) {
     823     5062535 :                         ++num_del;
     824     4079799 :                 } else if (num_del) {
     825     2954982 :                         msg->elements[i - num_del] = msg->elements[i];
     826             :                 }
     827             :         }
     828             : 
     829     1482037 :         msg->num_elements -= num_del;
     830     1482037 : }
     831             : 
     832             : /*
     833             :   convenience functions to return common types from a message
     834             :   these return the first value if the attribute is multi-valued
     835             : */
     836  3288723573 : const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
     837             :                                            const char *attr_name)
     838             : {
     839  3288723573 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
     840  3288723573 :         if (!el || el->num_values == 0) {
     841  1418741962 :                 return NULL;
     842             :         }
     843  1832717159 :         return &el->values[0];
     844             : }
     845             : 
     846   146629571 : int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
     847             :                              const char *attr_name,
     848             :                              int default_value)
     849             : {
     850   146629571 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     851   146629571 :         char buf[sizeof("-2147483648")] = {};
     852   146629571 :         char *end = NULL;
     853     3239263 :         int ret;
     854             : 
     855   146629571 :         if (!v || !v->data) {
     856     1878668 :                 return default_value;
     857             :         }
     858             : 
     859   144604118 :         if (v->length >= sizeof(buf)) {
     860          66 :                 return default_value;
     861             :         }
     862             : 
     863   144604052 :         memcpy(buf, v->data, v->length);
     864   144604052 :         errno = 0;
     865   144604052 :         ret = (int) strtoll(buf, &end, 10);
     866   144604052 :         if (errno != 0) {
     867           0 :                 return default_value;
     868             :         }
     869   144604052 :         if (end && end[0] != '\0') {
     870           0 :                 return default_value;
     871             :         }
     872   141511574 :         return ret;
     873             : }
     874             : 
     875   587279074 : unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
     876             :                                        const char *attr_name,
     877             :                                        unsigned int default_value)
     878             : {
     879   587279074 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     880   587279074 :         char buf[sizeof("-2147483648")] = {};
     881   587279074 :         char *end = NULL;
     882    14765137 :         unsigned int ret;
     883             : 
     884   587279074 :         if (!v || !v->data) {
     885   285176577 :                 return default_value;
     886             :         }
     887             : 
     888   294657953 :         if (v->length >= sizeof(buf)) {
     889          39 :                 return default_value;
     890             :         }
     891             : 
     892   294657914 :         memcpy(buf, v->data, v->length);
     893   294657914 :         errno = 0;
     894   294657914 :         ret = (unsigned int) strtoll(buf, &end, 10);
     895   294657914 :         if (errno != 0) {
     896           0 :                 errno = 0;
     897           0 :                 ret = (unsigned int) strtoull(buf, &end, 10);
     898           0 :                 if (errno != 0) {
     899           0 :                         return default_value;
     900             :                 }
     901             :         }
     902   294657914 :         if (end && end[0] != '\0') {
     903           0 :                 return default_value;
     904             :         }
     905   287337321 :         return ret;
     906             : }
     907             : 
     908     2474117 : int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
     909             :                                    const char *attr_name,
     910             :                                    int64_t default_value)
     911             : {
     912     2474117 :         int64_t val = 0;
     913     2474117 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     914     2474117 :         int ret = ldb_val_as_int64(v, &val);
     915     2474117 :         return ret ? default_value : val;
     916             : }
     917             : 
     918     2474440 : int ldb_val_as_int64(const struct ldb_val *v, int64_t *val)
     919             : {
     920     2474440 :         char buf[sizeof("-9223372036854775808")] = {};
     921     2474440 :         char *end = NULL;
     922       72116 :         int64_t result;
     923             : 
     924     2474440 :         if (!v || !v->data) {
     925      531604 :                 return LDB_ERR_OPERATIONS_ERROR;
     926             :         }
     927             : 
     928     1927120 :         if (v->length >= sizeof(buf)) {
     929           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     930             :         }
     931             : 
     932     1927120 :         memcpy(buf, v->data, v->length);
     933     1927120 :         errno = 0;
     934     1927120 :         result = (int64_t) strtoll(buf, &end, 10);
     935     1927120 :         if (errno != 0) {
     936           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     937             :         }
     938     1927120 :         if (end && end[0] != '\0') {
     939           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     940             :         }
     941             : 
     942     1927120 :         *val = result;
     943     1927120 :         return LDB_SUCCESS;
     944             : }
     945             : 
     946   244908609 : uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
     947             :                                      const char *attr_name,
     948             :                                      uint64_t default_value)
     949             : {
     950   244908609 :         uint64_t val = 0;
     951   244908609 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     952   244908609 :         int ret = ldb_val_as_uint64(v, &val);
     953   244908609 :         return ret ? default_value : val;
     954             : }
     955             : 
     956   244908609 : int ldb_val_as_uint64(const struct ldb_val *v, uint64_t *val)
     957             : {
     958   244908609 :         char buf[sizeof("-9223372036854775808")] = {};
     959   244908609 :         char *end = NULL;
     960     6816426 :         uint64_t result;
     961             : 
     962   244908609 :         if (!v || !v->data) {
     963   111271868 :                 return LDB_ERR_OPERATIONS_ERROR;
     964             :         }
     965             : 
     966   130797081 :         if (v->length >= sizeof(buf)) {
     967           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     968             :         }
     969             : 
     970   130797081 :         memcpy(buf, v->data, v->length);
     971   130797081 :         errno = 0;
     972   130797081 :         result = (uint64_t) strtoll(buf, &end, 10);
     973   130797081 :         if (errno != 0) {
     974           0 :                 errno = 0;
     975           0 :                 result = (uint64_t) strtoull(buf, &end, 10);
     976           0 :                 if (errno != 0) {
     977           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     978             :                 }
     979             :         }
     980   130797081 :         if (end && end[0] != '\0') {
     981           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     982             :         }
     983             : 
     984   130797081 :         *val = result;
     985   130797081 :         return LDB_SUCCESS;
     986             : }
     987             : 
     988           0 : double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
     989             :                                    const char *attr_name,
     990             :                                    double default_value)
     991             : {
     992           0 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     993           0 :         char *buf;
     994           0 :         char *end = NULL;
     995           0 :         double ret;
     996             : 
     997           0 :         if (!v || !v->data) {
     998           0 :                 return default_value;
     999             :         }
    1000           0 :         buf = talloc_strndup(msg, (const char *)v->data, v->length);
    1001           0 :         if (buf == NULL) {
    1002           0 :                 return default_value;
    1003             :         }
    1004             : 
    1005           0 :         errno = 0;
    1006           0 :         ret = strtod(buf, &end);
    1007           0 :         talloc_free(buf);
    1008           0 :         if (errno != 0) {
    1009           0 :                 return default_value;
    1010             :         }
    1011           0 :         if (end && end[0] != '\0') {
    1012           0 :                 return default_value;
    1013             :         }
    1014           0 :         return ret;
    1015             : }
    1016             : 
    1017     8260882 : int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
    1018             :                               const char *attr_name,
    1019             :                               int default_value)
    1020             : {
    1021     8260882 :         bool val = false;
    1022     8260882 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1023     8260882 :         int ret = ldb_val_as_bool(v, &val);
    1024     8260882 :         return ret ? default_value : val;
    1025             : }
    1026             : 
    1027     8260911 : int ldb_val_as_bool(const struct ldb_val *v, bool *val)
    1028             : {
    1029     8260911 :         if (!v || !v->data) {
    1030     2833683 :                 return LDB_ERR_OPERATIONS_ERROR;
    1031             :         }
    1032     5427016 :         if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
    1033       83612 :                 *val = false;
    1034       83612 :                 return LDB_SUCCESS;
    1035             :         }
    1036     5343404 :         if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
    1037     5343404 :                 *val = true;
    1038     5343404 :                 return LDB_SUCCESS;
    1039             :         }
    1040           0 :         return LDB_ERR_OPERATIONS_ERROR;
    1041             : }
    1042             : 
    1043   765809738 : const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
    1044             :                                         const char *attr_name,
    1045             :                                         const char *default_value)
    1046             : {
    1047   765809738 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1048   765809738 :         if (!v || !v->data) {
    1049   475827459 :                 return default_value;
    1050             :         }
    1051   277981823 :         if (v->data[v->length] != '\0') {
    1052           0 :                 return default_value;
    1053             :         }
    1054   271034206 :         return (const char *)v->data;
    1055             : }
    1056             : 
    1057     5616779 : struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
    1058             :                                        TALLOC_CTX *mem_ctx,
    1059             :                                        const struct ldb_message *msg,
    1060             :                                        const char *attr_name)
    1061             : {
    1062     5616779 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1063     5616779 :         return ldb_val_as_dn(ldb, mem_ctx, v);
    1064             : }
    1065             : 
    1066     5621862 : struct ldb_dn *ldb_val_as_dn(struct ldb_context *ldb,
    1067             :                              TALLOC_CTX *mem_ctx,
    1068             :                              const struct ldb_val *v)
    1069             : {
    1070      162756 :         struct ldb_dn *res_dn;
    1071             : 
    1072     5621862 :         if (!v || !v->data) {
    1073     1123690 :                 return NULL;
    1074             :         }
    1075     4395724 :         res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
    1076     4395724 :         if ( ! ldb_dn_validate(res_dn)) {
    1077           0 :                 talloc_free(res_dn);
    1078           0 :                 return NULL;
    1079             :         }
    1080     4335416 :         return res_dn;
    1081             : }
    1082             : 
    1083             : /*
    1084             :   sort the elements of a message by name
    1085             : */
    1086     1726337 : void ldb_msg_sort_elements(struct ldb_message *msg)
    1087             : {
    1088     1726337 :         TYPESAFE_QSORT(msg->elements, msg->num_elements,
    1089             :                        ldb_msg_element_compare_name);
    1090     1726337 : }
    1091             : 
    1092     9787899 : static struct ldb_message *ldb_msg_copy_shallow_impl(TALLOC_CTX *mem_ctx,
    1093             :                                          const struct ldb_message *msg)
    1094             : {
    1095      864193 :         struct ldb_message *msg2;
    1096      864193 :         unsigned int i;
    1097             : 
    1098     9787899 :         msg2 = talloc(mem_ctx, struct ldb_message);
    1099     9787899 :         if (msg2 == NULL) return NULL;
    1100             : 
    1101     9787899 :         *msg2 = *msg;
    1102             : 
    1103     9787899 :         msg2->elements = talloc_array(msg2, struct ldb_message_element,
    1104             :                                       msg2->num_elements);
    1105     9787899 :         if (msg2->elements == NULL) goto failed;
    1106             : 
    1107   107650425 :         for (i=0;i<msg2->num_elements;i++) {
    1108    97862526 :                 msg2->elements[i] = msg->elements[i];
    1109             :         }
    1110             : 
    1111     8923706 :         return msg2;
    1112             : 
    1113           0 : failed:
    1114           0 :         talloc_free(msg2);
    1115           0 :         return NULL;
    1116             : }
    1117             : 
    1118             : /*
    1119             :   shallow copy a message - copying only the elements array so that the caller
    1120             :   can safely add new elements without changing the message
    1121             : */
    1122     7887572 : struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
    1123             :                                          const struct ldb_message *msg)
    1124             : {
    1125      716187 :         struct ldb_message *msg2;
    1126      716187 :         unsigned int i;
    1127             : 
    1128     7887572 :         msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
    1129     7887572 :         if (msg2 == NULL) {
    1130           0 :                 return NULL;
    1131             :         }
    1132             : 
    1133    64831090 :         for (i = 0; i < msg2->num_elements; ++i) {
    1134             :                 /*
    1135             :                  * Mark this message's elements as sharing their values with the
    1136             :                  * original message, so that we don't inadvertently modify or
    1137             :                  * free them. We don't mark the original message element as
    1138             :                  * shared, so the original message element should not be
    1139             :                  * modified or freed while the shallow copy lives.
    1140             :                  */
    1141    56943518 :                 struct ldb_message_element *el = &msg2->elements[i];
    1142    56943518 :                 el->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
    1143             :         }
    1144             : 
    1145     7171385 :         return msg2;
    1146             : }
    1147             : 
    1148             : /*
    1149             :   copy a message, allocating new memory for all parts
    1150             : */
    1151     1900327 : struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
    1152             :                                  const struct ldb_message *msg)
    1153             : {
    1154      148006 :         struct ldb_message *msg2;
    1155      148006 :         unsigned int i, j;
    1156             : 
    1157     1900327 :         msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
    1158     1900327 :         if (msg2 == NULL) return NULL;
    1159             : 
    1160     1900327 :         if (msg2->dn != NULL) {
    1161     1900312 :                 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
    1162     1900312 :                 if (msg2->dn == NULL) goto failed;
    1163             :         }
    1164             : 
    1165    42819335 :         for (i=0;i<msg2->num_elements;i++) {
    1166    40919008 :                 struct ldb_message_element *el = &msg2->elements[i];
    1167    40919008 :                 struct ldb_val *values = el->values;
    1168    40919008 :                 if (el->name != NULL) {
    1169    40919008 :                         el->name = talloc_strdup(msg2->elements, el->name);
    1170    40919008 :                         if (el->name == NULL) goto failed;
    1171             :                 }
    1172    40919008 :                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
    1173    40919008 :                 if (el->values == NULL) goto failed;
    1174    90763973 :                 for (j=0;j<el->num_values;j++) {
    1175    49844965 :                         el->values[j] = ldb_val_dup(el->values, &values[j]);
    1176    49844965 :                         if (el->values[j].data == NULL && values[j].length != 0) {
    1177           0 :                                 goto failed;
    1178             :                         }
    1179             :                 }
    1180             : 
    1181             :                 /*
    1182             :                  * Since we copied this element's values, we can mark them as
    1183             :                  * not shared.
    1184             :                  */
    1185    40919008 :                 el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
    1186             :         }
    1187             : 
    1188     1752321 :         return msg2;
    1189             : 
    1190           0 : failed:
    1191           0 :         talloc_free(msg2);
    1192           0 :         return NULL;
    1193             : }
    1194             : 
    1195             : 
    1196             : /**
    1197             :  * Canonicalize a message, merging elements of the same name
    1198             :  */
    1199           0 : struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
    1200             :                                          const struct ldb_message *msg)
    1201             : {
    1202           0 :         int ret;
    1203           0 :         struct ldb_message *msg2;
    1204             : 
    1205             :         /*
    1206             :          * Preserve previous behavior and allocate
    1207             :          * *msg2 into *ldb context
    1208             :          */
    1209           0 :         ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
    1210           0 :         if (ret != LDB_SUCCESS) {
    1211           0 :                 return NULL;
    1212             :         }
    1213             : 
    1214           0 :         return msg2;
    1215             : }
    1216             : 
    1217             : /**
    1218             :  * Canonicalize a message, merging elements of the same name
    1219             :  */
    1220     1725711 : int ldb_msg_normalize(struct ldb_context *ldb,
    1221             :                       TALLOC_CTX *mem_ctx,
    1222             :                       const struct ldb_message *msg,
    1223             :                       struct ldb_message **_msg_out)
    1224             : {
    1225      137629 :         unsigned int i;
    1226      137629 :         struct ldb_message *msg2;
    1227             : 
    1228     1725711 :         msg2 = ldb_msg_copy(mem_ctx, msg);
    1229     1725711 :         if (msg2 == NULL) {
    1230           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1231             :         }
    1232             : 
    1233     1725711 :         ldb_msg_sort_elements(msg2);
    1234             : 
    1235    39531535 :         for (i=1; i < msg2->num_elements; i++) {
    1236    37668195 :                 struct ldb_message_element *el1 = &msg2->elements[i-1];
    1237    37668195 :                 struct ldb_message_element *el2 = &msg2->elements[i];
    1238             : 
    1239    37668195 :                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
    1240       14380 :                         el1->values = talloc_realloc(msg2->elements,
    1241             :                                                      el1->values, struct ldb_val,
    1242             :                                                      el1->num_values + el2->num_values);
    1243       14380 :                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
    1244           0 :                                 talloc_free(msg2);
    1245           0 :                                 return LDB_ERR_OPERATIONS_ERROR;
    1246             :                         }
    1247       14380 :                         memcpy(el1->values + el1->num_values,
    1248       14380 :                                el2->values,
    1249       14380 :                                sizeof(struct ldb_val) * el2->num_values);
    1250       14380 :                         el1->num_values += el2->num_values;
    1251       14380 :                         talloc_free(discard_const_p(char, el2->name));
    1252       14380 :                         if ((i+1) < msg2->num_elements) {
    1253         626 :                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
    1254           0 :                                         (msg2->num_elements - (i+1)));
    1255             :                         }
    1256       14380 :                         msg2->num_elements--;
    1257       14380 :                         i--;
    1258             :                 }
    1259             :         }
    1260             : 
    1261     1725711 :         *_msg_out = msg2;
    1262     1725711 :         return LDB_SUCCESS;
    1263             : }
    1264             : 
    1265             : 
    1266             : /**
    1267             :  * return a ldb_message representing the differences between msg1 and msg2.
    1268             :  * If you then use this in a ldb_modify() call,
    1269             :  * it can be used to save edits to a message
    1270             :  */
    1271           0 : struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
    1272             :                                  struct ldb_message *msg1,
    1273             :                                  struct ldb_message *msg2)
    1274             : {
    1275           0 :         int ldb_ret;
    1276           0 :         struct ldb_message *mod;
    1277             : 
    1278           0 :         ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
    1279           0 :         if (ldb_ret != LDB_SUCCESS) {
    1280           0 :                 return NULL;
    1281             :         }
    1282             : 
    1283           0 :         return mod;
    1284             : }
    1285             : 
    1286             : /**
    1287             :  * return a ldb_message representing the differences between msg1 and msg2.
    1288             :  * If you then use this in a ldb_modify() call it can be used to save edits to a message
    1289             :  *
    1290             :  * Result message is constructed as follows:
    1291             :  * - LDB_FLAG_MOD_ADD     - elements found only in msg2
    1292             :  * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
    1293             :  *                          Value for msg2 element is used
    1294             :  * - LDB_FLAG_MOD_DELETE  - elements found only in msg2
    1295             :  *
    1296             :  * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
    1297             :  */
    1298       90858 : int ldb_msg_difference(struct ldb_context *ldb,
    1299             :                        TALLOC_CTX *mem_ctx,
    1300             :                        struct ldb_message *msg1,
    1301             :                        struct ldb_message *msg2,
    1302             :                        struct ldb_message **_msg_out)
    1303             : {
    1304        2259 :         int ldb_res;
    1305        2259 :         unsigned int i;
    1306        2259 :         struct ldb_message *mod;
    1307        2259 :         struct ldb_message_element *el;
    1308        2259 :         TALLOC_CTX *temp_ctx;
    1309             : 
    1310       90858 :         temp_ctx = talloc_new(mem_ctx);
    1311       90858 :         if (!temp_ctx) {
    1312           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1313             :         }
    1314             : 
    1315       90858 :         mod = ldb_msg_new(temp_ctx);
    1316       90858 :         if (mod == NULL) {
    1317           0 :                 goto failed;
    1318             :         }
    1319             : 
    1320       90858 :         mod->dn = msg1->dn;
    1321       90858 :         mod->num_elements = 0;
    1322       90858 :         mod->elements = NULL;
    1323             : 
    1324             :         /*
    1325             :          * Canonicalize *msg2 so we have no repeated elements
    1326             :          * Resulting message is allocated in *mod's mem context,
    1327             :          * as we are going to move some elements from *msg2 to
    1328             :          * *mod object later
    1329             :          */
    1330       90858 :         ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
    1331       90858 :         if (ldb_res != LDB_SUCCESS) {
    1332           0 :                 goto failed;
    1333             :         }
    1334             : 
    1335             :         /* look in msg2 to find elements that need to be added or modified */
    1336    21721087 :         for (i=0;i<msg2->num_elements;i++) {
    1337    21630229 :                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
    1338             : 
    1339    21630229 :                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
    1340    21572244 :                         continue;
    1341             :                 }
    1342             : 
    1343       57985 :                 ldb_res = ldb_msg_add(mod,
    1344       57985 :                                       &msg2->elements[i],
    1345             :                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
    1346       57985 :                 if (ldb_res != LDB_SUCCESS) {
    1347           0 :                         goto failed;
    1348             :                 }
    1349             :         }
    1350             : 
    1351             :         /* look in msg1 to find elements that need to be deleted */
    1352    21721819 :         for (i=0;i<msg1->num_elements;i++) {
    1353    21630961 :                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
    1354    21630961 :                 if (el == NULL) {
    1355        2043 :                         ldb_res = ldb_msg_add_empty(mod,
    1356        2029 :                                                     msg1->elements[i].name,
    1357             :                                                     LDB_FLAG_MOD_DELETE, NULL);
    1358        2029 :                         if (ldb_res != LDB_SUCCESS) {
    1359           0 :                                 goto failed;
    1360             :                         }
    1361             :                 }
    1362             :         }
    1363             : 
    1364             :         /* steal resulting message into supplied context */
    1365       90858 :         talloc_steal(mem_ctx, mod);
    1366       90858 :         *_msg_out = mod;
    1367             : 
    1368       90858 :         talloc_free(temp_ctx);
    1369       90858 :         return LDB_SUCCESS;
    1370             : 
    1371           0 : failed:
    1372           0 :         talloc_free(temp_ctx);
    1373           0 :         return LDB_ERR_OPERATIONS_ERROR;
    1374             : }
    1375             : 
    1376             : 
    1377     1431843 : int ldb_msg_sanity_check(struct ldb_context *ldb,
    1378             :                          const struct ldb_message *msg)
    1379             : {
    1380      112715 :         unsigned int i, j;
    1381             : 
    1382             :         /* basic check on DN */
    1383     1431843 :         if (msg->dn == NULL) {
    1384           0 :                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
    1385           0 :                 return LDB_ERR_INVALID_DN_SYNTAX;
    1386             :         }
    1387             : 
    1388             :         /* basic syntax checks */
    1389     8547149 :         for (i = 0; i < msg->num_elements; i++) {
    1390    16667094 :                 for (j = 0; j < msg->elements[i].num_values; j++) {
    1391     9551788 :                         if (msg->elements[i].values[j].length == 0) {
    1392             :                                 /* an attribute cannot be empty */
    1393           4 :                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
    1394           2 :                                                             msg->elements[i].name,
    1395           2 :                                                             ldb_dn_get_linearized(msg->dn));
    1396           2 :                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1397             :                         }
    1398             :                 }
    1399             :         }
    1400             : 
    1401     1319126 :         return LDB_SUCCESS;
    1402             : }
    1403             : 
    1404             : 
    1405             : 
    1406             : 
    1407             : /*
    1408             :   copy an attribute list. This only copies the array, not the elements
    1409             :   (ie. the elements are left as the same pointers)
    1410             : */
    1411    10119855 : const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
    1412             : {
    1413      206085 :         const char **ret;
    1414      206085 :         unsigned int i;
    1415             : 
    1416   304779007 :         for (i=0;attrs && attrs[i];i++) /* noop */ ;
    1417    10119855 :         ret = talloc_array(mem_ctx, const char *, i+1);
    1418    10119855 :         if (ret == NULL) {
    1419           0 :                 return NULL;
    1420             :         }
    1421   304779007 :         for (i=0;attrs && attrs[i];i++) {
    1422   294659152 :                 ret[i] = attrs[i];
    1423             :         }
    1424    10119855 :         ret[i] = attrs[i];
    1425    10119855 :         return ret;
    1426             : }
    1427             : 
    1428             : 
    1429             : /*
    1430             :   copy an attribute list. This only copies the array, not the elements
    1431             :   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
    1432             : */
    1433    10905672 : const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
    1434             : {
    1435      230240 :         const char **ret;
    1436      230240 :         unsigned int i;
    1437    10905672 :         bool found = false;
    1438             : 
    1439   287098800 :         for (i=0;attrs && attrs[i];i++) {
    1440   276193128 :                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
    1441     7786781 :                         found = true;
    1442             :                 }
    1443             :         }
    1444    10905672 :         if (found) {
    1445     6936423 :                 return ldb_attr_list_copy(mem_ctx, attrs);
    1446             :         }
    1447     3969249 :         ret = talloc_array(mem_ctx, const char *, i+2);
    1448     3969249 :         if (ret == NULL) {
    1449           0 :                 return NULL;
    1450             :         }
    1451    37428720 :         for (i=0;attrs && attrs[i];i++) {
    1452    33459471 :                 ret[i] = attrs[i];
    1453             :         }
    1454     3969249 :         ret[i] = new_attr;
    1455     3969249 :         ret[i+1] = NULL;
    1456     3969249 :         return ret;
    1457             : }
    1458             : 
    1459             : 
    1460             : /*
    1461             :   return 1 if an attribute is in a list of attributes, or 0 otherwise
    1462             : */
    1463  2322114103 : int ldb_attr_in_list(const char * const *attrs, const char *attr)
    1464             : {
    1465    95906309 :         unsigned int i;
    1466  6342722868 :         for (i=0;attrs && attrs[i];i++) {
    1467  4118523688 :                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
    1468    96608102 :                         return 1;
    1469             :                 }
    1470             :         }
    1471  2129599692 :         return 0;
    1472             : }
    1473             : 
    1474             : 
    1475             : /*
    1476             :   rename the specified attribute in a search result
    1477             : */
    1478           3 : int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
    1479             : {
    1480           3 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
    1481           3 :         if (el == NULL) {
    1482           0 :                 return LDB_SUCCESS;
    1483             :         }
    1484           3 :         el->name = talloc_strdup(msg->elements, replace);
    1485           3 :         if (el->name == NULL) {
    1486           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1487             :         }
    1488           3 :         return LDB_SUCCESS;
    1489             : }
    1490             : 
    1491             : 
    1492             : /*
    1493             :   copy the specified attribute in a search result to a new attribute
    1494             : */
    1495           3 : int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
    1496             : {
    1497           3 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
    1498           0 :         int ret;
    1499             : 
    1500           3 :         if (el == NULL) {
    1501           0 :                 return LDB_SUCCESS;
    1502             :         }
    1503           3 :         ret = ldb_msg_add(msg, el, 0);
    1504           3 :         if (ret != LDB_SUCCESS) {
    1505           0 :                 return ret;
    1506             :         }
    1507           3 :         return ldb_msg_rename_attr(msg, attr, replace);
    1508             : }
    1509             : 
    1510             : /*
    1511             :   remove the specified element in a search result
    1512             : */
    1513     8880931 : void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
    1514             : {
    1515     8880931 :         ptrdiff_t n = (el - msg->elements);
    1516     8880931 :         if (n >= msg->num_elements || n < 0) {
    1517             :                 /* the element is not in the list. the caller is crazy. */
    1518           0 :                 return;
    1519             :         }
    1520     8880931 :         msg->num_elements--;
    1521     8880931 :         if (n != msg->num_elements) {
    1522     4970000 :                 memmove(el, el+1, (msg->num_elements - n)*sizeof(*el));
    1523             :         }
    1524             : }
    1525             : 
    1526             : 
    1527             : /*
    1528             :   remove the specified attribute in a search result
    1529             : */
    1530  2582001101 : void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
    1531             : {
    1532    77685226 :         unsigned int i;
    1533  2582001101 :         unsigned int num_del = 0;
    1534             : 
    1535 31410689258 :         for (i = 0; i < msg->num_elements; ++i) {
    1536 28828688157 :                 if (ldb_attr_cmp(msg->elements[i].name, attr) == 0) {
    1537    58079745 :                         ++num_del;
    1538 28770608412 :                 } else if (num_del) {
    1539   113013358 :                         msg->elements[i - num_del] = msg->elements[i];
    1540             :                 }
    1541             :         }
    1542             : 
    1543  2582001101 :         msg->num_elements -= num_del;
    1544  2582001101 : }
    1545             : 
    1546             : /* Reallocate elements to drop any excess capacity. */
    1547   168139339 : void ldb_msg_shrink_to_fit(struct ldb_message *msg)
    1548             : {
    1549   168139339 :         if (msg->num_elements > 0) {
    1550   149308562 :                 struct ldb_message_element *elements = talloc_realloc(msg,
    1551             :                                                                       msg->elements,
    1552             :                                                                       struct ldb_message_element,
    1553             :                                                                       msg->num_elements);
    1554   149308562 :                 if (elements != NULL) {
    1555   149308562 :                         msg->elements = elements;
    1556             :                 }
    1557             :         } else {
    1558    18830777 :                 TALLOC_FREE(msg->elements);
    1559             :         }
    1560   168139339 : }
    1561             : 
    1562             : /*
    1563             :   return a LDAP formatted GeneralizedTime string
    1564             : */
    1565     6378795 : char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
    1566             : {
    1567     6378795 :         struct tm *tm = gmtime(&t);
    1568      368486 :         char *ts;
    1569      368486 :         int r;
    1570             : 
    1571     6378795 :         if (!tm) {
    1572           3 :                 return NULL;
    1573             :         }
    1574             : 
    1575             :         /* we know exactly how long this string will be */
    1576     6378792 :         ts = talloc_array(mem_ctx, char, 18);
    1577             : 
    1578             :         /* formatted like: 20040408072012.0Z */
    1579     6378792 :         r = snprintf(ts, 18,
    1580             :                         "%04u%02u%02u%02u%02u%02u.0Z",
    1581     6378792 :                         tm->tm_year+1900, tm->tm_mon+1,
    1582             :                         tm->tm_mday, tm->tm_hour, tm->tm_min,
    1583             :                         tm->tm_sec);
    1584             : 
    1585     6378792 :         if (r != 17) {
    1586           6 :                 talloc_free(ts);
    1587           6 :                 errno = EOVERFLOW;
    1588           6 :                 return NULL;
    1589             :         }
    1590             : 
    1591     6010300 :         return ts;
    1592             : }
    1593             : 
    1594             : /*
    1595             :   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
    1596             : */
    1597       23252 : time_t ldb_string_to_time(const char *s)
    1598             : {
    1599          72 :         struct tm tm;
    1600             : 
    1601       23252 :         if (s == NULL) return 0;
    1602             : 
    1603       23226 :         memset(&tm, 0, sizeof(tm));
    1604       23226 :         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
    1605             :                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1606             :                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1607           0 :                 return 0;
    1608             :         }
    1609       23226 :         tm.tm_year -= 1900;
    1610       23226 :         tm.tm_mon -= 1;
    1611             : 
    1612       23226 :         return timegm(&tm);
    1613             : }
    1614             : 
    1615             : /*
    1616             :   convert a LDAP GeneralizedTime string in ldb_val format to a
    1617             :   time_t.
    1618             : */
    1619     4779972 : int ldb_val_to_time(const struct ldb_val *v, time_t *t)
    1620             : {
    1621     4779972 :         char val[15] = {0};
    1622     4779972 :         struct tm tm = {
    1623             :                 .tm_year = 0,
    1624             :         };
    1625             : 
    1626     4779972 :         if (v == NULL) {
    1627         164 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1628             :         }
    1629             : 
    1630     4779808 :         if (v->data == NULL) {
    1631           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1632             :         }
    1633             : 
    1634     4779808 :         if (v->length < 16 && v->length != 13) {
    1635           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1636             :         }
    1637             : 
    1638     4779808 :         if (v->data[v->length - 1] != 'Z') {
    1639           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1640             :         }
    1641             : 
    1642     4779808 :         if (v->length == 13) {
    1643         527 :                 memcpy(val, v->data, 12);
    1644             : 
    1645         527 :                 if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
    1646             :                         &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1647             :                         &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1648           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1649             :                 }
    1650         527 :                 if (tm.tm_year < 50) {
    1651         527 :                         tm.tm_year += 100;
    1652             :                 }
    1653             :         } else {
    1654             : 
    1655             :                 /*
    1656             :                  * anything between '.' and 'Z' is silently ignored.
    1657             :                  */
    1658     4779281 :                 if (v->data[14] != '.') {
    1659           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1660             :                 }
    1661             : 
    1662     4779281 :                 memcpy(val, v->data, 14);
    1663             : 
    1664     4779281 :                 if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
    1665             :                         &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1666             :                         &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1667           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1668             :                 }
    1669     4779281 :                 tm.tm_year -= 1900;
    1670             :         }
    1671     4779808 :         tm.tm_mon -= 1;
    1672             : 
    1673     4779808 :         *t = timegm(&tm);
    1674             : 
    1675     4779808 :         return LDB_SUCCESS;
    1676             : }
    1677             : 
    1678             : /*
    1679             :   return a LDAP formatted UTCTime string
    1680             : */
    1681          62 : char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
    1682             : {
    1683          62 :         struct tm *tm = gmtime(&t);
    1684           3 :         char *ts;
    1685           3 :         int r;
    1686             : 
    1687          62 :         if (!tm) {
    1688           0 :                 return NULL;
    1689             :         }
    1690             : 
    1691             :         /* we know exactly how long this string will be */
    1692          62 :         ts = talloc_array(mem_ctx, char, 14);
    1693             : 
    1694             :         /* formatted like: 20040408072012.0Z => 040408072012Z */
    1695          62 :         r = snprintf(ts, 14,
    1696             :                         "%02u%02u%02u%02u%02u%02uZ",
    1697          62 :                         (tm->tm_year+1900)%100, tm->tm_mon+1,
    1698             :                         tm->tm_mday, tm->tm_hour, tm->tm_min,
    1699             :                         tm->tm_sec);
    1700             : 
    1701          62 :         if (r != 13) {
    1702           0 :                 talloc_free(ts);
    1703           0 :                 return NULL;
    1704             :         }
    1705             : 
    1706          59 :         return ts;
    1707             : }
    1708             : 
    1709             : /*
    1710             :   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
    1711             : */
    1712           0 : time_t ldb_string_utc_to_time(const char *s)
    1713             : {
    1714           0 :         struct tm tm;
    1715             : 
    1716           0 :         if (s == NULL) return 0;
    1717             : 
    1718           0 :         memset(&tm, 0, sizeof(tm));
    1719           0 :         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
    1720             :                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1721             :                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1722           0 :                 return 0;
    1723             :         }
    1724           0 :         if (tm.tm_year < 50) {
    1725           0 :                 tm.tm_year += 100;
    1726             :         }
    1727           0 :         tm.tm_mon -= 1;
    1728             : 
    1729           0 :         return timegm(&tm);
    1730             : }
    1731             : 
    1732             : 
    1733             : /*
    1734             :   dump a set of results to a file. Useful from within gdb
    1735             : */
    1736           0 : void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
    1737             : {
    1738           0 :         unsigned int i;
    1739             : 
    1740           0 :         for (i = 0; i < result->count; i++) {
    1741           0 :                 struct ldb_ldif ldif;
    1742           0 :                 fprintf(f, "# record %d\n", i+1);
    1743           0 :                 ldif.changetype = LDB_CHANGETYPE_NONE;
    1744           0 :                 ldif.msg = result->msgs[i];
    1745           0 :                 ldb_ldif_write_file(ldb, f, &ldif);
    1746             :         }
    1747           0 : }
    1748             : 
    1749             : /*
    1750             :   checks for a string attribute. Returns "1" on match and otherwise "0".
    1751             : */
    1752     3232065 : int ldb_msg_check_string_attribute(const struct ldb_message *msg,
    1753             :                                    const char *name, const char *value)
    1754             : {
    1755       44965 :         struct ldb_message_element *el;
    1756       44965 :         struct ldb_val val;
    1757             : 
    1758     3232065 :         el = ldb_msg_find_element(msg, name);
    1759     3232065 :         if (el == NULL) {
    1760     1572168 :                 return 0;
    1761             :         }
    1762             : 
    1763     1635994 :         val.data = discard_const_p(uint8_t, value);
    1764     1635994 :         val.length = strlen(value);
    1765             : 
    1766     1635994 :         if (ldb_msg_find_val(el, &val)) {
    1767     1635197 :                 return 1;
    1768             :         }
    1769             : 
    1770         797 :         return 0;
    1771             : }
    1772             : 
    1773             : 
    1774             : /*
    1775             :   compare a ldb_val to a string
    1776             : */
    1777     3345449 : int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
    1778             : {
    1779     3345449 :         size_t len = strlen(str);
    1780     3345449 :         if (len != v->length) {
    1781           0 :                 return len - v->length;
    1782             :         }
    1783     3345449 :         return strncmp((const char *)v->data, str, len);
    1784             : }

Generated by: LCOV version 1.14