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