3 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1995 Regents of the University of Michigan.
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.
22 #include <ac/socket.h>
23 #include <ac/string.h>
35 char *dn, *ndn = NULL;
39 LDAPModList *modlist = NULL;
40 LDAPModList **modtail = &modlist;
44 Modifications *mods = NULL;
50 Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
53 * Parse the modify request. It looks like this:
55 * ModifyRequest := [APPLICATION 6] SEQUENCE {
56 * name DistinguishedName,
57 * mods SEQUENCE OF SEQUENCE {
58 * operation ENUMERATED {
63 * modification SEQUENCE {
65 * values SET OF AttributeValue
71 if ( ber_scanf( op->o_ber, "{a" /*}*/, &dn ) == LBER_ERROR ) {
72 Debug( LDAP_DEBUG_ANY, "do_modify: ber_scanf failed\n", 0, 0, 0 );
73 send_ldap_disconnect( conn, op,
74 LDAP_PROTOCOL_ERROR, "decoding error" );
75 return SLAPD_DISCONNECT;
78 Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
80 /* collect modifications & save for later */
82 for ( tag = ber_first_element( op->o_ber, &len, &last );
84 tag = ber_next_element( op->o_ber, &len, last ) )
88 (*modtail) = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) );
90 if ( ber_scanf( op->o_ber, "{i{a[V]}}", &mop,
91 &(*modtail)->ml_type, &(*modtail)->ml_bvalues )
94 send_ldap_disconnect( conn, op,
95 LDAP_PROTOCOL_ERROR, "decoding modlist error" );
96 rc = SLAPD_DISCONNECT;
102 if ( (*modtail)->ml_bvalues == NULL ) {
103 Debug( LDAP_DEBUG_ANY,
104 "do_modify: modify/add operation (%ld) requires values\n",
106 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
107 NULL, "modify/add operation requires values",
109 rc = LDAP_PROTOCOL_ERROR;
115 case LDAP_MOD_DELETE:
116 case LDAP_MOD_REPLACE:
120 Debug( LDAP_DEBUG_ANY,
121 "do_modify: invalid modify operation (%ld)\n",
123 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
124 NULL, "unrecognized modify operation", NULL, NULL );
125 rc = LDAP_PROTOCOL_ERROR;
130 (*modtail)->ml_op = mop;
131 modtail = &(*modtail)->ml_next;
135 if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
136 Debug( LDAP_DEBUG_ANY, "do_modify: get_ctrls failed\n", 0, 0, 0 );
140 ndn = ch_strdup( dn );
142 if( dn_normalize( ndn ) == NULL ) {
143 Debug( LDAP_DEBUG_ANY, "do_modify: invalid dn (%s)\n", dn, 0, 0 );
144 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
145 "invalid DN", NULL, NULL );
150 Debug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
151 for ( tmp = modlist; tmp != NULL; tmp = tmp->ml_next ) {
152 Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
153 tmp->ml_op == LDAP_MOD_ADD
154 ? "add" : (tmp->ml_op == LDAP_MOD_DELETE
155 ? "delete" : "replace"), tmp->ml_type, 0 );
159 Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d MOD dn=\"%s\"\n",
160 op->o_connid, op->o_opid, dn, 0, 0 );
163 * We could be serving multiple database backends. Select the
164 * appropriate one, or send a referral to our "referral server"
165 * if we don't hold it.
167 if ( (be = select_backend( ndn )) == NULL ) {
168 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
169 NULL, NULL, default_referral, NULL );
173 /* make sure this backend recongizes critical controls */
174 rc = backend_check_controls( be, conn, op, &text ) ;
176 if( rc != LDAP_SUCCESS ) {
177 send_ldap_result( conn, op, rc,
178 NULL, text, NULL, NULL );
182 /* check for referrals */
183 rc = backend_check_referrals( be, conn, op, &urls, &text );
184 if ( rc != LDAP_SUCCESS ) {
185 send_ldap_result( conn, op, rc,
186 NULL, text, urls, NULL );
187 ber_bvecfree( urls );
191 if ( global_readonly || be->be_readonly ) {
192 Debug( LDAP_DEBUG_ANY, "do_modify: database is read-only\n",
194 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
195 NULL, "directory is read-only", NULL, NULL );
199 /* deref suffix alias if appropriate */
200 ndn = suffix_alias( be, ndn );
203 * do the modify if 1 && (2 || 3)
204 * 1) there is a modify function implemented in this backend;
205 * 2) this backend is master for what it holds;
206 * 3) it's a replica and the dn supplied is the update_ndn.
208 if ( be->be_modify ) {
209 /* do the update here */
210 #ifndef SLAPD_MULTIMASTER
211 /* we don't have to check for replicator dn
212 * because we accept each modify request
214 if ( be->be_update_ndn == NULL ||
215 strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
218 int update = be->be_update_ndn != NULL;
220 rc = slap_modlist2mods( modlist, update, &mods, &text );
222 if( rc != LDAP_SUCCESS ) {
223 send_ldap_result( conn, op, rc,
224 NULL, text, NULL, NULL );
228 if ( (be->be_lastmod == ON || (be->be_lastmod == UNDEFINED &&
229 global_lastmod == ON)) && !update )
231 Modifications **modstail;
232 for( modstail = &mods;
234 modstail = &(*modstail)->sml_next )
238 rc = slap_mods_opattrs( op, modstail, &text );
240 if( rc != LDAP_SUCCESS ) {
241 send_ldap_result( conn, op, rc,
248 if ( (*be->be_modify)( be, conn, op, dn, ndn, mods ) == 0
249 #ifdef SLAPD_MULTIMASTER
250 && ( be->be_update_ndn == NULL ||
251 strcmp( be->be_update_ndn, op->o_ndn ) != 0 )
254 /* but we log only the ones not from a replicator user */
255 replog( be, op, dn, mods );
258 #ifndef SLAPD_MULTIMASTER
259 /* send a referral */
261 send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL,
262 be->be_update_refs ? be->be_update_refs : default_referral,
267 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
268 NULL, "operation not supported within namingContext", NULL, NULL );
273 if( ndn != NULL ) free( ndn );
274 if ( modlist != NULL )
275 slap_modlist_free( modlist );
277 slap_mods_free( mods );
282 * convert a raw list of modifications to internal format
283 * Do basic attribute type checking and syntax validation.
285 int slap_modlist2mods(
288 Modifications **mods,
292 Modifications **modtail = mods;
294 for( ; ml != NULL; ml = ml->ml_next ) {
296 AttributeDescription *ad = NULL;
298 mod = (Modifications *)
299 ch_calloc( 1, sizeof(Modifications) );
302 mod->sml_op = ml->ml_op;
304 /* convert to attribute description */
305 rc = slap_str2ad( ml->ml_type, &mod->sml_desc, text );
307 if( rc != LDAP_SUCCESS ) {
308 slap_mods_free( mod );
314 if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
315 && !slap_ad_is_binary( ad ))
317 /* attribute requires binary transfer */
318 slap_mods_free( mod );
319 *text = "attribute requires ;binary transfer";
320 return LDAP_UNDEFINED_TYPE;
323 if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
324 && slap_ad_is_binary( ad ))
326 /* attribute requires binary transfer */
327 slap_mods_free( mod );
328 *text = "attribute disallows ;binary transfer";
329 return LDAP_UNDEFINED_TYPE;
332 if (!update && is_at_no_user_mod( ad->ad_type )) {
333 /* user modification disallowed */
334 slap_mods_free( mod );
335 *text = "no user modification allowed";
336 return LDAP_CONSTRAINT_VIOLATION;
342 if( ml->ml_bvalues != NULL ) {
344 slap_syntax_validate_func *validate =
345 ad->ad_type->sat_syntax->ssyn_validate;
348 Debug( LDAP_DEBUG_TRACE,
349 "modlist2mods: no validator for syntax %s\n",
350 ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
351 slap_mods_free( mod );
352 *text = "no validator for syntax";
353 return LDAP_INVALID_SYNTAX;
357 * check that each value is valid per syntax
359 for( nvals = 0; ml->ml_bvalues[nvals]; nvals++ ) {
360 rc = validate( ad->ad_type->sat_syntax, ml->ml_bvalues[nvals] );
363 slap_mods_free( mod );
364 *text = "value contains invalid data";
365 return LDAP_INVALID_SYNTAX;
370 * a rough single value check... an additional check is needed
371 * to catch add of single value to existing single valued attribute
373 if( ( mod->sml_op == LDAP_MOD_ADD || mod->sml_op == LDAP_MOD_REPLACE )
374 && nvals > 1 && is_at_single_value( ad->ad_type ))
376 slap_mods_free( mod );
377 *text = "multiple values provided";
378 return LDAP_INVALID_SYNTAX;
382 mod->sml_bvalues = ml->ml_bvalues;
383 ml->ml_values = NULL;
386 modtail = &mod->sml_next;
392 int slap_mods_opattrs(
394 Modifications **modtail,
397 struct berval name, timestamp;
398 time_t now = slap_get_time();
403 int mop = op->o_tag == LDAP_REQ_ADD
404 ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
406 assert( modtail != NULL );
407 assert( *modtail == NULL );
409 ldap_pvt_thread_mutex_lock( &gmtime_mutex );
410 ltm = gmtime( &now );
411 strftime( timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", ltm );
412 ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
413 timestamp.bv_val = timebuf;
414 timestamp.bv_len = strlen(timebuf);
416 if( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
417 name.bv_val = SLAPD_ANONYMOUS;
418 name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
420 name.bv_val = op->o_dn;
421 name.bv_len = strlen( op->o_dn );
424 if( op->o_tag == LDAP_REQ_ADD ) {
425 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
427 mod->sml_desc = ad_dup( slap_schema.si_ad_creatorsName );
428 mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
429 mod->sml_bvalues[0] = ber_bvdup( &name );
430 mod->sml_bvalues[1] = NULL;
433 modtail = &mod->sml_next;
435 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
437 mod->sml_desc = ad_dup( slap_schema.si_ad_createTimestamp );
438 mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
439 mod->sml_bvalues[0] = ber_bvdup( ×tamp );
440 mod->sml_bvalues[1] = NULL;
442 modtail = &mod->sml_next;
445 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
447 mod->sml_desc = ad_dup( slap_schema.si_ad_modifiersName );
448 mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
449 mod->sml_bvalues[0] = ber_bvdup( &name );
450 mod->sml_bvalues[1] = NULL;
452 modtail = &mod->sml_next;
454 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
456 mod->sml_desc = ad_dup( slap_schema.si_ad_modifyTimestamp );
457 mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
458 mod->sml_bvalues[0] = ber_bvdup( ×tamp );
459 mod->sml_bvalues[1] = NULL;
461 modtail = &mod->sml_next;
473 ad_free( mod->sm_desc, 1 );
475 if ( mod->sm_bvalues != NULL )
476 ber_bvecfree( mod->sm_bvalues );
489 for ( ; ml != NULL; ml = next ) {
492 slap_mod_free( &ml->sml_mod, 0 );
504 for ( ; ml != NULL; ml = next ) {
510 if ( ml->ml_bvalues != NULL )
511 ber_bvecfree( ml->ml_bvalues );