]> git.sur5r.net Git - openldap/blob - servers/slapd/slapmodify.c
ITS#7256 Let slapmodify ignore unknown operations
[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                         /* record skipped e.g. version: or comment or something we don't handle yet */
198                         continue;
199                 }
200
201                 local_rc = dnNormalize( 0, NULL, NULL, &lr.lr_dn, &ndn, NULL );
202                 if ( local_rc != LDAP_SUCCESS ) {
203                         fprintf( stderr, "%s: DN=\"%s\" normalization failed (line=%lu)\n",
204                                 progname, lr.lr_dn.bv_val, lineno );
205                         rc = EXIT_FAILURE;
206                         if( continuemode ) continue;
207                         break;
208                 }
209
210                 /* make sure the DN is not empty */
211                 if( BER_BVISEMPTY( &ndn ) &&
212                         !BER_BVISEMPTY( be->be_nsuffix ))
213                 {
214                         fprintf( stderr, "%s: line %lu: "
215                                 "%s entry with empty dn=\"\"",
216                                 progname, lineno, request );
217                         bd = select_backend( &ndn, nosubordinates );
218                         if ( bd ) {
219                                 BackendDB *bdtmp;
220                                 int dbidx = 0;
221                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
222                                         if ( bdtmp == bd ) break;
223                                         dbidx++;
224                                 }
225
226                                 assert( bdtmp != NULL );
227                                 
228                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
229                                         dbidx,
230                                         bd->be_suffix[0].bv_val );
231
232                         }
233                         fprintf( stderr, "\n" );
234                         rc = EXIT_FAILURE;
235                         SLAP_FREE( ndn.bv_val );
236                         ldap_ldif_record_done( &lr );
237                         if( continuemode ) continue;
238                         break;
239                 }
240
241                 /* check backend */
242                 bd = select_backend( &ndn, nosubordinates );
243                 if ( bd != be ) {
244                         fprintf( stderr, "%s: line %lu: "
245                                 "database #%d (%s) not configured to hold \"%s\"",
246                                 progname, lineno,
247                                 dbnum,
248                                 be->be_suffix[0].bv_val,
249                                 lr.lr_dn.bv_val );
250                         if ( bd ) {
251                                 BackendDB *bdtmp;
252                                 int dbidx = 0;
253                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
254                                         if ( bdtmp == bd ) break;
255                                         dbidx++;
256                                 }
257
258                                 assert( bdtmp != NULL );
259                                 
260                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
261                                         dbidx,
262                                         bd->be_suffix[0].bv_val );
263
264                         } else {
265                                 fprintf( stderr, "; no database configured for that naming context" );
266                         }
267                         fprintf( stderr, "\n" );
268                         rc = EXIT_FAILURE;
269                         SLAP_FREE( ndn.bv_val );
270                         ldap_ldif_record_done( &lr );
271                         if( continuemode ) continue;
272                         break;
273                 }
274
275                 /* get entry */
276                 id = be->be_dn2id_get( be, &ndn );
277                 e = be->be_entry_get( be, id );
278                 if ( e != NULL ) {
279                         Entry *e_tmp = entry_dup( e );
280                         /* FIXME: release? */
281                         e = e_tmp;
282                 }
283
284                 for ( n = 0; lr.lrop_mods[ n ] != NULL; n++ ) {
285                         LDAPMod *mod = lr.lrop_mods[ n ];
286                         Modification mods = { 0 };
287                         unsigned i = 0;
288                         int bin = (mod->mod_op & LDAP_MOD_BVALUES);
289                         int pretty = 0;
290                         int normalize = 0;
291
292                         local_rc = slap_str2ad( mod->mod_type, &mods.sm_desc, &text );
293                         if ( local_rc != LDAP_SUCCESS ) {
294                                 fprintf( stderr, "%s: slap_str2ad(\"%s\") failed for entry \"%s\" (%d: %s, lineno=%lu)\n",
295                                         progname, mod->mod_type, lr.lr_dn.bv_val, local_rc, text, lineno );
296                                 rc = EXIT_FAILURE;
297                                 mod_err = 1;
298                                 if( continuemode ) continue;
299                                 SLAP_FREE( ndn.bv_val );
300                                 ldap_ldif_record_done( &lr );
301                                 entry_free( e );
302                                 goto done;
303                         }
304
305                         mods.sm_type = mods.sm_desc->ad_cname;
306
307                         if ( mods.sm_desc->ad_type->sat_syntax->ssyn_pretty ) {
308                                 pretty = 1;
309
310                         } else {
311                                 assert( mods.sm_desc->ad_type->sat_syntax->ssyn_validate != NULL );
312                         }
313
314                         if ( mods.sm_desc->ad_type->sat_equality &&
315                                 mods.sm_desc->ad_type->sat_equality->smr_normalize )
316                         {
317                                 normalize = 1;
318                         }
319
320                         if ( bin && mod->mod_bvalues ) {
321                                 for ( i = 0; mod->mod_bvalues[ i ] != NULL; i++ )
322                                         ;
323
324                         } else if ( !bin && mod->mod_values ) {
325                                 for ( i = 0; mod->mod_values[ i ] != NULL; i++ )
326                                         ;
327                         }
328
329                         mods.sm_values = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
330                         if ( normalize ) {
331                                 mods.sm_nvalues = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
332                         } else {
333                                 mods.sm_nvalues = NULL;
334                         }
335                         mods.sm_numvals = i;
336
337                         for ( i = 0; i < mods.sm_numvals; i++ ) {
338                                 struct berval bv;
339
340                                 if ( bin ) {
341                                         bv = *mod->mod_bvalues[ i ];
342                                 } else {
343                                         ber_str2bv( mod->mod_values[ i ], 0, 0, &bv );
344                                 }
345
346                                 if ( pretty ) {
347                                         local_rc = ordered_value_pretty( mods.sm_desc,
348                                         &bv, &mods.sm_values[i], NULL );
349
350                                 } else {
351                                         local_rc = ordered_value_validate( mods.sm_desc,
352                                                 &bv, 0 );
353                                 }
354
355                                 if ( local_rc != LDAP_SUCCESS ) {
356                                         fprintf( stderr, "%s: DN=\"%s\": unable to %s attr=%s value #%d\n",
357                                                 progname, e->e_dn, pretty ? "prettify" : "validate",
358                                                 mods.sm_desc->ad_cname.bv_val, i );
359                                         /* handle error */
360                                         mod_err = 1;
361                                         rc = EXIT_FAILURE;
362                                         ber_bvarray_free( mods.sm_values );
363                                         ber_bvarray_free( mods.sm_nvalues );
364                                         if( continuemode ) continue;
365                                         SLAP_FREE( ndn.bv_val );
366                                         ldap_ldif_record_done( &lr );
367                                         entry_free( e );
368                                         goto done;
369                                 }
370
371                                 if ( !pretty ) {
372                                         ber_dupbv( &mods.sm_values[i], &bv );
373                                 }
374
375                                 if ( normalize ) {
376                                         local_rc = ordered_value_normalize(
377                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
378                                                 mods.sm_desc,
379                                                 mods.sm_desc->ad_type->sat_equality,
380                                                 &mods.sm_values[i], &mods.sm_nvalues[i],
381                                                 NULL );
382                                         if ( local_rc != LDAP_SUCCESS ) {
383                                                 fprintf( stderr, "%s: DN=\"%s\": unable to normalize attr=%s value #%d\n",
384                                                         progname, e->e_dn, mods.sm_desc->ad_cname.bv_val, i );
385                                                 /* handle error */
386                                                 mod_err = 1;
387                                                 rc = EXIT_FAILURE;
388                                                 ber_bvarray_free( mods.sm_values );
389                                                 ber_bvarray_free( mods.sm_nvalues );
390                                                 if( continuemode ) continue;
391                                                 SLAP_FREE( ndn.bv_val );
392                                                 ldap_ldif_record_done( &lr );
393                                                 entry_free( e );
394                                                 goto done;
395                                         }
396                                 }
397                         }
398
399                         mods.sm_op = (mod->mod_op & ~LDAP_MOD_BVALUES);
400                         mods.sm_flags = 0;
401
402                         if ( mods.sm_desc == slap_schema.si_ad_objectClass ) {
403                                 is_oc = 1;
404                         }
405
406                         switch ( mods.sm_op ) {
407                         case LDAP_MOD_ADD:
408                                 local_rc = modify_add_values( e, &mods,
409                                         0, &text, textbuf, textlen );
410                                 break;
411
412                         case LDAP_MOD_DELETE:
413                                 local_rc = modify_delete_values( e, &mods,
414                                         0, &text, textbuf, textlen );
415                                 break;
416
417                         case LDAP_MOD_REPLACE:
418                                 local_rc = modify_replace_values( e, &mods,
419                                         0, &text, textbuf, textlen );
420                                 break;
421
422                         case LDAP_MOD_INCREMENT:
423                                 local_rc = modify_increment_values( e, &mods,
424                                         0, &text, textbuf, textlen );
425                                 break;
426                         }
427
428                         if ( local_rc != LDAP_SUCCESS ) {
429                                 fprintf( stderr, "%s: DN=\"%s\": unable to modify attr=%s\n",
430                                         progname, e->e_dn, mods.sm_desc->ad_cname.bv_val );
431                                 rc = EXIT_FAILURE;
432                                 ber_bvarray_free( mods.sm_values );
433                                 ber_bvarray_free( mods.sm_nvalues );
434                                 if( continuemode ) continue;
435                                 SLAP_FREE( ndn.bv_val );
436                                 ldap_ldif_record_done( &lr );
437                                 entry_free( e );
438                                 goto done;
439                         }
440                 }
441
442                 rc = slap_tool_entry_check( progname, op, e, lineno, &text, textbuf, textlen );
443                 if ( rc != LDAP_SUCCESS ) {
444                         rc = EXIT_FAILURE;
445                         SLAP_FREE( ndn.bv_val );
446                         ldap_ldif_record_done( &lr );
447                         if( continuemode ) continue;
448                         entry_free( e );
449                         break;
450                 }
451
452                 if ( SLAP_LASTMOD(be) ) {
453                         time_t now = slap_get_time();
454                         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
455                         struct berval vals[ 2 ];
456
457                         struct berval name, timestamp;
458
459                         struct berval nvals[ 2 ];
460                         struct berval nname;
461                         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
462
463                         Attribute *a;
464
465                         vals[1].bv_len = 0;
466                         vals[1].bv_val = NULL;
467
468                         nvals[1].bv_len = 0;
469                         nvals[1].bv_val = NULL;
470
471                         csn.bv_len = ldap_pvt_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 );
472                         csn.bv_val = csnbuf;
473
474                         timestamp.bv_val = timebuf;
475                         timestamp.bv_len = sizeof(timebuf);
476
477                         slap_timestamp( &now, &timestamp );
478
479                         if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
480                                 BER_BVSTR( &name, SLAPD_ANONYMOUS );
481                                 nname = name;
482                         } else {
483                                 name = be->be_rootdn;
484                                 nname = be->be_rootndn;
485                         }
486
487                         a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
488                         if ( a != NULL ) {
489                                 vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
490                                 vals[0].bv_val = uuidbuf;
491                                 if ( a->a_vals != a->a_nvals ) {
492                                         SLAP_FREE( a->a_nvals[0].bv_val );
493                                         SLAP_FREE( a->a_nvals );
494                                 }
495                                 SLAP_FREE( a->a_vals[0].bv_val );
496                                 SLAP_FREE( a->a_vals );
497                                 a->a_vals = NULL;
498                                 a->a_nvals = NULL;
499                                 a->a_numvals = 0;
500                         }
501                         attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL );
502
503                         a = attr_find( e->e_attrs, slap_schema.si_ad_creatorsName );
504                         if ( a == NULL ) {
505                                 vals[0] = name;
506                                 nvals[0] = nname;
507                                 attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
508
509                         } else {
510                                 ber_bvreplace( &a->a_vals[0], &name );
511                                 ber_bvreplace( &a->a_nvals[0], &nname );
512                         }
513
514                         a = attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp );
515                         if ( a == NULL ) {
516                                 vals[0] = timestamp;
517                                 attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
518
519                         } else {
520                                 ber_bvreplace( &a->a_vals[0], &timestamp );
521                         }
522
523                         a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
524                         if ( a == NULL ) {
525                                 vals[0] = csn;
526                                 attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
527
528                         } else {
529                                 ber_bvreplace( &a->a_vals[0], &csn );
530                         }
531
532                         a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName );
533                         if ( a == NULL ) {
534                                 vals[0] = name;
535                                 nvals[0] = nname;
536                                 attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
537
538                         } else {
539                                 ber_bvreplace( &a->a_vals[0], &name );
540                                 ber_bvreplace( &a->a_nvals[0], &nname );
541                         }
542
543                         a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp );
544                         if ( a == NULL ) {
545                                 vals[0] = timestamp;
546                                 attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
547
548                         } else {
549                                 ber_bvreplace( &a->a_vals[0], &timestamp );
550                         }
551                 }
552
553                 if ( mod_err ) break;
554
555                 /* check schema, objectClass etc */
556
557                 if ( !dryrun ) {
558                         switch ( lr.lr_op ) {
559                         case LDAP_REQ_ADD:
560                                 id = be->be_entry_put( be, e, &bvtext );
561                                 rc = (id == NOID);
562                                 break;
563
564                         case LDAP_REQ_MODIFY:
565                                 id = be->be_entry_modify( be, e, &bvtext );
566                                 rc = (id == NOID);
567                                 break;
568
569                         case LDAP_REQ_DELETE:
570                                 rc = be->be_entry_delete( be, id, &bvtext );
571                                 break;
572
573                         }
574
575                         if( rc != LDAP_SUCCESS ) {
576                                 fprintf( stderr, "%s: could not %s entry dn=\"%s\" "
577                                         "(line=%lu): %s\n", progname, request, e->e_dn,
578                                         lineno, bvtext.bv_val );
579                                 rc = EXIT_FAILURE;
580                                 entry_free( e );
581                                 if( continuemode ) continue;
582                                 break;
583                         }
584
585                         sid = slap_tool_update_ctxcsn_check( progname, e );
586
587                         if ( verbose )
588                                 fprintf( stderr, "%s: \"%s\" (%08lx)\n",
589                                         request, e->e_dn, (long) id );
590                 } else {
591                         if ( verbose )
592                                 fprintf( stderr, "%s: \"%s\"\n",
593                                         request, e->e_dn );
594                 }
595
596                 entry_free( e );
597         }
598
599 done:;
600         if ( ldifrc < 0 )
601                 rc = EXIT_FAILURE;
602
603         bvtext.bv_len = textlen;
604         bvtext.bv_val = textbuf;
605         bvtext.bv_val[0] = '\0';
606
607         if ( enable_meter ) {
608                 lutil_meter_update( &meter, ftell( ldiffp->fp ), 1);
609                 lutil_meter_close( &meter );
610         }
611
612         if ( rc == EXIT_SUCCESS ) {
613                 rc = slap_tool_update_ctxcsn( progname, sid, &bvtext );
614         }
615
616         ch_free( buf );
617
618         if ( !dryrun ) {
619                 if ( enable_meter ) {
620                         fprintf( stderr, "Closing DB..." );
621                 }
622                 if( be->be_entry_close( be ) ) {
623                         rc = EXIT_FAILURE;
624                 }
625
626                 if( be->be_sync ) {
627                         be->be_sync( be );
628                 }
629                 if ( enable_meter ) {
630                         fprintf( stderr, "\n" );
631                 }
632         }
633
634         if ( slap_tool_destroy())
635                 rc = EXIT_FAILURE;
636
637         return rc;
638 }
639