int backsql_count_children( Operation *op, SQLHDBC dbh, struct berval *dn, unsigned long *nchildren ) { backsql_info *bi = (backsql_info *)op->o_bd->be_private; SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row; RETCODE rc; int res = LDAP_SUCCESS; Debug( LDAP_DEBUG_TRACE, "==>backsql_count_children(): dn=\"%s\"\n", dn->bv_val, 0, 0 ); if ( dn->bv_len > BACKSQL_MAX_DN_LEN ) { Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): DN \"%s\" (%ld bytes) " "exceeds max DN length (%d):\n", dn->bv_val, dn->bv_len, BACKSQL_MAX_DN_LEN ); return LDAP_OTHER; } /* begin TimesTen */ Debug(LDAP_DEBUG_TRACE, "children id query \"%s\"\n", bi->sql_has_children_query, 0, 0); assert( bi->sql_has_children_query != NULL ); rc = backsql_Prepare( dbh, &sth, bi->sql_has_children_query, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): error preparing SQL:\n%s", bi->sql_has_children_query, 0, 0); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); return LDAP_OTHER; } rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, dn ); if ( rc != SQL_SUCCESS) { /* end TimesTen */ Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): " "error binding dn=\"%s\" parameter:\n", dn->bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); return LDAP_OTHER; } rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): " "error executing query (\"%s\", \"%s\"):\n", bi->sql_has_children_query, dn->bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); return LDAP_OTHER; } backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx ); rc = SQLFetch( sth ); if ( BACKSQL_SUCCESS( rc ) ) { char *end; *nchildren = strtol( row.cols[ 0 ], &end, 0 ); if ( end == row.cols[ 0 ] ) { res = LDAP_OTHER; } else { switch ( end[ 0 ] ) { case '\0': break; case '.': { unsigned long ul; /* FIXME: braindead RDBMSes return * a fractional number from COUNT! */ if ( lutil_atoul( &ul, end + 1 ) != 0 || ul != 0 ) { res = LDAP_OTHER; } } break; default: res = LDAP_OTHER; } } } else { res = LDAP_OTHER; } backsql_FreeRow_x( &row, op->o_tmpmemctx ); SQLFreeStmt( sth, SQL_DROP ); Debug( LDAP_DEBUG_TRACE, "<==backsql_count_children(): %lu\n", *nchildren, 0, 0 ); return res; }
static int dds_op_modify( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; dds_info_t *di = (dds_info_t *)on->on_bi.bi_private; Modifications *mod; Entry *e = NULL; BackendInfo *bi = op->o_bd->bd_info; int was_dynamicObject = 0, is_dynamicObject = 0; struct berval bv_entryTtl = BER_BVNULL; time_t entryTtl = 0; char textbuf[ SLAP_TEXT_BUFLEN ]; if ( DDS_OFF( di ) ) { return SLAP_CB_CONTINUE; } /* bv_entryTtl stores the string representation of the entryTtl * across modifies for consistency checks of the final value; * the bv_val points to a static buffer; the bv_len is zero when * the attribute is deleted. * entryTtl stores the integer representation of the entryTtl; * its value is -1 when the attribute is deleted; it is 0 only * if no modifications of the entryTtl occurred, as an entryTtl * of 0 is invalid. */ bv_entryTtl.bv_val = textbuf; op->o_bd->bd_info = (BackendInfo *)on->on_info; rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, slap_schema.si_oc_dynamicObject, slap_schema.si_ad_entryTtl, 0, &e ); if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) { Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryTtl ); /* the value of the entryTtl is saved for later checks */ if ( a != NULL ) { unsigned long ttl; int rc; bv_entryTtl.bv_len = a->a_nvals[ 0 ].bv_len; memcpy( bv_entryTtl.bv_val, a->a_nvals[ 0 ].bv_val, bv_entryTtl.bv_len ); bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0'; rc = lutil_atoul( &ttl, bv_entryTtl.bv_val ); assert( rc == 0 ); entryTtl = (time_t)ttl; } be_entry_release_r( op, e ); e = NULL; was_dynamicObject = is_dynamicObject = 1; } op->o_bd->bd_info = bi; rs->sr_err = LDAP_SUCCESS; for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) { if ( mod->sml_desc == slap_schema.si_ad_objectClass ) { int i; ObjectClass *oc; switch ( mod->sml_op ) { case LDAP_MOD_DELETE: if ( mod->sml_values == NULL ) { is_dynamicObject = 0; break; } for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) { oc = oc_bvfind( &mod->sml_values[ i ] ); if ( oc == slap_schema.si_oc_dynamicObject ) { is_dynamicObject = 0; break; } } break; case LDAP_MOD_REPLACE: if ( mod->sml_values == NULL ) { is_dynamicObject = 0; break; } /* fallthru */ case LDAP_MOD_ADD: for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) { oc = oc_bvfind( &mod->sml_values[ i ] ); if ( oc == slap_schema.si_oc_dynamicObject ) { is_dynamicObject = 1; break; } } break; } } else if ( mod->sml_desc == slap_schema.si_ad_entryTtl ) { unsigned long uttl; time_t ttl; int rc; switch ( mod->sml_op ) { case LDAP_MOD_DELETE: case SLAP_MOD_SOFTDEL: /* FIXME? */ if ( mod->sml_values != NULL ) { if ( BER_BVISEMPTY( &bv_entryTtl ) || !bvmatch( &bv_entryTtl, &mod->sml_values[ 0 ] ) ) { rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; } goto done; } } bv_entryTtl.bv_len = 0; entryTtl = -1; break; case LDAP_MOD_REPLACE: bv_entryTtl.bv_len = 0; entryTtl = -1; /* fallthru */ case LDAP_MOD_ADD: case SLAP_MOD_SOFTADD: /* FIXME? */ case SLAP_MOD_ADD_IF_NOT_PRESENT: /* FIXME? */ assert( mod->sml_values != NULL ); assert( BER_BVISNULL( &mod->sml_values[ 1 ] ) ); if ( !BER_BVISEMPTY( &bv_entryTtl ) ) { rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_text = "attribute 'entryTtl' cannot have multiple values"; rs->sr_err = LDAP_CONSTRAINT_VIOLATION; } goto done; } rc = lutil_atoul( &uttl, mod->sml_values[ 0 ].bv_val ); ttl = (time_t)uttl; assert( rc == 0 ); if ( ttl > DDS_RF2589_MAX_TTL ) { rs->sr_err = LDAP_PROTOCOL_ERROR; rs->sr_text = "invalid time-to-live for dynamicObject"; goto done; } if ( ttl <= 0 || ttl > di->di_max_ttl ) { /* FIXME: I don't understand if this has to be an error, * or an indication that the requested Ttl has been * shortened to di->di_max_ttl >= 1 day */ rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit"; goto done; } entryTtl = ttl; bv_entryTtl.bv_len = mod->sml_values[ 0 ].bv_len; memcpy( bv_entryTtl.bv_val, mod->sml_values[ 0 ].bv_val, bv_entryTtl.bv_len ); bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0'; break; case LDAP_MOD_INCREMENT: if ( BER_BVISEMPTY( &bv_entryTtl ) ) { rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; rs->sr_text = "modify/increment: entryTtl: no such attribute"; } goto done; } entryTtl++; if ( entryTtl > DDS_RF2589_MAX_TTL ) { rs->sr_err = LDAP_PROTOCOL_ERROR; rs->sr_text = "invalid time-to-live for dynamicObject"; } else if ( entryTtl <= 0 || entryTtl > di->di_max_ttl ) { /* FIXME: I don't understand if this has to be an error, * or an indication that the requested Ttl has been * shortened to di->di_max_ttl >= 1 day */ rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit"; } if ( rs->sr_err != LDAP_SUCCESS ) { rc = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rc == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_text = NULL; rs->sr_err = LDAP_NO_SUCH_OBJECT; } goto done; } bv_entryTtl.bv_len = snprintf( textbuf, sizeof( textbuf ), "%ld", entryTtl ); break; default: LDAP_BUG(); break; } } else if ( mod->sml_desc == ad_entryExpireTimestamp ) { /* should have been trapped earlier */ assert( mod->sml_flags & SLAP_MOD_INTERNAL ); } } done:; if ( rs->sr_err == LDAP_SUCCESS ) { int rc; /* FIXME: this could be allowed when the Relax control is used... * in that case: * * TODO * * static => dynamic: * entryTtl must be provided; add * entryExpireTimestamp accordingly * * dynamic => static: * entryTtl must be removed; remove * entryTimestamp accordingly * * ... but we need to make sure that there are no subordinate * issues... */ rc = is_dynamicObject - was_dynamicObject; if ( rc ) { #if 0 /* fix subordinate issues first */ if ( get_relax( op ) ) { switch ( rc ) { case -1: /* need to delete entryTtl to have a consistent entry */ if ( entryTtl != -1 ) { rs->sr_text = "objectClass modification from dynamicObject to static entry requires entryTtl deletion"; rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; } break; case 1: /* need to add entryTtl to have a consistent entry */ if ( entryTtl <= 0 ) { rs->sr_text = "objectClass modification from static entry to dynamicObject requires entryTtl addition"; rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; } break; } } else #endif { switch ( rc ) { case -1: rs->sr_text = "objectClass modification cannot turn dynamicObject into static entry"; break; case 1: rs->sr_text = "objectClass modification cannot turn static entry into dynamicObject"; break; } rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; } if ( rc != LDAP_SUCCESS ) { rc = backend_attribute( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE ); if ( rc == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_text = NULL; rs->sr_err = LDAP_NO_SUCH_OBJECT; } } } } if ( rs->sr_err == LDAP_SUCCESS && entryTtl != 0 ) { Modifications *tmpmod = NULL, **modp; for ( modp = &op->orm_modlist; *modp; modp = &(*modp)->sml_next ) ; tmpmod = ch_calloc( 1, sizeof( Modifications ) ); tmpmod->sml_flags = SLAP_MOD_INTERNAL; tmpmod->sml_type = ad_entryExpireTimestamp->ad_cname; tmpmod->sml_desc = ad_entryExpireTimestamp; *modp = tmpmod; if ( entryTtl == -1 ) { /* delete entryExpireTimestamp */ tmpmod->sml_op = LDAP_MOD_DELETE; } else { time_t expire; char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; struct berval bv; /* keep entryExpireTimestamp consistent * with entryTtl */ expire = slap_get_time() + entryTtl; bv.bv_val = tsbuf; bv.bv_len = sizeof( tsbuf ); slap_timestamp( &expire, &bv ); tmpmod->sml_op = LDAP_MOD_REPLACE; value_add_one( &tmpmod->sml_values, &bv ); value_add_one( &tmpmod->sml_nvalues, &bv ); tmpmod->sml_numvals = 1; } } if ( rs->sr_err ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; send_ldap_result( op, rs ); return rs->sr_err; } return SLAP_CB_CONTINUE; }