openldap/clients/tools/ldapmodify.c

953 lines
22 KiB
C
Raw Normal View History

/* $OpenLDAP$ */
Vienna Bulk Commit This commit includes many changes. All changes compile under NT but have not been tested under UNIX. A Summary of changes (likely incomplete): NT changes: Removed lint. Clean up configuration support for "Debug", "Release", "SDebug", and "SRelease" configurations. Share output directories for clients, libraries, and slapd. (maybe they should be combined further and moved to build/{,S}{Debug,Release}). Enable threading when _MT is defined. Enable debuging when _DEBUG is defined. Disable setting of NDEBUG under Release/SRelease. Asserts are disabled in <ac/assert.h> when LDAP_DEBUG is not defined. Added 'build/main.dsp' Master project. Removed non-slapd projects from slapd.dsp (see main.dsp). Removed replaced many uses of _WIN32 macro with feature based macros. ldap_cdefs.h changes #define LDAP_CONST const (see below) #define LDAP_F(type) LDAP_F_PRE type LDAP_F_POST To allow specifiers to be added before and after the type declaration. (For DLL handling) LBER/LDAP changes Namespace changes: s/lber_/ber_/ for here and there. s/NAME_ERROR/LDAP_NAME_ERROR/g Deleted NULLMSG and other NULL* macros for namespace reasons. "const" libraries. Installed headers (ie: lber.h, ldap.h) use LDAP_CONST macro. Normally set to 'const' when __STDC__. Can be set externally to enable/disable 'constification' of external interface. Internal interface always uses 'const'. Did not fix warnings in -lldif (in lieu of new LDIF parser). Added _ext API implementations (excepting search and bind). Need to implement ldap_int_get_controls() for reponses with controls. Added numberous assert() checks. LDAP_R _MT defines HAVE_NT_THREADS Added numberous assert() checks. Changed ldap_pthread_t back to unsigned long. Used cast to HANDLE in _join(). LDBM Replaced _WIN32 with HAVE_SYSLOG ud Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). slapd Made connection sockbuf field a pointer to a sockbuf. This removed slap.h dependency on lber-int.h. lber-int.h now only included by those files needing to mess with the sockbuf. Used ber_* functions/macros to access sockbuf internals whenever possible. Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). Removed FD_SET unsigned lint slapd/tools Used EXEEXT to added ".exe" to routines. Need to define EXEEXT under UNIX. ldappasswd Added ldappasswd.dsp. Ported to NT. Used getpid() to seed rand(). nt_debug Minor cleanup. Added "portable.h" include and used <ac/*.h> where appropriate. Added const to char* format argument.
1999-05-19 09:12:33 +08:00
/*
2000-05-13 10:25:54 +08:00
* Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
Vienna Bulk Commit This commit includes many changes. All changes compile under NT but have not been tested under UNIX. A Summary of changes (likely incomplete): NT changes: Removed lint. Clean up configuration support for "Debug", "Release", "SDebug", and "SRelease" configurations. Share output directories for clients, libraries, and slapd. (maybe they should be combined further and moved to build/{,S}{Debug,Release}). Enable threading when _MT is defined. Enable debuging when _DEBUG is defined. Disable setting of NDEBUG under Release/SRelease. Asserts are disabled in <ac/assert.h> when LDAP_DEBUG is not defined. Added 'build/main.dsp' Master project. Removed non-slapd projects from slapd.dsp (see main.dsp). Removed replaced many uses of _WIN32 macro with feature based macros. ldap_cdefs.h changes #define LDAP_CONST const (see below) #define LDAP_F(type) LDAP_F_PRE type LDAP_F_POST To allow specifiers to be added before and after the type declaration. (For DLL handling) LBER/LDAP changes Namespace changes: s/lber_/ber_/ for here and there. s/NAME_ERROR/LDAP_NAME_ERROR/g Deleted NULLMSG and other NULL* macros for namespace reasons. "const" libraries. Installed headers (ie: lber.h, ldap.h) use LDAP_CONST macro. Normally set to 'const' when __STDC__. Can be set externally to enable/disable 'constification' of external interface. Internal interface always uses 'const'. Did not fix warnings in -lldif (in lieu of new LDIF parser). Added _ext API implementations (excepting search and bind). Need to implement ldap_int_get_controls() for reponses with controls. Added numberous assert() checks. LDAP_R _MT defines HAVE_NT_THREADS Added numberous assert() checks. Changed ldap_pthread_t back to unsigned long. Used cast to HANDLE in _join(). LDBM Replaced _WIN32 with HAVE_SYSLOG ud Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). slapd Made connection sockbuf field a pointer to a sockbuf. This removed slap.h dependency on lber-int.h. lber-int.h now only included by those files needing to mess with the sockbuf. Used ber_* functions/macros to access sockbuf internals whenever possible. Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). Removed FD_SET unsigned lint slapd/tools Used EXEEXT to added ".exe" to routines. Need to define EXEEXT under UNIX. ldappasswd Added ldappasswd.dsp. Ported to NT. Used getpid() to seed rand(). nt_debug Minor cleanup. Added "portable.h" include and used <ac/*.h> where appropriate. Added const to char* format argument.
1999-05-19 09:12:33 +08:00
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
1998-08-09 08:43:13 +08:00
/* ldapmodify.c - generic program to modify or add entries using LDAP */
1998-10-25 09:41:42 +08:00
#include "portable.h"
1998-08-09 08:43:13 +08:00
#include <stdio.h>
1999-06-03 08:37:44 +08:00
#include <ac/stdlib.h>
1998-10-25 09:41:42 +08:00
1998-11-15 14:54:30 +08:00
#include <ac/ctype.h>
1999-01-21 06:01:14 +08:00
#include <ac/signal.h>
1998-10-25 09:41:42 +08:00
#include <ac/string.h>
#include <ac/unistd.h>
#ifdef HAVE_SYS_STAT_H
1998-08-09 08:43:13 +08:00
#include <sys/stat.h>
#endif
1998-10-25 09:41:42 +08:00
#ifdef HAVE_SYS_FILE_H
1998-08-09 08:43:13 +08:00
#include <sys/file.h>
1998-10-25 09:41:42 +08:00
#endif
#ifdef HAVE_FCNTL_H
1998-08-09 08:43:13 +08:00
#include <fcntl.h>
1998-10-25 09:41:42 +08:00
#endif
1998-08-09 08:43:13 +08:00
#include <ldap.h>
#include "ldif.h"
#include "ldap_defaults.h"
1998-08-09 08:43:13 +08:00
static char *prog;
static char *binddn = NULL;
2000-05-16 10:16:54 +08:00
static struct berval passwd = { 0, NULL};
static char *ldaphost = NULL;
static int ldapport = 0;
#ifdef HAVE_CYRUS_SASL
static char *sasl_authc_id = NULL;
static char *sasl_authz_id = NULL;
static char *sasl_mech = NULL;
static int sasl_integrity = 0;
static int sasl_privacy = 0;
#endif
static int use_tls = 0;
static int ldapadd, replace, not, verbose, contoper, force;
static LDAP *ld;
1998-08-09 08:43:13 +08:00
#define LDAPMOD_MAXLINE 4096
/* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
#define T_VERSION_STR "version"
1998-08-09 08:43:13 +08:00
#define T_REPLICA_STR "replica"
#define T_DN_STR "dn"
#define T_CHANGETYPESTR "changetype"
#define T_ADDCTSTR "add"
#define T_MODIFYCTSTR "modify"
#define T_DELETECTSTR "delete"
#define T_MODRDNCTSTR "modrdn"
#define T_MODDNCTSTR "moddn"
#define T_RENAMECTSTR "rename"
1998-08-09 08:43:13 +08:00
#define T_MODOPADDSTR "add"
#define T_MODOPREPLACESTR "replace"
#define T_MODOPDELETESTR "delete"
#define T_MODSEPSTR "-"
#define T_NEWRDNSTR "newrdn"
#define T_DELETEOLDRDNSTR "deleteoldrdn"
#define T_NEWSUPSTR "newsuperior"
1998-08-09 08:43:13 +08:00
static void usage LDAP_P(( const char *prog )) LDAP_GCCATTR((noreturn));
static int process_ldif_rec LDAP_P(( char *rbuf, int count ));
2000-06-30 03:35:51 +08:00
static void addmodifyop LDAP_P((
LDAPMod ***pmodsp, int modop,
const char *attr,
struct berval *value ));
static int domodify LDAP_P((
const char *dn,
LDAPMod **pmods,
int newentry ));
static int dodelete LDAP_P((
const char *dn ));
static int dorename LDAP_P((
const char *dn,
const char *newrdn,
const char *newsup,
int deleteoldrdn ));
1998-10-25 09:41:42 +08:00
static char *read_one_record LDAP_P(( FILE *fp ));
static void
usage( const char *prog )
{
1999-06-01 10:07:57 +08:00
fprintf( stderr,
"Add or modify entries from an LDAP server\n\n"
"usage: %s [options]\n"
" The list of desired operations are read from stdin or from the file\n"
" specified by \"-f file\".\n"
"options:\n"
" -a\t\tadd values (default%s)\n"
" -b\t\tread values from files (for binary attributes)\n"
" -c\t\tcontinuous operation\n"
" -C\t\tchase referrals\n"
" -d level\tset LDAP debugging level to `level'\n"
" -D dn\t\tbind DN\n"
" -E\t\trequest SASL privacy (-EE to make it critical)\n"
" -f file\t\tperform sequence of operations listed in file\n"
" -F\t\tforce all changes records to be used\n"
" -h host\t\tLDAP server\n"
" -I\t\trequest SASL integrity checking (-II to make it\n"
" \tcritical)\n"
" -k\t\tuse Kerberos authentication\n"
" -K\t\tlike -k, but do only step 1 of the Kerberos bind\n"
" -M\t\tenable Manage DSA IT control (-MM to make it critical)\n"
" -n\t\tprint changes, don't actually do them\n"
" -p port\t\tport on LDAP server\n"
" -r\t\treplace values\n"
" -U user\t\tSASL authentication identity (username)\n"
" -v\t\tverbose mode\n"
" -w passwd\tbind password (for Simple authentication)\n"
" -X id\t\tSASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
" -Y mech\t\tSASL mechanism\n"
" -Z\t\tissue Start TLS request (-ZZ to require successful response)\n"
, prog, (strcmp( prog, "ldapadd" ) ? " is to replace" : "") );
exit( EXIT_FAILURE );
}
1998-11-04 21:15:18 +08:00
int
main( int argc, char **argv )
1998-08-09 08:43:13 +08:00
{
char *infile, *rbuf, *start;
FILE *fp;
int rc, i, authmethod, version, want_bindpw, debug, manageDSAit, referrals;
int count;
1998-08-09 08:43:13 +08:00
if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) {
prog = argv[ 0 ];
} else {
++prog;
}
/* Print usage when no parameters */
if( argc < 2 ) usage( prog );
ldapadd = ( strcmp( prog, "ldapadd" ) == 0 );
1998-08-09 08:43:13 +08:00
infile = NULL;
not = verbose = want_bindpw = debug = manageDSAit = referrals = 0;
1998-12-15 04:39:02 +08:00
authmethod = LDAP_AUTH_SIMPLE;
1998-12-29 13:33:34 +08:00
version = -1;
1998-08-09 08:43:13 +08:00
while (( i = getopt( argc, argv, "acCD:d:EFf:h:IKkMnP:p:rtU:vWw:X:Y:Z" )) != EOF ) {
switch( i ) {
1998-08-09 08:43:13 +08:00
case 'a': /* add */
ldapadd = 1;
1998-08-09 08:43:13 +08:00
break;
case 'c': /* continuous operation */
1998-08-09 08:43:13 +08:00
contoper = 1;
break;
case 'C':
referrals++;
break;
case 'r': /* default is to replace rather than add values */
replace = 1;
break;
case 'k': /* kerberos bind */
#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
1998-12-15 04:39:02 +08:00
authmethod = LDAP_AUTH_KRBV4;
#else
fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
return( EXIT_FAILURE );
1998-12-15 04:39:02 +08:00
#endif
break;
case 'K': /* kerberos bind, part 1 only */
#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
1998-12-15 04:39:02 +08:00
authmethod = LDAP_AUTH_KRBV41;
#else
fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
return( EXIT_FAILURE );
1998-12-15 04:39:02 +08:00
#endif
break;
case 'F': /* force all changes records to be used */
force = 1;
break;
case 'h': /* ldap host */
ldaphost = strdup( optarg );
break;
case 'D': /* bind DN */
1998-08-09 08:43:13 +08:00
binddn = strdup( optarg );
break;
case 'w': /* password */
2000-05-16 10:16:54 +08:00
passwd.bv_val = strdup( optarg );
{
char* p;
1999-07-01 12:39:42 +08:00
for( p = optarg; *p == '\0'; p++ ) {
*p = '*';
}
}
2000-05-16 10:16:54 +08:00
passwd.bv_len = strlen( passwd.bv_val );
break;
case 'd':
debug |= atoi( optarg );
1998-08-09 08:43:13 +08:00
break;
case 'f': /* read from file */
infile = strdup( optarg );
break;
case 'p':
ldapport = atoi( optarg );
1998-08-09 08:43:13 +08:00
break;
case 'n': /* print adds, don't actually do them */
++not;
break;
case 'v': /* verbose mode */
1998-08-09 08:43:13 +08:00
verbose++;
break;
case 'M':
/* enable Manage DSA IT */
manageDSAit++;
break;
case 'W':
want_bindpw++;
break;
1998-12-27 22:08:46 +08:00
case 'P':
switch( atoi(optarg) )
1998-12-27 22:08:46 +08:00
{
case 2:
1998-12-27 22:08:46 +08:00
version = LDAP_VERSION2;
break;
case 3:
1998-12-27 22:08:46 +08:00
version = LDAP_VERSION3;
break;
default:
fprintf( stderr, "protocol version should be 2 or 3\n" );
usage( argv[0] );
1998-12-27 22:08:46 +08:00
}
break;
case 'I':
#ifdef HAVE_CYRUS_SASL
sasl_integrity++;
authmethod = LDAP_AUTH_SASL;
#else
fprintf( stderr, "%s was not compiled with SASL support\n",
argv[0] );
return( EXIT_FAILURE );
#endif
break;
case 'E':
#ifdef HAVE_CYRUS_SASL
sasl_privacy++;
authmethod = LDAP_AUTH_SASL;
#else
fprintf( stderr, "%s was not compiled with SASL support\n",
argv[0] );
return( EXIT_FAILURE );
#endif
break;
case 'Y':
#ifdef HAVE_CYRUS_SASL
if ( strcasecmp( optarg, "any" ) && strcmp( optarg, "*" ) ) {
sasl_mech = strdup( optarg );
}
authmethod = LDAP_AUTH_SASL;
#else
fprintf( stderr, "%s was not compiled with SASL support\n",
argv[0] );
return( EXIT_FAILURE );
#endif
break;
case 'U':
#ifdef HAVE_CYRUS_SASL
sasl_authc_id = strdup( optarg );
authmethod = LDAP_AUTH_SASL;
#else
fprintf( stderr, "%s was not compiled with SASL support\n",
argv[0] );
return( EXIT_FAILURE );
#endif
break;
case 'X':
#ifdef HAVE_CYRUS_SASL
sasl_authz_id = strdup( optarg );
authmethod = LDAP_AUTH_SASL;
#else
fprintf( stderr, "%s was not compiled with SASL support\n",
argv[0] );
return( EXIT_FAILURE );
#endif
break;
case 'Z':
#ifdef HAVE_TLS
use_tls++;
#else
fprintf( stderr, "%s was not compiled with TLS support\n",
argv[0] );
return( EXIT_FAILURE );
#endif
break;
default:
usage( prog );
1998-08-09 08:43:13 +08:00
}
}
if ( argc != optind )
usage( prog );
1998-08-09 08:43:13 +08:00
if ( ( authmethod == LDAP_AUTH_KRBV4 ) || ( authmethod ==
LDAP_AUTH_KRBV41 ) ) {
if( version > LDAP_VERSION2 ) {
fprintf( stderr, "Kerberos requires LDAPv2\n" );
return( EXIT_FAILURE );
}
version = LDAP_VERSION2;
}
else if ( authmethod == LDAP_AUTH_SASL ) {
2000-04-25 18:30:42 +08:00
if( version != -1 && version != LDAP_VERSION3 ) {
fprintf( stderr, "SASL requires LDAPv3\n" );
return( EXIT_FAILURE );
}
version = LDAP_VERSION3;
}
if( manageDSAit ) {
2000-04-25 18:30:42 +08:00
if( version != -1 && version != LDAP_VERSION3 ) {
fprintf(stderr, "manage DSA control requires LDAPv3\n");
return EXIT_FAILURE;
}
version = LDAP_VERSION3;
}
if( use_tls ) {
2000-04-25 18:30:42 +08:00
if( version != -1 && version != LDAP_VERSION3 ) {
fprintf(stderr, "Start TLS requires LDAPv3\n");
return EXIT_FAILURE;
}
version = LDAP_VERSION3;
}
1998-08-09 08:43:13 +08:00
if ( infile != NULL ) {
if (( fp = fopen( infile, "r" )) == NULL ) {
perror( infile );
return( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
} else {
fp = stdin;
}
if ( debug ) {
if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
}
if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
}
ldif_debug = debug;
}
1998-08-09 08:43:13 +08:00
1999-01-21 06:01:14 +08:00
#ifdef SIGPIPE
(void) SIGNAL( SIGPIPE, SIG_IGN );
#endif
1998-08-09 08:43:13 +08:00
if ( !not ) {
if (( ld = ldap_init( ldaphost, ldapport )) == NULL ) {
perror( "ldap_init" );
return( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
/* referrals */
if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
{
fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
referrals ? "on" : "off" );
return EXIT_FAILURE;
}
1998-08-09 08:43:13 +08:00
if (version == -1 ) {
version = 3;
}
if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
!= LDAP_OPT_SUCCESS )
{
fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
version );
2000-06-26 02:17:47 +08:00
return EXIT_FAILURE;
1998-12-29 13:33:34 +08:00
}
1998-12-27 22:08:46 +08:00
if ( use_tls && ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
if ( use_tls > 1 ) {
ldap_perror( ld, "ldap_start_tls" );
return( EXIT_FAILURE );
}
fprintf( stderr, "WARNING: could not start TLS\n" );
}
2000-06-14 11:07:33 +08:00
if (want_bindpw) {
passwd.bv_val = getpassphrase("Enter LDAP Password: ");
passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
2000-06-14 11:07:33 +08:00
}
if ( authmethod == LDAP_AUTH_SASL ) {
#ifdef HAVE_CYRUS_SASL
int minssf = 0, maxssf = 0;
if ( sasl_integrity > 0 )
maxssf = 1;
if ( sasl_integrity > 1 )
minssf = 1;
if ( sasl_privacy > 0 )
maxssf = 100000; /* Something big value */
if ( sasl_privacy > 1 )
minssf = 56;
if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MINSSF,
(void *)&minssf ) != LDAP_OPT_SUCCESS ) {
fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MINSSF"
"%d\n", minssf);
return( EXIT_FAILURE );
}
if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MAXSSF,
(void *)&maxssf ) != LDAP_OPT_SUCCESS ) {
fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MINSSF"
"%d\n", minssf);
return( EXIT_FAILURE );
}
2000-05-16 10:16:54 +08:00
rc = ldap_negotiated_sasl_bind_s( ld, binddn, sasl_authc_id,
sasl_authz_id, sasl_mech,
passwd.bv_len ? &passwd : NULL,
NULL, NULL );
if( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_negotiated_sasl_bind_s" );
return( EXIT_FAILURE );
}
#else
fprintf( stderr, "%s was not compiled with SASL support\n",
argv[0] );
return( EXIT_FAILURE );
#endif
1998-08-09 08:43:13 +08:00
}
else {
2000-05-16 10:16:54 +08:00
if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
!= LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_bind" );
return( EXIT_FAILURE );
}
}
1998-08-09 08:43:13 +08:00
}
rc = 0;
if ( manageDSAit ) {
int err;
LDAPControl c;
LDAPControl *ctrls[2];
ctrls[0] = &c;
ctrls[1] = NULL;
c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
c.ldctl_value.bv_val = NULL;
c.ldctl_value.bv_len = 0;
c.ldctl_iscritical = manageDSAit > 1;
err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, &ctrls );
if( err != LDAP_OPT_SUCCESS ) {
fprintf( stderr, "Could not set ManageDSAit %scontrol\n",
c.ldctl_iscritical ? "critical " : "" );
if( c.ldctl_iscritical ) {
exit( EXIT_FAILURE );
}
}
}
count = 0;
1998-08-09 08:43:13 +08:00
while (( rc == 0 || contoper ) &&
( rbuf = read_one_record( fp )) != NULL ) {
count++;
1998-08-09 08:43:13 +08:00
start = rbuf;
rc = process_ldif_rec( start, count );
1998-08-09 08:43:13 +08:00
if( rc )
fprintf( stderr, "ldif_record() = %d\n", rc );
free( rbuf );
1998-08-09 08:43:13 +08:00
}
if ( !not ) {
ldap_unbind( ld );
1998-08-09 08:43:13 +08:00
}
return( rc );
1998-08-09 08:43:13 +08:00
}
static int
process_ldif_rec( char *rbuf, int count )
1998-08-09 08:43:13 +08:00
{
2000-06-30 03:35:51 +08:00
char *line, *dn, *type, *newrdn, *newsup, *p;
int rc, linenum, modop, replicaport;
int expect_modop, expect_sep, expect_ct, expect_newrdn, expect_newsup;
1998-08-09 08:43:13 +08:00
int expect_deleteoldrdn, deleteoldrdn;
int saw_replica, use_record, new_entry, delete_entry, got_all;
LDAPMod **pmods;
int version;
2000-06-30 03:35:51 +08:00
struct berval val;
1998-08-09 08:43:13 +08:00
new_entry = ldapadd;
1998-08-09 08:43:13 +08:00
rc = got_all = saw_replica = delete_entry = modop = expect_modop = 0;
expect_deleteoldrdn = expect_newrdn = expect_newsup = 0;
expect_sep = expect_ct = 0;
1998-08-09 08:43:13 +08:00
linenum = 0;
version = 0;
1998-08-09 08:43:13 +08:00
deleteoldrdn = 1;
use_record = force;
pmods = NULL;
dn = newrdn = newsup = NULL;
1998-08-09 08:43:13 +08:00
while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
1998-08-09 08:43:13 +08:00
++linenum;
1998-08-09 08:43:13 +08:00
if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
expect_sep = 0;
expect_ct = 1;
continue;
}
2000-06-30 03:35:51 +08:00
if ( ldif_parse_line( line, &type, &val.bv_val, &val.bv_len ) < 0 ) {
fprintf( stderr, "%s: invalid format (line %d) entry: \"%s\"\n",
1998-08-09 08:43:13 +08:00
prog, linenum, dn == NULL ? "" : dn );
rc = LDAP_PARAM_ERROR;
break;
}
if ( dn == NULL ) {
if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
++saw_replica;
2000-06-30 03:35:51 +08:00
if (( p = strchr( val.bv_val, ':' )) == NULL ) {
replicaport = 0;
1998-08-09 08:43:13 +08:00
} else {
*p++ = '\0';
replicaport = atoi( p );
}
2000-06-30 03:35:51 +08:00
if ( ldaphost != NULL && strcasecmp( val.bv_val, ldaphost ) == 0 &&
1998-08-09 08:43:13 +08:00
replicaport == ldapport ) {
use_record = 1;
}
} else if ( count == 1 && linenum == 1 &&
strcasecmp( type, T_VERSION_STR ) == 0 )
{
2000-06-30 03:35:51 +08:00
if( val.bv_len == 0 || atoi(val.bv_val) != 1 ) {
fprintf( stderr, "%s: invalid version %s, line %d (ignored)\n",
2000-06-30 03:35:51 +08:00
prog, val.bv_val == NULL ? "(null)" : val.bv_val, linenum );
}
version++;
1998-08-09 08:43:13 +08:00
} else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
2000-06-30 03:35:51 +08:00
if (( dn = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
1998-08-09 08:43:13 +08:00
perror( "strdup" );
exit( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
expect_ct = 1;
}
1999-08-20 08:55:22 +08:00
goto end_line; /* skip all lines until we see "dn:" */
1998-08-09 08:43:13 +08:00
}
if ( expect_ct ) {
expect_ct = 0;
if ( !use_record && saw_replica ) {
printf( "%s: skipping change record for entry: %s\n"
"\t(LDAP host/port does not match replica: lines)\n",
1998-08-09 08:43:13 +08:00
prog, dn );
free( dn );
1999-08-20 08:55:22 +08:00
ber_memfree( type );
2000-06-30 03:35:51 +08:00
ber_memfree( val.bv_val );
1998-08-09 08:43:13 +08:00
return( 0 );
}
if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
2000-06-30 03:35:51 +08:00
if ( strcasecmp( val.bv_val, T_MODIFYCTSTR ) == 0 ) {
1998-08-09 08:43:13 +08:00
new_entry = 0;
expect_modop = 1;
2000-06-30 03:35:51 +08:00
} else if ( strcasecmp( val.bv_val, T_ADDCTSTR ) == 0 ) {
1998-08-09 08:43:13 +08:00
new_entry = 1;
2000-06-30 03:35:51 +08:00
} else if ( strcasecmp( val.bv_val, T_MODRDNCTSTR ) == 0
|| strcasecmp( val.bv_val, T_MODDNCTSTR ) == 0
|| strcasecmp( val.bv_val, T_RENAMECTSTR ) == 0)
{
1998-08-09 08:43:13 +08:00
expect_newrdn = 1;
2000-06-30 03:35:51 +08:00
} else if ( strcasecmp( val.bv_val, T_DELETECTSTR ) == 0 ) {
1998-08-09 08:43:13 +08:00
got_all = delete_entry = 1;
} else {
fprintf( stderr,
"%s: unknown %s \"%s\" (line %d of entry \"%s\")\n",
2000-06-30 03:35:51 +08:00
prog, T_CHANGETYPESTR, val.bv_val, linenum, dn );
1998-08-09 08:43:13 +08:00
rc = LDAP_PARAM_ERROR;
}
1999-08-20 08:55:22 +08:00
goto end_line;
} else if ( ldapadd ) { /* missing changetype => add */
1998-08-09 08:43:13 +08:00
new_entry = 1;
modop = LDAP_MOD_ADD;
} else {
expect_modop = 1; /* missing changetype => modify */
}
}
if ( expect_modop ) {
expect_modop = 0;
expect_sep = 1;
if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
modop = LDAP_MOD_ADD;
1999-08-20 08:55:22 +08:00
goto end_line;
1998-08-09 08:43:13 +08:00
} else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
modop = LDAP_MOD_REPLACE;
2000-06-30 03:35:51 +08:00
addmodifyop( &pmods, modop, val.bv_val, NULL );
1999-08-20 08:55:22 +08:00
goto end_line;
1998-08-09 08:43:13 +08:00
} else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
modop = LDAP_MOD_DELETE;
2000-06-30 03:35:51 +08:00
addmodifyop( &pmods, modop, val.bv_val, NULL );
1999-08-20 08:55:22 +08:00
goto end_line;
1998-08-09 08:43:13 +08:00
} else { /* no modify op: use default */
modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
}
}
if ( expect_newrdn ) {
if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
2000-06-30 03:35:51 +08:00
if (( newrdn = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
1998-08-09 08:43:13 +08:00
perror( "strdup" );
exit( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
expect_deleteoldrdn = 1;
expect_newrdn = 0;
} else {
fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1998-08-09 08:43:13 +08:00
prog, T_NEWRDNSTR, type, linenum, dn );
rc = LDAP_PARAM_ERROR;
}
} else if ( expect_deleteoldrdn ) {
if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
2000-06-30 03:35:51 +08:00
deleteoldrdn = ( *val.bv_val == '0' ) ? 0 : 1;
expect_deleteoldrdn = 0;
expect_newsup = 1;
1998-08-09 08:43:13 +08:00
got_all = 1;
} else {
fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1998-08-09 08:43:13 +08:00
prog, T_DELETEOLDRDNSTR, type, linenum, dn );
rc = LDAP_PARAM_ERROR;
}
} else if ( expect_newsup ) {
if ( strcasecmp( type, T_NEWSUPSTR ) == 0 ) {
2000-06-30 03:35:51 +08:00
if (( newsup = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
perror( "strdup" );
exit( EXIT_FAILURE );
}
expect_newsup = 0;
} else {
fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
prog, T_NEWSUPSTR, type, linenum, dn );
rc = LDAP_PARAM_ERROR;
}
1998-08-09 08:43:13 +08:00
} else if ( got_all ) {
fprintf( stderr,
"%s: extra lines at end (line %d of entry \"%s\")\n",
1998-08-09 08:43:13 +08:00
prog, linenum, dn );
rc = LDAP_PARAM_ERROR;
} else {
2000-06-30 03:35:51 +08:00
addmodifyop( &pmods, modop, type, val.bv_val == NULL ? NULL : &val );
1998-08-09 08:43:13 +08:00
}
1999-08-20 08:55:22 +08:00
end_line:
ber_memfree( type );
2000-06-30 03:35:51 +08:00
ber_memfree( val.bv_val );
1998-08-09 08:43:13 +08:00
}
if( linenum == 0 ) {
return 0;
}
if( version && linenum == 1 ) {
return 0;
}
1998-08-09 08:43:13 +08:00
if ( rc == 0 ) {
if ( delete_entry ) {
rc = dodelete( dn );
} else if ( newrdn != NULL ) {
2000-06-30 03:35:51 +08:00
rc = dorename( dn, newrdn, newsup, deleteoldrdn );
1998-08-09 08:43:13 +08:00
} else {
rc = domodify( dn, pmods, new_entry );
}
if ( rc == LDAP_SUCCESS ) {
rc = 0;
}
}
if ( dn != NULL ) {
free( dn );
}
if ( newrdn != NULL ) {
free( newrdn );
}
if ( pmods != NULL ) {
ldap_mods_free( pmods, 1 );
1998-08-09 08:43:13 +08:00
}
return( rc );
}
static void
2000-06-30 03:35:51 +08:00
addmodifyop(
LDAPMod ***pmodsp,
int modop,
const char *attr,
struct berval *val )
1998-08-09 08:43:13 +08:00
{
LDAPMod **pmods;
int i, j;
pmods = *pmodsp;
modop |= LDAP_MOD_BVALUES;
i = 0;
if ( pmods != NULL ) {
for ( ; pmods[ i ] != NULL; ++i ) {
if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
pmods[ i ]->mod_op == modop )
{
break;
}
}
1998-08-09 08:43:13 +08:00
}
if ( pmods == NULL || pmods[ i ] == NULL ) {
if (( pmods = (LDAPMod **)ber_memrealloc( pmods, (i + 2) *
sizeof( LDAPMod * ))) == NULL )
{
perror( "realloc" );
exit( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
*pmodsp = pmods;
pmods[ i + 1 ] = NULL;
1998-08-09 08:43:13 +08:00
pmods[ i ] = (LDAPMod *)ber_memcalloc( 1, sizeof( LDAPMod ));
if ( pmods[ i ] == NULL ) {
perror( "calloc" );
exit( EXIT_FAILURE );
1998-08-09 08:43:13 +08:00
}
pmods[ i ]->mod_op = modop;
pmods[ i ]->mod_type = ber_strdup( attr );
if ( pmods[ i ]->mod_type == NULL ) {
perror( "strdup" );
exit( EXIT_FAILURE );
}
1998-08-09 08:43:13 +08:00
}
2000-06-30 03:35:51 +08:00
if ( val != NULL ) {
j = 0;
if ( pmods[ i ]->mod_bvalues != NULL ) {
for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
/* Empty */;
}
}
1998-08-09 08:43:13 +08:00
pmods[ i ]->mod_bvalues = (struct berval **) ber_memrealloc(
pmods[ i ]->mod_bvalues, (j + 2) * sizeof( struct berval * ));
if ( pmods[ i ]->mod_bvalues == NULL ) {
perror( "ber_realloc" );
exit( EXIT_FAILURE );
}
1998-08-09 08:43:13 +08:00
pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
2000-06-30 03:35:51 +08:00
pmods[ i ]->mod_bvalues[ j ] = ber_bvdup( val );
if ( pmods[ i ]->mod_bvalues[ j ] == NULL ) {
perror( "ber_bvdup" );
exit( EXIT_FAILURE );
}
1998-08-09 08:43:13 +08:00
}
}
static int
2000-06-30 03:35:51 +08:00
domodify(
const char *dn,
LDAPMod **pmods,
int newentry )
1998-08-09 08:43:13 +08:00
{
int i, j, k, notascii, op;
struct berval *bvp;
if ( pmods == NULL ) {
fprintf( stderr, "%s: no attributes to change or add (entry=\"%s\")\n",
1998-08-09 08:43:13 +08:00
prog, dn );
return( LDAP_PARAM_ERROR );
}
if ( verbose ) {
for ( i = 0; pmods[ i ] != NULL; ++i ) {
op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
printf( "%s %s:\n", op == LDAP_MOD_REPLACE ?
"replace" : op == LDAP_MOD_ADD ?
"add" : "delete", pmods[ i ]->mod_type );
if ( pmods[ i ]->mod_bvalues != NULL ) {
for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
bvp = pmods[ i ]->mod_bvalues[ j ];
notascii = 0;
1998-10-25 09:41:42 +08:00
for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
1998-08-09 08:43:13 +08:00
if ( !isascii( bvp->bv_val[ k ] )) {
notascii = 1;
break;
}
}
if ( notascii ) {
printf( "\tNOT ASCII (%ld bytes)\n", bvp->bv_len );
} else {
printf( "\t%s\n", bvp->bv_val );
}
}
}
}
}
if ( newentry ) {
printf( "%sadding new entry \"%s\"\n", not ? "!" : "", dn );
1998-08-09 08:43:13 +08:00
} else {
printf( "%smodifying entry \"%s\"\n", not ? "!" : "", dn );
1998-08-09 08:43:13 +08:00
}
if ( !not ) {
if ( newentry ) {
i = ldap_add_s( ld, dn, pmods );
} else {
i = ldap_modify_s( ld, dn, pmods );
}
if ( i != LDAP_SUCCESS ) {
ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
} else if ( verbose ) {
printf( "modify complete\n" );
}
} else {
i = LDAP_SUCCESS;
}
putchar( '\n' );
return( i );
}
static int
2000-06-30 03:35:51 +08:00
dodelete(
const char *dn )
1998-08-09 08:43:13 +08:00
{
int rc;
printf( "%sdeleting entry \"%s\"\n", not ? "!" : "", dn );
1998-08-09 08:43:13 +08:00
if ( !not ) {
if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_delete" );
} else if ( verbose ) {
printf( "delete complete" );
}
} else {
rc = LDAP_SUCCESS;
}
putchar( '\n' );
return( rc );
}
static int
2000-06-30 03:35:51 +08:00
dorename(
const char *dn,
const char *newrdn,
const char* newsup,
int deleteoldrdn )
1998-08-09 08:43:13 +08:00
{
int rc;
printf( "%smodifying rdn of entry \"%s\"\n", not ? "!" : "", dn );
1998-08-09 08:43:13 +08:00
if ( verbose ) {
printf( "\tnew RDN: \"%s\" (%skeep existing values)\n",
1998-08-09 08:43:13 +08:00
newrdn, deleteoldrdn ? "do not " : "" );
}
if ( !not ) {
2000-06-30 03:35:51 +08:00
if (( rc = ldap_rename2_s( ld, dn, newrdn, newsup, deleteoldrdn ))
1998-08-09 08:43:13 +08:00
!= LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_modrdn" );
} else {
printf( "modrdn completed\n" );
}
} else {
rc = LDAP_SUCCESS;
}
putchar( '\n' );
return( rc );
}
static char *
read_one_record( FILE *fp )
{
char *buf, line[ LDAPMOD_MAXLINE ];
int lcur, lmax;
lcur = lmax = 0;
buf = NULL;
while ( fgets( line, sizeof(line), fp ) != NULL ) {
int len = strlen( line );
if( len < 2 ) {
if( buf == NULL ) {
continue;
} else {
break;
}
}
if ( lcur + len + 1 > lmax ) {
lmax = LDAPMOD_MAXLINE
* (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
if (( buf = (char *)realloc( buf, lmax )) == NULL ) {
perror( "realloc" );
exit( EXIT_FAILURE );
}
}
strcpy( buf + lcur, line );
lcur += len;
1998-08-09 08:43:13 +08:00
}
return( buf );
}