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