]> git.sur5r.net Git - openldap/blob - clients/tools/ldapmodify.c
1be272e08db962040ace7c96942e2748232a38f4
[openldap] / clients / tools / ldapmodify.c
1 /* ldapmodify.c - generic program to modify or add entries using LDAP */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include <ac/ctype.h>
9 #include <ac/signal.h>
10 #include <ac/string.h>
11 #include <ac/unistd.h>
12
13 #include <sys/stat.h>
14
15 #ifdef HAVE_SYS_FILE_H
16 #include <sys/file.h>
17 #endif
18 #ifdef HAVE_FCNTL_H
19 #include <fcntl.h>
20 #endif
21
22 #include <lber.h>
23 #include <ldap.h>
24 #include <ldif.h>
25
26 static char     *prog;
27 static char     *binddn = NULL;
28 static char     *passwd = NULL;
29 static char     *ldaphost = NULL;
30 static int      ldapport = 0;
31 static int      new, replace, not, verbose, contoper, force, valsfromfiles;
32 static LDAP     *ld;
33
34 #define safe_realloc( ptr, size )       ( ptr == NULL ? malloc( size ) : \
35                                          realloc( ptr, size ))
36
37 #define LDAPMOD_MAXLINE         4096
38
39 /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
40 #define T_REPLICA_STR           "replica"
41 #define T_DN_STR                "dn"
42 #define T_CHANGETYPESTR         "changetype"
43 #define T_ADDCTSTR              "add"
44 #define T_MODIFYCTSTR           "modify"
45 #define T_DELETECTSTR           "delete"
46 #define T_MODRDNCTSTR           "modrdn"
47 #define T_MODOPADDSTR           "add"
48 #define T_MODOPREPLACESTR       "replace"
49 #define T_MODOPDELETESTR        "delete"
50 #define T_MODSEPSTR             "-"
51 #define T_NEWRDNSTR             "newrdn"
52 #define T_DELETEOLDRDNSTR       "deleteoldrdn"
53
54
55 static void usage LDAP_P(( const char *prog ));
56 static int process_ldapmod_rec LDAP_P(( char *rbuf ));
57 static int process_ldif_rec LDAP_P(( char *rbuf ));
58 static void addmodifyop LDAP_P(( LDAPMod ***pmodsp, int modop, char *attr,
59         char *value, int vlen ));
60 static int domodify LDAP_P(( char *dn, LDAPMod **pmods, int newentry ));
61 static int dodelete LDAP_P(( char *dn ));
62 static int domodrdn LDAP_P(( char *dn, char *newrdn, int deleteoldrdn ));
63 static void freepmods LDAP_P(( LDAPMod **pmods ));
64 static int fromfile LDAP_P(( char *path, struct berval *bv ));
65 static char *read_one_record LDAP_P(( FILE *fp ));
66
67 static void
68 usage( const char *prog )
69 {
70     fprintf( stderr, "Add or modify entries from an LDAP server\n\n"
71              "usage: %s [-abcknrvF] [-d debug-level] [-P version] [-h ldaphost]\n"
72              "            [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile ]\n"
73              "       a    - add values (default%s)\n"
74              "       b    - read values from files (for binary attributes)\n"
75              "       c    - continuous operation\n"
76              "       D    - bind DN\n"
77              "       d    - debug level\n"
78              "       f    - read from file\n"
79              "       F    - force all changes records to be used\n"
80              "       h    - ldap host\n"
81              "       n    - print adds, don't actually do them\n"
82              "       p    - LDAP port\n"
83              "       r    - replace values\n"
84              "       v    - verbose mode\n"
85              "       w    - password\n"
86              , prog, (strcmp( prog, "ldapadd" ) ? " is to replace" : "") );
87     exit( 1 );
88 }
89
90
91 int
92 main( int argc, char **argv )
93 {
94     char                *infile, *rbuf, *start, *p, *q;
95     FILE                *fp;
96         int             rc, i, use_ldif, authmethod, version, want_bindpw, debug;
97
98     if (( prog = strrchr( argv[ 0 ], '/'  )) == NULL &&
99         ( prog = strrchr( argv[ 0 ], '\\' )) == NULL   ) { // for Windows/DOS
100         prog = argv[ 0 ];
101     } else {
102         ++prog;
103     }
104
105     // Print usage when no parameters
106     if( argc < 2 )
107         usage( prog );
108
109     new = ( strcmp( prog, "ldapadd" ) == 0 );
110
111     infile = NULL;
112     not = verbose = valsfromfiles = want_bindpw = debug = 0;
113     authmethod = LDAP_AUTH_SIMPLE;
114         version = -1;
115
116     while (( i = getopt( argc, argv, "WFabckKnrtvh:p:D:w:d:f:" )) != EOF ) {
117         switch( i ) {
118         case 'a':       /* add */
119             new = 1;
120             break;
121         case 'b':       /* read values from files (for binary attributes) */
122             valsfromfiles = 1;
123             break;
124         case 'c':       /* continuous operation */
125             contoper = 1;
126             break;
127         case 'r':       /* default is to replace rather than add values */
128             replace = 1;
129             break;
130         case 'k':       /* kerberos bind */
131 #ifdef HAVE_KERBEROS
132                 authmethod = LDAP_AUTH_KRBV4;
133 #else
134                 fprintf (stderr, "%s was not compiled with Kerberos support\n", argv[0]);
135 #endif
136             break;
137         case 'K':       /* kerberos bind, part 1 only */
138 #ifdef HAVE_KERBEROS
139                 authmethod = LDAP_AUTH_KRBV41;
140 #else
141                 fprintf (stderr, "%s was not compiled with Kerberos support\n", argv[0]);
142 #endif
143             break;
144         case 'F':       /* force all changes records to be used */
145             force = 1;
146             break;
147         case 'h':       /* ldap host */
148             ldaphost = strdup( optarg );
149             break;
150         case 'D':       /* bind DN */
151             binddn = strdup( optarg );
152             break;
153         case 'w':       /* password */
154             passwd = strdup( optarg );
155             break;
156         case 'd':
157             debug |= atoi( optarg );
158             break;
159         case 'f':       /* read from file */
160             infile = strdup( optarg );
161             break;
162         case 'p':
163             ldapport = atoi( optarg );
164             break;
165         case 'n':       /* print adds, don't actually do them */
166             ++not;
167             break;
168         case 'v':       /* verbose mode */
169             verbose++;
170             break;
171         case 'W':
172                 want_bindpw++;
173                 break;
174         case 'P':
175                 switch(optarg[0])
176                 {
177                 case '2':
178                         version = LDAP_VERSION2;
179                         break;
180                 case '3':
181                         version = LDAP_VERSION3;
182                         break;
183                 }
184                 break;
185         default:
186             usage( prog );
187         }
188     }
189
190     if ( argc != optind )
191         usage( prog );
192
193     if ( infile != NULL ) {
194         if (( fp = fopen( infile, "r" )) == NULL ) {
195             perror( infile );
196             exit( 1 );
197         }
198     } else {
199         fp = stdin;
200     }
201
202         if ( debug ) {
203                 lber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug );
204                 ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug );
205                 ldif_debug = debug;
206         }
207
208 #ifdef SIGPIPE
209         (void) SIGNAL( SIGPIPE, SIG_IGN );
210 #endif
211
212     if ( !not ) {
213         if (( ld = ldap_init( ldaphost, ldapport )) == NULL ) {
214             perror( "ldap_init" );
215             exit( 1 );
216         }
217
218         /* this seems prudent */
219         {
220                 int deref = LDAP_DEREF_NEVER;
221                 ldap_set_option( ld, LDAP_OPT_DEREF, &deref);
222         }
223
224         if (want_bindpw)
225                 passwd = getpass("Enter LDAP Password: ");
226
227         if( version != -1 ) {
228                 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
229         }
230
231         if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
232             ldap_perror( ld, "ldap_bind" );
233             exit( 1 );
234         }
235     }
236
237     rc = 0;
238
239     while (( rc == 0 || contoper ) &&
240                 ( rbuf = read_one_record( fp )) != NULL ) {
241         /*
242          * we assume record is ldif/slapd.replog if the first line
243          * has a colon that appears to the left of any equal signs, OR
244          * if the first line consists entirely of digits (an entry id)
245          */
246         use_ldif = ( p = strchr( rbuf, ':' )) != NULL &&
247                 ( q = strchr( rbuf, '\n' )) != NULL && p < q &&
248                 (( q = strchr( rbuf, '=' )) == NULL || p < q );
249
250         start = rbuf;
251
252         if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) {
253             for ( p = rbuf; p < q; ++p ) {
254                 if ( !isdigit( (unsigned char) *p )) {
255                     break;
256                 }
257             }
258             if ( p >= q ) {
259                 use_ldif = 1;
260                 start = q + 1;
261             }
262         }
263
264         if ( use_ldif ) {
265             rc = process_ldif_rec( start );
266         } else {
267             rc = process_ldapmod_rec( start );
268         }
269
270         if( rc )
271             fprintf( stderr, "%s() = %d\n",
272                      use_ldif ? "ldif_rec" : "ldapmod_rec" , rc );
273
274         free( rbuf );
275     }
276
277     if ( !not ) {
278         ldap_unbind( ld );
279     }
280
281     exit( rc );
282
283         /* UNREACHABLE */
284         return(0);
285 }
286
287
288 static int
289 process_ldif_rec( char *rbuf )
290 {
291     char        *line, *dn, *type, *value, *newrdn, *p;
292     int         rc, linenum, vlen, modop, replicaport;
293     int         expect_modop, expect_sep, expect_ct, expect_newrdn;
294     int         expect_deleteoldrdn, deleteoldrdn;
295     int         saw_replica, use_record, new_entry, delete_entry, got_all;
296     LDAPMod     **pmods;
297
298     new_entry = new;
299
300     rc = got_all = saw_replica = delete_entry = expect_modop = 0;
301     expect_deleteoldrdn = expect_newrdn = expect_sep = expect_ct = 0;
302     linenum = 0;
303     deleteoldrdn = 1;
304     use_record = force;
305     pmods = NULL;
306     dn = newrdn = NULL;
307
308     while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
309         ++linenum;
310         if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
311             expect_sep = 0;
312             expect_ct = 1;
313             continue;
314         }
315         
316         if ( ldif_parse_line( line, &type, &value, &vlen ) < 0 ) {
317             fprintf( stderr, "%s: invalid format (line %d of entry: %s\n",
318                     prog, linenum, dn == NULL ? "" : dn );
319             rc = LDAP_PARAM_ERROR;
320             break;
321         }
322
323         if ( dn == NULL ) {
324             if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
325                 ++saw_replica;
326                 if (( p = strchr( value, ':' )) == NULL ) {
327                     replicaport = 0;
328                 } else {
329                     *p++ = '\0';
330                     replicaport = atoi( p );
331                 }
332                 if ( strcasecmp( value, ldaphost ) == 0 &&
333                         replicaport == ldapport ) {
334                     use_record = 1;
335                 }
336             } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
337                 if (( dn = strdup( value )) == NULL ) {
338                     perror( "strdup" );
339                     exit( 1 );
340                 }
341                 expect_ct = 1;
342             }
343             continue;   /* skip all lines until we see "dn:" */
344         }
345
346         if ( expect_ct ) {
347             expect_ct = 0;
348             if ( !use_record && saw_replica ) {
349                 printf( "%s: skipping change record for entry: %s\n\t(LDAP host/port does not match replica: lines)\n",
350                         prog, dn );
351                 free( dn );
352                 return( 0 );
353             }
354
355             if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
356                 if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) {
357                         new_entry = 0;
358                         expect_modop = 1;
359                 } else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) {
360                         new_entry = 1;
361                 } else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0 ) {
362                     expect_newrdn = 1;
363                 } else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) {
364                     got_all = delete_entry = 1;
365                 } else {
366                     fprintf( stderr,
367                             "%s:  unknown %s \"%s\" (line %d of entry: %s)\n",
368                             prog, T_CHANGETYPESTR, value, linenum, dn );
369                     rc = LDAP_PARAM_ERROR;
370                 }
371                 continue;
372             } else if ( new ) {         /*  missing changetype => add */
373                 new_entry = 1;
374                 modop = LDAP_MOD_ADD;
375             } else {
376                 expect_modop = 1;       /* missing changetype => modify */
377             }
378         }
379
380         if ( expect_modop ) {
381             expect_modop = 0;
382             expect_sep = 1;
383             if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
384                 modop = LDAP_MOD_ADD;
385                 continue;
386             } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
387                 modop = LDAP_MOD_REPLACE;
388                 continue;
389             } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
390                 modop = LDAP_MOD_DELETE;
391                 addmodifyop( &pmods, modop, value, NULL, 0 );
392                 continue;
393             } else {    /* no modify op:  use default */
394                 modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
395             }
396         }
397
398         if ( expect_newrdn ) {
399             if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
400                 if (( newrdn = strdup( value )) == NULL ) {
401                     perror( "strdup" );
402                     exit( 1 );
403                 }
404                 expect_deleteoldrdn = 1;
405                 expect_newrdn = 0;
406             } else {
407                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n",
408                         prog, T_NEWRDNSTR, type, linenum, dn );
409                 rc = LDAP_PARAM_ERROR;
410             }
411         } else if ( expect_deleteoldrdn ) {
412             if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
413                 deleteoldrdn = ( *value == '0' ) ? 0 : 1;
414                 got_all = 1;
415             } else {
416                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n",
417                         prog, T_DELETEOLDRDNSTR, type, linenum, dn );
418                 rc = LDAP_PARAM_ERROR;
419             }
420         } else if ( got_all ) {
421             fprintf( stderr,
422                     "%s: extra lines at end (line %d of entry %s)\n",
423                     prog, linenum, dn );
424             rc = LDAP_PARAM_ERROR;
425         } else {
426             addmodifyop( &pmods, modop, type, value, vlen );
427         }
428     }
429
430     if ( rc == 0 ) {
431         if ( delete_entry ) {
432             rc = dodelete( dn );
433         } else if ( newrdn != NULL ) {
434             rc = domodrdn( dn, newrdn, deleteoldrdn );
435         } else {
436             rc = domodify( dn, pmods, new_entry );
437         }
438
439         if ( rc == LDAP_SUCCESS ) {
440             rc = 0;
441         }
442     }
443
444     if ( dn != NULL ) {
445         free( dn );
446     }
447     if ( newrdn != NULL ) {
448         free( newrdn );
449     }
450     if ( pmods != NULL ) {
451         freepmods( pmods );
452     }
453
454     return( rc );
455 }
456
457
458 static int
459 process_ldapmod_rec( char *rbuf )
460 {
461     char        *line, *dn, *p, *q, *attr, *value;
462     int         rc, linenum, modop;
463     LDAPMod     **pmods;
464
465     pmods = NULL;
466     dn = NULL;
467     linenum = 0;
468     line = rbuf;
469     rc = 0;
470
471     while ( rc == 0 && rbuf != NULL && *rbuf != '\0' ) {
472         ++linenum;
473         if (( p = strchr( rbuf, '\n' )) == NULL ) {
474             rbuf = NULL;
475         } else {
476             if ( *(p-1) == '\\' ) {     /* lines ending in '\' are continued */
477                 SAFEMEMCPY( p - 1, p, strlen( p ) + 1 );
478                 rbuf = p;
479                 continue;
480             }
481             *p++ = '\0';
482             rbuf = p;
483         }
484
485         if ( dn == NULL ) {     /* first line contains DN */
486             if (( dn = strdup( line )) == NULL ) {
487                 perror( "strdup" );
488                 exit( 1 );
489             }
490         } else {
491             if (( p = strchr( line, '=' )) == NULL ) {
492                 value = NULL;
493                 p = line + strlen( line );
494             } else {
495                 *p++ = '\0';
496                 value = p;
497             }
498
499             for ( attr = line;
500                   *attr != '\0' && isspace( (unsigned char) *attr ); ++attr ) {
501                 ;       /* skip attribute leading white space */
502             }
503
504             for ( q = p - 1; q > attr && isspace( (unsigned char) *q ); --q ) {
505                 *q = '\0';      /* remove attribute trailing white space */
506             }
507
508             if ( value != NULL ) {
509                 while ( isspace( (unsigned char) *value )) {
510                     ++value;            /* skip value leading white space */
511                 }
512                 for ( q = value + strlen( value ) - 1; q > value &&
513                         isspace( (unsigned char) *q ); --q ) {
514                     *q = '\0';  /* remove value trailing white space */
515                 }
516                 if ( *value == '\0' ) {
517                     value = NULL;
518                 }
519
520             }
521
522             if ( value == NULL && new ) {
523                 fprintf( stderr, "%s: missing value on line %d (attr is %s)\n",
524                         prog, linenum, attr );
525                 rc = LDAP_PARAM_ERROR;
526             } else {
527                  switch ( *attr ) {
528                 case '-':
529                     modop = LDAP_MOD_DELETE;
530                     ++attr;
531                     break;
532                 case '+':
533                     modop = LDAP_MOD_ADD;
534                     ++attr;
535                     break;
536                 default:
537                     modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
538                 }
539
540                 addmodifyop( &pmods, modop, attr, value,
541                         ( value == NULL ) ? 0 : strlen( value ));
542             }
543         }
544
545         line = rbuf;
546     }
547
548     if ( rc == 0 ) {
549         if ( dn == NULL ) {
550             rc = LDAP_PARAM_ERROR;
551         } else if (( rc = domodify( dn, pmods, new )) == LDAP_SUCCESS ) {
552             rc = 0;
553         }
554     }
555
556     if ( pmods != NULL ) {
557         freepmods( pmods );
558     }
559     if ( dn != NULL ) {
560         free( dn );
561     }
562
563     return( rc );
564 }
565
566
567 static void
568 addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
569 {
570     LDAPMod             **pmods;
571     int                 i, j;
572     struct berval       *bvp;
573
574     pmods = *pmodsp;
575     modop |= LDAP_MOD_BVALUES;
576
577     i = 0;
578     if ( pmods != NULL ) {
579         for ( ; pmods[ i ] != NULL; ++i ) {
580             if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
581                     pmods[ i ]->mod_op == modop ) {
582                 break;
583             }
584         }
585     }
586
587     if ( pmods == NULL || pmods[ i ] == NULL ) {
588         if (( pmods = (LDAPMod **)safe_realloc( pmods, (i + 2) *
589                 sizeof( LDAPMod * ))) == NULL ) {
590             perror( "safe_realloc" );
591             exit( 1 );
592         }
593         *pmodsp = pmods;
594         pmods[ i + 1 ] = NULL;
595         if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod )))
596                 == NULL ) {
597             perror( "calloc" );
598             exit( 1 );
599         }
600         pmods[ i ]->mod_op = modop;
601         if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) {
602             perror( "strdup" );
603             exit( 1 );
604         }
605     }
606
607     if ( value != NULL ) {
608         j = 0;
609         if ( pmods[ i ]->mod_bvalues != NULL ) {
610             for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
611                 ;
612             }
613         }
614         if (( pmods[ i ]->mod_bvalues =
615                 (struct berval **)safe_realloc( pmods[ i ]->mod_bvalues,
616                 (j + 2) * sizeof( struct berval * ))) == NULL ) {
617             perror( "safe_realloc" );
618             exit( 1 );
619         }
620         pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
621         if (( bvp = (struct berval *)malloc( sizeof( struct berval )))
622                 == NULL ) {
623             perror( "malloc" );
624             exit( 1 );
625         }
626         pmods[ i ]->mod_bvalues[ j ] = bvp;
627
628         if ( valsfromfiles && *value == '/' ) { /* get value from file */
629             if ( fromfile( value, bvp ) < 0 ) {
630                 exit( 1 );
631             }
632         } else {
633             bvp->bv_len = vlen;
634             if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) {
635                 perror( "malloc" );
636                 exit( 1 );
637             }
638             SAFEMEMCPY( bvp->bv_val, value, vlen );
639             bvp->bv_val[ vlen ] = '\0';
640         }
641     }
642 }
643
644
645 static int
646 domodify( char *dn, LDAPMod **pmods, int newentry )
647 {
648     int                 i, j, k, notascii, op;
649     struct berval       *bvp;
650
651     if ( pmods == NULL ) {
652         fprintf( stderr, "%s: no attributes to change or add (entry %s)\n",
653                 prog, dn );
654         return( LDAP_PARAM_ERROR );
655     }
656
657     if ( verbose ) {
658         for ( i = 0; pmods[ i ] != NULL; ++i ) {
659             op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
660             printf( "%s %s:\n", op == LDAP_MOD_REPLACE ?
661                     "replace" : op == LDAP_MOD_ADD ?
662                     "add" : "delete", pmods[ i ]->mod_type );
663             if ( pmods[ i ]->mod_bvalues != NULL ) {
664                 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
665                     bvp = pmods[ i ]->mod_bvalues[ j ];
666                     notascii = 0;
667                     for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
668                         if ( !isascii( bvp->bv_val[ k ] )) {
669                             notascii = 1;
670                             break;
671                         }
672                     }
673                     if ( notascii ) {
674                         printf( "\tNOT ASCII (%ld bytes)\n", bvp->bv_len );
675                     } else {
676                         printf( "\t%s\n", bvp->bv_val );
677                     }
678                 }
679             }
680         }
681     }
682
683     if ( newentry ) {
684         printf( "%sadding new entry %s\n", not ? "!" : "", dn );
685     } else {
686         printf( "%smodifying entry %s\n", not ? "!" : "", dn );
687     }
688
689     if ( !not ) {
690         if ( newentry ) {
691             i = ldap_add_s( ld, dn, pmods );
692         } else {
693             i = ldap_modify_s( ld, dn, pmods );
694         }
695         if ( i != LDAP_SUCCESS ) {
696             ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
697         } else if ( verbose ) {
698             printf( "modify complete\n" );
699         }
700     } else {
701         i = LDAP_SUCCESS;
702     }
703
704     putchar( '\n' );
705
706     return( i );
707 }
708
709
710 static int
711 dodelete( char *dn )
712 {
713     int rc;
714
715     printf( "%sdeleting entry %s\n", not ? "!" : "", dn );
716     if ( !not ) {
717         if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
718             ldap_perror( ld, "ldap_delete" );
719         } else if ( verbose ) {
720             printf( "delete complete" );
721         }
722     } else {
723         rc = LDAP_SUCCESS;
724     }
725
726     putchar( '\n' );
727
728     return( rc );
729 }
730
731
732 static int
733 domodrdn( char *dn, char *newrdn, int deleteoldrdn )
734 {
735     int rc;
736
737     if ( verbose ) {
738         printf( "new RDN: %s (%skeep existing values)\n",
739                 newrdn, deleteoldrdn ? "do not " : "" );
740     }
741
742     printf( "%smodifying rdn of entry %s\n", not ? "!" : "", dn );
743     if ( !not ) {
744         if (( rc = ldap_modrdn2_s( ld, dn, newrdn, deleteoldrdn ))
745                 != LDAP_SUCCESS ) {
746             ldap_perror( ld, "ldap_modrdn" );
747         } else {
748             printf( "modrdn completed\n" );
749         }
750     } else {
751         rc = LDAP_SUCCESS;
752     }
753
754     putchar( '\n' );
755
756     return( rc );
757 }
758
759
760
761 // for Windows we need local versions of the berval
762 // free functions because the LDAP DLL uses a different
763 // heap.
764
765 static void
766 l_ber_bvfree( struct berval *bv )
767 {
768     if ( bv != NULL ) {
769         if ( bv->bv_val != NULL ) {
770             free( bv->bv_val );
771         }
772         free( (char *) bv );
773     }
774 }
775
776 static void
777 l_ber_bvecfree( struct berval **bv )
778 {
779     int i;
780
781     for ( i = 0; bv[i] != NULL; i++ ) {
782         l_ber_bvfree( bv[i] );
783     }
784     free( (char *) bv );
785 }
786
787 static void
788 freepmods( LDAPMod **pmods )
789 {
790     int i;
791
792     for ( i = 0; pmods[ i ] != NULL; ++i ) {
793         if ( pmods[ i ]->mod_bvalues != NULL ) {
794             l_ber_bvecfree( pmods[ i ]->mod_bvalues );
795         }
796         if ( pmods[ i ]->mod_type != NULL ) {
797             free( pmods[ i ]->mod_type );
798         }
799         free( pmods[ i ] );
800     }
801     free( pmods );
802 }
803
804
805 static int
806 fromfile( char *path, struct berval *bv )
807 {
808         FILE            *fp;
809         long            rlen;
810         int             eof;
811
812         if (( fp = fopen( path, "r" )) == NULL ) {
813                 perror( path );
814                 return( -1 );
815         }
816
817         if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
818                 perror( path );
819                 fclose( fp );
820                 return( -1 );
821         }
822
823         bv->bv_len = ftell( fp );
824
825         if (( bv->bv_val = (char *)malloc( bv->bv_len )) == NULL ) {
826                 perror( "malloc" );
827                 fclose( fp );
828                 return( -1 );
829         }
830
831         if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
832                 perror( path );
833                 fclose( fp );
834                 return( -1 );
835         }
836
837         rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
838         eof = feof( fp );
839         fclose( fp );
840
841         if ( (unsigned long) rlen != bv->bv_len ) {
842                 perror( path );
843                 free( bv->bv_val );
844                 return( -1 );
845         }
846
847         return( bv->bv_len );
848 }
849
850
851 static char *
852 read_one_record( FILE *fp )
853 {
854     int         len;
855     char        *buf, line[ LDAPMOD_MAXLINE ];
856     int         lcur, lmax;
857
858     lcur = lmax = 0;
859     buf = NULL;
860
861     while (( fgets( line, sizeof(line), fp ) != NULL ) &&
862             (( len = strlen( line )) > 1 )) {
863         if ( lcur + len + 1 > lmax ) {
864             lmax = LDAPMOD_MAXLINE
865                     * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
866             if (( buf = (char *)safe_realloc( buf, lmax )) == NULL ) {
867                 perror( "safe_realloc" );
868                 exit( 1 );
869             }
870         }
871         strcpy( buf + lcur, line );
872         lcur += len;
873     }
874
875     return( buf );
876 }