]> git.sur5r.net Git - openldap/blob - servers/slapd/slapmodify.c
ITS#7256 Allow deletes with slapmodify
[openldap] / servers / slapd / slapmodify.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2014 The OpenLDAP Foundation.
5  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
6  * Portions Copyright 2003 IBM Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25
26 #include "ac/stdlib.h"
27
28 #include "ac/ctype.h"
29 #include "ac/string.h"
30 #include "ac/socket.h"
31 #include "ac/unistd.h"
32
33 #include "lber.h"
34 #include "ldif.h"
35 #include "lutil.h"
36 #include "lutil_meter.h"
37 #include <sys/stat.h>
38
39 #include "slapcommon.h"
40
41 static char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
42
43 int
44 slapmodify( int argc, char **argv )
45 {
46         char *buf = NULL;
47         const char *text;
48         char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
49         size_t textlen = sizeof textbuf;
50         const char *progname = "slapmodify";
51
52         struct berval csn;
53         unsigned long sid;
54         struct berval bvtext;
55         ID id;
56         OperationBuffer opbuf;
57         Operation *op;
58
59         int checkvals, ldifrc;
60         unsigned long lineno, nextline;
61         int lmax;
62         int rc = EXIT_SUCCESS;
63
64         int enable_meter = 0;
65         lutil_meter_t meter;
66         struct stat stat_buf;
67
68         /* default "000" */
69         csnsid = 0;
70
71         if ( isatty (2) ) enable_meter = 1;
72         slap_tool_init( progname, SLAPMODIFY, argc, argv );
73
74         memset( &opbuf, 0, sizeof(opbuf) );
75         op = &opbuf.ob_op;
76         op->o_hdr = &opbuf.ob_hdr;
77
78         if ( !be->be_entry_open ||
79                 !be->be_entry_close ||
80                 !be->be_entry_put ||
81                 !be->be_dn2id_get ||
82                 !be->be_entry_get ||
83                 !be->be_entry_modify )
84         {
85                 fprintf( stderr, "%s: database doesn't support necessary operations.\n",
86                         progname );
87                 if ( dryrun ) {
88                         fprintf( stderr, "\t(dry) continuing...\n" );
89
90                 } else {
91                         exit( EXIT_FAILURE );
92                 }
93         }
94
95         checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1;
96
97         lmax = 0;
98         nextline = 0;
99
100         /* enforce schema checking unless not disabled */
101         if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
102                 SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK);
103         }
104
105         if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) {
106                 fprintf( stderr, "%s: could not open database.\n",
107                         progname );
108                 exit( EXIT_FAILURE );
109         }
110
111         (void)slap_tool_update_ctxcsn_init();
112
113         if ( enable_meter 
114 #ifdef LDAP_DEBUG
115                 /* tools default to "none" */
116                 && slap_debug == LDAP_DEBUG_NONE
117 #endif
118                 && !fstat ( fileno ( ldiffp->fp ), &stat_buf )
119                 && S_ISREG(stat_buf.st_mode) ) {
120                 enable_meter = !lutil_meter_open(
121                         &meter,
122                         &lutil_meter_text_display,
123                         &lutil_meter_linear_estimator,
124                         stat_buf.st_size);
125         } else {
126                 enable_meter = 0;
127         }
128
129         /* nextline is the line number of the end of the current entry */
130         for( lineno=1; ( ldifrc = ldif_read_record( ldiffp, &nextline, &buf, &lmax )) > 0;
131                 lineno=nextline+1 )
132         {
133                 BackendDB *bd;
134                 Entry *e;
135                 struct berval rbuf;
136                 LDIFRecord lr;
137                 struct berval ndn;
138                 int n;
139                 int is_oc = 0;
140                 int local_rc;
141                 int mod_err = 0;
142                 char *request = "(unknown)";
143
144                 ber_str2bv( buf, 0, 0, &rbuf );
145
146                 if ( lineno < jumpline )
147                         continue;
148
149                 if ( enable_meter )
150                         lutil_meter_update( &meter,
151                                          ftell( ldiffp->fp ),
152                                          0);
153
154                 /*
155                  * Initialize text buffer
156                  */
157                 bvtext.bv_len = textlen;
158                 bvtext.bv_val = textbuf;
159                 bvtext.bv_val[0] = '\0';
160
161                 local_rc = ldap_parse_ldif_record( &rbuf, lineno, &lr,
162                         "slapmodify", LDIF_NO_CONTROLS );
163
164                 if ( local_rc != LDAP_SUCCESS ) {
165                         fprintf( stderr, "%s: could not parse entry (line=%lu)\n",
166                                 progname, lineno );
167                         rc = EXIT_FAILURE;
168                         if( continuemode ) continue;
169                         break;
170                 }
171
172                 switch ( lr.lr_op ) {
173                 case LDAP_REQ_ADD:
174                         request = "add";
175                         break;
176
177                 case LDAP_REQ_MODIFY:
178                         request = "modify";
179                         break;
180
181                 case LDAP_REQ_DELETE:
182                         if ( be->be_entry_delete )
183                         {
184                                 request = "delete";
185                                 break;
186                         }
187                         /* backend does not support delete, fallthrough */
188
189                 case LDAP_REQ_MODRDN:
190                         fprintf( stderr, "%s: request 0x%lx not supported (line=%lu)\n",
191                                 progname, (unsigned long)lr.lr_op, lineno );
192                         rc = EXIT_FAILURE;
193                         if( continuemode ) continue;
194                         goto done;
195
196                 default:
197                         fprintf( stderr, "%s: unknown request 0x%lx (line=%lu)\n",
198                                 progname, (unsigned long)lr.lr_op, lineno );
199                         rc = EXIT_FAILURE;
200                         if( continuemode ) continue;
201                         goto done;
202                 }
203
204                 local_rc = dnNormalize( 0, NULL, NULL, &lr.lr_dn, &ndn, NULL );
205                 if ( local_rc != LDAP_SUCCESS ) {
206                         fprintf( stderr, "%s: DN=\"%s\" normalization failed (line=%lu)\n",
207                                 progname, lr.lr_dn.bv_val, lineno );
208                         rc = EXIT_FAILURE;
209                         if( continuemode ) continue;
210                         break;
211                 }
212
213                 /* make sure the DN is not empty */
214                 if( BER_BVISEMPTY( &ndn ) &&
215                         !BER_BVISEMPTY( be->be_nsuffix ))
216                 {
217                         fprintf( stderr, "%s: line %lu: "
218                                 "%s entry with empty dn=\"\"",
219                                 progname, lineno, request );
220                         bd = select_backend( &ndn, nosubordinates );
221                         if ( bd ) {
222                                 BackendDB *bdtmp;
223                                 int dbidx = 0;
224                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
225                                         if ( bdtmp == bd ) break;
226                                         dbidx++;
227                                 }
228
229                                 assert( bdtmp != NULL );
230                                 
231                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
232                                         dbidx,
233                                         bd->be_suffix[0].bv_val );
234
235                         }
236                         fprintf( stderr, "\n" );
237                         rc = EXIT_FAILURE;
238                         SLAP_FREE( ndn.bv_val );
239                         ldap_ldif_record_done( &lr );
240                         if( continuemode ) continue;
241                         break;
242                 }
243
244                 /* check backend */
245                 bd = select_backend( &ndn, nosubordinates );
246                 if ( bd != be ) {
247                         fprintf( stderr, "%s: line %lu: "
248                                 "database #%d (%s) not configured to hold \"%s\"",
249                                 progname, lineno,
250                                 dbnum,
251                                 be->be_suffix[0].bv_val,
252                                 lr.lr_dn.bv_val );
253                         if ( bd ) {
254                                 BackendDB *bdtmp;
255                                 int dbidx = 0;
256                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
257                                         if ( bdtmp == bd ) break;
258                                         dbidx++;
259                                 }
260
261                                 assert( bdtmp != NULL );
262                                 
263                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
264                                         dbidx,
265                                         bd->be_suffix[0].bv_val );
266
267                         } else {
268                                 fprintf( stderr, "; no database configured for that naming context" );
269                         }
270                         fprintf( stderr, "\n" );
271                         rc = EXIT_FAILURE;
272                         SLAP_FREE( ndn.bv_val );
273                         ldap_ldif_record_done( &lr );
274                         if( continuemode ) continue;
275                         break;
276                 }
277
278                 /* get entry */
279                 id = be->be_dn2id_get( be, &ndn );
280                 e = be->be_entry_get( be, id );
281                 if ( e != NULL ) {
282                         Entry *e_tmp = entry_dup( e );
283                         /* FIXME: release? */
284                         e = e_tmp;
285                 }
286
287                 for ( n = 0; lr.lrop_mods[ n ] != NULL; n++ ) {
288                         LDAPMod *mod = lr.lrop_mods[ n ];
289                         Modification mods = { 0 };
290                         unsigned i = 0;
291                         int bin = (mod->mod_op & LDAP_MOD_BVALUES);
292                         int pretty = 0;
293                         int normalize = 0;
294
295                         local_rc = slap_str2ad( mod->mod_type, &mods.sm_desc, &text );
296                         if ( local_rc != LDAP_SUCCESS ) {
297                                 fprintf( stderr, "%s: slap_str2ad(\"%s\") failed for entry \"%s\" (%d: %s, lineno=%lu)\n",
298                                         progname, mod->mod_type, lr.lr_dn.bv_val, local_rc, text, lineno );
299                                 rc = EXIT_FAILURE;
300                                 mod_err = 1;
301                                 if( continuemode ) continue;
302                                 SLAP_FREE( ndn.bv_val );
303                                 ldap_ldif_record_done( &lr );
304                                 entry_free( e );
305                                 goto done;
306                         }
307
308                         mods.sm_type = mods.sm_desc->ad_cname;
309
310                         if ( mods.sm_desc->ad_type->sat_syntax->ssyn_pretty ) {
311                                 pretty = 1;
312
313                         } else {
314                                 assert( mods.sm_desc->ad_type->sat_syntax->ssyn_validate != NULL );
315                         }
316
317                         if ( mods.sm_desc->ad_type->sat_equality &&
318                                 mods.sm_desc->ad_type->sat_equality->smr_normalize )
319                         {
320                                 normalize = 1;
321                         }
322
323                         if ( bin && mod->mod_bvalues ) {
324                                 for ( i = 0; mod->mod_bvalues[ i ] != NULL; i++ )
325                                         ;
326
327                         } else if ( !bin && mod->mod_values ) {
328                                 for ( i = 0; mod->mod_values[ i ] != NULL; i++ )
329                                         ;
330                         }
331
332                         mods.sm_values = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
333                         if ( normalize ) {
334                                 mods.sm_nvalues = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
335                         } else {
336                                 mods.sm_nvalues = NULL;
337                         }
338                         mods.sm_numvals = i;
339
340                         for ( i = 0; i < mods.sm_numvals; i++ ) {
341                                 struct berval bv;
342
343                                 if ( bin ) {
344                                         bv = *mod->mod_bvalues[ i ];
345                                 } else {
346                                         ber_str2bv( mod->mod_values[ i ], 0, 0, &bv );
347                                 }
348
349                                 if ( pretty ) {
350                                         local_rc = ordered_value_pretty( mods.sm_desc,
351                                         &bv, &mods.sm_values[i], NULL );
352
353                                 } else {
354                                         local_rc = ordered_value_validate( mods.sm_desc,
355                                                 &bv, 0 );
356                                 }
357
358                                 if ( local_rc != LDAP_SUCCESS ) {
359                                         fprintf( stderr, "%s: DN=\"%s\": unable to %s attr=%s value #%d\n",
360                                                 progname, e->e_dn, pretty ? "prettify" : "validate",
361                                                 mods.sm_desc->ad_cname.bv_val, i );
362                                         /* handle error */
363                                         mod_err = 1;
364                                         rc = EXIT_FAILURE;
365                                         ber_bvarray_free( mods.sm_values );
366                                         ber_bvarray_free( mods.sm_nvalues );
367                                         if( continuemode ) continue;
368                                         SLAP_FREE( ndn.bv_val );
369                                         ldap_ldif_record_done( &lr );
370                                         entry_free( e );
371                                         goto done;
372                                 }
373
374                                 if ( !pretty ) {
375                                         ber_dupbv( &mods.sm_values[i], &bv );
376                                 }
377
378                                 if ( normalize ) {
379                                         local_rc = ordered_value_normalize(
380                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
381                                                 mods.sm_desc,
382                                                 mods.sm_desc->ad_type->sat_equality,
383                                                 &mods.sm_values[i], &mods.sm_nvalues[i],
384                                                 NULL );
385                                         if ( local_rc != LDAP_SUCCESS ) {
386                                                 fprintf( stderr, "%s: DN=\"%s\": unable to normalize attr=%s value #%d\n",
387                                                         progname, e->e_dn, mods.sm_desc->ad_cname.bv_val, i );
388                                                 /* handle error */
389                                                 mod_err = 1;
390                                                 rc = EXIT_FAILURE;
391                                                 ber_bvarray_free( mods.sm_values );
392                                                 ber_bvarray_free( mods.sm_nvalues );
393                                                 if( continuemode ) continue;
394                                                 SLAP_FREE( ndn.bv_val );
395                                                 ldap_ldif_record_done( &lr );
396                                                 entry_free( e );
397                                                 goto done;
398                                         }
399                                 }
400                         }
401
402                         mods.sm_op = (mod->mod_op & ~LDAP_MOD_BVALUES);
403                         mods.sm_flags = 0;
404
405                         if ( mods.sm_desc == slap_schema.si_ad_objectClass ) {
406                                 is_oc = 1;
407                         }
408
409                         switch ( mods.sm_op ) {
410                         case LDAP_MOD_ADD:
411                                 local_rc = modify_add_values( e, &mods,
412                                         0, &text, textbuf, textlen );
413                                 break;
414
415                         case LDAP_MOD_DELETE:
416                                 local_rc = modify_delete_values( e, &mods,
417                                         0, &text, textbuf, textlen );
418                                 break;
419
420                         case LDAP_MOD_REPLACE:
421                                 local_rc = modify_replace_values( e, &mods,
422                                         0, &text, textbuf, textlen );
423                                 break;
424
425                         case LDAP_MOD_INCREMENT:
426                                 local_rc = modify_increment_values( e, &mods,
427                                         0, &text, textbuf, textlen );
428                                 break;
429                         }
430
431                         if ( local_rc != LDAP_SUCCESS ) {
432                                 fprintf( stderr, "%s: DN=\"%s\": unable to modify attr=%s\n",
433                                         progname, e->e_dn, mods.sm_desc->ad_cname.bv_val );
434                                 rc = EXIT_FAILURE;
435                                 ber_bvarray_free( mods.sm_values );
436                                 ber_bvarray_free( mods.sm_nvalues );
437                                 if( continuemode ) continue;
438                                 SLAP_FREE( ndn.bv_val );
439                                 ldap_ldif_record_done( &lr );
440                                 entry_free( e );
441                                 goto done;
442                         }
443                 }
444
445                 rc = slap_tool_entry_check( progname, op, e, lineno, &text, textbuf, textlen );
446                 if ( rc != LDAP_SUCCESS ) {
447                         rc = EXIT_FAILURE;
448                         SLAP_FREE( ndn.bv_val );
449                         ldap_ldif_record_done( &lr );
450                         if( continuemode ) continue;
451                         entry_free( e );
452                         break;
453                 }
454
455                 if ( SLAP_LASTMOD(be) ) {
456                         time_t now = slap_get_time();
457                         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
458                         struct berval vals[ 2 ];
459
460                         struct berval name, timestamp;
461
462                         struct berval nvals[ 2 ];
463                         struct berval nname;
464                         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
465
466                         Attribute *a;
467
468                         vals[1].bv_len = 0;
469                         vals[1].bv_val = NULL;
470
471                         nvals[1].bv_len = 0;
472                         nvals[1].bv_val = NULL;
473
474                         csn.bv_len = ldap_pvt_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 );
475                         csn.bv_val = csnbuf;
476
477                         timestamp.bv_val = timebuf;
478                         timestamp.bv_len = sizeof(timebuf);
479
480                         slap_timestamp( &now, &timestamp );
481
482                         if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
483                                 BER_BVSTR( &name, SLAPD_ANONYMOUS );
484                                 nname = name;
485                         } else {
486                                 name = be->be_rootdn;
487                                 nname = be->be_rootndn;
488                         }
489
490                         a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
491                         if ( a != NULL ) {
492                                 vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
493                                 vals[0].bv_val = uuidbuf;
494                                 if ( a->a_vals != a->a_nvals ) {
495                                         SLAP_FREE( a->a_nvals[0].bv_val );
496                                         SLAP_FREE( a->a_nvals );
497                                 }
498                                 SLAP_FREE( a->a_vals[0].bv_val );
499                                 SLAP_FREE( a->a_vals );
500                                 a->a_vals = NULL;
501                                 a->a_nvals = NULL;
502                                 a->a_numvals = 0;
503                         }
504                         attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL );
505
506                         a = attr_find( e->e_attrs, slap_schema.si_ad_creatorsName );
507                         if ( a == NULL ) {
508                                 vals[0] = name;
509                                 nvals[0] = nname;
510                                 attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
511
512                         } else {
513                                 ber_bvreplace( &a->a_vals[0], &name );
514                                 ber_bvreplace( &a->a_nvals[0], &nname );
515                         }
516
517                         a = attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp );
518                         if ( a == NULL ) {
519                                 vals[0] = timestamp;
520                                 attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
521
522                         } else {
523                                 ber_bvreplace( &a->a_vals[0], &timestamp );
524                         }
525
526                         a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
527                         if ( a == NULL ) {
528                                 vals[0] = csn;
529                                 attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
530
531                         } else {
532                                 ber_bvreplace( &a->a_vals[0], &csn );
533                         }
534
535                         a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName );
536                         if ( a == NULL ) {
537                                 vals[0] = name;
538                                 nvals[0] = nname;
539                                 attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
540
541                         } else {
542                                 ber_bvreplace( &a->a_vals[0], &name );
543                                 ber_bvreplace( &a->a_nvals[0], &nname );
544                         }
545
546                         a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp );
547                         if ( a == NULL ) {
548                                 vals[0] = timestamp;
549                                 attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
550
551                         } else {
552                                 ber_bvreplace( &a->a_vals[0], &timestamp );
553                         }
554                 }
555
556                 if ( mod_err ) break;
557
558                 /* check schema, objectClass etc */
559
560                 if ( !dryrun ) {
561                         switch ( lr.lr_op ) {
562                         case LDAP_REQ_ADD:
563                                 id = be->be_entry_put( be, e, &bvtext );
564                                 rc = (id == NOID);
565                                 break;
566
567                         case LDAP_REQ_MODIFY:
568                                 id = be->be_entry_modify( be, e, &bvtext );
569                                 rc = (id == NOID);
570                                 break;
571
572                         case LDAP_REQ_DELETE:
573                                 rc = be->be_entry_delete( be, id, &bvtext );
574                                 break;
575
576                         }
577
578                         if( rc != LDAP_SUCCESS ) {
579                                 fprintf( stderr, "%s: could not %s entry dn=\"%s\" "
580                                         "(line=%lu): %s\n", progname, request, e->e_dn,
581                                         lineno, bvtext.bv_val );
582                                 rc = EXIT_FAILURE;
583                                 entry_free( e );
584                                 if( continuemode ) continue;
585                                 break;
586                         }
587
588                         sid = slap_tool_update_ctxcsn_check( progname, e );
589
590                         if ( verbose )
591                                 fprintf( stderr, "%s: \"%s\" (%08lx)\n",
592                                         request, e->e_dn, (long) id );
593                 } else {
594                         if ( verbose )
595                                 fprintf( stderr, "%s: \"%s\"\n",
596                                         request, e->e_dn );
597                 }
598
599                 entry_free( e );
600         }
601
602 done:;
603         if ( ldifrc < 0 )
604                 rc = EXIT_FAILURE;
605
606         bvtext.bv_len = textlen;
607         bvtext.bv_val = textbuf;
608         bvtext.bv_val[0] = '\0';
609
610         if ( enable_meter ) {
611                 lutil_meter_update( &meter, ftell( ldiffp->fp ), 1);
612                 lutil_meter_close( &meter );
613         }
614
615         if ( rc == EXIT_SUCCESS ) {
616                 rc = slap_tool_update_ctxcsn( progname, sid, &bvtext );
617         }
618
619         ch_free( buf );
620
621         if ( !dryrun ) {
622                 if ( enable_meter ) {
623                         fprintf( stderr, "Closing DB..." );
624                 }
625                 if( be->be_entry_close( be ) ) {
626                         rc = EXIT_FAILURE;
627                 }
628
629                 if( be->be_sync ) {
630                         be->be_sync( be );
631                 }
632                 if ( enable_meter ) {
633                         fprintf( stderr, "\n" );
634                 }
635         }
636
637         if ( slap_tool_destroy())
638                 rc = EXIT_FAILURE;
639
640         return rc;
641 }
642