]> git.sur5r.net Git - openldap/blob - clients/tools/ldapmodify.c
Added -llber 'N' ber_printf format which inserts a NULL if
[openldap] / clients / tools / ldapmodify.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* ldapmodify.c - generic program to modify or add entries using LDAP */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/stdlib.h>
13
14 #include <ac/ctype.h>
15 #include <ac/signal.h>
16 #include <ac/string.h>
17 #include <ac/unistd.h>
18
19 #ifdef HAVE_SYS_STAT_H
20 #include <sys/stat.h>
21 #endif
22
23 #ifdef HAVE_SYS_FILE_H
24 #include <sys/file.h>
25 #endif
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29
30 #include <ldap.h>
31
32 #include "ldif.h"
33 #include "ldap_defaults.h"
34
35 static char     *prog;
36 static char     *binddn = NULL;
37 static struct berval passwd = { 0, NULL};
38 static char     *ldaphost = NULL;
39 static int      ldapport = 0;
40 #ifdef HAVE_CYRUS_SASL
41 static char     *sasl_authc_id = NULL;
42 static char     *sasl_authz_id = NULL;
43 static char     *sasl_mech = NULL;
44 static int      sasl_integrity = 0;
45 static int      sasl_privacy = 0;
46 #endif
47 static int      use_tls = 0;
48 static int      new, replace, not, verbose, contoper, force, valsfromfiles;
49 static LDAP     *ld;
50
51 #define LDAPMOD_MAXLINE         4096
52
53 /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
54 #define T_VERSION_STR           "version"
55 #define T_REPLICA_STR           "replica"
56 #define T_DN_STR                "dn"
57 #define T_CHANGETYPESTR         "changetype"
58 #define T_ADDCTSTR              "add"
59 #define T_MODIFYCTSTR           "modify"
60 #define T_DELETECTSTR           "delete"
61 #define T_MODRDNCTSTR           "modrdn"
62 #define T_MODDNCTSTR            "moddn"
63 #define T_RENAMECTSTR           "rename"
64 #define T_MODOPADDSTR           "add"
65 #define T_MODOPREPLACESTR       "replace"
66 #define T_MODOPDELETESTR        "delete"
67 #define T_MODSEPSTR             "-"
68 #define T_NEWRDNSTR             "newrdn"
69 #define T_DELETEOLDRDNSTR       "deleteoldrdn"
70 #define T_NEWSUPSTR             "newsuperior"
71
72
73 static void usage LDAP_P(( const char *prog )) LDAP_GCCATTR((noreturn));
74 static int process_ldapmod_rec LDAP_P(( char *rbuf ));
75 static int process_ldif_rec LDAP_P(( char *rbuf, int count ));
76 static void addmodifyop LDAP_P(( LDAPMod ***pmodsp, int modop, char *attr,
77         char *value, int vlen ));
78 static int domodify LDAP_P(( char *dn, LDAPMod **pmods, int newentry ));
79 static int dodelete LDAP_P(( char *dn ));
80 static int domodrdn LDAP_P(( char *dn, char *newrdn, int deleteoldrdn ));
81 static int fromfile LDAP_P(( char *path, struct berval *bv ));
82 static char *read_one_record LDAP_P(( FILE *fp ));
83
84 static void
85 usage( const char *prog )
86 {
87     fprintf( stderr,
88 "Add or modify entries from an LDAP server\n\n"
89 "usage: %s [options]\n"
90 "       The list of desired operations are read from stdin or from the file\n"
91 "       specified by \"-f file\".\n"
92 "options:\n"
93 "       -a\t\tadd values (default%s)\n"
94 "       -b\t\tread values from files (for binary attributes)\n"
95 "       -c\t\tcontinuous operation\n"
96 "       -d level\tset LDAP debugging level to `level'\n"
97 "       -D dn\t\tbind DN\n"
98 "       -E\t\trequest SASL privacy (-EE to make it critical)\n"
99 "       -f file\t\tperform sequence of operations listed in file\n"
100 "       -F\t\tforce all changes records to be used\n"
101 "       -h host\t\tLDAP server\n"
102 "       -I\t\trequest SASL integrity checking (-II to make it\n"
103 "               \tcritical)\n"
104 "       -k\t\tuse Kerberos authentication\n"
105 "       -K\t\tlike -k, but do only step 1 of the Kerberos bind\n"
106 "       -M\t\tenable Manage DSA IT control (-MM to make it critical)\n"
107 "       -n\t\tprint adds, don't actually do them\n"
108 "       -p port\t\tport on LDAP server\n"
109 "       -r\t\treplace values\n"
110 "       -U user\t\tSASL authentication identity (username)\n"
111 "       -v\t\tverbose mode\n"
112 "       -w passwd\tbind password (for Simple authentication)\n"
113 "       -X id\t\tSASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
114 "       -Y mech\t\tSASL mechanism\n"
115 "       -Z\t\tissue Start TLS request (-ZZ to require successful response)\n"
116              , prog, (strcmp( prog, "ldapadd" ) ? " is to replace" : "") );
117     exit( EXIT_FAILURE );
118 }
119
120
121 int
122 main( int argc, char **argv )
123 {
124     char                *infile, *rbuf, *start, *p, *q;
125     FILE                *fp;
126         int             rc, i, use_ldif, authmethod, version, want_bindpw, debug, manageDSAit;
127         int count;
128
129     if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) {
130         prog = argv[ 0 ];
131     } else {
132         ++prog;
133     }
134
135     /* Print usage when no parameters */
136     if( argc < 2 )
137         usage( prog );
138
139     new = ( strcmp( prog, "ldapadd" ) == 0 );
140
141     infile = NULL;
142     not = verbose = valsfromfiles = want_bindpw = debug = manageDSAit = 0;
143     authmethod = LDAP_AUTH_SIMPLE;
144         version = -1;
145
146     while (( i = getopt( argc, argv, "abcD:d:EFf:h:IKkMnP:p:rtU:vWw:X:Y:Z" )) != EOF ) {
147         switch( i ) {
148         case 'a':       /* add */
149             new = 1;
150             break;
151         case 'b':       /* read values from files (for binary attributes) */
152             valsfromfiles = 1;
153             break;
154         case 'c':       /* continuous operation */
155             contoper = 1;
156             break;
157         case 'r':       /* default is to replace rather than add values */
158             replace = 1;
159             break;
160         case 'k':       /* kerberos bind */
161 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
162                 authmethod = LDAP_AUTH_KRBV4;
163 #else
164                 fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
165                 return( EXIT_FAILURE );
166 #endif
167             break;
168         case 'K':       /* kerberos bind, part 1 only */
169 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
170                 authmethod = LDAP_AUTH_KRBV41;
171 #else
172                 fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
173                 return( EXIT_FAILURE );
174 #endif
175             break;
176         case 'F':       /* force all changes records to be used */
177             force = 1;
178             break;
179         case 'h':       /* ldap host */
180             ldaphost = strdup( optarg );
181             break;
182         case 'D':       /* bind DN */
183             binddn = strdup( optarg );
184             break;
185         case 'w':       /* password */
186             passwd.bv_val = strdup( optarg );
187                 {
188                         char* p;
189
190                         for( p = optarg; *p == '\0'; p++ ) {
191                                 *p = '*';
192                         }
193                 }
194                 passwd.bv_len = strlen( passwd.bv_val );
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_s( 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.bv_val = getpassphrase("Enter LDAP Password: ");
385                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
386         }
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 }