LCOV - code coverage report
Current view: top level - lib/ldb/common - ldb_ldif.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 413 521 79.3 %
Date: 2021-09-23 10:06:22 Functions: 25 26 96.2 %

          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: ldif routines
      28             :  *
      29             :  *  Description: ldif pack/unpack routines
      30             :  *
      31             :  *  Author: Andrew Tridgell
      32             :  */
      33             : 
      34             : /*
      35             :   see RFC2849 for the LDIF format definition
      36             : */
      37             : 
      38             : #include "ldb_private.h"
      39             : #include "system/locale.h"
      40             : 
      41             : /*
      42             : 
      43             : */
      44           4 : static int ldb_read_data_file(TALLOC_CTX *mem_ctx, struct ldb_val *value)
      45             : {
      46             :         struct stat statbuf;
      47             :         char *buf;
      48             :         int count, size, bytes;
      49             :         int ret;
      50             :         int f;
      51           4 :         const char *fname = (const char *)value->data;
      52             : 
      53           4 :         if (strncmp(fname, "file://", 7) != 0) {
      54           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
      55             :         }
      56           4 :         fname += 7;
      57             : 
      58           4 :         f = open(fname, O_RDONLY);
      59           4 :         if (f == -1) {
      60           0 :                 return -1;
      61             :         }
      62             : 
      63           4 :         if (fstat(f, &statbuf) != 0) {
      64           0 :                 ret = -1;
      65           0 :                 goto done;
      66             :         }
      67             : 
      68           4 :         if (statbuf.st_size == 0) {
      69           0 :                 ret = -1;
      70           0 :                 goto done;
      71             :         }
      72             : 
      73           4 :         value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1);
      74           4 :         if (value->data == NULL) {
      75           0 :                 ret = -1;
      76           0 :                 goto done;
      77             :         }
      78           4 :         value->data[statbuf.st_size] = 0;
      79             : 
      80           4 :         count = 0;
      81           4 :         size = statbuf.st_size;
      82           4 :         buf = (char *)value->data;
      83          11 :         while (count < statbuf.st_size) {
      84           5 :                 bytes = read(f, buf, size);
      85           4 :                 if (bytes == -1) {
      86           0 :                         talloc_free(value->data);
      87           0 :                         ret = -1;
      88           0 :                         goto done;
      89             :                 }
      90           4 :                 count += bytes;
      91           4 :                 buf += bytes;
      92           4 :                 size -= bytes;
      93             :         }
      94             : 
      95           4 :         value->length = statbuf.st_size;
      96           4 :         ret = statbuf.st_size;
      97             : 
      98           4 : done:
      99           4 :         close(f);
     100           4 :         return ret;
     101             : }
     102             : 
     103             : /*
     104             :   this base64 decoder was taken from jitterbug (written by tridge).
     105             :   we might need to replace it with a new version
     106             : */
     107     1866785 : int ldb_base64_decode(char *s)
     108             : {
     109     1866785 :         const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     110     1866785 :         int bit_offset=0, byte_offset, idx, i, n;
     111     1866785 :         uint8_t *d = (uint8_t *)s;
     112     1866785 :         char *p=NULL;
     113             : 
     114     1866785 :         n=i=0;
     115             : 
     116    62279921 :         while (*s && (p=strchr(b64,*s))) {
     117    58901859 :                 idx = (int)(p - b64);
     118    58901859 :                 byte_offset = (i*6)/8;
     119    58901859 :                 bit_offset = (i*6)%8;
     120    58901859 :                 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
     121    58901859 :                 if (bit_offset < 3) {
     122    29309254 :                         d[byte_offset] |= (idx << (2-bit_offset));
     123    29309254 :                         n = byte_offset+1;
     124             :                 } else {
     125    29592605 :                         d[byte_offset] |= (idx >> (bit_offset-2));
     126    29592605 :                         d[byte_offset+1] = 0;
     127    29592605 :                         d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
     128    29592605 :                         n = byte_offset+2;
     129             :                 }
     130    58901859 :                 s++; i++;
     131             :         }
     132     1866785 :         if (bit_offset >= 3) {
     133     1478644 :                 n--;
     134             :         }
     135             : 
     136     1866785 :         if (*s && !p) {
     137             :                 /* the only termination allowed */
     138     1478642 :                 if (*s != '=') {
     139           0 :                         return -1;
     140             :                 }
     141             :         }
     142             : 
     143             :         /* null terminate */
     144     1866785 :         d[n] = 0;
     145     1866785 :         return n;
     146             : }
     147             : 
     148             : 
     149             : /*
     150             :   encode as base64
     151             :   caller frees
     152             : */
     153    12250303 : char *ldb_base64_encode(TALLOC_CTX *mem_ctx, const char *buf, int len)
     154             : {
     155    12250303 :         const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     156             :         int bit_offset, byte_offset, idx, i;
     157    12250303 :         const uint8_t *d = (const uint8_t *)buf;
     158    12250303 :         int bytes = (len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
     159             :         char *out;
     160             : 
     161    12250303 :         out = talloc_array(mem_ctx, char, bytes+pad_bytes+1);
     162    12250303 :         if (!out) return NULL;
     163             : 
     164   433632976 :         for (i=0;i<bytes;i++) {
     165   421708166 :                 byte_offset = (i*6)/8;
     166   421708166 :                 bit_offset = (i*6)%8;
     167   421708166 :                 if (bit_offset < 3) {
     168   210707995 :                         idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
     169             :                 } else {
     170   211000171 :                         idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
     171   211000171 :                         if (byte_offset+1 < len) {
     172   201443756 :                                 idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
     173             :                         }
     174             :                 }
     175   421708166 :                 out[i] = b64[idx];
     176             :         }
     177             : 
     178    30745464 :         for (;i<bytes+pad_bytes;i++)
     179    18820654 :                 out[i] = '=';
     180    12250303 :         out[i] = 0;
     181             : 
     182    12250303 :         return out;
     183             : }
     184             : 
     185             : /*
     186             :   see if a buffer should be base64 encoded
     187             : */
     188    36337027 : int ldb_should_b64_encode(struct ldb_context *ldb, const struct ldb_val *val)
     189             : {
     190             :         unsigned int i;
     191    36337027 :         uint8_t *p = val->data;
     192             : 
     193    36337027 :         if (val->length == 0) {
     194        5008 :                 return 0;
     195             :         }
     196             : 
     197    36331985 :         if (p[0] == ' ' || p[0] == ':') {
     198        3297 :                 return 1;
     199             :         }
     200             : 
     201  2230869218 :         for (i=0; i<val->length; i++) {
     202  2209340600 :                 if (!isprint(p[i]) || p[i] == '\n') {
     203    11872077 :                         return 1;
     204             :                 }
     205             :         }
     206    21853507 :         return 0;
     207             : }
     208             : 
     209             : /* this macro is used to handle the return checking on fprintf_fn() */
     210             : #define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
     211             : 
     212             : /*
     213             :   write a line folded string onto a file
     214             : */
     215      811949 : static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data,
     216             :                         const char *buf, size_t length, int start_pos)
     217             : {
     218             :         size_t i;
     219      811949 :         size_t total = 0;
     220             :         int ret;
     221             : 
     222    43324060 :         for (i=0;i<length;i++) {
     223    42512111 :                 ret = fprintf_fn(private_data, "%c", buf[i]);
     224    42512111 :                 CHECK_RET;
     225    42512111 :                 if (i != (length-1) && (i + start_pos) % 77 == 0) {
     226      391222 :                         ret = fprintf_fn(private_data, "\n ");
     227      391222 :                         CHECK_RET;
     228             :                 }
     229             :         }
     230             : 
     231      811949 :         return total;
     232             : }
     233             : 
     234             : #undef CHECK_RET
     235             : 
     236             : /*
     237             :   encode as base64 to a file
     238             : */
     239       91305 : static int base64_encode_f(struct ldb_context *ldb,
     240             :                            int (*fprintf_fn)(void *, const char *, ...),
     241             :                            void *private_data,
     242             :                            const char *buf, int len, int start_pos)
     243             : {
     244       91305 :         char *b = ldb_base64_encode(ldb, buf, len);
     245             :         int ret;
     246             : 
     247       91305 :         if (!b) {
     248           0 :                 return -1;
     249             :         }
     250             : 
     251       91305 :         ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
     252             : 
     253       91305 :         talloc_free(b);
     254       91305 :         return ret;
     255             : }
     256             : 
     257             : 
     258             : static const struct {
     259             :         const char *name;
     260             :         enum ldb_changetype changetype;
     261             : } ldb_changetypes[] = {
     262             :         {"add",    LDB_CHANGETYPE_ADD},
     263             :         {"delete", LDB_CHANGETYPE_DELETE},
     264             :         {"modify", LDB_CHANGETYPE_MODIFY},
     265             :         {"modrdn", LDB_CHANGETYPE_MODRDN},
     266             :         {"moddn",  LDB_CHANGETYPE_MODRDN},
     267             :         {NULL, 0}
     268             : };
     269             : 
     270             : /* this macro is used to handle the return checking on fprintf_fn() */
     271             : #define CHECK_RET do { if (ret < 0) { talloc_free(mem_ctx); return ret; } total += ret; } while (0)
     272             : 
     273             : /*
     274             :   write to ldif, using a caller supplied write method, and only printing secrets if we are not in a trace
     275             : */
     276      102418 : static int ldb_ldif_write_trace(struct ldb_context *ldb,
     277             :                                 int (*fprintf_fn)(void *, const char *, ...),
     278             :                                 void *private_data,
     279             :                                 const struct ldb_ldif *ldif,
     280             :                                 bool in_trace)
     281             : {
     282             :         TALLOC_CTX *mem_ctx;
     283             :         unsigned int i, j;
     284      102418 :         size_t total = 0;
     285             :         int ret;
     286             :         char *p;
     287             :         const struct ldb_message *msg;
     288      102418 :         const char * const * secret_attributes = ldb_get_opaque(ldb, LDB_SECRET_ATTRIBUTE_LIST_OPAQUE);
     289             : 
     290      102418 :         mem_ctx = talloc_named_const(NULL, 0, "ldb_ldif_write");
     291             : 
     292      102418 :         msg = ldif->msg;
     293      102418 :         p = ldb_dn_get_extended_linearized(mem_ctx, msg->dn, 1);
     294      102418 :         ret = fprintf_fn(private_data, "dn: %s\n", p);
     295      102418 :         talloc_free(p);
     296      102418 :         CHECK_RET;
     297             : 
     298      102418 :         if (ldif->changetype != LDB_CHANGETYPE_NONE) {
     299          48 :                 for (i=0;ldb_changetypes[i].name;i++) {
     300          48 :                         if (ldb_changetypes[i].changetype == ldif->changetype) {
     301          48 :                                 break;
     302             :                         }
     303             :                 }
     304          48 :                 if (!ldb_changetypes[i].name) {
     305           0 :                         ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Invalid ldif changetype %d",
     306           0 :                                   ldif->changetype);
     307           0 :                         talloc_free(mem_ctx);
     308           0 :                         return -1;
     309             :                 }
     310          48 :                 ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name);
     311          48 :                 CHECK_RET;
     312             :         }
     313             : 
     314      713850 :         for (i=0;i<msg->num_elements;i++) {
     315             :                 const struct ldb_schema_attribute *a;
     316             :                 size_t namelen;
     317             : 
     318      697452 :                 if (msg->elements[i].name == NULL) {
     319           0 :                         ldb_debug(ldb, LDB_DEBUG_ERROR,
     320             :                                         "Error: Invalid element name (NULL) at position %d", i);
     321           0 :                         talloc_free(mem_ctx);
     322           0 :                         return -1;
     323             :                 }
     324             : 
     325      697452 :                 namelen = strlen(msg->elements[i].name);
     326      697452 :                 a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
     327             : 
     328      697452 :                 if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
     329           0 :                         switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
     330           0 :                         case LDB_FLAG_MOD_ADD:
     331           0 :                                 fprintf_fn(private_data, "add: %s\n",
     332           0 :                                            msg->elements[i].name);
     333           0 :                                 break;
     334           0 :                         case LDB_FLAG_MOD_DELETE:
     335           0 :                                 fprintf_fn(private_data, "delete: %s\n",
     336           0 :                                            msg->elements[i].name);
     337           0 :                                 break;
     338           0 :                         case LDB_FLAG_MOD_REPLACE:
     339           0 :                                 fprintf_fn(private_data, "replace: %s\n",
     340           0 :                                            msg->elements[i].name);
     341           0 :                                 break;
     342             :                         }
     343             :                 }
     344             : 
     345      697452 :                 if (in_trace && secret_attributes && ldb_attr_in_list(secret_attributes, msg->elements[i].name)) {
     346             :                         /* Deliberatly skip printing this password */
     347          24 :                         ret = fprintf_fn(private_data, "# %s::: REDACTED SECRET ATTRIBUTE\n",
     348          24 :                                          msg->elements[i].name);
     349          24 :                         CHECK_RET;
     350          24 :                         continue;
     351             :                 }
     352     2546331 :                 for (j=0;j<msg->elements[i].num_values;j++) {
     353             :                         struct ldb_val v;
     354      817040 :                         bool use_b64_encode = false;
     355      817040 :                         bool copy_raw_bytes = false;
     356             : 
     357      817040 :                         ret = a->syntax->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v);
     358      817040 :                         if (ret != LDB_SUCCESS) {
     359          72 :                                 v = msg->elements[i].values[j];
     360             :                         }
     361             : 
     362      817040 :                         if (ldb->flags & LDB_FLG_SHOW_BINARY) {
     363         240 :                                 use_b64_encode = false;
     364         240 :                                 copy_raw_bytes = true;
     365      816799 :                         } else if (a->flags & LDB_ATTR_FLAG_FORCE_BASE64_LDIF) {
     366         276 :                                 use_b64_encode = true;
     367      816523 :                         } else if (msg->elements[i].flags &
     368             :                                    LDB_FLAG_FORCE_NO_BASE64_LDIF) {
     369        4850 :                                 use_b64_encode = false;
     370        4850 :                                 copy_raw_bytes = true;
     371             :                         } else {
     372      811673 :                                 use_b64_encode = ldb_should_b64_encode(ldb, &v);
     373             :                         }
     374             : 
     375      817040 :                         if (ret != LDB_SUCCESS || use_b64_encode) {
     376       91305 :                                 ret = fprintf_fn(private_data, "%s:: ",
     377       91305 :                                                  msg->elements[i].name);
     378       91305 :                                 CHECK_RET;
     379      273327 :                                 ret = base64_encode_f(ldb, fprintf_fn, private_data,
     380      182316 :                                                       (char *)v.data, v.length,
     381       91305 :                                                       namelen + 3);
     382       91305 :                                 CHECK_RET;
     383       91305 :                                 ret = fprintf_fn(private_data, "\n");
     384       91305 :                                 CHECK_RET;
     385             :                         } else {
     386      725735 :                                 ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
     387      725735 :                                 CHECK_RET;
     388      725735 :                                 if (copy_raw_bytes) {
     389        5091 :                                         ret = fprintf_fn(private_data, "%*.*s",
     390        5091 :                                                          v.length, v.length, (char *)v.data);
     391             :                                 } else {
     392     1434508 :                                         ret = fold_string(fprintf_fn, private_data,
     393      720644 :                                                           (char *)v.data, v.length,
     394      720644 :                                                           namelen + 2);
     395             :                                 }
     396      725735 :                                 CHECK_RET;
     397      725735 :                                 ret = fprintf_fn(private_data, "\n");
     398      725735 :                                 CHECK_RET;
     399             :                         }
     400      817040 :                         if (v.data != msg->elements[i].values[j].data) {
     401      816968 :                                 talloc_free(v.data);
     402             :                         }
     403             :                 }
     404      697428 :                 if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
     405           0 :                         fprintf_fn(private_data, "-\n");
     406             :                 }
     407             :         }
     408      102418 :         ret = fprintf_fn(private_data,"\n");
     409      102418 :         CHECK_RET;
     410             : 
     411      102418 :         talloc_free(mem_ctx);
     412             : 
     413      102418 :         return total;
     414             : }
     415             : 
     416             : #undef CHECK_RET
     417             : 
     418             : 
     419             : /*
     420             :   write to ldif, using a caller supplied write method
     421             : */
     422      102394 : int ldb_ldif_write(struct ldb_context *ldb,
     423             :                    int (*fprintf_fn)(void *, const char *, ...),
     424             :                    void *private_data,
     425             :                    const struct ldb_ldif *ldif)
     426             : {
     427      102394 :         return ldb_ldif_write_trace(ldb, fprintf_fn, private_data, ldif, false);
     428             : }
     429             : 
     430             : 
     431             : /*
     432             :   pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
     433             :   this routine removes any RFC2849 continuations and comments
     434             : 
     435             :   caller frees
     436             : */
     437     1061885 : static char *next_chunk(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
     438             :                         int (*fgetc_fn)(void *), void *private_data)
     439             : {
     440      942328 :         size_t alloc_size=0, chunk_size = 0;
     441      942328 :         char *chunk = NULL;
     442             :         int c;
     443      942328 :         int in_comment = 0;
     444             : 
     445   710426219 :         while ((c = fgetc_fn(private_data)) != EOF) {
     446   709642953 :                 if (chunk_size+1 >= alloc_size) {
     447             :                         char *c2;
     448     1185067 :                         alloc_size += 1024;
     449     1185067 :                         c2 = talloc_realloc(mem_ctx, chunk, char, alloc_size);
     450     1185067 :                         if (!c2) {
     451           0 :                                 talloc_free(chunk);
     452           0 :                                 errno = ENOMEM;
     453           0 :                                 return NULL;
     454             :                         }
     455     1047907 :                         chunk = c2;
     456             :                 }
     457             : 
     458   709642953 :                 if (in_comment) {
     459     1442908 :                         if (c == '\n') {
     460       31985 :                                 in_comment = 0;
     461             :                         }
     462     1442908 :                         continue;
     463             :                 }
     464             : 
     465             :                 /* handle continuation lines - see RFC2849 */
     466   708200045 :                 if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
     467      329205 :                         chunk_size--;
     468      329205 :                         continue;
     469             :                 }
     470             : 
     471             :                 /* chunks are terminated by a double line-feed */
     472   707870840 :                 if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
     473     1028135 :                         chunk[chunk_size-1] = 0;
     474      909419 :                         return chunk;
     475             :                 }
     476             : 
     477   706842705 :                 if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
     478       31985 :                         in_comment = 1;
     479       31985 :                         continue;
     480             :                 }
     481             : 
     482             :                 /* ignore leading blank lines */
     483   706810720 :                 if (chunk_size == 0 && c == '\n') {
     484       30950 :                         continue;
     485             :                 }
     486             : 
     487   706779770 :                 chunk[chunk_size++] = c;
     488             :         }
     489             : 
     490       33750 :         if (chunk) {
     491       32152 :                 chunk[chunk_size] = 0;
     492             :         }
     493             : 
     494       32909 :         return chunk;
     495             : }
     496             : 
     497             : 
     498             : /* simple ldif attribute parser */
     499    19966444 : static int next_attr(TALLOC_CTX *mem_ctx, char **s, const char **attr, struct ldb_val *value)
     500             : {
     501             :         char *p;
     502    19966444 :         int base64_encoded = 0;
     503    19966444 :         int binary_file = 0;
     504             : 
     505    19966444 :         if (strncmp(*s, "-\n", 2) == 0) {
     506       15012 :                 value->length = 0;
     507       15012 :                 *attr = "-";
     508       15012 :                 *s += 2;
     509       15012 :                 return 0;
     510             :         }
     511             : 
     512    19951432 :         p = strchr(*s, ':');
     513    19951432 :         if (!p) {
     514      940820 :                 return -1;
     515             :         }
     516             : 
     517    18891145 :         *p++ = 0;
     518             : 
     519    18891145 :         if (*p == ':') {
     520     1821336 :                 base64_encoded = 1;
     521     1821336 :                 p++;
     522             :         }
     523             : 
     524    18891145 :         if (*p == '<') {
     525           4 :                 binary_file = 1;
     526           4 :                 p++;
     527             :         }
     528             : 
     529    18891145 :         *attr = *s;
     530             : 
     531    53375033 :         while (*p == ' ' || *p == '\t') {
     532    18890843 :                 p++;
     533             :         }
     534             : 
     535    18891145 :         value->data = (uint8_t *)p;
     536             : 
     537    18891145 :         p = strchr(p, '\n');
     538             : 
     539    18891145 :         if (!p) {
     540     1019718 :                 value->length = strlen((char *)value->data);
     541     1019718 :                 *s = ((char *)value->data) + value->length;
     542             :         } else {
     543    17871427 :                 value->length = p - (char *)value->data;
     544    17871427 :                 *s = p+1;
     545    17871427 :                 *p = 0;
     546             :         }
     547             : 
     548    18891145 :         if (base64_encoded) {
     549     1821336 :                 int len = ldb_base64_decode((char *)value->data);
     550     1821336 :                 if (len == -1) {
     551             :                         /* it wasn't valid base64 data */
     552           0 :                         return -1;
     553             :                 }
     554     1821336 :                 value->length = len;
     555             :         }
     556             : 
     557    18891145 :         if (binary_file) {
     558           4 :                 int len = ldb_read_data_file(mem_ctx, value);
     559           4 :                 if (len == -1) {
     560             :                         /* an error occurred while trying to retrieve the file */
     561           0 :                         return -1;
     562             :                 }
     563             :         }
     564             : 
     565    16825774 :         return 0;
     566             : }
     567             : 
     568             : 
     569             : /*
     570             :   free a message from a ldif_read
     571             : */
     572         759 : void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
     573             : {
     574         759 :         talloc_free(ldif);
     575         759 : }
     576             : 
     577          12 : int ldb_ldif_parse_modrdn(struct ldb_context *ldb,
     578             :                           const struct ldb_ldif *ldif,
     579             :                           TALLOC_CTX *mem_ctx,
     580             :                           struct ldb_dn **_olddn,
     581             :                           struct ldb_dn **_newrdn,
     582             :                           bool *_deleteoldrdn,
     583             :                           struct ldb_dn **_newsuperior,
     584             :                           struct ldb_dn **_newdn)
     585             : {
     586          12 :         struct ldb_message *msg = ldif->msg;
     587          12 :         struct ldb_val *newrdn_val = NULL;
     588          12 :         struct ldb_val *deleteoldrdn_val = NULL;
     589          12 :         struct ldb_val *newsuperior_val = NULL;
     590          12 :         struct ldb_dn *olddn = NULL;
     591          12 :         struct ldb_dn *newrdn = NULL;
     592          12 :         bool deleteoldrdn = true;
     593          12 :         struct ldb_dn *newsuperior = NULL;
     594          12 :         struct ldb_dn *newdn = NULL;
     595             :         struct ldb_val tmp_false;
     596             :         struct ldb_val tmp_true;
     597             :         bool ok;
     598          12 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     599             : 
     600          12 :         if (tmp_ctx == NULL) {
     601           0 :                 ldb_debug(ldb, LDB_DEBUG_FATAL,
     602             :                           "Error: talloc_new() failed");
     603           0 :                 goto err_op;
     604             :         }
     605             : 
     606          12 :         if (ldif->changetype != LDB_CHANGETYPE_MODRDN) {
     607           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     608             :                           "Error: invalid changetype '%d'",
     609           0 :                           ldif->changetype);
     610           0 :                 goto err_other;
     611             :         }
     612             : 
     613          12 :         if (msg->num_elements < 2) {
     614           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     615             :                           "Error: num_elements[%u] < 2",
     616             :                           msg->num_elements);
     617           0 :                 goto err_other;
     618             :         }
     619             : 
     620          12 :         if (msg->num_elements > 3) {
     621           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     622             :                           "Error: num_elements[%u] > 3",
     623             :                           msg->num_elements);
     624           0 :                 goto err_other;
     625             :         }
     626             : 
     627             : #define CHECK_ELEMENT(i, _name, v, needed) do { \
     628             :         v = NULL; \
     629             :         if (msg->num_elements < (i + 1)) { \
     630             :                 if (needed) { \
     631             :                         ldb_debug(ldb, LDB_DEBUG_ERROR, \
     632             :                                   "Error: num_elements[%u] < (%u + 1)", \
     633             :                                   msg->num_elements, i); \
     634             :                         goto err_other; \
     635             :                 } \
     636             :         } else if (ldb_attr_cmp(msg->elements[i].name, _name) != 0) { \
     637             :                 ldb_debug(ldb, LDB_DEBUG_ERROR, \
     638             :                           "Error: elements[%u].name[%s] != [%s]", \
     639             :                           i, msg->elements[i].name, _name); \
     640             :                 goto err_other; \
     641             :         } else if (msg->elements[i].flags != 0) { \
     642             :                 ldb_debug(ldb, LDB_DEBUG_ERROR, \
     643             :                           "Error: elements[%u].flags[0x%X} != [0x0]", \
     644             :                           i, msg->elements[i].flags); \
     645             :                 goto err_other; \
     646             :         } else if (msg->elements[i].num_values != 1) { \
     647             :                 ldb_debug(ldb, LDB_DEBUG_ERROR, \
     648             :                           "Error: elements[%u].num_values[%u] != 1", \
     649             :                           i, msg->elements[i].num_values); \
     650             :                 goto err_other; \
     651             :         } else { \
     652             :                 v = &msg->elements[i].values[0]; \
     653             :         } \
     654             : } while (0)
     655             : 
     656          12 :         CHECK_ELEMENT(0, "newrdn", newrdn_val, true);
     657          12 :         CHECK_ELEMENT(1, "deleteoldrdn", deleteoldrdn_val, true);
     658          12 :         CHECK_ELEMENT(2, "newsuperior", newsuperior_val, false);
     659             : 
     660             : #undef CHECK_ELEMENT
     661             : 
     662          12 :         olddn = ldb_dn_copy(tmp_ctx, msg->dn);
     663          12 :         if (olddn == NULL) {
     664           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     665             :                           "Error: failed to copy olddn '%s'",
     666             :                           ldb_dn_get_linearized(msg->dn));
     667           0 :                 goto err_op;
     668             :         }
     669             : 
     670          12 :         newrdn = ldb_dn_from_ldb_val(tmp_ctx, ldb, newrdn_val);
     671          12 :         if (!ldb_dn_validate(newrdn)) {
     672           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     673             :                           "Error: Unable to parse dn '%s'",
     674           0 :                           (char *)newrdn_val->data);
     675           0 :                 goto err_dn;
     676             :         }
     677             : 
     678          12 :         tmp_false.length = 1;
     679          12 :         tmp_false.data = discard_const_p(uint8_t, "0");
     680          12 :         tmp_true.length = 1;
     681          12 :         tmp_true.data = discard_const_p(uint8_t, "1");
     682          12 :         if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_false) == 1) {
     683           0 :                 deleteoldrdn = false;
     684          12 :         } else if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_true) == 1) {
     685           6 :                 deleteoldrdn = true;
     686             :         } else {
     687           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     688             :                           "Error: deleteoldrdn value invalid '%s' not '0'/'1'",
     689           0 :                           (char *)deleteoldrdn_val->data);
     690           0 :                 goto err_attr;
     691             :         }
     692             : 
     693          12 :         if (newsuperior_val) {
     694           4 :                 newsuperior = ldb_dn_from_ldb_val(tmp_ctx, ldb, newsuperior_val);
     695           4 :                 if (!ldb_dn_validate(newsuperior)) {
     696           0 :                         ldb_debug(ldb, LDB_DEBUG_ERROR,
     697             :                                   "Error: Unable to parse dn '%s'",
     698           0 :                                   (char *)newsuperior_val->data);
     699           0 :                         goto err_dn;
     700             :                 }
     701             :         } else {
     702           8 :                 newsuperior = ldb_dn_get_parent(tmp_ctx, msg->dn);
     703           8 :                 if (newsuperior == NULL) {
     704           0 :                         ldb_debug(ldb, LDB_DEBUG_ERROR,
     705             :                                   "Error: Unable to get parent dn '%s'",
     706             :                                   ldb_dn_get_linearized(msg->dn));
     707           0 :                         goto err_dn;
     708             :                 }
     709             :         }
     710             : 
     711          12 :         newdn = ldb_dn_copy(tmp_ctx, newrdn);
     712          12 :         if (newdn == NULL) {
     713           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     714             :                           "Error: failed to copy newrdn '%s'",
     715             :                           ldb_dn_get_linearized(newrdn));
     716           0 :                 goto err_op;
     717             :         }
     718             : 
     719          12 :         ok = ldb_dn_add_base(newdn, newsuperior);
     720          12 :         if (!ok) {
     721           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     722             :                           "Error: failed to base '%s' to newdn '%s'",
     723             :                           ldb_dn_get_linearized(newsuperior),
     724             :                           ldb_dn_get_linearized(newdn));
     725           0 :                 goto err_op;
     726             :         }
     727             : 
     728          12 :         if (_olddn) {
     729           6 :                 *_olddn = talloc_move(mem_ctx, &olddn);
     730             :         }
     731          12 :         if (_newrdn) {
     732           0 :                 *_newrdn = talloc_move(mem_ctx, &newrdn);
     733             :         }
     734          12 :         if (_deleteoldrdn) {
     735           6 :                 *_deleteoldrdn = deleteoldrdn;
     736             :         }
     737          12 :         if (_newsuperior != NULL && _newrdn != NULL) {
     738           0 :                 if (newsuperior_val) {
     739           0 :                         *_newrdn = talloc_move(mem_ctx, &newrdn);
     740             :                 } else {
     741           0 :                         *_newrdn = NULL;
     742             :                 }
     743             :         }
     744          12 :         if (_newdn) {
     745           6 :                 *_newdn = talloc_move(mem_ctx, &newdn);
     746             :         }
     747             : 
     748          12 :         talloc_free(tmp_ctx);
     749          12 :         return LDB_SUCCESS;
     750           0 : err_other:
     751           0 :         talloc_free(tmp_ctx);
     752           0 :         return LDB_ERR_OTHER;
     753           0 : err_op:
     754           0 :         talloc_free(tmp_ctx);
     755           0 :         return LDB_ERR_OPERATIONS_ERROR;
     756           0 : err_attr:
     757           0 :         talloc_free(tmp_ctx);
     758           0 :         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
     759           0 : err_dn:
     760           0 :         talloc_free(tmp_ctx);
     761           0 :         return LDB_ERR_INVALID_DN_SYNTAX;
     762             : }
     763             : 
     764             : /*
     765             :  read from a LDIF source, creating a ldb_message
     766             : */
     767     1061885 : struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
     768             :                                int (*fgetc_fn)(void *), void *private_data)
     769             : {
     770             :         struct ldb_ldif *ldif;
     771             :         struct ldb_message *msg;
     772     1061885 :         const char *attr=NULL;
     773     1061885 :         char *chunk=NULL, *s;
     774             :         struct ldb_val value;
     775     1061885 :         unsigned flags = 0;
     776     1061885 :         value.data = NULL;
     777             : 
     778     1061885 :         ldif = talloc(ldb, struct ldb_ldif);
     779     1061885 :         if (!ldif) return NULL;
     780             : 
     781     1061885 :         ldif->msg = ldb_msg_new(ldif);
     782     1061885 :         if (ldif->msg == NULL) {
     783           0 :                 talloc_free(ldif);
     784           0 :                 return NULL;
     785             :         }
     786             : 
     787     1061885 :         ldif->changetype = LDB_CHANGETYPE_NONE;
     788     1061885 :         msg = ldif->msg;
     789             : 
     790     1061885 :         chunk = next_chunk(ldb, ldif, fgetc_fn, private_data);
     791     1061885 :         if (!chunk) {
     792        1508 :                 goto failed;
     793             :         }
     794             : 
     795     1060287 :         s = chunk;
     796             : 
     797     1060287 :         if (next_attr(ldif, &s, &attr, &value) != 0) {
     798         425 :                 goto failed;
     799             :         }
     800             : 
     801             :         /* first line must be a dn */
     802     1059861 :         if (ldb_attr_cmp(attr, "dn") != 0) {
     803           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'",
     804             :                           attr);
     805           0 :                 goto failed;
     806             :         }
     807             : 
     808     1059861 :         msg->dn = ldb_dn_from_ldb_val(msg, ldb, &value);
     809             : 
     810     1059861 :         if ( ! ldb_dn_validate(msg->dn)) {
     811           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Unable to parse dn '%s'",
     812           0 :                           (char *)value.data);
     813           0 :                 goto failed;
     814             :         }
     815             : 
     816    19653972 :         while (next_attr(ldif, &s, &attr, &value) == 0) {
     817             :                 const struct ldb_schema_attribute *a;
     818             :                 struct ldb_message_element *el;
     819    17846296 :                 int ret, empty = 0;
     820             : 
     821    17846296 :                 if (ldb_attr_cmp(attr, "changetype") == 0) {
     822             :                         int i;
     823      105262 :                         for (i=0;ldb_changetypes[i].name;i++) {
     824      107403 :                                 if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) {
     825       36520 :                                         ldif->changetype = ldb_changetypes[i].changetype;
     826       36520 :                                         break;
     827             :                                 }
     828             :                         }
     829       36520 :                         if (!ldb_changetypes[i].name) {
     830           0 :                                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     831           0 :                                           "Error: Bad ldif changetype '%s'",(char *)value.data);
     832             :                         }
     833       36520 :                         flags = 0;
     834       36520 :                         continue;
     835             :                 }
     836             : 
     837    17809776 :                 if (ldb_attr_cmp(attr, "add") == 0) {
     838       19854 :                         flags = LDB_FLAG_MOD_ADD;
     839       19854 :                         empty = 1;
     840             :                 }
     841    17809776 :                 if (ldb_attr_cmp(attr, "delete") == 0) {
     842       10844 :                         flags = LDB_FLAG_MOD_DELETE;
     843       10844 :                         empty = 1;
     844             :                 }
     845    17809776 :                 if (ldb_attr_cmp(attr, "replace") == 0) {
     846       25582 :                         flags = LDB_FLAG_MOD_REPLACE;
     847       25582 :                         empty = 1;
     848             :                 }
     849    17809776 :                 if (ldb_attr_cmp(attr, "-") == 0) {
     850       15012 :                         flags = 0;
     851       15012 :                         continue;
     852             :                 }
     853             : 
     854    17794764 :                 if (empty) {
     855       56280 :                         if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) {
     856           0 :                                 goto failed;
     857             :                         }
     858       56280 :                         continue;
     859             :                 }
     860             : 
     861    17738484 :                 el = &msg->elements[msg->num_elements-1];
     862             : 
     863    17738484 :                 a = ldb_schema_attribute_by_name(ldb, attr);
     864             : 
     865    20526780 :                 if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
     866     3459969 :                     flags == el->flags) {
     867             :                         /* its a continuation */
     868     3459969 :                         el->values =
     869     3459969 :                                 talloc_realloc(msg->elements, el->values,
     870             :                                                  struct ldb_val, el->num_values+1);
     871     3459969 :                         if (!el->values) {
     872           0 :                                 goto failed;
     873             :                         }
     874     3459969 :                         ret = a->syntax->ldif_read_fn(ldb, el->values, &value, &el->values[el->num_values]);
     875     3459969 :                         if (ret != 0) {
     876           0 :                                 goto failed;
     877             :                         }
     878     3459969 :                         if (value.length == 0) {
     879           0 :                                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     880             :                                           "Error: Attribute value cannot be empty for attribute '%s'", el->name);
     881           0 :                                 goto failed;
     882             :                         }
     883     3459969 :                         if (value.data != el->values[el->num_values].data) {
     884     3459969 :                                 talloc_steal(el->values, el->values[el->num_values].data);
     885             :                         }
     886     3459969 :                         el->num_values++;
     887             :                 } else {
     888             :                         /* its a new attribute */
     889    14278515 :                         msg->elements = talloc_realloc(msg, msg->elements,
     890             :                                                          struct ldb_message_element,
     891             :                                                          msg->num_elements+1);
     892    14278515 :                         if (!msg->elements) {
     893           0 :                                 goto failed;
     894             :                         }
     895    14278515 :                         el = &msg->elements[msg->num_elements];
     896    14278515 :                         el->flags = flags;
     897    14278515 :                         el->name = talloc_strdup(msg->elements, attr);
     898    14278515 :                         el->values = talloc(msg->elements, struct ldb_val);
     899    26153371 :                         if (!el->values || !el->name) {
     900           0 :                                 goto failed;
     901             :                         }
     902    14278515 :                         el->num_values = 1;
     903    14278515 :                         ret = a->syntax->ldif_read_fn(ldb, el->values, &value, &el->values[0]);
     904    14278515 :                         if (ret != 0) {
     905           0 :                                 goto failed;
     906             :                         }
     907    14278515 :                         if (value.data != el->values[0].data) {
     908    14278515 :                                 talloc_steal(el->values, el->values[0].data);
     909             :                         }
     910    14278515 :                         msg->num_elements++;
     911             :                 }
     912             :         }
     913             : 
     914     1059861 :         if (ldif->changetype == LDB_CHANGETYPE_MODRDN) {
     915             :                 int ret;
     916             : 
     917           6 :                 ret = ldb_ldif_parse_modrdn(ldb, ldif, ldif,
     918             :                                             NULL, NULL, NULL, NULL, NULL);
     919           6 :                 if (ret != LDB_SUCCESS) {
     920           0 :                         goto failed;
     921             :                 }
     922             :         }
     923             : 
     924      940395 :         return ldif;
     925             : 
     926        2024 : failed:
     927        2024 :         talloc_free(ldif);
     928        2024 :         return NULL;
     929             : }
     930             : 
     931             : 
     932             : 
     933             : /*
     934             :   a wrapper around ldif_read() for reading from FILE*
     935             : */
     936             : 
     937      206084 : static int fgetc_file(void *private_data)
     938             : {
     939             :         int c;
     940      206084 :         struct ldif_read_file_state *state =
     941             :                 (struct ldif_read_file_state *)private_data;
     942      206084 :         c = fgetc(state->f);
     943      206084 :         if (c == '\n') {
     944        5156 :                 state->line_no++;
     945             :         }
     946      206084 :         return c;
     947             : }
     948             : 
     949        1350 : struct ldb_ldif *ldb_ldif_read_file_state(struct ldb_context *ldb,
     950             :                                           struct ldif_read_file_state *state)
     951             : {
     952        1350 :         return ldb_ldif_read(ldb, fgetc_file, state);
     953             : }
     954             : 
     955           0 : struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f)
     956             : {
     957             :         struct ldif_read_file_state state;
     958           0 :         state.f = f;
     959           0 :         return ldb_ldif_read_file_state(ldb, &state);
     960             : }
     961             : 
     962             : /*
     963             :   a wrapper around ldif_read() for reading from const char*
     964             : */
     965             : struct ldif_read_string_state {
     966             :         const char *s;
     967             : };
     968             : 
     969   709470619 : static int fgetc_string(void *private_data)
     970             : {
     971   709470619 :         struct ldif_read_string_state *state =
     972             :                 (struct ldif_read_string_state *)private_data;
     973   709470619 :         if (state->s[0] != 0) {
     974   709438082 :                 return *state->s++;
     975             :         }
     976       31826 :         return EOF;
     977             : }
     978             : 
     979     1060535 : struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s)
     980             : {
     981             :         struct ldif_read_string_state state;
     982             :         struct ldb_ldif *ldif;
     983     1060535 :         state.s = *s;
     984     1060535 :         ldif = ldb_ldif_read(ldb, fgetc_string, &state);
     985     1060535 :         *s = state.s;
     986     1060535 :         return ldif;
     987             : }
     988             : 
     989             : 
     990             : /*
     991             :   wrapper around ldif_write() for a file
     992             : */
     993             : struct ldif_write_file_state {
     994             :         FILE *f;
     995             : };
     996             : 
     997             : static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
     998             : 
     999    41123767 : static int fprintf_file(void *private_data, const char *fmt, ...)
    1000             : {
    1001    41123767 :         struct ldif_write_file_state *state =
    1002             :                 (struct ldif_write_file_state *)private_data;
    1003             :         int ret;
    1004             :         va_list ap;
    1005             : 
    1006    41123767 :         va_start(ap, fmt);
    1007    79167676 :         ret = vfprintf(state->f, fmt, ap);
    1008    41123767 :         va_end(ap);
    1009    41123767 :         return ret;
    1010             : }
    1011             : 
    1012       93480 : int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif)
    1013             : {
    1014             :         struct ldif_write_file_state state;
    1015       93480 :         state.f = f;
    1016       93480 :         return ldb_ldif_write(ldb, fprintf_file, &state, ldif);
    1017             : }
    1018             : 
    1019             : /*
    1020             :   wrapper around ldif_write() for a string
    1021             : */
    1022             : struct ldif_write_string_state {
    1023             :         char *string;
    1024             : };
    1025             : 
    1026             : static int ldif_printf_string(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
    1027             : 
    1028     3623645 : static int ldif_printf_string(void *private_data, const char *fmt, ...)
    1029             : {
    1030     3623645 :         struct ldif_write_string_state *state =
    1031             :                 (struct ldif_write_string_state *)private_data;
    1032             :         va_list ap;
    1033     3623645 :         size_t oldlen = talloc_get_size(state->string);
    1034     3623645 :         va_start(ap, fmt);
    1035             : 
    1036     3623645 :         state->string = talloc_vasprintf_append(state->string, fmt, ap);
    1037     3623645 :         va_end(ap);
    1038     3623645 :         if (!state->string) {
    1039           0 :                 return -1;
    1040             :         }
    1041             : 
    1042     3623645 :         return talloc_get_size(state->string) - oldlen;
    1043             : }
    1044             : 
    1045          24 : char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    1046             :                                            const struct ldb_ldif *ldif)
    1047             : {
    1048             :         struct ldif_write_string_state state;
    1049          24 :         state.string = talloc_strdup(mem_ctx, "");
    1050          24 :         if (!state.string) {
    1051           0 :                 return NULL;
    1052             :         }
    1053          24 :         if (ldb_ldif_write_trace(ldb, ldif_printf_string, &state, ldif, true) == -1) {
    1054           0 :                 return NULL;
    1055             :         }
    1056          24 :         return state.string;
    1057             : }
    1058             : 
    1059        8914 : char *ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    1060             :                             const struct ldb_ldif *ldif)
    1061             : {
    1062             :         struct ldif_write_string_state state;
    1063        8914 :         state.string = talloc_strdup(mem_ctx, "");
    1064        8914 :         if (!state.string) {
    1065           0 :                 return NULL;
    1066             :         }
    1067        8914 :         if (ldb_ldif_write(ldb, ldif_printf_string, &state, ldif) == -1) {
    1068           0 :                 return NULL;
    1069             :         }
    1070        8914 :         return state.string;
    1071             : }
    1072             : 
    1073             : /*
    1074             :   convenient function to turn a ldb_message into a string. Useful for
    1075             :   debugging
    1076             :  */
    1077          24 : char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    1078             :                               enum ldb_changetype changetype,
    1079             :                               const struct ldb_message *msg)
    1080             : {
    1081             :         struct ldb_ldif ldif;
    1082             : 
    1083          24 :         ldif.changetype = changetype;
    1084          24 :         ldif.msg = discard_const_p(struct ldb_message, msg);
    1085             : 
    1086          24 :         return ldb_ldif_write_string(ldb, mem_ctx, &ldif);
    1087             : }
    1088             : 
    1089             : /*
    1090             :  * convenient function to turn a ldb_message into a string. Useful for
    1091             :  * debugging but also safer if some of the LDIF could be sensitive.
    1092             :  *
    1093             :  * The secret attributes are specified in a 'const char * const *' within
    1094             :  * the LDB_SECRET_ATTRIBUTE_LIST opaque set on the ldb
    1095             :  *
    1096             :  */
    1097          24 : char *ldb_ldif_message_redacted_string(struct ldb_context *ldb,
    1098             :                                        TALLOC_CTX *mem_ctx,
    1099             :                                        enum ldb_changetype changetype,
    1100             :                                        const struct ldb_message *msg)
    1101             : {
    1102             :         struct ldb_ldif ldif;
    1103             : 
    1104          24 :         ldif.changetype = changetype;
    1105          24 :         ldif.msg = discard_const_p(struct ldb_message, msg);
    1106             : 
    1107          24 :         return ldb_ldif_write_redacted_trace_string(ldb, mem_ctx, &ldif);
    1108             : }

Generated by: LCOV version 1.13