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