]> git.sur5r.net Git - openldap/blob - clients/tools/ldapmodify.c
Modify ldapsearch(1) significantly. Now handles LDAPv3 search
[openldap] / clients / tools / ldapmodify.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* ldapmodify.c - generic program to modify or add entries using LDAP */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/stdlib.h>
13
14 #include <ac/ctype.h>
15 #include <ac/signal.h>
16 #include <ac/string.h>
17 #include <ac/unistd.h>
18
19 #ifdef HAVE_SYS_STAT_H
20 #include <sys/stat.h>
21 #endif
22
23 #ifdef HAVE_SYS_FILE_H
24 #include <sys/file.h>
25 #endif
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29
30 #include <ldap.h>
31
32 #include "ldif.h"
33 #include "ldap_defaults.h"
34
35 static char     *prog;
36 static char     *binddn = NULL;
37 static struct berval passwd = { 0, NULL};
38 static char     *ldaphost = NULL;
39 static int      ldapport = 0;
40 #ifdef HAVE_CYRUS_SASL
41 static char     *sasl_authc_id = NULL;
42 static char     *sasl_authz_id = NULL;
43 static char     *sasl_mech = NULL;
44 static int      sasl_integrity = 0;
45 static int      sasl_privacy = 0;
46 #endif
47 static int      use_tls = 0;
48 static int      ldapadd, replace, not, verbose, contoper, force;
49 static LDAP     *ld;
50
51 #define LDAPMOD_MAXLINE         4096
52
53 /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
54 #define T_VERSION_STR           "version"
55 #define T_REPLICA_STR           "replica"
56 #define T_DN_STR                "dn"
57 #define T_CHANGETYPESTR         "changetype"
58 #define T_ADDCTSTR              "add"
59 #define T_MODIFYCTSTR           "modify"
60 #define T_DELETECTSTR           "delete"
61 #define T_MODRDNCTSTR           "modrdn"
62 #define T_MODDNCTSTR            "moddn"
63 #define T_RENAMECTSTR           "rename"
64 #define T_MODOPADDSTR           "add"
65 #define T_MODOPREPLACESTR       "replace"
66 #define T_MODOPDELETESTR        "delete"
67 #define T_MODSEPSTR             "-"
68 #define T_NEWRDNSTR             "newrdn"
69 #define T_DELETEOLDRDNSTR       "deleteoldrdn"
70 #define T_NEWSUPSTR             "newsuperior"
71
72
73 static void usage LDAP_P(( const char *prog )) LDAP_GCCATTR((noreturn));
74 static int process_ldif_rec LDAP_P(( char *rbuf, int count ));
75 static void addmodifyop LDAP_P(( LDAPMod ***pmodsp, int modop, char *attr,
76         char *value, int vlen ));
77 static int domodify LDAP_P(( char *dn, LDAPMod **pmods, int newentry ));
78 static int dodelete LDAP_P(( char *dn ));
79 static int domodrdn LDAP_P(( char *dn, char *newrdn, int deleteoldrdn ));
80 static char *read_one_record LDAP_P(( FILE *fp ));
81
82 static void
83 usage( const char *prog )
84 {
85     fprintf( stderr,
86 "Add or modify entries from an LDAP server\n\n"
87 "usage: %s [options]\n"
88 "       The list of desired operations are read from stdin or from the file\n"
89 "       specified by \"-f file\".\n"
90 "options:\n"
91 "       -a\t\tadd values (default%s)\n"
92 "       -b\t\tread values from files (for binary attributes)\n"
93 "       -c\t\tcontinuous operation\n"
94 "       -d level\tset LDAP debugging level to `level'\n"
95 "       -D dn\t\tbind DN\n"
96 "       -E\t\trequest SASL privacy (-EE to make it critical)\n"
97 "       -f file\t\tperform sequence of operations listed in file\n"
98 "       -F\t\tforce all changes records to be used\n"
99 "       -h host\t\tLDAP server\n"
100 "       -I\t\trequest SASL integrity checking (-II to make it\n"
101 "               \tcritical)\n"
102 "       -k\t\tuse Kerberos authentication\n"
103 "       -K\t\tlike -k, but do only step 1 of the Kerberos bind\n"
104 "       -M\t\tenable Manage DSA IT control (-MM to make it critical)\n"
105 "       -n\t\tprint changes, don't actually do them\n"
106 "       -p port\t\tport on LDAP server\n"
107 "       -r\t\treplace values\n"
108 "       -U user\t\tSASL authentication identity (username)\n"
109 "       -v\t\tverbose mode\n"
110 "       -w passwd\tbind password (for Simple authentication)\n"
111 "       -X id\t\tSASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
112 "       -Y mech\t\tSASL mechanism\n"
113 "       -Z\t\tissue Start TLS request (-ZZ to require successful response)\n"
114              , prog, (strcmp( prog, "ldapadd" ) ? " is to replace" : "") );
115     exit( EXIT_FAILURE );
116 }
117
118
119 int
120 main( int argc, char **argv )
121 {
122     char                *infile, *rbuf, *start;
123     FILE                *fp;
124         int             rc, i, authmethod, version, want_bindpw, debug, manageDSAit;
125         int count;
126
127     if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) {
128         prog = argv[ 0 ];
129     } else {
130         ++prog;
131     }
132
133     /* Print usage when no parameters */
134     if( argc < 2 ) usage( prog );
135
136     ldapadd = ( strcmp( prog, "ldapadd" ) == 0 );
137
138     infile = NULL;
139     not = verbose = want_bindpw = debug = manageDSAit = 0;
140     authmethod = LDAP_AUTH_SIMPLE;
141         version = -1;
142
143     while (( i = getopt( argc, argv, "acD:d:EFf:h:IKkMnP:p:rtU:vWw:X:Y:Z" )) != EOF ) {
144         switch( i ) {
145         case 'a':       /* add */
146             ldapadd = 1;
147             break;
148         case 'c':       /* continuous operation */
149             contoper = 1;
150             break;
151         case 'r':       /* default is to replace rather than add values */
152             replace = 1;
153             break;
154         case 'k':       /* kerberos bind */
155 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
156                 authmethod = LDAP_AUTH_KRBV4;
157 #else
158                 fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
159                 return( EXIT_FAILURE );
160 #endif
161             break;
162         case 'K':       /* kerberos bind, part 1 only */
163 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
164                 authmethod = LDAP_AUTH_KRBV41;
165 #else
166                 fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
167                 return( EXIT_FAILURE );
168 #endif
169             break;
170         case 'F':       /* force all changes records to be used */
171             force = 1;
172             break;
173         case 'h':       /* ldap host */
174             ldaphost = strdup( optarg );
175             break;
176         case 'D':       /* bind DN */
177             binddn = strdup( optarg );
178             break;
179         case 'w':       /* password */
180             passwd.bv_val = strdup( optarg );
181                 {
182                         char* p;
183
184                         for( p = optarg; *p == '\0'; p++ ) {
185                                 *p = '*';
186                         }
187                 }
188                 passwd.bv_len = strlen( passwd.bv_val );
189             break;
190         case 'd':
191             debug |= atoi( optarg );
192             break;
193         case 'f':       /* read from file */
194             infile = strdup( optarg );
195             break;
196         case 'p':
197             ldapport = atoi( optarg );
198             break;
199         case 'n':       /* print adds, don't actually do them */
200             ++not;
201             break;
202         case 'v':       /* verbose mode */
203             verbose++;
204             break;
205         case 'M':
206                 /* enable Manage DSA IT */
207                 manageDSAit++;
208                 break;
209         case 'W':
210                 want_bindpw++;
211                 break;
212         case 'P':
213                 switch( atoi(optarg) )
214                 {
215                 case 2:
216                         version = LDAP_VERSION2;
217                         break;
218                 case 3:
219                         version = LDAP_VERSION3;
220                         break;
221                 default:
222                         fprintf( stderr, "protocol version should be 2 or 3\n" );
223                         usage( argv[0] );
224                 }
225                 break;
226         case 'I':
227 #ifdef HAVE_CYRUS_SASL
228                 sasl_integrity++;
229                 authmethod = LDAP_AUTH_SASL;
230 #else
231                 fprintf( stderr, "%s was not compiled with SASL support\n",
232                         argv[0] );
233                 return( EXIT_FAILURE );
234 #endif
235                 break;
236         case 'E':
237 #ifdef HAVE_CYRUS_SASL
238                 sasl_privacy++;
239                 authmethod = LDAP_AUTH_SASL;
240 #else
241                 fprintf( stderr, "%s was not compiled with SASL support\n",
242                         argv[0] );
243                 return( EXIT_FAILURE );
244 #endif
245                 break;
246         case 'Y':
247 #ifdef HAVE_CYRUS_SASL
248                 if ( strcasecmp( optarg, "any" ) && strcmp( optarg, "*" ) ) {
249                         sasl_mech = strdup( optarg );
250                 }
251                 authmethod = LDAP_AUTH_SASL;
252 #else
253                 fprintf( stderr, "%s was not compiled with SASL support\n",
254                         argv[0] );
255                 return( EXIT_FAILURE );
256 #endif
257                 break;
258         case 'U':
259 #ifdef HAVE_CYRUS_SASL
260                 sasl_authc_id = strdup( optarg );
261                 authmethod = LDAP_AUTH_SASL;
262 #else
263                 fprintf( stderr, "%s was not compiled with SASL support\n",
264                         argv[0] );
265                 return( EXIT_FAILURE );
266 #endif
267                 break;
268         case 'X':
269 #ifdef HAVE_CYRUS_SASL
270                 sasl_authz_id = strdup( optarg );
271                 authmethod = LDAP_AUTH_SASL;
272 #else
273                 fprintf( stderr, "%s was not compiled with SASL support\n",
274                         argv[0] );
275                 return( EXIT_FAILURE );
276 #endif
277                 break;
278         case 'Z':
279 #ifdef HAVE_TLS
280                 use_tls++;
281 #else
282                 fprintf( stderr, "%s was not compiled with TLS support\n",
283                         argv[0] );
284                 return( EXIT_FAILURE );
285 #endif
286                 break;
287         default:
288             usage( prog );
289         }
290     }
291
292     if ( argc != optind )
293         usage( prog );
294
295         if ( ( authmethod == LDAP_AUTH_KRBV4 ) || ( authmethod ==
296                         LDAP_AUTH_KRBV41 ) ) {
297                 if( version > LDAP_VERSION2 ) {
298                         fprintf( stderr, "Kerberos requires LDAPv2\n" );
299                         return( EXIT_FAILURE );
300                 }
301                 version = LDAP_VERSION2;
302         }
303         else if ( authmethod == LDAP_AUTH_SASL ) {
304                 if( version != -1 && version != LDAP_VERSION3 ) {
305                         fprintf( stderr, "SASL requires LDAPv3\n" );
306                         return( EXIT_FAILURE );
307                 }
308                 version = LDAP_VERSION3;
309         }
310
311         if( manageDSAit ) {
312                 if( version != -1 && version != LDAP_VERSION3 ) {
313                         fprintf(stderr, "manage DSA control requires LDAPv3\n");
314                         return EXIT_FAILURE;
315                 }
316                 version = LDAP_VERSION3;
317         }
318
319         if( use_tls ) {
320                 if( version != -1 && version != LDAP_VERSION3 ) {
321                         fprintf(stderr, "Start TLS requires LDAPv3\n");
322                         return EXIT_FAILURE;
323                 }
324                 version = LDAP_VERSION3;
325         }
326
327     if ( infile != NULL ) {
328         if (( fp = fopen( infile, "r" )) == NULL ) {
329             perror( infile );
330             return( EXIT_FAILURE );
331         }
332     } else {
333         fp = stdin;
334     }
335
336         if ( debug ) {
337                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
338                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
339                 }
340                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
341                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
342                 }
343                 ldif_debug = debug;
344         }
345
346 #ifdef SIGPIPE
347         (void) SIGNAL( SIGPIPE, SIG_IGN );
348 #endif
349
350     if ( !not ) {
351         if (( ld = ldap_init( ldaphost, ldapport )) == NULL ) {
352             perror( "ldap_init" );
353             return( EXIT_FAILURE );
354         }
355
356         /* don't chase referrals */
357         ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
358
359         if (version == -1 ) {
360                 version = 3;
361         }
362
363         if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
364                 != LDAP_OPT_SUCCESS )
365         {
366                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
367                         version );
368         }
369
370         if ( use_tls && ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
371                 if ( use_tls > 1 ) {
372                         ldap_perror( ld, "ldap_start_tls" );
373                         return( EXIT_FAILURE );
374                 }
375         }
376
377         if (want_bindpw) {
378                 passwd.bv_val = getpassphrase("Enter LDAP Password: ");
379                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
380         }
381
382         if ( authmethod == LDAP_AUTH_SASL ) {
383 #ifdef HAVE_CYRUS_SASL
384                 int     minssf = 0, maxssf = 0;
385
386                 if ( sasl_integrity > 0 )
387                         maxssf = 1;
388                 if ( sasl_integrity > 1 )
389                         minssf = 1;
390                 if ( sasl_privacy > 0 )
391                         maxssf = 100000; /* Something big value */
392                 if ( sasl_privacy > 1 )
393                         minssf = 56;
394                 
395                 if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MINSSF,
396                         (void *)&minssf ) != LDAP_OPT_SUCCESS ) {
397                         fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MINSSF"
398                                 "%d\n", minssf);
399                         return( EXIT_FAILURE );
400                 }
401                 if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MAXSSF,
402                         (void *)&maxssf ) != LDAP_OPT_SUCCESS ) {
403                         fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MINSSF"
404                                 "%d\n", minssf);
405                         return( EXIT_FAILURE );
406                 }
407                 
408                 rc = ldap_negotiated_sasl_bind_s( ld, binddn, sasl_authc_id,
409                                 sasl_authz_id, sasl_mech,
410                                 passwd.bv_len ? &passwd : NULL,
411                                 NULL, NULL );
412
413                 if( rc != LDAP_SUCCESS ) {
414                         ldap_perror( ld, "ldap_negotiated_sasl_bind_s" );
415                         return( EXIT_FAILURE );
416                 }
417 #else
418                 fprintf( stderr, "%s was not compiled with SASL support\n",
419                         argv[0] );
420                 return( EXIT_FAILURE );
421 #endif
422         }
423         else {
424                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
425                                 != LDAP_SUCCESS ) {
426                         ldap_perror( ld, "ldap_bind" );
427                         return( EXIT_FAILURE );
428                 }
429         }
430
431     }
432
433     rc = 0;
434
435         if ( manageDSAit ) {
436                 int err;
437                 LDAPControl c;
438                 LDAPControl *ctrls[2];
439                 ctrls[0] = &c;
440                 ctrls[1] = NULL;
441
442                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
443                 c.ldctl_value.bv_val = NULL;
444                 c.ldctl_value.bv_len = 0;
445                 c.ldctl_iscritical = manageDSAit > 1;
446
447                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, &ctrls );
448
449                 if( err != LDAP_OPT_SUCCESS ) {
450                         fprintf( stderr, "Could not set Manage DSA IT Control\n" );
451                         if( c.ldctl_iscritical ) {
452                                 exit( EXIT_FAILURE );
453                         }
454                 }
455         }
456
457         count = 0;
458     while (( rc == 0 || contoper ) &&
459                 ( rbuf = read_one_record( fp )) != NULL ) {
460         count++;
461
462         start = rbuf;
463
464     rc = process_ldif_rec( start, count );
465
466         if( rc )
467                 fprintf( stderr, "ldif_record() = %d\n", rc );
468                 free( rbuf );
469     }
470
471     if ( !not ) {
472                 ldap_unbind( ld );
473     }
474
475         return( rc );
476 }
477
478
479 static int
480 process_ldif_rec( char *rbuf, int count )
481 {
482     char        *line, *dn, *type, *value, *newrdn, *newsup, *p;
483     int         rc, linenum, modop, replicaport;
484         ber_len_t vlen;
485     int         expect_modop, expect_sep, expect_ct, expect_newrdn, expect_newsup;
486     int         expect_deleteoldrdn, deleteoldrdn;
487     int         saw_replica, use_record, new_entry, delete_entry, got_all;
488     LDAPMod     **pmods;
489         int version;
490
491     new_entry = ldapadd;
492
493     rc = got_all = saw_replica = delete_entry = modop = expect_modop = 0;
494     expect_deleteoldrdn = expect_newrdn = expect_newsup = 0;
495         expect_sep = expect_ct = 0;
496     linenum = 0;
497         version = 0;
498     deleteoldrdn = 1;
499     use_record = force;
500     pmods = NULL;
501     dn = newrdn = newsup = NULL;
502
503     while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
504         ++linenum;
505
506         if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
507             expect_sep = 0;
508             expect_ct = 1;
509             continue;
510         }
511         
512         if ( ldif_parse_line( line, &type, &value, &vlen ) < 0 ) {
513             fprintf( stderr, "%s: invalid format (line %d) entry: \"%s\"\n",
514                     prog, linenum, dn == NULL ? "" : dn );
515             rc = LDAP_PARAM_ERROR;
516             break;
517         }
518
519         if ( dn == NULL ) {
520             if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
521                 ++saw_replica;
522                 if (( p = strchr( value, ':' )) == NULL ) {
523                     replicaport = 0;
524                 } else {
525                     *p++ = '\0';
526                     replicaport = atoi( p );
527                 }
528                 if ( ldaphost != NULL && strcasecmp( value, ldaphost ) == 0 &&
529                         replicaport == ldapport ) {
530                     use_record = 1;
531                 }
532             } else if ( count == 1 && linenum == 1 && 
533                         strcasecmp( type, T_VERSION_STR ) == 0 )
534                 {
535                         if( vlen == 0 || atoi(value) != 1 ) {
536                         fprintf( stderr, "%s: invalid version %s, line %d (ignored)\n",
537                                 prog, value == NULL ? "(null)" : value, linenum );
538                         }
539                         version++;
540
541             } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
542                 if (( dn = strdup( value ? value : "" )) == NULL ) {
543                     perror( "strdup" );
544                     exit( EXIT_FAILURE );
545                 }
546                 expect_ct = 1;
547             }
548             goto end_line;      /* skip all lines until we see "dn:" */
549         }
550
551         if ( expect_ct ) {
552             expect_ct = 0;
553             if ( !use_record && saw_replica ) {
554                 printf( "%s: skipping change record for entry: %s\n"
555                         "\t(LDAP host/port does not match replica: lines)\n",
556                         prog, dn );
557                 free( dn );
558                 ber_memfree( type );
559                 ber_memfree( value );
560                 return( 0 );
561             }
562
563             if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
564                 if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) {
565                         new_entry = 0;
566                         expect_modop = 1;
567                 } else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) {
568                         new_entry = 1;
569                 } else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0
570                         || strcasecmp( value, T_MODDNCTSTR ) == 0
571                         || strcasecmp( value, T_RENAMECTSTR ) == 0)
572                 {
573                     expect_newrdn = 1;
574                 } else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) {
575                     got_all = delete_entry = 1;
576                 } else {
577                     fprintf( stderr,
578                             "%s:  unknown %s \"%s\" (line %d of entry \"%s\")\n",
579                             prog, T_CHANGETYPESTR, value, linenum, dn );
580                     rc = LDAP_PARAM_ERROR;
581                 }
582                 goto end_line;
583             } else if ( ldapadd ) {             /*  missing changetype => add */
584                 new_entry = 1;
585                 modop = LDAP_MOD_ADD;
586             } else {
587                 expect_modop = 1;       /* missing changetype => modify */
588             }
589         }
590
591         if ( expect_modop ) {
592             expect_modop = 0;
593             expect_sep = 1;
594             if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
595                 modop = LDAP_MOD_ADD;
596                 goto end_line;
597             } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
598                 modop = LDAP_MOD_REPLACE;
599                 addmodifyop( &pmods, modop, value, NULL, 0 );
600                 goto end_line;
601             } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
602                 modop = LDAP_MOD_DELETE;
603                 addmodifyop( &pmods, modop, value, NULL, 0 );
604                 goto end_line;
605             } else {    /* no modify op:  use default */
606                 modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
607             }
608         }
609
610         if ( expect_newrdn ) {
611             if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
612                 if (( newrdn = strdup( value )) == NULL ) {
613                     perror( "strdup" );
614                     exit( EXIT_FAILURE );
615                 }
616                 expect_deleteoldrdn = 1;
617                 expect_newrdn = 0;
618             } else {
619                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
620                         prog, T_NEWRDNSTR, type, linenum, dn );
621                 rc = LDAP_PARAM_ERROR;
622             }
623         } else if ( expect_deleteoldrdn ) {
624             if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
625                 deleteoldrdn = ( *value == '0' ) ? 0 : 1;
626                 expect_deleteoldrdn = 0;
627                 expect_newsup = 1;
628                 got_all = 1;
629             } else {
630                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
631                         prog, T_DELETEOLDRDNSTR, type, linenum, dn );
632                 rc = LDAP_PARAM_ERROR;
633             }
634         } else if ( expect_newsup ) {
635             if ( strcasecmp( type, T_NEWSUPSTR ) == 0 ) {
636                 if (( newsup = strdup( value )) == NULL ) {
637                     perror( "strdup" );
638                     exit( EXIT_FAILURE );
639                 }
640                 expect_newsup = 0;
641             } else {
642                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
643                         prog, T_NEWSUPSTR, type, linenum, dn );
644                 rc = LDAP_PARAM_ERROR;
645             }
646         } else if ( got_all ) {
647             fprintf( stderr,
648                     "%s: extra lines at end (line %d of entry \"%s\")\n",
649                     prog, linenum, dn );
650             rc = LDAP_PARAM_ERROR;
651         } else {
652             addmodifyop( &pmods, modop, type, value, vlen );
653         }
654
655 end_line:
656         ber_memfree( type );
657         ber_memfree( value );
658     }
659
660         if( linenum == 0 ) {
661                 return 0;
662         }
663
664         if( version && linenum == 1 ) {
665                 return 0;
666         }
667
668     if ( rc == 0 ) {
669         if ( delete_entry ) {
670             rc = dodelete( dn );
671         } else if ( newrdn != NULL ) {
672             rc = domodrdn( dn, newrdn, deleteoldrdn );
673         } else {
674             rc = domodify( dn, pmods, new_entry );
675         }
676
677         if ( rc == LDAP_SUCCESS ) {
678             rc = 0;
679         }
680     }
681
682     if ( dn != NULL ) {
683         free( dn );
684     }
685     if ( newrdn != NULL ) {
686         free( newrdn );
687     }
688     if ( pmods != NULL ) {
689         ldap_mods_free( pmods, 1 );
690     }
691
692     return( rc );
693 }
694
695
696 static void
697 addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
698 {
699         LDAPMod         **pmods;
700         int                     i, j;
701         struct berval   *bvp;
702
703         pmods = *pmodsp;
704         modop |= LDAP_MOD_BVALUES;
705
706         i = 0;
707         if ( pmods != NULL ) {
708                 for ( ; pmods[ i ] != NULL; ++i ) {
709                         if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
710                                 pmods[ i ]->mod_op == modop )
711                         {
712                                 break;
713                         }
714                 }
715         }
716
717         if ( pmods == NULL || pmods[ i ] == NULL ) {
718                 if (( pmods = (LDAPMod **)ber_memrealloc( pmods, (i + 2) *
719                         sizeof( LDAPMod * ))) == NULL )
720                 {
721                         perror( "realloc" );
722                         exit( EXIT_FAILURE );
723                 }
724
725                 *pmodsp = pmods;
726                 pmods[ i + 1 ] = NULL;
727
728                 pmods[ i ] = (LDAPMod *)ber_memcalloc( 1, sizeof( LDAPMod ));
729                 if ( pmods[ i ] == NULL ) {
730                         perror( "calloc" );
731                         exit( EXIT_FAILURE );
732                 }
733
734                 pmods[ i ]->mod_op = modop;
735                 pmods[ i ]->mod_type = ber_strdup( attr );
736                 if ( pmods[ i ]->mod_type == NULL ) {
737                         perror( "strdup" );
738                         exit( EXIT_FAILURE );
739                 }
740         }
741
742         if ( value != NULL ) {
743                 j = 0;
744                 if ( pmods[ i ]->mod_bvalues != NULL ) {
745                         for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
746                                 /* Empty */;
747                         }
748                 }
749
750                 pmods[ i ]->mod_bvalues = (struct berval **) ber_memrealloc(
751                         pmods[ i ]->mod_bvalues, (j + 2) * sizeof( struct berval * ));
752                 if ( pmods[ i ]->mod_bvalues == NULL ) {
753                         perror( "ber_realloc" );
754                         exit( EXIT_FAILURE );
755                 }
756
757                 pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
758                 bvp = (struct berval *)ber_memalloc( sizeof( struct berval ));
759                 if ( bvp == NULL ) {
760                         perror( "ber_memalloc" );
761                         exit( EXIT_FAILURE );
762                 }
763                 pmods[ i ]->mod_bvalues[ j ] = bvp;
764
765                 bvp->bv_len = vlen;
766                 bvp->bv_val = (char *)ber_memalloc( vlen + 1 );
767                 if ( bvp->bv_val == NULL ) {
768                         perror( "malloc" );
769                         exit( EXIT_FAILURE );
770                 }
771
772                 SAFEMEMCPY( bvp->bv_val, value, vlen );
773                 bvp->bv_val[ vlen ] = '\0';
774         }
775 }
776
777
778 static int
779 domodify( char *dn, LDAPMod **pmods, int newentry )
780 {
781     int                 i, j, k, notascii, op;
782     struct berval       *bvp;
783
784     if ( pmods == NULL ) {
785         fprintf( stderr, "%s: no attributes to change or add (entry=\"%s\")\n",
786                 prog, dn );
787         return( LDAP_PARAM_ERROR );
788     }
789
790     if ( verbose ) {
791         for ( i = 0; pmods[ i ] != NULL; ++i ) {
792             op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
793             printf( "%s %s:\n", op == LDAP_MOD_REPLACE ?
794                     "replace" : op == LDAP_MOD_ADD ?
795                     "add" : "delete", pmods[ i ]->mod_type );
796             if ( pmods[ i ]->mod_bvalues != NULL ) {
797                 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
798                     bvp = pmods[ i ]->mod_bvalues[ j ];
799                     notascii = 0;
800                     for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
801                         if ( !isascii( bvp->bv_val[ k ] )) {
802                             notascii = 1;
803                             break;
804                         }
805                     }
806                     if ( notascii ) {
807                         printf( "\tNOT ASCII (%ld bytes)\n", bvp->bv_len );
808                     } else {
809                         printf( "\t%s\n", bvp->bv_val );
810                     }
811                 }
812             }
813         }
814     }
815
816     if ( newentry ) {
817         printf( "%sadding new entry \"%s\"\n", not ? "!" : "", dn );
818     } else {
819         printf( "%smodifying entry \"%s\"\n", not ? "!" : "", dn );
820     }
821
822     if ( !not ) {
823         if ( newentry ) {
824             i = ldap_add_s( ld, dn, pmods );
825         } else {
826             i = ldap_modify_s( ld, dn, pmods );
827         }
828         if ( i != LDAP_SUCCESS ) {
829             ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
830         } else if ( verbose ) {
831             printf( "modify complete\n" );
832         }
833     } else {
834         i = LDAP_SUCCESS;
835     }
836
837     putchar( '\n' );
838
839     return( i );
840 }
841
842
843 static int
844 dodelete( char *dn )
845 {
846     int rc;
847
848     printf( "%sdeleting entry \"%s\"\n", not ? "!" : "", dn );
849     if ( !not ) {
850         if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
851             ldap_perror( ld, "ldap_delete" );
852         } else if ( verbose ) {
853             printf( "delete complete" );
854         }
855     } else {
856         rc = LDAP_SUCCESS;
857     }
858
859     putchar( '\n' );
860
861     return( rc );
862 }
863
864
865 static int
866 domodrdn( char *dn, char *newrdn, int deleteoldrdn )
867 {
868     int rc;
869
870
871     printf( "%smodifying rdn of entry \"%s\"\n", not ? "!" : "", dn );
872     if ( verbose ) {
873         printf( "\tnew RDN: \"%s\" (%skeep existing values)\n",
874                 newrdn, deleteoldrdn ? "do not " : "" );
875     }
876     if ( !not ) {
877         if (( rc = ldap_modrdn2_s( ld, dn, newrdn, deleteoldrdn ))
878                 != LDAP_SUCCESS ) {
879             ldap_perror( ld, "ldap_modrdn" );
880         } else {
881             printf( "modrdn completed\n" );
882         }
883     } else {
884         rc = LDAP_SUCCESS;
885     }
886
887     putchar( '\n' );
888
889     return( rc );
890 }
891
892
893 static char *
894 read_one_record( FILE *fp )
895 {
896     char        *buf, line[ LDAPMOD_MAXLINE ];
897     int         lcur, lmax;
898
899     lcur = lmax = 0;
900     buf = NULL;
901
902     while ( fgets( line, sizeof(line), fp ) != NULL ) {
903         int len = strlen( line );
904
905                 if( len < 2 ) {
906                         if( buf == NULL ) {
907                                 continue;
908                         } else {
909                                 break;
910                         }
911                 }
912
913                 if ( lcur + len + 1 > lmax ) {
914                         lmax = LDAPMOD_MAXLINE
915                                 * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
916
917                         if (( buf = (char *)realloc( buf, lmax )) == NULL ) {
918                                 perror( "realloc" );
919                                 exit( EXIT_FAILURE );
920                         }
921                 }
922
923                 strcpy( buf + lcur, line );
924                 lcur += len;
925     }
926
927     return( buf );
928 }