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