2005-06-18 07:43:52 +00:00
/*
ldb database library - command line handling for ldb tools
Copyright ( C ) Andrew Tridgell 2005
* * 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
2007-07-10 02:46:15 +00:00
version 3 of the License , or ( at your option ) any later version .
2005-06-18 07:43:52 +00: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 03:42:26 +00:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2005-06-18 07:43:52 +00:00
*/
2010-11-01 23:36:42 +11:00
# include "replace.h"
# include "system/filesys.h"
# include "system/time.h"
2010-05-31 16:05:41 +02:00
# include "ldb.h"
2010-11-01 15:41:07 +11:00
# include "ldb_module.h"
2010-05-31 16:05:41 +02:00
# include "tools/cmdline.h"
2009-09-02 16:56:20 +10:00
static struct ldb_cmdline options ; /* needs to be static for older compilers */
2010-10-19 11:19:20 +11:00
enum ldb_cmdline_options { CMDLINE_RELAX = 1 } ;
2010-11-01 15:41:07 +11:00
static struct poptOption builtin_popt_options [ ] = {
2009-09-02 16:56:20 +10:00
POPT_AUTOHELP
{ " url " , ' H ' , POPT_ARG_STRING , & options . url , 0 , " database URL " , " URL " } ,
{ " basedn " , ' b ' , POPT_ARG_STRING , & options . basedn , 0 , " base DN " , " DN " } ,
{ " editor " , ' e ' , POPT_ARG_STRING , & options . editor , 0 , " external editor " , " PROGRAM " } ,
{ " scope " , ' s ' , POPT_ARG_STRING , NULL , ' s ' , " search scope " , " SCOPE " } ,
{ " verbose " , ' v ' , POPT_ARG_NONE , NULL , ' v ' , " increase verbosity " , NULL } ,
2009-09-21 15:24:39 -07:00
{ " trace " , 0 , POPT_ARG_NONE , & options . tracing , 0 , " enable tracing " , NULL } ,
2009-09-02 16:56:20 +10:00
{ " interactive " , ' i ' , POPT_ARG_NONE , & options . interactive , 0 , " input from stdin " , NULL } ,
{ " recursive " , ' r ' , POPT_ARG_NONE , & options . recursive , 0 , " recursive delete " , NULL } ,
{ " modules-path " , 0 , POPT_ARG_STRING , & options . modules_path , 0 , " modules path " , " PATH " } ,
{ " num-searches " , 0 , POPT_ARG_INT , & options . num_searches , 0 , " number of test searches " , NULL } ,
{ " num-records " , 0 , POPT_ARG_INT , & options . num_records , 0 , " number of test records " , NULL } ,
{ " all " , ' a ' , POPT_ARG_NONE , & options . all_records , 0 , " (|(objectClass=*)(distinguishedName=*)) " , NULL } ,
{ " nosync " , 0 , POPT_ARG_NONE , & options . nosync , 0 , " non-synchronous transactions " , NULL } ,
{ " sorted " , ' S ' , POPT_ARG_NONE , & options . sorted , 0 , " sort attributes " , NULL } ,
{ NULL , ' o ' , POPT_ARG_STRING , NULL , ' o ' , " ldb_connect option " , " OPTION " } ,
{ " controls " , 0 , POPT_ARG_STRING , NULL , ' c ' , " controls " , NULL } ,
2009-09-08 20:57:31 +10:00
{ " show-binary " , 0 , POPT_ARG_NONE , & options . show_binary , 0 , " display binary LDIF " , NULL } ,
2009-11-28 17:35:36 +11:00
{ " paged " , 0 , POPT_ARG_NONE , NULL , ' P ' , " use a paged search " , NULL } ,
{ " show-deleted " , 0 , POPT_ARG_NONE , NULL , ' D ' , " show deleted objects " , NULL } ,
{ " show-recycled " , 0 , POPT_ARG_NONE , NULL , ' R ' , " show recycled objects " , NULL } ,
2009-12-16 14:58:35 +11:00
{ " show-deactivated-link " , 0 , POPT_ARG_NONE , NULL , ' d ' , " show deactivated links " , NULL } ,
2009-12-10 23:44:05 +11:00
{ " reveal " , 0 , POPT_ARG_NONE , NULL , ' r ' , " reveal ldb internals " , NULL } ,
2010-10-19 11:19:20 +11:00
{ " relax " , 0 , POPT_ARG_NONE , NULL , CMDLINE_RELAX , " pass relax control " , NULL } ,
2009-11-28 17:35:36 +11:00
{ " cross-ncs " , 0 , POPT_ARG_NONE , NULL , ' N ' , " search across NC boundaries " , NULL } ,
{ " extended-dn " , 0 , POPT_ARG_NONE , NULL , ' E ' , " show extended DNs " , NULL } ,
2009-09-02 16:56:20 +10:00
{ NULL }
} ;
2006-08-25 06:38:29 +00:00
2010-11-01 15:41:07 +11:00
void ldb_cmdline_help ( struct ldb_context * ldb , const char * cmdname , FILE * f )
2009-09-02 16:56:20 +10:00
{
poptContext pc ;
2010-11-02 10:40:52 +11:00
struct poptOption * * popt_options = ldb_module_popt_options ( ldb ) ;
pc = poptGetContext ( cmdname , 0 , NULL , * popt_options ,
2009-09-02 16:56:20 +10:00
POPT_CONTEXT_KEEP_FIRST ) ;
poptPrintHelp ( pc , f , 0 ) ;
}
2006-08-25 06:38:29 +00:00
2009-11-28 17:35:36 +11:00
/*
add a control to the options structure
*/
static bool add_control ( TALLOC_CTX * mem_ctx , const char * control )
{
2010-09-11 17:43:44 +02:00
unsigned int i ;
2009-11-28 17:35:36 +11:00
/* count how many controls we already have */
for ( i = 0 ; options . controls & & options . controls [ i ] ; i + + ) ;
options . controls = talloc_realloc ( mem_ctx , options . controls , const char * , i + 2 ) ;
if ( options . controls = = NULL ) {
return false ;
}
options . controls [ i ] = control ;
options . controls [ i + 1 ] = NULL ;
return true ;
}
2007-12-02 17:09:43 +01:00
/**
2005-06-18 07:43:52 +00:00
process command line options
*/
2007-12-04 01:51:36 +01:00
struct ldb_cmdline * ldb_cmdline_process ( struct ldb_context * ldb ,
int argc , const char * * argv ,
2010-11-01 15:41:07 +11:00
void ( * usage ) ( struct ldb_context * ) )
2005-06-18 07:43:52 +00:00
{
2006-08-22 20:39:01 +00:00
struct ldb_cmdline * ret = NULL ;
2005-06-18 07:43:52 +00:00
poptContext pc ;
2006-05-30 17:02:21 +00:00
int num_options = 0 ;
2005-06-26 06:09:03 +00:00
int opt ;
2011-04-10 19:44:53 +02:00
unsigned int flags = 0 ;
2010-11-01 15:41:07 +11:00
int rc ;
2010-11-02 10:40:52 +11:00
struct poptOption * * popt_options ;
2005-06-18 09:01:09 +00:00
2009-11-20 11:33:43 +11:00
/* make the ldb utilities line buffered */
setlinebuf ( stdout ) ;
2005-06-18 07:43:52 +00:00
ret = talloc_zero ( ldb , struct ldb_cmdline ) ;
if ( ret = = NULL ) {
2009-01-29 18:39:30 -05:00
fprintf ( stderr , " Out of memory! \n " ) ;
2005-06-18 07:43:52 +00:00
goto failed ;
}
options = * ret ;
/* pull in URL */
options . url = getenv ( " LDB_URL " ) ;
/* and editor (used by ldbedit) */
options . editor = getenv ( " VISUAL " ) ;
if ( ! options . editor ) {
options . editor = getenv ( " EDITOR " ) ;
}
if ( ! options . editor ) {
options . editor = " vi " ;
}
2005-06-18 09:01:09 +00:00
options . scope = LDB_SCOPE_DEFAULT ;
2010-11-02 10:40:52 +11:00
popt_options = ldb_module_popt_options ( ldb ) ;
( * popt_options ) = builtin_popt_options ;
2010-11-01 15:41:07 +11:00
rc = ldb_modules_hook ( ldb , LDB_MODULE_HOOK_CMDLINE_OPTIONS ) ;
if ( rc ! = LDB_SUCCESS ) {
fprintf ( stderr , " ldb: failed to run command line hooks : %s \n " , ldb_strerror ( rc ) ) ;
goto failed ;
}
2010-11-02 10:40:52 +11:00
pc = poptGetContext ( argv [ 0 ] , argc , argv , * popt_options ,
2005-06-18 07:43:52 +00:00
POPT_CONTEXT_KEEP_FIRST ) ;
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
switch ( opt ) {
case ' s ' : {
const char * arg = poptGetOptArg ( pc ) ;
if ( strcmp ( arg , " base " ) = = 0 ) {
options . scope = LDB_SCOPE_BASE ;
} else if ( strcmp ( arg , " sub " ) = = 0 ) {
options . scope = LDB_SCOPE_SUBTREE ;
} else if ( strcmp ( arg , " one " ) = = 0 ) {
options . scope = LDB_SCOPE_ONELEVEL ;
} else {
fprintf ( stderr , " Invalid scope '%s' \n " , arg ) ;
goto failed ;
}
break ;
}
case ' v ' :
options . verbose + + ;
break ;
case ' o ' :
options . options = talloc_realloc ( ret , options . options ,
2005-08-27 15:13:15 +00:00
const char * , num_options + 3 ) ;
2005-06-18 07:43:52 +00:00
if ( options . options = = NULL ) {
2009-01-29 18:39:30 -05:00
fprintf ( stderr , " Out of memory! \n " ) ;
2005-06-18 07:43:52 +00:00
goto failed ;
}
2005-08-27 15:13:15 +00:00
options . options [ num_options ] = poptGetOptArg ( pc ) ;
2005-06-18 07:43:52 +00:00
options . options [ num_options + 1 ] = NULL ;
2005-08-27 15:13:15 +00:00
num_options + + ;
2005-06-18 07:43:52 +00:00
break ;
2006-01-06 19:42:08 +00:00
case ' c ' : {
const char * cs = poptGetOptArg ( pc ) ;
2009-11-28 17:35:36 +11:00
const char * p ;
2006-01-06 19:42:08 +00:00
2009-11-28 17:35:36 +11:00
for ( p = cs ; p ! = NULL ; ) {
const char * t , * c ;
2006-01-06 19:42:08 +00:00
t = strchr ( p , ' , ' ) ;
if ( t = = NULL ) {
2009-11-28 17:35:36 +11:00
c = talloc_strdup ( options . controls , p ) ;
2006-01-06 19:42:08 +00:00
p = NULL ;
} else {
2009-11-28 17:35:36 +11:00
c = talloc_strndup ( options . controls , p , t - p ) ;
2006-01-06 19:42:08 +00:00
p = t + 1 ;
}
2009-11-28 17:35:36 +11:00
if ( c = = NULL | | ! add_control ( ret , c ) ) {
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
2006-01-06 19:42:08 +00:00
}
break ;
}
2009-11-28 17:35:36 +11:00
case ' P ' :
if ( ! add_control ( ret , " paged_results:1:1024 " ) ) {
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
case ' D ' :
if ( ! add_control ( ret , " show_deleted:1 " ) ) {
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
case ' R ' :
2009-12-16 14:58:35 +11:00
if ( ! add_control ( ret , " show_recycled:0 " ) ) {
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
case ' d ' :
if ( ! add_control ( ret , " show_deactivated_link:0 " ) ) {
2009-11-28 17:35:36 +11:00
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
2009-12-10 23:44:05 +11:00
case ' r ' :
if ( ! add_control ( ret , " reveal_internals:0 " ) ) {
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
2010-10-19 11:19:20 +11:00
case CMDLINE_RELAX :
if ( ! add_control ( ret , " relax:0 " ) ) {
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
2009-11-28 17:35:36 +11:00
case ' N ' :
if ( ! add_control ( ret , " search_options:1:2 " ) ) {
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
case ' E ' :
2009-11-30 22:49:39 +11:00
if ( ! add_control ( ret , " extended_dn:1:1 " ) ) {
2009-11-28 17:35:36 +11:00
fprintf ( stderr , __location__ " : out of memory \n " ) ;
goto failed ;
}
break ;
2005-06-18 07:43:52 +00:00
default :
fprintf ( stderr , " Invalid option %s: %s \n " ,
poptBadOption ( pc , 0 ) , poptStrerror ( opt ) ) ;
2010-11-01 15:41:07 +11:00
if ( usage ) usage ( ldb ) ;
2005-06-18 07:43:52 +00:00
goto failed ;
}
}
/* setup the remaining options for the main program to use */
options . argv = poptGetArgs ( pc ) ;
if ( options . argv ) {
options . argv + + ;
while ( options . argv [ options . argc ] ) options . argc + + ;
}
* ret = options ;
/* all utils need some option */
2005-08-21 14:26:03 +00:00
if ( ret - > url = = NULL ) {
fprintf ( stderr , " You must supply a url with -H or with $LDB_URL \n " ) ;
2010-11-01 15:41:07 +11:00
if ( usage ) usage ( ldb ) ;
2005-08-21 14:26:03 +00:00
goto failed ;
}
2005-06-18 07:43:52 +00:00
2006-08-25 06:38:29 +00:00
if ( strcmp ( ret - > url , " NONE " ) = = 0 ) {
return ret ;
}
2005-12-01 04:52:54 +00:00
2006-08-25 06:38:29 +00:00
if ( options . nosync ) {
flags | = LDB_FLG_NOSYNC ;
}
2006-02-04 09:49:33 +00:00
2009-09-08 20:57:31 +10:00
if ( options . show_binary ) {
flags | = LDB_FLG_SHOW_BINARY ;
}
2009-09-21 15:24:39 -07:00
if ( options . tracing ) {
flags | = LDB_FLG_ENABLE_TRACING ;
}
2007-11-05 21:57:33 +01:00
if ( options . modules_path ! = NULL ) {
ldb_set_modules_dir ( ldb , options . modules_path ) ;
}
2010-11-01 15:41:07 +11:00
rc = ldb_modules_hook ( ldb , LDB_MODULE_HOOK_CMDLINE_PRECONNECT ) ;
if ( rc ! = LDB_SUCCESS ) {
fprintf ( stderr , " ldb: failed to run preconnect hooks : %s \n " , ldb_strerror ( rc ) ) ;
goto failed ;
}
2006-08-25 06:38:29 +00:00
/* now connect to the ldb */
2011-04-10 19:35:22 +02:00
if ( ldb_connect ( ldb , ret - > url , flags , ret - > options ) ! = LDB_SUCCESS ) {
2006-08-25 06:38:29 +00:00
fprintf ( stderr , " Failed to connect to %s - %s \n " ,
ret - > url , ldb_errstring ( ldb ) ) ;
goto failed ;
2005-06-18 09:01:09 +00:00
}
2010-11-01 15:41:07 +11:00
rc = ldb_modules_hook ( ldb , LDB_MODULE_HOOK_CMDLINE_POSTCONNECT ) ;
if ( rc ! = LDB_SUCCESS ) {
fprintf ( stderr , " ldb: failed to run post connect hooks : %s \n " , ldb_strerror ( rc ) ) ;
goto failed ;
}
2010-01-10 12:53:07 +11:00
2005-06-18 07:43:52 +00:00
return ret ;
failed :
talloc_free ( ret ) ;
2011-02-01 20:34:44 +01:00
exit ( LDB_ERR_OPERATIONS_ERROR ) ;
2005-06-18 07:43:52 +00:00
return NULL ;
}
2006-01-18 04:36:30 +00:00
/* this function check controls reply and determines if more
* processing is needed setting up the request controls correctly
*
* returns :
* - 1 error
* 0 all ok
* 1 all ok , more processing required
*/
int handle_controls_reply ( struct ldb_control * * reply , struct ldb_control * * request )
{
2009-11-06 18:35:17 +01:00
unsigned int i , j ;
int ret = 0 ;
2006-01-18 04:36:30 +00:00
if ( reply = = NULL | | request = = NULL ) return - 1 ;
for ( i = 0 ; reply [ i ] ; i + + ) {
2006-02-06 01:21:17 +00:00
if ( strcmp ( LDB_CONTROL_VLV_RESP_OID , reply [ i ] - > oid ) = = 0 ) {
struct ldb_vlv_resp_control * rep_control ;
rep_control = talloc_get_type ( reply [ i ] - > data , struct ldb_vlv_resp_control ) ;
/* check we have a matching control in the request */
for ( j = 0 ; request [ j ] ; j + + ) {
if ( strcmp ( LDB_CONTROL_VLV_REQ_OID , request [ j ] - > oid ) = = 0 )
break ;
}
if ( ! request [ j ] ) {
fprintf ( stderr , " Warning VLV reply received but no request have been made \n " ) ;
continue ;
}
/* check the result */
if ( rep_control - > vlv_result ! = 0 ) {
fprintf ( stderr , " Warning: VLV not performed with error: %d \n " , rep_control - > vlv_result ) ;
} else {
fprintf ( stderr , " VLV Info: target position = %d, content count = %d \n " , rep_control - > targetPosition , rep_control - > contentCount ) ;
}
continue ;
}
2006-01-18 04:36:30 +00:00
if ( strcmp ( LDB_CONTROL_ASQ_OID , reply [ i ] - > oid ) = = 0 ) {
struct ldb_asq_control * rep_control ;
rep_control = talloc_get_type ( reply [ i ] - > data , struct ldb_asq_control ) ;
/* check the result */
if ( rep_control - > result ! = 0 ) {
fprintf ( stderr , " Warning: ASQ not performed with error: %d \n " , rep_control - > result ) ;
}
continue ;
}
2006-02-06 01:21:17 +00:00
2006-01-18 04:36:30 +00:00
if ( strcmp ( LDB_CONTROL_PAGED_RESULTS_OID , reply [ i ] - > oid ) = = 0 ) {
struct ldb_paged_control * rep_control , * req_control ;
rep_control = talloc_get_type ( reply [ i ] - > data , struct ldb_paged_control ) ;
if ( rep_control - > cookie_len = = 0 ) /* we are done */
break ;
/* more processing required */
/* let's fill in the request control with the new cookie */
for ( j = 0 ; request [ j ] ; j + + ) {
if ( strcmp ( LDB_CONTROL_PAGED_RESULTS_OID , request [ j ] - > oid ) = = 0 )
break ;
}
/* if there's a reply control we must find a request
* control matching it */
if ( ! request [ j ] ) return - 1 ;
req_control = talloc_get_type ( request [ j ] - > data , struct ldb_paged_control ) ;
if ( req_control - > cookie )
talloc_free ( req_control - > cookie ) ;
2006-09-23 20:29:54 +00:00
req_control - > cookie = ( char * ) talloc_memdup (
req_control , rep_control - > cookie ,
rep_control - > cookie_len ) ;
2006-01-18 04:36:30 +00:00
req_control - > cookie_len = rep_control - > cookie_len ;
ret = 1 ;
continue ;
}
if ( strcmp ( LDB_CONTROL_SORT_RESP_OID , reply [ i ] - > oid ) = = 0 ) {
struct ldb_sort_resp_control * rep_control ;
rep_control = talloc_get_type ( reply [ i ] - > data , struct ldb_sort_resp_control ) ;
/* check we have a matching control in the request */
for ( j = 0 ; request [ j ] ; j + + ) {
if ( strcmp ( LDB_CONTROL_SERVER_SORT_OID , request [ j ] - > oid ) = = 0 )
break ;
}
if ( ! request [ j ] ) {
fprintf ( stderr , " Warning Server Sort reply received but no request found \n " ) ;
continue ;
}
/* check the result */
if ( rep_control - > result ! = 0 ) {
fprintf ( stderr , " Warning: Sorting not performed with error: %d \n " , rep_control - > result ) ;
}
continue ;
}
if ( strcmp ( LDB_CONTROL_DIRSYNC_OID , reply [ i ] - > oid ) = = 0 ) {
struct ldb_dirsync_control * rep_control , * req_control ;
char * cookie ;
rep_control = talloc_get_type ( reply [ i ] - > data , struct ldb_dirsync_control ) ;
if ( rep_control - > cookie_len = = 0 ) /* we are done */
break ;
/* more processing required */
/* let's fill in the request control with the new cookie */
for ( j = 0 ; request [ j ] ; j + + ) {
if ( strcmp ( LDB_CONTROL_DIRSYNC_OID , request [ j ] - > oid ) = = 0 )
break ;
}
/* if there's a reply control we must find a request
* control matching it */
if ( ! request [ j ] ) return - 1 ;
req_control = talloc_get_type ( request [ j ] - > data , struct ldb_dirsync_control ) ;
if ( req_control - > cookie )
talloc_free ( req_control - > cookie ) ;
2006-09-23 20:29:54 +00:00
req_control - > cookie = ( char * ) talloc_memdup (
req_control , rep_control - > cookie ,
rep_control - > cookie_len ) ;
2006-01-18 04:36:30 +00:00
req_control - > cookie_len = rep_control - > cookie_len ;
cookie = ldb_base64_encode ( req_control , rep_control - > cookie , rep_control - > cookie_len ) ;
printf ( " # DIRSYNC cookie returned was: \n # %s \n " , cookie ) ;
continue ;
}
/* no controls matched, throw a warning */
fprintf ( stderr , " Unknown reply control oid: %s \n " , reply [ i ] - > oid ) ;
}
return ret ;
}