2010-07-16 15:19:07 +04:00
/*
2004-04-11 00:18:22 +04:00
ldb database library
Copyright ( C ) Andrew Tridgell 2004
* * NOTE ! The following LGPL license applies to the ldb
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
2010-07-16 15:19:07 +04:00
2004-04-11 00:18:22 +04:00
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
2007-07-10 06:46:15 +04:00
version 3 of the License , or ( at your option ) any later version .
2004-04-11 00:18:22 +04:00
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
2007-07-10 07:42:26 +04:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2004-04-11 00:18:22 +04:00
*/
/*
* Name : ldb
*
* Component : ldbedit
*
2004-04-11 19:03:31 +04:00
* Description : utility for ldb database editing
2004-04-11 00:18:22 +04:00
*
* Author : Andrew Tridgell
*/
2010-05-31 18:05:41 +04:00
2010-11-01 15:36:42 +03:00
# include "replace.h"
# include "system/filesys.h"
# include "system/time.h"
2010-11-01 10:45:25 +03:00
# include "system/filesys.h"
2009-01-30 02:39:30 +03:00
# include "ldb.h"
2007-05-05 22:50:56 +04:00
# include "tools/cmdline.h"
2010-05-21 13:30:20 +04:00
# include "tools/ldbutil.h"
2004-04-11 00:18:22 +04:00
2005-06-19 05:32:47 +04:00
static struct ldb_cmdline * options ;
2004-09-17 14:42:33 +04:00
/*
2010-07-16 15:19:07 +04:00
debug routine
2004-09-17 14:42:33 +04:00
*/
2010-07-16 15:19:07 +04:00
static void ldif_write_msg ( struct ldb_context * ldb ,
FILE * f ,
2004-09-17 14:42:33 +04:00
enum ldb_changetype changetype ,
struct ldb_message * msg )
{
struct ldb_ldif ldif ;
ldif . changetype = changetype ;
2005-01-02 10:49:29 +03:00
ldif . msg = msg ;
2004-09-17 14:42:33 +04:00
ldb_ldif_write_file ( ldb , f , & ldif ) ;
}
2004-04-11 00:18:22 +04:00
/*
modify a database record so msg1 becomes msg2
2004-04-11 19:03:31 +04:00
returns the number of modified elements
2004-04-11 00:18:22 +04:00
*/
2010-07-16 15:19:07 +04:00
static int modify_record ( struct ldb_context * ldb ,
2004-04-11 00:18:22 +04:00
struct ldb_message * msg1 ,
2010-05-21 13:30:20 +04:00
struct ldb_message * msg2 ,
struct ldb_control * * req_ctrls )
2004-04-11 00:18:22 +04:00
{
2010-07-16 14:35:07 +04:00
int ret ;
2005-01-02 10:49:29 +03:00
struct ldb_message * mod ;
2004-04-11 00:18:22 +04:00
2010-07-16 14:35:07 +04:00
if ( ldb_msg_difference ( ldb , ldb , msg1 , msg2 , & mod ) ! = LDB_SUCCESS ) {
2005-05-17 02:31:45 +04:00
fprintf ( stderr , " Failed to calculate message differences \n " ) ;
2004-12-31 06:51:42 +03:00
return - 1 ;
}
2004-04-11 00:18:22 +04:00
2010-07-16 14:35:07 +04:00
ret = mod - > num_elements ;
if ( ret = = 0 ) {
goto done ;
2004-04-11 00:18:22 +04:00
}
2005-06-19 05:32:47 +04:00
if ( options - > verbose > 0 ) {
ldif_write_msg ( ldb , stdout , LDB_CHANGETYPE_MODIFY , mod ) ;
}
2012-04-04 06:51:00 +04:00
if ( ldb_modify_ctrl ( ldb , mod , req_ctrls ) ! = LDB_SUCCESS ) {
2010-07-16 15:19:07 +04:00
fprintf ( stderr , " failed to modify %s - %s \n " ,
2006-11-22 05:05:19 +03:00
ldb_dn_get_linearized ( msg1 - > dn ) , ldb_errstring ( ldb ) ) ;
2010-07-16 14:35:07 +04:00
ret = - 1 ;
goto done ;
2004-04-11 00:18:22 +04:00
}
2010-07-16 14:35:07 +04:00
done :
talloc_free ( mod ) ;
return ret ;
2004-04-11 00:18:22 +04:00
}
/*
find dn in msgs [ ]
*/
2005-07-16 22:16:32 +04:00
static struct ldb_message * msg_find ( struct ldb_context * ldb ,
struct ldb_message * * msgs ,
2009-11-06 20:35:17 +03:00
unsigned int count ,
2006-11-22 03:59:34 +03:00
struct ldb_dn * dn )
2004-04-11 00:18:22 +04:00
{
2009-11-06 20:35:17 +03:00
unsigned int i ;
2004-04-11 00:18:22 +04:00
for ( i = 0 ; i < count ; i + + ) {
2006-11-22 03:59:34 +03:00
if ( ldb_dn_compare ( dn , msgs [ i ] - > dn ) = = 0 ) {
2004-04-11 00:18:22 +04:00
return msgs [ i ] ;
}
}
return NULL ;
}
/*
merge the changes in msgs2 into the messages from msgs1
*/
static int merge_edits ( struct ldb_context * ldb ,
2009-11-06 20:35:17 +03:00
struct ldb_message * * msgs1 , unsigned int count1 ,
struct ldb_message * * msgs2 , unsigned int count2 )
2004-04-11 00:18:22 +04:00
{
2009-11-06 20:35:17 +03:00
unsigned int i ;
2004-04-11 00:18:22 +04:00
struct ldb_message * msg ;
2011-01-14 14:48:54 +03:00
int ret ;
2011-01-14 14:39:42 +03:00
unsigned int adds = 0 , modifies = 0 , deletes = 0 ;
2010-05-21 13:30:20 +04:00
struct ldb_control * * req_ctrls = ldb_parse_control_strings ( ldb , ldb , ( const char * * ) options - > controls ) ;
if ( options - > controls ! = NULL & & req_ctrls = = NULL ) {
fprintf ( stderr , " parsing controls failed: %s \n " , ldb_errstring ( ldb ) ) ;
return - 1 ;
}
2004-04-11 00:18:22 +04:00
2011-01-14 14:39:04 +03:00
if ( ldb_transaction_start ( ldb ) ! = LDB_SUCCESS ) {
2008-12-18 06:30:11 +03:00
fprintf ( stderr , " Failed to start transaction: %s \n " , ldb_errstring ( ldb ) ) ;
2008-12-16 06:39:42 +03:00
return - 1 ;
}
2004-04-11 00:18:22 +04:00
/* do the adds and modifies */
for ( i = 0 ; i < count2 ; i + + ) {
2005-07-16 22:16:32 +04:00
msg = msg_find ( ldb , msgs1 , count1 , msgs2 [ i ] - > dn ) ;
2004-04-11 00:18:22 +04:00
if ( ! msg ) {
2005-06-19 05:32:47 +04:00
if ( options - > verbose > 0 ) {
ldif_write_msg ( ldb , stdout , LDB_CHANGETYPE_ADD , msgs2 [ i ] ) ;
}
2012-04-04 06:51:00 +04:00
if ( ldb_add_ctrl ( ldb , msgs2 [ i ] , req_ctrls ) ! = LDB_SUCCESS ) {
2004-04-11 19:03:31 +04:00
fprintf ( stderr , " failed to add %s - %s \n " ,
2006-11-22 05:05:19 +03:00
ldb_dn_get_linearized ( msgs2 [ i ] - > dn ) ,
2005-08-18 19:02:01 +04:00
ldb_errstring ( ldb ) ) ;
2009-09-04 07:59:44 +04:00
ldb_transaction_cancel ( ldb ) ;
2004-04-11 00:18:22 +04:00
return - 1 ;
}
2004-04-11 19:03:31 +04:00
adds + + ;
2004-04-11 00:18:22 +04:00
} else {
2011-01-14 14:48:54 +03:00
ret = modify_record ( ldb , msg , msgs2 [ i ] , req_ctrls ) ;
if ( ret ! = - 1 ) {
modifies + = ( unsigned int ) ret ;
} else {
2012-01-25 07:58:44 +04:00
ldb_transaction_cancel ( ldb ) ;
2011-01-14 14:48:54 +03:00
return - 1 ;
2004-04-11 19:03:31 +04:00
}
2004-04-11 00:18:22 +04:00
}
}
/* do the deletes */
for ( i = 0 ; i < count1 ; i + + ) {
2005-07-16 22:16:32 +04:00
msg = msg_find ( ldb , msgs2 , count2 , msgs1 [ i ] - > dn ) ;
2004-04-11 00:18:22 +04:00
if ( ! msg ) {
2005-06-19 05:32:47 +04:00
if ( options - > verbose > 0 ) {
ldif_write_msg ( ldb , stdout , LDB_CHANGETYPE_DELETE , msgs1 [ i ] ) ;
}
2012-04-04 06:51:00 +04:00
if ( ldb_delete_ctrl ( ldb , msgs1 [ i ] - > dn , req_ctrls ) ! = LDB_SUCCESS ) {
2004-04-11 19:03:31 +04:00
fprintf ( stderr , " failed to delete %s - %s \n " ,
2006-11-22 05:05:19 +03:00
ldb_dn_get_linearized ( msgs1 [ i ] - > dn ) ,
2005-08-18 19:02:01 +04:00
ldb_errstring ( ldb ) ) ;
2009-09-04 07:59:44 +04:00
ldb_transaction_cancel ( ldb ) ;
2004-04-11 00:18:22 +04:00
return - 1 ;
}
2004-04-11 19:03:31 +04:00
deletes + + ;
2004-04-11 00:18:22 +04:00
}
}
2011-01-14 14:39:04 +03:00
if ( ldb_transaction_commit ( ldb ) ! = LDB_SUCCESS ) {
2008-12-18 06:30:11 +03:00
fprintf ( stderr , " Failed to commit transaction: %s \n " , ldb_errstring ( ldb ) ) ;
2008-12-16 06:39:42 +03:00
return - 1 ;
}
2011-01-14 14:39:42 +03:00
printf ( " # %u adds %u modifies %u deletes \n " , adds , modifies , deletes ) ;
2004-04-11 19:03:31 +04:00
2011-01-14 14:48:54 +03:00
return 0 ;
2004-04-11 00:18:22 +04:00
}
/*
save a set of messages as ldif to a file
*/
2010-07-16 15:19:07 +04:00
static int save_ldif ( struct ldb_context * ldb ,
2009-11-06 20:35:17 +03:00
FILE * f , struct ldb_message * * msgs , unsigned int count )
2004-04-11 00:18:22 +04:00
{
2009-11-06 20:35:17 +03:00
unsigned int i ;
2004-04-11 00:18:22 +04:00
2011-02-01 22:52:33 +03:00
fprintf ( f , " # editing %u records \n " , count ) ;
2004-04-11 00:18:22 +04:00
for ( i = 0 ; i < count ; i + + ) {
struct ldb_ldif ldif ;
2011-02-01 22:52:33 +03:00
fprintf ( f , " # record %u \n " , i + 1 ) ;
2004-04-11 00:18:22 +04:00
ldif . changetype = LDB_CHANGETYPE_NONE ;
2005-01-02 10:49:29 +03:00
ldif . msg = msgs [ i ] ;
2004-04-11 00:18:22 +04:00
2004-05-20 17:25:06 +04:00
ldb_ldif_write_file ( ldb , f , & ldif ) ;
2004-04-11 00:18:22 +04:00
}
return 0 ;
}
/*
edit the ldb search results in msgs using the user selected editor
*/
2009-11-06 20:35:17 +03:00
static int do_edit ( struct ldb_context * ldb , struct ldb_message * * msgs1 ,
unsigned int count1 , const char * editor )
2004-04-11 00:18:22 +04:00
{
int fd , ret ;
FILE * f ;
2006-09-23 08:36:30 +04:00
char file_template [ ] = " /tmp/ldbedit.XXXXXX " ;
2004-04-11 00:18:22 +04:00
char * cmd ;
struct ldb_ldif * ldif ;
struct ldb_message * * msgs2 = NULL ;
2009-11-06 20:35:17 +03:00
unsigned int count2 = 0 ;
2004-04-11 00:18:22 +04:00
/* write out the original set of messages to a temporary
file */
2006-09-23 08:36:30 +04:00
fd = mkstemp ( file_template ) ;
2004-04-11 00:18:22 +04:00
if ( fd = = - 1 ) {
2006-09-23 08:36:30 +04:00
perror ( file_template ) ;
2004-04-11 00:18:22 +04:00
return - 1 ;
}
f = fdopen ( fd , " r+ " ) ;
if ( ! f ) {
perror ( " fopen " ) ;
close ( fd ) ;
2006-09-23 08:36:30 +04:00
unlink ( file_template ) ;
2004-04-11 00:18:22 +04:00
return - 1 ;
}
2004-05-06 08:40:15 +04:00
if ( save_ldif ( ldb , f , msgs1 , count1 ) ! = 0 ) {
2004-04-11 00:18:22 +04:00
return - 1 ;
}
fclose ( f ) ;
2006-09-23 08:36:30 +04:00
cmd = talloc_asprintf ( ldb , " %s %s " , editor , file_template ) ;
2004-04-11 00:18:22 +04:00
if ( ! cmd ) {
2006-09-23 08:36:30 +04:00
unlink ( file_template ) ;
2004-04-11 00:18:22 +04:00
fprintf ( stderr , " out of memory \n " ) ;
return - 1 ;
}
/* run the editor */
ret = system ( cmd ) ;
2006-08-23 09:08:55 +04:00
talloc_free ( cmd ) ;
2004-04-11 00:18:22 +04:00
if ( ret ! = 0 ) {
2006-09-23 08:36:30 +04:00
unlink ( file_template ) ;
2004-04-11 00:18:22 +04:00
fprintf ( stderr , " edit with %s failed \n " , editor ) ;
return - 1 ;
}
/* read the resulting ldif into msgs2 */
2006-09-23 08:36:30 +04:00
f = fopen ( file_template , " r " ) ;
2004-04-11 00:18:22 +04:00
if ( ! f ) {
2006-09-23 08:36:30 +04:00
perror ( file_template ) ;
2004-04-11 00:18:22 +04:00
return - 1 ;
}
2004-05-20 17:25:06 +04:00
while ( ( ldif = ldb_ldif_read_file ( ldb , f ) ) ) {
2005-01-12 19:00:01 +03:00
msgs2 = talloc_realloc ( ldb , msgs2 , struct ldb_message * , count2 + 1 ) ;
2004-04-11 00:18:22 +04:00
if ( ! msgs2 ) {
fprintf ( stderr , " out of memory " ) ;
return - 1 ;
}
2005-01-02 10:49:29 +03:00
msgs2 [ count2 + + ] = ldif - > msg ;
2004-04-11 00:18:22 +04:00
}
2011-03-29 09:31:17 +04:00
/* the feof() test works here, even for the last line of the
* file , as we parse ldif files character by character , and
* feof ( ) is only true if we have failed to read a character
* from the file . So if the last line is bad , we don ' t get
* feof ( ) set , so we know the record was bad . Only if we
* attempt to go to the next record will we get feof ( ) and
* thus consider that the ldif has ended without errors
*/
if ( ! feof ( f ) ) {
fprintf ( stderr , " Error parsing ldif - aborting \n " ) ;
fclose ( f ) ;
unlink ( file_template ) ;
return - 1 ;
}
2004-04-11 00:18:22 +04:00
fclose ( f ) ;
2006-09-23 08:36:30 +04:00
unlink ( file_template ) ;
2004-04-11 00:18:22 +04:00
return merge_edits ( ldb , msgs1 , count1 , msgs2 , count2 ) ;
}
2010-11-01 10:45:25 +03:00
static void usage ( struct ldb_context * ldb )
2004-04-11 00:18:22 +04:00
{
2004-05-09 16:37:35 +04:00
printf ( " Usage: ldbedit <options> <expression> <attributes ...> \n " ) ;
2010-11-01 10:45:25 +03:00
ldb_cmdline_help ( ldb , " ldbedit " , stdout ) ;
2011-02-01 22:34:44 +03:00
exit ( LDB_ERR_OPERATIONS_ERROR ) ;
2004-04-11 00:18:22 +04:00
}
2006-05-01 05:34:04 +04:00
int main ( int argc , const char * * argv )
2004-04-11 00:18:22 +04:00
{
struct ldb_context * ldb ;
2005-11-08 03:11:45 +03:00
struct ldb_result * result = NULL ;
2005-08-18 19:02:01 +04:00
struct ldb_dn * basedn = NULL ;
2004-04-11 00:18:22 +04:00
int ret ;
2006-01-11 18:03:20 +03:00
const char * expression = " (|(objectClass=*)(distinguishedName=*)) " ;
2004-05-09 16:37:35 +04:00
const char * const * attrs = NULL ;
2010-05-02 17:53:14 +04:00
TALLOC_CTX * mem_ctx = talloc_new ( NULL ) ;
2010-11-04 12:05:59 +03:00
struct ldb_control * * req_ctrls ;
2017-01-30 01:08:07 +03:00
unsigned int i ;
2004-04-11 00:18:22 +04:00
2010-05-02 17:53:14 +04:00
ldb = ldb_init ( mem_ctx , NULL ) ;
2011-02-01 22:26:12 +03:00
if ( ldb = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2004-04-11 00:18:22 +04:00
2020-02-29 06:03:00 +03:00
options = ldb_cmdline_process_edit ( ldb , argc , argv , usage ) ;
2004-04-11 00:18:22 +04:00
2005-06-22 07:10:40 +04:00
/* the check for '=' is for compatibility with ldapsearch */
2010-07-16 15:19:07 +04:00
if ( options - > argc > 0 & &
2005-06-22 07:10:40 +04:00
strchr ( options - > argv [ 0 ] , ' = ' ) ) {
2005-06-18 11:42:21 +04:00
expression = options - > argv [ 0 ] ;
options - > argv + + ;
2005-06-22 07:10:40 +04:00
options - > argc - - ;
2004-05-09 16:37:35 +04:00
}
2005-06-18 11:42:21 +04:00
if ( options - > argc > 0 ) {
2005-06-22 07:10:40 +04:00
attrs = ( const char * const * ) ( options - > argv ) ;
2004-04-11 00:18:22 +04:00
}
2005-08-18 19:02:01 +04:00
if ( options - > basedn ! = NULL ) {
2006-11-22 03:59:34 +03:00
basedn = ldb_dn_new ( ldb , ldb , options - > basedn ) ;
2011-03-04 12:49:47 +03:00
if ( basedn = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
2005-08-18 19:02:01 +04:00
}
}
2017-01-30 01:08:07 +03:00
for ( i = 0 ; options - > controls ! = NULL & & options - > controls [ i ] ! = NULL ; i + + ) {
if ( strncmp ( options - > controls [ i ] , " reveal_internals: " , 17 ) = = 0 ) {
printf ( " Using reveal internals has unintended consequences. \n " ) ;
printf ( " If this is your intent, manually perform the search, "
" and use ldbmodify directly. \n " ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
}
2010-11-04 12:05:59 +03:00
req_ctrls = ldb_parse_control_strings ( ldb , ldb , ( const char * * ) options - > controls ) ;
if ( options - > controls ! = NULL & & req_ctrls = = NULL ) {
printf ( " parsing controls failed: %s \n " , ldb_errstring ( ldb ) ) ;
2011-02-01 22:34:44 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2010-11-04 12:05:59 +03:00
}
ret = ldb_search_ctrl ( ldb , ldb , & result , basedn , options - > scope , attrs , req_ctrls , " %s " , expression ) ;
2005-11-08 03:11:45 +03:00
if ( ret ! = LDB_SUCCESS ) {
2004-04-11 00:18:22 +04:00
printf ( " search failed - %s \n " , ldb_errstring ( ldb ) ) ;
2011-02-01 22:34:44 +03:00
return ret ;
2004-04-11 00:18:22 +04:00
}
2005-11-08 03:11:45 +03:00
if ( result - > count = = 0 ) {
2004-04-11 00:18:22 +04:00
printf ( " no matching records - cannot edit \n " ) ;
2011-02-05 15:19:56 +03:00
talloc_free ( mem_ctx ) ;
return LDB_SUCCESS ;
2004-04-11 00:18:22 +04:00
}
2011-02-05 15:19:56 +03:00
ret = do_edit ( ldb , result - > msgs , result - > count , options - > editor ) ;
2004-04-11 00:18:22 +04:00
2010-05-02 17:53:14 +04:00
talloc_free ( mem_ctx ) ;
2011-02-05 15:19:56 +03:00
return ret = = 0 ? LDB_SUCCESS : LDB_ERR_OPERATIONS_ERROR ;
2004-04-11 00:18:22 +04:00
}