]> git.sur5r.net Git - openldap/blob - servers/slapd/modify.c
Clean up some #else #if 'ing
[openldap] / servers / slapd / modify.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1995 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/socket.h>
23 #include <ac/string.h>
24 #include <ac/time.h>
25
26 #include "lutil.h"
27
28 #include "ldap_pvt.h"
29 #include "slap.h"
30
31 int
32 do_modify(
33     Connection  *conn,
34     Operation   *op )
35 {
36         struct berval dn = { 0, NULL };
37         struct berval pdn = { 0, NULL };
38         struct berval ndn = { 0, NULL };
39         char            *last;
40         ber_tag_t       tag;
41         ber_len_t       len;
42         Modifications   *modlist = NULL;
43         Modifications   **modtail = &modlist;
44 #ifdef LDAP_DEBUG
45         Modifications *tmp;
46 #endif
47         Backend         *be;
48         int rc;
49         const char      *text;
50         int manageDSAit;
51
52 #ifdef NEW_LOGGING
53         LDAP_LOG( OPERATION, ENTRY, "do_modify: enter\n", 0, 0, 0 );
54 #else
55         Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
56 #endif
57
58         /*
59          * Parse the modify request.  It looks like this:
60          *
61          *      ModifyRequest := [APPLICATION 6] SEQUENCE {
62          *              name    DistinguishedName,
63          *              mods    SEQUENCE OF SEQUENCE {
64          *                      operation       ENUMERATED {
65          *                              add     (0),
66          *                              delete  (1),
67          *                              replace (2)
68          *                      },
69          *                      modification    SEQUENCE {
70          *                              type    AttributeType,
71          *                              values  SET OF AttributeValue
72          *                      }
73          *              }
74          *      }
75          */
76
77         if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
78 #ifdef NEW_LOGGING
79                 LDAP_LOG( OPERATION, ERR, "do_modify: ber_scanf failed\n", 0, 0, 0 );
80 #else
81                 Debug( LDAP_DEBUG_ANY, "do_modify: ber_scanf failed\n", 0, 0, 0 );
82 #endif
83
84                 send_ldap_disconnect( conn, op,
85                         LDAP_PROTOCOL_ERROR, "decoding error" );
86                 return SLAPD_DISCONNECT;
87         }
88
89 #ifdef NEW_LOGGING
90         LDAP_LOG( OPERATION, ARGS, "do_modify: dn (%s)\n", dn.bv_val, 0, 0 );
91 #else
92         Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn.bv_val, 0, 0 );
93 #endif
94
95
96         /* collect modifications & save for later */
97
98         for ( tag = ber_first_element( op->o_ber, &len, &last );
99             tag != LBER_DEFAULT;
100             tag = ber_next_element( op->o_ber, &len, last ) )
101         {
102                 ber_int_t mop;
103                 Modifications tmp, *mod;
104
105
106                 if ( ber_scanf( op->o_ber, "{i{m[W]}}", &mop,
107                     &tmp.sml_type, &tmp.sml_bvalues )
108                     == LBER_ERROR )
109                 {
110                         send_ldap_disconnect( conn, op,
111                                 LDAP_PROTOCOL_ERROR, "decoding modlist error" );
112                         rc = SLAPD_DISCONNECT;
113                         goto cleanup;
114                 }
115
116                 mod = (Modifications *) ch_malloc( sizeof(Modifications) );
117                 mod->sml_op = mop;
118                 mod->sml_type = tmp.sml_type;
119                 mod->sml_bvalues = tmp.sml_bvalues;
120                 mod->sml_desc = NULL;
121                 mod->sml_next =NULL;
122                 *modtail = mod;
123
124                 switch( mop ) {
125                 case LDAP_MOD_ADD:
126                         if ( mod->sml_bvalues == NULL ) {
127 #ifdef NEW_LOGGING
128                                 LDAP_LOG( OPERATION, ERR, 
129                                         "do_modify: modify/add operation (%ld) requires values\n",
130                                         (long)mop, 0, 0 );
131 #else
132                                 Debug( LDAP_DEBUG_ANY,
133                                         "do_modify: modify/add operation (%ld) requires values\n",
134                                         (long) mop, 0, 0 );
135 #endif
136
137                                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
138                                         NULL, "modify/add operation requires values",
139                                         NULL, NULL );
140                                 rc = LDAP_PROTOCOL_ERROR;
141                                 goto cleanup;
142                         }
143
144                         /* fall through */
145
146                 case LDAP_MOD_DELETE:
147                 case LDAP_MOD_REPLACE:
148                         break;
149
150                 default: {
151 #ifdef NEW_LOGGING
152                                 LDAP_LOG( OPERATION, ERR, 
153                                         "do_modify: invalid modify operation (%ld)\n", (long)mop, 0, 0 );
154 #else
155                                 Debug( LDAP_DEBUG_ANY,
156                                         "do_modify: invalid modify operation (%ld)\n",
157                                         (long) mop, 0, 0 );
158 #endif
159
160                                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
161                                         NULL, "unrecognized modify operation", NULL, NULL );
162                                 rc = LDAP_PROTOCOL_ERROR;
163                                 goto cleanup;
164                         }
165                 }
166
167                 modtail = &mod->sml_next;
168         }
169         *modtail = NULL;
170
171         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
172 #ifdef NEW_LOGGING
173                 LDAP_LOG( OPERATION, ERR, "do_modify: get_ctrls failed\n", 0, 0, 0 );
174 #else
175                 Debug( LDAP_DEBUG_ANY, "do_modify: get_ctrls failed\n", 0, 0, 0 );
176 #endif
177
178                 goto cleanup;
179         }
180
181         rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn );
182         if( rc != LDAP_SUCCESS ) {
183 #ifdef NEW_LOGGING
184                 LDAP_LOG( OPERATION, INFO, "do_modify: conn %d  invalid dn (%s)\n",
185                         conn->c_connid, dn.bv_val, 0 );
186 #else
187                 Debug( LDAP_DEBUG_ANY,
188                         "do_modify: invalid dn (%s)\n", dn.bv_val, 0, 0 );
189 #endif
190                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
191                     "invalid DN", NULL, NULL );
192                 goto cleanup;
193         }
194
195         if( ndn.bv_len == 0 ) {
196 #ifdef NEW_LOGGING
197                 LDAP_LOG( OPERATION, ERR, 
198                         "do_modify: attempt to modify root DSE.\n",0, 0, 0 );
199 #else
200                 Debug( LDAP_DEBUG_ANY, "do_modify: root dse!\n", 0, 0, 0 );
201 #endif
202
203                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
204                         NULL, "modify upon the root DSE not supported", NULL, NULL );
205                 goto cleanup;
206
207         } else if ( bvmatch( &ndn, &global_schemandn ) ) {
208 #ifdef NEW_LOGGING
209                 LDAP_LOG( OPERATION, ERR,
210                         "do_modify: attempt to modify subschema subentry.\n" , 0, 0, 0  );
211 #else
212                 Debug( LDAP_DEBUG_ANY, "do_modify: subschema subentry!\n", 0, 0, 0 );
213 #endif
214
215                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
216                         NULL, "modification of subschema subentry not supported",
217                         NULL, NULL );
218                 goto cleanup;
219         }
220
221 #ifdef LDAP_DEBUG
222 #ifdef NEW_LOGGING
223         LDAP_LOG( OPERATION, DETAIL1, "do_modify: modifications:\n", 0, 0, 0  );
224 #else
225         Debug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
226 #endif
227
228         for ( tmp = modlist; tmp != NULL; tmp = tmp->sml_next ) {
229 #ifdef NEW_LOGGING
230                 LDAP_LOG( OPERATION, DETAIL1, "\t%s:  %s\n", 
231                         tmp->sml_op == LDAP_MOD_ADD ?
232                         "add" : (tmp->sml_op == LDAP_MOD_DELETE ?
233                         "delete" : "replace"), tmp->sml_type.bv_val, 0 );
234
235                 if ( tmp->sml_bvalues == NULL ) {
236                         LDAP_LOG( OPERATION, DETAIL1, "\t\tno values", 0, 0, 0 );
237                 } else if ( tmp->sml_bvalues[0].bv_val == NULL ) {
238                         LDAP_LOG( OPERATION, DETAIL1, "\t\tzero values", 0, 0, 0 );
239                 } else if ( tmp->sml_bvalues[1].bv_val == NULL ) {
240                         LDAP_LOG( OPERATION, DETAIL1, "\t\tone value", 0, 0, 0 );
241                 } else {
242                         LDAP_LOG( OPERATION, DETAIL1, "\t\tmultiple values", 0, 0, 0 );
243                 }
244
245 #else
246                 Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
247                         tmp->sml_op == LDAP_MOD_ADD
248                                 ? "add" : (tmp->sml_op == LDAP_MOD_DELETE
249                                         ? "delete" : "replace"), tmp->sml_type.bv_val, 0 );
250
251                 if ( tmp->sml_bvalues == NULL ) {
252                         Debug( LDAP_DEBUG_ARGS, "%s\n",
253                            "\t\tno values", NULL, NULL );
254                 } else if ( tmp->sml_bvalues[0].bv_val == NULL ) {
255                         Debug( LDAP_DEBUG_ARGS, "%s\n",
256                            "\t\tzero values", NULL, NULL );
257                 } else if ( tmp->sml_bvalues[1].bv_val == NULL ) {
258                         Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n",
259                            "\t\tone value", (long) tmp->sml_bvalues[0].bv_len, NULL );
260                 } else {
261                         Debug( LDAP_DEBUG_ARGS, "%s\n",
262                            "\t\tmultiple values", NULL, NULL );
263                 }
264 #endif
265         }
266 #endif
267
268         Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD dn=\"%s\"\n",
269             op->o_connid, op->o_opid, dn.bv_val, 0, 0 );
270
271         manageDSAit = get_manageDSAit( op );
272
273         /*
274          * We could be serving multiple database backends.  Select the
275          * appropriate one, or send a referral to our "referral server"
276          * if we don't hold it.
277          */
278         if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) {
279                 BerVarray ref = referral_rewrite( default_referral,
280                         NULL, &pdn, LDAP_SCOPE_DEFAULT );
281
282                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
283                         NULL, NULL, ref ? ref : default_referral, NULL );
284
285                 ber_bvarray_free( ref );
286                 goto cleanup;
287         }
288
289         /* check restrictions */
290         rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
291         if( rc != LDAP_SUCCESS ) {
292                 send_ldap_result( conn, op, rc,
293                         NULL, text, NULL, NULL );
294                 goto cleanup;
295         }
296
297         /* check for referrals */
298         rc = backend_check_referrals( be, conn, op, &pdn, &ndn );
299         if ( rc != LDAP_SUCCESS ) {
300                 goto cleanup;
301         }
302
303         /* deref suffix alias if appropriate */
304         suffix_alias( be, &ndn );
305
306         /*
307          * do the modify if 1 && (2 || 3)
308          * 1) there is a modify function implemented in this backend;
309          * 2) this backend is master for what it holds;
310          * 3) it's a replica and the dn supplied is the update_ndn.
311          */
312         if ( be->be_modify ) {
313                 /* do the update here */
314                 int repl_user = be_isupdate( be, &op->o_ndn );
315 #ifndef SLAPD_MULTIMASTER
316                 /* Multimaster slapd does not have to check for replicator dn
317                  * because it accepts each modify request
318                  */
319                 if ( !be->be_update_ndn.bv_len || repl_user )
320 #endif
321                 {
322                         int update = be->be_update_ndn.bv_len;
323                         const char *text;
324                         char textbuf[SLAP_TEXT_BUFLEN];
325                         size_t textlen = sizeof textbuf;
326
327                         rc = slap_mods_check( modlist, update, &text,
328                                 textbuf, textlen );
329
330                         if( rc != LDAP_SUCCESS ) {
331                                 send_ldap_result( conn, op, rc,
332                                         NULL, text, NULL, NULL );
333                                 goto cleanup;
334                         }
335
336                         if ( !repl_user ) {
337                                 for( modtail = &modlist;
338                                         *modtail != NULL;
339                                         modtail = &(*modtail)->sml_next )
340                                 {
341                                         /* empty */
342                                 }
343
344                                 rc = slap_mods_opattrs( be, op, modlist, modtail, &text,
345                                         textbuf, textlen );
346                                 if( rc != LDAP_SUCCESS ) {
347                                         send_ldap_result( conn, op, rc,
348                                                 NULL, text,
349                                                 NULL, NULL );
350                                         goto cleanup;
351                                 }
352                         }
353
354                         if ( (*be->be_modify)( be, conn, op, &pdn, &ndn, modlist ) == 0
355 #ifdef SLAPD_MULTIMASTER
356                                 && !repl_user
357 #endif
358                         ) {
359                                 /* but we log only the ones not from a replicator user */
360                                 replog( be, op, &pdn, &ndn, modlist );
361                         }
362
363 #ifndef SLAPD_MULTIMASTER
364                 /* send a referral */
365                 } else {
366                         BerVarray defref = be->be_update_refs
367                                 ? be->be_update_refs : default_referral;
368                         BerVarray ref = referral_rewrite( defref,
369                                 NULL, &pdn, LDAP_SCOPE_DEFAULT );
370
371                         send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL,
372                                 ref ? ref : defref, NULL );
373
374                         ber_bvarray_free( ref );
375 #endif
376                 }
377         } else {
378                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
379                     NULL, "operation not supported within namingContext",
380                         NULL, NULL );
381         }
382
383 cleanup:
384         free( pdn.bv_val );
385         free( ndn.bv_val );
386         if ( modlist != NULL )
387                 slap_mods_free( modlist );
388         return rc;
389 }
390
391 /*
392  * Do basic attribute type checking and syntax validation.
393  */
394 int slap_mods_check(
395         Modifications *ml,
396         int update,
397         const char **text,
398         char *textbuf,
399         size_t textlen )
400 {
401         int rc;
402
403         for( ; ml != NULL; ml = ml->sml_next ) {
404                 AttributeDescription *ad = NULL;
405
406                 /* convert to attribute description */
407                 rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
408
409                 if( rc != LDAP_SUCCESS ) {
410                         snprintf( textbuf, textlen, "%s: %s",
411                                 ml->sml_type.bv_val, *text );
412                         *text = textbuf;
413                         return rc;
414                 }
415
416                 ad = ml->sml_desc;
417
418                 if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
419                         && !slap_ad_is_binary( ad ))
420                 {
421                         /* attribute requires binary transfer */
422                         snprintf( textbuf, textlen,
423                                 "%s: requires ;binary transfer",
424                                 ml->sml_type.bv_val );
425                         *text = textbuf;
426                         return LDAP_UNDEFINED_TYPE;
427                 }
428
429                 if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
430                         && slap_ad_is_binary( ad ))
431                 {
432                         /* attribute requires binary transfer */
433                         snprintf( textbuf, textlen,
434                                 "%s: disallows ;binary transfer",
435                                 ml->sml_type.bv_val );
436                         *text = textbuf;
437                         return LDAP_UNDEFINED_TYPE;
438                 }
439
440                 if( slap_ad_is_lang_range( ad )) {
441                         /* attribute requires binary transfer */
442                         snprintf( textbuf, textlen,
443                                 "%s: inappropriate use of language range option",
444                                 ml->sml_type.bv_val );
445                         *text = textbuf;
446                         return LDAP_UNDEFINED_TYPE;
447                 }
448
449                 if (!update && is_at_no_user_mod( ad->ad_type )) {
450                         /* user modification disallowed */
451                         snprintf( textbuf, textlen,
452                                 "%s: no user modification allowed",
453                                 ml->sml_type.bv_val );
454                         *text = textbuf;
455                         return LDAP_CONSTRAINT_VIOLATION;
456                 }
457
458                 if ( is_at_obsolete( ad->ad_type ) &&
459                         ( ml->sml_op == LDAP_MOD_ADD || ml->sml_bvalues != NULL ) )
460                 {
461                         /*
462                          * attribute is obsolete,
463                          * only allow replace/delete with no values
464                          */
465                         snprintf( textbuf, textlen,
466                                 "%s: attribute is obsolete",
467                                 ml->sml_type.bv_val );
468                         *text = textbuf;
469                         return LDAP_CONSTRAINT_VIOLATION;
470                 }
471
472                 /*
473                  * check values
474                  */
475                 if( ml->sml_bvalues != NULL ) {
476                         ber_len_t nvals;
477                         slap_syntax_validate_func *validate =
478                                 ad->ad_type->sat_syntax->ssyn_validate;
479                         slap_syntax_transform_func *pretty =
480                                 ad->ad_type->sat_syntax->ssyn_pretty;
481  
482                         if( !pretty && !validate ) {
483                                 *text = "no validator for syntax";
484                                 snprintf( textbuf, textlen,
485                                         "%s: no validator for syntax %s",
486                                         ml->sml_type.bv_val,
487                                         ad->ad_type->sat_syntax->ssyn_oid );
488                                 *text = textbuf;
489                                 return LDAP_INVALID_SYNTAX;
490                         }
491
492                         /*
493                          * check that each value is valid per syntax
494                          *      and pretty if appropriate
495                          */
496                         for( nvals = 0; ml->sml_bvalues[nvals].bv_val; nvals++ ) {
497                                 struct berval pval;
498                                 if( pretty ) {
499                                         rc = pretty( ad->ad_type->sat_syntax,
500                                                 &ml->sml_bvalues[nvals], &pval );
501                                 } else {
502                                         rc = validate( ad->ad_type->sat_syntax,
503                                                 &ml->sml_bvalues[nvals] );
504                                 }
505
506                                 if( rc != 0 ) {
507                                         snprintf( textbuf, textlen,
508                                                 "%s: value #%ld invalid per syntax",
509                                                 ml->sml_type.bv_val, (long) nvals );
510                                         *text = textbuf;
511                                         return LDAP_INVALID_SYNTAX;
512                                 }
513
514                                 if( pretty ) {
515                                         ber_memfree( ml->sml_bvalues[nvals].bv_val );
516                                         ml->sml_bvalues[nvals] = pval;
517                                 }
518                         }
519
520                         /*
521                          * a rough single value check... an additional check is needed
522                          * to catch add of single value to existing single valued attribute
523                          */
524                         if( ( ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE )
525                                 && nvals > 1 && is_at_single_value( ad->ad_type ))
526                         {
527                                 snprintf( textbuf, textlen,
528                                         "%s: multiple value provided",
529                                         ml->sml_type.bv_val );
530                                 *text = textbuf;
531                                 return LDAP_CONSTRAINT_VIOLATION;
532                         }
533                 }
534         }
535
536         return LDAP_SUCCESS;
537 }
538
539 int slap_mods_opattrs(
540         Backend *be,
541         Operation *op,
542         Modifications *mods,
543         Modifications **modtail,
544         const char **text,
545         char *textbuf, size_t textlen )
546 {
547         struct berval name, timestamp, csn;
548         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
549         char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
550         Modifications *mod;
551
552         int mop = op->o_tag == LDAP_REQ_ADD
553                 ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
554
555         assert( modtail != NULL );
556         assert( *modtail == NULL );
557
558         if( SLAP_LASTMOD(be) ) {
559                 struct tm *ltm;
560                 time_t now = slap_get_time();
561
562                 ldap_pvt_thread_mutex_lock( &gmtime_mutex );
563                 ltm = gmtime( &now );
564                 lutil_gentime( timebuf, sizeof(timebuf), ltm );
565
566                 csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
567                 ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
568                 csn.bv_val = csnbuf;
569
570                 timestamp.bv_val = timebuf;
571                 timestamp.bv_len = strlen(timebuf);
572
573                 if( op->o_dn.bv_len == 0 ) {
574                         name.bv_val = SLAPD_ANONYMOUS;
575                         name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
576                 } else {
577                         name = op->o_dn;
578                 }
579         }
580
581         if( op->o_tag == LDAP_REQ_ADD ) {
582                 struct berval tmpval;
583
584                 if( global_schemacheck ) {
585                         int rc = mods_structural_class( mods, &tmpval,
586                                 text, textbuf, textlen );
587                         if( rc != LDAP_SUCCESS ) {
588                                 return rc;
589                         }
590
591                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
592                         mod->sml_op = mop;
593                         mod->sml_type.bv_val = NULL;
594                         mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
595                         mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
596                         ber_dupbv( &mod->sml_bvalues[0], &tmpval );
597                         mod->sml_bvalues[1].bv_val = NULL;
598                         assert( mod->sml_bvalues[0].bv_val );
599                         *modtail = mod;
600                         modtail = &mod->sml_next;
601                 }
602
603                 if( SLAP_LASTMOD(be) ) {
604                         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
605
606                         tmpval.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
607                         tmpval.bv_val = uuidbuf;
608                 
609                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
610                         mod->sml_op = mop;
611                         mod->sml_type.bv_val = NULL;
612                         mod->sml_desc = slap_schema.si_ad_entryUUID;
613                         mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
614                         ber_dupbv( &mod->sml_bvalues[0], &tmpval );
615                         mod->sml_bvalues[1].bv_val = NULL;
616                         assert( mod->sml_bvalues[0].bv_val );
617                         *modtail = mod;
618                         modtail = &mod->sml_next;
619
620                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
621                         mod->sml_op = mop;
622                         mod->sml_type.bv_val = NULL;
623                         mod->sml_desc = slap_schema.si_ad_creatorsName;
624                         mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
625                         ber_dupbv( &mod->sml_bvalues[0], &name );
626                         mod->sml_bvalues[1].bv_val = NULL;
627                         assert( mod->sml_bvalues[0].bv_val );
628                         *modtail = mod;
629                         modtail = &mod->sml_next;
630
631                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
632                         mod->sml_op = mop;
633                         mod->sml_type.bv_val = NULL;
634                         mod->sml_desc = slap_schema.si_ad_createTimestamp;
635                         mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
636                         ber_dupbv( &mod->sml_bvalues[0], &timestamp );
637                         mod->sml_bvalues[1].bv_val = NULL;
638                         assert( mod->sml_bvalues[0].bv_val );
639                         *modtail = mod;
640                         modtail = &mod->sml_next;
641                 }
642         }
643
644         if( SLAP_LASTMOD(be) ) {
645                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
646                 mod->sml_op = mop;
647                 mod->sml_type.bv_val = NULL;
648                 mod->sml_desc = slap_schema.si_ad_entryCSN;
649                 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
650                 ber_dupbv( &mod->sml_bvalues[0], &csn );
651                 mod->sml_bvalues[1].bv_val = NULL;
652                 assert( mod->sml_bvalues[0].bv_val );
653                 *modtail = mod;
654                 modtail = &mod->sml_next;
655
656                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
657                 mod->sml_op = mop;
658                 mod->sml_type.bv_val = NULL;
659                 mod->sml_desc = slap_schema.si_ad_modifiersName;
660                 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
661                 ber_dupbv( &mod->sml_bvalues[0], &name );
662                 mod->sml_bvalues[1].bv_val = NULL;
663                 assert( mod->sml_bvalues[0].bv_val );
664                 *modtail = mod;
665                 modtail = &mod->sml_next;
666
667                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
668                 mod->sml_op = mop;
669                 mod->sml_type.bv_val = NULL;
670                 mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
671                 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
672                 ber_dupbv( &mod->sml_bvalues[0], &timestamp );
673                 mod->sml_bvalues[1].bv_val = NULL;
674                 assert( mod->sml_bvalues[0].bv_val );
675                 *modtail = mod;
676                 modtail = &mod->sml_next;
677         }
678
679         *modtail = NULL;
680         return LDAP_SUCCESS;
681 }