~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to clients/tools/ldapmodify.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ldapmodify.c - generic program to modify or add entries using LDAP */
 
2
/* $OpenLDAP: pkg/ldap/clients/tools/ldapmodify.c,v 1.186.2.7 2008/02/11 23:26:38 kurt Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 1998-2008 The OpenLDAP Foundation.
 
6
 * Portions Copyright 2006 Howard Chu.
 
7
 * Portions Copyright 1998-2003 Kurt D. Zeilenga.
 
8
 * Portions Copyright 1998-2001 Net Boolean Incorporated.
 
9
 * Portions Copyright 2001-2003 IBM Corporation.
 
10
 * All rights reserved.
 
11
 *
 
12
 * Redistribution and use in source and binary forms, with or without
 
13
 * modification, are permitted only as authorized by the OpenLDAP
 
14
 * Public License.
 
15
 *
 
16
 * A copy of this license is available in the file LICENSE in the
 
17
 * top-level directory of the distribution or, alternatively, at
 
18
 * <http://www.OpenLDAP.org/license.html>.
 
19
 */
 
20
/* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
 
21
 * All rights reserved.
 
22
 *
 
23
 * Redistribution and use in source and binary forms are permitted
 
24
 * provided that this notice is preserved and that due credit is given
 
25
 * to the University of Michigan at Ann Arbor.  The name of the
 
26
 * University may not be used to endorse or promote products derived
 
27
 * from this software without specific prior written permission.  This
 
28
 * software is provided ``as is'' without express or implied warranty.
 
29
 */
 
30
/* ACKNOWLEDGEMENTS:
 
31
 * This work was originally developed by the University of Michigan
 
32
 * (as part of U-MICH LDAP).  Additional significant contributors
 
33
 * include:
 
34
 *   Kurt D. Zeilenga
 
35
 *   Norbert Klasen
 
36
 *   Howard Chu
 
37
 */
 
38
 
 
39
#include "portable.h"
 
40
 
 
41
#include <stdio.h>
 
42
 
 
43
#include <ac/stdlib.h>
 
44
#include <ac/ctype.h>
 
45
#include <ac/string.h>
 
46
#include <ac/unistd.h>
 
47
#include <ac/socket.h>
 
48
#include <ac/time.h>
 
49
 
 
50
#ifdef HAVE_SYS_STAT_H
 
51
#include <sys/stat.h>
 
52
#endif
 
53
 
 
54
#ifdef HAVE_SYS_FILE_H
 
55
#include <sys/file.h>
 
56
#endif
 
57
#ifdef HAVE_FCNTL_H
 
58
#include <fcntl.h>
 
59
#endif
 
60
 
 
61
#include <ldap.h>
 
62
 
 
63
#include "lutil.h"
 
64
#include "lutil_ldap.h"
 
65
#include "ldif.h"
 
66
#include "ldap_defaults.h"
 
67
#include "ldap_log.h"
 
68
#include "ldap_pvt.h"
 
69
#include "lber_pvt.h"
 
70
 
 
71
#include "common.h"
 
72
 
 
73
static int      ldapadd;
 
74
static char *rejfile = NULL;
 
75
static LDAP     *ld = NULL;
 
76
 
 
77
#define M_SEP   0x7f
 
78
 
 
79
/* strings found in LDIF entries */
 
80
static struct berval BV_VERSION = BER_BVC("version");
 
81
static struct berval BV_DN = BER_BVC("dn");
 
82
static struct berval BV_CONTROL = BER_BVC("control");
 
83
static struct berval BV_CHANGETYPE = BER_BVC("changetype");
 
84
static struct berval BV_ADDCT = BER_BVC("add");
 
85
static struct berval BV_MODIFYCT = BER_BVC("modify");
 
86
static struct berval BV_DELETECT = BER_BVC("delete");
 
87
static struct berval BV_MODRDNCT = BER_BVC("modrdn");
 
88
static struct berval BV_MODDNCT = BER_BVC("moddn");
 
89
static struct berval BV_RENAMECT = BER_BVC("rename");
 
90
static struct berval BV_MODOPADD = BER_BVC("add");
 
91
static struct berval BV_MODOPREPLACE = BER_BVC("replace");
 
92
static struct berval BV_MODOPDELETE = BER_BVC("delete");
 
93
static struct berval BV_MODOPINCREMENT = BER_BVC("increment");
 
94
static struct berval BV_NEWRDN = BER_BVC("newrdn");
 
95
static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn");
 
96
static struct berval BV_NEWSUP = BER_BVC("newsuperior");
 
97
 
 
98
#define BVICMP(a,b)     ((a)->bv_len != (b)->bv_len ? \
 
99
        (a)->bv_len - (b)->bv_len : strcasecmp((a)->bv_val, (b)->bv_val))
 
100
 
 
101
static int process_ldif_rec LDAP_P(( char *rbuf, int lineno ));
 
102
static int parse_ldif_control LDAP_P(( struct berval *val, LDAPControl ***pctrls ));
 
103
static int domodify LDAP_P((
 
104
        const char *dn,
 
105
        LDAPMod **pmods,
 
106
        LDAPControl **pctrls,
 
107
        int newentry ));
 
108
static int dodelete LDAP_P((
 
109
        const char *dn,
 
110
        LDAPControl **pctrls ));
 
111
static int dorename LDAP_P((
 
112
        const char *dn,
 
113
        const char *newrdn,
 
114
        const char *newsup,
 
115
        int deleteoldrdn,
 
116
        LDAPControl **pctrls ));
 
117
static int process_response(
 
118
        LDAP *ld,
 
119
        int msgid,
 
120
        int res,
 
121
        const char *dn );
 
122
 
 
123
#ifdef LDAP_X_TXN
 
124
static int txn = 0;
 
125
static int txnabort = 0;
 
126
struct berval *txn_id = NULL;
 
127
#endif
 
128
 
 
129
void
 
130
usage( void )
 
131
{
 
132
        fprintf( stderr, _("Add or modify entries from an LDAP server\n\n"));
 
133
        fprintf( stderr, _("usage: %s [options]\n"), prog);
 
134
        fprintf( stderr, _("    The list of desired operations are read from stdin"
 
135
                " or from the file\n"));
 
136
        fprintf( stderr, _("    specified by \"-f file\".\n"));
 
137
        fprintf( stderr, _("Add or modify options:\n"));
 
138
        fprintf( stderr, _("  -a         add values (%s)\n"),
 
139
                (ldapadd ? _("default") : _("default is to replace")));
 
140
        fprintf( stderr, _("  -E [!]ext=extparam        modify extensions"
 
141
                " (! indicate s criticality)\n"));
 
142
#ifdef LDAP_X_TXN
 
143
        fprintf( stderr,
 
144
                _("             [!]txn=<commit|abort>         (transaction)\n"));
 
145
#endif
 
146
        fprintf( stderr, _("  -S file    write skipped modifications to `file'\n"));
 
147
 
 
148
        tool_common_usage();
 
149
        exit( EXIT_FAILURE );
 
150
}
 
