summaryrefslogtreecommitdiff
path: root/source4/rpc_server
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2004-05-15 07:51:38 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:53:46 -0500
commit064e7447bebd715c8351d9a0ee31f648990f2336 (patch)
tree156925cd7c8d4616f0eca3a743b7323b3b0b23b7 /source4/rpc_server
parent31b9470996632d717c3c74482308e200906fdb8f (diff)
downloadsamba-064e7447bebd715c8351d9a0ee31f648990f2336.tar.gz
samba-064e7447bebd715c8351d9a0ee31f648990f2336.tar.bz2
samba-064e7447bebd715c8351d9a0ee31f648990f2336.zip
r743: Start on a NETLOGON server in Samba4.
Currently this only authentiates the machine, not real users. As a consequence of running the Samba4 NETLOGON test against Samba4, I found a number of issues in the SAMR server, which I have addressed. There are more templates in the provison.ldif for this reason. I also added some debug to our credentials code, and fixed some bugs in the auth_sam module. The static buffer in generate_random_string() bit me badly, so I removed it in favor of a talloc based system. Andrew Bartlett (This used to be commit 94624e519b66def97758b8a48a01ffe9029176f0)
Diffstat (limited to 'source4/rpc_server')
-rw-r--r--source4/rpc_server/config.m43
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c467
-rw-r--r--source4/rpc_server/samr/dcesrv_samr.c77
-rw-r--r--source4/rpc_server/samr/samdb.c202
-rw-r--r--source4/rpc_server/samr/samr_utils.c134
5 files changed, 777 insertions, 106 deletions
diff --git a/source4/rpc_server/config.m4 b/source4/rpc_server/config.m4
index 8c5f8baafc..20b8e5e2b1 100644
--- a/source4/rpc_server/config.m4
+++ b/source4/rpc_server/config.m4
@@ -4,7 +4,7 @@ SMB_SUBSYSTEM(DCERPC_COMMON,[],
[rpc_server/common/server_info.o
rpc_server/common/share_info.o])
-SMB_SUBSYSTEM(SAMDB,[rpc_server/samr/samdb.o],[],[],[LIBLDB])
+SMB_SUBSYSTEM(SAMDB,[rpc_server/samr/samdb.o rpc_server/samr/samr_utils.o],[],[],[LIBLDB])
SMB_MODULE(dcerpc_rpcecho,DCERPC,STATIC,[rpc_server/echo/rpc_echo.o])
SMB_MODULE(dcerpc_epmapper,DCERPC,STATIC,[rpc_server/epmapper/rpc_epmapper.o])
@@ -13,6 +13,7 @@ SMB_MODULE(dcerpc_srvsvc,DCERPC,STATIC,[rpc_server/srvsvc/dcesrv_srvsvc.o],[],[]
SMB_MODULE(dcerpc_wkssvc,DCERPC,STATIC,[rpc_server/wkssvc/dcesrv_wkssvc.o],[],[],[DCERPC_COMMON])
SMB_MODULE(dcerpc_samr,DCERPC,STATIC,[rpc_server/samr/dcesrv_samr.o],[],[],[SAMDB DCERPC_COMMON])
SMB_MODULE(dcerpc_winreg,DCERPC,STATIC,[rpc_server/winreg/rpc_winreg.o],[],[],[REGISTRY])
+SMB_MODULE(dcerpc_netlogon,DCERPC,STATIC,[rpc_server/netlogon/dcerpc_netlogon.o],[],[],[SAMDB DCERPC_COMMON])
SMB_SUBSYSTEM(DCERPC,rpc_server/dcerpc_server.o,
[rpc_server/dcerpc_tcp.o
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
new file mode 100644
index 0000000000..0c78ed1864
--- /dev/null
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -0,0 +1,467 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the netlogon pipe
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "rpc_server/common/common.h"
+
+struct server_pipe_state {
+ TALLOC_CTX *mem_ctx;
+ struct netr_Credential client_challenge;
+ struct netr_Credential server_challenge;
+ BOOL authenticated;
+ char *account_name;
+ char *computer_name; /* for logging only */
+ uint32 acct_flags;
+ uint16 sec_chan_type;
+ struct creds_CredentialState *creds;
+};
+
+static NTSTATUS netlogon_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *di)
+{
+ dce_call->conn->private = NULL;
+
+ return NT_STATUS_OK;
+}
+
+/* this function is called when the client disconnects the endpoint */
+static void netlogon_unbind(struct dcesrv_connection *conn, const struct dcesrv_interface *di)
+{
+ struct server_pipe_state *pipe_state = conn->private;
+
+ if (pipe_state)
+ talloc_destroy(pipe_state->mem_ctx);
+
+ conn->private = NULL;
+}
+
+#define DCESRV_INTERFACE_NETLOGON_BIND netlogon_bind
+#define DCESRV_INTERFACE_NETLOGON_UNBIND netlogon_unbind
+
+/*
+ netr_ServerReqChallenge
+
+ NTSTATUS netr_ServerReqChallenge(
+ [in] unistr *server_name,
+ [in] unistr computer_name,
+ [in][out] netr_Credential credentials
+ );
+
+*/
+static NTSTATUS netr_ServerReqChallenge(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_ServerReqChallenge *r)
+{
+ struct server_pipe_state *pipe_state = dce_call->conn->private;
+ TALLOC_CTX *pipe_mem_ctx;
+
+ ZERO_STRUCT(r->out.credentials);
+
+ /* destroyed on pipe shutdown */
+
+ if (pipe_state) {
+ talloc_destroy(pipe_state->mem_ctx);
+ dce_call->conn->private = NULL;
+ }
+
+ pipe_mem_ctx = talloc_init("internal netlogon pipe state for %s",
+ r->in.computer_name);
+
+ if (!pipe_mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pipe_state = talloc_p(pipe_mem_ctx, struct server_pipe_state);
+ if (!pipe_state) {
+ talloc_destroy(pipe_mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pipe_state->mem_ctx = pipe_mem_ctx;
+ pipe_state->authenticated = False;
+ pipe_state->creds = NULL;
+ pipe_state->account_name = NULL;
+ pipe_state->computer_name = NULL;
+
+ pipe_state->client_challenge = r->in.credentials;
+
+ generate_random_buffer(pipe_state->server_challenge.data,
+ sizeof(pipe_state->server_challenge.data),
+ False);
+
+ r->out.credentials = pipe_state->server_challenge;
+
+ dce_call->conn->private = pipe_state;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ netr_ServerAuthenticate
+
+ secure channel types:
+
+ const int SEC_CHAN_WKSTA = 2;
+ const int SEC_CHAN_DOMAIN = 4;
+ const int SEC_CHAN_BDC = 6;
+
+ NTSTATUS netr_ServerAuthenticate(
+ [in] unistr *server_name,
+ [in] unistr username,
+ [in] uint16 secure_channel_type,
+ [in] unistr computer_name,
+ [in,out] netr_Credential credentials
+ );
+
+
+*/
+
+static NTSTATUS netr_ServerAuthenticateInternals(struct server_pipe_state *pipe_state,
+ TALLOC_CTX *mem_ctx,
+ const char *account_name,
+ const char *computer_name,
+ uint16 secure_channel_type,
+ uint32 in_flags,
+ const struct netr_Credential *client_credentials,
+ struct netr_Credential *server_credentials,
+ uint32 *out_flags)
+{
+ void *sam_ctx;
+ uint8 *mach_pwd;
+ uint16 acct_flags;
+ int num_records;
+ struct ldb_message **msgs;
+ NTSTATUS nt_status;
+
+ const char *attrs[] = {"unicodePwd", "lmPwdHash", "ntPwdHash",
+ "userAccountControl", NULL
+ };
+
+ ZERO_STRUCTP(server_credentials);
+ if (out_flags) {
+ *out_flags = 0;
+ }
+
+ if (!pipe_state) {
+ DEBUG(1, ("No challange requested by client, cannot authenticate\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sam_ctx = samdb_connect();
+ if (sam_ctx == NULL) {
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+ /* pull the user attributes */
+ num_records = samdb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs,
+ "(&(sAMAccountName=%s)(objectclass=user))",
+ account_name);
+
+ if (num_records == 0) {
+ DEBUG(3,("Couldn't find user [%s] in passdb file.\n",
+ account_name));
+ samdb_close(sam_ctx);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (num_records > 1) {
+ DEBUG(1,("Found %d records matching user [%s]\n", num_records, account_name));
+ samdb_close(sam_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ acct_flags = samdb_result_acct_flags(msgs[0],
+ "userAccountControl");
+
+ if (acct_flags & ACB_DISABLED) {
+ DEBUG(1, ("Account [%s] is disabled\n", account_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (secure_channel_type == SEC_CHAN_WKSTA) {
+ if (!(acct_flags & ACB_WSTRUST)) {
+ DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", acct_flags));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else if (secure_channel_type == SEC_CHAN_DOMAIN) {
+ if (!(acct_flags & ACB_DOMTRUST)) {
+ DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", acct_flags));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else if (secure_channel_type == SEC_CHAN_BDC) {
+ if (!(acct_flags & ACB_SVRTRUST)) {
+ DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", acct_flags));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ DEBUG(1, ("Client asked for an invalid secure channel type: %d\n", secure_channel_type));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ pipe_state->acct_flags = acct_flags;
+ pipe_state->sec_chan_type = secure_channel_type;
+
+ if (!NT_STATUS_IS_OK(nt_status = samdb_result_passwords(mem_ctx, msgs[0],
+ NULL, &mach_pwd))) {
+ samdb_close(sam_ctx);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ samdb_close(sam_ctx);
+
+ if (!pipe_state->creds) {
+ pipe_state->creds = talloc_p(mem_ctx, struct creds_CredentialState);
+ if (!pipe_state->creds) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ creds_server_init(pipe_state->creds, &pipe_state->client_challenge,
+ &pipe_state->server_challenge, mach_pwd,
+ server_credentials);
+
+ if (!creds_server_check(pipe_state->creds, client_credentials)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ pipe_state->authenticated = True;
+
+ if (pipe_state->account_name) {
+ /* We don't want a memory leak on this long-lived talloc context */
+ talloc_free(pipe_state->mem_ctx, pipe_state->account_name);
+ }
+
+ pipe_state->account_name = talloc_strdup(pipe_state->mem_ctx, account_name);
+
+ if (pipe_state->computer_name) {
+ /* We don't want a memory leak on this long-lived talloc context */
+ talloc_free(pipe_state->mem_ctx, pipe_state->account_name);
+ }
+
+ pipe_state->computer_name = talloc_strdup(pipe_state->mem_ctx, computer_name);
+
+ if (out_flags) {
+ *out_flags = NETLOGON_NEG_AUTH2_FLAGS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS netr_ServerAuthenticate(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_ServerAuthenticate *r)
+{
+ struct server_pipe_state *pipe_state = dce_call->conn->private;
+
+ return netr_ServerAuthenticateInternals(pipe_state,
+ mem_ctx,
+ r->in.username,
+ r->in.computer_name,
+ r->in.secure_channel_type,
+ 0,
+ &r->in.credentials,
+ &r->out.credentials,
+ NULL);
+}
+
+static NTSTATUS netr_ServerAuthenticate2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_ServerAuthenticate2 *r)
+{
+ struct server_pipe_state *pipe_state = dce_call->conn->private;
+
+ return netr_ServerAuthenticateInternals(pipe_state,
+ mem_ctx,
+ r->in.username,
+ r->in.computer_name,
+ r->in.secure_channel_type,
+ *r->in.negotiate_flags,
+ &r->in.credentials,
+ &r->out.credentials,
+ r->out.negotiate_flags);
+}
+
+/*
+ netr_LogonUasLogon
+*/
+static WERROR netr_LogonUasLogon(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonUasLogon *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_LogonUasLogoff
+*/
+static WERROR netr_LogonUasLogoff(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonUasLogoff *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_LogonSamLogon
+
+
+
+*/
+static NTSTATUS netr_LogonSamLogon(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonSamLogon *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_LogonSamLogoff
+*/
+static NTSTATUS netr_LogonSamLogoff(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonSamLogoff *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+
+/*
+ netr_ServerPasswordSet
+*/
+static NTSTATUS netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_ServerPasswordSet *r)
+{
+
+
+
+}
+
+
+/*
+ netr_DatabaseDeltas
+*/
+static NTSTATUS netr_DatabaseDeltas(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_DatabaseDeltas *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_DatabaseSync
+*/
+static NTSTATUS netr_DatabaseSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_DatabaseSync *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_AccountDeltas
+*/
+static NTSTATUS netr_AccountDeltas(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_AccountDeltas *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_AccountSync
+*/
+static NTSTATUS netr_AccountSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_AccountSync *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_GetDcName
+*/
+static NTSTATUS netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_GetDcName *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_LogonControl
+*/
+static WERROR netr_LogonControl(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonControl *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_GetAnyDCName
+*/
+static WERROR netr_GetAnyDCName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_GetAnyDCName *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_LogonControl2
+*/
+static WERROR netr_LogonControl2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonControl2 *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_DatabaseSync2
+*/
+static NTSTATUS netr_DatabaseSync2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_DatabaseSync2 *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_DatabaseRedo
+*/
+static NTSTATUS netr_DatabaseRedo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_DatabaseRedo *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ netr_LogonControl2Ex
+*/
+static WERROR netr_LogonControl2Ex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonControl2Ex *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_netlogon_s.c"
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c
index d5a028ce09..847b30e71c 100644
--- a/source4/rpc_server/samr/dcesrv_samr.c
+++ b/source4/rpc_server/samr/dcesrv_samr.c
@@ -603,6 +603,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX
struct dcesrv_handle *u_handle;
int ret;
NTSTATUS status;
+ const char *container;
ZERO_STRUCTP(r->out.acct_handle);
*r->out.access_granted = 0;
@@ -628,14 +629,55 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX
ZERO_STRUCT(msg);
- /* pull in all the template attributes */
- ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
- "(&(name=TemplateUser)(objectclass=userTemplate))");
- if (ret != 0) {
- DEBUG(1,("Failed to load TemplateUser from samdb\n"));
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ /* This must be one of these values *only* */
+ if (r->in.acct_flags == ACB_NORMAL) {
+ /* pull in all the template attributes */
+ ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
+ "(&(name=TemplateUser)(objectclass=userTemplate))");
+ if (ret != 0) {
+ DEBUG(1,("Failed to load TemplateUser from samdb\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ container = "Users";
+
+ } else if (r->in.acct_flags == ACB_WSTRUST) {
+ /* pull in all the template attributes */
+ ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
+ "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
+ if (ret != 0) {
+ DEBUG(1,("Failed to load TemplateMemberServer from samdb\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ container = "Computers";
+
+ } else if (r->in.acct_flags == ACB_SVRTRUST) {
+ /* pull in all the template attributes */
+ ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
+ "(&(name=TemplateDomainController)(objectclass=userTemplate))");
+ if (ret != 0) {
+ DEBUG(1,("Failed to load TemplateDomainController from samdb\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ container = "DomainControllers";
+
+ } else if (r->in.acct_flags == ACB_DOMTRUST) {
+ /* pull in all the template attributes */
+ ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
+ "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
+ if (ret != 0) {
+ DEBUG(1,("Failed to load TemplateTrustingDomain from samdb\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ container = "ForeignDomains"; /* FIXME: Is this correct?*/
+
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
}
-
+
/* allocate a rid */
status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
d_state->domain_dn, "nextRid", &rid);
@@ -650,7 +692,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX
}
/* add core elements to the ldb_message for the user */
- msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", username, d_state->domain_dn);
+ msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", username, container, d_state->domain_dn);
if (!msg.dn) {
return NT_STATUS_NO_MEMORY;
}
@@ -723,7 +765,7 @@ static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *
/* a simple wrapper around samr_CreateUser2 works nicely */
r2.in.handle = r->in.handle;
r2.in.username = r->in.username;
- r2.in.acct_flags = 1234;
+ r2.in.acct_flags = ACB_NORMAL;
r2.in.access_mask = r->in.access_mask;
r2.out.acct_handle = r->out.acct_handle;
r2.out.access_granted = &access_granted;
@@ -914,18 +956,9 @@ static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX
continue;
}
- switch (atype & 0xF0000000) {
- case ATYPE_ACCOUNT:
- rtype = SID_NAME_USER;
- break;
- case ATYPE_GLOBAL_GROUP:
- rtype = SID_NAME_DOM_GRP;
- break;
- case ATYPE_LOCAL_GROUP:
- rtype = SID_NAME_ALIAS;
- break;
- default:
- DEBUG(1,("Unknown sAMAccountType 0x%08x\n", atype));
+ rtype = samdb_atype_map(atype);
+
+ if (rtype == SID_NAME_UNKNOWN) {
status = STATUS_SOME_UNMAPPED;
continue;
}
@@ -1654,7 +1687,7 @@ static NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
so the domain password policy can be used */
return samdb_set_password(a_state->sam_ctx, mem_ctx,
a_state->account_dn, a_state->domain_state->domain_dn,
- msg, new_pass);
+ msg, new_pass, False /* This is a password set, not change */);
}
/*
diff --git a/source4/rpc_server/samr/samdb.c b/source4/rpc_server/samr/samdb.c
index 2fa17af8ea..2489dae684 100644
--- a/source4/rpc_server/samr/samdb.c
+++ b/source4/rpc_server/samr/samdb.c
@@ -416,6 +416,68 @@ uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
return count;
}
+NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+ uint8 **lm_pwd, uint8 **nt_pwd)
+{
+
+ const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
+
+ struct samr_Hash *lmPwdHash, *ntPwdHash;
+ if (unicodePwd) {
+ if (nt_pwd) {
+ ntPwdHash = talloc_p(mem_ctx, struct samr_Hash);
+ if (!ntPwdHash) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ E_md4hash(unicodePwd, ntPwdHash->hash);
+ *nt_pwd = ntPwdHash->hash;
+ }
+
+ if (lm_pwd) {
+ BOOL lm_hash_ok;
+
+ lmPwdHash = talloc_p(mem_ctx, struct samr_Hash);
+ if (!lmPwdHash) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* compute the new nt and lm hashes */
+ lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
+
+ if (lm_hash_ok) {
+ *lm_pwd = lmPwdHash->hash;
+ } else {
+ *lm_pwd = NULL;
+ }
+ }
+ } else {
+ if (nt_pwd) {
+ int num_nt;
+ num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
+ if (num_nt == 0) {
+ nt_pwd = NULL;
+ } else if (num_nt > 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ } else {
+ *nt_pwd = ntPwdHash[0].hash;
+ }
+ }
+ if (lm_pwd) {
+ int num_lm;
+ num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
+ if (num_lm == 0) {
+ *lm_pwd = NULL;
+ } else if (num_lm > 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ } else {
+ *lm_pwd = lmPwdHash[0].hash;
+ }
+ }
+
+ }
+ return NT_STATUS_OK;
+}
/*
pull a samr_LogonHours structutre from a result set.
@@ -438,36 +500,13 @@ struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_
return hours;
}
-/* mapping between ADS userAccountControl and SAMR acct_flags */
-static const struct {
- uint32 uf, acb;
-} acct_flags_map[] = {
- { UF_ACCOUNTDISABLE, ACB_DISABLED },
- { UF_HOMEDIR_REQUIRED, ACB_HOMDIRREQ },
- { UF_PASSWD_NOTREQD, ACB_PWNOTREQ },
- { UF_TEMP_DUPLICATE_ACCOUNT, ACB_TEMPDUP },
- { UF_NORMAL_ACCOUNT, ACB_NORMAL },
- { UF_MNS_LOGON_ACCOUNT, ACB_MNS },
- { UF_INTERDOMAIN_TRUST_ACCOUNT, ACB_DOMTRUST },
- { UF_WORKSTATION_TRUST_ACCOUNT, ACB_WSTRUST },
- { UF_SERVER_TRUST_ACCOUNT, ACB_SVRTRUST },
- { UF_DONT_EXPIRE_PASSWD, ACB_PWNOEXP },
- { UF_LOCKOUT, ACB_AUTOLOCK }
-};
-
/*
pull a set of account_flags from a result set.
*/
-uint32 samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
+uint16 samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
{
uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
- uint32 i, ret = 0;
- for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) {
- if (acct_flags_map[i].uf & userAccountControl) {
- ret |= acct_flags_map[i].acb;
- }
- }
- return ret;
+ return samdb_uf2acb(userAccountControl);
}
/*
@@ -707,13 +746,7 @@ int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg
int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
const char *attr_name, uint32 v)
{
- uint_t i, flags = 0;
- for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) {
- if (acct_flags_map[i].acb & v) {
- flags |= acct_flags_map[i].uf;
- }
- }
- return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, flags);
+ return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
}
/*
@@ -808,7 +841,8 @@ static BOOL samdb_password_complexity_ok(const char *pass)
*/
NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
const char *user_dn, const char *domain_dn,
- struct ldb_message *mod, const char *new_pass)
+ struct ldb_message *mod, const char *new_pass,
+ BOOL user_change)
{
const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
"ntPwdHistory", "unicodePwd",
@@ -863,71 +897,73 @@ NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
minPwdAge = samdb_result_double(res[0], "minPwdAge", 0);
- /* are all password changes disallowed? */
- if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
-
- /* can this user change password? */
- if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
-
- /* check the various password restrictions */
- if (minPwdLength > str_charnum(new_pass)) {
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
-
- /* yes, this is a minus. The ages are in negative 100nsec units! */
- if (pwdLastSet - minPwdAge > now_double) {
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
-
- /* possibly check password complexity */
- if (pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
- !samdb_password_complexity_ok(new_pass)) {
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
-
/* compute the new nt and lm hashes */
lm_hash_ok = E_deshash(new_pass, lmNewHash.hash);
E_md4hash(new_pass, ntNewHash.hash);
- /* check the immediately past password */
- if (pwdHistoryLength > 0) {
- if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) {
+ if (user_change) {
+ /* are all password changes disallowed? */
+ if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
return NT_STATUS_PASSWORD_RESTRICTION;
}
- if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) {
+
+ /* can this user change password? */
+ if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
return NT_STATUS_PASSWORD_RESTRICTION;
}
- }
-
- /* check the password history */
- lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength);
- ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength);
-
- if (pwdHistoryLength > 0) {
- if (unicodePwd && strcmp(unicodePwd, new_pass) == 0) {
+
+ /* yes, this is a minus. The ages are in negative 100nsec units! */
+ if (pwdLastSet - minPwdAge > now_double) {
return NT_STATUS_PASSWORD_RESTRICTION;
}
- if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) {
- return NT_STATUS_PASSWORD_RESTRICTION;
+
+ /* check the immediately past password */
+ if (pwdHistoryLength > 0) {
+ if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
}
- if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) {
- return NT_STATUS_PASSWORD_RESTRICTION;
+
+ /* check the password history */
+ lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength);
+ ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength);
+
+ if (pwdHistoryLength > 0) {
+ if (unicodePwd && strcmp(unicodePwd, new_pass) == 0) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ }
+
+ for (i=0;lm_hash_ok && i<lmPwdHistory_len;i++) {
+ if (memcmp(lmNewHash.hash, lmPwdHistory[i].hash, 16) == 0) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ }
+ for (i=0;i<ntPwdHistory_len;i++) {
+ if (memcmp(ntNewHash.hash, ntPwdHistory[i].hash, 16) == 0) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
}
}
- for (i=0;lm_hash_ok && i<lmPwdHistory_len;i++) {
- if (memcmp(lmNewHash.hash, lmPwdHistory[i].hash, 16) == 0) {
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
+ /* check the various password restrictions */
+ if (minPwdLength > str_charnum(new_pass)) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
}
- for (i=0;i<ntPwdHistory_len;i++) {
- if (memcmp(ntNewHash.hash, ntPwdHistory[i].hash, 16) == 0) {
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
+
+ /* possibly check password complexity */
+ if (pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
+ !samdb_password_complexity_ok(new_pass)) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
}
#define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
diff --git a/source4/rpc_server/samr/samr_utils.c b/source4/rpc_server/samr/samr_utils.c
new file mode 100644
index 0000000000..247b2d47f4
--- /dev/null
+++ b/source4/rpc_server/samr/samr_utils.c
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+ helper mapping functions for the SAMDB server
+
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+translated the ACB_CTRL Flags to UserFlags (userAccountControl)
+*/
+/* mapping between ADS userAccountControl and SAMR acct_flags */
+static const struct {
+ uint32 uf;
+ uint16 acb;
+} acct_flags_map[] = {
+ { UF_ACCOUNTDISABLE, ACB_DISABLED },
+ { UF_HOMEDIR_REQUIRED, ACB_HOMDIRREQ },
+ { UF_PASSWD_NOTREQD, ACB_PWNOTREQ },
+ { UF_TEMP_DUPLICATE_ACCOUNT, ACB_TEMPDUP },
+ { UF_NORMAL_ACCOUNT, ACB_NORMAL },
+ { UF_MNS_LOGON_ACCOUNT, ACB_MNS },
+ { UF_INTERDOMAIN_TRUST_ACCOUNT, ACB_DOMTRUST },
+ { UF_WORKSTATION_TRUST_ACCOUNT, ACB_WSTRUST },
+ { UF_SERVER_TRUST_ACCOUNT, ACB_SVRTRUST },
+ { UF_DONT_EXPIRE_PASSWD, ACB_PWNOEXP },
+ { UF_LOCKOUT, ACB_AUTOLOCK }
+};
+
+uint32 samdb_acb2uf(uint16 acb)
+{
+ uint32 i, ret = 0;
+ for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) {
+ if (acct_flags_map[i].acb & acb) {
+ ret |= acct_flags_map[i].uf;
+ }
+ }
+ return ret;
+}
+
+/*
+translated the UserFlags (userAccountControl) to ACB_CTRL Flags
+*/
+uint16 samdb_uf2acb(uint32 uf)
+{
+ uint32 i;
+ uint16 ret = 0;
+ for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) {
+ if (acct_flags_map[i].uf & uf) {
+ ret |= acct_flags_map[i].acb;
+ }
+ }
+ return ret;
+}
+
+/*
+get the accountType from the UserFlags
+*/
+uint32 samdb_uf2atype(uint32 uf)
+{
+ uint32 atype = 0x00000000;
+
+ if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST;
+
+ return atype;
+}
+
+/*
+get the accountType from the groupType
+*/
+uint32 samdb_gtype2atype(uint32 gtype)
+{
+ uint32 atype = 0x00000000;
+
+ switch(gtype) {
+ case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_GLOBAL_GROUP:
+ atype = ATYPE_SECURITY_GLOBAL_GROUP;
+ break;
+
+ case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_LOCAL_GROUP;
+ break;
+ }
+
+ return atype;
+}
+
+/* turn a sAMAccountType into a SID_NAME_USE */
+enum SID_NAME_USE samdb_atype_map(uint32 atype)
+{
+ switch (atype & 0xF0000000) {
+ case ATYPE_GLOBAL_GROUP:
+ return SID_NAME_DOM_GRP;
+ case ATYPE_SECURITY_LOCAL_GROUP:
+ return SID_NAME_ALIAS;
+ case ATYPE_ACCOUNT:
+ return SID_NAME_USER;
+ default:
+ DEBUG(1,("hmm, need to map account type 0x%x\n", atype));
+ }
+ return SID_NAME_UNKNOWN;
+}