diff options
author | Andrew Bartlett <abartlet@samba.org> | 2004-05-15 07:51:38 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:53:46 -0500 |
commit | 064e7447bebd715c8351d9a0ee31f648990f2336 (patch) | |
tree | 156925cd7c8d4616f0eca3a743b7323b3b0b23b7 /source4/rpc_server/netlogon | |
parent | 31b9470996632d717c3c74482308e200906fdb8f (diff) | |
download | samba-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/netlogon')
-rw-r--r-- | source4/rpc_server/netlogon/dcerpc_netlogon.c | 467 |
1 files changed, 467 insertions, 0 deletions
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" |