LCOV - code coverage report
Current view: top level - lib/ldb/common - ldb_msg.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 654 799 81.9 %
Date: 2024-04-21 15:09:00 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   779116824 : struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
      40             : {
      41   779116824 :         return talloc_zero(mem_ctx, struct ldb_message);
      42             : }
      43             : 
      44             : /*
      45             :   find an element in a message by attribute name
      46             : */
      47  6882687928 : struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
      48             :                                                  const char *attr_name)
      49             : {
      50   185505537 :         unsigned int i;
      51 >10371*10^7 :         for (i=0;i<msg->num_elements;i++) {
      52 99574486617 :                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
      53  2741711642 :                         return &msg->elements[i];
      54             :                 }
      55             :         }
      56  4030528515 :         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   374417708 : int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
      64             : {
      65   374417708 :         if (v1->length != v2->length) return 0;
      66    59734325 :         if (v1->data == v2->data) return 1;
      67    59631852 :         if (v1->length == 0) return 1;
      68             : 
      69    59631852 :         if (memcmp(v1->data, v2->data, v1->length) == 0) {
      70    36238267 :                 return 1;
      71             :         }
      72             : 
      73    22301100 :         return 0;
      74             : }
      75             : 
      76             : /*
      77             :   find a value in an element
      78             :   assumes case sensitive comparison
      79             : */
      80    28908997 : struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
      81             :                                  struct ldb_val *val)
      82             : {
      83      941005 :         unsigned int i;
      84   353044618 :         for (i=0;i<el->num_values;i++) {
      85   352396802 :                 if (ldb_val_equal_exact(val, &el->values[i])) {
      86    28261181 :                         return &el->values[i];
      87             :                 }
      88             :         }
      89      626781 :         return NULL;
      90             : }
      91             : 
      92             : 
      93     8706724 : static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
      94             : {
      95     8706724 :         if (v1->length != v2->length) {
      96     7302960 :                 return NUMERIC_CMP(v1->length, v2->length);
      97             :         }
      98     1403764 :         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    30883616 : 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     2196902 :         unsigned int i, j;
     118     2196902 :         struct ldb_val *val;
     119             : 
     120    30883616 :         if (options != 0) {
     121           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     122             :         }
     123             : 
     124    30883616 :         *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    30883616 :         if (el->num_values < LDB_DUP_QUADRATIC_THRESHOLD) {
     131    64240728 :                 for (j = 0; j < el->num_values; j++) {
     132    33413847 :                         val = &el->values[j];
     133    38320820 :                         for ( i = j + 1; i < el->num_values; i++) {
     134     4906979 :                                 if (ldb_val_equal_exact(val, &el->values[i])) {
     135           6 :                                         *duplicate = val;
     136           6 :                                         return LDB_SUCCESS;
     137             :                                 }
     138             :                         }
     139             :                 }
     140             :         } else {
     141        5679 :                 struct ldb_val *values;
     142       56729 :                 values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
     143       56729 :                 if (values == NULL) {
     144           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     145             :                 }
     146             : 
     147       56729 :                 memcpy(values, el->values,
     148       56729 :                        el->num_values * sizeof(struct ldb_val));
     149       56729 :                 TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
     150     2033484 :                 for (i = 1; i < el->num_values; i++) {
     151     1976756 :                         if (ldb_val_equal_exact(&values[i],
     152     1976756 :                                                 &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       56728 :                 talloc_free(values);
     171             :         }
     172    28686713 :         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        5248 : 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         556 :         struct ldb_val *values;
     198         556 :         struct ldb_val *values2;
     199         556 :         unsigned int i, j, k, n_values;
     200             : 
     201        5248 :         bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
     202             : 
     203        5248 :         if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
     204           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     205             :         }
     206             : 
     207        5248 :         if (strcmp(el->name, el2->name) != 0) {
     208           0 :                 return LDB_ERR_INAPPROPRIATE_MATCHING;
     209             :         }
     210        5247 :         if (el->num_values == 0 || el2->num_values == 0) {
     211           0 :                 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        5235 :         if (MIN(el->num_values, el2->num_values) == 1 ||
     218         224 :             MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
     219       22807 :                 for (i = 0; i < el2->num_values; i++) {
     220       36200 :                         for (j = 0; j < el->num_values; j++) {
     221       18510 :                                 if (ldb_val_equal_exact(&el->values[j],
     222       18510 :                                                         &el2->values[i])) {
     223          21 :                                         if (! remove_duplicates) {
     224             :                                             return                      \
     225          17 :                                               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        4572 :                 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        3637 :         while (i != n_values && j < el2->num_values) {
     269        3523 :                 int ret = ldb_val_cmp(&values[i], &values2[j]);
     270        3523 :                 if (ret < 0) {
     271         845 :                         i++;
     272        2678 :                 } else if (ret > 0) {
     273        2660 :                         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           0 :                                                         &values[i])) {
     289           0 :                                         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  3156781870 : struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
     309             : {
     310   104999328 :         struct ldb_val v2;
     311  3156781870 :         v2.length = v->length;
     312  3156781870 :         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  3156623460 :         v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
     320  3156623460 :         if (!v2.data) {
     321           0 :                 v2.length = 0;
     322           0 :                 return v2;
     323             :         }
     324             : 
     325  3156623460 :         memcpy(v2.data, v->data, v->length);
     326  3156623460 :         ((char *)v2.data)[v->length] = 0;
     327  3156623460 :         return v2;
     328             : }
     329             : 
     330             : /**
     331             :  * Adds new empty element to msg->elements
     332             :  */
     333   240977115 : static int _ldb_msg_add_el(struct ldb_message *msg,
     334             :                            struct ldb_message_element **return_el)
     335             : {
     336     8104913 :         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   240977115 :         els = talloc_realloc(msg, msg->elements,
     344             :                              struct ldb_message_element, msg->num_elements + 1);
     345   240977115 :         if (!els) {
     346           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     347             :         }
     348             : 
     349   240977115 :         els[msg->num_elements] = (struct ldb_message_element) {};
     350             : 
     351   240977115 :         msg->elements = els;
     352   240977115 :         msg->num_elements++;
     353             : 
     354   240977115 :         *return_el = &els[msg->num_elements-1];
     355             : 
     356   240977115 :         return LDB_SUCCESS;
     357             : }
     358             : 
     359             : /**
     360             :  * Add an empty element with a given name to a message
     361             :  */
     362   238897249 : 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     8050689 :         int ret;
     368     8050689 :         struct ldb_message_element *el;
     369             : 
     370   238897249 :         ret = _ldb_msg_add_el(msg, &el);
     371   238897249 :         if (ret != LDB_SUCCESS) {
     372           0 :                 return ret;
     373             :         }
     374             : 
     375             :         /* initialize newly added element */
     376   238897249 :         el->flags = flags;
     377   238897249 :         el->name = talloc_strdup(msg->elements, attr_name);
     378   238897249 :         if (!el->name) {
     379           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     380             :         }
     381             : 
     382   238897249 :         if (return_el) {
     383   237716331 :                 *return_el = el;
     384             :         }
     385             : 
     386   230846560 :         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     2079866 : int ldb_msg_add(struct ldb_message *msg,
     398             :                 const struct ldb_message_element *el,
     399             :                 int flags)
     400             : {
     401       54224 :         int ret;
     402       54224 :         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     2079866 :         struct ldb_message_element el_copy = *el;
     406             : 
     407     2079866 :         ret = _ldb_msg_add_el(msg, &el_new);
     408     2079866 :         if (ret != LDB_SUCCESS) {
     409           0 :                 return ret;
     410             :         }
     411             : 
     412     2079866 :         el_new->flags      = flags;
     413     2079866 :         el_new->name       = el_copy.name;
     414     2079866 :         el_new->num_values = el_copy.num_values;
     415     2079866 :         el_new->values     = el_copy.values;
     416             : 
     417     2079866 :         return LDB_SUCCESS;
     418             : }
     419             : 
     420             : /*
     421             :  * add a value to a message element
     422             :  */
     423   231793309 : int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
     424             :                               struct ldb_message_element *el,
     425             :                               const struct ldb_val *val)
     426             : {
     427     7482733 :         struct ldb_val *vals;
     428             : 
     429   231793309 :         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   231793271 :                 vals = talloc_realloc(mem_ctx, el->values, struct ldb_val,
     449             :                                       el->num_values + 1);
     450   231793271 :                 if (vals == NULL) {
     451           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     452             :                 }
     453             :         }
     454   231793309 :         el->values = vals;
     455   231793309 :         el->values[el->num_values] = *val;
     456   231793309 :         el->num_values++;
     457             : 
     458   231793309 :         return LDB_SUCCESS;
     459             : }
     460             : 
     461             : /*
     462             :   add a value to a message
     463             : */
     464   231438822 : 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     7477498 :         struct ldb_message_element *el;
     470     7477498 :         int ret;
     471             : 
     472   231438822 :         el = ldb_msg_find_element(msg, attr_name);
     473   231438822 :         if (!el) {
     474   225506660 :                 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
     475   225506660 :                 if (ret != LDB_SUCCESS) {
     476           0 :                         return ret;
     477             :                 }
     478             :         }
     479             : 
     480   231438822 :         ret = ldb_msg_element_add_value(msg->elements, el, val);
     481   231438822 :         if (ret != LDB_SUCCESS) {
     482           0 :                 return ret;
     483             :         }
     484             : 
     485   231438822 :         if (return_el) {
     486   228927960 :                 *return_el = el;
     487             :         }
     488             : 
     489   223961324 :         return LDB_SUCCESS;
     490             : }
     491             : 
     492             : 
     493             : /*
     494             :   add a value to a message, stealing it into the 'right' place
     495             : */
     496   192722043 : int ldb_msg_add_steal_value(struct ldb_message *msg,
     497             :                             const char *attr_name,
     498             :                             struct ldb_val *val)
     499             : {
     500     5628828 :         int ret;
     501     5628828 :         struct ldb_message_element *el;
     502             : 
     503   192722043 :         ret = ldb_msg_add_value(msg, attr_name, val, &el);
     504   192722043 :         if (ret == LDB_SUCCESS) {
     505   192722043 :                 talloc_steal(el->values, val->data);
     506             :         }
     507   192722043 :         return ret;
     508             : }
     509             : 
     510             : 
     511             : /*
     512             :   add a string element to a message, specifying flags
     513             : */
     514    35644824 : int ldb_msg_add_string_flags(struct ldb_message *msg,
     515             :                              const char *attr_name, const char *str,
     516             :                              int flags)
     517             : {
     518     1626981 :         struct ldb_val val;
     519     1626981 :         int ret;
     520    35644824 :         struct ldb_message_element *el = NULL;
     521             : 
     522    35644824 :         val.data = discard_const_p(uint8_t, str);
     523    35644824 :         val.length = strlen(str);
     524             : 
     525    35644824 :         if (val.length == 0) {
     526             :                 /* allow empty strings as non-existent attributes */
     527         284 :                 return LDB_SUCCESS;
     528             :         }
     529             : 
     530    35644518 :         ret = ldb_msg_add_value(msg, attr_name, &val, &el);
     531    35644518 :         if (ret != LDB_SUCCESS) {
     532           0 :                 return ret;
     533             :         }
     534             : 
     535    35644518 :         if (flags != 0) {
     536       89840 :                 el->flags = flags;
     537             :         }
     538             : 
     539    34017559 :         return LDB_SUCCESS;
     540             : }
     541             : 
     542             : /*
     543             :   add a string element to a message
     544             : */
     545    35554984 : int ldb_msg_add_string(struct ldb_message *msg,
     546             :                        const char *attr_name, const char *str)
     547             : {
     548    35554984 :         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   174956720 : int ldb_msg_add_steal_string(struct ldb_message *msg,
     555             :                              const char *attr_name, char *str)
     556             : {
     557     4665684 :         struct ldb_val val;
     558             : 
     559   174956720 :         val.data = (uint8_t *)str;
     560   174956720 :         val.length = strlen(str);
     561             : 
     562   174956720 :         if (val.length == 0) {
     563             :                 /* allow empty strings as non-existent attributes */
     564           0 :                 return LDB_SUCCESS;
     565             :         }
     566             : 
     567   174956720 :         return ldb_msg_add_steal_value(msg, attr_name, &val);
     568             : }
     569             : 
     570             : /*
     571             :   add a DN element to a message
     572             : */
     573        1988 : int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
     574             :                               struct ldb_dn *dn)
     575             : {
     576        1988 :         char *str = ldb_dn_alloc_linearized(msg, dn);
     577             : 
     578        1988 :         if (str == NULL) {
     579             :                 /* we don't want to have unknown DNs added */
     580           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     581             :         }
     582             : 
     583        1988 :         return ldb_msg_add_steal_string(msg, attr_name, str);
     584             : }
     585             : 
     586             : /*
     587             :   add a printf formatted element to a message
     588             : */
     589    10466536 : int ldb_msg_add_fmt(struct ldb_message *msg,
     590             :                     const char *attr_name, const char *fmt, ...)
     591             : {
     592      725063 :         struct ldb_val val;
     593      725063 :         va_list ap;
     594      725063 :         char *str;
     595             : 
     596    10466536 :         va_start(ap, fmt);
     597    10466536 :         str = talloc_vasprintf(msg, fmt, ap);
     598    10466536 :         va_end(ap);
     599             : 
     600    10466536 :         if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
     601             : 
     602    10466536 :         val.data   = (uint8_t *)str;
     603    10466536 :         val.length = strlen(str);
     604             : 
     605    10466536 :         return ldb_msg_add_steal_value(msg, attr_name, &val);
     606             : }
     607             : 
     608      353835 : 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      353835 :         struct ldb_message_element *el = NULL;
     615        5229 :         int ret;
     616             : 
     617      353835 :         ret = ldb_msg_add_empty(msg, attr_name, flags, &el);
     618      353835 :         if (ret != LDB_SUCCESS) {
     619           0 :                 return ret;
     620             :         }
     621             : 
     622      353835 :         ret = ldb_msg_element_add_value(msg->elements, el, val);
     623      353835 :         if (ret != LDB_SUCCESS) {
     624           0 :                 return ret;
     625             :         }
     626             : 
     627      353835 :         if (return_el != NULL) {
     628        2307 :                 *return_el = el;
     629             :         }
     630             : 
     631      348606 :         return LDB_SUCCESS;
     632             : }
     633             : 
     634             : /*
     635             :   append a value to a message
     636             : */
     637      351528 : 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      351528 :         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        2307 : 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         158 :         int ret;
     654        2307 :         struct ldb_message_element *el = NULL;
     655             : 
     656        2307 :         ret = ldb_msg_append_value_impl(msg, attr_name, val, flags, &el);
     657        2307 :         if (ret == LDB_SUCCESS) {
     658        2307 :                 talloc_steal(el->values, val->data);
     659             :         }
     660        2307 :         return ret;
     661             : }
     662             : 
     663             : /*
     664             :   append a string element to a message, stealing it into the 'right' place
     665             : */
     666        1078 : int ldb_msg_append_steal_string(struct ldb_message *msg,
     667             :                                 const char *attr_name, char *str,
     668             :                                 int flags)
     669             : {
     670         132 :         struct ldb_val val;
     671             : 
     672        1078 :         val.data = (uint8_t *)str;
     673        1078 :         val.length = strlen(str);
     674             : 
     675        1078 :         if (val.length == 0) {
     676             :                 /* allow empty strings as non-existent attributes */
     677           0 :                 return LDB_SUCCESS;
     678             :         }
     679             : 
     680        1078 :         return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
     681             : }
     682             : 
     683             : /*
     684             :   append a string element to a message
     685             : */
     686       89526 : int ldb_msg_append_string(struct ldb_message *msg,
     687             :                           const char *attr_name, const char *str, int flags)
     688             : {
     689         588 :         struct ldb_val val;
     690             : 
     691       89526 :         val.data = discard_const_p(uint8_t, str);
     692       89526 :         val.length = strlen(str);
     693             : 
     694       89526 :         if (val.length == 0) {
     695             :                 /* allow empty strings as non-existent attributes */
     696           0 :                 return LDB_SUCCESS;
     697             :         }
     698             : 
     699       89526 :         return ldb_msg_append_value(msg, attr_name, &val, flags);
     700             : }
     701             : 
     702             : /*
     703             :   append a DN element to a message
     704             : */
     705          99 : int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
     706             :                                  struct ldb_dn *dn, int flags)
     707             : {
     708          99 :         char *str = ldb_dn_alloc_linearized(msg, dn);
     709             : 
     710          99 :         if (str == NULL) {
     711             :                 /* we don't want to have unknown DNs added */
     712           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     713             :         }
     714             : 
     715          99 :         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        1109 : 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        1109 :         char *str = NULL;
     727             : 
     728        1109 :         va_start(ap, fmt);
     729        1109 :         str = talloc_vasprintf(msg, fmt, ap);
     730        1109 :         va_end(ap);
     731             : 
     732        1109 :         if (str == NULL) {
     733           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     734             :         }
     735             : 
     736        1109 :         val.data   = (uint8_t *)str;
     737        1109 :         val.length = strlen(str);
     738             : 
     739        1109 :         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    21858076 : int ldb_msg_element_compare(struct ldb_message_element *el1,
     747             :                             struct ldb_message_element *el2)
     748             : {
     749      727192 :         unsigned int i;
     750             : 
     751    21858076 :         if (el1->num_values != el2->num_values) {
     752         243 :                 return NUMERIC_CMP(el1->num_values, el2->num_values);
     753             :         }
     754             :         /*
     755             :          * Note this is an inconsistent comparison, unsuitable for
     756             :          * sorting. If A has values {a, b} and B has values {b, c},
     757             :          * then
     758             :          *
     759             :          * ldb_msg_element_compare(A, B) returns -1, meaning A < B
     760             :          * ldb_msg_element_compare(B, A) returns -1, meaning B < A
     761             :          */
     762    48416433 :         for (i=0;i<el1->num_values;i++) {
     763    26615057 :                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
     764       54517 :                         return -1;
     765             :                 }
     766             :         }
     767             : 
     768    21076125 :         return 0;
     769             : }
     770             : 
     771             : /*
     772             :   compare two ldb_message_element structures.
     773             :   Different ordering is considered a mismatch
     774             : */
     775    11942873 : bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
     776             :                                    const struct ldb_message_element *el2)
     777             : {
     778      416310 :         unsigned i;
     779    11942873 :         if (el1->num_values != el2->num_values) {
     780     1078759 :                 return false;
     781             :         }
     782    16374318 :         for (i=0;i<el1->num_values;i++) {
     783    11362647 :                 if (ldb_val_equal_exact(&el1->values[i],
     784    11362647 :                                         &el2->values[i]) != 1) {
     785     5644342 :                         return false;
     786             :                 }
     787             :         }
     788     4803462 :         return true;
     789             : }
     790             : 
     791             : /*
     792             :   compare two ldb_message_element structures
     793             :   comparing by element name
     794             : */
     795   255502117 : int ldb_msg_element_compare_name(struct ldb_message_element *el1,
     796             :                                  struct ldb_message_element *el2)
     797             : {
     798   255502117 :         if (el1->name == el2->name) {
     799           0 :                 return 0;
     800             :         }
     801             : 
     802   255502117 :         if (el1->name == NULL) {
     803           0 :                 return -1;
     804             :         }
     805             : 
     806   255502117 :         if (el2->name == NULL) {
     807           0 :                 return 1;
     808             :         }
     809             : 
     810   255502117 :         return ldb_attr_cmp(el1->name, el2->name);
     811             : }
     812             : 
     813     5071619 : void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el)
     814             : {
     815     5071619 :         el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
     816     5071619 : }
     817             : 
     818   212097024 : bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el)
     819             : {
     820   212097024 :         return (el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE) != 0;
     821             : }
     822             : 
     823     1483932 : void ldb_msg_remove_inaccessible(struct ldb_message *msg)
     824             : {
     825         268 :         unsigned i;
     826     1483932 :         unsigned num_del = 0;
     827             : 
     828    10652366 :         for (i = 0; i < msg->num_elements; ++i) {
     829     9168434 :                 if (ldb_msg_element_is_inaccessible(&msg->elements[i])) {
     830     5066874 :                         ++num_del;
     831     4101560 :                 } else if (num_del) {
     832     2969021 :                         msg->elements[i - num_del] = msg->elements[i];
     833             :                 }
     834             :         }
     835             : 
     836     1483932 :         msg->num_elements -= num_del;
     837     1483932 : }
     838             : 
     839             : /*
     840             :   convenience functions to return common types from a message
     841             :   these return the first value if the attribute is multi-valued
     842             : */
     843  3324420656 : const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
     844             :                                            const char *attr_name)
     845             : {
     846  3324420656 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
     847  3324420656 :         if (!el || el->num_values == 0) {
     848  1434977013 :                 return NULL;
     849             :         }
     850  1852174901 :         return &el->values[0];
     851             : }
     852             : 
     853   147169411 : int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
     854             :                              const char *attr_name,
     855             :                              int default_value)
     856             : {
     857   147169411 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     858   147169411 :         char buf[sizeof("-2147483648")] = {};
     859   147169411 :         char *end = NULL;
     860     3218343 :         int ret;
     861             : 
     862   147169411 :         if (!v || !v->data) {
     863     1890169 :                 return default_value;
     864             :         }
     865             : 
     866   145130164 :         if (v->length >= sizeof(buf)) {
     867          66 :                 return default_value;
     868             :         }
     869             : 
     870   145130098 :         memcpy(buf, v->data, v->length);
     871   145130098 :         errno = 0;
     872   145130098 :         ret = (int) strtoll(buf, &end, 10);
     873   145130098 :         if (errno != 0) {
     874           0 :                 return default_value;
     875             :         }
     876   145130098 :         if (end && end[0] != '\0') {
     877           0 :                 return default_value;
     878             :         }
     879   142060833 :         return ret;
     880             : }
     881             : 
     882   593925181 : unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
     883             :                                        const char *attr_name,
     884             :                                        unsigned int default_value)
     885             : {
     886   593925181 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     887   593925181 :         char buf[sizeof("-2147483648")] = {};
     888   593925181 :         char *end = NULL;
     889    14765203 :         unsigned int ret;
     890             : 
     891   593925181 :         if (!v || !v->data) {
     892   288485823 :                 return default_value;
     893             :         }
     894             : 
     895   297994770 :         if (v->length >= sizeof(buf)) {
     896          48 :                 return default_value;
     897             :         }
     898             : 
     899   297994722 :         memcpy(buf, v->data, v->length);
     900   297994722 :         errno = 0;
     901   297994722 :         ret = (unsigned int) strtoll(buf, &end, 10);
     902   297994722 :         if (errno != 0) {
     903           0 :                 errno = 0;
     904           0 :                 ret = (unsigned int) strtoull(buf, &end, 10);
     905           0 :                 if (errno != 0) {
     906           0 :                         return default_value;
     907             :                 }
     908             :         }
     909   297994722 :         if (end && end[0] != '\0') {
     910           0 :                 return default_value;
     911             :         }
     912   290674107 :         return ret;
     913             : }
     914             : 
     915     2515223 : int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
     916             :                                    const char *attr_name,
     917             :                                    int64_t default_value)
     918             : {
     919     2515223 :         int64_t val = 0;
     920     2515223 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     921     2515223 :         int ret = ldb_val_as_int64(v, &val);
     922     2515223 :         return ret ? default_value : val;
     923             : }
     924             : 
     925     2515546 : int ldb_val_as_int64(const struct ldb_val *v, int64_t *val)
     926             : {
     927     2515546 :         char buf[sizeof("-9223372036854775808")] = {};
     928     2515546 :         char *end = NULL;
     929       72116 :         int64_t result;
     930             : 
     931     2515546 :         if (!v || !v->data) {
     932      540283 :                 return LDB_ERR_OPERATIONS_ERROR;
     933             :         }
     934             : 
     935     1959547 :         if (v->length >= sizeof(buf)) {
     936           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     937             :         }
     938             : 
     939     1959547 :         memcpy(buf, v->data, v->length);
     940     1959547 :         errno = 0;
     941     1959547 :         result = (int64_t) strtoll(buf, &end, 10);
     942     1959547 :         if (errno != 0) {
     943           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     944             :         }
     945     1959547 :         if (end && end[0] != '\0') {
     946           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     947             :         }
     948             : 
     949     1959547 :         *val = result;
     950     1959547 :         return LDB_SUCCESS;
     951             : }
     952             : 
     953   247656834 : uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
     954             :                                      const char *attr_name,
     955             :                                      uint64_t default_value)
     956             : {
     957   247656834 :         uint64_t val = 0;
     958   247656834 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     959   247656834 :         int ret = ldb_val_as_uint64(v, &val);
     960   247656834 :         return ret ? default_value : val;
     961             : }
     962             : 
     963   247656834 : int ldb_val_as_uint64(const struct ldb_val *v, uint64_t *val)
     964             : {
     965   247656834 :         char buf[sizeof("-9223372036854775808")] = {};
     966   247656834 :         char *end = NULL;
     967     6826432 :         uint64_t result;
     968             : 
     969   247656834 :         if (!v || !v->data) {
     970   112563599 :                 return LDB_ERR_OPERATIONS_ERROR;
     971             :         }
     972             : 
     973   132253533 :         if (v->length >= sizeof(buf)) {
     974           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     975             :         }
     976             : 
     977   132253533 :         memcpy(buf, v->data, v->length);
     978   132253533 :         errno = 0;
     979   132253533 :         result = (uint64_t) strtoll(buf, &end, 10);
     980   132253533 :         if (errno != 0) {
     981           0 :                 errno = 0;
     982           0 :                 result = (uint64_t) strtoull(buf, &end, 10);
     983           0 :                 if (errno != 0) {
     984           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     985             :                 }
     986             :         }
     987   132253533 :         if (end && end[0] != '\0') {
     988           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     989             :         }
     990             : 
     991   132253533 :         *val = result;
     992   132253533 :         return LDB_SUCCESS;
     993             : }
     994             : 
     995           0 : double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
     996             :                                    const char *attr_name,
     997             :                                    double default_value)
     998             : {
     999           0 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1000           0 :         char *buf;
    1001           0 :         char *end = NULL;
    1002           0 :         double ret;
    1003             : 
    1004           0 :         if (!v || !v->data) {
    1005           0 :                 return default_value;
    1006             :         }
    1007           0 :         buf = talloc_strndup(msg, (const char *)v->data, v->length);
    1008           0 :         if (buf == NULL) {
    1009           0 :                 return default_value;
    1010             :         }
    1011             : 
    1012           0 :         errno = 0;
    1013           0 :         ret = strtod(buf, &end);
    1014           0 :         talloc_free(buf);
    1015           0 :         if (errno != 0) {
    1016           0 :                 return default_value;
    1017             :         }
    1018           0 :         if (end && end[0] != '\0') {
    1019           0 :                 return default_value;
    1020             :         }
    1021           0 :         return ret;
    1022             : }
    1023             : 
    1024     8366051 : int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
    1025             :                               const char *attr_name,
    1026             :                               int default_value)
    1027             : {
    1028     8366051 :         bool val = false;
    1029     8366051 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1030     8366051 :         int ret = ldb_val_as_bool(v, &val);
    1031     8366051 :         return ret ? default_value : val;
    1032             : }
    1033             : 
    1034     8366080 : int ldb_val_as_bool(const struct ldb_val *v, bool *val)
    1035             : {
    1036     8366080 :         if (!v || !v->data) {
    1037     2881459 :                 return LDB_ERR_OPERATIONS_ERROR;
    1038             :         }
    1039     5484368 :         if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
    1040       84567 :                 *val = false;
    1041       84567 :                 return LDB_SUCCESS;
    1042             :         }
    1043     5399801 :         if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
    1044     5399801 :                 *val = true;
    1045     5399801 :                 return LDB_SUCCESS;
    1046             :         }
    1047           0 :         return LDB_ERR_OPERATIONS_ERROR;
    1048             : }
    1049             : 
    1050   774528709 : const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
    1051             :                                         const char *attr_name,
    1052             :                                         const char *default_value)
    1053             : {
    1054   774528709 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1055   774528709 :         if (!v || !v->data) {
    1056   481361069 :                 return default_value;
    1057             :         }
    1058   281165902 :         if (v->data[v->length] != '\0') {
    1059           0 :                 return default_value;
    1060             :         }
    1061   274214936 :         return (const char *)v->data;
    1062             : }
    1063             : 
    1064     5682271 : struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
    1065             :                                        TALLOC_CTX *mem_ctx,
    1066             :                                        const struct ldb_message *msg,
    1067             :                                        const char *attr_name)
    1068             : {
    1069     5682271 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1070     5682271 :         return ldb_val_as_dn(ldb, mem_ctx, v);
    1071             : }
    1072             : 
    1073     5687354 : struct ldb_dn *ldb_val_as_dn(struct ldb_context *ldb,
    1074             :                              TALLOC_CTX *mem_ctx,
    1075             :                              const struct ldb_val *v)
    1076             : {
    1077      163015 :         struct ldb_dn *res_dn;
    1078             : 
    1079     5687354 :         if (!v || !v->data) {
    1080     1134439 :                 return NULL;
    1081             :         }
    1082     4450445 :         res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
    1083     4450445 :         if ( ! ldb_dn_validate(res_dn)) {
    1084           0 :                 talloc_free(res_dn);
    1085           0 :                 return NULL;
    1086             :         }
    1087     4389900 :         return res_dn;
    1088             : }
    1089             : 
    1090             : /*
    1091             :   sort the elements of a message by name
    1092             : */
    1093     1698408 : void ldb_msg_sort_elements(struct ldb_message *msg)
    1094             : {
    1095     1698408 :         TYPESAFE_QSORT(msg->elements, msg->num_elements,
    1096             :                        ldb_msg_element_compare_name);
    1097     1698408 : }
    1098             : 
    1099     9761680 : static struct ldb_message *ldb_msg_copy_shallow_impl(TALLOC_CTX *mem_ctx,
    1100             :                                          const struct ldb_message *msg)
    1101             : {
    1102      869211 :         struct ldb_message *msg2;
    1103      869211 :         unsigned int i;
    1104             : 
    1105     9761680 :         msg2 = talloc(mem_ctx, struct ldb_message);
    1106     9761680 :         if (msg2 == NULL) return NULL;
    1107             : 
    1108     9761680 :         *msg2 = *msg;
    1109             : 
    1110     9761680 :         msg2->elements = talloc_array(msg2, struct ldb_message_element,
    1111             :                                       msg2->num_elements);
    1112     9761680 :         if (msg2->elements == NULL) goto failed;
    1113             : 
    1114   107808635 :         for (i=0;i<msg2->num_elements;i++) {
    1115    98046955 :                 msg2->elements[i] = msg->elements[i];
    1116             :         }
    1117             : 
    1118     8892469 :         return msg2;
    1119             : 
    1120           0 : failed:
    1121           0 :         talloc_free(msg2);
    1122           0 :         return NULL;
    1123             : }
    1124             : 
    1125             : /*
    1126             :   shallow copy a message - copying only the elements array so that the caller
    1127             :   can safely add new elements without changing the message
    1128             : */
    1129     7888980 : struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
    1130             :                                          const struct ldb_message *msg)
    1131             : {
    1132      716913 :         struct ldb_message *msg2;
    1133      716913 :         unsigned int i;
    1134             : 
    1135     7888980 :         msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
    1136     7888980 :         if (msg2 == NULL) {
    1137           0 :                 return NULL;
    1138             :         }
    1139             : 
    1140    64909155 :         for (i = 0; i < msg2->num_elements; ++i) {
    1141             :                 /*
    1142             :                  * Mark this message's elements as sharing their values with the
    1143             :                  * original message, so that we don't inadvertently modify or
    1144             :                  * free them. We don't mark the original message element as
    1145             :                  * shared, so the original message element should not be
    1146             :                  * modified or freed while the shallow copy lives.
    1147             :                  */
    1148    57020175 :                 struct ldb_message_element *el = &msg2->elements[i];
    1149    57020175 :                 el->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
    1150             :         }
    1151             : 
    1152     7172067 :         return msg2;
    1153             : }
    1154             : 
    1155             : /*
    1156             :   copy a message, allocating new memory for all parts
    1157             : */
    1158     1872700 : struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
    1159             :                                  const struct ldb_message *msg)
    1160             : {
    1161      152298 :         struct ldb_message *msg2;
    1162      152298 :         unsigned int i, j;
    1163             : 
    1164     1872700 :         msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
    1165     1872700 :         if (msg2 == NULL) return NULL;
    1166             : 
    1167     1872700 :         if (msg2->dn != NULL) {
    1168     1872685 :                 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
    1169     1872685 :                 if (msg2->dn == NULL) goto failed;
    1170             :         }
    1171             : 
    1172    42899480 :         for (i=0;i<msg2->num_elements;i++) {
    1173    41026780 :                 struct ldb_message_element *el = &msg2->elements[i];
    1174    41026780 :                 struct ldb_val *values = el->values;
    1175    41026780 :                 if (el->name != NULL) {
    1176    41026780 :                         el->name = talloc_strdup(msg2->elements, el->name);
    1177    41026780 :                         if (el->name == NULL) goto failed;
    1178             :                 }
    1179    41026780 :                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
    1180    41026780 :                 if (el->values == NULL) goto failed;
    1181    91032343 :                 for (j=0;j<el->num_values;j++) {
    1182    50005563 :                         el->values[j] = ldb_val_dup(el->values, &values[j]);
    1183    50005563 :                         if (el->values[j].data == NULL && values[j].length != 0) {
    1184           0 :                                 goto failed;
    1185             :                         }
    1186             :                 }
    1187             : 
    1188             :                 /*
    1189             :                  * Since we copied this element's values, we can mark them as
    1190             :                  * not shared.
    1191             :                  */
    1192    41026780 :                 el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
    1193             :         }
    1194             : 
    1195     1720402 :         return msg2;
    1196             : 
    1197           0 : failed:
    1198           0 :         talloc_free(msg2);
    1199           0 :         return NULL;
    1200             : }
    1201             : 
    1202             : 
    1203             : /**
    1204             :  * Canonicalize a message, merging elements of the same name
    1205             :  */
    1206           0 : struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
    1207             :                                          const struct ldb_message *msg)
    1208             : {
    1209           0 :         int ret;
    1210           0 :         struct ldb_message *msg2;
    1211             : 
    1212             :         /*
    1213             :          * Preserve previous behavior and allocate
    1214             :          * *msg2 into *ldb context
    1215             :          */
    1216           0 :         ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
    1217           0 :         if (ret != LDB_SUCCESS) {
    1218           0 :                 return NULL;
    1219             :         }
    1220             : 
    1221           0 :         return msg2;
    1222             : }
    1223             : 
    1224             : /**
    1225             :  * Canonicalize a message, merging elements of the same name
    1226             :  */
    1227     1697782 : int ldb_msg_normalize(struct ldb_context *ldb,
    1228             :                       TALLOC_CTX *mem_ctx,
    1229             :                       const struct ldb_message *msg,
    1230             :                       struct ldb_message **_msg_out)
    1231             : {
    1232      141899 :         unsigned int i;
    1233      141899 :         struct ldb_message *msg2;
    1234             : 
    1235     1697782 :         msg2 = ldb_msg_copy(mem_ctx, msg);
    1236     1697782 :         if (msg2 == NULL) {
    1237           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1238             :         }
    1239             : 
    1240     1697782 :         ldb_msg_sort_elements(msg2);
    1241             : 
    1242    39641466 :         for (i=1; i < msg2->num_elements; i++) {
    1243    37801785 :                 struct ldb_message_element *el1 = &msg2->elements[i-1];
    1244    37801785 :                 struct ldb_message_element *el2 = &msg2->elements[i];
    1245             : 
    1246    37801785 :                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
    1247       15377 :                         el1->values = talloc_realloc(msg2->elements,
    1248             :                                                      el1->values, struct ldb_val,
    1249             :                                                      el1->num_values + el2->num_values);
    1250       15377 :                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
    1251           0 :                                 talloc_free(msg2);
    1252           0 :                                 return LDB_ERR_OPERATIONS_ERROR;
    1253             :                         }
    1254       15377 :                         memcpy(el1->values + el1->num_values,
    1255       15377 :                                el2->values,
    1256       15377 :                                sizeof(struct ldb_val) * el2->num_values);
    1257       15377 :                         el1->num_values += el2->num_values;
    1258       15377 :                         talloc_free(discard_const_p(char, el2->name));
    1259       15377 :                         if ((i+1) < msg2->num_elements) {
    1260         626 :                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
    1261           0 :                                         (msg2->num_elements - (i+1)));
    1262             :                         }
    1263       15377 :                         msg2->num_elements--;
    1264       15377 :                         i--;
    1265             :                 }
    1266             :         }
    1267             : 
    1268     1697782 :         *_msg_out = msg2;
    1269     1697782 :         return LDB_SUCCESS;
    1270             : }
    1271             : 
    1272             : 
    1273             : /**
    1274             :  * return a ldb_message representing the differences between msg1 and msg2.
    1275             :  * If you then use this in a ldb_modify() call,
    1276             :  * it can be used to save edits to a message
    1277             :  */
    1278           0 : struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
    1279             :                                  struct ldb_message *msg1,
    1280             :                                  struct ldb_message *msg2)
    1281             : {
    1282           0 :         int ldb_ret;
    1283           0 :         struct ldb_message *mod;
    1284             : 
    1285           0 :         ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
    1286           0 :         if (ldb_ret != LDB_SUCCESS) {
    1287           0 :                 return NULL;
    1288             :         }
    1289             : 
    1290           0 :         return mod;
    1291             : }
    1292             : 
    1293             : /**
    1294             :  * return a ldb_message representing the differences between msg1 and msg2.
    1295             :  * If you then use this in a ldb_modify() call it can be used to save edits to a message
    1296             :  *
    1297             :  * Result message is constructed as follows:
    1298             :  * - LDB_FLAG_MOD_ADD     - elements found only in msg2
    1299             :  * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
    1300             :  *                          Value for msg2 element is used
    1301             :  * - LDB_FLAG_MOD_DELETE  - elements found only in msg2
    1302             :  *
    1303             :  * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
    1304             :  */
    1305       91548 : int ldb_msg_difference(struct ldb_context *ldb,
    1306             :                        TALLOC_CTX *mem_ctx,
    1307             :                        struct ldb_message *msg1,
    1308             :                        struct ldb_message *msg2,
    1309             :                        struct ldb_message **_msg_out)
    1310             : {
    1311        2259 :         int ldb_res;
    1312        2259 :         unsigned int i;
    1313        2259 :         struct ldb_message *mod;
    1314        2259 :         struct ldb_message_element *el;
    1315        2259 :         TALLOC_CTX *temp_ctx;
    1316             : 
    1317       91548 :         temp_ctx = talloc_new(mem_ctx);
    1318       91548 :         if (!temp_ctx) {
    1319           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1320             :         }
    1321             : 
    1322       91548 :         mod = ldb_msg_new(temp_ctx);
    1323       91548 :         if (mod == NULL) {
    1324           0 :                 goto failed;
    1325             :         }
    1326             : 
    1327       91548 :         mod->dn = msg1->dn;
    1328       91548 :         mod->num_elements = 0;
    1329       91548 :         mod->elements = NULL;
    1330             : 
    1331             :         /*
    1332             :          * Canonicalize *msg2 so we have no repeated elements
    1333             :          * Resulting message is allocated in *mod's mem context,
    1334             :          * as we are going to move some elements from *msg2 to
    1335             :          * *mod object later
    1336             :          */
    1337       91548 :         ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
    1338       91548 :         if (ldb_res != LDB_SUCCESS) {
    1339           0 :                 goto failed;
    1340             :         }
    1341             : 
    1342             :         /* look in msg2 to find elements that need to be added or modified */
    1343    21943429 :         for (i=0;i<msg2->num_elements;i++) {
    1344    21851881 :                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
    1345             : 
    1346    21851881 :                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
    1347    21793902 :                         continue;
    1348             :                 }
    1349             : 
    1350       57979 :                 ldb_res = ldb_msg_add(mod,
    1351       57979 :                                       &msg2->elements[i],
    1352             :                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
    1353       57979 :                 if (ldb_res != LDB_SUCCESS) {
    1354           0 :                         goto failed;
    1355             :                 }
    1356             :         }
    1357             : 
    1358             :         /* look in msg1 to find elements that need to be deleted */
    1359    21944166 :         for (i=0;i<msg1->num_elements;i++) {
    1360    21852618 :                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
    1361    21852618 :                 if (el == NULL) {
    1362        2043 :                         ldb_res = ldb_msg_add_empty(mod,
    1363        2029 :                                                     msg1->elements[i].name,
    1364             :                                                     LDB_FLAG_MOD_DELETE, NULL);
    1365        2029 :                         if (ldb_res != LDB_SUCCESS) {
    1366           0 :                                 goto failed;
    1367             :                         }
    1368             :                 }
    1369             :         }
    1370             : 
    1371             :         /* steal resulting message into supplied context */
    1372       91548 :         talloc_steal(mem_ctx, mod);
    1373       91548 :         *_msg_out = mod;
    1374             : 
    1375       91548 :         talloc_free(temp_ctx);
    1376       91548 :         return LDB_SUCCESS;
    1377             : 
    1378           0 : failed:
    1379           0 :         talloc_free(temp_ctx);
    1380           0 :         return LDB_ERR_OPERATIONS_ERROR;
    1381             : }
    1382             : 
    1383             : 
    1384     1396985 : int ldb_msg_sanity_check(struct ldb_context *ldb,
    1385             :                          const struct ldb_message *msg)
    1386             : {
    1387      117446 :         unsigned int i, j;
    1388             : 
    1389             :         /* basic check on DN */
    1390     1396985 :         if (msg->dn == NULL) {
    1391           0 :                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
    1392           0 :                 return LDB_ERR_INVALID_DN_SYNTAX;
    1393             :         }
    1394             : 
    1395             :         /* basic syntax checks */
    1396     8381039 :         for (i = 0; i < msg->num_elements; i++) {
    1397    16406648 :                 for (j = 0; j < msg->elements[i].num_values; j++) {
    1398     9422594 :                         if (msg->elements[i].values[j].length == 0) {
    1399             :                                 /* an attribute cannot be empty */
    1400           4 :                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
    1401           2 :                                                             msg->elements[i].name,
    1402           2 :                                                             ldb_dn_get_linearized(msg->dn));
    1403           2 :                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1404             :                         }
    1405             :                 }
    1406             :         }
    1407             : 
    1408     1279537 :         return LDB_SUCCESS;
    1409             : }
    1410             : 
    1411             : 
    1412             : 
    1413             : 
    1414             : /*
    1415             :   copy an attribute list. This only copies the array, not the elements
    1416             :   (ie. the elements are left as the same pointers)
    1417             : */
    1418    10318000 : const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
    1419             : {
    1420      206085 :         const char **ret;
    1421      206085 :         unsigned int i;
    1422             : 
    1423   311071705 :         for (i=0;attrs && attrs[i];i++) /* noop */ ;
    1424    10318000 :         ret = talloc_array(mem_ctx, const char *, i+1);
    1425    10318000 :         if (ret == NULL) {
    1426           0 :                 return NULL;
    1427             :         }
    1428   311071705 :         for (i=0;attrs && attrs[i];i++) {
    1429   300753705 :                 ret[i] = attrs[i];
    1430             :         }
    1431    10318000 :         ret[i] = attrs[i];
    1432    10318000 :         return ret;
    1433             : }
    1434             : 
    1435             : 
    1436             : /*
    1437             :   copy an attribute list. This only copies the array, not the elements
    1438             :   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
    1439             : */
    1440    11111693 : const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
    1441             : {
    1442      230349 :         const char **ret;
    1443      230349 :         unsigned int i;
    1444    11111693 :         bool found = false;
    1445             : 
    1446   293381698 :         for (i=0;attrs && attrs[i];i++) {
    1447   282270005 :                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
    1448     7950947 :                         found = true;
    1449             :                 }
    1450             :         }
    1451    11111693 :         if (found) {
    1452     7082552 :                 return ldb_attr_list_copy(mem_ctx, attrs);
    1453             :         }
    1454     4029141 :         ret = talloc_array(mem_ctx, const char *, i+2);
    1455     4029141 :         if (ret == NULL) {
    1456           0 :                 return NULL;
    1457             :         }
    1458    38408248 :         for (i=0;attrs && attrs[i];i++) {
    1459    34379107 :                 ret[i] = attrs[i];
    1460             :         }
    1461     4029141 :         ret[i] = new_attr;
    1462     4029141 :         ret[i+1] = NULL;
    1463     4029141 :         return ret;
    1464             : }
    1465             : 
    1466             : 
    1467             : /*
    1468             :   return 1 if an attribute is in a list of attributes, or 0 otherwise
    1469             : */
    1470  2337323433 : int ldb_attr_in_list(const char * const *attrs, const char *attr)
    1471             : {
    1472    95670673 :         unsigned int i;
    1473  6402006785 :         for (i=0;attrs && attrs[i];i++) {
    1474  4163919928 :                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
    1475    97929441 :                         return 1;
    1476             :                 }
    1477             :         }
    1478  2143723319 :         return 0;
    1479             : }
    1480             : 
    1481             : 
    1482             : /*
    1483             :   rename the specified attribute in a search result
    1484             : */
    1485           3 : int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
    1486             : {
    1487           3 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
    1488           3 :         if (el == NULL) {
    1489           0 :                 return LDB_SUCCESS;
    1490             :         }
    1491           3 :         el->name = talloc_strdup(msg->elements, replace);
    1492           3 :         if (el->name == NULL) {
    1493           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1494             :         }
    1495           3 :         return LDB_SUCCESS;
    1496             : }
    1497             : 
    1498             : 
    1499             : /*
    1500             :   copy the specified attribute in a search result to a new attribute
    1501             : */
    1502           3 : int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
    1503             : {
    1504           3 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
    1505           0 :         int ret;
    1506             : 
    1507           3 :         if (el == NULL) {
    1508           0 :                 return LDB_SUCCESS;
    1509             :         }
    1510           3 :         ret = ldb_msg_add(msg, el, 0);
    1511           3 :         if (ret != LDB_SUCCESS) {
    1512           0 :                 return ret;
    1513             :         }
    1514           3 :         return ldb_msg_rename_attr(msg, attr, replace);
    1515             : }
    1516             : 
    1517             : /*
    1518             :   remove the specified element in a search result
    1519             : */
    1520     8889251 : void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
    1521             : {
    1522     8889251 :         ptrdiff_t n = (el - msg->elements);
    1523     8889251 :         if (n >= msg->num_elements || n < 0) {
    1524             :                 /* the element is not in the list. the caller is crazy. */
    1525           0 :                 return;
    1526             :         }
    1527     8889251 :         msg->num_elements--;
    1528     8889251 :         if (n != msg->num_elements) {
    1529     4995366 :                 memmove(el, el+1, (msg->num_elements - n)*sizeof(*el));
    1530             :         }
    1531             : }
    1532             : 
    1533             : 
    1534             : /*
    1535             :   remove the specified attribute in a search result
    1536             : */
    1537  2607131219 : void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
    1538             : {
    1539    77598369 :         unsigned int i;
    1540  2607131219 :         unsigned int num_del = 0;
    1541             : 
    1542 31744680255 :         for (i = 0; i < msg->num_elements; ++i) {
    1543 29137549036 :                 if (ldb_attr_cmp(msg->elements[i].name, attr) == 0) {
    1544    58491922 :                         ++num_del;
    1545 29079057114 :                 } else if (num_del) {
    1546   113683004 :                         msg->elements[i - num_del] = msg->elements[i];
    1547             :                 }
    1548             :         }
    1549             : 
    1550  2607131219 :         msg->num_elements -= num_del;
    1551  2607131219 : }
    1552             : 
    1553             : /* Reallocate elements to drop any excess capacity. */
    1554   169725518 : void ldb_msg_shrink_to_fit(struct ldb_message *msg)
    1555             : {
    1556   169725518 :         if (msg->num_elements > 0) {
    1557   150821403 :                 struct ldb_message_element *elements = talloc_realloc(msg,
    1558             :                                                                       msg->elements,
    1559             :                                                                       struct ldb_message_element,
    1560             :                                                                       msg->num_elements);
    1561   150821403 :                 if (elements != NULL) {
    1562   150821403 :                         msg->elements = elements;
    1563             :                 }
    1564             :         } else {
    1565    18904115 :                 TALLOC_FREE(msg->elements);
    1566             :         }
    1567   169725518 : }
    1568             : 
    1569             : /*
    1570             :   return a LDAP formatted GeneralizedTime string
    1571             : */
    1572     6369036 : char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
    1573             : {
    1574     6369036 :         struct tm *tm = gmtime(&t);
    1575      374997 :         char *ts;
    1576      374997 :         int r;
    1577             : 
    1578     6369036 :         if (!tm) {
    1579           2 :                 return NULL;
    1580             :         }
    1581             : 
    1582             :         /* we know exactly how long this string will be */
    1583     6369034 :         ts = talloc_array(mem_ctx, char, 18);
    1584             : 
    1585             :         /* formatted like: 20040408072012.0Z */
    1586     6369034 :         r = snprintf(ts, 18,
    1587             :                         "%04u%02u%02u%02u%02u%02u.0Z",
    1588     6369034 :                         tm->tm_year+1900, tm->tm_mon+1,
    1589             :                         tm->tm_mday, tm->tm_hour, tm->tm_min,
    1590             :                         tm->tm_sec);
    1591             : 
    1592     6369034 :         if (r != 17) {
    1593           4 :                 talloc_free(ts);
    1594           4 :                 errno = EOVERFLOW;
    1595           4 :                 return NULL;
    1596             :         }
    1597             : 
    1598     5994033 :         return ts;
    1599             : }
    1600             : 
    1601             : /*
    1602             :   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
    1603             : */
    1604       23489 : time_t ldb_string_to_time(const char *s)
    1605             : {
    1606          72 :         struct tm tm;
    1607          72 :         time_t t;
    1608             : 
    1609       23489 :         if (s == NULL) return 0;
    1610             : 
    1611       23463 :         memset(&tm, 0, sizeof(tm));
    1612       23463 :         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
    1613             :                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1614             :                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1615           0 :                 return 0;
    1616             :         }
    1617       23463 :         tm.tm_year -= 1900;
    1618       23463 :         tm.tm_mon -= 1;
    1619             : 
    1620       23463 :         t = timegm(&tm);
    1621             : 
    1622       23463 :         if (t == (time_t)-1 && errno != 0) {
    1623             :                 /*
    1624             :                  * timegm() returns -1 on error, but also for '19691231235959.0Z'.
    1625             :                  */
    1626           0 :                 return 0;
    1627             :         }
    1628       23391 :         return t;
    1629             : }
    1630             : 
    1631             : /*
    1632             :   convert a LDAP GeneralizedTime string in ldb_val format to a
    1633             :   time_t.
    1634             : */
    1635     4730068 : int ldb_val_to_time(const struct ldb_val *v, time_t *t)
    1636             : {
    1637     4730068 :         char val[15] = {0};
    1638     4730068 :         struct tm tm = {
    1639             :                 .tm_year = 0,
    1640             :         };
    1641             : 
    1642     4730068 :         if (v == NULL) {
    1643         260 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1644             :         }
    1645             : 
    1646     4729808 :         if (v->data == NULL) {
    1647           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1648             :         }
    1649             : 
    1650     4729808 :         if (v->length < 16 && v->length != 13) {
    1651           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1652             :         }
    1653             : 
    1654     4729808 :         if (v->data[v->length - 1] != 'Z') {
    1655           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1656             :         }
    1657             : 
    1658     4729808 :         if (v->length == 13) {
    1659         535 :                 memcpy(val, v->data, 12);
    1660             : 
    1661         535 :                 if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
    1662             :                         &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1663             :                         &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1664           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1665             :                 }
    1666         535 :                 if (tm.tm_year < 50) {
    1667         535 :                         tm.tm_year += 100;
    1668             :                 }
    1669             :         } else {
    1670             : 
    1671             :                 /*
    1672             :                  * anything between '.' and 'Z' is silently ignored.
    1673             :                  */
    1674     4729273 :                 if (v->data[14] != '.') {
    1675           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1676             :                 }
    1677             : 
    1678     4729273 :                 memcpy(val, v->data, 14);
    1679             : 
    1680     4729273 :                 if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
    1681             :                         &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1682             :                         &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1683           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1684             :                 }
    1685     4729273 :                 tm.tm_year -= 1900;
    1686             :         }
    1687     4729808 :         tm.tm_mon -= 1;
    1688             : 
    1689     4729808 :         *t = timegm(&tm);
    1690             : 
    1691     4729808 :         return LDB_SUCCESS;
    1692             : }
    1693             : 
    1694             : /*
    1695             :   return a LDAP formatted UTCTime string
    1696             : */
    1697          63 : char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
    1698             : {
    1699          63 :         struct tm *tm = gmtime(&t);
    1700           3 :         char *ts;
    1701           3 :         int r;
    1702             : 
    1703          63 :         if (!tm) {
    1704           0 :                 return NULL;
    1705             :         }
    1706             : 
    1707             :         /* we know exactly how long this string will be */
    1708          63 :         ts = talloc_array(mem_ctx, char, 14);
    1709             : 
    1710             :         /* formatted like: 20040408072012.0Z => 040408072012Z */
    1711          63 :         r = snprintf(ts, 14,
    1712             :                         "%02u%02u%02u%02u%02u%02uZ",
    1713          63 :                         (tm->tm_year+1900)%100, tm->tm_mon+1,
    1714             :                         tm->tm_mday, tm->tm_hour, tm->tm_min,
    1715             :                         tm->tm_sec);
    1716             : 
    1717          63 :         if (r != 13) {
    1718           0 :                 talloc_free(ts);
    1719           0 :                 return NULL;
    1720             :         }
    1721             : 
    1722          60 :         return ts;
    1723             : }
    1724             : 
    1725             : /*
    1726             :   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
    1727             : */
    1728           0 : time_t ldb_string_utc_to_time(const char *s)
    1729             : {
    1730           0 :         struct tm tm;
    1731             : 
    1732           0 :         if (s == NULL) return 0;
    1733             : 
    1734           0 :         memset(&tm, 0, sizeof(tm));
    1735           0 :         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
    1736             :                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1737             :                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1738           0 :                 return 0;
    1739             :         }
    1740           0 :         if (tm.tm_year < 50) {
    1741           0 :                 tm.tm_year += 100;
    1742             :         }
    1743           0 :         tm.tm_mon -= 1;
    1744             : 
    1745           0 :         return timegm(&tm);
    1746             : }
    1747             : 
    1748             : 
    1749             : /*
    1750             :   dump a set of results to a file. Useful from within gdb
    1751             : */
    1752           0 : void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
    1753             : {
    1754           0 :         unsigned int i;
    1755             : 
    1756           0 :         for (i = 0; i < result->count; i++) {
    1757           0 :                 struct ldb_ldif ldif;
    1758           0 :                 fprintf(f, "# record %d\n", i+1);
    1759           0 :                 ldif.changetype = LDB_CHANGETYPE_NONE;
    1760           0 :                 ldif.msg = result->msgs[i];
    1761           0 :                 ldb_ldif_write_file(ldb, f, &ldif);
    1762             :         }
    1763           0 : }
    1764             : 
    1765             : /*
    1766             :   checks for a string attribute. Returns "1" on match and otherwise "0".
    1767             : */
    1768     3260954 : int ldb_msg_check_string_attribute(const struct ldb_message *msg,
    1769             :                                    const char *name, const char *value)
    1770             : {
    1771       45034 :         struct ldb_message_element *el;
    1772       45034 :         struct ldb_val val;
    1773             : 
    1774     3260954 :         el = ldb_msg_find_element(msg, name);
    1775     3260954 :         if (el == NULL) {
    1776     1580986 :                 return 0;
    1777             :         }
    1778             : 
    1779     1656065 :         val.data = discard_const_p(uint8_t, value);
    1780     1656065 :         val.length = strlen(value);
    1781             : 
    1782     1656065 :         if (ldb_msg_find_val(el, &val)) {
    1783     1655267 :                 return 1;
    1784             :         }
    1785             : 
    1786         798 :         return 0;
    1787             : }
    1788             : 
    1789             : 
    1790             : /*
    1791             :   compare a ldb_val to a string
    1792             : */
    1793     3389170 : int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
    1794             : {
    1795     3389170 :         size_t len = strlen(str);
    1796     3389170 :         if (len != v->length) {
    1797           0 :                 return len - v->length;
    1798             :         }
    1799     3389170 :         return strncmp((const char *)v->data, str, len);
    1800             : }

Generated by: LCOV version 1.14