LCOV - code coverage report
Current view: top level - lib/ldb/tools - ldbdump.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 111 204 54.4 %
Date: 2024-04-21 15:09:00 Functions: 6 9 66.7 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    simple ldb tdb dump util
       4             :    Copyright (C) Andrew Tridgell              2001
       5             :    Copyright (C) Andrew Bartlett              2012
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "replace.h"
      22             : #include "system/locale.h"
      23             : #include "system/time.h"
      24             : #include "system/filesys.h"
      25             : #include "system/wait.h"
      26             : #include <tdb.h>
      27             : #include <ldb.h>
      28             : #include <ldb_private.h>
      29             : 
      30             : #ifdef HAVE_LMDB
      31             : #include <lmdb.h>
      32             : #endif /* ifdef HAVE_LMDB */
      33             : 
      34             : 
      35             : static struct ldb_context *ldb;
      36             : bool show_index = false;
      37             : bool validate_contents = false;
      38             : 
      39       90042 : static void print_data(TDB_DATA d)
      40             : {
      41       90042 :         unsigned char *p = (unsigned char *)d.dptr;
      42       90042 :         int len = d.dsize;
      43     4318028 :         while (len--) {
      44     4227986 :                 if (isprint(*p) && !strchr("\"\\", *p)) {
      45     4036971 :                         fputc(*p, stdout);
      46             :                 } else {
      47      191015 :                         printf("\\%02X", *p);
      48             :                 }
      49     4227986 :                 p++;
      50             :         }
      51       90042 : }
      52             : 
      53       90042 : static unsigned int pull_uint32(uint8_t *p)
      54             : {
      55       90042 :        return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
      56             : }
      57             : 
      58             : 
      59       90042 : static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA _dbuf, void *state)
      60             : {
      61       90042 :         int ret, i, j;
      62       90042 :         struct ldb_dn *dn = state;
      63       90042 :         struct ldb_message *msg = ldb_msg_new(NULL);
      64       90042 :         struct ldb_val dbuf = {
      65           0 :                 .data = _dbuf.dptr,
      66       90042 :                 .length = _dbuf.dsize,
      67             :         };
      68       90042 :         struct ldb_ldif ldif = {
      69             :                 .msg = msg,
      70             :                 .changetype = LDB_CHANGETYPE_NONE
      71             :         };
      72       90042 :         if (!msg) {
      73           0 :                 return -1;
      74             :         }
      75             : 
      76       90042 :         ret = ldb_unpack_data(ldb, &dbuf, msg);
      77       90042 :         if (ret != 0) {
      78           0 :                 fprintf(stderr, "Failed to parse record %*.*s as an LDB record\n", (int)key.dsize, (int)key.dsize, (char *)key.dptr);
      79           0 :                 TALLOC_FREE(msg);
      80           0 :                 return 0;
      81             :         }
      82             : 
      83       90042 :         if (dn && ldb_dn_compare(msg->dn, dn) != 0) {
      84           0 :                 TALLOC_FREE(msg);
      85           0 :                 return 0;
      86             :         }
      87             : 
      88       90042 :         if (!show_index && ldb_dn_is_special(msg->dn)) {
      89           0 :                 const char *dn_lin = ldb_dn_get_linearized(msg->dn);
      90           0 :                 if ((strcmp(dn_lin, "@BASEINFO") == 0) || (strncmp(dn_lin, "@INDEX:", strlen("@INDEX:")) == 0)) {
      91             :                         /*
      92             :                           the user has asked not to show index
      93             :                           records. Also exclude BASEINFO as it
      94             :                           contains meta-data which will be re-created
      95             :                           if this database is restored
      96             :                          */
      97           0 :                         TALLOC_FREE(msg);
      98           0 :                         return 0;
      99             :                 }
     100             :         }
     101             : 
     102       90042 :         printf("# key: ");
     103       90042 :         print_data(key);
     104       90042 :         printf("\n# pack format: %#010x\n", pull_uint32(_dbuf.dptr));
     105             : 
     106       90042 :         if (!validate_contents || ldb_dn_is_special(msg->dn)) {
     107       90042 :                 ldb_ldif_write_file(ldb, stdout, &ldif);
     108       90042 :                 TALLOC_FREE(msg);
     109       90042 :                 return 0;
     110             :         }
     111             : 
     112           0 :         for (i=0;i<msg->num_elements;i++) {
     113           0 :                 const struct ldb_schema_attribute *a;
     114             : 
     115           0 :                 a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
     116           0 :                 for (j=0;j<msg->elements[i].num_values;j++) {
     117           0 :                         struct ldb_val v;
     118           0 :                         ret = a->syntax->ldif_write_fn(ldb, msg, &msg->elements[i].values[j], &v);
     119           0 :                         if (ret != 0) {
     120           0 :                                 v = msg->elements[i].values[j];
     121           0 :                                 if (ldb_should_b64_encode(ldb, &v)) {
     122           0 :                                         v.data = (uint8_t *)ldb_base64_encode(ldb, (char *)v.data, v.length);
     123           0 :                                         v.length = strlen((char *)v.data);
     124             :                                 }
     125           0 :                                 fprintf(stderr, "On %s element %s value %d (%*.*s) failed to convert to LDIF correctly, skipping possibly corrupt record\n",
     126             :                                         ldb_dn_get_linearized(msg->dn),
     127           0 :                                         msg->elements[i].name,
     128           0 :                                         j, (int)v.length, (int)v.length,
     129             :                                         v.data);
     130           0 :                                 TALLOC_FREE(msg);
     131           0 :                                 return 0;
     132             :                         }
     133             :                 }
     134             :         }
     135           0 :         ldb_ldif_write_file(ldb, stdout, &ldif);
     136           0 :         TALLOC_FREE(msg);
     137             : 
     138           0 :         return 0;
     139             : }
     140             : 
     141             : static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
     142             :                        const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
     143             : 
     144           0 : static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
     145             :                        const char *fmt, ...)
     146             : {
     147           0 :         va_list ap;
     148           0 :         const char *name = tdb_name(tdb);
     149           0 :         const char *prefix = "";
     150             : 
     151           0 :         if (!name)
     152           0 :                 name = "unnamed";
     153             : 
     154           0 :         switch (level) {
     155           0 :         case TDB_DEBUG_ERROR:
     156           0 :                 prefix = "ERROR: ";
     157           0 :                 break;
     158           0 :         case TDB_DEBUG_WARNING:
     159           0 :                 prefix = "WARNING: ";
     160           0 :                 break;
     161           0 :         case TDB_DEBUG_TRACE:
     162           0 :                 return;
     163             : 
     164           0 :         default:
     165             :         case TDB_DEBUG_FATAL:
     166           0 :                 prefix = "FATAL: ";
     167           0 :                 break;
     168             :         }
     169             : 
     170           0 :         va_start(ap, fmt);
     171           0 :         fprintf(stderr, "tdb(%s): %s", name, prefix);
     172           0 :         vfprintf(stderr, fmt, ap);
     173           0 :         va_end(ap);
     174             : }
     175             : 
     176           0 : static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname)
     177             : {
     178           0 :         traverse_fn(NULL, key, dbuf, keyname);
     179           0 : }
     180             : 
     181          48 : static int dump_tdb(const char *fname, struct ldb_dn *dn, bool emergency)
     182             : {
     183          48 :         TDB_CONTEXT *tdb;
     184          48 :         struct tdb_logging_context logfn = {
     185             :                 .log_fn = log_stderr,
     186             :         };
     187             : 
     188          48 :         tdb = tdb_open_ex(fname, 0, 0, O_RDONLY, 0, &logfn, NULL);
     189          48 :         if (!tdb) {
     190           0 :                 fprintf(stderr, "Failed to open %s\n", fname);
     191           0 :                 return 1;
     192             :         }
     193             : 
     194          48 :         if (emergency) {
     195           0 :                 return tdb_rescue(tdb, emergency_walk, dn) == 0;
     196             :         }
     197          48 :         return tdb_traverse(tdb, traverse_fn, dn) == -1 ? 1 : 0;
     198             : }
     199             : 
     200             : #ifdef HAVE_LMDB
     201          58 : static int dump_lmdb(const char *fname, struct ldb_dn *dn, bool emergency)
     202             : {
     203          58 :         int ret;
     204          58 :         struct MDB_env *env = NULL;
     205          58 :         struct MDB_txn *txn = NULL;
     206          58 :         MDB_dbi dbi;
     207          58 :         struct MDB_cursor *cursor = NULL;
     208          58 :         struct MDB_val key;
     209          58 :         struct MDB_val data;
     210             : 
     211          58 :         ret = mdb_env_create(&env);
     212          58 :         if (ret != 0) {
     213           0 :                 fprintf(stderr,
     214             :                         "Could not create MDB environment: (%d)  %s\n",
     215             :                         ret,
     216             :                         mdb_strerror(ret));
     217           0 :                 goto close_env;
     218             :         }
     219             : 
     220          58 :         ret = mdb_env_open(env,
     221             :                            fname,
     222             :                            MDB_NOSUBDIR|MDB_NOTLS|MDB_RDONLY,
     223             :                            0600);
     224          58 :         if (ret != 0) {
     225          48 :                 fprintf(stderr,
     226             :                         "Could not open environment for %s: (%d)  %s\n",
     227             :                         fname,
     228             :                         ret,
     229             :                         mdb_strerror(ret));
     230          48 :                 goto close_env;
     231             :         }
     232             : 
     233          10 :         ret = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
     234          10 :         if (ret != 0) {
     235           0 :                 fprintf(stderr,
     236             :                         "Could not start transaction: (%d)  %s\n",
     237             :                         ret,
     238             :                         mdb_strerror(ret));
     239           0 :                 goto close_env;
     240             :         }
     241             : 
     242          10 :         ret = mdb_dbi_open(txn, NULL, 0, &dbi);
     243          10 :         if (ret != 0) {
     244           0 :                 fprintf(stderr,
     245             :                         "Could not open database: (%d)  %s\n",
     246             :                         ret,
     247             :                         mdb_strerror(ret));
     248           0 :                 goto close_txn;
     249             :         }
     250             : 
     251          10 :         ret = mdb_cursor_open(txn, dbi, &cursor);
     252          10 :         if (ret != 0) {
     253           0 :                 fprintf(stderr,
     254             :                         "Could not open cursor: (%d)  %s\n",
     255             :                         ret,
     256             :                         mdb_strerror(ret));
     257           0 :                 goto close_txn;
     258             :         }
     259             : 
     260          10 :         ret = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
     261          10 :         if (ret != 0 && ret != MDB_NOTFOUND) {
     262           0 :                 fprintf(stderr,
     263             :                         "Could not find first record: (%d)  %s\n",
     264             :                         ret,
     265             :                         mdb_strerror(ret));
     266           0 :                 goto close_cursor;
     267             :         }
     268       44730 :         while (ret != MDB_NOTFOUND) {
     269       44720 :                 struct TDB_DATA tkey = {
     270       44720 :                         .dptr = key.mv_data,
     271       44720 :                         .dsize = key.mv_size
     272             :                 };
     273       44720 :                 struct TDB_DATA tdata = {
     274       44720 :                         .dptr = data.mv_data,
     275       44720 :                         .dsize = data.mv_size
     276             :                 };
     277       44720 :                 traverse_fn(NULL, tkey, tdata, dn);
     278       44720 :                 ret = mdb_cursor_get(cursor, &key, &data, MDB_NEXT);
     279       44720 :                 if (ret != 0 && ret != MDB_NOTFOUND) {
     280           0 :                         fprintf(stderr,
     281             :                                 "Could not read next record: (%d)  %s\n",
     282             :                                 ret,
     283             :                                 mdb_strerror(ret));
     284           0 :                         goto close_cursor;
     285             :                 }
     286             :         }
     287           0 :         ret = 0;
     288             : 
     289          10 : close_cursor:
     290          10 :         mdb_cursor_close(cursor);
     291          10 : close_txn:
     292          10 :         mdb_txn_commit(txn);
     293          58 : close_env:
     294          58 :         mdb_env_close(env);
     295             : 
     296          58 :         if (ret != 0) {
     297          48 :                 return 1;
     298             :         }
     299           0 :         return 0;
     300             : 
     301             : }
     302             : #else
     303             : static int dump_lmdb(const char *fname, struct ldb_dn *dn, bool emergency)
     304             : {
     305             :         /* not built with lmdb support */
     306             :         return 1;
     307             : }
     308             : #endif /* #ifdef HAVE_LMDB */
     309             : 
     310           2 : static void usage( void)
     311             : {
     312           2 :         printf( "Usage: ldbdump [options] <filename>\n\n");
     313           2 :         printf( "   -h          this help message\n");
     314           2 :         printf( "   -d DN       dumps DN only\n");
     315           2 :         printf( "   -e          emergency dump, for corrupt databases\n");
     316           2 :         printf( "   -i          include index and @BASEINFO records in dump\n");
     317           2 :         printf( "   -c          validate contents of the records\n");
     318           2 : }
     319             : 
     320          60 :  int main(int argc, char *argv[])
     321             : {
     322          60 :         bool emergency = false;
     323          58 :         int c, rc;
     324          58 :         char *fname;
     325          60 :         struct ldb_dn *dn = NULL;
     326             : 
     327          60 :         ldb = ldb_init(NULL, NULL);
     328          60 :         if (ldb == NULL) {
     329           0 :                 fprintf(stderr, "ldb: ldb_init failed()");
     330           0 :                 exit(1);
     331             :         }
     332             : 
     333          60 :         rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_PRECONNECT);
     334          60 :         if (rc != LDB_SUCCESS) {
     335           0 :                 fprintf(stderr, "ldb: failed to run preconnect hooks (needed to get Samba LDIF handlers): %s\n", ldb_strerror(rc));
     336           0 :                 exit(1);
     337             :         }
     338             : 
     339          60 :         if (argc < 2) {
     340           0 :                 printf("Usage: ldbdump <fname>\n");
     341           0 :                 exit(1);
     342             :         }
     343             : 
     344         118 :         while ((c = getopt( argc, argv, "hd:eic")) != -1) {
     345          60 :                 switch (c) {
     346           1 :                 case 'h':
     347           1 :                         usage();
     348           1 :                         exit( 0);
     349           0 :                 case 'd':
     350           0 :                         dn = ldb_dn_new(ldb, ldb, optarg);
     351           0 :                         if (!dn) {
     352           0 :                                 fprintf(stderr, "ldb failed to parse %s as a DN\n", optarg);
     353           0 :                                 exit(1);
     354             :                         }
     355           0 :                         break;
     356           0 :                 case 'e':
     357           0 :                         emergency = true;
     358           0 :                         break;
     359          58 :                 case 'i':
     360          58 :                         show_index = true;
     361          58 :                         break;
     362           0 :                 case 'c':
     363           0 :                         validate_contents = true;
     364           0 :                         break;
     365           1 :                 default:
     366           1 :                         usage();
     367           1 :                         exit( 1);
     368             :                 }
     369             :         }
     370             : 
     371          58 :         fname = argv[optind];
     372             : 
     373          58 :         rc = dump_lmdb(fname, dn, emergency);
     374          58 :         if (rc != 0) {
     375          48 :                 rc = dump_tdb(fname, dn, emergency);
     376          48 :                 if (rc != 0) {
     377           0 :                         fprintf(stderr, "Failed to open %s\n", fname);
     378           0 :                         return 1;
     379             :                 }
     380             :         }
     381           0 :         return 0;
     382             : 
     383             : }

Generated by: LCOV version 1.14