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