+/*
+ * convert a raw list of modifications to internal format
+ * Do basic attribute type checking and syntax validation.
+ */
+int slap_modlist2mods(
+ LDAPModList *ml,
+ int update,
+ Modifications **mods,
+ const char **text )
+{
+ int rc;
+ Modifications **modtail = mods;
+
+ for( ; ml != NULL; ml = ml->ml_next ) {
+ Modifications *mod;
+ AttributeDescription *ad = NULL;
+
+ mod = (Modifications *)
+ ch_calloc( 1, sizeof(Modifications) );
+
+ /* copy the op */
+ mod->sml_op = ml->ml_op;
+
+ /* convert to attribute description */
+ rc = slap_str2ad( ml->ml_type, &mod->sml_desc, text );
+
+ if( rc != LDAP_SUCCESS ) {
+ slap_mods_free( mod );
+ return rc;
+ }
+
+ ad = mod->sml_desc;
+
+ if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
+ && !slap_ad_is_binary( ad ))
+ {
+ /* attribute requires binary transfer */
+ slap_mods_free( mod );
+ *text = "attribute requires ;binary transfer";
+ return LDAP_UNDEFINED_TYPE;
+ }
+
+ if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
+ && slap_ad_is_binary( ad ))
+ {
+ /* attribute requires binary transfer */
+ slap_mods_free( mod );
+ *text = "attribute disallows ;binary transfer";
+ return LDAP_UNDEFINED_TYPE;
+ }
+
+ if (!update && is_at_no_user_mod( ad->ad_type )) {
+ /* user modification disallowed */
+ slap_mods_free( mod );
+ *text = "no user modification allowed";
+ return LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ /*
+ * check values
+ */
+ if( ml->ml_bvalues != NULL ) {
+ ber_len_t nvals;
+ slap_syntax_validate_func *validate =
+ ad->ad_type->sat_syntax->ssyn_validate;
+
+ if( !validate ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "modlist2mods: no validator for syntax %s\n",
+ ad->ad_type->sat_syntax->ssyn_oid, 0, 0 );
+ slap_mods_free( mod );
+ *text = "no validator for syntax";
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /*
+ * check that each value is valid per syntax
+ */
+ for( nvals = 0; ml->ml_bvalues[nvals]; nvals++ ) {
+ rc = validate( ad->ad_type->sat_syntax, ml->ml_bvalues[nvals] );
+
+ if( rc != 0 ) {
+ slap_mods_free( mod );
+ *text = "value contains invalid data";
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ /*
+ * a rough single value check... an additional check is needed
+ * to catch add of single value to existing single valued attribute
+ */
+ if( ( mod->sml_op == LDAP_MOD_ADD || mod->sml_op == LDAP_MOD_REPLACE )
+ && nvals > 1 && is_at_single_value( ad->ad_type ))
+ {
+ slap_mods_free( mod );
+ *text = "multiple values provided";
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ mod->sml_bvalues = ml->ml_bvalues;
+ ml->ml_values = NULL;
+
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int slap_mods_opattrs(
+ Operation *op,
+ Modifications **modtail,
+ const char **text )
+{
+ struct berval name, timestamp;
+ time_t now = slap_get_time();
+ char timebuf[22];
+ struct tm *ltm;
+ Modifications *mod;
+
+ int mop = op->o_tag == LDAP_REQ_ADD
+ ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
+
+ assert( modtail != NULL );
+ assert( *modtail == NULL );
+
+ ldap_pvt_thread_mutex_lock( &gmtime_mutex );
+ ltm = gmtime( &now );
+ strftime( timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", ltm );
+ ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
+ timestamp.bv_val = timebuf;
+ timestamp.bv_len = strlen(timebuf);
+
+ if( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
+ name.bv_val = SLAPD_ANONYMOUS;
+ name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
+ } else {
+ name.bv_val = op->o_dn;
+ name.bv_len = strlen( op->o_dn );
+ }
+
+ if( op->o_tag == LDAP_REQ_ADD ) {
+ mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_desc = ad_dup( slap_schema.si_ad_creatorsName );
+ mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
+ mod->sml_bvalues[0] = ber_bvdup( &name );
+ mod->sml_bvalues[1] = NULL;
+
+ *modtail = mod;
+ modtail = &mod->sml_next;
+
+ mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_desc = ad_dup( slap_schema.si_ad_createTimestamp );
+ mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
+ mod->sml_bvalues[0] = ber_bvdup( ×tamp );
+ mod->sml_bvalues[1] = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+
+ mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_desc = ad_dup( slap_schema.si_ad_modifiersName );
+ mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
+ mod->sml_bvalues[0] = ber_bvdup( &name );
+ mod->sml_bvalues[1] = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+
+ mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ) );
+ mod->sml_op = mop;
+ mod->sml_desc = ad_dup( slap_schema.si_ad_modifyTimestamp );
+ mod->sml_bvalues = (struct berval **) malloc( 2 * sizeof( struct berval * ) );
+ mod->sml_bvalues[0] = ber_bvdup( ×tamp );
+ mod->sml_bvalues[1] = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+
+ return LDAP_SUCCESS;
+}
+
+
+void
+slap_mod_free(
+ Modification *mod,
+ int freeit
+)
+{
+ ad_free( mod->sm_desc, 1 );
+
+ if ( mod->sm_bvalues != NULL )
+ ber_bvecfree( mod->sm_bvalues );
+
+ if( freeit )
+ free( mod );
+}
+
+void
+slap_mods_free(
+ Modifications *ml
+)
+{
+ Modifications *next;
+
+ for ( ; ml != NULL; ml = next ) {
+ next = ml->sml_next;
+
+ slap_mod_free( &ml->sml_mod, 0 );
+ free( ml );
+ }
+}
+
+void
+slap_modlist_free(