]> git.sur5r.net Git - openldap/blob - clients/tools/ldapmodify.c
Use provided macros and comment
[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\trequest the use of TLS (-ZZ to make it critical)\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( 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         if ( authmethod == LDAP_AUTH_SASL ) {
389 #ifdef HAVE_CYRUS_SASL
390                 int     minssf = 0, maxssf = 0;
391
392                 if ( sasl_integrity > 0 )
393                         maxssf = 1;
394                 if ( sasl_integrity > 1 )
395                         minssf = 1;
396                 if ( sasl_privacy > 0 )
397                         maxssf = 100000; /* Something big value */
398                 if ( sasl_privacy > 1 )
399                         minssf = 56;
400                 
401                 if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MINSSF,
402                         (void *)&minssf ) != LDAP_OPT_SUCCESS ) {
403                         fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MINSSF"
404                                 "%d\n", minssf);
405                         return( EXIT_FAILURE );
406                 }
407                 if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MAXSSF,
408                         (void *)&maxssf ) != LDAP_OPT_SUCCESS ) {
409                         fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MINSSF"
410                                 "%d\n", minssf);
411                         return( EXIT_FAILURE );
412                 }
413                 
414                 rc = ldap_negotiated_sasl_bind_s( ld, binddn, sasl_authc_id,
415                                 sasl_authz_id, sasl_mech,
416                                 passwd.bv_len ? &passwd : NULL,
417                                 NULL, NULL );
418
419                 if( rc != LDAP_SUCCESS ) {
420                         ldap_perror( ld, "ldap_negotiated_sasl_bind_s" );
421                         return( EXIT_FAILURE );
422                 }
423 #else
424                 fprintf( stderr, "%s was not compiled with SASL support\n",
425                         argv[0] );
426                 return( EXIT_FAILURE );
427 #endif
428         }
429         else {
430                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
431                                 != LDAP_SUCCESS ) {
432                         ldap_perror( ld, "ldap_bind" );
433                         return( EXIT_FAILURE );
434                 }
435         }
436
437     }
438
439     rc = 0;
440
441         if ( manageDSAit ) {
442                 int err;
443                 LDAPControl c;
444                 LDAPControl *ctrls[2];
445                 ctrls[0] = &c;
446                 ctrls[1] = NULL;
447
448                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
449                 c.ldctl_value.bv_val = NULL;
450                 c.ldctl_value.bv_len = 0;
451                 c.ldctl_iscritical = manageDSAit > 1;
452
453                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, &ctrls );
454
455                 if( err != LDAP_OPT_SUCCESS ) {
456                         fprintf( stderr, "Could not set Manage DSA IT Control\n" );
457                         if( c.ldctl_iscritical ) {
458                                 exit( EXIT_FAILURE );
459                         }
460                 }
461         }
462
463         count = 0;
464     while (( rc == 0 || contoper ) &&
465                 ( rbuf = read_one_record( fp )) != NULL ) {
466         count++;
467         /*
468          * we assume record is ldif/slapd.replog if the first line
469          * has a colon that appears to the left of any equal signs, OR
470          * if the first line consists entirely of digits (an entry id)
471          */
472 #ifdef LDAP_LDIF
473         use_ldif = 1;
474 #else
475         use_ldif = ( *rbuf == '#' ) ||
476                 (( p = strchr( rbuf, ':' )) != NULL &&
477                 (  q = strchr( rbuf, '\n' )) != NULL && p < q &&
478                 (( q = strchr( rbuf, '=' )) == NULL || p < q ));
479 #endif
480
481         start = rbuf;
482
483         if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) {
484             for ( p = rbuf; p < q; ++p ) {
485                 if ( !isdigit( (unsigned char) *p )) {
486                     break;
487                 }
488             }
489             if ( p >= q ) {
490                 use_ldif = 1;
491                 start = q + 1;
492             }
493         }
494
495         if ( use_ldif ) {
496             rc = process_ldif_rec( start, count );
497         } else {
498             rc = process_ldapmod_rec( start );
499         }
500
501         if( rc )
502             fprintf( stderr, "%s() = %d\n",
503                      use_ldif ? "ldif_rec" : "ldapmod_rec" , rc );
504
505         free( rbuf );
506     }
507
508     if ( !not ) {
509         ldap_unbind( ld );
510     }
511
512         return( rc );
513 }
514
515
516 static int
517 process_ldif_rec( char *rbuf, int count )
518 {
519     char        *line, *dn, *type, *value, *newrdn, *newsup, *p;
520     int         rc, linenum, modop, replicaport;
521         ber_len_t vlen;
522     int         expect_modop, expect_sep, expect_ct, expect_newrdn, expect_newsup;
523     int         expect_deleteoldrdn, deleteoldrdn;
524     int         saw_replica, use_record, new_entry, delete_entry, got_all;
525     LDAPMod     **pmods;
526         int version;
527
528     new_entry = new;
529
530     rc = got_all = saw_replica = delete_entry = modop = expect_modop = 0;
531     expect_deleteoldrdn = expect_newrdn = expect_newsup = 0;
532         expect_sep = expect_ct = 0;
533     linenum = 0;
534         version = 0;
535     deleteoldrdn = 1;
536     use_record = force;
537     pmods = NULL;
538     dn = newrdn = newsup = NULL;
539
540     while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
541         ++linenum;
542
543         if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
544             expect_sep = 0;
545             expect_ct = 1;
546             continue;
547         }
548         
549         if ( ldif_parse_line( line, &type, &value, &vlen ) < 0 ) {
550             fprintf( stderr, "%s: invalid format (line %d) entry: \"%s\"\n",
551                     prog, linenum, dn == NULL ? "" : dn );
552             rc = LDAP_PARAM_ERROR;
553             break;
554         }
555
556         if ( dn == NULL ) {
557             if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
558                 ++saw_replica;
559                 if (( p = strchr( value, ':' )) == NULL ) {
560                     replicaport = 0;
561                 } else {
562                     *p++ = '\0';
563                     replicaport = atoi( p );
564                 }
565                 if ( ldaphost != NULL && strcasecmp( value, ldaphost ) == 0 &&
566                         replicaport == ldapport ) {
567                     use_record = 1;
568                 }
569             } else if ( count == 1 && linenum == 1 && 
570                         strcasecmp( type, T_VERSION_STR ) == 0 )
571                 {
572                         if( vlen == 0 || atoi(value) != 1 ) {
573                         fprintf( stderr, "%s: invalid version %s, line %d (ignored)\n",
574                                 prog, value == NULL ? "(null)" : value, linenum );
575                         }
576                         version++;
577
578             } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
579                 if (( dn = strdup( value ? value : "" )) == NULL ) {
580                     perror( "strdup" );
581                     exit( EXIT_FAILURE );
582                 }
583                 expect_ct = 1;
584             }
585             goto end_line;      /* skip all lines until we see "dn:" */
586         }
587
588         if ( expect_ct ) {
589             expect_ct = 0;
590             if ( !use_record && saw_replica ) {
591                 printf( "%s: skipping change record for entry: %s\n"
592                         "\t(LDAP host/port does not match replica: lines)\n",
593                         prog, dn );
594                 free( dn );
595                 ber_memfree( type );
596                 ber_memfree( value );
597                 return( 0 );
598             }
599
600             if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
601                 if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) {
602                         new_entry = 0;
603                         expect_modop = 1;
604                 } else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) {
605                         new_entry = 1;
606                 } else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0
607                         || strcasecmp( value, T_MODDNCTSTR ) == 0
608                         || strcasecmp( value, T_RENAMECTSTR ) == 0)
609                 {
610                     expect_newrdn = 1;
611                 } else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) {
612                     got_all = delete_entry = 1;
613                 } else {
614                     fprintf( stderr,
615                             "%s:  unknown %s \"%s\" (line %d of entry \"%s\")\n",
616                             prog, T_CHANGETYPESTR, value, linenum, dn );
617                     rc = LDAP_PARAM_ERROR;
618                 }
619                 goto end_line;
620             } else if ( new ) {         /*  missing changetype => add */
621                 new_entry = 1;
622                 modop = LDAP_MOD_ADD;
623             } else {
624                 expect_modop = 1;       /* missing changetype => modify */
625             }
626         }
627
628         if ( expect_modop ) {
629             expect_modop = 0;
630             expect_sep = 1;
631             if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
632                 modop = LDAP_MOD_ADD;
633                 goto end_line;
634             } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
635                 modop = LDAP_MOD_REPLACE;
636                 addmodifyop( &pmods, modop, value, NULL, 0 );
637                 goto end_line;
638             } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
639                 modop = LDAP_MOD_DELETE;
640                 addmodifyop( &pmods, modop, value, NULL, 0 );
641                 goto end_line;
642             } else {    /* no modify op:  use default */
643                 modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
644             }
645         }
646
647         if ( expect_newrdn ) {
648             if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
649                 if (( newrdn = strdup( value )) == NULL ) {
650                     perror( "strdup" );
651                     exit( EXIT_FAILURE );
652                 }
653                 expect_deleteoldrdn = 1;
654                 expect_newrdn = 0;
655             } else {
656                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
657                         prog, T_NEWRDNSTR, type, linenum, dn );
658                 rc = LDAP_PARAM_ERROR;
659             }
660         } else if ( expect_deleteoldrdn ) {
661             if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
662                 deleteoldrdn = ( *value == '0' ) ? 0 : 1;
663                 expect_deleteoldrdn = 0;
664                 expect_newsup = 1;
665                 got_all = 1;
666             } else {
667                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
668                         prog, T_DELETEOLDRDNSTR, type, linenum, dn );
669                 rc = LDAP_PARAM_ERROR;
670             }
671         } else if ( expect_newsup ) {
672             if ( strcasecmp( type, T_NEWSUPSTR ) == 0 ) {
673                 if (( newsup = strdup( value )) == NULL ) {
674                     perror( "strdup" );
675                     exit( EXIT_FAILURE );
676                 }
677                 expect_newsup = 0;
678             } else {
679                 fprintf( stderr, "%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry \"%s\")\n",
680                         prog, T_NEWSUPSTR, type, linenum, dn );
681                 rc = LDAP_PARAM_ERROR;
682             }
683         } else if ( got_all ) {
684             fprintf( stderr,
685                     "%s: extra lines at end (line %d of entry \"%s\")\n",
686                     prog, linenum, dn );
687             rc = LDAP_PARAM_ERROR;
688         } else {
689             addmodifyop( &pmods, modop, type, value, vlen );
690         }
691
692 end_line:
693         ber_memfree( type );
694         ber_memfree( value );
695     }
696
697         if( linenum == 0 ) {
698                 return 0;
699         }
700
701         if( version && linenum == 1 ) {
702                 return 0;
703         }
704
705     if ( rc == 0 ) {
706         if ( delete_entry ) {
707             rc = dodelete( dn );
708         } else if ( newrdn != NULL ) {
709             rc = domodrdn( dn, newrdn, deleteoldrdn );
710         } else {
711             rc = domodify( dn, pmods, new_entry );
712         }
713
714         if ( rc == LDAP_SUCCESS ) {
715             rc = 0;
716         }
717     }
718
719     if ( dn != NULL ) {
720         free( dn );
721     }
722     if ( newrdn != NULL ) {
723         free( newrdn );
724     }
725     if ( pmods != NULL ) {
726         ldap_mods_free( pmods, 1 );
727     }
728
729     return( rc );
730 }
731
732
733 static int
734 process_ldapmod_rec( char *rbuf )
735 {
736     char        *line, *dn, *p, *q, *attr, *value;
737     int         rc, linenum, modop;
738     LDAPMod     **pmods;
739
740     pmods = NULL;
741     dn = NULL;
742     linenum = 0;
743     line = rbuf;
744     rc = 0;
745
746     while ( rc == 0 && rbuf != NULL && *rbuf != '\0' ) {
747         ++linenum;
748         if (( p = strchr( rbuf, '\n' )) == NULL ) {
749             rbuf = NULL;
750         } else {
751             if ( *(p-1) == '\\' ) {     /* lines ending in '\' are continued */
752                 SAFEMEMCPY( p - 1, p, strlen( p ) + 1 );
753                 rbuf = p;
754                 continue;
755             }
756             *p++ = '\0';
757             rbuf = p;
758         }
759
760         if ( dn == NULL ) {     /* first line contains DN */
761             if (( dn = strdup( line )) == NULL ) {
762                 perror( "strdup" );
763                 exit( EXIT_FAILURE );
764             }
765         } else {
766             if (( p = strchr( line, '=' )) == NULL ) {
767                 value = NULL;
768                 p = line + strlen( line );
769             } else {
770                 *p++ = '\0';
771                 value = p;
772             }
773
774             for ( attr = line;
775                   *attr != '\0' && isspace( (unsigned char) *attr ); ++attr ) {
776                 ;       /* skip attribute leading white space */
777             }
778
779             for ( q = p - 1; q > attr && isspace( (unsigned char) *q ); --q ) {
780                 *q = '\0';      /* remove attribute trailing white space */
781             }
782
783             if ( value != NULL ) {
784                 while ( isspace( (unsigned char) *value )) {
785                     ++value;            /* skip value leading white space */
786                 }
787                 for ( q = value + strlen( value ) - 1; q > value &&
788                         isspace( (unsigned char) *q ); --q ) {
789                     *q = '\0';  /* remove value trailing white space */
790                 }
791                 if ( *value == '\0' ) {
792                     value = NULL;
793                 }
794
795             }
796
797             if ( value == NULL && new ) {
798                 fprintf( stderr, "%s: missing value on line %d (attr=\"%s\")\n",
799                         prog, linenum, attr );
800                 rc = LDAP_PARAM_ERROR;
801             } else {
802                  switch ( *attr ) {
803                 case '-':
804                     modop = LDAP_MOD_DELETE;
805                     ++attr;
806                     break;
807                 case '+':
808                     modop = LDAP_MOD_ADD;
809                     ++attr;
810                     break;
811                 default:
812                     modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
813                 }
814
815                 addmodifyop( &pmods, modop, attr, value,
816                         ( value == NULL ) ? 0 : strlen( value ));
817             }
818         }
819
820         line = rbuf;
821     }
822
823     if ( rc == 0 ) {
824         if ( dn == NULL ) {
825             rc = LDAP_PARAM_ERROR;
826         } else if (( rc = domodify( dn, pmods, new )) == LDAP_SUCCESS ) {
827             rc = 0;
828         }
829     }
830
831     if ( pmods != NULL ) {
832         ldap_mods_free( pmods, 1 );
833     }
834     if ( dn != NULL ) {
835         free( dn );
836     }
837
838     return( rc );
839 }
840
841
842 static void
843 addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
844 {
845     LDAPMod             **pmods;
846     int                 i, j;
847     struct berval       *bvp;
848
849     pmods = *pmodsp;
850     modop |= LDAP_MOD_BVALUES;
851
852     i = 0;
853     if ( pmods != NULL ) {
854         for ( ; pmods[ i ] != NULL; ++i ) {
855             if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
856                     pmods[ i ]->mod_op == modop ) {
857                 break;
858             }
859         }
860     }
861
862     if ( pmods == NULL || pmods[ i ] == NULL ) {
863         if (( pmods = (LDAPMod **)ber_memrealloc( pmods, (i + 2) *
864                 sizeof( LDAPMod * ))) == NULL ) {
865             perror( "realloc" );
866             exit( EXIT_FAILURE );
867         }
868         *pmodsp = pmods;
869         pmods[ i + 1 ] = NULL;
870         if (( pmods[ i ] = (LDAPMod *)ber_memcalloc( 1, sizeof( LDAPMod )))
871                 == NULL ) {
872             perror( "calloc" );
873             exit( EXIT_FAILURE );
874         }
875         pmods[ i ]->mod_op = modop;
876         if (( pmods[ i ]->mod_type = ber_strdup( attr )) == NULL ) {
877             perror( "strdup" );
878             exit( EXIT_FAILURE );
879         }
880     }
881
882     if ( value != NULL ) {
883         j = 0;
884         if ( pmods[ i ]->mod_bvalues != NULL ) {
885             for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
886                 ;
887             }
888         }
889         if (( pmods[ i ]->mod_bvalues =
890                 (struct berval **)ber_memrealloc( pmods[ i ]->mod_bvalues,
891                 (j + 2) * sizeof( struct berval * ))) == NULL ) {
892             perror( "ber_realloc" );
893             exit( EXIT_FAILURE );
894         }
895         pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
896         if (( bvp = (struct berval *)ber_memalloc( sizeof( struct berval )))
897                 == NULL ) {
898             perror( "ber_memalloc" );
899             exit( EXIT_FAILURE );
900         }
901         pmods[ i ]->mod_bvalues[ j ] = bvp;
902
903         if ( valsfromfiles && *value == '/' ) { /* get value from file */
904             if ( fromfile( value, bvp ) < 0 ) {
905                 exit( EXIT_FAILURE );
906             }
907         } else {
908             bvp->bv_len = vlen;
909             if (( bvp->bv_val = (char *)ber_memalloc( vlen + 1 )) == NULL ) {
910                 perror( "malloc" );
911                 exit( EXIT_FAILURE );
912             }
913             SAFEMEMCPY( bvp->bv_val, value, vlen );
914             bvp->bv_val[ vlen ] = '\0';
915         }
916     }
917 }
918
919
920 static int
921 domodify( char *dn, LDAPMod **pmods, int newentry )
922 {
923     int                 i, j, k, notascii, op;
924     struct berval       *bvp;
925
926     if ( pmods == NULL ) {
927         fprintf( stderr, "%s: no attributes to change or add (entry=\"%s\")\n",
928                 prog, dn );
929         return( LDAP_PARAM_ERROR );
930     }
931
932     if ( verbose ) {
933         for ( i = 0; pmods[ i ] != NULL; ++i ) {
934             op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
935             printf( "%s %s:\n", op == LDAP_MOD_REPLACE ?
936                     "replace" : op == LDAP_MOD_ADD ?
937                     "add" : "delete", pmods[ i ]->mod_type );
938             if ( pmods[ i ]->mod_bvalues != NULL ) {
939                 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
940                     bvp = pmods[ i ]->mod_bvalues[ j ];
941                     notascii = 0;
942                     for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
943                         if ( !isascii( bvp->bv_val[ k ] )) {
944                             notascii = 1;
945                             break;
946                         }
947                     }
948                     if ( notascii ) {
949                         printf( "\tNOT ASCII (%ld bytes)\n", bvp->bv_len );
950                     } else {
951                         printf( "\t%s\n", bvp->bv_val );
952                     }
953                 }
954             }
955         }
956     }
957
958     if ( newentry ) {
959         printf( "%sadding new entry \"%s\"\n", not ? "!" : "", dn );
960     } else {
961         printf( "%smodifying entry \"%s\"\n", not ? "!" : "", dn );
962     }
963
964     if ( !not ) {
965         if ( newentry ) {
966             i = ldap_add_s( ld, dn, pmods );
967         } else {
968             i = ldap_modify_s( ld, dn, pmods );
969         }
970         if ( i != LDAP_SUCCESS ) {
971             ldap_perror( ld, newentry ? "ldap_add" : "ldap_modify" );
972         } else if ( verbose ) {
973             printf( "modify complete\n" );
974         }
975     } else {
976         i = LDAP_SUCCESS;
977     }
978
979     putchar( '\n' );
980
981     return( i );
982 }
983
984
985 static int
986 dodelete( char *dn )
987 {
988     int rc;
989
990     printf( "%sdeleting entry \"%s\"\n", not ? "!" : "", dn );
991     if ( !not ) {
992         if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
993             ldap_perror( ld, "ldap_delete" );
994         } else if ( verbose ) {
995             printf( "delete complete" );
996         }
997     } else {
998         rc = LDAP_SUCCESS;
999     }
1000
1001     putchar( '\n' );
1002
1003     return( rc );
1004 }
1005
1006
1007 static int
1008 domodrdn( char *dn, char *newrdn, int deleteoldrdn )
1009 {
1010     int rc;
1011
1012
1013     printf( "%smodifying rdn of entry \"%s\"\n", not ? "!" : "", dn );
1014     if ( verbose ) {
1015         printf( "\tnew RDN: \"%s\" (%skeep existing values)\n",
1016                 newrdn, deleteoldrdn ? "do not " : "" );
1017     }
1018     if ( !not ) {
1019         if (( rc = ldap_modrdn2_s( ld, dn, newrdn, deleteoldrdn ))
1020                 != LDAP_SUCCESS ) {
1021             ldap_perror( ld, "ldap_modrdn" );
1022         } else {
1023             printf( "modrdn completed\n" );
1024         }
1025     } else {
1026         rc = LDAP_SUCCESS;
1027     }
1028
1029     putchar( '\n' );
1030
1031     return( rc );
1032 }
1033
1034
1035 static int
1036 fromfile( char *path, struct berval *bv )
1037 {
1038         FILE            *fp;
1039         long            rlen;
1040         int             eof;
1041
1042         if (( fp = fopen( path, "r" )) == NULL ) {
1043                 perror( path );
1044                 return( -1 );
1045         }
1046
1047         if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
1048                 perror( path );
1049                 fclose( fp );
1050                 return( -1 );
1051         }
1052
1053         bv->bv_len = ftell( fp );
1054
1055         if (( bv->bv_val = (char *)ber_memalloc( bv->bv_len )) == NULL ) {
1056                 perror( "malloc" );
1057                 fclose( fp );
1058                 return( -1 );
1059         }
1060
1061         if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
1062                 perror( path );
1063                 fclose( fp );
1064                 ber_memfree( bv->bv_val );
1065                 bv->bv_val = NULL;
1066                 return( -1 );
1067         }
1068
1069         rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
1070         eof = feof( fp );
1071         fclose( fp );
1072
1073         if ( (unsigned long) rlen != bv->bv_len ) {
1074                 perror( path );
1075                 ber_memfree( bv->bv_val );
1076                 bv->bv_val = NULL;
1077                 return( -1 );
1078         }
1079
1080         return( bv->bv_len );
1081 }
1082
1083
1084 static char *
1085 read_one_record( FILE *fp )
1086 {
1087     char        *buf, line[ LDAPMOD_MAXLINE ];
1088     int         lcur, lmax;
1089
1090     lcur = lmax = 0;
1091     buf = NULL;
1092
1093     while ( fgets( line, sizeof(line), fp ) != NULL ) {
1094         int len = strlen( line );
1095
1096                 if( len < 2 ) {
1097                         if( buf == NULL ) {
1098                                 continue;
1099                         } else {
1100                                 break;
1101                         }
1102                 }
1103
1104                 if ( lcur + len + 1 > lmax ) {
1105                         lmax = LDAPMOD_MAXLINE
1106                                 * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
1107
1108                         if (( buf = (char *)realloc( buf, lmax )) == NULL ) {
1109                                 perror( "realloc" );
1110                                 exit( EXIT_FAILURE );
1111                         }
1112                 }
1113
1114                 strcpy( buf + lcur, line );
1115                 lcur += len;
1116     }
1117
1118     return( buf );
1119 }