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
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
version 2 of the License , or ( at your option ) any later version .
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
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/*
* 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
*/
# include "includes.h"
2006-01-10 19:48:32 +03:00
# include "ldb/include/includes.h"
2005-06-18 11:42:21 +04:00
# include "ldb/tools/cmdline.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
/*
debug routine
*/
static void ldif_write_msg ( struct ldb_context * ldb ,
FILE * f ,
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
*/
static int modify_record ( struct ldb_context * ldb ,
struct ldb_message * msg1 ,
struct ldb_message * msg2 )
{
2005-01-02 10:49:29 +03:00
struct ldb_message * mod ;
2004-04-11 00:18:22 +04:00
2005-05-17 02:31:45 +04:00
mod = ldb_msg_diff ( ldb , msg1 , msg2 ) ;
if ( mod = = NULL ) {
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
2005-01-02 10:49:29 +03:00
if ( mod - > num_elements = = 0 ) {
2004-04-11 00:18:22 +04:00
return 0 ;
}
2005-06-19 05:32:47 +04:00
if ( options - > verbose > 0 ) {
ldif_write_msg ( ldb , stdout , LDB_CHANGETYPE_MODIFY , mod ) ;
}
2005-01-02 10:49:29 +03:00
if ( ldb_modify ( ldb , mod ) ! = 0 ) {
2004-04-11 19:03:31 +04:00
fprintf ( stderr , " failed to modify %s - %s \n " ,
2005-08-18 19:02:01 +04:00
ldb_dn_linearize ( ldb , msg1 - > dn ) , ldb_errstring ( ldb ) ) ;
2004-04-11 00:18:22 +04:00
return - 1 ;
}
2005-05-17 02:31:45 +04:00
return mod - > num_elements ;
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 ,
int count ,
2006-11-22 03:59:34 +03:00
struct ldb_dn * dn )
2004-04-11 00:18:22 +04:00
{
int i ;
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 ,
struct ldb_message * * msgs1 , int count1 ,
struct ldb_message * * msgs2 , int count2 )
{
int i ;
struct ldb_message * msg ;
int ret = 0 ;
2004-04-11 19:03:31 +04:00
int adds = 0 , modifies = 0 , deletes = 0 ;
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 ] ) ;
}
2004-04-11 00:18:22 +04:00
if ( ldb_add ( ldb , msgs2 [ i ] ) ! = 0 ) {
2004-04-11 19:03:31 +04:00
fprintf ( stderr , " failed to add %s - %s \n " ,
2005-08-18 19:02:01 +04:00
ldb_dn_linearize ( ldb , msgs2 [ i ] - > dn ) ,
ldb_errstring ( 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 {
2004-04-11 19:03:31 +04:00
if ( modify_record ( ldb , msg , msgs2 [ i ] ) > 0 ) {
modifies + + ;
}
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 ] ) ;
}
2004-04-11 00:18:22 +04:00
if ( ldb_delete ( ldb , msgs1 [ i ] - > dn ) ! = 0 ) {
2004-04-11 19:03:31 +04:00
fprintf ( stderr , " failed to delete %s - %s \n " ,
2005-08-18 19:02:01 +04:00
ldb_dn_linearize ( ldb , msgs1 [ i ] - > dn ) ,
ldb_errstring ( 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
}
}
2004-04-11 19:03:31 +04:00
printf ( " # %d adds %d modifies %d deletes \n " , adds , modifies , deletes ) ;
2004-04-11 00:18:22 +04:00
return ret ;
}
/*
save a set of messages as ldif to a file
*/
2004-05-06 08:40:15 +04:00
static int save_ldif ( struct ldb_context * ldb ,
FILE * f , struct ldb_message * * msgs , int count )
2004-04-11 00:18:22 +04:00
{
int i ;
2004-04-11 19:03:31 +04:00
fprintf ( f , " # editing %d records \n " , count ) ;
2004-04-11 00:18:22 +04:00
for ( i = 0 ; i < count ; i + + ) {
struct ldb_ldif ldif ;
fprintf ( f , " # record %d \n " , i + 1 ) ;
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
*/
static int do_edit ( struct ldb_context * ldb , struct ldb_message * * msgs1 , int count1 ,
const char * editor )
{
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 ;
int count2 = 0 ;
/* 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
}
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 ) ;
}
static void usage ( void )
{
2004-05-09 16:37:35 +04:00
printf ( " Usage: ldbedit <options> <expression> <attributes ...> \n " ) ;
2004-04-11 00:18:22 +04:00
printf ( " Options: \n " ) ;
printf ( " -H ldb_url choose the database (or $LDB_URL) \n " ) ;
printf ( " -s base|sub|one choose search scope \n " ) ;
printf ( " -b basedn choose baseDN \n " ) ;
2004-04-11 19:03:31 +04:00
printf ( " -a edit all records (expression 'objectclass=*') \n " ) ;
2004-04-11 00:18:22 +04:00
printf ( " -e editor choose editor (or $VISUAL or $EDITOR) \n " ) ;
2005-12-30 14:56:52 +03:00
printf ( " -v verbose mode \n " ) ;
2004-04-11 00:18:22 +04:00
exit ( 1 ) ;
}
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 ;
2004-04-11 00:18:22 +04:00
2006-03-02 19:32:53 +03:00
ldb_global_init ( ) ;
2005-06-18 11:42:21 +04:00
ldb = ldb_init ( NULL ) ;
2004-04-11 00:18:22 +04:00
2005-06-18 11:42:21 +04:00
options = ldb_cmdline_process ( 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 */
if ( options - > argc > 0 & &
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 ) ;
if ( ! ldb_dn_validate ( basedn ) ) {
2005-08-18 19:02:01 +04:00
printf ( " Invalid Base DN format \n " ) ;
exit ( 1 ) ;
}
}
2005-11-08 03:11:45 +03:00
ret = ldb_search ( ldb , basedn , options - > scope , expression , attrs , & result ) ;
if ( ret ! = LDB_SUCCESS ) {
2004-04-11 00:18:22 +04:00
printf ( " search failed - %s \n " , ldb_errstring ( ldb ) ) ;
exit ( 1 ) ;
}
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 " ) ;
return 0 ;
}
2005-11-08 03:11:45 +03:00
do_edit ( ldb , result - > msgs , result - > count , options - > editor ) ;
2004-04-11 00:18:22 +04:00
2005-11-08 03:11:45 +03:00
if ( result ) {
ret = talloc_free ( result ) ;
2004-04-11 00:18:22 +04:00
if ( ret = = - 1 ) {
2005-04-25 16:46:18 +04:00
fprintf ( stderr , " talloc_free failed \n " ) ;
2004-04-11 00:18:22 +04:00
exit ( 1 ) ;
}
}
2005-02-27 14:35:47 +03:00
talloc_free ( ldb ) ;
2004-04-11 00:18:22 +04:00
return 0 ;
}