151
 
 
152
 
 
153
const char options[] = "aE:rS:"
 
154
        "cd:D:e:f:h:H:IMnO:o:p:P:QR:U:vVw:WxX:y:Y:Z";
 
155
 
 
156
int
 
157
handle_private_option( int i )
 
158
{
 
159
        char    *control, *cvalue;
 
160
        int             crit;
 
161
 
 
162
        switch ( i ) {
 
163
        case 'E': /* modify extensions */
 
164
                if( protocol == LDAP_VERSION2 ) {
 
165
                        fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
 
166
                                prog, protocol );
 
167
                        exit( EXIT_FAILURE );
 
168
                }
 
169
 
 
170
                /* should be extended to support comma separated list of
 
171
                 *      [!]key[=value] parameters, e.g.  -E !foo,bar=567
 
172
                 */
 
173
 
 
174
                crit = 0;
 
175
                cvalue = NULL;
 
176
                if( optarg[0] == '!' ) {
 
177
                        crit = 1;
 
178
                        optarg++;
 
179
                }
 
180
 
 
181
                control = ber_strdup( optarg );
 
182
                if ( (cvalue = strchr( control, '=' )) != NULL ) {
 
183
                        *cvalue++ = '\0';
 
184
                }
 
185
 
 
186
#ifdef LDAP_X_TXN
 
187
                if( strcasecmp( control, "txn" ) == 0 ) {
 
188
                        /* Transaction */
 
189
                        if( txn ) {
 
190
                                fprintf( stderr,
 
191
                                        _("txn control previously specified\n"));
 
192
                                exit( EXIT_FAILURE );
 
193
                        }
 
194
                        if( cvalue != NULL ) {
 
195
                                if( strcasecmp( cvalue, "abort" ) == 0 ) {
 
196
                                        txnabort=1;
 
197
                                } else if( strcasecmp( cvalue, "commit" ) != 0 ) {
 
198
                                        fprintf( stderr, _("Invalid value for txn control, %s\n"),
 
199
                                                cvalue );
 
200
                                        exit( EXIT_FAILURE );
 
201
                                }
 
202
                        }
 
203
 
 
204
                        txn = 1 + crit;
 
205
                } else
 
206
#endif
 
207
                {
 
208
                        fprintf( stderr, _("Invalid modify extension name: %s\n"),
 
209
                                control );
 
210
                        usage();
 
211
                }
 
212
                break;
 
213
 
 
214
        case 'a':       /* add */
 
215
                ldapadd = 1;
 
216
                break;
 
217
 
 
218
        case 'r':       /* replace (obsolete) */
 
219
                break;
 
220
 
 
221
        case 'S':       /* skipped modifications to file */
 
222
                if( rejfile != NULL ) {
 
223
                        fprintf( stderr, _("%s: -S previously specified\n"), prog );
 
224
                        exit( EXIT_FAILURE );
 
225
                }
 
226
                rejfile = ber_strdup( optarg );
 
227
                break;
 
228
 
 
229
        default:
 
230
                return 0;
 
231
        }
 
232
        return 1;
 
233
}
 
234
 
 
235
 
 
236
int
 
237
main( int argc, char **argv )
 
238
{
 
239
        char            *rbuf = NULL, *rejbuf = NULL;
 
240
        FILE            *rejfp;
 
241
        struct LDIFFP *ldiffp, ldifdummy = {0};
 
242
        char            *matched_msg, *error_msg;
 
243
        int             rc, retval;
 
244
        int             len;
 
245
        int             i = 0;
 
246
        int             lineno, nextline = 0, lmax = 0;
 
247
        LDAPControl     c[1];
 
248
 
 
249
        prog = lutil_progname( "ldapmodify", argc, argv );
 
250
 
 
251
        /* strncmp instead of strcmp since NT binaries carry .exe extension */
 
252
        ldapadd = ( strncasecmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 );
 
253
 
 
254
        tool_init( ldapadd ? TOOL_ADD : TOOL_MODIFY );
 
255
 
 
256
        tool_args( argc, argv );
 
257
 
 
258
        if ( argc != optind ) usage();
 
259
 
 
260
        if ( rejfile != NULL ) {
 
261
                if (( rejfp = fopen( rejfile, "w" )) == NULL ) {
 
262
                        perror( rejfile );
 
263
                        return( EXIT_FAILURE );
 
264
                }
 
265
        } else {
 
266
                rejfp = NULL;
 
267
        }
 
268
 
 
269
        if ( infile != NULL ) {
 
270
                if (( ldiffp = ldif_open( infile, "r" )) == NULL ) {
 
271
                        perror( infile );
 
272
                        return( EXIT_FAILURE );
 
273
                }
 
274
        } else {
 
275
                ldifdummy.fp = stdin;
 
276
                ldiffp = &ldifdummy;
 
277
        }
 
278
 
 
279
        if ( debug ) ldif_debug = debug;
 
280
 
 
281
        ld = tool_conn_setup( dont, 0 );
 
282
 
 
283
        if ( !dont ) {
 
284
                if ( pw_file || want_bindpw ) {
 
285
                        if ( pw_file ) {
 
286
                                rc = lutil_get_filed_password( pw_file, &passwd );
 
287
                                if( rc ) return EXIT_FAILURE;
 
288
                        } else {
 
289
                                passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") );
 
290
                                passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
 
291
                        }
 
292
                }
 
293
                tool_bind( ld );
 
294
        }
 
295
 
 
296
#ifdef LDAP_X_TXN
 
297
        if( txn ) {
 
298
                /* start transaction */
 
299
                rc = ldap_txn_start_s( ld, NULL, NULL, &txn_id );
 
300
                if( rc != LDAP_SUCCESS ) {
 
301
                        tool_perror( "ldap_txn_start_s", rc, NULL, NULL, NULL, NULL );
 
302
                        if( txn > 1 ) return EXIT_FAILURE;
 
303
                        txn = 0;
 
304
                }
 
305
        }
 
306
#endif
 
307
 
 
308
        if ( 0
 
309
#ifdef LDAP_X_TXN
 
310
                || txn
 
311
#endif
 
312
                )
 
313
        {
 
314
#ifdef LDAP_X_TXN
 
315
                if( txn ) {
 
316
                        c[i].ldctl_oid = LDAP_CONTROL_X_TXN_SPEC;
 
317
                        c[i].ldctl_value = *txn_id;
 
318
                        c[i].ldctl_iscritical = 1;
 
319
                        i++;
 
320
                }
 
321
#endif
 
322
        }
 
323
 
 
324
        tool_server_controls( ld, c, i );
 
325
 
 
326
        rc = 0;
 
327
        retval = 0;
 
328
        lineno = 1;
 
329
        while (( rc == 0 || contoper ) && ldif_read_record( ldiffp, &nextline,
 
330
                &rbuf, &lmax ))
 
331
        {
 
332
                if ( rejfp ) {
 
333
                        len = strlen( rbuf );
 
334
                        if (( rejbuf = (char *)ber_memalloc( len+1 )) == NULL ) {
 
335
                                perror( "malloc" );
 
336
                                exit( EXIT_FAILURE );
 
337
                        }
 
338
                        memcpy( rejbuf, rbuf, len+1 );
 
339
                }
 
340
 
 
341
                rc = process_ldif_rec( rbuf, lineno );
 
342
                lineno = nextline+1;
 
343
 
 
344
                if ( rc ) retval = rc;
 
345
                if ( rc && rejfp ) {
 
346
                        fprintf(rejfp, _("# Error: %s (%d)"), ldap_err2string(rc), rc);
 
347
 
 
348
                        matched_msg = NULL;
 
349
                        ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg);
 
350
                        if ( matched_msg != NULL ) {
 
351
                                if ( *matched_msg != '\0' ) {
 
352
                                        fprintf( rejfp, _(", matched DN: %s"), matched_msg );
 
353
                                }
 
354
                                ldap_memfree( matched_msg );
 
355
                        }
 
356
 
 
357
                        error_msg = NULL;
 
358
                        ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &error_msg);
 
359
                        if ( error_msg != NULL ) {
 
360
                                if ( *error_msg != '\0' ) {
 
361
                                        fprintf( rejfp, _(", additional info: %s"), error_msg );
 
362
                                }
 
363
                                ldap_memfree( error_msg );
 
364
                        }
 
365
                        fprintf( rejfp, "\n%s\n", rejbuf );
 
366
                }
 
