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