]> git.sur5r.net Git - openldap/blob - clients/tools/ldapmodify.c
9f5d1273815292f84449b4eca75879ecbf36a2d5
[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 #include <ctype.h>
8
9 #include <ac/string.h>
10 #include <ac/socket.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 #include "ldapconfig.h"
27
28 static char     *prog;
29 static char     *binddn = LDAPMODIFY_BINDDN;
30 static char     *passwd = LDAPMODIFY_BIND_CRED;
31 static char     *ldaphost = LDAPHOST;
32 static int      ldapport = LDAP_PORT;
33 static int      new, replace, not, verbose, contoper, force, valsfromfiles;
34 static LDAP     *ld;
35
36 #ifdef LDAP_DEBUG
37 extern int ldap_debug, lber_debug;
38 #endif /* LDAP_DEBUG */
39
40 #define safe_realloc( ptr, size )       ( ptr == NULL ? malloc( size ) : \
41                                          realloc( ptr, size ))
42
43 #define LDAPMOD_MAXLINE         4096
44
45 /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
46 #define T_REPLICA_STR           "replica"
47 #define T_DN_STR                "dn"
48 #define T_CHANGETYPESTR         "changetype"
49 #define T_ADDCTSTR              "add"
50 #define T_MODIFYCTSTR           "modify"
51 #define T_DELETECTSTR           "delete"
52 #define T_MODRDNCTSTR           "modrdn"
53 #define T_MODOPADDSTR           "add"
54 #define T_MODOPREPLACESTR       "replace"
55 #define T_MODOPDELETESTR        "delete"
56 #define T_MODSEPSTR             "-"
57 #define T_NEWRDNSTR             "newrdn"
58 #define T_DELETEOLDRDNSTR       "deleteoldrdn"
59
60
61 static int process_ldapmod_rec LDAP_P(( char *rbuf ));
62 static int process_ldif_rec LDAP_P(( char *rbuf ));
63 static void addmodifyop LDAP_P(( LDAPMod ***pmodsp, int modop, char *attr,
64         char *value, int vlen ));
65 static int domodify LDAP_P(( char *dn, LDAPMod **pmods, int newentry ));
66 static int dodelete LDAP_P(( char *dn ));
67 static int domodrdn LDAP_P(( char *dn, char *newrdn, int deleteoldrdn ));
68 static void freepmods LDAP_P(( LDAPMod **pmods ));
69 static int fromfile LDAP_P(( char *path, struct berval *bv ));
70 static char *read_one_record LDAP_P(( FILE *fp ));
71
72
73 main( argc, argv )
74     int         argc;
75     char        **argv;
76 {
77     char                *infile, *rbuf, *start, *p, *q;
78     FILE                *fp;
79     int                 rc, i, kerberos, use_ldif, authmethod;
80     char                *usage = "usage: %s [-abcknrvF] [-d debug-level] [-h ldaphost] [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile ]\n";
81
82     extern char *optarg;
83     extern int  optind;
84
85     if (( prog = strrchr( argv[ 0 ], '/' )) == NULL ) {
86         prog = argv[ 0 ];
87     } else {
88         ++prog;
89     }
90     new = ( strcmp( prog, "ldapadd" ) == 0 );
91
92     infile = NULL;
93     kerberos = not = verbose = valsfromfiles = 0;
94
95     while (( i = getopt( argc, argv, "FabckKnrtvh:p:D:w:d:f:" )) != EOF ) {
96         switch( i ) {
97         case 'a':       /* add */
98             new = 1;
99             break;
100         case 'b':       /* read values from files (for binary attributes) */
101             valsfromfiles = 1;
102             break;
103         case 'c':       /* continuous operation */
104             contoper = 1;
105             break;
106         case 'r':       /* default is to replace rather than add values */
107             replace = 1;
108             break;
109         case 'k':       /* kerberos bind */
110             kerberos = 2;
111             break;
112         case 'K':       /* kerberos bind, part 1 only */
113             kerberos = 1;
114             break;
115         case 'F':       /* force all changes records to be used */
116             force = 1;
117             break;
118         case 'h':       /* ldap host */
119             ldaphost = strdup( optarg );
120             break;
121         case 'D':       /* bind DN */
122             binddn = strdup( optarg );
123             break;
124         case 'w':       /* password */
125             passwd = strdup( optarg );
126             break;
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         case 'f':       /* read from file */
136             infile = strdup( optarg );
137             break;
138         case 'p':
139             ldapport = atoi( optarg );
140             break;
141         case 'n':       /* print adds, don't actually do them */
142             ++not;
143             break;
144         case 'v':       /* verbose mode */
145             verbose++;
146             break;
147         default:
148             fprintf( stderr, usage, prog );
149             exit( 1 );
150         }
151     }
152
153     if ( argc - optind != 0 ) {
154         fprintf( stderr, usage, prog );
155         exit( 1 );
156     }
157
158     if ( infile != NULL ) {
159         if (( fp = fopen( infile, "r" )) == NULL ) {
160             perror( infile );
161             exit( 1 );
162         }
163     } else {
164         fp = stdin;
165     }
166
167
168     if ( !not ) {
169         if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
170             perror( "ldap_open" );
171             exit( 1 );
172         }
173
174         ld->ld_deref = LDAP_DEREF_NEVER;        /* this seems prudent */
175
176         if ( !kerberos ) {
177             authmethod = LDAP_AUTH_SIMPLE;
178         } else if ( kerberos == 1 ) {
179             authmethod = LDAP_AUTH_KRBV41;
180         } else {
181             authmethod = LDAP_AUTH_KRBV4;
182         }
183         if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
184             ldap_perror( ld, "ldap_bind" );
185             exit( 1 );
186         }
187     }
188
189     rc = 0;
190
191     while (( rc == 0 || contoper ) &&
192                 ( rbuf = read_one_record( fp )) != NULL ) {
193         /*
194          * we assume record is ldif/slapd.replog if the first line
195          * has a colon that appears to the left of any equal signs, OR
196          * if the first line consists entirely of digits (an entry id)
197          */
198         use_ldif = ( p = strchr( rbuf, ':' )) != NULL &&
199                 ( q = strchr( rbuf, '\n' )) != NULL && p < q &&
200                 (( q = strchr( rbuf, '=' )) == NULL || p < q );
201
202         start = rbuf;
203
204         if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) {
205             for ( p = rbuf; p < q; ++p ) {
206                 if ( !isdigit( *p )) {
207                     break;
208                 }
209             }
210             if ( p >= q ) {
211                 use_ldif = 1;
212                 start = q + 1;
213             }
214         }
215
216         if ( use_ldif ) {
217             rc = process_ldif_rec( start );
218         } else {
219             rc = process_ldapmod_rec( start );
220         }
221
222         free( rbuf );
223     }
224
225     if ( !not ) {
226         ldap_unbind( ld );
227     }
228
229     exit( rc );
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 }