#include "rpc_server/samr/proto.h"
#include "../lib/util/util_ldb.h"
#include "param/param.h"
+#include "lib/util/tsort.h"
/* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
ZERO_STRUCTP(r->out.connect_handle);
- c_state = talloc(dce_call->conn, struct samr_connect_state);
+ c_state = talloc(mem_ctx, struct samr_connect_state);
if (!c_state) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_INVALID_PARAMETER;
}
- d_state = talloc(c_state, struct samr_domain_state);
+ d_state = talloc(mem_ctx, struct samr_domain_state);
if (!d_state) {
return NT_STATUS_NO_MEMORY;
}
}
/* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
- info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
+ info->num_users = samdb_search_count(state->sam_ctx, state->domain_dn,
"(objectClass=user)");
- info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
- "(&(objectClass=group)(sAMAccountType=%u))",
- ATYPE_GLOBAL_GROUP);
- info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
- "(&(objectClass=group)(sAMAccountType=%u))",
- ATYPE_LOCAL_GROUP);
+ info->num_groups = samdb_search_count(state->sam_ctx, state->domain_dn,
+ "(&(objectClass=group)(groupType=%u))",
+ GTYPE_SECURITY_GLOBAL_GROUP);
+ info->num_aliases = samdb_search_count(state->sam_ctx, state->domain_dn,
+ "(&(objectClass=group)(groupType=%u))",
+ GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
return NT_STATUS_OK;
}
break;
}
case 9:
+ {
attrs = NULL;
- break;
+ break;
+ }
case 11:
{
static const char * const attrs2[] = { "oEMInformation",
attrs = attrs2;
break;
}
+ default:
+ {
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
}
/* some levels don't need a search */
case 13:
return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
&info->info13);
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
}
-
- return NT_STATUS_INVALID_INFO_CLASS;
}
return NT_STATUS_OK;
case 12:
-
+ /*
+ * It is not possible to set lockout_duration < lockout_window.
+ * (The test is the other way around since the negative numbers
+ * are stored...)
+ *
+ * TODO:
+ * This check should be moved to the backend, i.e. to some
+ * ldb module under dsdb/samdb/ldb_modules/ .
+ *
+ * This constraint is documented here for the samr rpc service:
+ * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
+ * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
+ *
+ * And here for the ldap backend:
+ * MS-ADTS 3.1.1.5.3.2 Constraints
+ * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
+ */
+ if (r->in.info->info12.lockout_duration >
+ r->in.info->info12.lockout_window)
+ {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- a_state = talloc(d_state, struct samr_account_state);
+ a_state = talloc(mem_ctx, struct samr_account_state);
if (!a_state) {
return NT_STATUS_NO_MEMORY;
}
}
/* sort the results by rid */
- qsort(entries, count, sizeof(struct samr_SamEntry),
- (comparison_fn_t)compare_SamEntry);
+ TYPESAFE_QSORT(entries, count, compare_SamEntry);
/* find the first entry to return */
for (first=0;
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- a_state = talloc(d_state, struct samr_account_state);
+ a_state = talloc(mem_ctx, struct samr_account_state);
if (!a_state) {
ldb_transaction_cancel(d_state->sam_ctx);
return NT_STATUS_NO_MEMORY;
}
/* modify the samdb record */
- ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
+ ret = dsdb_replace(a_state->sam_ctx, msg, 0);
if (ret != LDB_SUCCESS) {
DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
ldb_dn_get_linearized(msg->dn),
}
/* sort the results by rid */
- qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry),
- (comparison_fn_t)compare_SamEntry);
+ TYPESAFE_QSORT(entries, num_filtered_entries, compare_SamEntry);
/* find the first entry to return */
for (first=0;
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- a_state = talloc(d_state, struct samr_account_state);
+ a_state = talloc(mem_ctx, struct samr_account_state);
if (!a_state) {
return NT_STATUS_NO_MEMORY;
}
}
/* sort the results by rid */
- qsort(entries, count, sizeof(struct samr_SamEntry),
- (comparison_fn_t)compare_SamEntry);
+ TYPESAFE_QSORT(entries, count, compare_SamEntry);
/* find the first entry to return */
for (first=0;
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- a_state = talloc(d_state, struct samr_account_state);
+ a_state = talloc(mem_ctx, struct samr_account_state);
if (!a_state) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_UNSUCCESSFUL;
}
+ talloc_free(h);
ZERO_STRUCTP(r->out.group_handle);
return NT_STATUS_OK;
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- a_state = talloc(d_state, struct samr_account_state);
+ a_state = talloc(mem_ctx, struct samr_account_state);
if (!a_state) {
return NT_STATUS_NO_MEMORY;
}
a_state = h->data;
ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
- if (ret != 0) {
+ if (ret != LDB_SUCCESS) {
return NT_STATUS_UNSUCCESSFUL;
}
+ talloc_free(h);
ZERO_STRUCTP(r->out.alias_handle);
return NT_STATUS_OK;
return NT_STATUS_UNSUCCESSFUL;
}
+ talloc_free(h);
ZERO_STRUCTP(r->out.user_handle);
return NT_STATUS_OK;
attrs = attrs2;
break;
}
+ case 18:
+ {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
case 20:
{
static const char * const attrs2[] = {"userParameters",
attrs = attrs2;
break;
}
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+ default:
+ {
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
}
/* pull all the user attributes */
}
if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
- "member", memberdn) != 0)
+ "member", memberdn) != LDB_SUCCESS)
return NT_STATUS_NO_MEMORY;
- if (ldb_modify(d_state->sam_ctx, mod) != 0)
+ if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
return NT_STATUS_UNSUCCESSFUL;
talloc_free(mod);
ZERO_STRUCTP(r->out.info);
- sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
+ dce_call->conn->auth_state.session_info);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
"pwdProperties", 1);
talloc_free(msgs);
- talloc_free(sam_ctx);
+ talloc_unlink(mem_ctx, sam_ctx);
return NT_STATUS_OK;
}
/*
- samr_ValidatePassword
+ samr_ValidatePassword
+
+ For now the call checks the password complexity (if active) and the minimum
+ password length on level 2 and 3. Level 1 is ignored for now.
*/
-static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct samr_ValidatePassword *r)
+static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct samr_ValidatePassword *r)
{
- /* just say it's OK for now - we need to hook this into our
- password strength code later */
- DEBUG(0,(__location__ ": Faking samr_ValidatePassword reply\n"));
+ struct samr_GetDomPwInfo r2;
+ struct samr_PwInfo pwInfo;
+ DATA_BLOB password;
+ enum samr_ValidationStatus res;
+ NTSTATUS status;
+
(*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
+
+ r2.in.domain_name = NULL;
+ r2.out.info = &pwInfo;
+ status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ switch (r->in.level) {
+ case NetValidateAuthentication:
+ /* we don't support this yet */
+ return NT_STATUS_NOT_SUPPORTED;
+ break;
+ case NetValidatePasswordChange:
+ password = data_blob_const(r->in.req->req2.password.string,
+ r->in.req->req2.password.length);
+ res = samdb_check_password(&password,
+ pwInfo.password_properties,
+ pwInfo.min_password_length);
+ (*r->out.rep)->ctr2.status = res;
+ break;
+ case NetValidatePasswordReset:
+ password = data_blob_const(r->in.req->req3.password.string,
+ r->in.req->req3.password.length);
+ res = samdb_check_password(&password,
+ pwInfo.password_properties,
+ pwInfo.min_password_length);
+ (*r->out.rep)->ctr3.status = res;
+ break;
+ default:
+ return NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
return NT_STATUS_OK;
}