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