367
 
 
368
                if (rejfp) ber_memfree( rejbuf );
 
369
        }
 
370
        ber_memfree( rbuf );
 
371
 
 
372
#ifdef LDAP_X_TXN
 
373
        if( retval == 0 && txn ) {
 
374
                rc = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, NULL );
 
375
                if ( rc != LDAP_OPT_SUCCESS ) {
 
376
                        fprintf( stderr, "Could not unset controls for ldap_txn_end\n");
 
377
                }
 
378
 
 
379
                /* create transaction */
 
380
                rc = ldap_txn_end_s( ld, !txnabort, txn_id, NULL, NULL, NULL );
 
381
                if( rc != LDAP_SUCCESS ) {
 
382
                        tool_perror( "ldap_txn_end_s", rc, NULL, NULL, NULL, NULL );
 
383
                        retval = rc;
 
384
                }
 
385
        }
 
386
#endif
 
387
 
 
388
        if ( !dont ) {
 
389
                tool_unbind( ld );
 
390
        }
 
391
 
 
392
        if ( rejfp != NULL ) {
 
393
                fclose( rejfp );
 
394
        }
 
395
 
 
396
        tool_destroy();
 
397
        return( retval );
 
398
}
 
399
 
 
400
 
 
401
static int
 
402
process_ldif_rec( char *rbuf, int linenum )
 
403
{
 
404
        char    *line, *dn, *newrdn, *newsup;
 
405
        int             rc, modop;
 
406
        int             expect_modop, expect_sep;
 
407
        int             deleteoldrdn;
 
408
        int             new_entry, delete_entry, got_all;
 
409
        LDAPMod **pmods, *lm = NULL;
 
410
        int version;
 
411
        LDAPControl **pctrls;
 
412
        int i, j, k, lines, idn, nmods;
 
413
        struct berval *btype, *vals, **bvl, bv;
 
414
        char *freeval;
 
415
        unsigned char *mops = NULL;
 
416
 
 
417
        new_entry = ldapadd;
 
418
 
 
419
        rc = got_all = delete_entry = modop = expect_modop = 0;
 
420
        expect_sep = 0;
 
421
        version = 0;
 
422
        deleteoldrdn = 1;
 
423
        pmods = NULL;
 
424
        pctrls = NULL;
 
425
        dn = newrdn = newsup = NULL;
 
426
 
 
427
        lines = ldif_countlines( rbuf );
 
428
        btype = ber_memcalloc( 1, (lines+1)*2*sizeof(struct berval)+lines );
 
429
        if ( !btype )
 
430
                return LDAP_NO_MEMORY;
 
431
 
 
432
        vals = btype+lines+1;
 
433
        freeval = (char *)(vals+lines+1);
 
434
        i = -1;
 
435
 
 
436
        while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
 
437
                int freev;
 
438
 
 
439
                if ( *line == '\n' || *line == '\0' ) {
 
440
                        break;
 
441
                }
 
442
 
 
443
                ++i;
 
444
 
 
445
                if ( line[0] == '-' && !line[1] ) {
 
446
                        BER_BVZERO( btype+i );
 
447
                        freeval[i] = 0;
 
448
                        continue;
 
449
                }
 
450
        
 
451
                if ( ( rc = ldif_parse_line2( line, btype+i, vals+i, &freev ) ) < 0 ) {
 
452
                        fprintf( stderr, _("%s: invalid format (line %d) entry: \"%s\"\n"),
 
453
                                prog, linenum+i, dn == NULL ? "" : dn );
 
454
                        rc = LDAP_PARAM_ERROR;
 
455
                        break;
 
456
                }
 
457
                freeval[i] = freev;
 
458
 
 
459
                if ( dn == NULL ) {
 
460
                        if ( linenum+i == 1 && !BVICMP( btype+i, &BV_VERSION )) {
 
461
                                int     v;
 
462
                                if( vals[i].bv_len == 0 || lutil_atoi( &v, vals[i].bv_val) != 0 || v != 1 ) {
 
463
                                        fprintf( stderr,
 
464
                                                _("%s: invalid version %s, line %d (ignored)\n"),
 
465
                                                prog, vals[i].bv_val, linenum );
 
466
                                }
 
467
                                version++;
 
468
 
 
469
                        } else if ( !BVICMP( btype+i, &BV_DN )) {
 
470
                                dn = vals[i].bv_val;
 
471
                                idn = i;
 
472
                        }
 
473
                        /* skip all lines until we see "dn:" */
 
474
                }
 
475
        }
 
476
 
 
477
        /* check to make sure there was a dn: line */
 
478
        if ( !dn ) {
 
479
                rc = 0;
 
480
                goto leave;
 
481
        }
 
482
 
 
483
        lines = i+1;
 
484
 
 
485
        if( lines == 0 ) {
 
486
                rc = 0;
 
487
                goto leave;
 
488
        }
 
489
 
 
490
        if( version && lines == 1 ) {
 
491
                rc = 0;
 
492
                goto leave;
 
493
        }
 
494
 
 
495
        i = idn+1;
 
496
        /* Check for "control" tag after dn and before changetype. */
 
