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