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