]> git.sur5r.net Git - openldap/blob - clients/tools/ldapmodify.c
9d4fe45fabfe738bddf210933b2aadfba2fdfc99
[openldap] / clients / tools / ldapmodify.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* ldapmodify.c - generic program to modify or add entries using LDAP */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/stdlib.h>
13
14 #include <ac/ctype.h>
15 #include <ac/signal.h>
16 #include <ac/string.h>
17 #include <ac/unistd.h>
18
19 #ifdef HAVE_SYS_STAT_H
20 #include <sys/stat.h>
21 #endif
22
23 #ifdef HAVE_SYS_FILE_H
24 #include <sys/file.h>
25 #endif
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29
30 #include <ldap.h>
31
32 #include "lutil.h"
33 #include "lutil_ldap.h"
34 #include "ldif.h"
35 #include "ldap_defaults.h"
36 #include "ldap_log.h"
37
38 static char     *prog;
39 static char     *binddn = NULL;
40 static struct berval passwd = { 0, NULL };
41 static char *ldapuri = NULL;
42 static char     *ldaphost = NULL;
43 static int      ldapport = 0;
44 #ifdef HAVE_CYRUS_SASL
45 static unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
46 static char *sasl_realm = NULL;
47 static char     *sasl_authc_id = NULL;
48 static char     *sasl_authz_id = NULL;
49 static char     *sasl_mech = NULL;
50 static char     *sasl_secprops = NULL;
51 #endif
52 static int      use_tls = 0;
53 static int      ldapadd, not, verbose, contoper, force;
54 static LDAP     *ld = NULL;
55
56 #define LDAPMOD_MAXLINE         4096
57
58 /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
59 #define T_VERSION_STR           "version"
60 #define T_REPLICA_STR           "replica"
61 #define T_DN_STR                "dn"
62 #define T_CHANGETYPESTR         "changetype"
63 #define T_ADDCTSTR              "add"
64 #define T_MODIFYCTSTR           "modify"
65 #define T_DELETECTSTR           "delete"
66 #define T_MODRDNCTSTR           "modrdn"
67 #define T_MODDNCTSTR            "moddn"
68 #define T_RENAMECTSTR           "rename"
69 #define T_MODOPADDSTR           "add"
70 #define T_MODOPREPLACESTR       "replace"
71 #define T_MODOPDELETESTR        "delete"
72 #define T_MODSEPSTR             "-"
73 #define T_NEWRDNSTR             "newrdn"
74 #define T_DELETEOLDRDNSTR       "deleteoldrdn"
75 #define T_NEWSUPSTR             "newsuperior"
76
77
78 static void usage LDAP_P(( const char *prog )) LDAP_GCCATTR((noreturn));
79 static int process_ldif_rec LDAP_P(( char *rbuf, int count ));
80 static void addmodifyop LDAP_P((
81         LDAPMod ***pmodsp, int modop,
82         const char *attr,
83         struct berval *value ));
84 static int domodify LDAP_P((
85         const char *dn,
86         LDAPMod **pmods,
87         int newentry ));
88 static int dodelete LDAP_P((
89         const char *dn ));
90 static int dorename LDAP_P((
91         const char *dn,
92         const char *newrdn,
93         const char *newsup,
94         int deleteoldrdn ));
95 static char *read_one_record LDAP_P(( FILE *fp ));
96
97 static void
98 usage( const char *prog )
99 {
100     fprintf( stderr,
101 "Add or modify entries from an LDAP server\n\n"
102 "usage: %s [options]\n"
103 "       The list of desired operations are read from stdin or from the file\n"
104 "       specified by \"-f file\".\n"
105 "Add or modify options:\n"
106 "  -a         add values (default%s)\n"
107 "  -c         continuous operation mode (do not stop on errors)\n"
108 "  -F         force all changes records to be used\n"
109 "  -S file    write skipped modifications to `file'\n"
110
111 "Common options:\n"
112 "  -d level   set LDAP debugging level to `level'\n"
113 "  -D binddn  bind DN\n"
114 "  -e [!]<ctrl>[=<ctrlparam>] general controls (! indicates criticality)\n"
115 "             [!]manageDSAit   (alternate form, see -M)\n"
116 #ifdef LDAP_CONTROL_NOOP
117 "             [!]noop\n"
118 #endif
119 "  -f file    read operations from `file'\n"
120 "  -h host    LDAP server\n"
121 "  -H URI     LDAP Uniform Resource Indentifier(s)\n"
122 "  -I         use SASL Interactive mode\n"
123 "  -k         use Kerberos authentication\n"
124 "  -K         like -k, but do only step 1 of the Kerberos bind\n"
125 "  -M         enable Manage DSA IT control (-MM to make critical)\n"
126 "  -n         show what would be done but don't actually update\n"
127 "  -O props   SASL security properties\n"
128 "  -p port    port on LDAP server\n"
129 "  -P version procotol version (default: 3)\n"
130 "  -Q         use SASL Quiet mode\n"
131 "  -R realm   SASL realm\n"
132 "  -U authcid SASL authentication identity\n"
133 "  -v         run in verbose mode (diagnostics to standard output)\n"
134 "  -w passwd  bind passwd (for simple authentication)\n"
135 "  -W         prompt for bind passwd\n"
136 "  -x         Simple authentication\n"
137 "  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
138 "  -y file    Read passwd from file\n"
139 "  -Y mech    SASL mechanism\n"
140 "  -Z         Start TLS request (-ZZ to require successful response)\n"
141              , prog, (strcmp( prog, "ldapadd" ) ? " is to replace" : "") );
142
143     exit( EXIT_FAILURE );
144 }
145
146
147 int
148 main( int argc, char **argv )
149 {
150     char                *infile, *rejfile, *rbuf, *start, *rejbuf = NULL;
151     FILE                *fp, *rejfp;
152         char            *matched_msg = NULL, *error_msg = NULL;
153         int             rc, i, authmethod, version, want_bindpw, debug, manageDSAit, referrals;
154         int count, len;
155         char    *pw_file = NULL;
156         char    *control, *cvalue;
157         int             crit;
158 #ifdef LDAP_CONTROL_NOOP
159         int noop=0;
160 #endif
161
162     prog = lutil_progname( "ldapmodify", argc, argv );
163
164     /* Print usage when no parameters */
165     if( argc < 2 ) usage( prog );
166
167         /* strncmp instead of strcmp since NT binaries carry .exe extension */
168     ldapadd = ( strncmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 );
169
170     infile = NULL;
171     rejfile = NULL;
172     not = verbose = want_bindpw = debug = manageDSAit = referrals = 0;
173     authmethod = -1;
174         version = -1;
175
176     while (( i = getopt( argc, argv, "acrf:E:F"
177                 "Cd:D:e:h:H:IkKMnO:p:P:QR:S:U:vw:WxX:y:Y:Z" )) != EOF )
178         {
179         switch( i ) {
180         /* Modify Options */
181         case 'a':       /* add */
182             ldapadd = 1;
183             break;
184         case 'c':       /* continuous operation */
185             contoper = 1;
186             break;
187         case 'E': /* modify controls */
188                 if( version == LDAP_VERSION2 ) {
189                         fprintf( stderr, "%s: -E incompatible with LDAPv%d\n",
190                                 prog, version );
191                         return EXIT_FAILURE;
192                 }
193
194                 /* should be extended to support comma separated list of
195                  *      [!]key[=value] parameters, e.g.  -E !foo,bar=567
196                  */
197
198                 crit = 0;
199                 cvalue = NULL;
200                 if( optarg[0] == '!' ) {
201                         crit = 1;
202                         optarg++;
203                 }
204
205                 control = strdup( optarg );
206                 if ( (cvalue = strchr( control, '=' )) != NULL ) {
207                         *cvalue++ = '\0';
208                 }
209                 fprintf( stderr, "Invalid modify control name: %s\n", control );
210                 usage(prog);
211                 return EXIT_FAILURE;
212         case 'f':       /* read from file */
213                 if( infile != NULL ) {
214                         fprintf( stderr, "%s: -f previously specified\n", prog );
215                         return EXIT_FAILURE;
216                 }
217             infile = strdup( optarg );
218             break;
219         case 'F':       /* force all changes records to be used */
220             force = 1;
221             break;
222
223         /* Common Options */
224         case 'C':
225                 referrals++;
226                 break;
227         case 'd':
228             debug |= atoi( optarg );
229             break;
230         case 'D':       /* bind DN */
231                 if( binddn != NULL ) {
232                         fprintf( stderr, "%s: -D previously specified\n", prog );
233                         return EXIT_FAILURE;
234                 }
235             binddn = strdup( optarg );
236             break;
237         case 'e': /* general controls */
238                 if( version == LDAP_VERSION2 ) {
239                         fprintf( stderr, "%s: -e incompatible with LDAPv%d\n",
240                                 prog, version );
241                         return EXIT_FAILURE;
242                 }
243
244                 /* should be extended to support comma separated list of
245                  *      [!]key[=value] parameters, e.g.  -e !foo,bar=567
246                  */
247
248                 crit = 0;
249                 cvalue = NULL;
250                 if( optarg[0] == '!' ) {
251                         crit = 1;
252                         optarg++;
253                 }
254
255                 control = strdup( optarg );
256                 if ( (cvalue = strchr( control, '=' )) != NULL ) {
257                         *cvalue++ = '\0';
258                 }
259
260                 if ( strcasecmp( control, "manageDSAit" ) == 0 ) {
261                         if( cvalue != NULL ) {
262                                 fprintf( stderr, "manageDSAit: no control value expected" );
263                                 usage(prog);
264                                 return EXIT_FAILURE;
265                         }
266
267                         manageDSAit = 1 + crit;
268                         free( control );
269                         break;
270                         
271 #ifdef LDAP_CONTROL_NOOP
272                 } else if ( strcasecmp( control, "noop" ) == 0 ) {
273                         if( cvalue != NULL ) {
274                                 fprintf( stderr, "noop: no control value expected" );
275                                 usage(prog);
276                                 return EXIT_FAILURE;
277                         }
278
279                         noop = 1 + crit;
280                         free( control );
281                         break;
282 #endif
283
284                 } else {
285                         fprintf( stderr, "Invalid general control name: %s\n", control );
286                         usage(prog);
287                         return EXIT_FAILURE;
288                 }
289         case 'h':       /* ldap host */
290                 if( ldapuri != NULL ) {
291                         fprintf( stderr, "%s: -h incompatible with -H\n", prog );
292                         return EXIT_FAILURE;
293                 }
294                 if( ldaphost != NULL ) {
295                         fprintf( stderr, "%s: -h previously specified\n", prog );
296                         return EXIT_FAILURE;
297                 }
298             ldaphost = strdup( optarg );
299             break;
300         case 'H':       /* ldap URI */
301                 if( ldaphost != NULL ) {
302                         fprintf( stderr, "%s: -H incompatible with -h\n", prog );
303                         return EXIT_FAILURE;
304                 }
305                 if( ldapport ) {
306                         fprintf( stderr, "%s: -H incompatible with -p\n", prog );
307                         return EXIT_FAILURE;
308                 }
309                 if( ldapuri != NULL ) {
310                         fprintf( stderr, "%s: -H previously specified\n", prog );
311                         return EXIT_FAILURE;
312                 }
313             ldapuri = strdup( optarg );
314             break;
315         case 'I':
316 #ifdef HAVE_CYRUS_SASL
317                 if( version == LDAP_VERSION2 ) {
318                         fprintf( stderr, "%s: -I incompatible with version %d\n",
319                                 prog, version );
320                         return EXIT_FAILURE;
321                 }
322                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
323                         fprintf( stderr, "%s: incompatible previous "
324                                 "authentication choice\n",
325                                 prog );
326                         return EXIT_FAILURE;
327                 }
328                 authmethod = LDAP_AUTH_SASL;
329                 version = LDAP_VERSION3;
330                 sasl_flags = LDAP_SASL_INTERACTIVE;
331                 break;
332 #else
333                 fprintf( stderr, "%s: was not compiled with SASL support\n",
334                         prog );
335                 return( EXIT_FAILURE );
336 #endif
337         case 'k':       /* kerberos bind */
338 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
339                 if( version > LDAP_VERSION2 ) {
340                         fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
341                                 prog, version );
342                         return EXIT_FAILURE;
343                 }
344
345                 if( authmethod != -1 ) {
346                         fprintf( stderr, "%s: -k incompatible with previous "
347                                 "authentication choice\n", prog );
348                         return EXIT_FAILURE;
349                 }
350                         
351                 authmethod = LDAP_AUTH_KRBV4;
352 #else
353                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
354                 return EXIT_FAILURE;
355 #endif
356             break;
357         case 'K':       /* kerberos bind, part one only */
358 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
359                 if( version > LDAP_VERSION2 ) {
360                         fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
361                                 prog, version );
362                         return EXIT_FAILURE;
363                 }
364                 if( authmethod != -1 ) {
365                         fprintf( stderr, "%s: incompatible with previous "
366                                 "authentication choice\n", prog );
367                         return EXIT_FAILURE;
368                 }
369
370                 authmethod = LDAP_AUTH_KRBV41;
371 #else
372                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
373                 return( EXIT_FAILURE );
374 #endif
375             break;
376         case 'M':
377                 /* enable Manage DSA IT */
378                 if( version == LDAP_VERSION2 ) {
379                         fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
380                                 prog, version );
381                         return EXIT_FAILURE;
382                 }
383                 manageDSAit++;
384                 version = LDAP_VERSION3;
385                 break;
386         case 'n':       /* print deletes, don't actually do them */
387             ++not;
388             break;
389         case 'O':
390 #ifdef HAVE_CYRUS_SASL
391                 if( sasl_secprops != NULL ) {
392                         fprintf( stderr, "%s: -O previously specified\n", prog );
393                         return EXIT_FAILURE;
394                 }
395                 if( version == LDAP_VERSION2 ) {
396                         fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
397                                 prog, version );
398                         return EXIT_FAILURE;
399                 }
400                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
401                         fprintf( stderr, "%s: incompatible previous "
402                                 "authentication choice\n", prog );
403                         return EXIT_FAILURE;
404                 }
405                 authmethod = LDAP_AUTH_SASL;
406                 version = LDAP_VERSION3;
407                 sasl_secprops = strdup( optarg );
408 #else
409                 fprintf( stderr, "%s: not compiled with SASL support\n",
410                         prog );
411                 return( EXIT_FAILURE );
412 #endif
413                 break;
414         case 'p':
415                 if( ldapport ) {
416                         fprintf( stderr, "%s: -p previously specified\n", prog );
417                         return EXIT_FAILURE;
418                 }
419             ldapport = atoi( optarg );
420             break;
421         case 'P':
422                 switch( atoi(optarg) ) {
423                 case 2:
424                         if( version == LDAP_VERSION3 ) {
425                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
426                                         prog, version );
427                                 return EXIT_FAILURE;
428                         }
429                         version = LDAP_VERSION2;
430                         break;
431                 case 3:
432                         if( version == LDAP_VERSION2 ) {
433                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
434                                         prog, version );
435                                 return EXIT_FAILURE;
436                         }
437                         version = LDAP_VERSION3;
438                         break;
439                 default:
440                         fprintf( stderr, "%s: protocol version should be 2 or 3\n",
441                                 prog );
442                         usage( prog );
443                         return( EXIT_FAILURE );
444                 } break;
445         case 'Q':
446 #ifdef HAVE_CYRUS_SASL
447                 if( version == LDAP_VERSION2 ) {
448                         fprintf( stderr, "%s: -Q incompatible with version %d\n",
449                                 prog, version );
450                         return EXIT_FAILURE;
451                 }
452                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
453                         fprintf( stderr, "%s: incompatible previous "
454                                 "authentication choice\n",
455                                 prog );
456                         return EXIT_FAILURE;
457                 }
458                 authmethod = LDAP_AUTH_SASL;
459                 version = LDAP_VERSION3;
460                 sasl_flags = LDAP_SASL_QUIET;
461                 break;
462 #else
463                 fprintf( stderr, "%s: not compiled with SASL support\n",
464                         prog );
465                 return( EXIT_FAILURE );
466 #endif
467         case 'r':       /* replace (obsolete) */
468                 break;
469
470         case 'R':
471 #ifdef HAVE_CYRUS_SASL
472                 if( sasl_realm != NULL ) {
473                         fprintf( stderr, "%s: -R previously specified\n", prog );
474                         return EXIT_FAILURE;
475                 }
476                 if( version == LDAP_VERSION2 ) {
477                         fprintf( stderr, "%s: -R incompatible with version %d\n",
478                                 prog, version );
479                         return EXIT_FAILURE;
480                 }
481                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
482                         fprintf( stderr, "%s: incompatible previous "
483                                 "authentication choice\n",
484                                 prog );
485                         return EXIT_FAILURE;
486                 }
487                 authmethod = LDAP_AUTH_SASL;
488                 version = LDAP_VERSION3;
489                 sasl_realm = strdup( optarg );
490 #else
491                 fprintf( stderr, "%s: not compiled with SASL support\n",
492                         prog );
493                 return( EXIT_FAILURE );
494 #endif
495                 break;
496         case 'S':       /* skipped modifications to file */
497                 if( rejfile != NULL ) {
498                         fprintf( stderr, "%s: -S previously specified\n", prog );
499                         return EXIT_FAILURE;
500                 }
501                 rejfile = strdup( optarg );
502                 break;
503         case 'U':
504 #ifdef HAVE_CYRUS_SASL
505                 if( sasl_authc_id != NULL ) {
506                         fprintf( stderr, "%s: -U previously specified\n", prog );
507                         return EXIT_FAILURE;
508                 }
509                 if( version == LDAP_VERSION2 ) {
510                         fprintf( stderr, "%s: -U incompatible with version %d\n",
511                                 prog, version );
512                         return EXIT_FAILURE;
513                 }
514                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
515                         fprintf( stderr, "%s: incompatible previous "
516                                 "authentication choice\n",
517                                 prog );
518                         return EXIT_FAILURE;
519                 }
520                 authmethod = LDAP_AUTH_SASL;
521                 version = LDAP_VERSION3;
522                 sasl_authc_id = strdup( optarg );
523 #else
524                 fprintf( stderr, "%s: not compiled with SASL support\n",
525                         prog );
526                 return( EXIT_FAILURE );
527 #endif
528                 break;
529         case 'v':       /* verbose mode */
530             verbose++;
531             break;
532         case 'w':       /* password */
533             passwd.bv_val = strdup( optarg );
534                 {
535                         char* p;
536
537                         for( p = optarg; *p != '\0'; p++ ) {
538                                 *p = '\0';
539                         }
540                 }
541                 passwd.bv_len = strlen( passwd.bv_val );
542             break;
543         case 'W':
544                 want_bindpw++;
545                 break;
546         case 'y':
547                 pw_file = optarg;
548                 break;
549         case 'Y':
550 #ifdef HAVE_CYRUS_SASL
551                 if( sasl_mech != NULL ) {
552                         fprintf( stderr, "%s: -Y previously specified\n", prog );
553                         return EXIT_FAILURE;
554                 }
555                 if( version == LDAP_VERSION2 ) {
556                         fprintf( stderr, "%s: -Y incompatible with version %d\n",
557                                 prog, version );
558                         return EXIT_FAILURE;
559                 }
560                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
561                         fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
562                         return EXIT_FAILURE;
563                 }
564                 authmethod = LDAP_AUTH_SASL;
565                 version = LDAP_VERSION3;
566                 sasl_mech = strdup( optarg );
567 #else
568                 fprintf( stderr, "%s: not compiled with SASL support\n",
569                         prog );
570                 return( EXIT_FAILURE );
571 #endif
572                 break;
573         case 'x':
574                 if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
575                         fprintf( stderr, "%s: incompatible with previous "
576                                 "authentication choice\n", prog );
577                         return EXIT_FAILURE;
578                 }
579                 authmethod = LDAP_AUTH_SIMPLE;
580                 break;
581         case 'X':
582 #ifdef HAVE_CYRUS_SASL
583                 if( sasl_authz_id != NULL ) {
584                         fprintf( stderr, "%s: -X previously specified\n", prog );
585                         return EXIT_FAILURE;
586                 }
587                 if( version == LDAP_VERSION2 ) {
588                         fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
589                                 prog, version );
590                         return EXIT_FAILURE;
591                 }
592                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
593                         fprintf( stderr, "%s: -X incompatible with "
594                                 "authentication choice\n", prog );
595                         return EXIT_FAILURE;
596                 }
597                 authmethod = LDAP_AUTH_SASL;
598                 version = LDAP_VERSION3;
599                 sasl_authz_id = strdup( optarg );
600 #else
601                 fprintf( stderr, "%s: not compiled with SASL support\n",
602                         prog );
603                 return( EXIT_FAILURE );
604 #endif
605                 break;
606         case 'Z':
607 #ifdef HAVE_TLS
608                 if( version == LDAP_VERSION2 ) {
609                         fprintf( stderr, "%s: -Z incompatible with version %d\n",
610                                 prog, version );
611                         return EXIT_FAILURE;
612                 }
613                 version = LDAP_VERSION3;
614                 use_tls++;
615 #else
616                 fprintf( stderr, "%s: not compiled with TLS support\n",
617                         prog );
618                 return( EXIT_FAILURE );
619 #endif
620                 break;
621         default:
622                 fprintf( stderr, "%s: unrecognized option -%c\n",
623                         prog, optopt );
624             usage( prog );
625         }
626     }
627
628         if (version == -1) {
629                 version = LDAP_VERSION3;
630         }
631         if (authmethod == -1 && version > LDAP_VERSION2) {
632 #ifdef HAVE_CYRUS_SASL
633                 authmethod = LDAP_AUTH_SASL;
634 #else
635                 authmethod = LDAP_AUTH_SIMPLE;
636 #endif
637         }
638
639         if ( argc != optind )
640         usage( prog );
641
642     if ( rejfile != NULL ) {
643         if (( rejfp = fopen( rejfile, "w" )) == NULL ) {
644             perror( rejfile );
645             return( EXIT_FAILURE );
646         }
647     } else {
648         rejfp = NULL;
649     }
650
651     if ( infile != NULL ) {
652         if (( fp = fopen( infile, "r" )) == NULL ) {
653             perror( infile );
654             return( EXIT_FAILURE );
655         }
656     } else {
657         fp = stdin;
658     }
659
660         if ( debug ) {
661                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
662                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
663                 }
664                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
665                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
666                 }
667                 ldif_debug = debug;
668         }
669
670 #ifdef SIGPIPE
671         (void) SIGNAL( SIGPIPE, SIG_IGN );
672 #endif
673
674     if ( !not ) {
675         if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
676                 if ( verbose ) {
677                         fprintf( stderr, "ldap_init( %s, %d )\n",
678                                 ldaphost != NULL ? ldaphost : "<DEFAULT>",
679                                 ldapport );
680                 }
681
682                 ld = ldap_init( ldaphost, ldapport );
683                 if( ld == NULL ) {
684                         perror("ldapmodify: ldap_init");
685                         return EXIT_FAILURE;
686                 }
687
688         } else {
689                 if ( verbose ) {
690                         fprintf( stderr, "ldap_initialize( %s )\n",
691                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
692                 }
693
694                 rc = ldap_initialize( &ld, ldapuri );
695                 if( rc != LDAP_SUCCESS ) {
696                         fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
697                                 rc, ldap_err2string(rc) );
698                         return EXIT_FAILURE;
699                 }
700         }
701
702         /* referrals */
703         if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
704                 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
705         {
706                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
707                         referrals ? "on" : "off" );
708                 return EXIT_FAILURE;
709         }
710
711
712         if (version == -1 ) {
713                 version = LDAP_VERSION3;
714         }
715
716         if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
717                 != LDAP_OPT_SUCCESS )
718         {
719                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
720                         version );
721                 return EXIT_FAILURE;
722         }
723
724         if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
725                 ldap_perror( ld, "ldap_start_tls" );
726                 if ( use_tls > 1 ) {
727                         return( EXIT_FAILURE );
728                 }
729         }
730
731         if ( pw_file || want_bindpw ) {
732                 if ( pw_file ) {
733                         rc = lutil_get_filed_password( pw_file, &passwd );
734                         if( rc ) return EXIT_FAILURE;
735                 } else {
736                         passwd.bv_val = getpassphrase( "Enter LDAP Password: " );
737                         passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
738                 }
739         }
740
741         if ( authmethod == LDAP_AUTH_SASL ) {
742 #ifdef HAVE_CYRUS_SASL
743                 void *defaults;
744
745                 if( sasl_secprops != NULL ) {
746                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
747                                 (void *) sasl_secprops );
748                         
749                         if( rc != LDAP_OPT_SUCCESS ) {
750                                 fprintf( stderr,
751                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
752                                         sasl_secprops );
753                                 return( EXIT_FAILURE );
754                         }
755                 }
756                 
757                 defaults = lutil_sasl_defaults( ld,
758                         sasl_mech,
759                         sasl_realm,
760                         sasl_authc_id,
761                         passwd.bv_val,
762                         sasl_authz_id );
763
764                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
765                         sasl_mech, NULL, NULL,
766                         sasl_flags, lutil_sasl_interact, defaults );
767
768                 if( rc != LDAP_SUCCESS ) {
769                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
770                         return( EXIT_FAILURE );
771                 }
772 #else
773                 fprintf( stderr, "%s: not compiled with SASL support\n",
774                         prog );
775                 return( EXIT_FAILURE );
776 #endif
777         }
778         else {
779                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
780                                 != LDAP_SUCCESS ) {
781                         ldap_perror( ld, "ldap_bind" );
782                         return( EXIT_FAILURE );
783                 }
784
785         }
786
787     }
788
789     rc = 0;
790
791         if ( manageDSAit
792 #ifdef LDAP_CONTROL_NOOP
793                 || noop
794 #endif
795         ) {
796                 int err, i = 0;
797                 LDAPControl c1, c2;
798                 LDAPControl *ctrls[3];
799
800                 if ( manageDSAit ) {
801                         ctrls[i++] = &c1;
802                         ctrls[i] = NULL;
803                         c1.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
804                         c1.ldctl_value.bv_val = NULL;
805                         c1.ldctl_value.bv_len = 0;
806                         c1.ldctl_iscritical = manageDSAit > 1;
807                 }
808
809 #ifdef LDAP_CONTROL_NOOP
810                 if ( noop ) {
811                         ctrls[i++] = &c2;
812                         ctrls[i] = NULL;
813
814                         c2.ldctl_oid = LDAP_CONTROL_NOOP;
815                         c2.ldctl_value.bv_val = NULL;
816                         c2.ldctl_value.bv_len = 0;
817                         c2.ldctl_iscritical = noop > 1;
818                 }
819 #endif
820                 
821                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
822
823                 if( err != LDAP_OPT_SUCCESS ) {
824                         fprintf( stderr, "Could not set %scontrols\n",
825                                 (c1.ldctl_iscritical || c2.ldctl_iscritical)
826                                 ? "critical " : "" );
827                         if ( c1.ldctl_iscritical && c2.ldctl_iscritical ) {
828                                 return EXIT_FAILURE;
829                         }
830                 }
831         }
832
833         count = 0;
834     while (( rc == 0 || contoper ) &&
835                 ( rbuf = read_one_record( fp )) != NULL ) {
836         count++;
837
838         start = rbuf;
839
840         if ( rejfp ) {
841                 len = strlen( rbuf );
842                 if (( rejbuf = (char *)malloc( len+1 )) == NULL ) {
843                         perror( "realloc" );
844                         exit( EXIT_FAILURE );
845                 }
846                 memcpy( rejbuf, rbuf, len+1 );
847         }
848
849     rc = process_ldif_rec( start, count );
850
851         if ( rc && rejfp ) {
852                 fprintf(rejfp, "# Error: %s (%d)", ldap_err2string(rc), rc);
853
854                 ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg);
855                 if ( matched_msg != NULL && *matched_msg != '\0' ) {
856                         fprintf( rejfp, ", matched DN: %s", matched_msg );
857                 }
858
859                 ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &error_msg);
860                 if ( error_msg != NULL && *error_msg != '\0' ) {
861                         fprintf( rejfp, ", additional info: %s", error_msg );
862                 }
863                 fprintf( rejfp, "\n%s\n", rejbuf );
864         }
865                 if (rejfp) 
866                         free( rejbuf );
867                 free( rbuf );
868     }
869
870     if ( !not ) {
871                 ldap_unbind( ld );
872     }
873
874     if ( rejfp != NULL ) {
875             fclose( rejfp );
876     }
877
878         return( rc );
879 }
880
881
882 static int
883 process_ldif_rec( char *rbuf, int count )
884 {
885     char        *line, *dn, *type, *newrdn, *newsup, *p;
886     int         rc, linenum, modop, replicaport;
887     int         expect_modop, expect_sep, expect_ct, expect_newrdn, expect_newsup;
888     int         expect_deleteoldrdn, deleteoldrdn;
889     int         saw_replica, use_record, new_entry, delete_entry, got_all;
890     LDAPMod     **pmods;
891         int version;
892         struct berval val;
893
894     new_entry = ldapadd;
895
896     rc = got_all = saw_replica = delete_entry = modop = expect_modop = 0;
897     expect_deleteoldrdn = expect_newrdn = expect_newsup = 0;
898         expect_sep = expect_ct = 0;
899     linenum = 0;
900         version = 0;
901     deleteoldrdn = 1;
902     use_record = force;
903     pmods = NULL;
904     dn = newrdn = newsup = NULL;
905
906     while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
907         ++linenum;
908
909         if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
910             expect_sep = 0;
911             expect_ct = 1;
912             continue;
913         }
914         
915         if ( ldif_parse_line( line, &type, &val.bv_val, &val.bv_len ) < 0 ) {
916             fprintf( stderr, "%s: invalid format (line %d) entry: \"%s\"\n",
917                     prog, linenum, dn == NULL ? "" : dn );
918             rc = LDAP_PARAM_ERROR;
919             break;
920         }
921
922         if ( dn == NULL ) {
923             if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
924                 ++saw_replica;
925                 if (( p = strchr( val.bv_val, ':' )) == NULL ) {
926                     replicaport = 0;
927                 } else {
928                     *p++ = '\0';
929                     replicaport = atoi( p );
930                 }
931                 if ( ldaphost != NULL && strcasecmp( val.bv_val, ldaphost ) == 0 &&
932                         replicaport == ldapport ) {
933                     use_record = 1;
934                 }
935             } else if ( count == 1 && linenum == 1 && 
936                         strcasecmp( type, T_VERSION_STR ) == 0 )
937                 {
938                         if( val.bv_len == 0 || atoi(val.bv_val) != 1 ) {
939                         fprintf( stderr, "%s: invalid version %s, line %d (ignored)\n",
940                                 prog, val.bv_val == NULL ? "(null)" : val.bv_val, linenum );
941                         }
942                         version++;
943
944             } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
945                 if (( dn = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
946                     perror( "strdup" );
947                     exit( EXIT_FAILURE );
948                 }
949                 expect_ct = 1;
950             }
951             goto end_line;      /* skip all lines until we see "dn:" */
952         }
953
954         if ( expect_ct ) {
955             expect_ct = 0;
956             if ( !use_record && saw_replica ) {
957                 printf( "%s: skipping change record for entry: %s\n"
958                         "\t(LDAP host/port does not match replica: lines)\n",
959                         prog, dn );
960                 free( dn );
961                 ber_memfree( type );
962                 ber_memfree( val.bv_val );
963                 return( 0 );
964             }
965
966             if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
967 #ifdef LIBERAL_CHANGETYPE_MODOP
968                 /* trim trailing spaces (and log warning ...) */
969
970                 int icnt;
971                 for ( icnt = val.bv_len; --icnt > 0; ) {
972                     if ( !isspace( (unsigned char) val.bv_val[icnt] ) ) {
973                         break;
974                     }
975                 }
976
977                 if ( ++icnt != val.bv_len ) {
978                     fprintf( stderr, "%s: illegal trailing space after \"%s: %s\" trimmed (line %d of entry \"%s\")\n",
979                             prog, T_CHANGETYPESTR, val.bv_val, linenum, dn );
980                     val.bv_val[icnt] = '\0';
981                 }
982 #endif /* LIBERAL_CHANGETYPE_MODOP */
983
984                 if ( strcasecmp( val.bv_val, T_MODIFYCTSTR ) == 0 ) {
985                         new_entry = 0;
986                         expect_modop = 1;
987                 } else if ( strcasecmp( val.bv_val, T_ADDCTSTR ) == 0 ) {
988                         new_entry = 1;
989                 } else if ( strcasecmp( val.bv_val, T_MODRDNCTSTR ) == 0
990                         || strcasecmp( val.bv_val, T_MODDNCTSTR ) == 0
991                         || strcasecmp( val.bv_val, T_RENAMECTSTR ) == 0)
992                 {
993                     expect_newrdn = 1;
994                 } else if ( strcasecmp( val.bv_val, T_DELETECTSTR ) == 0 ) {
995                     got_all = delete_entry = 1;
996                 } else {
997                     fprintf( stderr,
998                             "%s:  unknown %s \"%s\" (line %d of entry \"%s\")\n",
999                             prog, T_CHANGETYPESTR, val.bv_val, linenum, dn );
1000                     rc = LDAP_PARAM_ERROR;
1001                 }
1002                 goto end_line;
1003             } else if ( ldapadd ) {             /*  missing changetype => add */
1004                 new_entry = 1;
1005                 modop = LDAP_MOD_ADD;
1006             } else {
1007                 expect_modop = 1;       /* missing changetype => modify */
1008             }
1009         }
1010
1011         if ( expect_modop ) {
1012 #ifdef LIBERAL_CHANGETYPE_MODOP
1013             /* trim trailing spaces (and log warning ...) */
1014             
1015             int icnt;
1016             for ( icnt = val.bv_len; --icnt > 0; ) {
1017                 if ( !isspace( (unsigned char) val.bv_val[icnt] ) ) {
1018                     break;
1019                 }
1020             }
1021             
1022             if ( ++icnt != val.bv_len ) {
1023                 fprintf( stderr, "%s: illegal trailing space after \"%s: %s\" trimmed (line %d of entry \"%s\")\n",
1024                         prog, type, val.bv_val, linenum, dn );
1025                 val.bv_val[icnt] = '\0';
1026             }
1027 #endif /* LIBERAL_CHANGETYPE_MODOP */
1028
1029             expect_modop = 0;
1030             expect_sep = 1;
1031             if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
1032                 modop = LDAP_MOD_ADD;
1033                 goto end_line;
1034             } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
1035                 modop = LDAP_MOD_REPLACE;
1036                 addmodifyop( &pmods, modop, val.bv_val, NULL );
1037                 goto end_line;
1038             } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
1039                 modop = LDAP_MOD_DELETE;
1040                 addmodifyop( &pmods, modop, val.bv_val, NULL );
1041                 goto end_line;
1042             } else {    /* no modify op:  use default */
1043                 modop = ldapadd ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
1044             }
1045         }
1046
1047         if ( expect_newrdn ) {
1048             if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
1049                         if (( newrdn = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
1050                     perror( "strdup" );
1051                     exit( EXIT_FAILURE );
1052                 }
1053                 expect_deleteoldrdn = 1;
1054                 expect_newrdn = 0;
1055             } else {
1056                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1057                         prog, T_NEWRDNSTR, type, linenum, dn );
1058                 rc = LDAP_PARAM_ERROR;
1059             }
1060         } else if ( expect_deleteoldrdn ) {
1061             if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
1062                 deleteoldrdn = ( *val.bv_val == '0' ) ? 0 : 1;
1063                 expect_deleteoldrdn = 0;
1064                 expect_newsup = 1;
1065                 got_all = 1;
1066             } else {
1067                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1068                         prog, T_DELETEOLDRDNSTR, type, linenum, dn );
1069                 rc = LDAP_PARAM_ERROR;
1070             }
1071         } else if ( expect_newsup ) {
1072             if ( strcasecmp( type, T_NEWSUPSTR ) == 0 ) {
1073                 if (( newsup = strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
1074                     perror( "strdup" );
1075                     exit( EXIT_FAILURE );
1076                 }
1077                 expect_newsup = 0;
1078             } else {
1079                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1080                         prog, T_NEWSUPSTR, type, linenum, dn );
1081                 rc = LDAP_PARAM_ERROR;
1082             }
1083         } else if ( got_all ) {
1084             fprintf( stderr,
1085                     "%s: extra lines at end (line %d of entry \"%s\")\n",
1086                     prog, linenum, dn );
1087             rc = LDAP_PARAM_ERROR;
1088         } else {
1089                 addmodifyop( &pmods, modop, type, val.bv_val == NULL ? NULL : &val );
1090         }
1091
1092 end_line:
1093         ber_memfree( type );
1094         ber_memfree( val.bv_val );
1095     }
1096
1097         if( linenum == 0 ) {
1098                 return 0;
1099         }
1100
1101         if( version && linenum == 1 ) {
1102                 return 0;
1103         }
1104
1105     if ( rc == 0 ) {
1106         if ( delete_entry ) {
1107             rc = dodelete( dn );
1108         } else if ( newrdn != NULL ) {
1109             rc = dorename( dn, newrdn, newsup, deleteoldrdn );
1110         } else {
1111             rc = domodify( dn, pmods, new_entry );
1112         }
1113
1114         if ( rc == LDAP_SUCCESS ) {
1115             rc = 0;
1116         }
1117     }
1118
1119     if ( dn != NULL ) {
1120         free( dn );
1121     }
1122     if ( newrdn != NULL ) {
1123         free( newrdn );
1124     }
1125     if ( pmods != NULL ) {
1126         ldap_mods_free( pmods, 1 );
1127     }
1128
1129     return( rc );
1130 }
1131
1132
1133 static void
1134 addmodifyop(
1135         LDAPMod ***pmodsp,
1136         int modop,
1137         const char *attr,
1138         struct berval *val )
1139 {
1140         LDAPMod         **pmods;
1141         int                     i, j;
1142
1143         pmods = *pmodsp;
1144         modop |= LDAP_MOD_BVALUES;
1145
1146         i = 0;
1147         if ( pmods != NULL ) {
1148                 for ( ; pmods[ i ] != NULL; ++i ) {
1149                         if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
1150                                 pmods[ i ]->mod_op == modop )
1151                         {
1152                                 break;
1153                         }
1154                 }
1155         }
1156
1157         if ( pmods == NULL || pmods[ i ] == NULL ) {
1158                 if (( pmods = (LDAPMod **)ber_memrealloc( pmods, (i + 2) *
1159                         sizeof( LDAPMod * ))) == NULL )
1160                 {
1161                         perror( "realloc" );
1162                         exit( EXIT_FAILURE );
1163                 }
1164
1165                 *pmodsp = pmods;
1166                 pmods[ i + 1 ] = NULL;
1167
1168                 pmods[ i ] = (LDAPMod *)ber_memcalloc( 1, sizeof( LDAPMod ));
1169                 if ( pmods[ i ] == NULL ) {
1170                         perror( "calloc" );
1171                         exit( EXIT_FAILURE );
1172                 }
1173
1174                 pmods[ i ]->mod_op = modop;
1175                 pmods[ i ]->mod_type = ber_strdup( attr );
1176                 if ( pmods[ i ]->mod_type == NULL ) {
1177                         perror( "strdup" );
1178                         exit( EXIT_FAILURE );
1179                 }
1180         }
1181
1182         if ( val != NULL ) {
1183                 j = 0;
1184                 if ( pmods[ i ]->mod_bvalues != NULL ) {
1185                         for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
1186                                 /* Empty */;
1187                         }
1188                 }
1189
1190                 pmods[ i ]->mod_bvalues = (struct berval **) ber_memrealloc(
1191                         pmods[ i ]->mod_bvalues, (j + 2) * sizeof( struct berval * ));
1192                 if ( pmods[ i ]->mod_bvalues == NULL ) {
1193                         perror( "ber_realloc" );
1194                         exit( EXIT_FAILURE );
1195                 }
1196
1197                 pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
1198                 pmods[ i ]->mod_bvalues[ j ] = ber_bvdup( val );
1199                 if ( pmods[ i ]->mod_bvalues[ j ] == NULL ) {
1200                         perror( "ber_bvdup" );
1201                         exit( EXIT_FAILURE );
1202                 }
1203         }
1204 }
1205
1206
1207 static int
1208 domodify(
1209         const char *dn,
1210         LDAPMod **pmods,
1211         int newentry )
1212 {
1213     int                 i, j, k, notascii, op;
1214     struct berval       *bvp;
1215
1216     if ( pmods == NULL ) {
1217         fprintf( stderr, "%s: no attributes to change or add (entry=\"%s\")\n",
1218                 prog, dn );
1219         return( LDAP_PARAM_ERROR );
1220     } 
1221
1222     for ( i = 0; pmods[ i ] != NULL; ++i ) {
1223         op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
1224         if( op == LDAP_MOD_ADD && ( pmods[i]->mod_bvalues == NULL )) {
1225                 fprintf( stderr,
1226                         "%s: attribute \"%s\" has no values (entry=\"%s\")\n",
1227                         prog, pmods[i]->mod_type, dn );
1228                 return LDAP_PARAM_ERROR;
1229         }
1230     }
1231
1232     if ( verbose ) {
1233         for ( i = 0; pmods[ i ] != NULL; ++i ) {
1234             op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
1235             printf( "%s %s:\n", op == LDAP_MOD_REPLACE ?
1236                     "replace" : op == LDAP_MOD_ADD ?
1237                     "add" : "delete", pmods[ i ]->mod_type );
1238             if ( pmods[ i ]->mod_bvalues != NULL ) {
1239                 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
1240                     bvp = pmods[ i ]->mod_bvalues[ j ];
1241                     notascii = 0;
1242                     for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
1243                         if ( !isascii( bvp->bv_val[ k ] )) {
1244                             notascii = 1;
1245                             break;
1246                         }
1247                     }
1248                     if ( notascii ) {
1249                         printf( "\tNOT ASCII (%ld bytes)\n", bvp->bv_len );
1250                     } else {
1251                         printf( "\t%s\n", bvp->bv_val );
1252                     }
1253                 }
1254             }
1255         }
1256     }
1257
1258     if ( newentry ) {
1259         printf( "%sadding new entry \"%s\"\n", not ? "!" : "", dn );
1260     } else {
1261         printf( "%smodifying entry \"%s\"\n", not ? "!" : "", dn );
1262     }
1263
1264     if ( !not ) {
1265         if ( newentry ) {
1266             i = ldap_add_s( ld, dn, pmods );
1267         } else {
1268             i = ldap_modify_s( ld, dn, pmods );
1269         }
1270         if ( i != LDAP_SUCCESS ) {
1271                 /* print error message about failed update including DN */
1272                 fprintf( stderr, "%s: update failed: %s\n", prog, dn );
1273                 ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
1274         } else if ( verbose ) {
1275             printf( "modify complete\n" );
1276         }
1277     } else {
1278         i = LDAP_SUCCESS;
1279     }
1280
1281     putchar( '\n' );
1282
1283     return( i );
1284 }
1285
1286
1287 static int
1288 dodelete(
1289         const char *dn )
1290 {
1291     int rc;
1292
1293     printf( "%sdeleting entry \"%s\"\n", not ? "!" : "", dn );
1294     if ( !not ) {
1295         if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
1296                 fprintf( stderr, "%s: delete failed: %s\n", prog, dn );
1297                 ldap_perror( ld, "ldap_delete" );
1298         } else if ( verbose ) {
1299             printf( "delete complete" );
1300         }
1301     } else {
1302         rc = LDAP_SUCCESS;
1303     }
1304
1305     putchar( '\n' );
1306
1307     return( rc );
1308 }
1309
1310
1311 static int
1312 dorename(
1313         const char *dn,
1314         const char *newrdn,
1315         const char* newsup,
1316         int deleteoldrdn )
1317 {
1318     int rc;
1319
1320
1321     printf( "%smodifying rdn of entry \"%s\"\n", not ? "!" : "", dn );
1322     if ( verbose ) {
1323         printf( "\tnew RDN: \"%s\" (%skeep existing values)\n",
1324                 newrdn, deleteoldrdn ? "do not " : "" );
1325     }
1326     if ( !not ) {
1327         if (( rc = ldap_rename2_s( ld, dn, newrdn, newsup, deleteoldrdn ))
1328                 != LDAP_SUCCESS )
1329         {
1330                 fprintf( stderr, "%s: rename failed: %s\n", prog, dn );
1331                 ldap_perror( ld, "ldap_modrdn" );
1332         } else {
1333             printf( "modrdn completed\n" );
1334         }
1335     } else {
1336         rc = LDAP_SUCCESS;
1337     }
1338
1339     putchar( '\n' );
1340
1341     return( rc );
1342 }
1343
1344
1345 static char *
1346 read_one_record( FILE *fp )
1347 {
1348     char        *buf, line[ LDAPMOD_MAXLINE ];
1349     int         lcur, lmax;
1350
1351     lcur = lmax = 0;
1352     buf = NULL;
1353
1354     while ( fgets( line, sizeof(line), fp ) != NULL ) {
1355         int len = strlen( line );
1356
1357                 if( len < 2 || ( len == 2 && *line == '\r' )) {
1358                         if( buf == NULL ) {
1359                                 continue;
1360                         } else {
1361                                 break;
1362                         }
1363                 }
1364
1365                 if ( lcur + len + 1 > lmax ) {
1366                         lmax = LDAPMOD_MAXLINE
1367                                 * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
1368
1369                         if (( buf = (char *)realloc( buf, lmax )) == NULL ) {
1370                                 perror( "realloc" );
1371                                 exit( EXIT_FAILURE );
1372                         }
1373                 }
1374
1375                 strcpy( buf + lcur, line );
1376                 lcur += len;
1377     }
1378
1379     return( buf );
1380 }