LCOV - code coverage report
Current view: top level - lib/ldb/common - ldb_msg.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 557 689 80.8 %
Date: 2024-02-14 10:14:15 Functions: 60 66 90.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   553555953 : struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
      40             : {
      41   553555953 :         return talloc_zero(mem_ctx, struct ldb_message);
      42             : }
      43             : 
      44             : /*
      45             :   find an element in a message by attribute name
      46             : */
      47  7005463381 : struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
      48             :                                                  const char *attr_name)
      49             : {
      50             :         unsigned int i;
      51 >10026*10^7 :         for (i=0;i<msg->num_elements;i++) {
      52 95327674676 :                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
      53  2068958192 :                         return &msg->elements[i];
      54             :                 }
      55             :         }
      56  4936505189 :         return NULL;
      57             : }
      58             : 
      59             : /*
      60             :   see if two ldb_val structures contain exactly the same data
      61             :   return 1 for a match, 0 for a mis-match
      62             : */
      63   243962845 : int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
      64             : {
      65   243962845 :         if (v1->length != v2->length) return 0;
      66    41928353 :         if (v1->data == v2->data) return 1;
      67    41847577 :         if (v1->length == 0) return 1;
      68             : 
      69    41847577 :         if (memcmp(v1->data, v2->data, v1->length) == 0) {
      70    25772410 :                 return 1;
      71             :         }
      72             : 
      73    16075167 :         return 0;
      74             : }
      75             : 
      76             : /*
      77             :   find a value in an element
      78             :   assumes case sensitive comparison
      79             : */
      80    19617588 : struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
      81             :                                  struct ldb_val *val)
      82             : {
      83             :         unsigned int i;
      84   227114507 :         for (i=0;i<el->num_values;i++) {
      85   226862394 :                 if (ldb_val_equal_exact(val, &el->values[i])) {
      86    19365475 :                         return &el->values[i];
      87             :                 }
      88             :         }
      89      252113 :         return NULL;
      90             : }
      91             : 
      92             : 
      93     6474715 : static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
      94             : {
      95     6474715 :         if (v1->length != v2->length) {
      96     5423411 :                 return v1->length - v2->length;
      97             :         }
      98     1051304 :         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    22413481 : 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             :         unsigned int i, j;
     118             :         struct ldb_val *val;
     119             : 
     120    22413481 :         if (options != 0) {
     121           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     122             :         }
     123             : 
     124    22413481 :         *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    22413481 :         if (el->num_values < LDB_DUP_QUADRATIC_THRESHOLD) {
     131    46665647 :                 for (j = 0; j < el->num_values; j++) {
     132    24294357 :                         val = &el->values[j];
     133    28035457 :                         for ( i = j + 1; i < el->num_values; i++) {
     134     3741104 :                                 if (ldb_val_equal_exact(val, &el->values[i])) {
     135           4 :                                         *duplicate = val;
     136           4 :                                         return LDB_SUCCESS;
     137             :                                 }
     138             :                         }
     139             :                 }
     140             :         } else {
     141             :                 struct ldb_val *values;
     142       42187 :                 values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
     143       42187 :                 if (values == NULL) {
     144           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     145             :                 }
     146             : 
     147       42187 :                 memcpy(values, el->values,
     148       42187 :                        el->num_values * sizeof(struct ldb_val));
     149       42187 :                 TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
     150     1513411 :                 for (i = 1; i < el->num_values; i++) {
     151     1471225 :                         if (ldb_val_equal_exact(&values[i],
     152     1471225 :                                                 &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       42186 :                 talloc_free(values);
     171             :         }
     172    22413476 :         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        3659 : 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             :         struct ldb_val *values;
     198             :         struct ldb_val *values2;
     199             :         unsigned int i, j, k, n_values;
     200             : 
     201        3659 :         bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
     202             : 
     203        3659 :         if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
     204           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     205             :         }
     206             : 
     207        3659 :         if (strcmp(el->name, el2->name) != 0) {
     208           1 :                 return LDB_ERR_INAPPROPRIATE_MATCHING;
     209             :         }
     210        3658 :         if (el->num_values == 0 || el2->num_values == 0) {
     211          12 :                 return LDB_SUCCESS;
     212             :         }
     213             :         /*
     214             :            With few values, it is better to do the brute-force search than the
     215             :            clever search involving tallocs, memcpys, sorts, etc.
     216             :         */
     217        3646 :         if (MIN(el->num_values, el2->num_values) == 1 ||
     218         159 :             MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
     219       16036 :                 for (i = 0; i < el2->num_values; i++) {
     220       25503 :                         for (j = 0; j < el->num_values; j++) {
     221       13011 :                                 if (ldb_val_equal_exact(&el->values[j],
     222       13011 :                                                         &el2->values[i])) {
     223           8 :                                         if (! remove_duplicates) {
     224             :                                             return                      \
     225           6 :                                               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        3538 :                 return LDB_SUCCESS;
     242             :         }
     243             : 
     244         102 :         values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
     245         102 :         if (values == NULL) {
     246           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     247             :         }
     248         102 :         values2 = talloc_array(mem_ctx, struct ldb_val,
     249             :                                     el2->num_values);
     250         102 :         if (values2 == NULL) {
     251           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     252             :         }
     253             : 
     254         102 :         memcpy(values, el->values,
     255         102 :                el->num_values * sizeof(struct ldb_val));
     256         102 :         memcpy(values2, el2->values,
     257         102 :                el2->num_values * sizeof(struct ldb_val));
     258         102 :         TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
     259         102 :         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         102 :         n_values = el->num_values;
     266         102 :         i = 0;
     267         102 :         j = 0;
     268        3322 :         while (i != n_values && j < el2->num_values) {
     269        3224 :                 int ret = ldb_val_cmp(&values[i], &values2[j]);
     270        3224 :                 if (ret < 0) {
     271         743 :                         i++;
     272        2481 :                 } else if (ret > 0) {
     273        2463 :                         j++;
     274             :                 } else {
     275             :                         /* we have a collision */
     276          18 :                         if (! remove_duplicates) {
     277           4 :                                 TALLOC_FREE(values);
     278           4 :                                 TALLOC_FREE(values2);
     279           4 :                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
     280             :                         }
     281             :                         /*
     282             :                            With the remove_duplicates flag we need to find
     283             :                            this in the original list and remove it, which is
     284             :                            inefficient but hopefully rare.
     285             :                         */
     286          23 :                         for (k = 0; k < el->num_values; k++) {
     287          23 :                                 if (ldb_val_equal_exact(&el->values[k],
     288          23 :                                                         &values[i])) {
     289          14 :                                         break;
     290             :                                 }
     291             :                         }
     292          14 :                         el->num_values--;
     293          76 :                         for (; k < el->num_values; k++) {
     294          62 :                                 el->values[k] = el->values[k + 1];
     295             :                         }
     296          14 :                         i++;
     297             :                 }
     298             :         }
     299          98 :         TALLOC_FREE(values);
     300          98 :         TALLOC_FREE(values2);
     301             : 
     302          98 :         return LDB_SUCCESS;
     303             : }
     304             : 
     305             : /*
     306             :   duplicate a ldb_val structure
     307             : */
     308  2290511846 : struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
     309             : {
     310             :         struct ldb_val v2;
     311  2290511846 :         v2.length = v->length;
     312  2290511846 :         if (v->data == NULL) {
     313       93122 :                 v2.data = NULL;
     314       93122 :                 return v2;
     315             :         }
     316             : 
     317             :         /* the +1 is to cope with buggy C library routines like strndup
     318             :            that look one byte beyond */
     319  2290418724 :         v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
     320  2290418724 :         if (!v2.data) {
     321           0 :                 v2.length = 0;
     322           0 :                 return v2;
     323             :         }
     324             : 
     325  2290418724 :         memcpy(v2.data, v->data, v->length);
     326  2290418724 :         ((char *)v2.data)[v->length] = 0;
     327  2290418724 :         return v2;
     328             : }
     329             : 
     330             : /**
     331             :  * Adds new empty element to msg->elements
     332             :  */
     333   178746357 : static int _ldb_msg_add_el(struct ldb_message *msg,
     334             :                            struct ldb_message_element **return_el)
     335             : {
     336             :         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   178746357 :         els = talloc_realloc(msg, msg->elements,
     344             :                              struct ldb_message_element, msg->num_elements + 1);
     345   178746357 :         if (!els) {
     346           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     347             :         }
     348             : 
     349   178746357 :         ZERO_STRUCT(els[msg->num_elements]);
     350             : 
     351   178746357 :         msg->elements = els;
     352   178746357 :         msg->num_elements++;
     353             : 
     354   178746357 :         *return_el = &els[msg->num_elements-1];
     355             : 
     356   178746357 :         return LDB_SUCCESS;
     357             : }
     358             : 
     359             : /**
     360             :  * Add an empty element with a given name to a message
     361             :  */
     362   177120184 : 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             :         int ret;
     368             :         struct ldb_message_element *el;
     369             : 
     370   177120184 :         ret = _ldb_msg_add_el(msg, &el);
     371   177120184 :         if (ret != LDB_SUCCESS) {
     372           0 :                 return ret;
     373             :         }
     374             : 
     375             :         /* initialize newly added element */
     376   177120184 :         el->flags = flags;
     377   177120184 :         el->name = talloc_strdup(msg->elements, attr_name);
     378   177120184 :         if (!el->name) {
     379           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     380             :         }
     381             : 
     382   177120184 :         if (return_el) {
     383   176747349 :                 *return_el = el;
     384             :         }
     385             : 
     386   177120184 :         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     1626173 : int ldb_msg_add(struct ldb_message *msg,
     398             :                 const struct ldb_message_element *el,
     399             :                 int flags)
     400             : {
     401             :         int ret;
     402             :         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     1626173 :         struct ldb_message_element el_copy = *el;
     406             : 
     407     1626173 :         ret = _ldb_msg_add_el(msg, &el_new);
     408     1626173 :         if (ret != LDB_SUCCESS) {
     409           0 :                 return ret;
     410             :         }
     411             : 
     412     1626173 :         el_new->flags      = flags;
     413     1626173 :         el_new->name       = el_copy.name;
     414     1626173 :         el_new->num_values = el_copy.num_values;
     415     1626173 :         el_new->values     = el_copy.values;
     416             : 
     417     1626173 :         return LDB_SUCCESS;
     418             : }
     419             : 
     420             : /*
     421             :  * add a value to a message element
     422             :  */
     423   171180802 : int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
     424             :                               struct ldb_message_element *el,
     425             :                               const struct ldb_val *val)
     426             : {
     427             :         struct ldb_val *vals;
     428             : 
     429   171180802 :         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          26 :                 el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
     437             : 
     438          26 :                 vals = talloc_array(mem_ctx, struct ldb_val,
     439             :                                     el->num_values + 1);
     440          26 :                 if (vals == NULL) {
     441           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     442             :                 }
     443             : 
     444          26 :                 if (el->values != NULL) {
     445          26 :                         memcpy(vals, el->values, el->num_values * sizeof(struct ldb_val));
     446             :                 }
     447             :         } else {
     448   171180776 :                 vals = talloc_realloc(mem_ctx, el->values, struct ldb_val,
     449             :                                       el->num_values + 1);
     450   171180776 :                 if (vals == NULL) {
     451           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     452             :                 }
     453             :         }
     454   171180802 :         el->values = vals;
     455   171180802 :         el->values[el->num_values] = *val;
     456   171180802 :         el->num_values++;
     457             : 
     458   171180802 :         return LDB_SUCCESS;
     459             : }
     460             : 
     461             : /*
     462             :   add a value to a message
     463             : */
     464   171102234 : 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             :         struct ldb_message_element *el;
     470             :         int ret;
     471             : 
     472   171102234 :         el = ldb_msg_find_element(msg, attr_name);
     473   171102234 :         if (!el) {
     474   166988512 :                 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
     475   166988512 :                 if (ret != LDB_SUCCESS) {
     476           0 :                         return ret;
     477             :                 }
     478             :         }
     479             : 
     480   171102234 :         ret = ldb_msg_element_add_value(msg->elements, el, val);
     481   171102234 :         if (ret != LDB_SUCCESS) {
     482           0 :                 return ret;
     483             :         }
     484             : 
     485   171102234 :         if (return_el) {
     486   169285456 :                 *return_el = el;
     487             :         }
     488             : 
     489   171102234 :         return LDB_SUCCESS;
     490             : }
     491             : 
     492             : 
     493             : /*
     494             :   add a value to a message, stealing it into the 'right' place
     495             : */
     496   144468530 : int ldb_msg_add_steal_value(struct ldb_message *msg,
     497             :                             const char *attr_name,
     498             :                             struct ldb_val *val)
     499             : {
     500             :         int ret;
     501             :         struct ldb_message_element *el;
     502             : 
     503   144468530 :         ret = ldb_msg_add_value(msg, attr_name, val, &el);
     504   144468530 :         if (ret == LDB_SUCCESS) {
     505   144468530 :                 talloc_steal(el->values, val->data);
     506             :         }
     507   144468530 :         return ret;
     508             : }
     509             : 
     510             : 
     511             : /*
     512             :   add a string element to a message, specifying flags
     513             : */
     514    24396958 : int ldb_msg_add_string_flags(struct ldb_message *msg,
     515             :                              const char *attr_name, const char *str,
     516             :                              int flags)
     517             : {
     518             :         struct ldb_val val;
     519             :         int ret;
     520    24396958 :         struct ldb_message_element *el = NULL;
     521             : 
     522    24396958 :         val.data = discard_const_p(uint8_t, str);
     523    24396958 :         val.length = strlen(str);
     524             : 
     525    24396958 :         if (val.length == 0) {
     526             :                 /* allow empty strings as non-existent attributes */
     527         266 :                 return LDB_SUCCESS;
     528             :         }
     529             : 
     530    24396692 :         ret = ldb_msg_add_value(msg, attr_name, &val, &el);
     531    24396692 :         if (ret != LDB_SUCCESS) {
     532           0 :                 return ret;
     533             :         }
     534             : 
     535    24396692 :         if (flags != 0) {
     536       67700 :                 el->flags = flags;
     537             :         }
     538             : 
     539    24396692 :         return LDB_SUCCESS;
     540             : }
     541             : 
     542             : /*
     543             :   add a string element to a message
     544             : */
     545    24329258 : int ldb_msg_add_string(struct ldb_message *msg,
     546             :                        const char *attr_name, const char *str)
     547             : {
     548    24329258 :         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   130097552 : int ldb_msg_add_steal_string(struct ldb_message *msg,
     555             :                              const char *attr_name, char *str)
     556             : {
     557             :         struct ldb_val val;
     558             : 
     559   130097552 :         val.data = (uint8_t *)str;
     560   130097552 :         val.length = strlen(str);
     561             : 
     562   130097552 :         if (val.length == 0) {
     563             :                 /* allow empty strings as non-existent attributes */
     564           0 :                 return LDB_SUCCESS;
     565             :         }
     566             : 
     567   130097552 :         return ldb_msg_add_steal_value(msg, attr_name, &val);
     568             : }
     569             : 
     570             : /*
     571             :   add a DN element to a message
     572             :   WARNING: this uses the linearized string from the dn, and does not
     573             :   copy the string.
     574             : */
     575        1600 : int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
     576             :                               struct ldb_dn *dn)
     577             : {
     578        1600 :         char *str = ldb_dn_alloc_linearized(msg, dn);
     579             : 
     580        1600 :         if (str == NULL) {
     581             :                 /* we don't want to have unknown DNs added */
     582           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     583             :         }
     584             : 
     585        1600 :         return ldb_msg_add_steal_string(msg, attr_name, str);
     586             : }
     587             : 
     588             : /*
     589             :   add a printf formatted element to a message
     590             : */
     591     8046671 : int ldb_msg_add_fmt(struct ldb_message *msg,
     592             :                     const char *attr_name, const char *fmt, ...)
     593             : {
     594             :         struct ldb_val val;
     595             :         va_list ap;
     596             :         char *str;
     597             : 
     598     8046671 :         va_start(ap, fmt);
     599     8046671 :         str = talloc_vasprintf(msg, fmt, ap);
     600     8046671 :         va_end(ap);
     601             : 
     602     8046671 :         if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
     603             : 
     604     8046671 :         val.data   = (uint8_t *)str;
     605     8046671 :         val.length = strlen(str);
     606             : 
     607     8046671 :         return ldb_msg_add_steal_value(msg, attr_name, &val);
     608             : }
     609             : 
     610       78140 : static int ldb_msg_append_value_impl(struct ldb_message *msg,
     611             :                                      const char *attr_name,
     612             :                                      const struct ldb_val *val,
     613             :                                      int flags,
     614             :                                      struct ldb_message_element **return_el)
     615             : {
     616       78140 :         struct ldb_message_element *el = NULL;
     617             :         int ret;
     618             : 
     619       78140 :         ret = ldb_msg_add_empty(msg, attr_name, flags, &el);
     620       78140 :         if (ret != LDB_SUCCESS) {
     621           0 :                 return ret;
     622             :         }
     623             : 
     624       78140 :         ret = ldb_msg_element_add_value(msg->elements, el, val);
     625       78140 :         if (ret != LDB_SUCCESS) {
     626           0 :                 return ret;
     627             :         }
     628             : 
     629       78140 :         if (return_el != NULL) {
     630        1552 :                 *return_el = el;
     631             :         }
     632             : 
     633       78140 :         return LDB_SUCCESS;
     634             : }
     635             : 
     636             : /*
     637             :   append a value to a message
     638             : */
     639       76588 : int ldb_msg_append_value(struct ldb_message *msg,
     640             :                          const char *attr_name,
     641             :                          const struct ldb_val *val,
     642             :                          int flags)
     643             : {
     644       76588 :         return ldb_msg_append_value_impl(msg, attr_name, val, flags, NULL);
     645             : }
     646             : 
     647             : /*
     648             :   append a value to a message, stealing it into the 'right' place
     649             : */
     650        1552 : int ldb_msg_append_steal_value(struct ldb_message *msg,
     651             :                                const char *attr_name,
     652             :                                struct ldb_val *val,
     653             :                                int flags)
     654             : {
     655             :         int ret;
     656        1552 :         struct ldb_message_element *el = NULL;
     657             : 
     658        1552 :         ret = ldb_msg_append_value_impl(msg, attr_name, val, flags, &el);
     659        1552 :         if (ret == LDB_SUCCESS) {
     660        1552 :                 talloc_steal(el->values, val->data);
     661             :         }
     662        1552 :         return ret;
     663             : }
     664             : 
     665             : /*
     666             :   append a string element to a message, stealing it into the 'right' place
     667             : */
     668         706 : int ldb_msg_append_steal_string(struct ldb_message *msg,
     669             :                                 const char *attr_name, char *str,
     670             :                                 int flags)
     671             : {
     672             :         struct ldb_val val;
     673             : 
     674         706 :         val.data = (uint8_t *)str;
     675         706 :         val.length = strlen(str);
     676             : 
     677         706 :         if (val.length == 0) {
     678             :                 /* allow empty strings as non-existent attributes */
     679           0 :                 return LDB_SUCCESS;
     680             :         }
     681             : 
     682         706 :         return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
     683             : }
     684             : 
     685             : /*
     686             :   append a string element to a message
     687             : */
     688       45685 : int ldb_msg_append_string(struct ldb_message *msg,
     689             :                           const char *attr_name, const char *str, int flags)
     690             : {
     691             :         struct ldb_val val;
     692             : 
     693       45685 :         val.data = discard_const_p(uint8_t, str);
     694       45685 :         val.length = strlen(str);
     695             : 
     696       45685 :         if (val.length == 0) {
     697             :                 /* allow empty strings as non-existent attributes */
     698           0 :                 return LDB_SUCCESS;
     699             :         }
     700             : 
     701       45685 :         return ldb_msg_append_value(msg, attr_name, &val, flags);
     702             : }
     703             : 
     704             : /*
     705             :   append a DN element to a message
     706             :   WARNING: this uses the linearized string from the dn, and does not
     707             :   copy the string.
     708             : */
     709           0 : int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
     710             :                                  struct ldb_dn *dn, int flags)
     711             : {
     712           0 :         char *str = ldb_dn_alloc_linearized(msg, dn);
     713             : 
     714           0 :         if (str == NULL) {
     715             :                 /* we don't want to have unknown DNs added */
     716           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     717             :         }
     718             : 
     719           0 :         return ldb_msg_append_steal_string(msg, attr_name, str, flags);
     720             : }
     721             : 
     722             : /*
     723             :   append a printf formatted element to a message
     724             : */
     725         846 : int ldb_msg_append_fmt(struct ldb_message *msg, int flags,
     726             :                        const char *attr_name, const char *fmt, ...)
     727             : {
     728             :         struct ldb_val val;
     729             :         va_list ap;
     730         846 :         char *str = NULL;
     731             : 
     732         846 :         va_start(ap, fmt);
     733         846 :         str = talloc_vasprintf(msg, fmt, ap);
     734         846 :         va_end(ap);
     735             : 
     736         846 :         if (str == NULL) {
     737           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     738             :         }
     739             : 
     740         846 :         val.data   = (uint8_t *)str;
     741         846 :         val.length = strlen(str);
     742             : 
     743         846 :         return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
     744             : }
     745             : 
     746             : /*
     747             :   compare two ldb_message_element structures
     748             :   assumes case sensitive comparison
     749             : */
     750    14927021 : int ldb_msg_element_compare(struct ldb_message_element *el1,
     751             :                             struct ldb_message_element *el2)
     752             : {
     753             :         unsigned int i;
     754             : 
     755    14927021 :         if (el1->num_values != el2->num_values) {
     756          96 :                 return el1->num_values - el2->num_values;
     757             :         }
     758             : 
     759    32990768 :         for (i=0;i<el1->num_values;i++) {
     760    18118299 :                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
     761       54456 :                         return -1;
     762             :                 }
     763             :         }
     764             : 
     765    14872469 :         return 0;
     766             : }
     767             : 
     768             : /*
     769             :   compare two ldb_message_element structures.
     770             :   Different ordering is considered a mismatch
     771             : */
     772     8783348 : bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
     773             :                                    const struct ldb_message_element *el2)
     774             : {
     775             :         unsigned i;
     776     8783348 :         if (el1->num_values != el2->num_values) {
     777      866867 :                 return false;
     778             :         }
     779    12050437 :         for (i=0;i<el1->num_values;i++) {
     780     8375765 :                 if (ldb_val_equal_exact(&el1->values[i],
     781     8375765 :                                         &el2->values[i]) != 1) {
     782     4241809 :                         return false;
     783             :                 }
     784             :         }
     785     3674672 :         return true;
     786             : }
     787             : 
     788             : /*
     789             :   compare two ldb_message_element structures
     790             :   comparing by element name
     791             : */
     792   178367688 : int ldb_msg_element_compare_name(struct ldb_message_element *el1,
     793             :                                  struct ldb_message_element *el2)
     794             : {
     795   178367688 :         return ldb_attr_cmp(el1->name, el2->name);
     796             : }
     797             : 
     798     4782397 : void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el)
     799             : {
     800     4782397 :         el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
     801     4782397 : }
     802             : 
     803   159695349 : bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el)
     804             : {
     805   159695349 :         return (el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE) != 0;
     806             : }
     807             : 
     808     1378416 : void ldb_msg_remove_inaccessible(struct ldb_message *msg)
     809             : {
     810             :         unsigned i;
     811     1378416 :         unsigned num_del = 0;
     812             : 
     813     9692981 :         for (i = 0; i < msg->num_elements; ++i) {
     814     8314565 :                 if (ldb_msg_element_is_inaccessible(&msg->elements[i])) {
     815     4777745 :                         ++num_del;
     816     3536820 :                 } else if (num_del) {
     817     2599327 :                         msg->elements[i - num_del] = msg->elements[i];
     818             :                 }
     819             :         }
     820             : 
     821     1378416 :         msg->num_elements -= num_del;
     822     1378416 : }
     823             : 
     824             : /*
     825             :   convenience functions to return common types from a message
     826             :   these return the first value if the attribute is multi-valued
     827             : */
     828  2482074569 : const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
     829             :                                            const char *attr_name)
     830             : {
     831  2482074569 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
     832  2482074569 :         if (!el || el->num_values == 0) {
     833  1108496021 :                 return NULL;
     834             :         }
     835  1373578548 :         return &el->values[0];
     836             : }
     837             : 
     838   103676033 : int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
     839             :                              const char *attr_name,
     840             :                              int default_value)
     841             : {
     842   103676033 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     843             :         char buf[sizeof("-2147483648")];
     844   103676033 :         char *end = NULL;
     845             :         int ret;
     846             : 
     847   103676033 :         if (!v || !v->data) {
     848     1385699 :                 return default_value;
     849             :         }
     850             : 
     851   102290334 :         ZERO_STRUCT(buf);
     852   102290334 :         if (v->length >= sizeof(buf)) {
     853          66 :                 return default_value;
     854             :         }
     855             : 
     856   102290268 :         memcpy(buf, v->data, v->length);
     857   102290268 :         errno = 0;
     858   102290268 :         ret = (int) strtoll(buf, &end, 10);
     859   102290268 :         if (errno != 0) {
     860           0 :                 return default_value;
     861             :         }
     862   102290268 :         if (end && end[0] != '\0') {
     863           0 :                 return default_value;
     864             :         }
     865   102290268 :         return ret;
     866             : }
     867             : 
     868   448085712 : unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
     869             :                                        const char *attr_name,
     870             :                                        unsigned int default_value)
     871             : {
     872   448085712 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     873             :         char buf[sizeof("-2147483648")];
     874   448085712 :         char *end = NULL;
     875             :         unsigned int ret;
     876             : 
     877   448085712 :         if (!v || !v->data) {
     878   223451900 :                 return default_value;
     879             :         }
     880             : 
     881   224633812 :         ZERO_STRUCT(buf);
     882   224633812 :         if (v->length >= sizeof(buf)) {
     883          39 :                 return default_value;
     884             :         }
     885             : 
     886   224633773 :         memcpy(buf, v->data, v->length);
     887   224633773 :         errno = 0;
     888   224633773 :         ret = (unsigned int) strtoll(buf, &end, 10);
     889   224633773 :         if (errno != 0) {
     890           0 :                 errno = 0;
     891           0 :                 ret = (unsigned int) strtoull(buf, &end, 10);
     892           0 :                 if (errno != 0) {
     893           0 :                         return default_value;
     894             :                 }
     895             :         }
     896   224633773 :         if (end && end[0] != '\0') {
     897          39 :                 return default_value;
     898             :         }
     899   224633734 :         return ret;
     900             : }
     901             : 
     902     1888957 : int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
     903             :                                    const char *attr_name,
     904             :                                    int64_t default_value)
     905             : {
     906     1888957 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     907             :         char buf[sizeof("-9223372036854775808")];
     908     1888957 :         char *end = NULL;
     909             :         int64_t ret;
     910             : 
     911     1888957 :         if (!v || !v->data) {
     912      415791 :                 return default_value;
     913             :         }
     914             : 
     915     1473166 :         ZERO_STRUCT(buf);
     916     1473166 :         if (v->length >= sizeof(buf)) {
     917           0 :                 return default_value;
     918             :         }
     919             : 
     920     1473166 :         memcpy(buf, v->data, v->length);
     921     1473166 :         errno = 0;
     922     1473166 :         ret = (int64_t) strtoll(buf, &end, 10);
     923     1473166 :         if (errno != 0) {
     924           0 :                 return default_value;
     925             :         }
     926     1473166 :         if (end && end[0] != '\0') {
     927           0 :                 return default_value;
     928             :         }
     929     1473166 :         return ret;
     930             : }
     931             : 
     932   171955766 : uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
     933             :                                      const char *attr_name,
     934             :                                      uint64_t default_value)
     935             : {
     936   171955766 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     937             :         char buf[sizeof("-9223372036854775808")];
     938   171955766 :         char *end = NULL;
     939             :         uint64_t ret;
     940             : 
     941   171955766 :         if (!v || !v->data) {
     942    87307476 :                 return default_value;
     943             :         }
     944             : 
     945    84648290 :         ZERO_STRUCT(buf);
     946    84648290 :         if (v->length >= sizeof(buf)) {
     947           0 :                 return default_value;
     948             :         }
     949             : 
     950    84648290 :         memcpy(buf, v->data, v->length);
     951    84648290 :         errno = 0;
     952    84648290 :         ret = (uint64_t) strtoll(buf, &end, 10);
     953    84648290 :         if (errno != 0) {
     954           0 :                 errno = 0;
     955           0 :                 ret = (uint64_t) strtoull(buf, &end, 10);
     956           0 :                 if (errno != 0) {
     957           0 :                         return default_value;
     958             :                 }
     959             :         }
     960    84648290 :         if (end && end[0] != '\0') {
     961           0 :                 return default_value;
     962             :         }
     963    84648290 :         return ret;
     964             : }
     965             : 
     966           0 : double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
     967             :                                    const char *attr_name,
     968             :                                    double default_value)
     969             : {
     970           0 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
     971             :         char *buf;
     972           0 :         char *end = NULL;
     973             :         double ret;
     974             : 
     975           0 :         if (!v || !v->data) {
     976           0 :                 return default_value;
     977             :         }
     978           0 :         buf = talloc_strndup(msg, (const char *)v->data, v->length);
     979           0 :         if (buf == NULL) {
     980           0 :                 return default_value;
     981             :         }
     982             : 
     983           0 :         errno = 0;
     984           0 :         ret = strtod(buf, &end);
     985           0 :         talloc_free(buf);
     986           0 :         if (errno != 0) {
     987           0 :                 return default_value;
     988             :         }
     989           0 :         if (end && end[0] != '\0') {
     990           0 :                 return default_value;
     991             :         }
     992           0 :         return ret;
     993             : }
     994             : 
     995     6995822 : int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
     996             :                               const char *attr_name,
     997             :                               int default_value)
     998             : {
     999     6995822 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1000     6995822 :         if (!v || !v->data) {
    1001     2731490 :                 return default_value;
    1002             :         }
    1003     4264332 :         if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
    1004       72968 :                 return 0;
    1005             :         }
    1006     4191364 :         if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
    1007     4191364 :                 return 1;
    1008             :         }
    1009           0 :         return default_value;
    1010             : }
    1011             : 
    1012   585007953 : const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
    1013             :                                         const char *attr_name,
    1014             :                                         const char *default_value)
    1015             : {
    1016   585007953 :         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
    1017   585007953 :         if (!v || !v->data) {
    1018   372960513 :                 return default_value;
    1019             :         }
    1020   212047440 :         if (v->data[v->length] != '\0') {
    1021           0 :                 return default_value;
    1022             :         }
    1023   212047440 :         return (const char *)v->data;
    1024             : }
    1025             : 
    1026     4400548 : struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
    1027             :                                        TALLOC_CTX *mem_ctx,
    1028             :                                        const struct ldb_message *msg,
    1029             :                                        const char *attr_name)
    1030             : {
    1031             :         struct ldb_dn *res_dn;
    1032             :         const struct ldb_val *v;
    1033             : 
    1034     4400548 :         v = ldb_msg_find_ldb_val(msg, attr_name);
    1035     4400548 :         if (!v || !v->data) {
    1036      856287 :                 return NULL;
    1037             :         }
    1038     3544261 :         res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
    1039     3544261 :         if ( ! ldb_dn_validate(res_dn)) {
    1040           0 :                 talloc_free(res_dn);
    1041           0 :                 return NULL;
    1042             :         }
    1043     3544261 :         return res_dn;
    1044             : }
    1045             : 
    1046             : /*
    1047             :   sort the elements of a message by name
    1048             : */
    1049     1255510 : void ldb_msg_sort_elements(struct ldb_message *msg)
    1050             : {
    1051     1255510 :         TYPESAFE_QSORT(msg->elements, msg->num_elements,
    1052             :                        ldb_msg_element_compare_name);
    1053     1255510 : }
    1054             : 
    1055     6505380 : static struct ldb_message *ldb_msg_copy_shallow_impl(TALLOC_CTX *mem_ctx,
    1056             :                                          const struct ldb_message *msg)
    1057             : {
    1058             :         struct ldb_message *msg2;
    1059             :         unsigned int i;
    1060             : 
    1061     6505380 :         msg2 = talloc(mem_ctx, struct ldb_message);
    1062     6505380 :         if (msg2 == NULL) return NULL;
    1063             : 
    1064     6505380 :         *msg2 = *msg;
    1065             : 
    1066     6505380 :         msg2->elements = talloc_array(msg2, struct ldb_message_element,
    1067             :                                       msg2->num_elements);
    1068     6505380 :         if (msg2->elements == NULL) goto failed;
    1069             : 
    1070    72049274 :         for (i=0;i<msg2->num_elements;i++) {
    1071    65543894 :                 msg2->elements[i] = msg->elements[i];
    1072             :         }
    1073             : 
    1074     6505380 :         return msg2;
    1075             : 
    1076           0 : failed:
    1077           0 :         talloc_free(msg2);
    1078           0 :         return NULL;
    1079             : }
    1080             : 
    1081             : /*
    1082             :   shallow copy a message - copying only the elements array so that the caller
    1083             :   can safely add new elements without changing the message
    1084             : */
    1085     5116863 : struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
    1086             :                                          const struct ldb_message *msg)
    1087             : {
    1088             :         struct ldb_message *msg2;
    1089             :         unsigned int i;
    1090             : 
    1091     5116863 :         msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
    1092     5116863 :         if (msg2 == NULL) {
    1093           0 :                 return NULL;
    1094             :         }
    1095             : 
    1096    41272425 :         for (i = 0; i < msg2->num_elements; ++i) {
    1097             :                 /*
    1098             :                  * Mark this message's elements as sharing their values with the
    1099             :                  * original message, so that we don't inadvertently modify or
    1100             :                  * free them. We don't mark the original message element as
    1101             :                  * shared, so the original message element should not be
    1102             :                  * modified or freed while the shallow copy lives.
    1103             :                  */
    1104    36155562 :                 struct ldb_message_element *el = &msg2->elements[i];
    1105    36155562 :                 el->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
    1106             :         }
    1107             : 
    1108     5116863 :         return msg2;
    1109             : }
    1110             : 
    1111             : /*
    1112             :   copy a message, allocating new memory for all parts
    1113             : */
    1114     1388517 : struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
    1115             :                                  const struct ldb_message *msg)
    1116             : {
    1117             :         struct ldb_message *msg2;
    1118             :         unsigned int i, j;
    1119             : 
    1120     1388517 :         msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
    1121     1388517 :         if (msg2 == NULL) return NULL;
    1122             : 
    1123     1388517 :         if (msg2->dn != NULL) {
    1124     1388505 :                 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
    1125     1388505 :                 if (msg2->dn == NULL) goto failed;
    1126             :         }
    1127             : 
    1128    30776849 :         for (i=0;i<msg2->num_elements;i++) {
    1129    29388332 :                 struct ldb_message_element *el = &msg2->elements[i];
    1130    29388332 :                 struct ldb_val *values = el->values;
    1131    29388332 :                 el->name = talloc_strdup(msg2->elements, el->name);
    1132    29388332 :                 if (el->name == NULL) goto failed;
    1133    29388332 :                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
    1134    29388332 :                 if (el->values == NULL) goto failed;
    1135    64879278 :                 for (j=0;j<el->num_values;j++) {
    1136    35490946 :                         el->values[j] = ldb_val_dup(el->values, &values[j]);
    1137    35490946 :                         if (el->values[j].data == NULL && values[j].length != 0) {
    1138           0 :                                 goto failed;
    1139             :                         }
    1140             :                 }
    1141             : 
    1142             :                 /*
    1143             :                  * Since we copied this element's values, we can mark them as
    1144             :                  * not shared.
    1145             :                  */
    1146    29388332 :                 el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
    1147             :         }
    1148             : 
    1149     1388517 :         return msg2;
    1150             : 
    1151           0 : failed:
    1152           0 :         talloc_free(msg2);
    1153           0 :         return NULL;
    1154             : }
    1155             : 
    1156             : 
    1157             : /**
    1158             :  * Canonicalize a message, merging elements of the same name
    1159             :  */
    1160           0 : struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
    1161             :                                          const struct ldb_message *msg)
    1162             : {
    1163             :         int ret;
    1164             :         struct ldb_message *msg2;
    1165             : 
    1166             :         /*
    1167             :          * Preserve previous behavior and allocate
    1168             :          * *msg2 into *ldb context
    1169             :          */
    1170           0 :         ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
    1171           0 :         if (ret != LDB_SUCCESS) {
    1172           0 :                 return NULL;
    1173             :         }
    1174             : 
    1175           0 :         return msg2;
    1176             : }
    1177             : 
    1178             : /**
    1179             :  * Canonicalize a message, merging elements of the same name
    1180             :  */
    1181     1255335 : int ldb_msg_normalize(struct ldb_context *ldb,
    1182             :                       TALLOC_CTX *mem_ctx,
    1183             :                       const struct ldb_message *msg,
    1184             :                       struct ldb_message **_msg_out)
    1185             : {
    1186             :         unsigned int i;
    1187             :         struct ldb_message *msg2;
    1188             : 
    1189     1255335 :         msg2 = ldb_msg_copy(mem_ctx, msg);
    1190     1255335 :         if (msg2 == NULL) {
    1191           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1192             :         }
    1193             : 
    1194     1255335 :         ldb_msg_sort_elements(msg2);
    1195             : 
    1196    28306833 :         for (i=1; i < msg2->num_elements; i++) {
    1197    27051498 :                 struct ldb_message_element *el1 = &msg2->elements[i-1];
    1198    27051498 :                 struct ldb_message_element *el2 = &msg2->elements[i];
    1199             : 
    1200    27051498 :                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
    1201        5382 :                         el1->values = talloc_realloc(msg2->elements,
    1202             :                                                      el1->values, struct ldb_val,
    1203             :                                                      el1->num_values + el2->num_values);
    1204        5382 :                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
    1205           0 :                                 talloc_free(msg2);
    1206           0 :                                 return LDB_ERR_OPERATIONS_ERROR;
    1207             :                         }
    1208        5382 :                         memcpy(el1->values + el1->num_values,
    1209        5382 :                                el2->values,
    1210        5382 :                                sizeof(struct ldb_val) * el2->num_values);
    1211        5382 :                         el1->num_values += el2->num_values;
    1212        5382 :                         talloc_free(discard_const_p(char, el2->name));
    1213        5382 :                         if ((i+1) < msg2->num_elements) {
    1214           0 :                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
    1215           0 :                                         (msg2->num_elements - (i+1)));
    1216             :                         }
    1217        5382 :                         msg2->num_elements--;
    1218        5382 :                         i--;
    1219             :                 }
    1220             :         }
    1221             : 
    1222     1255335 :         *_msg_out = msg2;
    1223     1255335 :         return LDB_SUCCESS;
    1224             : }
    1225             : 
    1226             : 
    1227             : /**
    1228             :  * return a ldb_message representing the differences between msg1 and msg2.
    1229             :  * If you then use this in a ldb_modify() call,
    1230             :  * it can be used to save edits to a message
    1231             :  */
    1232           0 : struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
    1233             :                                  struct ldb_message *msg1,
    1234             :                                  struct ldb_message *msg2)
    1235             : {
    1236             :         int ldb_ret;
    1237             :         struct ldb_message *mod;
    1238             : 
    1239           0 :         ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
    1240           0 :         if (ldb_ret != LDB_SUCCESS) {
    1241           0 :                 return NULL;
    1242             :         }
    1243             : 
    1244           0 :         return mod;
    1245             : }
    1246             : 
    1247             : /**
    1248             :  * return a ldb_message representing the differences between msg1 and msg2.
    1249             :  * If you then use this in a ldb_modify() call it can be used to save edits to a message
    1250             :  *
    1251             :  * Result message is constructed as follows:
    1252             :  * - LDB_FLAG_MOD_ADD     - elements found only in msg2
    1253             :  * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
    1254             :  *                          Value for msg2 element is used
    1255             :  * - LDB_FLAG_MOD_DELETE  - elements found only in msg2
    1256             :  *
    1257             :  * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
    1258             :  */
    1259       69270 : int ldb_msg_difference(struct ldb_context *ldb,
    1260             :                        TALLOC_CTX *mem_ctx,
    1261             :                        struct ldb_message *msg1,
    1262             :                        struct ldb_message *msg2,
    1263             :                        struct ldb_message **_msg_out)
    1264             : {
    1265             :         int ldb_res;
    1266             :         unsigned int i;
    1267             :         struct ldb_message *mod;
    1268             :         struct ldb_message_element *el;
    1269             :         TALLOC_CTX *temp_ctx;
    1270             : 
    1271       69270 :         temp_ctx = talloc_new(mem_ctx);
    1272       69270 :         if (!temp_ctx) {
    1273           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1274             :         }
    1275             : 
    1276       69270 :         mod = ldb_msg_new(temp_ctx);
    1277       69270 :         if (mod == NULL) {
    1278           0 :                 goto failed;
    1279             :         }
    1280             : 
    1281       69270 :         mod->dn = msg1->dn;
    1282       69270 :         mod->num_elements = 0;
    1283       69270 :         mod->elements = NULL;
    1284             : 
    1285             :         /*
    1286             :          * Canonicalize *msg2 so we have no repeated elements
    1287             :          * Resulting message is allocated in *mod's mem context,
    1288             :          * as we are going to move some elements from *msg2 to
    1289             :          * *mod object later
    1290             :          */
    1291       69270 :         ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
    1292       69270 :         if (ldb_res != LDB_SUCCESS) {
    1293           0 :                 goto failed;
    1294             :         }
    1295             : 
    1296             :         /* look in msg2 to find elements that need to be added or modified */
    1297    14990732 :         for (i=0;i<msg2->num_elements;i++) {
    1298    14921462 :                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
    1299             : 
    1300    14921462 :                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
    1301    14865716 :                         continue;
    1302             :                 }
    1303             : 
    1304       55746 :                 ldb_res = ldb_msg_add(mod,
    1305       55746 :                                       &msg2->elements[i],
    1306             :                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
    1307       55746 :                 if (ldb_res != LDB_SUCCESS) {
    1308           0 :                         goto failed;
    1309             :                 }
    1310             :         }
    1311             : 
    1312             :         /* look in msg1 to find elements that need to be deleted */
    1313    14990097 :         for (i=0;i<msg1->num_elements;i++) {
    1314    14920827 :                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
    1315    14920827 :                 if (el == NULL) {
    1316         575 :                         ldb_res = ldb_msg_add_empty(mod,
    1317         575 :                                                     msg1->elements[i].name,
    1318             :                                                     LDB_FLAG_MOD_DELETE, NULL);
    1319         575 :                         if (ldb_res != LDB_SUCCESS) {
    1320           0 :                                 goto failed;
    1321             :                         }
    1322             :                 }
    1323             :         }
    1324             : 
    1325             :         /* steal resulting message into supplied context */
    1326       69270 :         talloc_steal(mem_ctx, mod);
    1327       69270 :         *_msg_out = mod;
    1328             : 
    1329       69270 :         talloc_free(temp_ctx);
    1330       69270 :         return LDB_SUCCESS;
    1331             : 
    1332           0 : failed:
    1333           0 :         talloc_free(temp_ctx);
    1334           0 :         return LDB_ERR_OPERATIONS_ERROR;
    1335             : }
    1336             : 
    1337             : 
    1338     1003177 : int ldb_msg_sanity_check(struct ldb_context *ldb,
    1339             :                          const struct ldb_message *msg)
    1340             : {
    1341             :         unsigned int i, j;
    1342             : 
    1343             :         /* basic check on DN */
    1344     1003177 :         if (msg->dn == NULL) {
    1345           0 :                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
    1346           0 :                 return LDB_ERR_INVALID_DN_SYNTAX;
    1347             :         }
    1348             : 
    1349             :         /* basic syntax checks */
    1350     5475934 :         for (i = 0; i < msg->num_elements; i++) {
    1351    10469399 :                 for (j = 0; j < msg->elements[i].num_values; j++) {
    1352     5996642 :                         if (msg->elements[i].values[j].length == 0) {
    1353             :                                 /* an attribute cannot be empty */
    1354           4 :                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
    1355           2 :                                                             msg->elements[i].name,
    1356           2 :                                                             ldb_dn_get_linearized(msg->dn));
    1357           2 :                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1358             :                         }
    1359             :                 }
    1360             :         }
    1361             : 
    1362     1003175 :         return LDB_SUCCESS;
    1363             : }
    1364             : 
    1365             : 
    1366             : 
    1367             : 
    1368             : /*
    1369             :   copy an attribute list. This only copies the array, not the elements
    1370             :   (ie. the elements are left as the same pointers)
    1371             : */
    1372     8241674 : const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
    1373             : {
    1374             :         const char **ret;
    1375             :         unsigned int i;
    1376             : 
    1377   220864391 :         for (i=0;attrs && attrs[i];i++) /* noop */ ;
    1378     8241674 :         ret = talloc_array(mem_ctx, const char *, i+1);
    1379     8241674 :         if (ret == NULL) {
    1380           0 :                 return NULL;
    1381             :         }
    1382   220864391 :         for (i=0;attrs && attrs[i];i++) {
    1383   212622717 :                 ret[i] = attrs[i];
    1384             :         }
    1385     8241674 :         ret[i] = attrs[i];
    1386     8241674 :         return ret;
    1387             : }
    1388             : 
    1389             : 
    1390             : /*
    1391             :   copy an attribute list. This only copies the array, not the elements
    1392             :   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
    1393             : */
    1394     8738561 : const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
    1395             : {
    1396             :         const char **ret;
    1397             :         unsigned int i;
    1398     8738561 :         bool found = false;
    1399             : 
    1400   197113685 :         for (i=0;attrs && attrs[i];i++) {
    1401   188375124 :                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
    1402     5912678 :                         found = true;
    1403             :                 }
    1404             :         }
    1405     8738561 :         if (found) {
    1406     5267518 :                 return ldb_attr_list_copy(mem_ctx, attrs);
    1407             :         }
    1408     3471043 :         ret = talloc_array(mem_ctx, const char *, i+2);
    1409     3471043 :         if (ret == NULL) {
    1410           0 :                 return NULL;
    1411             :         }
    1412    27673328 :         for (i=0;attrs && attrs[i];i++) {
    1413    24202285 :                 ret[i] = attrs[i];
    1414             :         }
    1415     3471043 :         ret[i] = new_attr;
    1416     3471043 :         ret[i+1] = NULL;
    1417     3471043 :         return ret;
    1418             : }
    1419             : 
    1420             : 
    1421             : /*
    1422             :   return 1 if an attribute is in a list of attributes, or 0 otherwise
    1423             : */
    1424  1475171545 : int ldb_attr_in_list(const char * const *attrs, const char *attr)
    1425             : {
    1426             :         unsigned int i;
    1427  4205767425 :         for (i=0;attrs && attrs[i];i++) {
    1428  2805732868 :                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
    1429    75136988 :                         return 1;
    1430             :                 }
    1431             :         }
    1432  1400034557 :         return 0;
    1433             : }
    1434             : 
    1435             : 
    1436             : /*
    1437             :   rename the specified attribute in a search result
    1438             : */
    1439           3 : int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
    1440             : {
    1441           3 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
    1442           3 :         if (el == NULL) {
    1443           0 :                 return LDB_SUCCESS;
    1444             :         }
    1445           3 :         el->name = talloc_strdup(msg->elements, replace);
    1446           3 :         if (el->name == NULL) {
    1447           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1448             :         }
    1449           3 :         return LDB_SUCCESS;
    1450             : }
    1451             : 
    1452             : 
    1453             : /*
    1454             :   copy the specified attribute in a search result to a new attribute
    1455             : */
    1456           3 : int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
    1457             : {
    1458           3 :         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
    1459             :         int ret;
    1460             : 
    1461           3 :         if (el == NULL) {
    1462           0 :                 return LDB_SUCCESS;
    1463             :         }
    1464           3 :         ret = ldb_msg_add(msg, el, 0);
    1465           3 :         if (ret != LDB_SUCCESS) {
    1466           0 :                 return ret;
    1467             :         }
    1468           3 :         return ldb_msg_rename_attr(msg, attr, replace);
    1469             : }
    1470             : 
    1471             : /*
    1472             :   remove the specified element in a search result
    1473             : */
    1474    44635132 : void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
    1475             : {
    1476    44635132 :         ptrdiff_t n = (el - msg->elements);
    1477    44635132 :         if (n >= msg->num_elements || n < 0) {
    1478             :                 /* the element is not in the list. the caller is crazy. */
    1479           0 :                 return;
    1480             :         }
    1481    44635132 :         msg->num_elements--;
    1482    44635132 :         if (n != msg->num_elements) {
    1483    21896395 :                 memmove(el, el+1, (msg->num_elements - n)*sizeof(*el));
    1484             :         }
    1485             : }
    1486             : 
    1487             : 
    1488             : /*
    1489             :   remove the specified attribute in a search result
    1490             : */
    1491  1889742138 : void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
    1492             : {
    1493             :         struct ldb_message_element *el;
    1494             : 
    1495  1927866244 :         while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
    1496    38124106 :                 ldb_msg_remove_element(msg, el);
    1497             :         }
    1498  1889742138 : }
    1499             : 
    1500             : /* Reallocate elements to drop any excess capacity. */
    1501   125692393 : void ldb_msg_shrink_to_fit(struct ldb_message *msg)
    1502             : {
    1503   125692393 :         if (msg->num_elements > 0) {
    1504   111894175 :                 struct ldb_message_element *elements = talloc_realloc(msg,
    1505             :                                                                       msg->elements,
    1506             :                                                                       struct ldb_message_element,
    1507             :                                                                       msg->num_elements);
    1508   111894175 :                 if (elements != NULL) {
    1509   111894175 :                         msg->elements = elements;
    1510             :                 }
    1511             :         } else {
    1512    13798218 :                 TALLOC_FREE(msg->elements);
    1513             :         }
    1514   125692393 : }
    1515             : 
    1516             : /*
    1517             :   return a LDAP formatted GeneralizedTime string
    1518             : */
    1519     4515436 : char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
    1520             : {
    1521     4515436 :         struct tm *tm = gmtime(&t);
    1522             :         char *ts;
    1523             :         int r;
    1524             : 
    1525     4515436 :         if (!tm) {
    1526           3 :                 return NULL;
    1527             :         }
    1528             : 
    1529             :         /* we now excatly how long this string will be */
    1530     4515433 :         ts = talloc_array(mem_ctx, char, 18);
    1531             : 
    1532             :         /* formatted like: 20040408072012.0Z */
    1533     4515433 :         r = snprintf(ts, 18,
    1534             :                         "%04u%02u%02u%02u%02u%02u.0Z",
    1535     4515433 :                         tm->tm_year+1900, tm->tm_mon+1,
    1536             :                         tm->tm_mday, tm->tm_hour, tm->tm_min,
    1537             :                         tm->tm_sec);
    1538             : 
    1539     4515433 :         if (r != 17) {
    1540           6 :                 talloc_free(ts);
    1541           6 :                 errno = EOVERFLOW;
    1542           6 :                 return NULL;
    1543             :         }
    1544             : 
    1545     4515427 :         return ts;
    1546             : }
    1547             : 
    1548             : /*
    1549             :   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
    1550             : */
    1551       20330 : time_t ldb_string_to_time(const char *s)
    1552             : {
    1553             :         struct tm tm;
    1554             : 
    1555       20330 :         if (s == NULL) return 0;
    1556             : 
    1557       20304 :         memset(&tm, 0, sizeof(tm));
    1558       20304 :         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
    1559             :                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1560             :                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1561           0 :                 return 0;
    1562             :         }
    1563       20304 :         tm.tm_year -= 1900;
    1564       20304 :         tm.tm_mon -= 1;
    1565             : 
    1566       20304 :         return timegm(&tm);
    1567             : }
    1568             : 
    1569             : /*
    1570             :   convert a LDAP GeneralizedTime string in ldb_val format to a
    1571             :   time_t.
    1572             : */
    1573     4118466 : int ldb_val_to_time(const struct ldb_val *v, time_t *t)
    1574             : {
    1575     4118466 :         char val[15] = {0};
    1576     4118466 :         struct tm tm = {
    1577             :                 .tm_year = 0,
    1578             :         };
    1579             : 
    1580     4118466 :         if (v == NULL) {
    1581           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1582             :         }
    1583             : 
    1584     4118466 :         if (v->data == NULL) {
    1585           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1586             :         }
    1587             : 
    1588     4118466 :         if (v->length < 16 && v->length != 13) {
    1589           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1590             :         }
    1591             : 
    1592     4118466 :         if (v->data[v->length - 1] != 'Z') {
    1593           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1594             :         }
    1595             : 
    1596     4118466 :         if (v->length == 13) {
    1597         456 :                 memcpy(val, v->data, 12);
    1598             : 
    1599         456 :                 if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
    1600             :                         &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1601             :                         &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1602           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1603             :                 }
    1604         456 :                 if (tm.tm_year < 50) {
    1605         456 :                         tm.tm_year += 100;
    1606             :                 }
    1607             :         } else {
    1608             : 
    1609             :                 /*
    1610             :                  * anything between '.' and 'Z' is silently ignored.
    1611             :                  */
    1612     4118010 :                 if (v->data[14] != '.') {
    1613           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1614             :                 }
    1615             : 
    1616     4118010 :                 memcpy(val, v->data, 14);
    1617             : 
    1618     4118010 :                 if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
    1619             :                         &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1620             :                         &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1621           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1622             :                 }
    1623     4118010 :                 tm.tm_year -= 1900;
    1624             :         }
    1625     4118466 :         tm.tm_mon -= 1;
    1626             : 
    1627     4118466 :         *t = timegm(&tm);
    1628             : 
    1629     4118466 :         return LDB_SUCCESS;
    1630             : }
    1631             : 
    1632             : /*
    1633             :   return a LDAP formatted UTCTime string
    1634             : */
    1635          51 : char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
    1636             : {
    1637          51 :         struct tm *tm = gmtime(&t);
    1638             :         char *ts;
    1639             :         int r;
    1640             : 
    1641          51 :         if (!tm) {
    1642           0 :                 return NULL;
    1643             :         }
    1644             : 
    1645             :         /* we now excatly how long this string will be */
    1646          51 :         ts = talloc_array(mem_ctx, char, 14);
    1647             : 
    1648             :         /* formatted like: 20040408072012.0Z => 040408072012Z */
    1649          51 :         r = snprintf(ts, 14,
    1650             :                         "%02u%02u%02u%02u%02u%02uZ",
    1651          51 :                         (tm->tm_year+1900)%100, tm->tm_mon+1,
    1652             :                         tm->tm_mday, tm->tm_hour, tm->tm_min,
    1653             :                         tm->tm_sec);
    1654             : 
    1655          51 :         if (r != 13) {
    1656           0 :                 talloc_free(ts);
    1657           0 :                 return NULL;
    1658             :         }
    1659             : 
    1660          51 :         return ts;
    1661             : }
    1662             : 
    1663             : /*
    1664             :   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
    1665             : */
    1666           0 : time_t ldb_string_utc_to_time(const char *s)
    1667             : {
    1668             :         struct tm tm;
    1669             : 
    1670           0 :         if (s == NULL) return 0;
    1671             : 
    1672           0 :         memset(&tm, 0, sizeof(tm));
    1673           0 :         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
    1674             :                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
    1675             :                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    1676           0 :                 return 0;
    1677             :         }
    1678           0 :         if (tm.tm_year < 50) {
    1679           0 :                 tm.tm_year += 100;
    1680             :         }
    1681           0 :         tm.tm_mon -= 1;
    1682             : 
    1683           0 :         return timegm(&tm);
    1684             : }
    1685             : 
    1686             : 
    1687             : /*
    1688             :   dump a set of results to a file. Useful from within gdb
    1689             : */
    1690           0 : void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
    1691             : {
    1692             :         unsigned int i;
    1693             : 
    1694           0 :         for (i = 0; i < result->count; i++) {
    1695             :                 struct ldb_ldif ldif;
    1696           0 :                 fprintf(f, "# record %d\n", i+1);
    1697           0 :                 ldif.changetype = LDB_CHANGETYPE_NONE;
    1698           0 :                 ldif.msg = result->msgs[i];
    1699           0 :                 ldb_ldif_write_file(ldb, f, &ldif);
    1700             :         }
    1701           0 : }
    1702             : 
    1703             : /*
    1704             :   checks for a string attribute. Returns "1" on match and otherwise "0".
    1705             : */
    1706     2612218 : int ldb_msg_check_string_attribute(const struct ldb_message *msg,
    1707             :                                    const char *name, const char *value)
    1708             : {
    1709             :         struct ldb_message_element *el;
    1710             :         struct ldb_val val;
    1711             : 
    1712     2612218 :         el = ldb_msg_find_element(msg, name);
    1713     2612218 :         if (el == NULL) {
    1714     1341706 :                 return 0;
    1715             :         }
    1716             : 
    1717     1270512 :         val.data = discard_const_p(uint8_t, value);
    1718     1270512 :         val.length = strlen(value);
    1719             : 
    1720     1270512 :         if (ldb_msg_find_val(el, &val)) {
    1721     1269765 :                 return 1;
    1722             :         }
    1723             : 
    1724         747 :         return 0;
    1725             : }
    1726             : 
    1727             : 
    1728             : /*
    1729             :   compare a ldb_val to a string
    1730             : */
    1731     2859245 : int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
    1732             : {
    1733     2859245 :         size_t len = strlen(str);
    1734     2859245 :         if (len != v->length) {
    1735           0 :                 return len - v->length;
    1736             :         }
    1737     2859245 :         return strncmp((const char *)v->data, str, len);
    1738             : }

Generated by: LCOV version 1.14