Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}