497
        if (!BVICMP( btype+i, &BV_CONTROL)) {
 
498
                /* Parse and add it to the list of controls */
 
499
                rc = parse_ldif_control( vals+i, &pctrls );
 
500
                if (rc != 0) {
 
501
                        fprintf( stderr,
 
502
                                _("%s: Error processing %s line, line %d: %s\n"),
 
503
                                prog, BV_CONTROL.bv_val, linenum+i, ldap_err2string(rc) );
 
504
                }
 
505
                i++;
 
506
                if ( i>= lines ) {
 
507
short_input:
 
508
                        fprintf( stderr,
 
509
                                _("%s: Expecting more input after %s line, line %d\n"),
 
510
                                prog, btype[i-1].bv_val, linenum+i );
 
511
                        
 
512
                        rc = LDAP_PARAM_ERROR;
 
513
                        goto leave;
 
514
                }
 
515
        }
 
516
 
 
517
        /* Check for changetype */
 
518
        if ( !BVICMP( btype+i, &BV_CHANGETYPE )) {
 
519
#ifdef LIBERAL_CHANGETYPE_MODOP
 
520
                /* trim trailing spaces (and log warning ...) */
 
521
                int icnt;
 
522
                for ( icnt = vals[i].bv_len; --icnt > 0; ) {
 
523
                        if ( !isspace( (unsigned char) vals[i].bv_val[icnt] ) ) {
 
524
                                break;
 
525
                        }
 
526
                }
 
527
 
 
528
                if ( ++icnt != vals[i].bv_len ) {
 
529
                        fprintf( stderr, _("%s: illegal trailing space after"
 
530
                                " \"%s: %s\" trimmed (line %d, entry \"%s\")\n"),
 
531
                                prog, BV_CHANGETYPE.bv_val, vals[i].bv_val, linenum+i, dn );
 
532
                        vals[i].bv_val[icnt] = '\0';
 
533
                }
 
534
#endif /* LIBERAL_CHANGETYPE_MODOP */
 
535
 
 
536
                if ( BVICMP( vals+i, &BV_MODIFYCT ) == 0 ) {
 
537
                        new_entry = 0;
 
538
                        expect_modop = 1;
 
539
                } else if ( BVICMP( vals+i, &BV_ADDCT ) == 0 ) {
 
540
                        new_entry = 1;
 
541
                        modop = LDAP_MOD_ADD;
 
542
                } else if ( BVICMP( vals+i, &BV_MODRDNCT ) == 0
 
543
                        || BVICMP( vals+i, &BV_MODDNCT ) == 0
 
544
                        || BVICMP( vals+i, &BV_RENAMECT ) == 0)
 
545
                {
 
546
                        i++;
 
547
                        if ( i >= lines )
 
548
                                goto short_input;
 
549
                        if ( BVICMP( btype+i, &BV_NEWRDN )) {
 
550
                                fprintf( stderr, _("%s: expecting \"%s:\" but saw"
 
551
                                        " \"%s:\" (line %d, entry \"%s\")\n"),
 
552
                                        prog, BV_NEWRDN.bv_val, btype[i].bv_val, linenum+i, dn );
 
553
                                rc = LDAP_PARAM_ERROR;
 
554
                                goto leave;
 
555
                        }
 
556
                        newrdn = vals[i].bv_val;
 
557
                        i++;
 
558
                        if ( i >= lines )
 
559
                                goto short_input;
 
560
                        if ( BVICMP( btype+i, &BV_DELETEOLDRDN )) {
 
561
                                fprintf( stderr, _("%s: expecting \"%s:\" but saw"
 
562
                                        " \"%s:\" (line %d, entry \"%s\")\n"),
 
563
                                        prog, BV_DELETEOLDRDN.bv_val, btype[i].bv_val, linenum+i, dn );
 
564
                                rc = LDAP_PARAM_ERROR;
 
565
                                goto leave;
 
566
                        }
 
567
                        deleteoldrdn = ( vals[i].bv_val[0] == '0' ) ? 0 : 1;
 
568
                        i++;
 
569
                        if ( i < lines ) {
 
570
                                if ( BVICMP( btype+i, &BV_NEWSUP )) {
 
571
                                        fprintf( stderr, _("%s: expecting \"%s:\" but saw"
 
572
                                                " \"%s:\" (line %d, entry \"%s\")\n"),
 
573
                                                prog, BV_NEWSUP.bv_val, btype[i].bv_val, linenum+i, dn );
 
574
                                        rc = LDAP_PARAM_ERROR;
 
575
                                        goto leave;
 
576
                                }
 
577
                                newsup = vals[i].bv_val;
 
578
                                i++;
 
579
                        }
 
580
                        got_all = 1;
 
581
                } else if ( BVICMP( vals+i, &BV_DELETECT ) == 0 ) {
 
582
                        got_all = delete_entry = 1;
 
583
                } else {
 
584
                        fprintf( stderr,
 
585
                                _("%s:  unknown %s \"%s\" (line %d, entry \"%s\")\n"),
 
586
                                prog, BV_CHANGETYPE.bv_val, vals[i].bv_val, linenum+i, dn );
 
587
                        rc = LDAP_PARAM_ERROR;
 
588
                        goto leave;
 
589
                }
 
590
                i++;
 
591
        } else if ( ldapadd ) {         /*  missing changetype => add */
 
592
                new_entry = 1;
 
593
                modop = LDAP_MOD_ADD;
 
594
        } else {
 
595
                expect_modop = 1;       /* missing changetype => modify */
 
596
        }
 
597
 
 
598
        if ( got_all ) {
 
599
                if ( i < lines ) {
 
600
                        fprintf( stderr,
 
601
                                _("%s: extra lines at end (line %d, entry \"%s\")\n"),
 
602
                                prog, linenum+i, dn );
 
603
                        rc = LDAP_PARAM_ERROR;
 
604
                        goto leave;
 
605
                }
 
606
                goto doit;
 
607
        }
 
608
 
 
609
        nmods = lines - i;
 
610
        idn = i;
 
