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