mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
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 94624e519b
)
This commit is contained in:
parent
31b9470996
commit
064e7447be
@ -187,16 +187,12 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
|
||||
NTSTATUS nt_status;
|
||||
DATA_BLOB user_sess_key = data_blob(NULL, 0);
|
||||
DATA_BLOB lm_sess_key = data_blob(NULL, 0);
|
||||
const uint8 *lm_pwd, *nt_pwd;
|
||||
const char *unicodePwd;
|
||||
struct samr_Hash lmPwdHash_u, ntPwdHash_u;
|
||||
struct samr_Hash *lmPwdHash, *ntPwdHash;
|
||||
uint_t num_lm, num_nt;
|
||||
uint8 *lm_pwd, *nt_pwd;
|
||||
|
||||
struct dom_sid *domain_sid;
|
||||
|
||||
const char *attrs[] = {"unicodePwd", "lmPwdHash", "ntPwdHash",
|
||||
"sAMAcctFlags",
|
||||
"userAccountControl",
|
||||
"pwdLastSet",
|
||||
"accountExpires",
|
||||
"objectSid",
|
||||
@ -204,7 +200,7 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const char *domain_attrs[] = {NULL};
|
||||
const char *domain_attrs[] = {"name"};
|
||||
|
||||
if (!user_info || !auth_context) {
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
@ -270,40 +266,9 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
|
||||
return NT_STATUS_ACCOUNT_LOCKED_OUT;
|
||||
}
|
||||
|
||||
unicodePwd = samdb_result_string(msgs[0], "unicodePwd", NULL);
|
||||
|
||||
if (unicodePwd) {
|
||||
BOOL lm_hash_ok;
|
||||
/* compute the new nt and lm hashes */
|
||||
lm_hash_ok = E_deshash(unicodePwd, lmPwdHash_u.hash);
|
||||
E_md4hash(unicodePwd, ntPwdHash_u.hash);
|
||||
|
||||
if (lm_hash_ok) {
|
||||
lm_pwd = lmPwdHash_u.hash;
|
||||
} else {
|
||||
lm_pwd = NULL;
|
||||
}
|
||||
|
||||
nt_pwd = ntPwdHash_u.hash;
|
||||
|
||||
} else {
|
||||
num_lm = samdb_result_hashes(mem_ctx, msgs[0], "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;
|
||||
}
|
||||
|
||||
num_nt = samdb_result_hashes(mem_ctx, msgs[0], "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 (!NT_STATUS_IS_OK(nt_status = samdb_result_passwords(mem_ctx, msgs[0],
|
||||
&lm_pwd, &nt_pwd))) {
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
nt_status = sam_password_ok(auth_context, mem_ctx,
|
||||
|
@ -269,15 +269,14 @@ BOOL check_password_quality(const char *s)
|
||||
|
||||
static char c_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
|
||||
|
||||
char *generate_random_str(size_t len)
|
||||
char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
|
||||
{
|
||||
static unsigned char retstr[256];
|
||||
size_t i;
|
||||
|
||||
memset(retstr, '\0', sizeof(retstr));
|
||||
char *retstr = talloc(mem_ctx, len + 1);
|
||||
|
||||
if (len > sizeof(retstr)-1)
|
||||
len = sizeof(retstr) -1;
|
||||
if (!retstr)
|
||||
return NULL;
|
||||
|
||||
again:
|
||||
generate_random_buffer(retstr, len, False);
|
||||
@ -292,5 +291,5 @@ again:
|
||||
goto again;
|
||||
}
|
||||
|
||||
return (char *)retstr;
|
||||
return retstr;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
code to manipulate domain credentials
|
||||
|
||||
Copyright (C) Andrew Tridgell 1997-2003
|
||||
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
|
||||
@ -36,6 +37,10 @@ static void creds_init(struct creds_CredentialState *creds,
|
||||
uint32 sum[2];
|
||||
uint8 sum2[8];
|
||||
|
||||
dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
|
||||
dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
|
||||
dump_data_pw("Machine Pass", machine_password, 16);
|
||||
|
||||
sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
|
||||
sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
|
||||
|
||||
@ -44,8 +49,6 @@ static void creds_init(struct creds_CredentialState *creds,
|
||||
|
||||
cred_hash1(creds->session_key, sum2, machine_password);
|
||||
|
||||
creds->sequence = time(NULL);
|
||||
|
||||
SIVAL(time_cred.data, 0, IVAL(client_challenge->data, 0));
|
||||
SIVAL(time_cred.data, 4, IVAL(client_challenge->data, 4));
|
||||
cred_hash2(creds->client.data, time_cred.data, creds->session_key, 1);
|
||||
@ -136,6 +139,7 @@ void creds_client_init(struct creds_CredentialState *creds,
|
||||
struct netr_Credential *initial_credential)
|
||||
{
|
||||
creds_init(creds, client_challenge, server_challenge, machine_password);
|
||||
creds->sequence = time(NULL);
|
||||
|
||||
*initial_credential = creds->client;
|
||||
}
|
||||
@ -146,7 +150,8 @@ void creds_client_init(struct creds_CredentialState *creds,
|
||||
BOOL creds_client_check(struct creds_CredentialState *creds,
|
||||
const struct netr_Credential *received_credentials)
|
||||
{
|
||||
if (memcmp(received_credentials->data, creds->server.data, 8) != 0) {
|
||||
if (!received_credentials ||
|
||||
memcmp(received_credentials->data, creds->server.data, 8) != 0) {
|
||||
DEBUG(2,("credentials check failed\n"));
|
||||
return False;
|
||||
}
|
||||
@ -167,3 +172,38 @@ void creds_client_authenticator(struct creds_CredentialState *creds,
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
The above functions are common to the client and server interface
|
||||
next comes the server specific functions
|
||||
******************************************************************/
|
||||
|
||||
/*
|
||||
initialise the credentials chain and return the first server
|
||||
credentials
|
||||
*/
|
||||
void creds_server_init(struct creds_CredentialState *creds,
|
||||
const struct netr_Credential *client_challenge,
|
||||
const struct netr_Credential *server_challenge,
|
||||
const uint8 machine_password[16],
|
||||
struct netr_Credential *initial_credential)
|
||||
{
|
||||
creds_init(creds, client_challenge, server_challenge, machine_password);
|
||||
|
||||
*initial_credential = creds->server;
|
||||
}
|
||||
|
||||
/*
|
||||
check that a credentials reply from a server is correct
|
||||
*/
|
||||
BOOL creds_server_check(const struct creds_CredentialState *creds,
|
||||
const struct netr_Credential *received_credentials)
|
||||
{
|
||||
if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
|
||||
DEBUG(2,("credentials check failed\n"));
|
||||
dump_data_pw("client creds", creds->client.data, 8);
|
||||
dump_data_pw("calc creds", received_credentials->data, 8);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
|
@ -27,3 +27,12 @@ struct creds_CredentialState {
|
||||
struct netr_Credential client;
|
||||
struct netr_Credential server;
|
||||
};
|
||||
|
||||
|
||||
/* for the timebeing, use the same neg flags as Samba3. */
|
||||
/* The 7 here seems to be required to get Win2k not to downgrade us
|
||||
to NT4. Actually, anything other than 1ff would seem to do... */
|
||||
#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
|
||||
|
||||
#define NETLOGON_NEG_SCHANNEL 0x40000000
|
||||
|
||||
|
@ -932,7 +932,7 @@ static void init_globals(void)
|
||||
string_set(&sDefault.fstype, FSTYPE_STRING);
|
||||
string_set(&sDefault.ntvfs_handler, "default");
|
||||
|
||||
Globals.dcerpc_ep_servers = str_list_make("epmapper srvsvc wkssvc rpcecho samr", NULL);
|
||||
Globals.dcerpc_ep_servers = str_list_make("epmapper srvsvc wkssvc rpcecho samr netlogon", NULL);
|
||||
|
||||
Globals.AuthMethods = str_list_make("guest sam_ignoredomain", NULL);
|
||||
|
||||
|
@ -763,7 +763,7 @@ objectClass: userTemplate
|
||||
cn: TemplateUser
|
||||
name: TemplateUser
|
||||
instanceType: 4
|
||||
userAccountControl: 0x222
|
||||
userAccountControl: 0x202
|
||||
badPwdCount: 0
|
||||
codePage: 0
|
||||
countryCode: 0
|
||||
@ -776,6 +776,48 @@ accountExpires: -1
|
||||
logonCount: 0
|
||||
sAMAccountType: 0x30000000
|
||||
|
||||
dn: CN=TemplateMemberServer,CN=Templates,${BASEDN}
|
||||
objectClass: top
|
||||
objectClass: computer
|
||||
objectClass: Template
|
||||
objectClass: userTemplate
|
||||
cn: TemplateMemberServer
|
||||
name: TemplateMemberServer
|
||||
instanceType: 4
|
||||
userAccountControl: 0x1002
|
||||
badPwdCount: 0
|
||||
codePage: 0
|
||||
countryCode: 0
|
||||
badPasswordTime: 0
|
||||
lastLogoff: 0
|
||||
lastLogon: 0
|
||||
pwdLastSet: 0
|
||||
primaryGroupID: 513
|
||||
accountExpires: -1
|
||||
logonCount: 0
|
||||
sAMAccountType: 0x30000001
|
||||
|
||||
dn: CN=TemplateDomainController,CN=Templates,${BASEDN}
|
||||
objectClass: top
|
||||
objectClass: computer
|
||||
objectClass: Template
|
||||
objectClass: userTemplate
|
||||
cn: TemplateDomainController
|
||||
name: TemplateDomainController
|
||||
instanceType: 4
|
||||
userAccountControl: 0x2002
|
||||
badPwdCount: 0
|
||||
codePage: 0
|
||||
countryCode: 0
|
||||
badPasswordTime: 0
|
||||
lastLogoff: 0
|
||||
lastLogon: 0
|
||||
pwdLastSet: 0
|
||||
primaryGroupID: 513
|
||||
accountExpires: -1
|
||||
logonCount: 0
|
||||
sAMAccountType: 0x30000001
|
||||
|
||||
dn: CN=TemplateGroup,CN=Templates,${BASEDN}
|
||||
objectClass: top
|
||||
objectClass: Template
|
||||
|
@ -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
|
||||
|
467
source4/rpc_server/netlogon/dcerpc_netlogon.c
Normal file
467
source4/rpc_server/netlogon/dcerpc_netlogon.c
Normal file
@ -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"
|
@ -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 */);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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,14 +897,62 @@ 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;
|
||||
}
|
||||
/* compute the new nt and lm hashes */
|
||||
lm_hash_ok = E_deshash(new_pass, lmNewHash.hash);
|
||||
E_md4hash(new_pass, ntNewHash.hash);
|
||||
|
||||
/* can this user change password? */
|
||||
if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
|
||||
return NT_STATUS_PASSWORD_RESTRICTION;
|
||||
if (user_change) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* yes, this is a minus. The ages are in negative 100nsec units! */
|
||||
if (pwdLastSet - minPwdAge > now_double) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check the various password restrictions */
|
||||
@ -878,58 +960,12 @@ NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
|
||||
|
||||
/* the password is acceptable. Start forming the new fields */
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
ads (active directory) utility library
|
||||
helper mapping functions for the SAMDB server
|
||||
|
||||
Copyright (C) Stefan (metze) Metzmacher 2002
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
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
|
||||
@ -25,57 +25,54 @@
|
||||
/*
|
||||
translated the ACB_CTRL Flags to UserFlags (userAccountControl)
|
||||
*/
|
||||
uint32 ads_acb2uf(uint16 acb)
|
||||
{
|
||||
uint32 uf = 0x00000000;
|
||||
|
||||
if (acb & ACB_DISABLED) uf |= UF_ACCOUNTDISABLE;
|
||||
if (acb & ACB_HOMDIRREQ) uf |= UF_HOMEDIR_REQUIRED;
|
||||
if (acb & ACB_PWNOTREQ) uf |= UF_PASSWD_NOTREQD;
|
||||
if (acb & ACB_TEMPDUP) uf |= UF_TEMP_DUPLICATE_ACCOUNT;
|
||||
if (acb & ACB_NORMAL) uf |= UF_NORMAL_ACCOUNT;
|
||||
if (acb & ACB_MNS) uf |= UF_MNS_LOGON_ACCOUNT;
|
||||
if (acb & ACB_DOMTRUST) uf |= UF_INTERDOMAIN_TRUST_ACCOUNT;
|
||||
if (acb & ACB_WSTRUST) uf |= UF_WORKSTATION_TRUST_ACCOUNT;
|
||||
if (acb & ACB_SVRTRUST) uf |= UF_SERVER_TRUST_ACCOUNT;
|
||||
if (acb & ACB_PWNOEXP) uf |= UF_DONT_EXPIRE_PASSWD;
|
||||
if (acb & ACB_AUTOLOCK) uf |= UF_LOCKOUT;
|
||||
/* 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 }
|
||||
};
|
||||
|
||||
return uf;
|
||||
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 ads_uf2acb(uint32 uf)
|
||||
uint16 samdb_uf2acb(uint32 uf)
|
||||
{
|
||||
uint16 acb = 0x0000;
|
||||
|
||||
if (uf & UF_ACCOUNTDISABLE) acb |= ACB_DISABLED;
|
||||
if (uf & UF_HOMEDIR_REQUIRED) acb |= ACB_HOMDIRREQ;
|
||||
if (uf & UF_PASSWD_NOTREQD) acb |= ACB_PWNOTREQ;
|
||||
if (uf & UF_MNS_LOGON_ACCOUNT) acb |= ACB_MNS;
|
||||
if (uf & UF_DONT_EXPIRE_PASSWD) acb |= ACB_PWNOEXP;
|
||||
if (uf & UF_LOCKOUT) acb |= ACB_AUTOLOCK;
|
||||
|
||||
switch (uf & UF_ACCOUNT_TYPE_MASK)
|
||||
{
|
||||
case UF_TEMP_DUPLICATE_ACCOUNT: acb |= ACB_TEMPDUP;break;
|
||||
case UF_NORMAL_ACCOUNT: acb |= ACB_NORMAL;break;
|
||||
case UF_INTERDOMAIN_TRUST_ACCOUNT: acb |= ACB_DOMTRUST;break;
|
||||
case UF_WORKSTATION_TRUST_ACCOUNT: acb |= ACB_WSTRUST;break;
|
||||
case UF_SERVER_TRUST_ACCOUNT: acb |= ACB_SVRTRUST;break;
|
||||
/*Fix Me: what should we do here? */
|
||||
default: acb |= ACB_NORMAL;break;
|
||||
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 acb;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
get the accountType from the UserFlags
|
||||
*/
|
||||
uint32 ads_uf2atype(uint32 uf)
|
||||
uint32 samdb_uf2atype(uint32 uf)
|
||||
{
|
||||
uint32 atype = 0x00000000;
|
||||
|
||||
@ -91,7 +88,7 @@ uint32 ads_uf2atype(uint32 uf)
|
||||
/*
|
||||
get the accountType from the groupType
|
||||
*/
|
||||
uint32 ads_gtype2atype(uint32 gtype)
|
||||
uint32 samdb_gtype2atype(uint32 gtype)
|
||||
{
|
||||
uint32 atype = 0x00000000;
|
||||
|
||||
@ -121,7 +118,7 @@ uint32 ads_gtype2atype(uint32 gtype)
|
||||
}
|
||||
|
||||
/* turn a sAMAccountType into a SID_NAME_USE */
|
||||
enum SID_NAME_USE ads_atype_map(uint32 atype)
|
||||
enum SID_NAME_USE samdb_atype_map(uint32 atype)
|
||||
{
|
||||
switch (atype & 0xF0000000) {
|
||||
case ATYPE_GLOBAL_GROUP:
|
@ -27,14 +27,6 @@
|
||||
|
||||
#define TEST_MACHINE_NAME "torturetest"
|
||||
|
||||
/* for the timebeing, use the same neg flags as Samba3. */
|
||||
/* The 7 here seems to be required to get Win2k not to downgrade us
|
||||
to NT4. Actually, anything other than 1ff would seem to do... */
|
||||
#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
|
||||
|
||||
#define NETLOGON_NEG_SCHANNEL 0x40000000
|
||||
|
||||
|
||||
static struct {
|
||||
struct dcerpc_pipe *p;
|
||||
const char *machine_password;
|
||||
@ -51,6 +43,7 @@ static BOOL join_domain_bdc(TALLOC_CTX *mem_ctx)
|
||||
struct samr_CreateUser2 r;
|
||||
struct samr_OpenDomain o;
|
||||
struct samr_LookupDomain l;
|
||||
struct samr_GetUserPwInfo pwp;
|
||||
struct samr_SetUserInfo s;
|
||||
union samr_UserInfo u;
|
||||
struct policy_handle handle;
|
||||
@ -60,6 +53,7 @@ static BOOL join_domain_bdc(TALLOC_CTX *mem_ctx)
|
||||
BOOL ret = True;
|
||||
DATA_BLOB session_key;
|
||||
struct samr_Name name;
|
||||
int policy_min_pw_len = 0;
|
||||
|
||||
printf("Connecting to SAMR\n");
|
||||
|
||||
@ -128,7 +122,14 @@ again:
|
||||
return False;
|
||||
}
|
||||
|
||||
join.machine_password = generate_random_str(8);
|
||||
pwp.in.handle = &join.acct_handle;
|
||||
|
||||
status = dcerpc_samr_GetUserPwInfo(join.p, mem_ctx, &pwp);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
policy_min_pw_len = pwp.out.info.min_pwd_len;
|
||||
}
|
||||
|
||||
join.machine_password = generate_random_str(mem_ctx, MAX(8, policy_min_pw_len));
|
||||
|
||||
printf("Setting machine account password '%s'\n", join.machine_password);
|
||||
|
||||
@ -179,6 +180,8 @@ static BOOL leave_domain_bdc(TALLOC_CTX *mem_ctx)
|
||||
struct samr_DeleteUser d;
|
||||
NTSTATUS status;
|
||||
|
||||
return True;
|
||||
|
||||
d.in.handle = &join.acct_handle;
|
||||
d.out.handle = &join.acct_handle;
|
||||
|
||||
@ -432,15 +435,16 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
|
||||
|
||||
ZERO_STRUCT(samlogon_state->auth2);
|
||||
creds_client_authenticator(&samlogon_state->creds, &samlogon_state->auth);
|
||||
|
||||
|
||||
r->out.authenticator = NULL;
|
||||
status = dcerpc_netr_LogonSamLogon(samlogon_state->p, samlogon_state->mem_ctx, r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (error_string) {
|
||||
*error_string = strdup(nt_errstr(status));
|
||||
}
|
||||
}
|
||||
|
||||
if (!creds_client_check(&samlogon_state->creds, &r->out.authenticator->cred)) {
|
||||
|
||||
if (!r->out.authenticator || !creds_client_check(&samlogon_state->creds, &r->out.authenticator->cred)) {
|
||||
printf("Credential chaining failed\n");
|
||||
}
|
||||
|
||||
@ -1020,12 +1024,13 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
|
||||
r.in.secure_channel_type = SEC_CHAN_BDC;
|
||||
r.in.computer_name = TEST_MACHINE_NAME;
|
||||
|
||||
password = generate_random_str(8);
|
||||
password = generate_random_str(mem_ctx, 8);
|
||||
E_md4hash(password, r.in.new_password.data);
|
||||
|
||||
creds_des_encrypt(&creds, &r.in.new_password);
|
||||
|
||||
printf("Testing ServerPasswordSet on machine account\n");
|
||||
printf("Changing machine account password to '%s'\n", password);
|
||||
|
||||
creds_client_authenticator(&creds, &r.in.credential);
|
||||
|
||||
@ -1035,21 +1040,23 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
|
||||
return False;
|
||||
}
|
||||
|
||||
join.machine_password = password;
|
||||
|
||||
if (!creds_client_check(&creds, &r.out.return_authenticator.cred)) {
|
||||
printf("Credential chaining failed\n");
|
||||
}
|
||||
|
||||
password = generate_random_str(mem_ctx, 8);
|
||||
E_md4hash(password, r.in.new_password.data);
|
||||
|
||||
/* by changing the machine password twice we test the credentials
|
||||
chaining fully */
|
||||
printf("Testing a second ServerPasswordSet on machine account\n");
|
||||
printf("Changing machine account password to '%s'\n", password);
|
||||
|
||||
creds_client_authenticator(&creds, &r.in.credential);
|
||||
|
||||
status = dcerpc_netr_ServerPasswordSet(p, mem_ctx, &r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("ServerPasswordSet - %s\n", nt_errstr(status));
|
||||
printf("ServerPasswordSet (2) - %s\n", nt_errstr(status));
|
||||
return False;
|
||||
}
|
||||
|
||||
@ -1057,6 +1064,8 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
|
||||
printf("Credential chaining failed\n");
|
||||
}
|
||||
|
||||
join.machine_password = password;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
@ -330,9 +330,9 @@ static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
|
||||
static char *samr_rand_pass(TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
size_t len = 8 + (random() % 6);
|
||||
char *s = generate_random_str(len);
|
||||
char *s = generate_random_str(mem_ctx, len);
|
||||
printf("Generated password '%s'\n", s);
|
||||
return talloc_strdup(mem_ctx, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static BOOL test_SetUserPass(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
|
||||
|
Loading…
Reference in New Issue
Block a user