611
 
 
612
        if ( new_entry ) {
 
613
                int fv;
 
614
 
 
615
                /* Make sure all attributes with multiple values are contiguous */
 
616
                for (; i<lines; i++) {
 
617
                        for (j=i+1; j<lines; j++) {
 
618
                                if ( !BVICMP( btype+i, btype+j )) {
 
619
                                        nmods--;
 
620
                                        /* out of order, move intervening attributes down */
 
621
                                        if ( j != i+1 ) {
 
622
                                                bv = vals[j];
 
623
                                                fv = freeval[j];
 
624
                                                for (k=j; k>i; k--) {
 
625
                                                        btype[k] = btype[k-1];
 
626
                                                        vals[k] = vals[k-1];
 
627
                                                        freeval[k] = freeval[k-1];
 
628
                                                }
 
629
                                                k++;
 
630
                                                btype[k] = btype[i];
 
631
                                                vals[k] = bv;
 
632
                                                freeval[k] = fv;
 
633
                                        }
 
634
                                        i++;
 
635
                                }
 
636
                        }
 
637
                }
 
638
                /* Allocate space for array of mods, array of pointers to mods,
 
639
                 * and array of pointers to values, allowing for NULL terminators
 
640
                 * for the pointer arrays...
 
641
                 */
 
642
                lm = ber_memalloc( nmods * sizeof(LDAPMod) +
 
643
                        (nmods+1) * sizeof(LDAPMod*) +
 
644
                        (lines + nmods - idn) * sizeof(struct berval *));
 
645
                pmods = (LDAPMod **)(lm+nmods);
 
646
                bvl = (struct berval **)(pmods+nmods+1);
 
647
 
 
648
                j = 0;
 
649
                k = -1;
 
650
                BER_BVZERO(&bv);
 
651
                for (i=idn; i<lines; i++) {
 
652
                        if ( !BVICMP( btype+i, &BV_DN )) {
 
653
                                fprintf( stderr, _("%s: attributeDescription \"%s\":"
 
654
                                        " (possible missing newline"
 
655
                                                " after line %d, entry \"%s\"?)\n"),
 
656
                                        prog, btype[i].bv_val, linenum+i - 1, dn );
 
657
                        }
 
658
                        if ( BVICMP(btype+i,&bv)) {
 
659
                                bvl[k++] = NULL;
 
660
                                bv = btype[i];
 
661
                                lm[j].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
 
662
                                lm[j].mod_type = bv.bv_val;
 
663
                                lm[j].mod_bvalues = bvl+k;
 
664
                                pmods[j] = lm+j;
 
665
                                j++;
 
666
                        }
 
667
                        bvl[k++] = vals+i;
 
668
                }
 
669
                bvl[k] = NULL;
 
670
                pmods[j] = NULL;
 
671
                goto doit;
 
672
        }
 
673
 
 
674
        mops = ber_memalloc( lines+1 );
 
675
        mops[lines] = M_SEP;
 
676
        mops[i-1] = M_SEP;
 
677
 
 
678
        for ( ; i<lines; i++ ) {
 
679
                if ( expect_modop ) {
 
680
#ifdef LIBERAL_CHANGETYPE_MODOP
 
681
                        /* trim trailing spaces (and log warning ...) */
 
682
                    int icnt;
 
683
                    for ( icnt = vals[i].bv_len; --icnt > 0; ) {
 
684
                                if ( !isspace( (unsigned char) vals[i].bv_val[icnt] ) ) break;
 
685
                        }
 
686
    
 
687
                        if ( ++icnt != vals[i].bv_len ) {
 
688
                                fprintf( stderr, _("%s: illegal trailing space after"
 
689
                                        " \"%s: %s\" trimmed (line %d, entry \"%s\")\n"),
 
690
                                        prog, type, vals[i].bv_val, linenum+i, dn );
 
691
                                vals[i].bv_val[icnt] = '\0';
 
692
                        }
 
693
#endif /* LIBERAL_CHANGETYPE_MODOP */
 
694
 
 
695
                        expect_modop = 0;
 
696
                        expect_sep = 1;
 
697
                        if ( BVICMP( btype+i, &BV_MODOPADD ) == 0 ) {
 
698
                                modop = LDAP_MOD_ADD;
 
699
                                mops[i] = M_SEP;
 
700
                                nmods--;
 
701
                        } else if ( BVICMP( btype+i, &BV_MODOPREPLACE ) == 0 ) {
 
702
                        /* defer handling these since they might have no values.
 
703
                         * Use the BVALUES flag to signal that these were
 
704
                         * deferred. If values are provided later, this
 
705
                         * flag will be switched off.
 
706
                         */
 
707
                                modop = LDAP_MOD_REPLACE;
 
708
                                mops[i] = modop | LDAP_MOD_BVALUES;
 
709
                                btype[i] = vals[i];
 
710
                        } else if ( BVICMP( btype+i, &BV_MODOPDELETE ) == 0 ) {
 
711
                                modop = LDAP_MOD_DELETE;
 
712
                                mops[i] = modop | LDAP_MOD_BVALUES;
 
713
                                btype[i] = vals[i];
 
714
                        } else if ( BVICMP( btype+i, &BV_MODOPINCREMENT ) == 0 ) {
 
715
                                modop = LDAP_MOD_INCREMENT;
 
716
                                mops[i] = M_SEP;
 
717
                                nmods--;
 
718
                        } else {        /* no modify op: invalid LDIF */
 
719
                                fprintf( stderr, _("%s: modify operation type is missing at"
 
720
                                        " line %d, entry \"%s\"\n"),
 
721
                                        prog, linenum+i, dn );
 
722
                                rc = LDAP_PARAM_ERROR;
 
723
                                goto leave;
 
724
                        }
 
725
                        bv = vals[i];
 
726
                } else if ( expect_sep && BER_BVISEMPTY( btype+i )) {
 
727
                        mops[i] = M_SEP;
 
728
                        expect_sep = 0;
 
729
                        expect_modop = 1;
 
730
                        nmods--;
 
731
                } else {
 
732
                        if ( BVICMP( btype+i, &bv )) {
 
733
                                fprintf( stderr, _("%s: wrong attributeType at"
 
734
                                        " line %d, entry \"%s\"\n"),
 
735
                                        prog, linenum+i, dn );
 
736
                                rc = LDAP_PARAM_ERROR;
 
737
                                goto leave;
 
738
                        }
 
739
                        mops[i] = modop;
 
740
                        /* If prev op was deferred and matches this type,
 
741
                         * clear the flag
 
742
                         */
 
743
                        if ( (mops[i-1]&LDAP_MOD_BVALUES) && !BVICMP(btype+i,
 
744
                                btype+i-1)) {
 
745
                                mops[i-1] = M_SEP;
 
746
                                nmods--;
 
747
                        }
 
748
                }
 
749
        }
 
750
 
 
751
#if 0   /* we should faithfully encode the LDIF, not combine */
 
752
        /* Make sure all modops with multiple values are contiguous */
 
753
        for (i=idn; i<lines; i++) {
 
754
                if ( mops[i] == M_SEP )
 
755
                        continue;
 
756
                for (j=i+1; j<lines; j++) {
 
757
                        if ( mops[j] == M_SEP || mops[i] != mops[j] )
 
758
                                continue;
 
759
                        if ( !BVICMP( btype+i, btype+j )) {
 
760
                                nmods--;
 
761
                                /* out of order, move intervening attributes down */
 
762
                                if ( j != i+1 ) {
 
763
                                        int c;
 
764
                                        struct berval bv;
 
765
                                        char fv;
 
766
 
 
767
                                        c = mops[j];
 
768
                                        bv = vals[j];
 
769
                                        fv = freeval[j];
 
770
                                        for (k=j; k>i; k--) {
 
771
                                                btype[k] = btype[k-1];
 
772
                                                vals[k] = vals[k-1];
 
773
                                                freeval[k] = freeval[k-1];
 
774
                                                mops[k] = mops[k-1];
 
775
                                        }
 
776
                                        k++;
 
777
                                        btype[k] = btype[i];
 
778
                                        vals[k] = bv;
 
779
                                        freeval[k] = fv;
 
780
                                        mops[k] = c;
 
781
                                }
 
782
                                i++;
 
783
                        }
 
784
                }
 
785
        }
 
786
#endif
 
