+/*
+ filter from controls from clients in several ways
+
+ 1) mark our registered controls as non-critical in the request
+
+ This is needed as clients may mark controls as critical even if
+ they are not needed at all in a request. For example, the centrify
+ client sets the SD_FLAGS control as critical on ldap modify
+ requests which are setting the dNSHostName attribute on the
+ machine account. That request doesn't need SD_FLAGS at all, but
+ centrify adds it on all ldap requests.
+
+ 2) if this request is untrusted then remove any non-registered
+ controls that are non-critical
+
+ This is used on ldap:// connections to prevent remote users from
+ setting an internal control that may be dangerous
+
+ 3) if this request is untrusted then fail any request that includes
+ a critical non-registered control
+ */
+static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req)
+{
+ unsigned int i, j;
+ struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
+ bool is_untrusted;
+
+ if (!req->controls) {
+ return LDB_SUCCESS;
+ }
+
+ is_untrusted = ldb_req_is_untrusted(req);
+
+ for (i=0; req->controls[i]; i++) {
+ bool is_registered = false;
+ bool is_critical = (req->controls[i]->critical != 0);
+
+ if (req->controls[i]->oid == NULL) {
+ continue;
+ }
+
+ if (is_untrusted || is_critical) {
+ for (j=0; j<priv->num_controls; j++) {
+ if (strcasecmp(priv->controls[j], req->controls[i]->oid) == 0) {
+ is_registered = true;
+ break;
+ }
+ }
+ }
+
+ if (is_untrusted && !is_registered) {
+ if (!is_critical) {
+ /* remove it by marking the oid NULL */
+ req->controls[i]->oid = NULL;
+ req->controls[i]->data = NULL;
+ req->controls[i]->critical = 0;
+ continue;
+ }
+ /* its a critical unregistered control - give
+ an error */
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Attempt to use critical non-registered control '%s'",
+ req->controls[i]->oid);
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
+ if (!is_critical) {
+ continue;
+ }
+
+ if (is_registered) {
+ req->controls[i]->critical = 0;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
+
+static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
+{
+ struct auth_session_info *session_info;
+ struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
+ bool is_untrusted = ldb_req_is_untrusted(req);
+ bool is_anonymous = true;
+ if (is_untrusted == false) {
+ return LDB_SUCCESS;
+ }
+
+ session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo");
+ if (session_info) {
+ is_anonymous = security_token_is_anonymous(session_info->security_token);
+ }
+
+ if (is_anonymous == false || (priv && priv->block_anonymous == false)) {
+ return LDB_SUCCESS;
+ }
+
+ if (req->operation == LDB_SEARCH) {
+ if (req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base)) {
+ return LDB_SUCCESS;
+ }
+ }
+ ldb_set_errstring(ldb_module_get_ctx(module), "Operation unavailable without authentication");
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+