Newer
Older
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "lutil.h"
Operation *op,
SlapReply *rs )
Pierangelo Masarati
committed
char textbuf[ SLAP_TEXT_BUFLEN ];
size_t textlen = sizeof( textbuf );
#ifdef LDAP_DEBUG
Modifications *tmp;
#endif
Pierangelo Masarati
committed
Debug( LDAP_DEBUG_TRACE, "%s do_modify\n",
op->o_log_prefix, 0, 0 );
/*
* Parse the modify request. It looks like this:
*
* ModifyRequest := [APPLICATION 6] SEQUENCE {
* name DistinguishedName,
* mods SEQUENCE OF SEQUENCE {
* operation ENUMERATED {
* add (0),
* delete (1),
* replace (2)
* },
* modification SEQUENCE {
* type AttributeType,
* values SET OF AttributeValue
* }
* }
* }
*/
if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "%s do_modify: ber_scanf failed\n",
op->o_log_prefix, 0, 0 );
send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
return SLAPD_DISCONNECT;
Debug( LDAP_DEBUG_ARGS, "%s do_modify: dn (%s)\n",
op->o_log_prefix, dn.bv_val, 0 );
rs->sr_err = slap_parse_modlist( op, rs, op->o_ber, &op->oq_modify );
if ( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "%s do_modify: slap_parse_modlist failed err=%d msg=%s\n",
op->o_log_prefix, rs->sr_err, rs->sr_text );
if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "%s do_modify: get_ctrls failed\n",
op->o_log_prefix, 0, 0 );
rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
op->o_tmpmemctx );
if( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "%s do_modify: invalid dn (%s)\n",
op->o_log_prefix, dn.bv_val, 0 );
send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
Debug( LDAP_DEBUG_ARGS, "%s modifications:\n",
op->o_log_prefix, 0, 0 );
for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) {
tmp->sml_op == LDAP_MOD_ADD ? "add" :
(tmp->sml_op == LDAP_MOD_INCREMENT ? "increment" :
(tmp->sml_op == LDAP_MOD_DELETE ? "delete" :
"replace")), tmp->sml_type.bv_val, 0 );
Debug( LDAP_DEBUG_ARGS, "%s\n",
"\t\tno values", NULL, NULL );
} else if ( BER_BVISNULL( &tmp->sml_values[ 0 ] ) ) {
Debug( LDAP_DEBUG_ARGS, "%s\n",
"\t\tzero values", NULL, NULL );
} else if ( BER_BVISNULL( &tmp->sml_values[ 1 ] ) ) {
Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n",
"\t\tone value", (long) tmp->sml_values[0].bv_len, NULL );
} else {
Debug( LDAP_DEBUG_ARGS, "%s\n",
"\t\tmultiple values", NULL, NULL );
}
if ( StatslogTest( LDAP_DEBUG_STATS ) ) {
char abuf[BUFSIZ/2], *ptr = abuf;
int len = 0;
Statslog( LDAP_DEBUG_STATS, "%s MOD dn=\"%s\"\n",
op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );
for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) {
Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
op->o_log_prefix, abuf, 0, 0, 0 );
if( 1 + tmp->sml_type.bv_len > sizeof(abuf)) {
Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
op->o_log_prefix, tmp->sml_type.bv_val, 0, 0, 0 );
}
if (len) {
*ptr++ = ' ';
len++;
}
ptr = lutil_strcopy(ptr, tmp->sml_type.bv_val);
len += tmp->sml_type.bv_len;
}
if (len) {
Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
op->o_log_prefix, abuf, 0, 0, 0 );
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
rs->sr_err = slap_mods_check( op, op->orm_modlist,
&rs->sr_text, textbuf, textlen, NULL );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto cleanup;
}
op->o_bd = frontendDB;
rs->sr_err = frontendDB->be_modify( op, rs );
#ifdef LDAP_X_TXN
if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) {
/* skip cleanup */
return rs->sr_err;
}
#endif
cleanup:
op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
if ( op->orm_modlist != NULL ) slap_mods_free( op->orm_modlist, 1 );
return rs->sr_err;
}
int
fe_op_modify( Operation *op, SlapReply *rs )
{
BackendDB *op_be, *bd = op->o_bd;
char textbuf[ SLAP_TEXT_BUFLEN ];
size_t textlen = sizeof( textbuf );
if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
Debug( LDAP_DEBUG_ANY, "%s do_modify: root dse!\n",
op->o_log_prefix, 0, 0 );
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"modify upon the root DSE not supported" );
goto cleanup;
} else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
Debug( LDAP_DEBUG_ANY, "%s do_modify: subschema subentry!\n",
op->o_log_prefix, 0, 0 );
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"modification of subschema subentry not supported" );
goto cleanup;
}
/*
* We could be serving multiple database backends. Select the
* appropriate one, or send a referral to our "referral server"
* if we don't hold it.
*/
op->o_bd = select_backend( &op->o_req_ndn, 1 );
rs->sr_ref = referral_rewrite( default_referral,
NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
if ( !rs->sr_ref ) {
rs->sr_ref = default_referral;
}
rs->sr_err = LDAP_REFERRAL;
send_ldap_result( op, rs );
if ( rs->sr_ref != default_referral ) {
ber_bvarray_free( rs->sr_ref );
}
} else {
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
/* If we've got a glued backend, check the real backend */
op_be = op->o_bd;
if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
op->o_bd = select_backend( &op->o_req_ndn, 0 );
/* check restrictions */
if ( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
rs->sr_err = slap_mods_obsolete_check( op, op->orm_modlist,
&rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto cleanup;
/* check for modify/increment support */
if ( op->orm_increment && !SLAP_INCREMENT( op->o_bd ) ) {
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"modify/increment not supported in context" );
}
/*
* do the modify if 1 && (2 || 3)
* 1) there is a modify function implemented in this backend;
* 2) this backend is master for what it holds;
* 3) it's a replica and the dn supplied is the update_ndn.
if ( op->o_bd->be_modify ) {
int repl_user = be_isupdate( op );
/*
* Multimaster slapd does not have to check for replicator dn
if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) {
int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn );
op->o_bd = op_be;
Pierangelo Masarati
committed
if ( !update ) {
rs->sr_err = slap_mods_no_user_mod_check( op, op->orm_modlist,
&rs->sr_text, textbuf, textlen );
Pierangelo Masarati
committed
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto cleanup;
}
op->o_bd->be_modify( op, rs );
BerVarray defref = op->o_bd->be_update_refs
? op->o_bd->be_update_refs : default_referral;
if ( defref != NULL ) {
rs->sr_ref = referral_rewrite( defref,
NULL, &op->o_req_dn,
LDAP_SCOPE_DEFAULT );
Pierangelo Masarati
committed
if ( rs->sr_ref == NULL ) {
/* FIXME: must duplicate, because
* overlays may muck with it */
rs->sr_ref = defref;
}
rs->sr_err = LDAP_REFERRAL;
send_ldap_result( op, rs );
Pierangelo Masarati
committed
if ( rs->sr_ref != defref ) {
ber_bvarray_free( rs->sr_ref );
}
Pierangelo Masarati
committed
} else {
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"shadow context; no update referral" );
}
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
"operation not supported within namingContext" );
Pierangelo Masarati
committed
cleanup:;
return rs->sr_err;
Pierangelo Masarati
committed
/*
* Obsolete constraint checking.
Pierangelo Masarati
committed
*/
int
slap_mods_obsolete_check(
Operation *op,
Modifications *ml,
const char **text,
char *textbuf,
size_t textlen )
{
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
for ( ; ml != NULL; ml = ml->sml_next ) {
if ( is_at_obsolete( ml->sml_desc->ad_type ) &&
(( ml->sml_op != LDAP_MOD_REPLACE &&
ml->sml_op != LDAP_MOD_DELETE ) ||
ml->sml_values != NULL ))
{
/*
* attribute is obsolete,
* only allow replace/delete with no values
*/
snprintf( textbuf, textlen,
"%s: attribute is obsolete",
ml->sml_type.bv_val );
*text = textbuf;
return LDAP_CONSTRAINT_VIOLATION;
}
}
return LDAP_SUCCESS;
}
/*
* No-user-modification constraint checking.
*/
int
slap_mods_no_user_mod_check(
Operation *op,
Pierangelo Masarati
committed
Modifications *ml,
const char **text,
char *textbuf,
size_t textlen )
{
for ( ; ml != NULL; ml = ml->sml_next ) {
if ( !is_at_no_user_mod( ml->sml_desc->ad_type ) ) {
continue;
}
if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_MANAGEABLE ) {
ml->sml_flags |= SLAP_MOD_MANAGING;
/* attribute not manageable */
snprintf( textbuf, textlen,
"%s: no-user-modification attribute not manageable",
ml->sml_type.bv_val );
Pierangelo Masarati
committed
/* user modification disallowed */
snprintf( textbuf, textlen,
"%s: no user modification allowed",
ml->sml_type.bv_val );
}
*text = textbuf;
return LDAP_CONSTRAINT_VIOLATION;
Pierangelo Masarati
committed
}
return LDAP_SUCCESS;
}
int
slap_mods_no_repl_user_mod_check(
Operation *op,
Modifications *ml,
const char **text,
char *textbuf,
size_t textlen )
{
Modifications *mods;
Modifications *modp;
for ( mods = ml; mods != NULL; mods = mods->sml_next ) {
assert( mods->sml_op == LDAP_MOD_ADD );
/* check doesn't already appear */
for ( modp = ml; modp != NULL; modp = modp->sml_next ) {
if ( mods->sml_desc == modp->sml_desc && mods != modp ) {
snprintf( textbuf, textlen,
"attribute '%s' provided more than once",
mods->sml_desc->ad_cname.bv_val );
return LDAP_TYPE_OR_VALUE_EXISTS;
}
}
}
return LDAP_SUCCESS;
}
/*
* Do basic attribute type checking and syntax validation.
*/
{
int rc;
for( ; ml != NULL; ml = ml->sml_next ) {
AttributeDescription *ad = NULL;
/* convert to attribute description */
if ( ml->sml_desc == NULL ) {
rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
if( rc != LDAP_SUCCESS ) {
if ( get_no_schema_check( op )) {
rc = slap_bv2undef_ad( &ml->sml_type, &ml->sml_desc,
text, 0 );
}
}
if( rc != LDAP_SUCCESS ) {
snprintf( textbuf, textlen, "%s: %s",
ml->sml_type.bv_val, *text );
*text = textbuf;
return rc;
}
if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
&& !slap_ad_is_binary( ad ))
{
/* attribute requires binary transfer */
snprintf( textbuf, textlen,
"%s: requires ;binary transfer",
return LDAP_UNDEFINED_TYPE;
}
if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
&& slap_ad_is_binary( ad ))
{
snprintf( textbuf, textlen,
"%s: disallows ;binary transfer",
return LDAP_UNDEFINED_TYPE;
}
Hallvard Furuseth
committed
if( slap_ad_is_tag_range( ad )) {
/* attribute requires binary transfer */
snprintf( textbuf, textlen,
Hallvard Furuseth
committed
"%s: inappropriate use of tag range option",
ml->sml_type.bv_val );
*text = textbuf;
return LDAP_UNDEFINED_TYPE;
}
Pierangelo Masarati
committed
#if 0
if ( is_at_obsolete( ad->ad_type ) &&
(( ml->sml_op != LDAP_MOD_REPLACE &&
ml->sml_op != LDAP_MOD_DELETE ) ||
ml->sml_values != NULL ))
{
/*
* attribute is obsolete,
* only allow replace/delete with no values
*/
snprintf( textbuf, textlen,
"%s: attribute is obsolete",
*text = textbuf;
return LDAP_CONSTRAINT_VIOLATION;
}
if ( ml->sml_op == LDAP_MOD_INCREMENT &&
#ifdef SLAPD_REAL_SYNTAX
!is_at_syntax( ad->ad_type, SLAPD_REAL_SYNTAX ) &&
#endif
!is_at_syntax( ad->ad_type, SLAPD_INTEGER_SYNTAX ) )
{
/*
* attribute values must be INTEGER or REAL
*/
snprintf( textbuf, textlen,
"%s: attribute syntax inappropriate for increment",
ml->sml_type.bv_val );
*text = textbuf;
return LDAP_CONSTRAINT_VIOLATION;
}
/*
* check values
*/
ber_len_t nvals;
slap_syntax_validate_func *validate =
ad->ad_type->sat_syntax->ssyn_validate;
slap_syntax_transform_func *pretty =
ad->ad_type->sat_syntax->ssyn_pretty;
if( !pretty && !validate ) {
*text = "no validator for syntax";
snprintf( textbuf, textlen,
"%s: no validator for syntax %s",
ad->ad_type->sat_syntax->ssyn_oid );
*text = textbuf;
return LDAP_INVALID_SYNTAX;
}
/*
* check that each value is valid per syntax
* and pretty if appropriate
for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
struct berval pval;
Pierangelo Masarati
committed
if ( pretty ) {
rc = ordered_value_pretty( ad,
&ml->sml_values[nvals], &pval, ctx );
Pierangelo Masarati
committed
rc = ordered_value_validate( ad,
if( rc != 0 ) {
snprintf( textbuf, textlen,
"%s: value #%ld invalid per syntax",
return LDAP_INVALID_SYNTAX;
}
ber_memfree_x( ml->sml_values[nvals].bv_val, ctx );
/*
* a rough single value check... an additional check is needed
* to catch add of single value to existing single valued attribute
*/
if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
&& nvals > 1 && is_at_single_value( ad->ad_type ))
{
snprintf( textbuf, textlen,
"%s: multiple values provided",
ml->sml_type.bv_val );
*text = textbuf;
return LDAP_CONSTRAINT_VIOLATION;
}
/* if the type has a normalizer, generate the
* normalized values. otherwise leave them NULL.
*
* this is different from the rule for attributes
* in an entry - in an attribute list, the normalized
* value is set equal to the non-normalized value
* when there is no normalizer.
*/
if( nvals && ad->ad_type->sat_equality &&
ml->sml_nvalues = ber_memalloc_x(
(nvals+1)*sizeof(struct berval), ctx );
for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
Pierangelo Masarati
committed
rc = ordered_value_normalize(
SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
ad,
ad->ad_type->sat_equality,
&ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
if ( rc ) {
Debug( LDAP_DEBUG_ANY,
"<= str2entry NULL (ssyn_normalize %d)\n",
rc, 0, 0 );
snprintf( textbuf, textlen,
"%s: value #%ld normalization failed",
ml->sml_type.bv_val, (long) nvals );
*text = textbuf;
BER_BVZERO( &ml->sml_nvalues[nvals] );
Pierangelo Masarati
committed
BER_BVZERO( &ml->sml_nvalues[nvals] );
/* check for duplicates, but ignore Deletes.
*/
if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
#define SLAP_MODS_CHECK_QUICKSORT
#ifndef SLAP_MODS_CHECK_QUICKSORT
MatchingRule *mr = ad->ad_type->sat_equality;
for ( i = 1; i < nvals ; i++ ) {
/* test asserted values against themselves */
for( j = 0; j < i; j++ ) {
rc = ordered_value_match( &match, ml->sml_desc, mr,
SLAP_MR_EQUALITY
| SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX
| SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
| SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
ml->sml_nvalues
? &ml->sml_nvalues[i]
: &ml->sml_values[i],
ml->sml_nvalues
? &ml->sml_nvalues[j]
: &ml->sml_values[j],
text );
if ( rc == LDAP_SUCCESS && match == 0 ) {
/* value exists already */
snprintf( textbuf, textlen,
"%s: value #%d provided more than once",
ml->sml_desc->ad_cname.bv_val, j );
*text = textbuf;
return LDAP_TYPE_OR_VALUE_EXISTS;
} else if ( rc != LDAP_SUCCESS ) {
return rc;
#else /* SLAP_MODS_CHECK_QUICKSORT */
/* Quicksort + Insertion sort for small arrays */
#define SMALL 8
#define SWAP(a,b,tmp) tmp=(a);(a)=(b);(b)=tmp
#define COMP(a,b) match=0; rc = ordered_value_match( &match, \
ml->sml_desc, mr, SLAP_MR_EQUALITY \
| SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX \
| SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH \
| SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, \
&(a), &(b), text );
MatchingRule *mr = ad->ad_type->sat_equality;
int istack[sizeof(int)*16];
int i, j, k, l, ir, jstack, match, *ix, itmp;
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
struct berval a, *cv;
/* If PRESERVE_ORDER is defined only the index array is sorted; the
* actual values are left in their incoming order. Otherwise, the
* only reason to keep the index array is to identify the offending
* value when duplicates are found.
*/
#define PRESERVE_ORDER
#ifndef PRESERVE_ORDER
struct berval va, *v, *nv, bvtmp;
#define IX(x) x
#define EXCH(x,y) SWAP(ix[x],ix[y],itmp); SWAP(cv[x],cv[y],bvtmp); \
if (nv) {SWAP(v[x],v[y],bvtmp);}
#define SETA(x) itmp = ix[x]; a = cv[x]; if (nv) va=v[x]
#define GETA(x) ix[x] = itmp; cv[x] = a; if (nv) v[x]=va
#define SET(x,y) ix[x] = ix[y]; cv[x] = cv[y]; if (nv) v[x]=v[y]
v = ml->sml_values;
nv = ml->sml_nvalues;
#else /* PRESERVE_ORDER */
#define IX(x) ix[x]
#define EXCH(x,y) SWAP(ix[x],ix[y],itmp)
#define SETA(x) itmp = ix[x]; a = cv[itmp]
#define GETA(x) ix[x] = itmp;
#define SET(x,y) ix[x] = ix[y]
#endif /* PRESERVE_ORDER */
cv = ml->sml_nvalues ? ml->sml_nvalues : ml->sml_values;
if ( ad == slap_schema.si_ad_objectClass )
mr = NULL; /* shortcut matching */
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
/* record indices to preserve input ordering */
ix = slap_sl_malloc( nvals * sizeof(int), ctx );
for (i=0; i<nvals; i++) ix[i] = i;
ir = nvals-1;
l = 0;
jstack = 0;
for(;;) {
if (ir - l < SMALL) { /* Insertion sort */
match=1;
for (j=l+1;j<=ir;j++) {
SETA(j);
for (i=j-1;i>=0;i--) {
COMP(cv[IX(i)], a);
if ( match <= 0 )
break;
SET(i+1,i);
}
GETA(i+1);
if ( match == 0 ) goto done;
}
if ( jstack == 0 ) break;
if ( match == 0 ) break;
ir = istack[jstack--];
l = istack[jstack--];
} else {
k = (l + ir) >> 1; /* Choose median of left, center, right */
EXCH(k, l+1);
COMP( cv[IX(l)], cv[IX(ir)] );
if ( match > 0 ) {
EXCH(l, ir);
} else if ( match == 0 ) {
i = ir;
break;
}
COMP( cv[IX(l+1)], cv[IX(ir)] );
if ( match > 0 ) {
EXCH(l+1, ir);
} else if ( match == 0 ) {
i = ir;
break;
}
COMP( cv[IX(l)], cv[IX(l+1)] );
if ( match > 0 ) {
EXCH(l, l+1);
} else if ( match == 0 ) {
i = l;
break;
}
i = l+1;
j = ir;
a = cv[IX(i)];
for(;;) {
do {
i++;
COMP( cv[IX(i)], a );
} while( match < 0 );
while( match > 0 ) {
j--;
COMP( cv[IX(j)], a );
}
if (j < i) {
match = 1;
break;
}
if ( match == 0 ) {
i = l+1;
break;
}
EXCH(i,j);
}
if ( match == 0 )
break;
EXCH(l+1,j);
jstack += 2;
if (ir-i+1 >= j) {
istack[jstack] = ir;
istack[jstack-1] = i;
ir = j;
} else {
istack[jstack] = j;
istack[jstack-1] = l;
l = i;
}
}
}
done:
slap_sl_free( ix, ctx );
if ( rc != LDAP_SUCCESS ) {
return rc;
} else if ( match == 0 ) {
/* value exists already */
assert( i >= 0 );
assert( i < nvals );
snprintf( textbuf, textlen,
"%s: value #%d provided more than once",
*text = textbuf;
return LDAP_TYPE_OR_VALUE_EXISTS;
}
#endif /* SLAP_MODS_CHECK_QUICKSORT */
}
}
return LDAP_SUCCESS;
}
/* Enter with bv->bv_len = sizeof buffer, returns with
* actual length of string
*/
void slap_timestamp( time_t *tm, struct berval *bv )
{
struct tm *ltm;
#ifdef HAVE_GMTIME_R
struct tm ltm_buf;
ltm = gmtime_r( tm, <m_buf );
#else
ldap_pvt_thread_mutex_lock( &gmtime_mutex );
#endif
bv->bv_len = lutil_gentime( bv->bv_val, bv->bv_len, ltm );
#ifndef HAVE_GMTIME_R
ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
#endif
}
/* Called for all modify and modrdn ops. If the current op was replicated
* from elsewhere, all of the attrs should already be present.
Operation *op,
Pierangelo Masarati
committed
Modifications **modsp,
struct berval name, timestamp, csn = BER_BVNULL;
char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
int gotcsn = 0, gotmname = 0, gotmtime = 0;
Pierangelo Masarati
committed
if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) {
timestamp.bv_val = timebuf;
for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) {
if ( (*modtail)->sml_op != LDAP_MOD_ADD &&
(*modtail)->sml_op != SLAP_MOD_SOFTADD &&
(*modtail)->sml_op != LDAP_MOD_REPLACE )
{
continue;
}
if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN )
{
csn = (*modtail)->sml_values[0];
gotcsn = 1;
} else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName )
{
gotmname = 1;
} else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp )
{
gotmtime = 1;
}
}
if ( !gotcsn ) {
csn.bv_val = csnbuf;
csn.bv_len = sizeof( csnbuf );
slap_get_csn( op, &csn, manage_ctxcsn );
slap_queue_csn( op, &csn );
ptr = ber_bvchr( &csn, '#' );
timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ");
timebuf[timestamp.bv_len-1] = 'Z';
} else {
time_t now = slap_get_time();
timestamp.bv_len = sizeof(timebuf);
slap_timestamp( &now, ×tamp );
}
if ( BER_BVISEMPTY( &op->o_dn ) ) {
} else {
name = op->o_dn;
if ( !gotcsn ) {
mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
mod->sml_op = LDAP_MOD_REPLACE;
mod->sml_flags = SLAP_MOD_INTERNAL;
mod->sml_next = NULL;
BER_BVZERO( &mod->sml_type );
mod->sml_desc = slap_schema.si_ad_entryCSN;
mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &mod->sml_values[0], &csn );
BER_BVZERO( &mod->sml_values[1] );
assert( !BER_BVISNULL( &mod->sml_values[0] ) );
mod->sml_nvalues = NULL;
*modtail = mod;
modlast = mod;
modtail = &mod->sml_next;
}
if ( !gotmname ) {
mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
mod->sml_flags = SLAP_MOD_INTERNAL;
mod->sml_desc = slap_schema.si_ad_modifiersName;
mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
BER_BVZERO( &mod->sml_values[1] );
assert( !BER_BVISNULL( &mod->sml_values[0] ) );
mod->sml_nvalues =
(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &mod->sml_nvalues[0], &nname );
BER_BVZERO( &mod->sml_nvalues[1] );
assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) );
*modtail = mod;
modtail = &mod->sml_next;
}
if ( !gotmtime ) {
mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
mod->sml_flags = SLAP_MOD_INTERNAL;
mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
BER_BVZERO( &mod->sml_values[1] );
assert( !BER_BVISNULL( &mod->sml_values[0] ) );
Pierangelo Masarati
committed
*modtail = mod;
modtail = &mod->sml_next;
int
slap_parse_modlist(
Operation *op,
SlapReply *rs,