787
 
 
788
        /* Allocate space for array of mods, array of pointers to mods,
 
789
         * and array of pointers to values, allowing for NULL terminators
 
790
         * for the pointer arrays...
 
791
         */
 
792
        lm = ber_memalloc( nmods * sizeof(LDAPMod) +
 
793
                (nmods+1) * sizeof(LDAPMod*) +
 
794
                (lines + nmods - idn) * sizeof(struct berval *));
 
795
        pmods = (LDAPMod **)(lm+nmods);
 
796
        bvl = (struct berval **)(pmods+nmods+1);
 
797
 
 
798
        j = 0;
 
799
        k = -1;
 
800
        BER_BVZERO(&bv);
 
801
        mops[idn-1] = M_SEP;
 
802
        for (i=idn; i<lines; i++) {
 
803
                if ( mops[i] == M_SEP )
 
804
                        continue;
 
805
                if ( mops[i] != mops[i-1] || BVICMP(btype+i,&bv)) {
 
806
                        bvl[k++] = NULL;
 
807
                        bv = btype[i];
 
808
                        lm[j].mod_op = mops[i] | LDAP_MOD_BVALUES;
 
809
                        lm[j].mod_type = bv.bv_val;
 
810
                        if ( mops[i] & LDAP_MOD_BVALUES ) {
 
811
                                lm[j].mod_bvalues = NULL;
 
812
                        } else {
 
813
                                lm[j].mod_bvalues = bvl+k;
 
814
                        }
 
815
                        pmods[j] = lm+j;
 
816
                        j++;
 
817
                }
 
818
                bvl[k++] = vals+i;
 
819
        }
 
820
        bvl[k] = NULL;
 
821
        pmods[j] = NULL;
 
822
 
 
823
doit:
 
824
        /* If default controls are set (as with -M option) and controls are
 
825
           specified in the LDIF file, we must add the default controls to
 
826
           the list of controls sent with the ldap operation.
 
827
        */
 
828
        if ( rc == 0 ) {
 
829
                if (pctrls) {
 
830
                        LDAPControl **defctrls = NULL;   /* Default server controls */
 
831
                        LDAPControl **newctrls = NULL;
 
832
                        ldap_get_option(ld, LDAP_OPT_SERVER_CONTROLS, &defctrls);
 
833
                        if (defctrls) {
 
834
                                int npc=0;                       /* Num of LDIF controls */
 
835
                                int ndefc=0;                     /* Num of default controls */
 
836
                                while (pctrls[npc]) npc++;       /* Count LDIF controls */
 
837
                                while (defctrls[ndefc]) ndefc++; /* Count default controls */
 
838
                                newctrls = ber_memrealloc(pctrls,
 
839
                                        (npc+ndefc+1)*sizeof(LDAPControl*));
 
840
 
 
841
                                if (newctrls == NULL) {
 
842
                                        rc = LDAP_NO_MEMORY;
 
843
                                } else {
 
844
                                        int i;
 
845
                                        pctrls = newctrls;
 
846
                                        for (i=npc; i<npc+ndefc; i++) {
 
847
                                                pctrls[i] = ldap_control_dup(defctrls[i-npc]);
 
848
                                                if (pctrls[i] == NULL) {
 
849
                                                        rc = LDAP_NO_MEMORY;
 
850
                                                        break;
 
851
                                                }
 
852
                                        }
 
853
                                        pctrls[npc+ndefc] = NULL;
 
854
                                }
 
855
                                ldap_controls_free(defctrls);  /* Must be freed by library */
 
856
                        }
 
857
                }
 
858
        }
 
859
 
 
860
        if ( rc == 0 ) {
 
861
                if ( delete_entry ) {
 
862
                        rc = dodelete( dn, pctrls );
 
863
                } else if ( newrdn != NULL ) {
 
864
                        rc = dorename( dn, newrdn, newsup, deleteoldrdn, pctrls );
 
865
                } else {
 
866
                        rc = domodify( dn, pmods, pctrls, new_entry );
 
867
                }
 
868
 
 
869
                if ( rc == LDAP_SUCCESS ) {
 
870
                        rc = 0;
 
871
                }
 
872
        }
 
873
 
 
874
leave:
 
875
    if (pctrls != NULL) {
 
876
        ldap_controls_free( pctrls );
 
877
        }
 
878
        if ( lm != NULL ) {
 
879
                ber_memfree( lm );
 
880
        }
 
881
        if ( mops != NULL ) {
 
882
                ber_memfree( mops );
 
883
        }
 
884
        for (i=lines-1; i>=0; i--)
 
885
                if ( freeval[i] ) ber_memfree( vals[i].bv_val );
 
886
        ber_memfree( btype );
 
887
 
 
888
        return( rc );
 
889
}
 
890
 
 
891
/* Parse an LDIF control line of the form
 
892
      control:  oid  [true/false]  [: value]              or
 
893
      control:  oid  [true/false]  [:: base64-value]      or
 
894
      control:  oid  [true/false]  [:< url]
 
895
   The control is added to the list of controls in *ppctrls.
 
896
*/      
 
897
static int
 
898
parse_ldif_control(
 
899
        struct berval *bval,
 
900
        LDAPControl ***ppctrls )
 
901
{
 
902
        char *oid = NULL;
 
903
        int criticality = 0;   /* Default is false if not present */
 
904
        int i, rc=0;
 
905
        char *s, *oidStart;
 
906
        LDAPControl *newctrl = NULL;
 
907
        LDAPControl **pctrls = NULL;
 
908
        struct berval type, bv;
 
909
        int freeval;
 
910
 
 
911
        if (ppctrls) pctrls = *ppctrls;
 
912
        /* OID should come first. Validate and extract it. */
 
913
        s = bval->bv_val;
 
914
        if (*s == 0) return ( LDAP_PARAM_ERROR );
 
915
        oidStart = s;
 
916
        while (isdigit((unsigned char)*s) || *s == '.') {
 
917
                s++;                           /* OID should be digits or . */
 
918
        }
 
919
        if (s == oidStart) { 
 
920
                return ( LDAP_PARAM_ERROR );   /* OID was not present */
 
921
        }
 
922
        if (*s) {                          /* End of OID should be space or NULL */
 
923
                if (!isspace((unsigned char)*s)) {
 
924
                        return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */
 
925
                }
 
926
                *s++ = 0;                    /* Replace space with null to terminate */
 
927
        }
 
928
 
 
929
        oid = ber_strdup(oidStart);
 
930
        if (oid == NULL) return ( LDAP_NO_MEMORY );
 
931
 
 
932
        /* Optional Criticality field is next. */
 
933
        while (*s && isspace((unsigned char)*s)) {
 
934
                s++;                         /* Skip white space before criticality */
 
935
        }
 
936
        if (strncasecmp(s, "true", 4) == 0) {
 
937
                criticality = 1;
 
938
                s += 4;
 
939
        } 
 
940
        else if (strncasecmp(s, "false", 5) == 0) {
 
941
                criticality = 0;
 
942
                s += 5;
 
943
        }
 
944
 
 
945
        /* Optional value field is next */
 
946
        while (*s && isspace((unsigned char)*s)) {
 
947
                s++;                         /* Skip white space before value */
 
948
        }
 
949
        if (*s) {
 
950
                if (*s != ':') {           /* If value is present, must start with : */
 
951
                        rc = LDAP_PARAM_ERROR;
 
952
                        goto cleanup;
 
953
                }
 
954
 
 
955
                /* Back up so value is in the form
 
956
                     a: value
 
957
                     a:: base64-value
 
958
                     a:< url
 
959
                   Then we can use ldif_parse_line2 to extract and decode the value
 
960
                */
 
961
                s--;
 
962
                *s = 'a';
 
963
 
 
964
                rc = ldif_parse_line2(s, &type, &bv, &freeval);
 
965
                if (rc < 0) {
 
966
                        rc = LDAP_PARAM_ERROR;
 
967
                        goto cleanup;
 
968
                }
 
969
    }
 
970
 
 
971
        /* Create a new LDAPControl structure. */
 
972
        newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl));
 
