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