2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * The contents of this file are subject to the Netscape Public
8 * License Version 1.1 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.mozilla.org/NPL/
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is Netscape
21 * Communications Corporation. Portions created by Netscape are
22 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
28 /* ldapmodify.c - generic program to modify or add entries using LDAP */
33 #ifdef SOLARIS_LDAP_CMD
36 #endif /* SOLARIS_LDAP_CMD */
38 #ifndef SOLARIS_LDAP_CMD
42 static int newval
, contoper
, force
, valsfromfiles
, display_binary_values
;
43 static int ldif_version
= -1; /* -1 => unknown version */
44 static char *rejfile
= NULL
;
45 static char *bulkimport_suffix
= NULL
;
46 static int ldapmodify_quiet
= 0;
48 #ifdef SOLARIS_LDAP_CMD
49 static int error
= 0, replace
, nbthreads
= 1;
50 static int thr_create_errors
= 0;
51 static pthread_mutex_t read_mutex
= {0};
52 static pthread_mutex_t wait_mutex
= {0};
53 static pthread_cond_t wait_cond
= {0};
56 * For Solaris, ld is defined local to process() because
57 * multiple threads restricts Solaris from using a global
59 * Solaris uses multiple threads to create multiple
60 * ldap connections if nbthreads > 1 (i.e -l option).
63 #endif /* SOLARIS_LDAP_CMD */
65 #define LDAPMOD_MAXLINE 4096
67 /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
68 #define T_REPLICA_STR "replica"
70 #define T_VERSION_STR "version"
71 #define T_CHANGETYPESTR "changetype"
72 #define T_ADDCTSTR "add"
73 #define T_MODIFYCTSTR "modify"
74 #define T_DELETECTSTR "delete"
75 #define T_RENAMECTSTR "rename" /* non-standard */
76 #define T_MODDNCTSTR "moddn"
77 #define T_MODRDNCTSTR "modrdn"
78 #define T_MODOPADDSTR "add"
79 #define T_MODOPREPLACESTR "replace"
80 #define T_MODOPDELETESTR "delete"
81 #define T_MODSEPSTR "-"
82 #define T_NEWRDNSTR "newrdn"
83 #define T_NEWSUPERIORSTR "newsuperior"
84 #define T_NEWPARENTSTR "newparent"
85 #define T_DELETEOLDRDNSTR "deleteoldrdn"
86 #define T_NEWSUPERIORSTR "newsuperior"
87 #define T_NEWPARENTSTR "newparent" /* non-standard */
90 #define BULKIMPORT_START_OID "2.16.840.1.113730.3.5.7"
91 #define BULKIMPORT_STOP_OID "2.16.840.1.113730.3.5.8"
93 static int process( void *arg
);
94 static void options_callback( int option
, char *optarg
);
95 static void addmodifyop( LDAPMod
***pmodsp
, int modop
, char *attr
,
96 char *value
, int vlen
);
97 static void freepmods( LDAPMod
**pmods
);
98 static char *read_one_record( FILE *fp
);
99 static char *strdup_and_trim( char *s
);
101 #ifdef SOLARIS_LDAP_CMD
102 static int process_ldapmod_rec( LDAP
*ld
, char *rbuf
);
103 static int process_ldif_rec( LDAP
*ld
, char *rbuf
);
104 static int domodify( LDAP
*ld
, char *dn
, LDAPMod
**pmods
, int newentry
);
105 static int dodelete( LDAP
*ld
, char *dn
);
106 static int dorename( LDAP
*ld
, char *dn
, char *newrdn
, char *newparent
,
109 static int process_ldapmod_rec( char *rbuf
);
110 static int process_ldif_rec( char *rbuf
);
111 static int domodify( char *dn
, LDAPMod
**pmods
, int newentry
);
112 static int dodelete( char *dn
);
113 static int dorename( char *dn
, char *newrdn
, char *newparent
,
115 #endif /* SOLARIS_LDAP_CMD */
120 fprintf( stderr
, gettext("usage: %s [options]\n"), ldaptool_progname
);
121 fprintf( stderr
, gettext("options:\n") );
122 ldaptool_common_usage( 0 );
123 fprintf( stderr
, gettext(" -c\t\tcontinuous mode (do not stop on errors)\n") );
124 fprintf( stderr
, gettext(" -A\t\tdisplay non-ASCII values in conjunction with -v\n") );
125 fprintf( stderr
, gettext(" -f file\tread modifications from file (default: standard input)\n") );
126 if ( strcmp( ldaptool_progname
, "ldapmodify" ) == 0 ){
127 fprintf( stderr
, gettext(" -a\t\tadd entries\n") );
129 fprintf( stderr
, gettext(" -b\t\tread values that start with / from files (for bin attrs)\n") );
130 fprintf( stderr
, gettext(" -F\t\tforce application of all changes, regardless of\n") );
131 fprintf( stderr
, gettext(" \t\treplica lines\n") );
132 fprintf( stderr
, gettext(" -e rejfile\tsave rejected entries in \"rejfile\"\n") );
133 fprintf( stderr
, gettext(" -B suffix\tbulk import to \"suffix\"\n"));
134 fprintf( stderr
, gettext(" -q\t\tbe quiet when adding/modifying entries\n") );
135 #ifdef SOLARIS_LDAP_CMD
136 fprintf( stderr
, gettext(" -r\t\treplace values\n"));
137 fprintf( stderr
, gettext(" -l nb-connections\tnumber of LDAP connections\n"));
138 #endif /* SOLARIS_LDAP_CMD */
139 exit( LDAP_PARAM_ERROR
);
144 main( int argc
, char **argv
)
149 #ifdef SOLARIS_LDAP_CMD
150 char *locale
= setlocale(LC_ALL
, "");
151 textdomain(TEXT_DOMAIN
);
162 valsfromfiles
= display_binary_values
= 0;
164 #ifdef SOLARIS_LDAP_CMD
165 optind
= ldaptool_process_args( argc
, argv
, "aAbcFe:B:qrl:", 0,
168 optind
= ldaptool_process_args( argc
, argv
, "aAbcFe:B:q", 0,
170 #endif /* SOLARIS_LDAP_CMD */
173 if ( optind
== -1 ) {
177 if ( !newval
&& strcmp( ldaptool_progname
, "ldapadd" ) == 0 ) {
181 if ( ldaptool_fp
== NULL
) {
185 if ( argc
- optind
!= 0 ) {
189 #ifdef SOLARIS_LDAP_CMD
191 if ( nbthreads
== 1 ) {
193 /* check for and report output error */
195 rc
= ldaptool_check_ferror( stdout
, rc
,
196 gettext("output error (output might be incomplete)") );
200 for ( i
=0; i
<nbthreads
; ++i
) {
201 if ( thr_create(NULL
, 0, process
, NULL
, NULL
, NULL
) != 0 )
205 if ( thr_create_errors
< nbthreads
)
206 while ( thr_join(0, NULL
, NULL
) == 0 );
210 /* check for and report output error */
212 rc
= ldaptool_check_ferror( stdout
, rc
,
213 gettext("output error (output might be incomplete)") );
217 /* check for and report output error */
219 rc
= ldaptool_check_ferror( stdout
, rc
,
220 gettext("output error (output might be incomplete)") );
222 #endif /* SOLARIS_LDAP_CMD */
225 #ifdef SOLARIS_LDAP_CMD
227 if (nbthreads > 1) { \
228 mutex_lock(&read_mutex); \
230 mutex_unlock(&read_mutex); \
235 #endif /* SOLARIS_LDAP_CMD */
240 char *rbuf
, *saved_rbuf
, *start
, *p
, *q
;
242 int rc
, use_ldif
, deref
;
245 #ifdef SOLARIS_LDAP_CMD
247 #endif /* SOLARIS_LDAP_CMD */
249 ld
= ldaptool_ldap_init( 0 );
251 if ( !ldaptool_not
) {
252 deref
= LDAP_DEREF_NEVER
; /* this seems prudent */
253 ldap_set_option( ld
, LDAP_OPT_DEREF
, &deref
);
258 if (( ldctrl
= ldaptool_create_manage_dsait_control()) != NULL
) {
259 ldaptool_add_control_to_array( ldctrl
, ldaptool_request_ctrls
);
262 if ((ldctrl
= ldaptool_create_proxyauth_control(ld
)) !=NULL
) {
263 ldaptool_add_control_to_array( ldctrl
, ldaptool_request_ctrls
);
268 /* turn on bulk import?*/
269 if (bulkimport_suffix
) {
270 struct berval bv
, *retdata
;
273 bv
.bv_val
= bulkimport_suffix
;
274 bv
.bv_len
= strlen(bulkimport_suffix
);
275 if ((rc
= ldap_extended_operation_s(ld
,
276 BULKIMPORT_START_OID
, &bv
, NULL
,
277 NULL
, &retoid
, &retdata
)) != 0) {
278 fprintf(stderr
, gettext("Error: unable to service "
279 "extended operation request\n\t'%s' for "
280 "bulk import\n\t(error:%d:'%s')\n"),
281 BULKIMPORT_START_OID
, rc
, ldap_err2string(rc
));
285 ldap_memfree(retoid
);
290 while (( rc
== 0 || contoper
) &&
291 ( rbuf
= read_one_record( ldaptool_fp
)) != NULL
) {
293 * we assume record is ldif/slapd.replog if the first line
294 * has a colon that appears to the left of any equal signs, OR
295 * if the first line consists entirely of digits (an entry id)
297 use_ldif
= ( p
= strchr( rbuf
, ':' )) != NULL
&&
298 ( q
= strchr( rbuf
, '\n' )) != NULL
&& p
< q
&&
299 (( q
= strchr( rbuf
, '=' )) == NULL
|| p
< q
);
302 saved_rbuf
= strdup( rbuf
);
304 if ( !use_ldif
&& ( q
= strchr( rbuf
, '\n' )) != NULL
) {
305 for ( p
= rbuf
; p
< q
; ++p
) {
306 if ( !isdigit( *p
)) {
316 #ifdef SOLARIS_LDAP_CMD
318 rc
= process_ldif_rec( ld
, start
);
320 rc
= process_ldapmod_rec( ld
, start
);
324 rc
= process_ldif_rec( start
);
326 rc
= process_ldapmod_rec( start
);
328 #endif /* SOLARIS_LDAP_CMD */
330 if ( rc
!= LDAP_SUCCESS
&& rejfile
!= NULL
) {
331 /* Write this record to the reject file */
334 if ( stat( rejfile
, &stbuf
) < 0 ) {
335 if ( errno
== ENOENT
) {
339 if (( rfp
= ldaptool_open_file( rejfile
, "a" )) == NULL
) {
340 fprintf( stderr
, gettext("Cannot open error file \"%s\" - "
341 "erroneous entries will not be saved\n"), rejfile
);
344 if ( newfile
== 0 ) {
347 fprintf( rfp
, gettext("# Error: %s\n"), ldap_err2string( rc
));
348 fputs( saved_rbuf
, rfp
);
357 ldaptool_reset_control_array( ldaptool_request_ctrls
);
359 /* turn off bulk import?*/
360 if (bulkimport_suffix
) {
361 struct berval bv
, *retdata
;
366 if ((rc
= ldap_extended_operation_s(ld
,
367 BULKIMPORT_STOP_OID
, &bv
, NULL
,
368 NULL
, &retoid
, &retdata
)) != 0) {
370 fprintf(stderr
, gettext("Error: unable to service "
371 "extended operation request\n\t '%s' for "
372 "bulk import\n\t(rc:%d:'%s')\n"),
373 BULKIMPORT_STOP_OID
, rc
, ldap_err2string(rc
));
377 ldap_memfree(retoid
);
382 #ifdef SOLARIS_LDAP_CMD
383 mutex_lock(&read_mutex
);
385 ldaptool_cleanup( ld
);
386 #ifdef SOLARIS_LDAP_CMD
387 mutex_unlock(&read_mutex
);
394 options_callback( int option
, char *optarg
)
400 case 'b': /* read values from files (for binary attributes) */
403 case 'A': /* display non-ASCII values when -v is used */
404 display_binary_values
= 1;
406 case 'c': /* continuous operation */
409 case 'F': /* force all changes records to be used */
413 rejfile
= strdup( optarg
);
415 case 'B': /* bulk import option */
416 bulkimport_suffix
= strdup( optarg
);
418 case 'q': /* quiet mode on add/modify operations */
419 ldapmodify_quiet
= 1;
421 #ifdef SOLARIS_LDAP_CMD
422 case 'r': /* default is to replace rather than add values */
426 nbthreads
= atoi(optarg
);
428 #endif /* SOLARIS_LDAP_CMD */
437 #ifdef SOLARIS_LDAP_CMD
438 process_ldif_rec( LDAP
*ld
, char *rbuf
)
440 process_ldif_rec( char *rbuf
)
443 char *line
, *dn
, *type
, *value
, *newrdn
, *newparent
, *p
;
444 char *ctrl_oid
=NULL
, *ctrl_value
=NULL
;
445 int ctrl_criticality
=1;
447 int rc
, linenum
, vlen
, modop
, replicaport
;
448 int expect_modop
, expect_sep
, expect_chgtype_or_control
, expect_newrdn
;
449 int expect_deleteoldrdn
, expect_newparent
, rename
, moddn
;
450 int deleteoldrdn
, saw_replica
, use_record
, new_entry
, delete_entry
;
451 int got_all
, got_value
;
456 rc
= got_all
= saw_replica
= delete_entry
= expect_modop
= 0;
457 expect_deleteoldrdn
= expect_newrdn
= expect_newparent
= expect_sep
= 0;
458 expect_chgtype_or_control
= linenum
= got_value
= rename
= moddn
= 0;
462 dn
= newrdn
= newparent
= NULL
;
464 #ifdef SOLARIS_LDAP_CMD
465 while ( rc
== 0 && ( line
= str_getline( &rbuf
)) != NULL
) {
467 while ( rc
== 0 && ( line
= ldif_getline( &rbuf
)) != NULL
) {
468 #endif /* SOLARIS_LDAP_CMD */
470 if ( expect_sep
&& strcasecmp( line
, T_MODSEPSTR
) == 0 ) {
474 /*If we see a separator in the input stream,
475 but we didn't get a value from the last modify
476 then we have to fill pmods with an empty value*/
477 if (modop
== LDAP_MOD_REPLACE
&& !got_value
){
478 addmodifyop( &pmods
, modop
, value
, NULL
, 0);
485 #ifdef SOLARIS_LDAP_CMD
486 if ( str_parse_line( line
, &type
, &value
, &vlen
) < 0 ) {
488 if ( ldif_parse_line( line
, &type
, &value
, &vlen
) < 0 ) {
489 #endif /* SOLARIS_LDAP_CMD */
490 fprintf( stderr
, gettext("%s: invalid format (line %d of entry: %s)\n"),
491 ldaptool_progname
, linenum
, dn
== NULL
? "" : dn
);
492 fprintf( stderr
, gettext("%s: line contents: (%s)\n"),
493 ldaptool_progname
, line
);
494 rc
= LDAP_PARAM_ERROR
;
500 if ( !use_record
&& strcasecmp( type
, T_REPLICA_STR
) == 0 ) {
502 if (( p
= strchr( value
, ':' )) == NULL
) {
503 replicaport
= LDAP_PORT
;
506 replicaport
= atoi( p
);
508 if ( strcasecmp( value
, ldaptool_host
) == 0 &&
509 replicaport
== ldaptool_port
) {
513 } else if ( strcasecmp( type
, T_DN_STR
) == 0 ) {
514 if (( dn
= strdup( value
)) == NULL
) {
516 exit( LDAP_NO_MEMORY
);
518 expect_chgtype_or_control
= 1;
520 } else if ( strcasecmp( type
, T_VERSION_STR
) == 0 ) {
521 ldif_version
= atoi( value
);
522 if ( ldif_version
!= LDIF_VERSION_ONE
) {
523 fprintf( stderr
, gettext("%s: LDIF version %d is not supported;"
524 " use version: %d\n"), ldaptool_progname
, ldif_version
,
526 exit( LDAP_PARAM_ERROR
);
528 if ( ldaptool_verbose
) {
529 printf( gettext("Processing a version %d LDIF file...\n"),
533 /* Now check if there's something left to process */
534 /* and if not, go get the new record, else continue */
535 if ( *rbuf
== '\0' ) {
539 } else if ( !saw_replica
) {
540 printf( gettext("%s: skipping change record: no dn: line\n"),
545 continue; /* skip all lines until we see "dn:" */
548 if ( expect_chgtype_or_control
) {
549 expect_chgtype_or_control
= 0;
550 if ( !use_record
&& saw_replica
) {
551 printf( gettext("%s: skipping change record for entry: %s\n\t(LDAP host/port does not match replica: lines)\n"),
552 ldaptool_progname
, dn
);
557 #ifndef SOLARIS_LDAP_CMD
558 if ( strcasecmp( type
, "control" ) == 0 ) {
559 value
= strdup_and_trim( value
);
560 if (ldaptool_parse_ctrl_arg(value
, ' ', &ctrl_oid
,
561 &ctrl_criticality
, &ctrl_value
, &vlen
)) {
564 ldctrl
= calloc(1,sizeof(LDAPControl
));
566 rc
= ldaptool_berval_from_ldif_value( ctrl_value
, vlen
,
567 &(ldctrl
->ldctl_value
),
568 1 /* recognize file URLs */, 0 /* always try file */,
569 1 /* report errors */ );
570 if ((rc
= ldaptool_fileurlerr2ldaperr( rc
)) != LDAP_SUCCESS
) {
571 fprintf( stderr
, gettext("Unable to parse %s\n"), ctrl_value
);
575 ldctrl
->ldctl_oid
= ctrl_oid
;
576 ldctrl
->ldctl_iscritical
= ctrl_criticality
;
577 ldaptool_add_control_to_array(ldctrl
, ldaptool_request_ctrls
);
578 expect_chgtype_or_control
= 1;
581 #endif /* SOLARIS_LDAP_CMD */
583 if ( strcasecmp( type
, T_CHANGETYPESTR
) == 0 ) {
584 value
= strdup_and_trim( value
);
585 if ( strcasecmp( value
, T_MODIFYCTSTR
) == 0 ) {
588 } else if ( strcasecmp( value
, T_ADDCTSTR
) == 0 ) {
590 modop
= LDAP_MOD_ADD
;
591 } else if ( strcasecmp( value
, T_MODRDNCTSTR
) == 0 ) {
594 } else if ( strcasecmp( value
, T_MODDNCTSTR
) == 0 ) {
597 } else if ( strcasecmp( value
, T_RENAMECTSTR
) == 0 ) {
600 } else if ( strcasecmp( value
, T_DELETECTSTR
) == 0 ) {
601 got_all
= delete_entry
= 1;
604 gettext("%s: unknown %s \"%s\" (line %d of entry: %s)\n"),
605 ldaptool_progname
, T_CHANGETYPESTR
, value
,
607 rc
= LDAP_PARAM_ERROR
;
611 } else if ( newval
) { /* missing changetype => add */
613 modop
= LDAP_MOD_ADD
;
615 /*The user MUST put in changetype: blah
616 unless adding a new entry with either -a or ldapadd*/
617 fprintf(stderr
, gettext("%s: Missing changetype operation specification.\n\tThe dn line must be followed by \"changetype: operation\"\n\t(unless ldapmodify is called with -a option)\n\twhere operation is add|delete|modify|modrdn|moddn|rename\n\t\"%s\" is not a valid changetype operation specification\n\t(line %d of entry %s)\n"),
618 ldaptool_progname
, type
, linenum
, dn
);
619 rc
= LDAP_PARAM_ERROR
;
620 /*expect_modop = 1; missing changetype => modify */
624 if ( expect_modop
) {
627 if ( strcasecmp( type
, T_MODOPADDSTR
) == 0 ) {
628 modop
= LDAP_MOD_ADD
;
630 } else if ( strcasecmp( type
, T_MODOPREPLACESTR
) == 0 ) {
631 modop
= LDAP_MOD_REPLACE
;
633 } else if ( strcasecmp( type
, T_MODOPDELETESTR
) == 0 ) {
634 modop
= LDAP_MOD_DELETE
;
635 addmodifyop( &pmods
, modop
, value
, NULL
, 0 );
637 #ifdef SOLARIS_LDAP_CMD
638 } else { /* no modify op: use default */
639 modop
= replace
? LDAP_MOD_REPLACE
: LDAP_MOD_ADD
;
642 } else { /*Bug 27479. Remove default add operation*/
643 fprintf(stderr
, gettext("%s: Invalid parameter \"%s\" specified for changetype modify (line %d of entry %s)\n"),
644 ldaptool_progname
, type
, linenum
, dn
);
645 rc
= LDAP_PARAM_ERROR
;
647 #endif /* SOLARIS_LDAP_CMD */
651 if ( expect_newrdn
) {
652 if ( strcasecmp( type
, T_NEWRDNSTR
) == 0 ) {
653 if ( *value
== '\0' ) {
655 gettext("%s: newrdn value missing (line %d of entry: %s)\n"),
656 ldaptool_progname
, linenum
, dn
== NULL
? "" : dn
);
657 rc
= LDAP_PARAM_ERROR
;
658 } else if (( newrdn
= strdup( value
)) == NULL
) {
660 exit( LDAP_NO_MEMORY
);
664 expect_newparent
= 1;
666 expect_deleteoldrdn
= 1;
670 fprintf( stderr
, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"),
671 ldaptool_progname
, T_NEWRDNSTR
, type
, linenum
, dn
);
672 rc
= LDAP_PARAM_ERROR
;
674 } else if ( expect_newparent
) {
675 expect_newparent
= 0;
677 expect_deleteoldrdn
= 1;
679 if ( strcasecmp( type
, T_NEWPARENTSTR
) == 0
680 || strcasecmp( type
, T_NEWSUPERIORSTR
) == 0 ) {
681 if (( newparent
= strdup( value
)) == NULL
) {
683 exit( LDAP_NO_MEMORY
);
686 /* Since this is an optional argument for rename/moddn, cause
687 * the current line to be re-evaluated if newparent doesn't
688 * follow deleteoldrdn.
693 } else if ( expect_deleteoldrdn
) {
694 if ( strcasecmp( type
, T_DELETEOLDRDNSTR
) == 0 ) {
695 if ( *value
== '\0' ) {
697 gettext("%s: missing 0 or 1 (line %d of entry: %s)\n"),
698 ldaptool_progname
, linenum
, dn
== NULL
? "" : dn
);
699 rc
= LDAP_PARAM_ERROR
;
701 deleteoldrdn
= ( *value
== '0' ) ? 0 : 1;
702 expect_deleteoldrdn
= 0;
704 expect_newparent
= 1;
708 fprintf( stderr
, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"),
709 ldaptool_progname
, T_DELETEOLDRDNSTR
, type
, linenum
,
711 rc
= LDAP_PARAM_ERROR
;
714 } else if ( got_all
) {
716 gettext("%s: extra lines at end (line %d of entry %s)\n"),
717 ldaptool_progname
, linenum
, dn
);
718 rc
= LDAP_PARAM_ERROR
;
721 addmodifyop( &pmods
, modop
, type
, value
, vlen
);
722 /*There was a value to replace*/
729 if ( delete_entry
) {
730 #ifdef SOLARIS_LDAP_CMD
731 rc
= dodelete( ld
, dn
);
734 #endif /* SOLARIS_LDAP_CMD */
735 } else if ( newrdn
!= NULL
) {
736 #ifdef SOLARIS_LDAP_CMD
737 rc
= dorename( ld
, dn
, newrdn
, newparent
, deleteoldrdn
);
739 rc
= dorename( dn
, newrdn
, newparent
, deleteoldrdn
);
740 #endif /* SOLARIS_LDAP_CMD */
744 /*Patch to fix Bug 22183
745 If pmods is null, then there is no
746 attribute to replace, so we alloc
748 if (modop
== LDAP_MOD_REPLACE
&& !got_value
&& expect_sep
){
749 addmodifyop( &pmods
, modop
, value
, NULL
, 0);
753 #ifdef SOLARIS_LDAP_CMD
754 rc
= domodify( ld
, dn
, pmods
, new_entry
);
756 rc
= domodify( dn
, pmods
, new_entry
);
757 #endif /* SOLARIS_LDAP_CMD */
760 if ( rc
== LDAP_SUCCESS
) {
768 if ( newrdn
!= NULL
) {
771 if ( newparent
!= NULL
) {
774 if ( pmods
!= NULL
) {
783 #ifdef SOLARIS_LDAP_CMD
784 process_ldapmod_rec( LDAP
*ld
, char *rbuf
)
786 process_ldapmod_rec( char *rbuf
)
787 #endif /* SOLARIS_LDAP_CMD */
789 char *line
, *dn
, *p
, *q
, *attr
, *value
;
790 int rc
, linenum
, modop
;
799 while ( rc
== 0 && rbuf
!= NULL
&& *rbuf
!= '\0' ) {
801 if (( p
= strchr( rbuf
, '\n' )) == NULL
) {
804 if ( *(p
-1) == '\\' ) { /* lines ending in '\' are continued */
813 if ( dn
== NULL
) { /* first line contains DN */
814 if (( dn
= strdup( line
)) == NULL
) {
816 exit( LDAP_NO_MEMORY
);
819 if (( p
= strchr( line
, '=' )) == NULL
) {
821 p
= line
+ strlen( line
);
827 for ( attr
= line
; *attr
!= '\0' && isspace( *attr
); ++attr
) {
828 ; /* skip attribute leading white space */
831 for ( q
= p
- 1; q
> attr
&& isspace( *q
); --q
) {
832 *q
= '\0'; /* remove attribute trailing white space */
835 if ( value
!= NULL
) {
836 while ( isspace( *value
)) {
837 ++value
; /* skip value leading white space */
839 for ( q
= value
+ strlen( value
) - 1; q
> value
&&
840 isspace( *q
); --q
) {
841 *q
= '\0'; /* remove value trailing white space */
843 if ( *value
== '\0' ) {
849 if ( value
== NULL
&& newval
) {
850 fprintf( stderr
, gettext("%s: missing value on line %d (attr is %s)\n"),
851 ldaptool_progname
, linenum
, attr
);
852 rc
= LDAP_PARAM_ERROR
;
856 modop
= LDAP_MOD_DELETE
;
860 modop
= LDAP_MOD_ADD
;
864 #ifdef SOLARIS_LDAP_CMD
865 modop
= replace
? LDAP_MOD_REPLACE
: LDAP_MOD_ADD
;
867 /*Bug 27479. Remove the add default*/
868 fprintf(stderr
, gettext("%s: Invalid parameter specified for changetype modify (line %d of entry %s)\n"),
869 ldaptool_progname
, linenum
, dn
);
870 rc
= LDAP_PARAM_ERROR
;
871 #endif /* SOLARIS_LDAP_CMD */
874 addmodifyop( &pmods
, modop
, attr
, value
,
875 ( value
== NULL
) ? 0 : strlen( value
));
884 rc
= LDAP_PARAM_ERROR
;
885 #ifdef SOLARIS_LDAP_CMD
886 } else if (( rc
= domodify( ld
, dn
, pmods
, newval
)) == LDAP_SUCCESS
){
888 } else if (( rc
= domodify( dn
, pmods
, newval
)) == LDAP_SUCCESS
){
889 #endif /* SOLARIS_LDAP_CMD */
894 if ( pmods
!= NULL
) {
906 addmodifyop( LDAPMod
***pmodsp
, int modop
, char *attr
, char *value
, int vlen
)
913 modop
|= LDAP_MOD_BVALUES
;
916 if ( pmods
!= NULL
) {
917 for ( ; pmods
[ i
] != NULL
; ++i
) {
918 if ( strcasecmp( pmods
[ i
]->mod_type
, attr
) == 0 &&
919 pmods
[ i
]->mod_op
== modop
) {
925 if ( pmods
== NULL
|| pmods
[ i
] == NULL
) {
926 if (( pmods
= (LDAPMod
**)LDAPTOOL_SAFEREALLOC( pmods
, (i
+ 2) *
927 sizeof( LDAPMod
* ))) == NULL
) {
929 exit( LDAP_NO_MEMORY
);
932 pmods
[ i
+ 1 ] = NULL
;
933 if (( pmods
[ i
] = (LDAPMod
*)calloc( 1, sizeof( LDAPMod
)))
936 exit( LDAP_NO_MEMORY
);
938 pmods
[ i
]->mod_op
= modop
;
939 if (( pmods
[ i
]->mod_type
= strdup( attr
)) == NULL
) {
941 exit( LDAP_NO_MEMORY
);
945 if ( value
!= NULL
) {
947 if ( pmods
[ i
]->mod_bvalues
!= NULL
) {
948 for ( ; pmods
[ i
]->mod_bvalues
[ j
] != NULL
; ++j
) {
952 if (( pmods
[ i
]->mod_bvalues
= (struct berval
**)
953 LDAPTOOL_SAFEREALLOC( pmods
[ i
]->mod_bvalues
,
954 (j
+ 2) * sizeof( struct berval
* ))) == NULL
) {
956 exit( LDAP_NO_MEMORY
);
958 pmods
[ i
]->mod_bvalues
[ j
+ 1 ] = NULL
;
959 if (( bvp
= (struct berval
*)malloc( sizeof( struct berval
)))
962 exit( LDAP_NO_MEMORY
);
964 pmods
[ i
]->mod_bvalues
[ j
] = bvp
;
967 if (ldaptool_verbose
) {
968 printf(gettext("%s: value: %s vlen: %d\n"), "ldapmodify", value
, vlen
);
971 rc
= ldaptool_berval_from_ldif_value( value
, vlen
, bvp
,
972 ( ldif_version
>= LDIF_VERSION_ONE
), valsfromfiles
,
973 1 /* report errors */ );
974 if ( rc
!= LDAPTOOL_FILEURL_SUCCESS
) {
975 exit( ldaptool_fileurlerr2ldaperr( rc
));
982 #ifdef SOLARIS_LDAP_CMD
983 domodify( LDAP
*ld
, char *dn
, LDAPMod
**pmods
, int newentry
)
985 domodify( char *dn
, LDAPMod
**pmods
, int newentry
)
986 #endif /* SOLARIS_LDAP_CMD */
988 int i
, j
, notascii
, op
;
991 if ( pmods
== NULL
) {
992 fprintf( stderr
, gettext("%s: no attributes to change or add (entry %s)\n"),
993 ldaptool_progname
, dn
);
994 return( LDAP_PARAM_ERROR
);
997 if ( ldaptool_verbose
) {
998 for ( i
= 0; pmods
[ i
] != NULL
; ++i
) {
999 op
= pmods
[ i
]->mod_op
& ~LDAP_MOD_BVALUES
;
1000 printf( gettext("%s %s:\n"), op
== LDAP_MOD_REPLACE
?
1001 gettext("replace") : op
== LDAP_MOD_ADD
?
1002 gettext("add") : gettext("delete"), pmods
[ i
]->mod_type
);
1003 if ( pmods
[ i
]->mod_bvalues
!= NULL
) {
1004 for ( j
= 0; pmods
[ i
]->mod_bvalues
[ j
] != NULL
; ++j
) {
1005 bvp
= pmods
[ i
]->mod_bvalues
[ j
];
1007 if ( !display_binary_values
) {
1008 notascii
= !ldaptool_berval_is_ascii( bvp
);
1011 printf( gettext("\tNOT ASCII (%ld bytes)\n"), bvp
->bv_len
);
1013 printf( "\t%s\n", bvp
->bv_val
);
1020 if ( !ldapmodify_quiet
) {
1022 printf( gettext("%sadding new entry %s\n"),
1023 ldaptool_not
? "!" : "", dn
);
1025 printf( gettext("%smodifying entry %s\n"),
1026 ldaptool_not
? "!" : "", dn
);
1030 if ( !ldaptool_not
) {
1032 unsigned int sleep_interval
= 2; /* seconds */
1034 #ifdef SOLARIS_LDAP_CMD
1035 /* Backward compatibility with old Solaris command */
1036 unsigned int nb
= 0;
1038 while ((i
= ldaptool_add_ext_s( ld
, dn
, pmods
,
1039 ldaptool_request_ctrls
, NULL
, "ldap_add" ))
1041 if (i
== LDAP_BUSY
) {
1042 if ( sleep_interval
> 3600 ) {
1043 printf(gettext("ldap_add: Unable to complete "
1044 "request. Server is too "
1045 "busy servicing other "
1049 if ( !ldapmodify_quiet
) {
1050 printf(gettext("ldap_add: LDAP_BUSY returned "
1051 "by server. Will retry "
1052 "operation in %d seconds\n"),
1055 sleep( sleep_interval
);
1056 sleep_interval
*= 2;
1057 } else if (i
== LDAP_NO_SUCH_OBJECT
) {
1059 * Wait for the parent entry to be created by
1060 * another thread. Do not retry more than the
1061 * number of threads.
1064 if (nb
>= nbthreads
)
1066 mutex_lock(&wait_mutex
);
1069 if (cond_reltimedwait(&wait_cond
, &wait_mutex
, &to
)
1071 nb
= nbthreads
; /* last chance */
1073 mutex_unlock(&wait_mutex
);
1078 cond_broadcast(&wait_cond
);
1080 while ((i
= ldaptool_add_ext_s( ld
, dn
, pmods
,
1081 ldaptool_request_ctrls
, NULL
, "ldap_add" ))
1083 if ( sleep_interval
> 3600 ) {
1084 printf("ldap_add: Unable to complete request. ");
1085 printf("Server is too ");
1086 printf("busy servicing other requests\n");
1089 if ( !ldapmodify_quiet
) {
1090 printf("ldap_add: LDAP_BUSY returned by server. ");
1091 printf("Will retry operation ");
1092 printf("in %d seconds\n", sleep_interval
);
1094 sleep( sleep_interval
);
1095 sleep_interval
*= 2;
1097 #endif /* SOLARIS_LDAP_CMD */
1099 i
= ldaptool_modify_ext_s( ld
, dn
, pmods
, ldaptool_request_ctrls
,
1100 NULL
, "ldap_modify" );
1102 if ( i
== LDAP_SUCCESS
&& ldaptool_verbose
) {
1103 printf( gettext("modify complete\n") );
1109 if ( !ldapmodify_quiet
) {
1118 #ifdef SOLARIS_LDAP_CMD
1119 dodelete( LDAP
*ld
, char *dn
)
1121 dodelete( char *dn
)
1122 #endif /* SOLARIS_LDAP_CMD */
1126 printf( gettext("%sdeleting entry %s\n"), ldaptool_not
? "!" : "", dn
);
1127 if ( !ldaptool_not
) {
1128 if (( rc
= ldaptool_delete_ext_s( ld
, dn
, ldaptool_request_ctrls
,
1129 NULL
, "ldap_delete" )) == LDAP_SUCCESS
&& ldaptool_verbose
) {
1130 printf( gettext("delete complete") );
1143 #ifdef SOLARIS_LDAP_CMD
1144 dorename( LDAP
*ld
, char *dn
, char *newrdn
, char *newparent
, int deleteoldrdn
)
1146 dorename( char *dn
, char *newrdn
, char *newparent
, int deleteoldrdn
)
1147 #endif /* SOLARIS_LDAP_CMD */
1151 if ( ldaptool_verbose
) {
1152 if ( newparent
== NULL
) {
1153 printf(deleteoldrdn
?
1154 gettext("new RDN: %s (do not keep existing values)\n"):
1155 gettext("new RDN: %s (keep existing values)\n"));
1157 printf(deleteoldrdn
?
1158 gettext("new RDN: %s, new parent %s ( do not keep existing values)\n"):
1159 gettext("new RDN: %s, new parent %s ( keep existing values)\n"));
1163 printf( gettext("%smodifying RDN of entry %s%s\n"),
1164 ldaptool_not
? "!" : "", dn
, ( newparent
== NULL
) ? "" :
1165 gettext(" and/or moving it beneath a new parent\n") );
1167 if ( !ldaptool_not
) {
1168 if (( rc
= ldaptool_rename_s( ld
, dn
, newrdn
, newparent
, deleteoldrdn
,
1169 ldaptool_request_ctrls
, NULL
, "ldap_rename" )) == LDAP_SUCCESS
1170 && ldaptool_verbose
) {
1171 printf( gettext("rename completed\n") );
1184 freepmods( LDAPMod
**pmods
)
1188 for ( i
= 0; pmods
[ i
] != NULL
; ++i
) {
1189 if ( pmods
[ i
]->mod_bvalues
!= NULL
) {
1190 ber_bvecfree( pmods
[ i
]->mod_bvalues
);
1192 if ( pmods
[ i
]->mod_type
!= NULL
) {
1193 free( pmods
[ i
]->mod_type
);
1202 read_one_record( FILE *fp
)
1204 int len
, gotnothing
;
1205 char *buf
, line
[ LDAPMOD_MAXLINE
];
1212 #ifdef SOLARIS_LDAP_CMD
1213 mutex_lock(&read_mutex
);
1216 mutex_unlock(&read_mutex
);
1221 while ( fgets( line
, sizeof(line
), fp
) != NULL
) {
1222 if ( (len
= strlen( line
)) < 2 ) {
1230 /* Check if the blank line starts with '\r' (CR) */
1231 if ( ((len
= strlen( line
)) == 2) && (line
[0] == '\r') ) {
1239 if ( *line
== '#' ) {
1240 continue; /* skip comment lines */
1244 if ( lcur
+ len
+ 1 > lmax
) {
1245 lmax
= LDAPMOD_MAXLINE
1246 * (( lcur
+ len
+ 1 ) / LDAPMOD_MAXLINE
+ 1 );
1247 if (( buf
= (char *)LDAPTOOL_SAFEREALLOC( buf
, lmax
)) == NULL
) {
1248 perror( "realloc" );
1249 #ifdef SOLARIS_LDAP_CMD
1250 mutex_unlock(&read_mutex
);
1252 exit( LDAP_NO_MEMORY
);
1255 strcpy( buf
+ lcur
, line
);
1259 #ifdef SOLARIS_LDAP_CMD
1260 mutex_unlock(&read_mutex
);
1268 * strdup and trim trailing blanks
1271 strdup_and_trim( char *s
)
1275 if (( s
= strdup( s
)) == NULL
) {
1277 exit( LDAP_NO_MEMORY
);
1280 p
= s
+ strlen( s
) - 1;
1281 while ( p
>= s
&& isspace( *p
)) {