LCOV - code coverage report
Current view: top level - lib/ldb/tools - ldbedit.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 13 166 7.8 %
Date: 2024-04-21 15:09:00 Functions: 2 8 25.0 %

          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: ldbedit
      28             :  *
      29             :  *  Description: utility for ldb database editing
      30             :  *
      31             :  *  Author: Andrew Tridgell
      32             :  */
      33             : 
      34             : #include "replace.h"
      35             : #include "system/filesys.h"
      36             : #include "system/time.h"
      37             : #include "system/filesys.h"
      38             : #include "ldb.h"
      39             : #include "tools/cmdline.h"
      40             : #include "tools/ldbutil.h"
      41             : 
      42             : static struct ldb_cmdline *options;
      43             : 
      44             : /*
      45             :   debug routine
      46             : */
      47           0 : static void ldif_write_msg(struct ldb_context *ldb,
      48             :                            FILE *f,
      49             :                            enum ldb_changetype changetype,
      50             :                            struct ldb_message *msg)
      51             : {
      52             :         struct ldb_ldif ldif;
      53           0 :         ldif.changetype = changetype;
      54           0 :         ldif.msg = msg;
      55           0 :         ldb_ldif_write_file(ldb, f, &ldif);
      56           0 : }
      57             : 
      58             : /*
      59             :   modify a database record so msg1 becomes msg2
      60             :   returns the number of modified elements
      61             : */
      62           0 : static int modify_record(struct ldb_context *ldb,
      63             :                          struct ldb_message *msg1,
      64             :                          struct ldb_message *msg2,
      65             :                          struct ldb_control **req_ctrls)
      66             : {
      67             :         int ret;
      68             :         struct ldb_message *mod;
      69             : 
      70           0 :         if (ldb_msg_difference(ldb, ldb, msg1, msg2, &mod) != LDB_SUCCESS) {
      71           0 :                 fprintf(stderr, "Failed to calculate message differences\n");
      72           0 :                 return -1;
      73             :         }
      74             : 
      75           0 :         ret = mod->num_elements;
      76           0 :         if (ret == 0) {
      77           0 :                 goto done;
      78             :         }
      79             : 
      80           0 :         if (options->verbose > 0) {
      81           0 :                 ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod);
      82             :         }
      83             : 
      84           0 :         if (ldb_modify_ctrl(ldb, mod, req_ctrls) != LDB_SUCCESS) {
      85           0 :                 fprintf(stderr, "failed to modify %s - %s\n",
      86             :                         ldb_dn_get_linearized(msg1->dn), ldb_errstring(ldb));
      87           0 :                 ret = -1;
      88           0 :                 goto done;
      89             :         }
      90             : 
      91           0 : done:
      92           0 :         talloc_free(mod);
      93           0 :         return ret;
      94             : }
      95             : 
      96             : /*
      97             :   find dn in msgs[]
      98             : */
      99           0 : static struct ldb_message *msg_find(struct ldb_context *ldb,
     100             :                                     struct ldb_message **msgs,
     101             :                                     unsigned int count,
     102             :                                     struct ldb_dn *dn)
     103             : {
     104             :         unsigned int i;
     105           0 :         for (i=0;i<count;i++) {
     106           0 :                 if (ldb_dn_compare(dn, msgs[i]->dn) == 0) {
     107           0 :                         return msgs[i];
     108             :                 }
     109             :         }
     110           0 :         return NULL;
     111             : }
     112             : 
     113             : /*
     114             :   merge the changes in msgs2 into the messages from msgs1
     115             : */
     116           0 : static int merge_edits(struct ldb_context *ldb,
     117             :                        struct ldb_message **msgs1, unsigned int count1,
     118             :                        struct ldb_message **msgs2, unsigned int count2)
     119             : {
     120             :         unsigned int i;
     121             :         struct ldb_message *msg;
     122             :         int ret;
     123           0 :         unsigned int adds=0, modifies=0, deletes=0;
     124           0 :         struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
     125           0 :         if (options->controls != NULL && req_ctrls == NULL) {
     126           0 :                 fprintf(stderr, "parsing controls failed: %s\n", ldb_errstring(ldb));
     127           0 :                 return -1;
     128             :         }
     129             : 
     130           0 :         if (ldb_transaction_start(ldb) != LDB_SUCCESS) {
     131           0 :                 fprintf(stderr, "Failed to start transaction: %s\n", ldb_errstring(ldb));
     132           0 :                 return -1;
     133             :         }
     134             : 
     135             :         /* do the adds and modifies */
     136           0 :         for (i=0;i<count2;i++) {
     137           0 :                 msg = msg_find(ldb, msgs1, count1, msgs2[i]->dn);
     138           0 :                 if (!msg) {
     139           0 :                         if (options->verbose > 0) {
     140           0 :                                 ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_ADD, msgs2[i]);
     141             :                         }
     142           0 :                         if (ldb_add_ctrl(ldb, msgs2[i], req_ctrls) != LDB_SUCCESS) {
     143           0 :                                 fprintf(stderr, "failed to add %s - %s\n",
     144           0 :                                         ldb_dn_get_linearized(msgs2[i]->dn),
     145             :                                         ldb_errstring(ldb));
     146           0 :                                 ldb_transaction_cancel(ldb);
     147           0 :                                 return -1;
     148             :                         }
     149           0 :                         adds++;
     150             :                 } else {
     151           0 :                         ret = modify_record(ldb, msg, msgs2[i], req_ctrls);
     152           0 :                         if (ret != -1) {
     153           0 :                                 modifies += (unsigned int) ret;
     154             :                         } else {
     155           0 :                                 ldb_transaction_cancel(ldb);
     156           0 :                                 return -1;
     157             :                         }
     158             :                 }
     159             :         }
     160             : 
     161             :         /* do the deletes */
     162           0 :         for (i=0;i<count1;i++) {
     163           0 :                 msg = msg_find(ldb, msgs2, count2, msgs1[i]->dn);
     164           0 :                 if (!msg) {
     165           0 :                         if (options->verbose > 0) {
     166           0 :                                 ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_DELETE, msgs1[i]);
     167             :                         }
     168           0 :                         if (ldb_delete_ctrl(ldb, msgs1[i]->dn, req_ctrls) != LDB_SUCCESS) {
     169           0 :                                 fprintf(stderr, "failed to delete %s - %s\n",
     170           0 :                                         ldb_dn_get_linearized(msgs1[i]->dn),
     171             :                                         ldb_errstring(ldb));
     172           0 :                                 ldb_transaction_cancel(ldb);
     173           0 :                                 return -1;
     174             :                         }
     175           0 :                         deletes++;
     176             :                 }
     177             :         }
     178             : 
     179           0 :         if (ldb_transaction_commit(ldb) != LDB_SUCCESS) {
     180           0 :                 fprintf(stderr, "Failed to commit transaction: %s\n", ldb_errstring(ldb));
     181           0 :                 return -1;
     182             :         }
     183             : 
     184           0 :         printf("# %u adds  %u modifies  %u deletes\n", adds, modifies, deletes);
     185             : 
     186           0 :         return 0;
     187             : }
     188             : 
     189             : /*
     190             :   save a set of messages as ldif to a file
     191             : */
     192           0 : static int save_ldif(struct ldb_context *ldb,
     193             :                      FILE *f, struct ldb_message **msgs, unsigned int count)
     194             : {
     195             :         unsigned int i;
     196             : 
     197           0 :         fprintf(f, "# editing %u records\n", count);
     198             : 
     199           0 :         for (i=0;i<count;i++) {
     200             :                 struct ldb_ldif ldif;
     201           0 :                 fprintf(f, "# record %u\n", i+1);
     202             : 
     203           0 :                 ldif.changetype = LDB_CHANGETYPE_NONE;
     204           0 :                 ldif.msg = msgs[i];
     205             : 
     206           0 :                 ldb_ldif_write_file(ldb, f, &ldif);
     207             :         }
     208             : 
     209           0 :         return 0;
     210             : }
     211             : 
     212             : 
     213             : /*
     214             :   edit the ldb search results in msgs using the user selected editor
     215             : */
     216           0 : static int do_edit(struct ldb_context *ldb, struct ldb_message **msgs1,
     217             :                    unsigned int count1, const char *editor)
     218             : {
     219             :         int fd, ret;
     220             :         FILE *f;
     221           0 :         char file_template[] = "/tmp/ldbedit.XXXXXX";
     222             :         char *cmd;
     223             :         struct ldb_ldif *ldif;
     224           0 :         struct ldb_message **msgs2 = NULL;
     225           0 :         unsigned int count2 = 0;
     226             : 
     227             :         /* write out the original set of messages to a temporary
     228             :            file */
     229           0 :         fd = mkstemp(file_template);
     230             : 
     231           0 :         if (fd == -1) {
     232           0 :                 perror(file_template);
     233           0 :                 return -1;
     234             :         }
     235             : 
     236           0 :         f = fdopen(fd, "r+");
     237             : 
     238           0 :         if (!f) {
     239           0 :                 perror("fopen");
     240           0 :                 close(fd);
     241           0 :                 unlink(file_template);
     242           0 :                 return -1;
     243             :         }
     244             : 
     245           0 :         if (save_ldif(ldb, f, msgs1, count1) != 0) {
     246           0 :                 return -1;
     247             :         }
     248             : 
     249           0 :         fclose(f);
     250             : 
     251           0 :         cmd = talloc_asprintf(ldb, "%s %s", editor, file_template);
     252             : 
     253           0 :         if (!cmd) {
     254           0 :                 unlink(file_template);
     255           0 :                 fprintf(stderr, "out of memory\n");
     256           0 :                 return -1;
     257             :         }
     258             : 
     259             :         /* run the editor */
     260           0 :         ret = system(cmd);
     261           0 :         talloc_free(cmd);
     262             : 
     263           0 :         if (ret != 0) {
     264           0 :                 unlink(file_template);
     265           0 :                 fprintf(stderr, "edit with %s failed\n", editor);
     266           0 :                 return -1;
     267             :         }
     268             : 
     269             :         /* read the resulting ldif into msgs2 */
     270           0 :         f = fopen(file_template, "r");
     271           0 :         if (!f) {
     272           0 :                 perror(file_template);
     273           0 :                 return -1;
     274             :         }
     275             : 
     276           0 :         while ((ldif = ldb_ldif_read_file(ldb, f))) {
     277           0 :                 msgs2 = talloc_realloc(ldb, msgs2, struct ldb_message *, count2+1);
     278           0 :                 if (!msgs2) {
     279           0 :                         fprintf(stderr, "out of memory");
     280           0 :                         return -1;
     281             :                 }
     282           0 :                 msgs2[count2++] = ldif->msg;
     283             :         }
     284             : 
     285             :         /* the feof() test works here, even for the last line of the
     286             :          * file, as we parse ldif files character by character, and
     287             :          * feof() is only true if we have failed to read a character
     288             :          * from the file. So if the last line is bad, we don't get
     289             :          * feof() set, so we know the record was bad. Only if we
     290             :          * attempt to go to the next record will we get feof() and
     291             :          * thus consider that the ldif has ended without errors
     292             :          */
     293           0 :         if (!feof(f)) {
     294           0 :                 fprintf(stderr, "Error parsing ldif - aborting\n");
     295           0 :                 fclose(f);
     296           0 :                 unlink(file_template);
     297           0 :                 return -1;
     298             :         }
     299             : 
     300           0 :         fclose(f);
     301           0 :         unlink(file_template);
     302             : 
     303           0 :         return merge_edits(ldb, msgs1, count1, msgs2, count2);
     304             : }
     305             : 
     306           1 : static void usage(struct ldb_context *ldb)
     307             : {
     308           1 :         printf("Usage: ldbedit <options> <expression> <attributes ...>\n");
     309           1 :         ldb_cmdline_help(ldb, "ldbedit", stdout);
     310           1 :         exit(LDB_ERR_OPERATIONS_ERROR);
     311             : }
     312             : 
     313           2 : int main(int argc, const char **argv)
     314             : {
     315             :         struct ldb_context *ldb;
     316           2 :         struct ldb_result *result = NULL;
     317           2 :         struct ldb_dn *basedn = NULL;
     318             :         int ret;
     319           2 :         const char *expression = "(|(objectClass=*)(distinguishedName=*))";
     320           2 :         const char * const * attrs = NULL;
     321           2 :         TALLOC_CTX *mem_ctx = talloc_new(NULL);
     322             :         struct ldb_control **req_ctrls;
     323             :         unsigned int i;
     324             : 
     325           2 :         ldb = ldb_init(mem_ctx, NULL);
     326           2 :         if (ldb == NULL) {
     327           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     328             :         }
     329             : 
     330           2 :         options = ldb_cmdline_process_edit(ldb, argc, argv, usage);
     331             : 
     332             :         /* the check for '=' is for compatibility with ldapsearch */
     333           0 :         if (options->argc > 0 &&
     334           0 :             strchr(options->argv[0], '=')) {
     335           0 :                 expression = options->argv[0];
     336           0 :                 options->argv++;
     337           0 :                 options->argc--;
     338             :         }
     339             : 
     340           0 :         if (options->argc > 0) {
     341           0 :                 attrs = (const char * const *)(options->argv);
     342             :         }
     343             : 
     344           0 :         if (options->basedn != NULL) {
     345           0 :                 basedn = ldb_dn_new(ldb, ldb, options->basedn);
     346           0 :                 if (basedn == NULL) {
     347           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     348             :                 }
     349             :         }
     350             : 
     351           0 :         for (i = 0; options->controls != NULL && options->controls[i] != NULL; i++) {
     352           0 :                 if (strncmp(options->controls[i], "reveal_internals:", 17) == 0) {
     353           0 :                         printf("Using reveal internals has unintended consequences.\n");
     354           0 :                         printf("If this is your intent, manually perform the search,"
     355             :                                " and use ldbmodify directly.\n");
     356           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     357             :                 }
     358             :         }
     359             : 
     360           0 :         req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
     361           0 :         if (options->controls != NULL &&  req_ctrls== NULL) {
     362           0 :                 printf("parsing controls failed: %s\n", ldb_errstring(ldb));
     363           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     364             :         }
     365             : 
     366           0 :         ret = ldb_search_ctrl(ldb, ldb, &result, basedn, options->scope, attrs, req_ctrls, "%s", expression);
     367           0 :         if (ret != LDB_SUCCESS) {
     368           0 :                 printf("search failed - %s\n", ldb_errstring(ldb));
     369           0 :                 return ret;
     370             :         }
     371             : 
     372           0 :         if (result->count == 0) {
     373           0 :                 printf("no matching records - cannot edit\n");
     374           0 :                 talloc_free(mem_ctx);
     375           0 :                 return LDB_SUCCESS;
     376             :         }
     377             : 
     378           0 :         ret = do_edit(ldb, result->msgs, result->count, options->editor);
     379             : 
     380           0 :         talloc_free(mem_ctx);
     381             : 
     382           0 :         return ret == 0 ? LDB_SUCCESS : LDB_ERR_OPERATIONS_ERROR;
     383             : }

Generated by: LCOV version 1.14