973
        if ( newctrl == NULL ) {
 
974
                rc = LDAP_NO_MEMORY;
 
975
                goto cleanup;
 
976
        }
 
977
        newctrl->ldctl_oid = oid;
 
978
        oid = NULL;
 
979
        newctrl->ldctl_iscritical = criticality;
 
980
        if ( freeval )
 
981
                newctrl->ldctl_value = bv;
 
982
        else
 
983
                ber_dupbv( &newctrl->ldctl_value, &bv );
 
984
 
 
985
        /* Add the new control to the passed-in list of controls. */
 
986
        i = 0;
 
987
        if (pctrls) {
 
988
                while ( pctrls[i] ) {    /* Count the # of controls passed in */
 
989
                        i++;
 
990
                }
 
991
        }
 
992
        /* Allocate 1 more slot for the new control and 1 for the NULL. */
 
993
        pctrls = (LDAPControl **) ber_memrealloc(pctrls,
 
994
                (i+2)*(sizeof(LDAPControl *)));
 
995
        if (pctrls == NULL) {
 
996
                rc = LDAP_NO_MEMORY;
 
997
                goto cleanup;
 
998
        }
 
999
        pctrls[i] = newctrl;
 
1000
        newctrl = NULL;
 
1001
        pctrls[i+1] = NULL;
 
1002
        *ppctrls = pctrls;
 
1003
 
 
1004
cleanup:
 
1005
        if (newctrl) {
 
1006
                if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid);
 
1007
                if (newctrl->ldctl_value.bv_val) {
 
1008
                        ber_memfree(newctrl->ldctl_value.bv_val);
 
1009
                }
 
1010
                ber_memfree(newctrl);
 
1011
        }
 
1012
        if (oid) ber_memfree(oid);
 
1013
 
 
1014
        return( rc );
 
1015
}
 
1016
 
 
1017
 
 
1018
static int
 
1019
domodify(
 
1020
        const char *dn,
 
1021
        LDAPMod **pmods,
 
1022
        LDAPControl **pctrls,
 
1023
        int newentry )
 
1024
{
 
1025
        int                     rc, i, j, k, notascii, op;
 
1026
        struct berval   *bvp;
 
1027
 
 
1028
        if ( dn == NULL ) {
 
1029
                fprintf( stderr, _("%s: no DN specified\n"), prog );
 
1030
                return( LDAP_PARAM_ERROR );
 
1031
        }
 
1032
 
 
1033
        if ( pmods == NULL ) {
 
1034
                /* implement "touch" (empty sequence)
 
1035
                 * modify operation (note that there
 
1036
                 * is no symmetry with the UNIX command,
 
1037
                 * since \"touch\" on a non-existent entry
 
1038
                 * will fail)*/
 
1039
                printf( "warning: no attributes to %sadd (entry=\"%s\")\n",
 
1040
                        newentry ? "" : "change or ", dn );
 
1041
 
 
1042
        } else {
 
1043
                for ( i = 0; pmods[ i ] != NULL; ++i ) {
 
1044
                        op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
 
1045
                        if( op == LDAP_MOD_ADD && ( pmods[i]->mod_bvalues == NULL )) {
 
1046
                                fprintf( stderr,
 
1047
                                        _("%s: attribute \"%s\" has no values (entry=\"%s\")\n"),
 
1048
                                        prog, pmods[i]->mod_type, dn );
 
1049
                                return LDAP_PARAM_ERROR;
 
1050
                        }
 
1051
                }
 
1052
 
 
1053
                if ( verbose ) {
 
1054
                        for ( i = 0; pmods[ i ] != NULL; ++i ) {
 
1055
                                op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
 
1056
                                printf( "%s %s:\n",
 
1057
                                        op == LDAP_MOD_REPLACE ? _("replace") :
 
1058
                                                op == LDAP_MOD_ADD ?  _("add") :
 
1059
                                                        op == LDAP_MOD_INCREMENT ?  _("increment") :
 
1060
                                                                op == LDAP_MOD_DELETE ?  _("delete") :
 
1061
                                                                        _("unknown"),
 
1062
                                        pmods[ i ]->mod_type );
 
1063
        
 
1064
                                if ( pmods[ i ]->mod_bvalues != NULL ) {
 
1065
                                        for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
 
1066
                                                bvp = pmods[ i ]->mod_bvalues[ j ];
 
1067
                                                notascii = 0;
 
1068
                                                for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
 
1069
                                                        if ( !isascii( bvp->bv_val[ k ] )) {
 
1070
                                                                notascii = 1;
 
1071
                                                                break;
 
1072
                                                        }
 
1073
                                                }
 
1074
                                                if ( notascii ) {
 
1075
                                                        printf( _("\tNOT ASCII (%ld bytes)\n"), bvp->bv_len );
 
1076
                                                } else {
 
1077
                                                        printf( "\t%s\n", bvp->bv_val );
 
1078
                                                }
 
1079
                                        }
 
1080
                                }
 
1081
                        }
 
1082
                }
 
1083
        }
 
1084
 
 
1085
        if ( newentry ) {
 
1086
                printf( "%sadding new entry \"%s\"\n", dont ? "!" : "", dn );
 
1087
        } else {
 
1088
                printf( "%smodifying entry \"%s\"\n", dont ? "!" : "", dn );
 
1089
        }
 
