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/string.h>
#include <ac/time.h>
#include <ac/socket.h>
do_add( Operation *op, SlapReply *rs )
char *last;
Pierangelo Masarati
committed
struct berval dn = BER_BVNULL;
ber_len_t len;
ber_tag_t tag;
Pierangelo Masarati
committed
char textbuf[ SLAP_TEXT_BUFLEN ];
size_t textlen = sizeof( textbuf );
Pierangelo Masarati
committed
Debug( LDAP_DEBUG_TRACE, "%s do_add\n",
op->o_log_prefix, 0, 0 );
/*
* Parse the add request. It looks like this:
*
* AddRequest := [APPLICATION 14] SEQUENCE {
* name DistinguishedName,
* attrs SEQUENCE OF SEQUENCE {
* type AttributeType,
* values SET OF AttributeValue
* }
* }
*/
/* get the name */
if ( ber_scanf( ber, "{m", /*}*/ &dn ) == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "%s do_add: ber_scanf failed\n",
op->o_log_prefix, 0, 0 );
send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
Debug( LDAP_DEBUG_ARGS, "%s do_add: dn (%s)\n",
op->o_log_prefix, dn.bv_val, 0 );
/* get the attrs */
for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
tag = ber_next_element( ber, &len, last ) )
{
tmp.sml_nvalues = NULL;
rtag = ber_scanf( ber, "{m{W}}", &tmp.sml_type, &tmp.sml_values );
if ( rtag == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "%s do_add: decoding error\n",
op->o_log_prefix, 0, 0 );
send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
Debug( LDAP_DEBUG_ANY, "%s do_add: no values for type %s\n",
op->o_log_prefix, tmp.sml_type.bv_val, 0 );
send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
"no values for attribute type" );
mod = (Modifications *) ch_malloc( sizeof(Modifications) );
mod->sml_flags = 0;
mod->sml_next = NULL;
mod->sml_desc = NULL;
mod->sml_values = tmp.sml_values;
mod->sml_nvalues = NULL;
if ( ber_scanf( ber, /*{*/ "}") == LBER_ERROR ) {
Debug( LDAP_DEBUG_ANY, "%s do_add: ber_scanf failed\n",
op->o_log_prefix, 0, 0 );
send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
Pierangelo Masarati
committed
if ( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "%s do_add: 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_add: invalid dn (%s)\n",
op->o_log_prefix, dn.bv_val, 0 );
send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
goto done;
}
op->ora_e = entry_alloc();
ber_dupbv( &op->ora_e->e_name, &op->o_req_dn );
ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn );
Statslog( LDAP_DEBUG_STATS, "%s ADD dn=\"%s\"\n",
op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );
send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
"no attributes provided" );
goto done;
}
Pierangelo Masarati
committed
if ( dn_match( &op->ora_e->e_nname, &slap_empty_bv ) ) {
/* protocolError may be a more appropriate error */
send_ldap_error( op, rs, LDAP_ALREADY_EXISTS,
"root DSE already exists" );
Pierangelo Masarati
committed
} else if ( dn_match( &op->ora_e->e_nname, &frontendDB->be_schemandn ) ) {
send_ldap_error( op, rs, LDAP_ALREADY_EXISTS,
"subschema subentry already exists" );
goto done;
rs->sr_err = slap_mods_check( op, modlist, &rs->sr_text,
Pierangelo Masarati
committed
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto done;
}
Pierangelo Masarati
committed
/* temporary; remove if not invoking backend function */
op->ora_modlist = modlist;
/* call this so global overlays/SLAPI have access to ora_e */
rs->sr_err = slap_mods2entry( op->ora_modlist, &op->ora_e,
1, 0, &rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto done;
}
oex.oe.oe_key = (void *)do_add;
oex.oe_db = NULL;
LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
Pierangelo Masarati
committed
op->o_bd = frontendDB;
Pierangelo Masarati
committed
rc = frontendDB->be_add( op, rs );
LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
#ifdef LDAP_X_TXN
if ( rc == LDAP_X_TXN_SPECIFY_OKAY ) {
/* skip cleanup */
return rc;
} else
#endif
Pierangelo Masarati
committed
if ( rc == 0 ) {
Pierangelo Masarati
committed
be_entry_release_w( op, op->ora_e );
Pierangelo Masarati
committed
op->ora_e = NULL;
Pierangelo Masarati
committed
}
Pierangelo Masarati
committed
}
done:;
Pierangelo Masarati
committed
if ( modlist != NULL ) {
/* in case of error, free the values as well */
slap_mods_free( modlist, freevals );
Pierangelo Masarati
committed
}
Pierangelo Masarati
committed
if ( op->ora_e != NULL ) {
entry_free( op->ora_e );
Pierangelo Masarati
committed
}
op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
Pierangelo Masarati
committed
return rc;
Pierangelo Masarati
committed
}
int
fe_op_add( Operation *op, SlapReply *rs )
{
Modifications **modtail = &op->ora_modlist;
char textbuf[ SLAP_TEXT_BUFLEN ];
size_t textlen = sizeof( textbuf );
Pierangelo Masarati
committed
/*
* 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->ora_e->e_nname, 1 );
if ( op->o_bd == NULL ) {
rs->sr_ref = referral_rewrite( default_referral,
Pierangelo Masarati
committed
NULL, &op->ora_e->e_name, 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 ) {
} 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->ora_e->e_nname, 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->ora_modlist,
&rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto done;
}
/*
* do the add if 1 && (2 || 3)
* 1) there is an add 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 updatedn.
*/
if ( op->o_bd->be_add ) {
int repl_user = be_isupdate( op );
if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) {
Pierangelo Masarati
committed
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->ora_modlist,
&rs->sr_text, textbuf, textlen );
Pierangelo Masarati
committed
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto done;
}
if ( !repl_user ) {
Pierangelo Masarati
committed
/* go to the last mod */
for ( modtail = &op->ora_modlist;
Pierangelo Masarati
committed
*modtail != NULL;
modtail = &(*modtail)->sml_next )
assert( (*modtail)->sml_op == LDAP_MOD_ADD );
assert( (*modtail)->sml_desc != NULL );
Pierangelo Masarati
committed
/* check for unmodifiable attributes */
rs->sr_err = slap_mods_no_repl_user_mod_check( op,
op->ora_modlist, &rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto done;
}
Pierangelo Masarati
committed
rc = op->o_bd->be_add( op, rs );
Pierangelo Masarati
committed
/* NOTE: be_entry_release_w() is
* called by do_add(), so that global
* overlays on the way back can
* at least read the entry */
LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
if ( oex->oe_key == (void *)do_add ) {
((OpExtraDB *)oex)->oe_db = op->o_bd;
break;
}
}
? op->o_bd->be_update_refs : default_referral;
if ( defref != NULL ) {
rs->sr_ref = referral_rewrite( defref,
Pierangelo Masarati
committed
NULL, &op->ora_e->e_name, LDAP_SCOPE_DEFAULT );
if ( rs->sr_ref == NULL ) rs->sr_ref = defref;
rs->sr_err = LDAP_REFERRAL;
if (!rs->sr_ref) rs->sr_ref = default_referral;
send_ldap_result( op, rs );
if ( rs->sr_ref != default_referral ) {
} else {
send_ldap_error( op, rs,
LDAP_UNWILLING_TO_PERFORM,
"shadow context; no update referral" );
}
Debug( LDAP_DEBUG_ARGS, "do_add: no backend support\n", 0, 0, 0 );
send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
Pierangelo Masarati
committed
done:;
Pierangelo Masarati
committed
int
slap_mods2entry(
Modifications *mods,
Entry **e,
int initial,
const char **text,
char *textbuf, size_t textlen )
if ( initial ) {
for ( tail = &(*e)->e_attrs; *tail != NULL; tail = &(*tail)->a_next )
;
for( ; mods != NULL; mods = mods->sml_next ) {
Attribute *attr;
assert( mods->sml_desc != NULL );
attr = attr_find( (*e)->e_attrs, mods->sml_desc );
if( attr != NULL ) {
#define SLURPD_FRIENDLY
#ifdef SLURPD_FRIENDLY
if ( !initial ) {
/*
* This check allows overlays to override operational
* attributes by setting them directly in the entry.
* We assume slap_mods_no_user_mod_check() was called
* with the user modifications.
*/
*text = NULL;
return LDAP_SUCCESS;
}
i = attr->a_numvals;
j = mods->sml_numvals;
attr->a_numvals += j;
j++; /* NULL */
attr->a_vals = ch_realloc( attr->a_vals,
/* checked for duplicates in slap_mods_check */
if ( dup ) {
for ( j = 0; mods->sml_values[j].bv_val; j++ ) {
ber_dupbv( &attr->a_vals[i+j], &mods->sml_values[j] );
}
Hallvard Furuseth
committed
BER_BVZERO( &attr->a_vals[i+j] );
j++;
} else {
AC_MEMCPY( &attr->a_vals[i], mods->sml_values,
sizeof( struct berval ) * j );
}
if( mods->sml_nvalues ) {
attr->a_nvals = ch_realloc( attr->a_nvals,
sizeof( struct berval ) * (i+j) );
if ( dup ) {
for ( j = 0; mods->sml_nvalues[j].bv_val; j++ ) {
ber_dupbv( &attr->a_nvals[i+j], &mods->sml_nvalues[j] );
}
BER_BVZERO( &attr->a_nvals[i+j] );
} else {
AC_MEMCPY( &attr->a_nvals[i], mods->sml_nvalues,
sizeof( struct berval ) * j );
}
} else {
attr->a_nvals = attr->a_vals;
snprintf( textbuf, textlen,
"attribute '%s' provided more than once",
mods->sml_desc->ad_cname.bv_val );
return LDAP_TYPE_OR_VALUE_EXISTS;
#endif
attr = attr_alloc( mods->sml_desc );
/* move values to attr structure */
i = mods->sml_numvals;
attr->a_numvals = mods->sml_numvals;
if ( dup ) {
attr->a_vals = (BerVarray) ch_calloc( i+1, sizeof( BerValue ));
ber_dupbv( &attr->a_vals[i], &mods->sml_values[i] );
} else {
attr->a_vals = mods->sml_values;
}
if ( mods->sml_nvalues ) {
attr->a_nvals = (BerVarray) ch_calloc( i+1, sizeof( BerValue ));
ber_dupbv( &attr->a_nvals[i], &mods->sml_nvalues[i] );
} else {
attr->a_nvals = mods->sml_nvalues;
}
} else {
attr->a_nvals = attr->a_vals;
}
*tail = attr;
tail = &attr->a_next;
}
return LDAP_SUCCESS;
Pierangelo Masarati
committed
int
slap_entry2mods(
Entry *e,
Modifications **mods,
{
Modifications *modhead = NULL;
Modifications *mod;
Modifications **modtail = &modhead;
Attribute *a_new;
AttributeDescription *a_new_desc;
a_new = e->e_attrs;
while ( a_new != NULL ) {
a_new_desc = a_new->a_desc;
mod = (Modifications *) ch_malloc( sizeof( Modifications ));
mod->sml_op = LDAP_MOD_REPLACE;
mod->sml_flags = 0;
mod->sml_type = a_new_desc->ad_cname;
count = a_new->a_numvals;
mod->sml_numvals = a_new->a_numvals;
/* see slap_mods_check() comments...
* if a_vals == a_nvals, there is no normalizer.
* in this case, mod->sml_nvalues must be left NULL.
*/
if ( a_new->a_vals != a_new->a_nvals ) {
(count+1) * sizeof( struct berval) );
} else {
mod->sml_nvalues = NULL;
}
for ( i = 0; i < count; i++ ) {
ber_dupbv( mod->sml_nvalues+i, a_new->a_nvals+i );
mod->sml_values[count].bv_val = NULL;
mod->sml_values[count].bv_len = 0;
mod->sml_nvalues[count].bv_len = 0;
}
mod->sml_next =NULL;
*modtail = mod;
modtail = &mod->sml_next;
a_new = a_new->a_next;
}
return LDAP_SUCCESS;
}
int slap_add_opattrs(
Operation *op,
const char **text,
char *textbuf,
size_t textlen,
int manage_ctxcsn )
{
struct berval name, timestamp, csn = BER_BVNULL;
struct berval nname, tmp;
char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
Attribute *a;
if ( SLAP_LASTMOD( op->o_bd ) ) {
char *ptr;
int gotcsn = 0;
a = attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryCSN );
if ( a ) {
gotcsn = 1;
csn = a->a_vals[0];
}
if ( !gotcsn ) {
csn.bv_val = csnbuf;
csn.bv_len = sizeof(csnbuf);
slap_get_csn( op, &csn, manage_ctxcsn );
} else {
if ( manage_ctxcsn )
slap_queue_csn( op, &csn );
}
ptr = ber_bvchr( &csn, '#' );
timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ");
timebuf[timestamp.bv_len-1] = 'Z';
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
timebuf[timestamp.bv_len] = '\0';
} else {
time_t now = slap_get_time();
timestamp.bv_len = sizeof(timebuf);
slap_timestamp( &now, ×tamp );
}
if ( BER_BVISEMPTY( &op->o_dn ) ) {
BER_BVSTR( &name, SLAPD_ANONYMOUS );
nname = name;
} else {
name = op->o_dn;
nname = op->o_ndn;
}
a = attr_find( op->ora_e->e_attrs,
slap_schema.si_ad_entryUUID );
if ( !a ) {
char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
tmp.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
tmp.bv_val = uuidbuf;
attr_merge_normalize_one( op->ora_e,
slap_schema.si_ad_entryUUID, &tmp, op->o_tmpmemctx );
}
a = attr_find( op->ora_e->e_attrs,
slap_schema.si_ad_creatorsName );
if ( !a ) {
attr_merge_one( op->ora_e,
slap_schema.si_ad_creatorsName, &name, &nname );
}
a = attr_find( op->ora_e->e_attrs,
slap_schema.si_ad_createTimestamp );
if ( !a ) {
attr_merge_one( op->ora_e,
slap_schema.si_ad_createTimestamp, ×tamp, NULL );
}
if ( !gotcsn ) {
attr_merge_one( op->ora_e,
slap_schema.si_ad_entryCSN, &csn, NULL );
}
a = attr_find( op->ora_e->e_attrs,
slap_schema.si_ad_modifiersName );
if ( !a ) {
attr_merge_one( op->ora_e,
slap_schema.si_ad_modifiersName, &name, &nname );
}
a = attr_find( op->ora_e->e_attrs,
slap_schema.si_ad_modifyTimestamp );
if ( !a ) {
attr_merge_one( op->ora_e,
slap_schema.si_ad_modifyTimestamp, ×tamp, NULL );
}
}