]> git.sur5r.net Git - openldap/blob - clients/tools/ldapmodify.c
adf04033068e65d22a2fd0f4a77bd0bc1de5c7cb
[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 "             [!]authzid=<authzid> (\"dn:<dn>\" or \"u:<user>\")\n"
122 "             [!]manageDSAit   (alternate form, see -M)\n"
123 "             [!]noop\n"
124 "  -f file    read operations from `file'\n"
125 "  -h host    LDAP server\n"
126 "  -H URI     LDAP Uniform Resource Indentifier(s)\n"
127 "  -I         use SASL Interactive mode\n"
128 "  -k         use Kerberos authentication\n"
129 "  -K         like -k, but do only step 1 of the Kerberos bind\n"
130 "  -M         enable Manage DSA IT control (-MM to make critical)\n"
131 "  -n         show what would be done but don't actually update\n"
132 "  -O props   SASL security properties\n"
133 "  -p port    port on LDAP server\n"
134 "  -P version procotol version (default: 3)\n"
135 "  -Q         use SASL Quiet mode\n"
136 "  -R realm   SASL realm\n"
137 "  -U authcid SASL authentication identity\n"
138 "  -v         run in verbose mode (diagnostics to standard output)\n"
139 "  -w passwd  bind passwd (for simple authentication)\n"
140 "  -W         prompt for bind passwd\n"
141 "  -x         Simple authentication\n"
142 "  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
143 "  -y file    Read passwd from file\n"
144 "  -Y mech    SASL mechanism\n"
145 "  -Z         Start TLS request (-ZZ to require successful response)\n"
146              , prog, (strcmp( prog, "ldapadd" ) ? " is to replace" : "") );
147
148     exit( EXIT_FAILURE );
149 }
150
151
152 int
153 main( int argc, char **argv )
154 {
155     char                *infile, *rejfile, *rbuf, *start, *rejbuf = NULL;
156     FILE                *fp, *rejfp;
157         char            *matched_msg = NULL, *error_msg = NULL;
158         int             rc, retval, i, authmethod, version, want_bindpw;
159         int             debug, manageDSAit, noop, referrals;
160         int count, len;
161         char    *pw_file = NULL;
162         char    *control, *cvalue;
163         char    *authzid = NULL;
164         int             crit;
165
166     prog = lutil_progname( "ldapmodify", argc, argv );
167
168     /* Print usage when no parameters */
169     if( argc < 2 ) usage( prog );
170
171         /* strncmp instead of strcmp since NT binaries carry .exe extension */
172     ldapadd = ( strncmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 );
173
174     infile = NULL;
175     rejfile = NULL;
176     not = verbose = want_bindpw = debug = manageDSAit = noop = referrals = 0;
177     authmethod = -1;
178         version = -1;
179
180     while (( i = getopt( argc, argv, "acrf:E:F"
181                 "Cd:D:e:h:H:IkKMnO:p:P:QR:S:U:vw:WxX:y:Y:Z" )) != EOF )
182         {
183         switch( i ) {
184         /* Modify Options */
185         case 'a':       /* add */
186             ldapadd = 1;
187             break;
188         case 'c':       /* continuous operation */
189             contoper = 1;
190             break;
191         case 'E': /* modify controls */
192                 if( version == LDAP_VERSION2 ) {
193                         fprintf( stderr, "%s: -E incompatible with LDAPv%d\n",
194                                 prog, version );
195                         return EXIT_FAILURE;
196                 }
197
198                 /* should be extended to support comma separated list of
199                  *      [!]key[=value] parameters, e.g.  -E !foo,bar=567
200                  */
201
202                 crit = 0;
203                 cvalue = NULL;
204                 if( optarg[0] == '!' ) {
205                         crit = 1;
206                         optarg++;
207                 }
208
209                 control = ber_strdup( optarg );
210                 if ( (cvalue = strchr( control, '=' )) != NULL ) {
211                         *cvalue++ = '\0';
212                 }
213                 fprintf( stderr, "Invalid modify control name: %s\n", control );
214                 usage(prog);
215                 return EXIT_FAILURE;
216         case 'f':       /* read from file */
217                 if( infile != NULL ) {
218                         fprintf( stderr, "%s: -f previously specified\n", prog );
219                         return EXIT_FAILURE;
220                 }
221             infile = ber_strdup( optarg );
222             break;
223         case 'F':       /* force all changes records to be used */
224             force = 1;
225             break;
226
227         /* Common Options */
228         case 'C':
229                 referrals++;
230                 break;
231         case 'd':
232             debug |= atoi( optarg );
233             break;
234         case 'D':       /* bind DN */
235                 if( binddn != NULL ) {
236                         fprintf( stderr, "%s: -D previously specified\n", prog );
237                         return EXIT_FAILURE;
238                 }
239             binddn = ber_strdup( optarg );
240             break;
241         case 'e': /* general controls */
242                 if( version == LDAP_VERSION2 ) {
243                         fprintf( stderr, "%s: -e incompatible with LDAPv%d\n",
244                                 prog, version );
245                         return EXIT_FAILURE;
246                 }
247
248                 /* should be extended to support comma separated list of
249                  *      [!]key[=value] parameters, e.g.  -e !foo,bar=567
250                  */
251
252                 crit = 0;
253                 cvalue = NULL;
254                 if( optarg[0] == '!' ) {
255                         crit = 1;
256                         optarg++;
257                 }
258
259                 control = ber_strdup( optarg );
260                 if ( (cvalue = strchr( control, '=' )) != NULL ) {
261                         *cvalue++ = '\0';
262                 }
263
264                 if ( strcasecmp( control, "manageDSAit" ) == 0 ) {
265                         if( manageDSAit ) {
266                                 fprintf( stderr, "manageDSAit control previously specified");
267                                 return EXIT_FAILURE;
268                         }
269                         if( cvalue != NULL ) {
270                                 fprintf( stderr, "manageDSAit: no control value expected" );
271                                 usage(prog);
272                                 return EXIT_FAILURE;
273                         }
274
275                         manageDSAit = 1 + crit;
276                         break;
277                         
278                 } else if ( strcasecmp( control, "noop" ) == 0 ) {
279                         if( noop ) {
280                                 fprintf( stderr, "noop control previously specified");
281                                 return EXIT_FAILURE;
282                         }
283                         if( cvalue != NULL ) {
284                                 fprintf( stderr, "noop: no control value expected" );
285                                 usage(prog);
286                                 return EXIT_FAILURE;
287                         }
288
289                         noop = 1 + crit;
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 ( authzid || manageDSAit || noop ) {
800                 int err, crit=0, i=0;
801                 LDAPControl c[3];
802                 LDAPControl *ctrls[4];
803
804                 if ( authzid ) {
805                         c[i].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
806                         c[i].ldctl_value.bv_val = authzid;
807                         c[i].ldctl_value.bv_len = strlen( authzid );
808                         c[i].ldctl_iscritical = 1;
809
810                         if( c[i].ldctl_iscritical ) crit++;
811                         ctrls[i] = &c[i];
812                         ctrls[++i] = NULL;
813                 }
814
815                 if ( manageDSAit ) {
816                         c[i].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
817                         c[i].ldctl_value.bv_val = NULL;
818                         c[i].ldctl_value.bv_len = 0;
819                         c[i].ldctl_iscritical = manageDSAit > 1;
820
821                         if( c[i].ldctl_iscritical ) crit++;
822                         ctrls[i] = &c[i];
823                         ctrls[++i] = NULL;
824                 }
825
826                 if ( noop ) {
827                         c[i].ldctl_oid = LDAP_CONTROL_NOOP;
828                         c[i].ldctl_value.bv_val = NULL;
829                         c[i].ldctl_value.bv_len = 0;
830                         c[i].ldctl_iscritical = noop > 1;
831
832                         if( c[i].ldctl_iscritical ) crit++;
833                         ctrls[i] = &c[i];
834                         ctrls[++i] = NULL;
835                 }
836         
837                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
838
839                 if( err != LDAP_OPT_SUCCESS ) {
840                         fprintf( stderr, "Could not set %scontrols\n",
841                                 crit ? "critical " : "" );
842                         if ( crit ) {
843                                 return EXIT_FAILURE;
844                         }
845                 }
846         }
847
848         count = 0;
849         retval = 0;
850     while (( rc == 0 || contoper ) &&
851                 ( rbuf = read_one_record( fp )) != NULL ) {
852         count++;
853
854         start = rbuf;
855
856         if ( rejfp ) {
857                 len = strlen( rbuf );
858                 if (( rejbuf = (char *)ber_memalloc( len+1 )) == NULL ) {
859                         perror( "malloc" );
860                         exit( EXIT_FAILURE );
861                 }
862                 memcpy( rejbuf, rbuf, len+1 );
863         }
864
865     rc = process_ldif_rec( start, count );
866
867         if ( rc )
868                 retval = rc;
869         if ( rc && rejfp ) {
870                 fprintf(rejfp, "# Error: %s (%d)", ldap_err2string(rc), rc);
871
872                 ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg);
873                 if ( matched_msg != NULL && *matched_msg != '\0' ) {
874                         fprintf( rejfp, ", matched DN: %s", matched_msg );
875                 }
876
877                 ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &error_msg);
878                 if ( error_msg != NULL && *error_msg != '\0' ) {
879                         fprintf( rejfp, ", additional info: %s", error_msg );
880                 }
881                 fprintf( rejfp, "\n%s\n", rejbuf );
882         }
883                 if (rejfp) 
884                         free( rejbuf );
885                 free( rbuf );
886     }
887
888     if ( !not ) {
889                 ldap_unbind( ld );
890     }
891
892     if ( rejfp != NULL ) {
893             fclose( rejfp );
894     }
895
896     return( retval );
897 }
898
899
900 static int
901 process_ldif_rec( char *rbuf, int count )
902 {
903     char        *line, *dn, *type, *newrdn, *newsup, *p;
904     int         rc, linenum, modop, replicaport;
905     int         expect_modop, expect_sep, expect_ct, expect_newrdn, expect_newsup;
906     int         expect_deleteoldrdn, deleteoldrdn;
907     int         saw_replica, use_record, new_entry, delete_entry, got_all;
908     LDAPMod     **pmods;
909         int version;
910         struct berval val;
911     LDAPControl **pctrls;
912
913     new_entry = ldapadd;
914
915     rc = got_all = saw_replica = delete_entry = modop = expect_modop = 0;
916     expect_deleteoldrdn = expect_newrdn = expect_newsup = 0;
917         expect_sep = expect_ct = 0;
918     linenum = 0;
919         version = 0;
920     deleteoldrdn = 1;
921     use_record = force;
922     pmods = NULL;
923     pctrls = NULL;
924     dn = newrdn = newsup = NULL;
925
926     while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
927         ++linenum;
928
929         if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
930             expect_sep = 0;
931             expect_ct = 1;
932             continue;
933         }
934         
935         if ( ldif_parse_line( line, &type, &val.bv_val, &val.bv_len ) < 0 ) {
936             fprintf( stderr, "%s: invalid format (line %d) entry: \"%s\"\n",
937                     prog, linenum, dn == NULL ? "" : dn );
938             rc = LDAP_PARAM_ERROR;
939             break;
940         }
941
942         if ( dn == NULL ) {
943             if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
944                 ++saw_replica;
945                 if (( p = strchr( val.bv_val, ':' )) == NULL ) {
946                     replicaport = 0;
947                 } else {
948                     *p++ = '\0';
949                     replicaport = atoi( p );
950                 }
951                 if ( ldaphost != NULL && strcasecmp( val.bv_val, ldaphost ) == 0 &&
952                         replicaport == ldapport ) {
953                     use_record = 1;
954                 }
955             } else if ( count == 1 && linenum == 1 && 
956                         strcasecmp( type, T_VERSION_STR ) == 0 )
957                 {
958                         if( val.bv_len == 0 || atoi(val.bv_val) != 1 ) {
959                         fprintf( stderr, "%s: invalid version %s, line %d (ignored)\n",
960                                 prog, val.bv_val == NULL ? "(null)" : val.bv_val, linenum );
961                         }
962                         version++;
963
964             } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
965                 if (( dn = ber_strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
966                     perror( "strdup" );
967                     exit( EXIT_FAILURE );
968                 }
969                 expect_ct = 1;
970             }
971             goto end_line;      /* skip all lines until we see "dn:" */
972         }
973
974         if ( expect_ct ) {
975         
976         /* Check for "control" tag after dn and before changetype. */
977         if (strcasecmp(type, T_CONTROL_STR) == 0) {
978             /* Parse and add it to the list of controls */
979             rc = parse_ldif_control( line, &pctrls );
980             if (rc != 0) {
981                         fprintf( stderr, "%s: Error processing %s line, line %d: %s\n",
982                                 prog, T_CONTROL_STR, linenum, ldap_err2string(rc) );
983             }
984             goto end_line;
985         }
986         
987             expect_ct = 0;
988             if ( !use_record && saw_replica ) {
989                 printf( "%s: skipping change record for entry: %s\n"
990                         "\t(LDAP host/port does not match replica: lines)\n",
991                         prog, dn );
992                 free( dn );
993                 ber_memfree( type );
994                 ber_memfree( val.bv_val );
995                 return( 0 );
996             }
997
998             if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
999 #ifdef LIBERAL_CHANGETYPE_MODOP
1000                 /* trim trailing spaces (and log warning ...) */
1001
1002                 int icnt;
1003                 for ( icnt = val.bv_len; --icnt > 0; ) {
1004                     if ( !isspace( (unsigned char) val.bv_val[icnt] ) ) {
1005                         break;
1006                     }
1007                 }
1008
1009                 if ( ++icnt != val.bv_len ) {
1010                     fprintf( stderr, "%s: illegal trailing space after \"%s: %s\" trimmed (line %d of entry \"%s\")\n",
1011                             prog, T_CHANGETYPESTR, val.bv_val, linenum, dn );
1012                     val.bv_val[icnt] = '\0';
1013                 }
1014 #endif /* LIBERAL_CHANGETYPE_MODOP */
1015
1016                 if ( strcasecmp( val.bv_val, T_MODIFYCTSTR ) == 0 ) {
1017                         new_entry = 0;
1018                         expect_modop = 1;
1019                 } else if ( strcasecmp( val.bv_val, T_ADDCTSTR ) == 0 ) {
1020                         new_entry = 1;
1021                 } else if ( strcasecmp( val.bv_val, T_MODRDNCTSTR ) == 0
1022                         || strcasecmp( val.bv_val, T_MODDNCTSTR ) == 0
1023                         || strcasecmp( val.bv_val, T_RENAMECTSTR ) == 0)
1024                 {
1025                     expect_newrdn = 1;
1026                 } else if ( strcasecmp( val.bv_val, T_DELETECTSTR ) == 0 ) {
1027                     got_all = delete_entry = 1;
1028                 } else {
1029                     fprintf( stderr,
1030                             "%s:  unknown %s \"%s\" (line %d of entry \"%s\")\n",
1031                             prog, T_CHANGETYPESTR, val.bv_val, linenum, dn );
1032                     rc = LDAP_PARAM_ERROR;
1033                 }
1034                 goto end_line;
1035             } else if ( ldapadd ) {             /*  missing changetype => add */
1036                 new_entry = 1;
1037                 modop = LDAP_MOD_ADD;
1038             } else {
1039                 expect_modop = 1;       /* missing changetype => modify */
1040             }
1041         }
1042
1043         if ( expect_modop ) {
1044 #ifdef LIBERAL_CHANGETYPE_MODOP
1045             /* trim trailing spaces (and log warning ...) */
1046             
1047             int icnt;
1048             for ( icnt = val.bv_len; --icnt > 0; ) {
1049                 if ( !isspace( (unsigned char) val.bv_val[icnt] ) ) {
1050                     break;
1051                 }
1052             }
1053             
1054             if ( ++icnt != val.bv_len ) {
1055                 fprintf( stderr, "%s: illegal trailing space after \"%s: %s\" trimmed (line %d of entry \"%s\")\n",
1056                         prog, type, val.bv_val, linenum, dn );
1057                 val.bv_val[icnt] = '\0';
1058             }
1059 #endif /* LIBERAL_CHANGETYPE_MODOP */
1060
1061             expect_modop = 0;
1062             expect_sep = 1;
1063             if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
1064                 modop = LDAP_MOD_ADD;
1065                 goto end_line;
1066             } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
1067                 modop = LDAP_MOD_REPLACE;
1068                 addmodifyop( &pmods, modop, val.bv_val, NULL );
1069                 goto end_line;
1070             } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
1071                 modop = LDAP_MOD_DELETE;
1072                 addmodifyop( &pmods, modop, val.bv_val, NULL );
1073                 goto end_line;
1074             } else {    /* no modify op:  use default */
1075                 modop = ldapadd ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
1076             }
1077         }
1078
1079         if ( expect_newrdn ) {
1080             if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
1081                         if (( newrdn = ber_strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
1082                     perror( "strdup" );
1083                     exit( EXIT_FAILURE );
1084                 }
1085                 expect_deleteoldrdn = 1;
1086                 expect_newrdn = 0;
1087             } else {
1088                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1089                         prog, T_NEWRDNSTR, type, linenum, dn );
1090                 rc = LDAP_PARAM_ERROR;
1091             }
1092         } else if ( expect_deleteoldrdn ) {
1093             if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
1094                 deleteoldrdn = ( *val.bv_val == '0' ) ? 0 : 1;
1095                 expect_deleteoldrdn = 0;
1096                 expect_newsup = 1;
1097                 got_all = 1;
1098             } else {
1099                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1100                         prog, T_DELETEOLDRDNSTR, type, linenum, dn );
1101                 rc = LDAP_PARAM_ERROR;
1102             }
1103         } else if ( expect_newsup ) {
1104             if ( strcasecmp( type, T_NEWSUPSTR ) == 0 ) {
1105                 if (( newsup = ber_strdup( val.bv_val ? val.bv_val : "" )) == NULL ) {
1106                     perror( "strdup" );
1107                     exit( EXIT_FAILURE );
1108                 }
1109                 expect_newsup = 0;
1110             } else {
1111                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
1112                         prog, T_NEWSUPSTR, type, linenum, dn );
1113                 rc = LDAP_PARAM_ERROR;
1114             }
1115         } else if ( got_all ) {
1116             fprintf( stderr,
1117                     "%s: extra lines at end (line %d of entry \"%s\")\n",
1118                     prog, linenum, dn );
1119             rc = LDAP_PARAM_ERROR;
1120         } else {
1121                 addmodifyop( &pmods, modop, type, val.bv_val == NULL ? NULL : &val );
1122         }
1123
1124 end_line:
1125         ber_memfree( type );
1126         ber_memfree( val.bv_val );
1127     }
1128
1129         if( linenum == 0 ) {
1130                 return 0;
1131         }
1132
1133         if( version && linenum == 1 ) {
1134                 return 0;
1135         }
1136
1137     /* If default controls are set (as with -M option) and controls are
1138        specified in the LDIF file, we must add the default controls to
1139        the list of controls sent with the ldap operation.
1140     */
1141     if ( rc == 0 ) {
1142         if (pctrls) {
1143             LDAPControl **defctrls = NULL;   /* Default server controls */
1144             LDAPControl **newctrls = NULL;
1145             ldap_get_option(ld, LDAP_OPT_SERVER_CONTROLS, &defctrls);
1146             if (defctrls) {
1147                 int npc=0;                  /* Number of LDIF controls */
1148                 int ndefc=0;                /* Number of default controls */
1149                 while (pctrls[npc])         /* Count LDIF controls */
1150                     npc++; 
1151                 while (defctrls[ndefc])     /* Count default controls */
1152                     ndefc++;
1153                 newctrls = ber_memrealloc(pctrls, (npc+ndefc+1)*sizeof(LDAPControl*));
1154                 if (newctrls == NULL)
1155                     rc = LDAP_NO_MEMORY;
1156                 else {
1157                     int i;
1158                     pctrls = newctrls;
1159                     for (i=npc; i<npc+ndefc; i++) {
1160                         pctrls[i] = ldap_control_dup(defctrls[i-npc]);
1161                         if (pctrls[i] == NULL) {
1162                             rc = LDAP_NO_MEMORY;
1163                             break;
1164                         }
1165                     }
1166                     pctrls[npc+ndefc] = NULL;
1167                     ldap_controls_free(defctrls);  /* Must be freed by library */
1168                 }
1169             }
1170         }
1171     }
1172
1173
1174     if ( rc == 0 ) {
1175         if ( delete_entry ) {
1176             rc = dodelete( dn, pctrls );
1177         } else if ( newrdn != NULL ) {
1178             rc = dorename( dn, newrdn, newsup, deleteoldrdn, pctrls );
1179         } else {
1180             rc = domodify( dn, pmods, pctrls, new_entry );
1181         }
1182
1183         if ( rc == LDAP_SUCCESS ) {
1184             rc = 0;
1185         }
1186     }
1187
1188     if ( dn != NULL ) {
1189         free( dn );
1190     }
1191     if ( newrdn != NULL ) {
1192         free( newrdn );
1193     }
1194     if ( pmods != NULL ) {
1195         ldap_mods_free( pmods, 1 );
1196     }
1197
1198     if (pctrls != NULL) {
1199         ldap_controls_free( pctrls );
1200     }
1201
1202     return( rc );
1203 }
1204
1205 /* Parse an LDIF control line of the form
1206       control:  oid  [true/false]  [: value]              or
1207       control:  oid  [true/false]  [:: base64-value]      or
1208       control:  oid  [true/false]  [:< url]
1209    The control is added to the list of controls in *ppctrls.
1210 */      
1211 static int
1212 parse_ldif_control( char *line, 
1213                     LDAPControl ***ppctrls )
1214 {
1215     char *oid = NULL;
1216     int criticality = 0;   /* Default is false if not present */
1217     char *type=NULL;
1218     char *val = NULL;
1219     ber_len_t value_len = 0;
1220     int i, rc=0;
1221     char *s, *oidStart, *pcolon;
1222     LDAPControl *newctrl = NULL;
1223     LDAPControl **pctrls = NULL;
1224
1225     if (ppctrls) {
1226         pctrls = *ppctrls;
1227     }
1228     s = line + strlen(T_CONTROL_STR);  /* Skip over "control" */
1229     pcolon = s;                        /* Save this position for later */
1230     if (*s++ != ':')                   /* Make sure colon follows */
1231         return ( LDAP_PARAM_ERROR );
1232     while (*s && isspace(*s))  s++;    /* Skip white space before OID */
1233
1234     /* OID should come next. Validate and extract it. */
1235     if (*s == 0)
1236         return ( LDAP_PARAM_ERROR );
1237     oidStart = s;
1238     while (isdigit(*s) || *s == '.')  s++;    /* OID should be digits or . */
1239     if (s == oidStart) 
1240         return ( LDAP_PARAM_ERROR );   /* OID was not present */
1241     if (*s) {                          /* End of OID should be space or NULL */
1242         if (!isspace(*s))
1243             return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */
1244         *s++ = 0;                    /* Replace space with null to terminate */
1245     }
1246
1247     
1248     oid = ber_strdup(oidStart);
1249     if (oid == NULL)
1250         return ( LDAP_NO_MEMORY );
1251
1252     /* Optional Criticality field is next. */
1253     while (*s && isspace(*s))  s++;   /* Skip white space before criticality */
1254     if (strncasecmp(s, "true", 4) == 0) {
1255         criticality = 1;
1256         s += 4;
1257     } 
1258     else if (strncasecmp(s, "false", 5) == 0) {
1259         criticality = 0;
1260         s += 5;
1261     }
1262
1263     /* Optional value field is next */
1264     while (*s && isspace(*s))  s++;    /* Skip white space before value */
1265     if (*s) {
1266         if (*s != ':') {           /* If value is present, must start with : */
1267             rc = LDAP_PARAM_ERROR;
1268             goto cleanup;
1269         }
1270
1271         /* Shift value down over OID and criticality so it's in the form
1272              control: value
1273              control:: base64-value
1274              control:< url
1275            Then we can use ldif_parse_line to extract and decode the value
1276         */
1277         while ( (*pcolon++ = *s++) != 0)     /* Shift value */
1278             ;
1279         rc = ldif_parse_line(line, &type, &val, &value_len);
1280         if (type)  ber_memfree(type);   /* Don't need this field*/
1281         if (rc < 0) {
1282             rc = LDAP_PARAM_ERROR;
1283             goto cleanup;
1284         }
1285     }
1286
1287     /* Create a new LDAPControl structure. */
1288     newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl));
1289     if ( newctrl == NULL ) {
1290         rc = LDAP_NO_MEMORY;
1291         goto cleanup;
1292     }
1293     newctrl->ldctl_oid = oid;
1294     oid = NULL;
1295     newctrl->ldctl_iscritical = criticality;
1296     newctrl->ldctl_value.bv_len = value_len;
1297     newctrl->ldctl_value.bv_val = val;
1298     val = NULL;
1299
1300     /* Add the new control to the passed-in list of controls. */
1301     i = 0;
1302     if (pctrls) {
1303         while ( pctrls[i] )      /* Count the # of controls passed in */
1304             i++;
1305     }
1306     /* Allocate 1 more slot for the new control and 1 for the NULL. */
1307     pctrls = (LDAPControl **)ber_memrealloc(pctrls, (i+2)*(sizeof(LDAPControl *)));
1308     if (pctrls == NULL) {
1309         rc = LDAP_NO_MEMORY;
1310         goto cleanup;
1311     }
1312     pctrls[i] = newctrl;
1313     newctrl = NULL;
1314     pctrls[i+1] = NULL;
1315     *ppctrls = pctrls;
1316
1317 cleanup:
1318     if (newctrl) {
1319         if (newctrl->ldctl_oid)
1320             ber_memfree(newctrl->ldctl_oid);
1321         if (newctrl->ldctl_value.bv_val)
1322             ber_memfree(newctrl->ldctl_value.bv_val);
1323         ber_memfree(newctrl);
1324     }
1325     if (val)
1326         ber_memfree(val);
1327     if (oid)
1328         ber_memfree(oid);
1329
1330     return( rc );
1331 }
1332
1333
1334 static void
1335 addmodifyop(
1336         LDAPMod ***pmodsp,
1337         int modop,
1338         const char *attr,
1339         struct berval *val )
1340 {
1341         LDAPMod         **pmods;
1342         int                     i, j;
1343
1344         pmods = *pmodsp;
1345         modop |= LDAP_MOD_BVALUES;
1346
1347         i = 0;
1348         if ( pmods != NULL ) {
1349                 for ( ; pmods[ i ] != NULL; ++i ) {
1350                         if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
1351                                 pmods[ i ]->mod_op == modop )
1352                         {
1353                                 break;
1354                         }
1355                 }
1356         }
1357
1358         if ( pmods == NULL || pmods[ i ] == NULL ) {
1359                 if (( pmods = (LDAPMod **)ber_memrealloc( pmods, (i + 2) *
1360                         sizeof( LDAPMod * ))) == NULL )
1361                 {
1362                         perror( "realloc" );
1363                         exit( EXIT_FAILURE );
1364                 }
1365
1366                 *pmodsp = pmods;
1367                 pmods[ i + 1 ] = NULL;
1368
1369                 pmods[ i ] = (LDAPMod *)ber_memcalloc( 1, sizeof( LDAPMod ));
1370                 if ( pmods[ i ] == NULL ) {
1371                         perror( "calloc" );
1372                         exit( EXIT_FAILURE );
1373                 }
1374
1375                 pmods[ i ]->mod_op = modop;
1376                 pmods[ i ]->mod_type = ber_strdup( attr );
1377                 if ( pmods[ i ]->mod_type == NULL ) {
1378                         perror( "strdup" );
1379                         exit( EXIT_FAILURE );
1380                 }
1381         }
1382
1383         if ( val != NULL ) {
1384                 j = 0;
1385                 if ( pmods[ i ]->mod_bvalues != NULL ) {
1386                         for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
1387                                 /* Empty */;
1388                         }
1389                 }
1390
1391                 pmods[ i ]->mod_bvalues = (struct berval **) ber_memrealloc(
1392                         pmods[ i ]->mod_bvalues, (j + 2) * sizeof( struct berval * ));
1393                 if ( pmods[ i ]->mod_bvalues == NULL ) {
1394                         perror( "ber_realloc" );
1395                         exit( EXIT_FAILURE );
1396                 }
1397
1398                 pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
1399                 pmods[ i ]->mod_bvalues[ j ] = ber_bvdup( val );
1400                 if ( pmods[ i ]->mod_bvalues[ j ] == NULL ) {
1401                         perror( "ber_bvdup" );
1402                         exit( EXIT_FAILURE );
1403                 }
1404         }
1405 }
1406
1407
1408 static int
1409 domodify(
1410         const char *dn,
1411         LDAPMod **pmods,
1412     LDAPControl **pctrls,
1413         int newentry )
1414 {
1415     int                 i, j, k, notascii, op;
1416     struct berval       *bvp;
1417
1418     if ( pmods == NULL ) {
1419         fprintf( stderr, "%s: no attributes to change or add (entry=\"%s\")\n",
1420                 prog, dn );
1421         return( LDAP_PARAM_ERROR );
1422     } 
1423
1424     for ( i = 0; pmods[ i ] != NULL; ++i ) {
1425         op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
1426         if( op == LDAP_MOD_ADD && ( pmods[i]->mod_bvalues == NULL )) {
1427                 fprintf( stderr,
1428                         "%s: attribute \"%s\" has no values (entry=\"%s\")\n",
1429                         prog, pmods[i]->mod_type, dn );
1430                 return LDAP_PARAM_ERROR;
1431         }
1432     }
1433
1434     if ( verbose ) {
1435         for ( i = 0; pmods[ i ] != NULL; ++i ) {
1436             op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
1437             printf( "%s %s:\n", op == LDAP_MOD_REPLACE ?
1438                     "replace" : op == LDAP_MOD_ADD ?
1439                     "add" : "delete", pmods[ i ]->mod_type );
1440             if ( pmods[ i ]->mod_bvalues != NULL ) {
1441                 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
1442                     bvp = pmods[ i ]->mod_bvalues[ j ];
1443                     notascii = 0;
1444                     for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
1445                         if ( !isascii( bvp->bv_val[ k ] )) {
1446                             notascii = 1;
1447                             break;
1448                         }
1449                     }
1450                     if ( notascii ) {
1451                         printf( "\tNOT ASCII (%ld bytes)\n", bvp->bv_len );
1452                     } else {
1453                         printf( "\t%s\n", bvp->bv_val );
1454                     }
1455                 }
1456             }
1457         }
1458     }
1459
1460     if ( newentry ) {
1461         printf( "%sadding new entry \"%s\"\n", not ? "!" : "", dn );
1462     } else {
1463         printf( "%smodifying entry \"%s\"\n", not ? "!" : "", dn );
1464     }
1465
1466     if ( !not ) {
1467         if ( newentry ) {
1468             i = ldap_add_ext_s( ld, dn, pmods, pctrls, NULL );
1469         } else {
1470             i = ldap_modify_ext_s( ld, dn, pmods, pctrls, NULL );
1471         }
1472         if ( i != LDAP_SUCCESS ) {
1473                 /* print error message about failed update including DN */
1474                 fprintf( stderr, "%s: update failed: %s\n", prog, dn );
1475                 ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
1476         } else if ( verbose ) {
1477             printf( "modify complete\n" );
1478         }
1479     } else {
1480         i = LDAP_SUCCESS;
1481     }
1482
1483     putchar( '\n' );
1484
1485     return( i );
1486 }
1487
1488
1489 static int
1490 dodelete(
1491         const char *dn,
1492     LDAPControl **pctrls )
1493 {
1494     int rc;
1495
1496     printf( "%sdeleting entry \"%s\"\n", not ? "!" : "", dn );
1497     if ( !not ) {
1498         if (( rc = ldap_delete_ext_s( ld, dn, pctrls, NULL )) != LDAP_SUCCESS ) {
1499                 fprintf( stderr, "%s: delete failed: %s\n", prog, dn );
1500                 ldap_perror( ld, "ldap_delete" );
1501         } else if ( verbose ) {
1502             printf( "delete complete" );
1503         }
1504     } else {
1505         rc = LDAP_SUCCESS;
1506     }
1507
1508     putchar( '\n' );
1509
1510     return( rc );
1511 }
1512
1513
1514 static int
1515 dorename(
1516         const char *dn,
1517         const char *newrdn,
1518         const char* newsup,
1519         int deleteoldrdn,
1520     LDAPControl **pctrls )
1521 {
1522     int rc;
1523
1524
1525     printf( "%smodifying rdn of entry \"%s\"\n", not ? "!" : "", dn );
1526     if ( verbose ) {
1527         printf( "\tnew RDN: \"%s\" (%skeep existing values)\n",
1528                 newrdn, deleteoldrdn ? "do not " : "" );
1529     }
1530     if ( !not ) {
1531         if (( rc = ldap_rename_s( ld, dn, newrdn, newsup, deleteoldrdn, pctrls, NULL ))
1532                 != LDAP_SUCCESS ) {
1533                 fprintf( stderr, "%s: rename failed: %s\n", prog, dn );
1534                 ldap_perror( ld, "ldap_modrdn" );
1535         } else {
1536             printf( "modrdn completed\n" );
1537         }
1538     } else {
1539         rc = LDAP_SUCCESS;
1540     }
1541
1542     putchar( '\n' );
1543
1544     return( rc );
1545 }
1546
1547
1548 static char *
1549 read_one_record( FILE *fp )
1550 {
1551     char        *buf, line[ LDAPMOD_MAXLINE ];
1552     int         lcur, lmax;
1553
1554     lcur = lmax = 0;
1555     buf = NULL;
1556
1557     while ( fgets( line, sizeof(line), fp ) != NULL ) {
1558         int len = strlen( line );
1559
1560                 if( len < 2 || ( len == 2 && *line == '\r' )) {
1561                         if( buf == NULL ) {
1562                                 continue;
1563                         } else {
1564                                 break;
1565                         }
1566                 }
1567
1568                 if ( lcur + len + 1 > lmax ) {
1569                         lmax = LDAPMOD_MAXLINE
1570                                 * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
1571
1572                         if (( buf = (char *)ber_memrealloc( buf, lmax )) == NULL ) {
1573                                 perror( "realloc" );
1574                                 exit( EXIT_FAILURE );
1575                         }
1576                 }
1577
1578                 strcpy( buf + lcur, line );
1579                 lcur += len;
1580     }
1581
1582     return( buf );
1583 }
1584
1585