1090
 
 
1091
        if ( !dont ) {
 
1092
                int     msgid;
 
1093
                if ( newentry ) {
 
1094
                        rc = ldap_add_ext( ld, dn, pmods, pctrls, NULL, &msgid );
 
1095
                } else {
 
1096
                        rc = ldap_modify_ext( ld, dn, pmods, pctrls, NULL, &msgid );
 
1097
                }
 
1098
 
 
1099
                if ( rc != LDAP_SUCCESS ) {
 
1100
                        /* print error message about failed update including DN */
 
1101
                        fprintf( stderr, _("%s: update failed: %s\n"), prog, dn );
 
1102
                        tool_perror( newentry ? "ldap_add" : "ldap_modify",
 
1103
                                rc, NULL, NULL, NULL, NULL );
 
1104
                        goto done;
 
1105
                }
 
1106
                rc = process_response( ld, msgid,
 
1107
                        newentry ? LDAP_RES_ADD : LDAP_RES_MODIFY, dn );
 
1108
 
 
1109
                if ( verbose && rc == LDAP_SUCCESS ) {
 
1110
                        printf( _("modify complete\n") );
 
1111
                }
 
1112
 
 
1113
        } else {
 
1114
                rc = LDAP_SUCCESS;
 
1115
        }
 
1116
 
 
1117
done:
 
1118
        putchar( '\n' );
 
1119
        return rc;
 
1120
}
 
1121
 
 
1122
 
 
1123
static int
 
1124
dodelete(
 
1125
        const char *dn,
 
1126
        LDAPControl **pctrls )
 
1127
{
 
1128
        int     rc;
 
1129
        int msgid;
 
1130
 
 
1131
        printf( _("%sdeleting entry \"%s\"\n"), dont ? "!" : "", dn );
 
1132
        if ( !dont ) {
 
1133
                rc = ldap_delete_ext( ld, dn, pctrls, NULL, &msgid );
 
1134
                if ( rc != LDAP_SUCCESS ) {
 
1135
                        fprintf( stderr, _("%s: delete failed: %s\n"), prog, dn );
 
1136
                        tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
 
1137
                        goto done;
 
1138
                }
 
1139
                rc = process_response( ld, msgid, LDAP_RES_DELETE, dn );
 
1140
 
 
1141
                if ( verbose && rc == LDAP_SUCCESS ) {
 
1142
                        printf( _("delete complete\n") );
 
1143
                }
 
1144
        } else {
 
1145
                rc = LDAP_SUCCESS;
 
1146
        }
 
1147
 
 
1148
done:
 
1149
        putchar( '\n' );
 
1150
        return( rc );
 
1151
}
 
1152
 
 
1153
 
 
1154
static int
 
1155
dorename(
 
1156
        const char *dn,
 
1157
        const char *newrdn,
 
1158
        const char* newsup,
 
1159
        int deleteoldrdn,
 
1160
        LDAPControl **pctrls )
 
1161
{
 
1162
        int     rc;
 
1163
        int msgid;
 
1164
 
 
1165
        printf( _("%smodifying rdn of entry \"%s\"\n"), dont ? "!" : "", dn );
 
1166
        if ( verbose ) {
 
1167
                printf( _("\tnew RDN: \"%s\" (%skeep existing values)\n"),
 
1168
                        newrdn, deleteoldrdn ? _("do not ") : "" );
 
1169
        }
 
1170
        if ( !dont ) {
 
1171
                rc = ldap_rename( ld, dn, newrdn, newsup, deleteoldrdn,
 
1172
                        pctrls, NULL, &msgid );
 
1173
                if ( rc != LDAP_SUCCESS ) {
 
1174
                        fprintf( stderr, _("%s: rename failed: %s\n"), prog, dn );
 
1175
                        tool_perror( "ldap_rename", rc, NULL, NULL, NULL, NULL );
 
1176
                        goto done;
 
1177
                }
 
1178
                rc = process_response( ld, msgid, LDAP_RES_RENAME, dn );
 
1179
 
 
1180
                if ( verbose && rc == LDAP_SUCCESS ) {
 
1181
                        printf( _("rename complete\n") );
 
1182
                }
 
1183
        } else {
 
1184
                rc = LDAP_SUCCESS;
 
1185
        }
 
1186
 
 
1187
done:
 
1188
        putchar( '\n' );
 
1189
        return( rc );
 
1190
}
 
1191
 
 
1192
static const char *
 
1193
res2str( int res ) {
 
1194
        switch ( res ) {
 
1195
        case LDAP_RES_ADD:
 
1196
                return "ldap_add";
 
1197
        case LDAP_RES_DELETE:
 
1198
                return "ldap_delete";
 
1199
        case LDAP_RES_MODIFY:
 
1200
                return "ldap_modify";
 
1201
        case LDAP_RES_MODRDN:
 
1202
                return "ldap_rename";
 
1203
        default:
 
1204
                assert( 0 );
 
1205
        }
 
1206
 
 
1207
        return "ldap_unknown";
 
1208
}
 
1209
 
 
1210
static int process_response(
 
1211
        LDAP *ld,
 
1212
        int msgid,
 
1213
        int op,
 
1214
        const char *dn )
 
1215
{
 
1216
        LDAPMessage     *res;
 
1217
        int             rc = LDAP_OTHER, msgtype;
 
1218
        struct timeval  tv = { 0, 0 };
 
1219
        int             err;
 
1220
        char            *text = NULL, *matched = NULL, **refs = NULL;
 
1221
        LDAPControl     **ctrls = NULL;
 
1222
 
 
1223
        for ( ; ; ) {
 
1224
                tv.tv_sec = 0;
 
1225
                tv.tv_usec = 100000;
 
1226
 
 
1227
                rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
 
1228
                if ( tool_check_abandon( ld, msgid ) ) {
 
1229
                        return LDAP_CANCELLED;
 
1230
                }
 
1231
 
 
1232
                if ( rc == -1 ) {
 
1233
                        ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc );
 
1234
                        tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
 
1235
                        return rc;
 
1236
                }
 
1237
 
 
1238
                if ( rc != 0 ) {
 
1239
                        break;
 
1240
                }
 
1241
        }
 
1242
 
 
1243
        msgtype = ldap_msgtype( res );
 
1244
 
 
1245
        rc = ldap_parse_result( ld, res, &err, &matched, &text, &refs, &ctrls, 1 );
 
1246
        if ( rc == LDAP_SUCCESS ) rc = err;
 
1247
 
 
1248
#ifdef LDAP_X_TXN
 
1249
        if ( rc == LDAP_X_TXN_SPECIFY_OKAY ) {
 
1250
                rc = LDAP_SUCCESS;
 
1251
        } else
 
1252
#endif
 
1253
        if ( rc != LDAP_SUCCESS ) {
 
1254
                tool_perror( res2str( op ), rc, NULL, matched, text, refs );
 
1255
        } else if ( msgtype != op ) {
 
1256
                fprintf( stderr, "%s: msgtype: expected %d got %d\n",
 
1257
                        res2str( op ), op, msgtype );
 
1258
                rc = LDAP_OTHER;
 
1259
        }
 
1260
 
 
1261
        if ( text ) ldap_memfree( text );
 
1262
        if ( matched ) ldap_memfree( matched );
 
1263
        if ( text ) ber_memvfree( (void **)refs );
 
1264
 
 
1265
        if ( ctrls ) {
 
1266
                tool_print_ctrls( ld, ctrls );
 
1267
                ldap_controls_free( ctrls );
 
1268
        }
 
1269
 
 
1270
        return rc;
 
1271
}