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