X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Frpc_server%2Fsrv_netlog_nt.c;h=b9bfda9a83bbbaa6c062f28a9825d088a7be2760;hb=1d0938c629904e14c3769036d1a8d1a6d7b3f34b;hp=c5e2ca7c7180a04dfbeb9c5dff9d4a40bc4112fb;hpb=f28f113d8e76824b080359c90efd9c92de533740;p=samba.git diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c index c5e2ca7c718..b9bfda9a83b 100644 --- a/source3/rpc_server/srv_netlog_nt.c +++ b/source3/rpc_server/srv_netlog_nt.c @@ -6,7 +6,7 @@ * Copyright (C) Paul Ashton 1997. * Copyright (C) Jeremy Allison 1998-2001. * Copyright (C) Andrew Bartlett 2001. - * Copyright (C) Guenther Deschner 2008. + * Copyright (C) Guenther Deschner 2008-2009. * * 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,64 +25,18 @@ /* This is the implementation of the netlogon pipe. */ #include "includes.h" -#include "../libcli/auth/libcli_auth.h" +#include "../libcli/auth/schannel.h" +#include "../librpc/gen_ndr/srv_netlogon.h" extern userdom_struct current_user_info; #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV -/************************************************************************* - init_net_r_req_chal: - *************************************************************************/ - -static void init_net_r_req_chal(struct netr_Credential *r, - struct netr_Credential *srv_chal) -{ - DEBUG(6,("init_net_r_req_chal: %d\n", __LINE__)); - - memcpy(r->data, srv_chal->data, sizeof(r->data)); -} - -/******************************************************************* - Inits a netr_NETLOGON_INFO_1 structure. -********************************************************************/ - -static void init_netlogon_info1(struct netr_NETLOGON_INFO_1 *r, - uint32_t flags, - uint32_t pdc_connection_status) -{ - r->flags = flags; - r->pdc_connection_status = pdc_connection_status; -} - -/******************************************************************* - Inits a netr_NETLOGON_INFO_2 structure. -********************************************************************/ - -static void init_netlogon_info2(struct netr_NETLOGON_INFO_2 *r, - uint32_t flags, - uint32_t pdc_connection_status, - const char *trusted_dc_name, - uint32_t tc_connection_status) -{ - r->flags = flags; - r->pdc_connection_status = pdc_connection_status; - r->trusted_dc_name = trusted_dc_name; - r->tc_connection_status = tc_connection_status; -} - -/******************************************************************* - Inits a netr_NETLOGON_INFO_3 structure. -********************************************************************/ - -static void init_netlogon_info3(struct netr_NETLOGON_INFO_3 *r, - uint32_t flags, - uint32_t logon_attempts) -{ - r->flags = flags; - r->logon_attempts = logon_attempts; -} +struct netlogon_server_pipe_state { + struct netr_Credential client_challenge; + struct netr_Credential server_challenge; +}; /************************************************************************* _netr_LogonControl @@ -106,7 +60,7 @@ WERROR _netr_LogonControl(pipes_struct *p, l.in.function_code = r->in.function_code; l.in.level = r->in.level; l.in.data = NULL; - l.out.query = r->out.info; + l.out.query = r->out.query; return _netr_LogonControl2Ex(p, &l); } @@ -140,6 +94,68 @@ WERROR _netr_LogonControl2(pipes_struct *p, return _netr_LogonControl2Ex(p, &l); } +/************************************************************************* + *************************************************************************/ + +static bool wb_change_trust_creds(const char *domain, WERROR *tc_status) +{ + wbcErr result; + struct wbcAuthErrorInfo *error = NULL; + + result = wbcChangeTrustCredentials(domain, &error); + switch (result) { + case WBC_ERR_WINBIND_NOT_AVAILABLE: + return false; + case WBC_ERR_DOMAIN_NOT_FOUND: + *tc_status = WERR_NO_SUCH_DOMAIN; + return true; + case WBC_ERR_SUCCESS: + *tc_status = WERR_OK; + return true; + default: + break; + } + + if (error && error->nt_status != 0) { + *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status)); + } else { + *tc_status = WERR_TRUST_FAILURE; + } + wbcFreeMemory(error); + return true; +} + +/************************************************************************* + *************************************************************************/ + +static bool wb_check_trust_creds(const char *domain, WERROR *tc_status) +{ + wbcErr result; + struct wbcAuthErrorInfo *error = NULL; + + result = wbcCheckTrustCredentials(domain, &error); + switch (result) { + case WBC_ERR_WINBIND_NOT_AVAILABLE: + return false; + case WBC_ERR_DOMAIN_NOT_FOUND: + *tc_status = WERR_NO_SUCH_DOMAIN; + return true; + case WBC_ERR_SUCCESS: + *tc_status = WERR_OK; + return true; + default: + break; + } + + if (error && error->nt_status != 0) { + *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status)); + } else { + *tc_status = WERR_TRUST_FAILURE; + } + wbcFreeMemory(error); + return true; +} + /**************************************************************** _netr_LogonControl2Ex ****************************************************************/ @@ -147,10 +163,10 @@ WERROR _netr_LogonControl2(pipes_struct *p, WERROR _netr_LogonControl2Ex(pipes_struct *p, struct netr_LogonControl2Ex *r) { - uint32 flags = 0x0; - uint32 pdc_connection_status = 0x0; - uint32 logon_attempts = 0x0; - uint32 tc_status; + uint32_t flags = 0x0; + WERROR pdc_connection_status = WERR_OK; + uint32_t logon_attempts = 0x0; + WERROR tc_status; fstring dc_name2; const char *dc_name = NULL; struct sockaddr_storage dc_ss; @@ -158,106 +174,201 @@ WERROR _netr_LogonControl2Ex(pipes_struct *p, struct netr_NETLOGON_INFO_1 *info1; struct netr_NETLOGON_INFO_2 *info2; struct netr_NETLOGON_INFO_3 *info3; + struct netr_NETLOGON_INFO_4 *info4; const char *fn; + uint32_t acct_ctrl; switch (p->hdr_req.opnum) { - case NDR_NETR_LOGONCONTROL: - fn = "_netr_LogonControl"; - break; - case NDR_NETR_LOGONCONTROL2: - fn = "_netr_LogonControl2"; - break; - case NDR_NETR_LOGONCONTROL2EX: - fn = "_netr_LogonControl2Ex"; - break; - default: - return WERR_INVALID_PARAM; + case NDR_NETR_LOGONCONTROL: + fn = "_netr_LogonControl"; + break; + case NDR_NETR_LOGONCONTROL2: + fn = "_netr_LogonControl2"; + break; + case NDR_NETR_LOGONCONTROL2EX: + fn = "_netr_LogonControl2Ex"; + break; + default: + return WERR_INVALID_PARAM; } - tc_status = W_ERROR_V(WERR_NO_SUCH_DOMAIN); + acct_ctrl = pdb_get_acct_ctrl(p->server_info->sam_account); switch (r->in.function_code) { - case NETLOGON_CONTROL_TC_QUERY: - domain = r->in.data->domain; + case NETLOGON_CONTROL_TC_VERIFY: + case NETLOGON_CONTROL_CHANGE_PASSWORD: + case NETLOGON_CONTROL_REDISCOVER: + if ((geteuid() != sec_initial_uid()) && + !nt_token_check_domain_rid(p->server_info->ptok, DOMAIN_RID_ADMINS) && + !nt_token_check_sid(&global_sid_Builtin_Administrators, p->server_info->ptok) && + !(acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST))) { + return WERR_ACCESS_DENIED; + } + break; + default: + break; + } - if ( !is_trusted_domain( domain ) ) - break; + tc_status = WERR_NO_SUCH_DOMAIN; - if ( !get_dc_name( domain, NULL, dc_name2, &dc_ss ) ) { - tc_status = W_ERROR_V(WERR_NO_LOGON_SERVERS); - break; - } + switch (r->in.function_code) { + case NETLOGON_CONTROL_QUERY: + tc_status = WERR_OK; + break; + case NETLOGON_CONTROL_REPLICATE: + case NETLOGON_CONTROL_SYNCHRONIZE: + case NETLOGON_CONTROL_PDC_REPLICATE: + case NETLOGON_CONTROL_BACKUP_CHANGE_LOG: + case NETLOGON_CONTROL_BREAKPOINT: + if (acct_ctrl & ACB_NORMAL) { + return WERR_NOT_SUPPORTED; + } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) { + return WERR_ACCESS_DENIED; + } else { + return WERR_ACCESS_DENIED; + } + case NETLOGON_CONTROL_TRUNCATE_LOG: + if (acct_ctrl & ACB_NORMAL) { + break; + } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) { + return WERR_ACCESS_DENIED; + } else { + return WERR_ACCESS_DENIED; + } - dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); - if (!dc_name) { - return WERR_NOMEM; - } + case NETLOGON_CONTROL_TRANSPORT_NOTIFY: + case NETLOGON_CONTROL_FORCE_DNS_REG: + case NETLOGON_CONTROL_QUERY_DNS_REG: + return WERR_NOT_SUPPORTED; + case NETLOGON_CONTROL_FIND_USER: + if (!r->in.data || !r->in.data->user) { + return WERR_NOT_SUPPORTED; + } + break; + case NETLOGON_CONTROL_SET_DBFLAG: + if (!r->in.data) { + return WERR_NOT_SUPPORTED; + } + break; + case NETLOGON_CONTROL_TC_VERIFY: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } - tc_status = W_ERROR_V(WERR_OK); + if (!wb_check_trust_creds(r->in.data->domain, &tc_status)) { + return WERR_NOT_SUPPORTED; + } + break; + case NETLOGON_CONTROL_TC_QUERY: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } + + domain = r->in.data->domain; + + if (!is_trusted_domain(domain)) { + break; + } + if (!get_dc_name(domain, NULL, dc_name2, &dc_ss)) { + tc_status = WERR_NO_LOGON_SERVERS; break; + } - case NETLOGON_CONTROL_REDISCOVER: - domain = r->in.data->domain; + dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); + if (!dc_name) { + return WERR_NOMEM; + } - if ( !is_trusted_domain( domain ) ) - break; + tc_status = WERR_OK; - if ( !get_dc_name( domain, NULL, dc_name2, &dc_ss ) ) { - tc_status = W_ERROR_V(WERR_NO_LOGON_SERVERS); - break; - } + break; - dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); - if (!dc_name) { - return WERR_NOMEM; - } + case NETLOGON_CONTROL_REDISCOVER: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } - tc_status = W_ERROR_V(WERR_OK); + domain = r->in.data->domain; + if (!is_trusted_domain(domain)) { break; + } - default: - /* no idea what this should be */ - DEBUG(0,("%s: unimplemented function level [%d]\n", - fn, r->in.function_code)); - return WERR_UNKNOWN_LEVEL; + if (!get_dc_name(domain, NULL, dc_name2, &dc_ss)) { + tc_status = WERR_NO_LOGON_SERVERS; + break; + } + + dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); + if (!dc_name) { + return WERR_NOMEM; + } + + tc_status = WERR_OK; + + break; + + case NETLOGON_CONTROL_CHANGE_PASSWORD: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } + + if (!wb_change_trust_creds(r->in.data->domain, &tc_status)) { + return WERR_NOT_SUPPORTED; + } + break; + + default: + /* no idea what this should be */ + DEBUG(0,("%s: unimplemented function level [%d]\n", + fn, r->in.function_code)); + return WERR_UNKNOWN_LEVEL; } /* prepare the response */ switch (r->in.level) { - case 1: - info1 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_1); - W_ERROR_HAVE_NO_MEMORY(info1); - - init_netlogon_info1(info1, - flags, - pdc_connection_status); - r->out.query->info1 = info1; - break; - case 2: - info2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_2); - W_ERROR_HAVE_NO_MEMORY(info2); - - init_netlogon_info2(info2, - flags, - pdc_connection_status, - dc_name, - tc_status); - r->out.query->info2 = info2; - break; - case 3: - info3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_3); - W_ERROR_HAVE_NO_MEMORY(info3); - - init_netlogon_info3(info3, - flags, - logon_attempts); - r->out.query->info3 = info3; - break; - default: - return WERR_UNKNOWN_LEVEL; + case 1: + info1 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_1); + W_ERROR_HAVE_NO_MEMORY(info1); + + info1->flags = flags; + info1->pdc_connection_status = pdc_connection_status; + + r->out.query->info1 = info1; + break; + case 2: + info2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_2); + W_ERROR_HAVE_NO_MEMORY(info2); + + info2->flags = flags; + info2->pdc_connection_status = pdc_connection_status; + info2->trusted_dc_name = dc_name; + info2->tc_connection_status = tc_status; + + r->out.query->info2 = info2; + break; + case 3: + info3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_3); + W_ERROR_HAVE_NO_MEMORY(info3); + + info3->flags = flags; + info3->logon_attempts = logon_attempts; + + r->out.query->info3 = info3; + break; + case 4: + info4 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_4); + W_ERROR_HAVE_NO_MEMORY(info4); + + info4->trusted_dc_name = dc_name; + info4->trusted_domain_name = r->in.data->domain; + + r->out.query->info4 = info4; + break; + default: + return WERR_UNKNOWN_LEVEL; } if (lp_server_role() == ROLE_DOMAIN_BDC) { @@ -274,20 +385,47 @@ WERROR _netr_LogonControl2Ex(pipes_struct *p, WERROR _netr_NetrEnumerateTrustedDomains(pipes_struct *p, struct netr_NetrEnumerateTrustedDomains *r) { - struct netr_Blob trusted_domains_blob; + NTSTATUS status; DATA_BLOB blob; + struct trustdom_info **domains; + uint32_t num_domains; + const char **trusted_domains; + int i; DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__)); /* set up the Trusted Domain List response */ - blob = data_blob_talloc_zero(p->mem_ctx, 2); - trusted_domains_blob.data = blob.data; - trusted_domains_blob.length = blob.length; + become_root(); + status = pdb_enum_trusteddoms(p->mem_ctx, &num_domains, &domains); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } - DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__)); + trusted_domains = talloc_zero_array(p->mem_ctx, const char *, num_domains + 1); + if (!trusted_domains) { + return WERR_NOMEM; + } + + for (i = 0; i < num_domains; i++) { + trusted_domains[i] = talloc_strdup(trusted_domains, domains[i]->name); + if (!trusted_domains[i]) { + TALLOC_FREE(trusted_domains); + return WERR_NOMEM; + } + } + + if (!push_reg_multi_sz(trusted_domains, &blob, trusted_domains)) { + TALLOC_FREE(trusted_domains); + return WERR_NOMEM; + } + + r->out.trusted_domains_blob->data = blob.data; + r->out.trusted_domains_blob->length = blob.length; - *r->out.trusted_domains_blob = trusted_domains_blob; + DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__)); return WERR_OK; } @@ -296,8 +434,8 @@ WERROR _netr_NetrEnumerateTrustedDomains(pipes_struct *p, gets a machine password entry. checks access rights of the host. ******************************************************************/ -static NTSTATUS get_md4pw(char *md4pw, const char *mach_acct, - uint16_t sec_chan_type, uint32_t *rid) +static NTSTATUS get_md4pw(struct samr_Password *md4pw, const char *mach_acct, + enum netr_SchannelType sec_chan_type, struct dom_sid *sid) { struct samu *sampass = NULL; const uint8 *pass; @@ -390,12 +528,10 @@ static NTSTATUS get_md4pw(char *md4pw, const char *mach_acct, return NT_STATUS_LOGON_FAILURE; } - memcpy(md4pw, pass, 16); - dump_data(5, (uint8 *)md4pw, 16); + memcpy(md4pw->hash, pass, 16); + dump_data(5, md4pw->hash, 16); - if (rid) { - *rid = pdb_get_user_rid(sampass); - } + sid_copy(sid, pdb_get_user_sid(sampass)); TALLOC_FREE(sampass); @@ -411,30 +547,26 @@ static NTSTATUS get_md4pw(char *md4pw, const char *mach_acct, NTSTATUS _netr_ServerReqChallenge(pipes_struct *p, struct netr_ServerReqChallenge *r) { - if (!p->dc) { - p->dc = TALLOC_ZERO_P(p, struct dcinfo); - if (!p->dc) { - return NT_STATUS_NO_MEMORY; - } - } else { + struct netlogon_server_pipe_state *pipe_state = + talloc_get_type(p->private_data, struct netlogon_server_pipe_state); + + if (pipe_state) { DEBUG(10,("_netr_ServerReqChallenge: new challenge requested. Clearing old state.\n")); - ZERO_STRUCTP(p->dc); + talloc_free(pipe_state); + p->private_data = NULL; } - fstrcpy(p->dc->remote_machine, r->in.computer_name); + pipe_state = talloc(p, struct netlogon_server_pipe_state); + NT_STATUS_HAVE_NO_MEMORY(pipe_state); - /* Save the client challenge to the server. */ - memcpy(p->dc->clnt_chal.data, r->in.credentials->data, - sizeof(r->in.credentials->data)); + pipe_state->client_challenge = *r->in.credentials; - /* Create a server challenge for the client */ - /* Set this to a random value. */ - generate_random_buffer(p->dc->srv_chal.data, 8); + generate_random_buffer(pipe_state->server_challenge.data, + sizeof(pipe_state->server_challenge.data)); - /* set up the LSA REQUEST CHALLENGE response */ - init_net_r_req_chal(r->out.return_credentials, &p->dc->srv_chal); + *r->out.return_credentials = pipe_state->server_challenge; - p->dc->challenge_sent = True; + p->private_data = pipe_state; return NT_STATUS_OK; } @@ -447,56 +579,23 @@ NTSTATUS _netr_ServerReqChallenge(pipes_struct *p, NTSTATUS _netr_ServerAuthenticate(pipes_struct *p, struct netr_ServerAuthenticate *r) { - NTSTATUS status; - struct netr_Credential srv_chal_out; - - if (!p->dc || !p->dc->challenge_sent) { - return NT_STATUS_ACCESS_DENIED; - } - - status = get_md4pw((char *)p->dc->mach_pw, - r->in.account_name, - r->in.secure_channel_type, - NULL); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("_netr_ServerAuthenticate: get_md4pw failed. Failed to " - "get password for machine account %s " - "from client %s: %s\n", - r->in.account_name, - r->in.computer_name, - nt_errstr(status) )); - /* always return NT_STATUS_ACCESS_DENIED */ - return NT_STATUS_ACCESS_DENIED; - } - - /* From the client / server challenges and md4 password, generate sess key */ - creds_server_init(0, /* No neg flags. */ - p->dc, - &p->dc->clnt_chal, /* Stored client chal. */ - &p->dc->srv_chal, /* Stored server chal. */ - p->dc->mach_pw, - &srv_chal_out); - - /* Check client credentials are valid. */ - if (!netlogon_creds_server_check(p->dc, r->in.credentials)) { - DEBUG(0,("_netr_ServerAuthenticate: netlogon_creds_server_check failed. Rejecting auth " - "request from client %s machine account %s\n", - r->in.computer_name, - r->in.account_name)); - return NT_STATUS_ACCESS_DENIED; - } + struct netr_ServerAuthenticate3 a; + uint32_t negotiate_flags = 0; + uint32_t rid; - fstrcpy(p->dc->mach_acct, r->in.account_name); - fstrcpy(p->dc->remote_machine, r->in.computer_name); - p->dc->authenticated = True; + a.in.server_name = r->in.server_name; + a.in.account_name = r->in.account_name; + a.in.secure_channel_type = r->in.secure_channel_type; + a.in.computer_name = r->in.computer_name; + a.in.credentials = r->in.credentials; + a.in.negotiate_flags = &negotiate_flags; - /* set up the LSA AUTH response */ - /* Return the server credentials. */ + a.out.return_credentials = r->out.return_credentials; + a.out.rid = &rid; + a.out.negotiate_flags = &negotiate_flags; - memcpy(r->out.return_credentials->data, &srv_chal_out.data, - sizeof(r->out.return_credentials->data)); + return _netr_ServerAuthenticate3(p, &a); - return NT_STATUS_OK; } /************************************************************************* @@ -508,13 +607,20 @@ NTSTATUS _netr_ServerAuthenticate3(pipes_struct *p, { NTSTATUS status; uint32_t srv_flgs; - struct netr_Credential srv_chal_out; + /* r->in.negotiate_flags is an aliased pointer to r->out.negotiate_flags, + * so use a copy to avoid destroying the client values. */ + uint32_t in_neg_flags = *r->in.negotiate_flags; const char *fn; + struct dom_sid sid; + struct samr_Password mach_pwd; + struct netlogon_creds_CredentialState *creds; + struct netlogon_server_pipe_state *pipe_state = + talloc_get_type(p->private_data, struct netlogon_server_pipe_state); /* According to Microsoft (see bugid #6099) * Windows 7 looks at the negotiate_flags * returned in this structure *even if the - * call fails with access denied ! So in order + * call fails with access denied* ! So in order * to allow Win7 to connect to a Samba NT style * PDC we set the flags before we know if it's * an error or not. @@ -529,15 +635,22 @@ NTSTATUS _netr_ServerAuthenticate3(pipes_struct *p, NETLOGON_NEG_FULL_SYNC_REPL | NETLOGON_NEG_MULTIPLE_SIDS | NETLOGON_NEG_REDO | - NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL; + NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL | + NETLOGON_NEG_PASSWORD_SET2; + + /* Ensure we support strong (128-bit) keys. */ + if (in_neg_flags & NETLOGON_NEG_STRONG_KEYS) { + srv_flgs |= NETLOGON_NEG_STRONG_KEYS; + } if (lp_server_schannel() != false) { srv_flgs |= NETLOGON_NEG_SCHANNEL; } - *r->out.negotiate_flags = srv_flgs; - switch (p->hdr_req.opnum) { + case NDR_NETR_SERVERAUTHENTICATE: + fn = "_netr_ServerAuthenticate"; + break; case NDR_NETR_SERVERAUTHENTICATE2: fn = "_netr_ServerAuthenticate2"; break; @@ -551,68 +664,82 @@ NTSTATUS _netr_ServerAuthenticate3(pipes_struct *p, /* We use this as the key to store the creds: */ /* r->in.computer_name */ - if (!p->dc || !p->dc->challenge_sent) { + if (!pipe_state) { DEBUG(0,("%s: no challenge sent to client %s\n", fn, r->in.computer_name)); - return NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_ACCESS_DENIED; + goto out; } if ( (lp_server_schannel() == true) && - ((*r->in.negotiate_flags & NETLOGON_NEG_SCHANNEL) == 0) ) { + ((in_neg_flags & NETLOGON_NEG_SCHANNEL) == 0) ) { /* schannel must be used, but client did not offer it. */ DEBUG(0,("%s: schannel required but client failed " "to offer it. Client was %s\n", fn, r->in.account_name)); - return NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_ACCESS_DENIED; + goto out; } - status = get_md4pw((char *)p->dc->mach_pw, + status = get_md4pw(&mach_pwd, r->in.account_name, r->in.secure_channel_type, - r->out.rid); + &sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("%s: failed to get machine password for " "account %s: %s\n", fn, r->in.account_name, nt_errstr(status) )); /* always return NT_STATUS_ACCESS_DENIED */ - return NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_ACCESS_DENIED; + goto out; } /* From the client / server challenges and md4 password, generate sess key */ - creds_server_init(*r->in.negotiate_flags, - p->dc, - &p->dc->clnt_chal, /* Stored client chal. */ - &p->dc->srv_chal, /* Stored server chal. */ - p->dc->mach_pw, - &srv_chal_out); - /* Check client credentials are valid. */ - if (!netlogon_creds_server_check(p->dc, r->in.credentials)) { + creds = netlogon_creds_server_init(p->mem_ctx, + r->in.account_name, + r->in.computer_name, + r->in.secure_channel_type, + &pipe_state->client_challenge, + &pipe_state->server_challenge, + &mach_pwd, + r->in.credentials, + r->out.return_credentials, + *r->in.negotiate_flags); + if (!creds) { DEBUG(0,("%s: netlogon_creds_server_check failed. Rejecting auth " "request from client %s machine account %s\n", fn, r->in.computer_name, r->in.account_name)); - return NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_ACCESS_DENIED; + goto out; } - /* set up the LSA AUTH 2 response */ - memcpy(r->out.return_credentials->data, &srv_chal_out.data, - sizeof(r->out.return_credentials->data)); - - fstrcpy(p->dc->mach_acct, r->in.account_name); - fstrcpy(p->dc->remote_machine, r->in.computer_name); - fstrcpy(p->dc->domain, lp_workgroup() ); - p->dc->authenticated = True; + creds->sid = sid_dup_talloc(creds, &sid); + if (!creds->sid) { + status = NT_STATUS_NO_MEMORY; + goto out; + } /* Store off the state so we can continue after client disconnect. */ become_root(); - secrets_store_schannel_session_info(p->mem_ctx, - r->in.computer_name, - p->dc); + status = schannel_save_creds_state(p->mem_ctx, + NULL, lp_private_dir(), creds); unbecome_root(); - return NT_STATUS_OK; + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + sid_peek_rid(&sid, r->out.rid); + + status = NT_STATUS_OK; + + out: + + *r->out.negotiate_flags = srv_flgs; + return status; } /************************************************************************* @@ -640,71 +767,85 @@ NTSTATUS _netr_ServerAuthenticate2(pipes_struct *p, } /************************************************************************* - _netr_ServerPasswordSet + * If schannel is required for this call test that it actually is available. *************************************************************************/ - -NTSTATUS _netr_ServerPasswordSet(pipes_struct *p, - struct netr_ServerPasswordSet *r) +static NTSTATUS schannel_check_required(struct pipe_auth_data *auth_info, + const char *computer_name, + bool integrity, bool privacy) { - NTSTATUS status = NT_STATUS_OK; - fstring remote_machine; - struct samu *sampass=NULL; - bool ret = False; - unsigned char pwd[16]; - int i; - uint32 acct_ctrl; - struct netr_Authenticator cred_out; - const uchar *old_pw; - - DEBUG(5,("_netr_ServerPasswordSet: %d\n", __LINE__)); + if (auth_info && auth_info->auth_type == PIPE_AUTH_TYPE_SCHANNEL) { + if (!privacy && !integrity) { + return NT_STATUS_OK; + } - /* We need the remote machine name for the creds lookup. */ - fstrcpy(remote_machine, r->in.computer_name); + if ((!privacy && integrity) && + auth_info->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + return NT_STATUS_OK; + } - if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) { - /* 'server schannel = yes' should enforce use of - schannel, the client did offer it in auth2, but - obviously did not use it. */ - DEBUG(0,("_netr_ServerPasswordSet: client %s not using schannel for netlogon\n", - remote_machine )); - return NT_STATUS_ACCESS_DENIED; + if ((privacy || integrity) && + auth_info->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + return NT_STATUS_OK; + } } - if (!p->dc) { - /* Restore the saved state of the netlogon creds. */ - become_root(); - ret = secrets_restore_schannel_session_info(p, remote_machine, - &p->dc); - unbecome_root(); - if (!ret) { - return NT_STATUS_INVALID_HANDLE; + /* test didn't pass */ + DEBUG(0, ("schannel_check_required: [%s] is not using schannel\n", + computer_name)); + + return NT_STATUS_ACCESS_DENIED; +} + +/************************************************************************* + *************************************************************************/ + +static NTSTATUS netr_creds_server_step_check(pipes_struct *p, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out) +{ + NTSTATUS status; + bool schannel_global_required = (lp_server_schannel() == true) ? true:false; + + if (schannel_global_required) { + status = schannel_check_required(&p->auth, + computer_name, + false, false); + if (!NT_STATUS_IS_OK(status)) { + return status; } } - if (!p->dc || !p->dc->authenticated) { - return NT_STATUS_INVALID_HANDLE; - } + status = schannel_check_creds_state(mem_ctx, NULL, + lp_private_dir(), + computer_name, + received_authenticator, + return_authenticator, + creds_out); - DEBUG(3,("_netr_ServerPasswordSet: Server Password Set by remote machine:[%s] on account [%s]\n", - remote_machine, p->dc->mach_acct)); + return status; +} - /* Step the creds chain forward. */ - if (!netlogon_creds_server_step(p->dc, r->in.credential, &cred_out)) { - DEBUG(2,("_netr_ServerPasswordSet: netlogon_creds_server_step failed. Rejecting auth " - "request from client %s machine account %s\n", - remote_machine, p->dc->mach_acct )); - return NT_STATUS_INVALID_PARAMETER; - } +/************************************************************************* + *************************************************************************/ + +static NTSTATUS netr_find_machine_account(TALLOC_CTX *mem_ctx, + const char *account_name, + struct samu **sampassp) +{ + struct samu *sampass; + bool ret = false; + uint32_t acct_ctrl; - /* We must store the creds state after an update. */ - sampass = samu_new( NULL ); + sampass = samu_new(mem_ctx); if (!sampass) { return NT_STATUS_NO_MEMORY; } become_root(); - secrets_store_schannel_session_info(p, remote_machine, p->dc); - ret = pdb_getsampwnam(sampass, p->dc->mach_acct); + ret = pdb_getsampwnam(sampass, account_name); unbecome_root(); if (!ret) { @@ -717,131 +858,236 @@ NTSTATUS _netr_ServerPasswordSet(pipes_struct *p, acct_ctrl = pdb_get_acct_ctrl(sampass); if (!(acct_ctrl & ACB_WSTRUST || - acct_ctrl & ACB_SVRTRUST || - acct_ctrl & ACB_DOMTRUST)) { + acct_ctrl & ACB_SVRTRUST || + acct_ctrl & ACB_DOMTRUST)) { TALLOC_FREE(sampass); return NT_STATUS_NO_SUCH_USER; } - if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) { + if (acct_ctrl & ACB_DISABLED) { TALLOC_FREE(sampass); return NT_STATUS_ACCOUNT_DISABLED; } - /* Woah - what does this to to the credential chain ? JRA */ - cred_hash3(pwd, r->in.new_password->hash, p->dc->sess_key, 0); - - DEBUG(100,("_netr_ServerPasswordSet: new given value was :\n")); - for(i = 0; i < sizeof(pwd); i++) - DEBUG(100,("%02X ", pwd[i])); - DEBUG(100,("\n")); + *sampassp = sampass; - old_pw = pdb_get_nt_passwd(sampass); + return NT_STATUS_OK; +} - if (old_pw && memcmp(pwd, old_pw, 16) == 0) { - /* Avoid backend modificiations and other fun if the - client changed the password to the *same thing* */ +/************************************************************************* + *************************************************************************/ - ret = True; - } else { +static NTSTATUS netr_set_machine_account_password(TALLOC_CTX *mem_ctx, + struct samu *sampass, + DATA_BLOB *plaintext_blob, + struct samr_Password *nt_hash, + struct samr_Password *lm_hash) +{ + NTSTATUS status; + const uchar *old_pw; + const char *plaintext = NULL; + size_t plaintext_len; + struct samr_Password nt_hash_local; - /* LM password should be NULL for machines */ - if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) { - TALLOC_FREE(sampass); - return NT_STATUS_NO_MEMORY; - } + if (!sampass) { + return NT_STATUS_INVALID_PARAMETER; + } - if (!pdb_set_nt_passwd(sampass, pwd, PDB_CHANGED)) { - TALLOC_FREE(sampass); - return NT_STATUS_NO_MEMORY; + if (plaintext_blob) { + if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, + plaintext_blob->data, plaintext_blob->length, + &plaintext, &plaintext_len, false)) + { + plaintext = NULL; + mdfour(nt_hash_local.hash, plaintext_blob->data, plaintext_blob->length); + nt_hash = &nt_hash_local; } + } - if (!pdb_set_pass_last_set_time(sampass, time(NULL), PDB_CHANGED)) { - TALLOC_FREE(sampass); - /* Not quite sure what this one qualifies as, but this will do */ - return NT_STATUS_UNSUCCESSFUL; + if (plaintext) { + if (!pdb_set_plaintext_passwd(sampass, plaintext)) { + return NT_STATUS_ACCESS_DENIED; } - become_root(); - status = pdb_update_sam_account(sampass); - unbecome_root(); + goto done; } - /* set up the LSA Server Password Set response */ + if (nt_hash) { + old_pw = pdb_get_nt_passwd(sampass); - memcpy(r->out.return_authenticator, &cred_out, - sizeof(*(r->out.return_authenticator))); + if (old_pw && memcmp(nt_hash->hash, old_pw, 16) == 0) { + /* Avoid backend modificiations and other fun if the + client changed the password to the *same thing* */ + } else { + /* LM password should be NULL for machines */ + if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) { + return NT_STATUS_NO_MEMORY; + } + if (!pdb_set_nt_passwd(sampass, nt_hash->hash, PDB_CHANGED)) { + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_pass_last_set_time(sampass, time(NULL), PDB_CHANGED)) { + /* Not quite sure what this one qualifies as, but this will do */ + return NT_STATUS_UNSUCCESSFUL; + } + } + } + + done: + become_root(); + status = pdb_update_sam_account(sampass); + unbecome_root(); - TALLOC_FREE(sampass); return status; } /************************************************************************* - _netr_LogonSamLogoff + _netr_ServerPasswordSet *************************************************************************/ -NTSTATUS _netr_LogonSamLogoff(pipes_struct *p, - struct netr_LogonSamLogoff *r) +NTSTATUS _netr_ServerPasswordSet(pipes_struct *p, + struct netr_ServerPasswordSet *r) { - if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) { - /* 'server schannel = yes' should enforce use of - schannel, the client did offer it in auth2, but - obviously did not use it. */ - DEBUG(0,("_netr_LogonSamLogoff: client %s not using schannel for netlogon\n", - get_remote_machine_name() )); - return NT_STATUS_ACCESS_DENIED; + NTSTATUS status = NT_STATUS_OK; + struct samu *sampass=NULL; + int i; + struct netlogon_creds_CredentialState *creds; + + DEBUG(5,("_netr_ServerPasswordSet: %d\n", __LINE__)); + + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("_netr_ServerPasswordSet: netlogon_creds_server_step failed. Rejecting auth " + "request from client %s machine account %s\n", + r->in.computer_name, creds->computer_name)); + TALLOC_FREE(creds); + return status; } + DEBUG(3,("_netr_ServerPasswordSet: Server Password Set by remote machine:[%s] on account [%s]\n", + r->in.computer_name, creds->computer_name)); - /* Using the remote machine name for the creds store: */ - /* r->in.computer_name */ + netlogon_creds_des_decrypt(creds, r->in.new_password); - if (!p->dc) { - /* Restore the saved state of the netlogon creds. */ - bool ret; + DEBUG(100,("_netr_ServerPasswordSet: new given value was :\n")); + for(i = 0; i < sizeof(r->in.new_password->hash); i++) + DEBUG(100,("%02X ", r->in.new_password->hash[i])); + DEBUG(100,("\n")); - become_root(); - ret = secrets_restore_schannel_session_info( - p, r->in.computer_name, &p->dc); - unbecome_root(); - if (!ret) { - return NT_STATUS_INVALID_HANDLE; - } + status = netr_find_machine_account(p->mem_ctx, + creds->account_name, + &sampass); + if (!NT_STATUS_IS_OK(status)) { + return status; } - if (!p->dc || !p->dc->authenticated) { - return NT_STATUS_INVALID_HANDLE; + status = netr_set_machine_account_password(sampass, + sampass, + NULL, + r->in.new_password, + NULL); + TALLOC_FREE(sampass); + return status; +} + +/**************************************************************** + _netr_ServerPasswordSet2 +****************************************************************/ + +NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p, + struct netr_ServerPasswordSet2 *r) +{ + NTSTATUS status; + struct netlogon_creds_CredentialState *creds; + struct samu *sampass; + DATA_BLOB plaintext; + struct samr_CryptPassword password_buf; + struct samr_Password nt_hash; + + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("_netr_ServerPasswordSet2: netlogon_creds_server_step " + "failed. Rejecting auth request from client %s machine account %s\n", + r->in.computer_name, creds->computer_name)); + TALLOC_FREE(creds); + return status; } - /* checks and updates credentials. creates reply credentials */ - if (!netlogon_creds_server_step(p->dc, r->in.credential, r->out.return_authenticator)) { - DEBUG(2,("_netr_LogonSamLogoff: netlogon_creds_server_step failed. Rejecting auth " - "request from client %s machine account %s\n", - r->in.computer_name, p->dc->mach_acct )); - return NT_STATUS_INVALID_PARAMETER; + memcpy(password_buf.data, r->in.new_password->data, 512); + SIVAL(password_buf.data, 512, r->in.new_password->length); + netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); + + if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &plaintext)) { + return NT_STATUS_WRONG_PASSWORD; + } + + mdfour(nt_hash.hash, plaintext.data, plaintext.length); + + status = netr_find_machine_account(p->mem_ctx, + creds->account_name, + &sampass); + if (!NT_STATUS_IS_OK(status)) { + return status; } - /* We must store the creds state after an update. */ + status = netr_set_machine_account_password(sampass, + sampass, + NULL, + &nt_hash, + NULL); + TALLOC_FREE(sampass); + return status; +} + +/************************************************************************* + _netr_LogonSamLogoff + *************************************************************************/ + +NTSTATUS _netr_LogonSamLogoff(pipes_struct *p, + struct netr_LogonSamLogoff *r) +{ + NTSTATUS status; + struct netlogon_creds_CredentialState *creds; + become_root(); - secrets_store_schannel_session_info(p, r->in.computer_name, p->dc); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); unbecome_root(); - return NT_STATUS_OK; + return status; } /************************************************************************* - _netr_LogonSamLogon + _netr_LogonSamLogon_base *************************************************************************/ -NTSTATUS _netr_LogonSamLogon(pipes_struct *p, - struct netr_LogonSamLogon *r) +static NTSTATUS _netr_LogonSamLogon_base(pipes_struct *p, + struct netr_LogonSamLogonEx *r, + struct netlogon_creds_CredentialState *creds) { NTSTATUS status = NT_STATUS_OK; - struct netr_SamInfo3 *sam3 = NULL; union netr_LogonLevel *logon = r->in.logon; - fstring nt_username, nt_domain, nt_workstation; - auth_usersupplied_info *user_info = NULL; - auth_serversupplied_info *server_info = NULL; + const char *nt_username, *nt_domain, *nt_workstation; + struct auth_usersupplied_info *user_info = NULL; + struct auth_serversupplied_info *server_info = NULL; struct auth_context *auth_context = NULL; uint8_t pipe_session_key[16]; bool process_creds = true; @@ -852,92 +1098,61 @@ NTSTATUS _netr_LogonSamLogon(pipes_struct *p, process_creds = true; fn = "_netr_LogonSamLogon"; break; + case NDR_NETR_LOGONSAMLOGONWITHFLAGS: + process_creds = true; + fn = "_netr_LogonSamLogonWithFlags"; + break; case NDR_NETR_LOGONSAMLOGONEX: + process_creds = false; fn = "_netr_LogonSamLogonEx"; + break; default: - fn = ""; - process_creds = false; - } - - if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) { - /* 'server schannel = yes' should enforce use of - schannel, the client did offer it in auth2, but - obviously did not use it. */ - DEBUG(0,("%s: client %s not using schannel for netlogon\n", - fn, get_remote_machine_name() )); - return NT_STATUS_ACCESS_DENIED; - } - - sam3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo3); - if (!sam3) { - return NT_STATUS_NO_MEMORY; + return NT_STATUS_INTERNAL_ERROR; } - /* store the user information, if there is any. */ - r->out.validation->sam3 = sam3; *r->out.authoritative = true; /* authoritative response */ - if (r->in.validation_level != 2 && r->in.validation_level != 3) { - DEBUG(0,("%s: bad validation_level value %d.\n", - fn, (int)r->in.validation_level)); - return NT_STATUS_ACCESS_DENIED; - } - - if (process_creds) { - /* Get the remote machine name for the creds store. */ - /* Note this is the remote machine this request is coming from (member server), - not neccessarily the workstation name the user is logging onto. - */ - - if (!p->dc) { - /* Restore the saved state of the netlogon creds. */ - bool ret; - - become_root(); - ret = secrets_restore_schannel_session_info( - p, r->in.computer_name, &p->dc); - unbecome_root(); - if (!ret) { - return NT_STATUS_INVALID_HANDLE; - } + switch (r->in.validation_level) { + case 2: + r->out.validation->sam2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo2); + if (!r->out.validation->sam2) { + return NT_STATUS_NO_MEMORY; } - - if (!p->dc || !p->dc->authenticated) { - return NT_STATUS_INVALID_HANDLE; + break; + case 3: + r->out.validation->sam3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo3); + if (!r->out.validation->sam3) { + return NT_STATUS_NO_MEMORY; } - - /* checks and updates credentials. creates reply credentials */ - if (!netlogon_creds_server_step(p->dc, r->in.credential, r->out.return_authenticator)) { - DEBUG(2,("%s: creds_server_step failed. Rejecting auth " - "request from client %s machine account %s\n", - fn, r->in.computer_name, p->dc->mach_acct )); - return NT_STATUS_INVALID_PARAMETER; + break; + case 6: + r->out.validation->sam6 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo6); + if (!r->out.validation->sam6) { + return NT_STATUS_NO_MEMORY; } - - /* We must store the creds state after an update. */ - become_root(); - secrets_store_schannel_session_info(p, r->in.computer_name, p->dc); - unbecome_root(); + break; + default: + DEBUG(0,("%s: bad validation_level value %d.\n", + fn, (int)r->in.validation_level)); + return NT_STATUS_INVALID_INFO_CLASS; } switch (r->in.logon_level) { case NetlogonInteractiveInformation: - fstrcpy(nt_username, - logon->password->identity_info.account_name.string); - fstrcpy(nt_domain, - logon->password->identity_info.domain_name.string); - fstrcpy(nt_workstation, - logon->password->identity_info.workstation.string); + case NetlogonServiceInformation: + case NetlogonInteractiveTransitiveInformation: + case NetlogonServiceTransitiveInformation: + nt_username = logon->password->identity_info.account_name.string; + nt_domain = logon->password->identity_info.domain_name.string; + nt_workstation = logon->password->identity_info.workstation.string; DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup())); break; case NetlogonNetworkInformation: - fstrcpy(nt_username, - logon->network->identity_info.account_name.string); - fstrcpy(nt_domain, - logon->network->identity_info.domain_name.string); - fstrcpy(nt_workstation, - logon->network->identity_info.workstation.string); + case NetlogonNetworkTransitiveInformation: + nt_username = logon->network->identity_info.account_name.string; + nt_domain = logon->network->identity_info.domain_name.string; + nt_workstation = logon->network->identity_info.workstation.string; DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup())); break; @@ -957,6 +1172,7 @@ NTSTATUS _netr_LogonSamLogon(pipes_struct *p, switch (r->in.logon_level) { case NetlogonNetworkInformation: + case NetlogonNetworkTransitiveInformation: { const char *wksname = nt_workstation; @@ -986,6 +1202,10 @@ NTSTATUS _netr_LogonSamLogon(pipes_struct *p, break; } case NetlogonInteractiveInformation: + case NetlogonServiceInformation: + case NetlogonInteractiveTransitiveInformation: + case NetlogonServiceTransitiveInformation: + /* 'Interactive' authentication, supplies the password in its MD4 form, encrypted with the session key. We will convert this to challenge/response for the auth subsystem to chew @@ -1006,7 +1226,7 @@ NTSTATUS _netr_LogonSamLogon(pipes_struct *p, chal, logon->password->lmpassword.hash, logon->password->ntpassword.hash, - p->dc->sess_key)) { + creds->session_key)) { status = NT_STATUS_NO_MEMORY; } break; @@ -1057,18 +1277,102 @@ NTSTATUS _netr_LogonSamLogon(pipes_struct *p, if (process_creds) { /* Get the pipe session key from the creds. */ - memcpy(pipe_session_key, p->dc->sess_key, 16); + memcpy(pipe_session_key, creds->session_key, 16); } else { /* Get the pipe session key from the schannel. */ if ((p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) || (p->auth.a_u.schannel_auth == NULL)) { return NT_STATUS_INVALID_HANDLE; } - memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16); + memcpy(pipe_session_key, p->auth.a_u.schannel_auth->creds->session_key, 16); + } + + switch (r->in.validation_level) { + case 2: + status = serverinfo_to_SamInfo2(server_info, pipe_session_key, 16, + r->out.validation->sam2); + break; + case 3: + status = serverinfo_to_SamInfo3(server_info, pipe_session_key, 16, + r->out.validation->sam3); + break; + case 6: + status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16, + r->out.validation->sam6); + break; } - status = serverinfo_to_SamInfo3(server_info, pipe_session_key, 16, sam3); TALLOC_FREE(server_info); + + return status; +} + +/**************************************************************** + _netr_LogonSamLogonWithFlags +****************************************************************/ + +NTSTATUS _netr_LogonSamLogonWithFlags(pipes_struct *p, + struct netr_LogonSamLogonWithFlags *r) +{ + NTSTATUS status; + struct netlogon_creds_CredentialState *creds; + struct netr_LogonSamLogonEx r2; + struct netr_Authenticator return_authenticator; + + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + &return_authenticator, + &creds); + unbecome_root(); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r2.in.server_name = r->in.server_name; + r2.in.computer_name = r->in.computer_name; + r2.in.logon_level = r->in.logon_level; + r2.in.logon = r->in.logon; + r2.in.validation_level = r->in.validation_level; + r2.in.flags = r->in.flags; + r2.out.validation = r->out.validation; + r2.out.authoritative = r->out.authoritative; + r2.out.flags = r->out.flags; + + status = _netr_LogonSamLogon_base(p, &r2, creds); + + *r->out.return_authenticator = return_authenticator; + + return status; +} + +/************************************************************************* + _netr_LogonSamLogon + *************************************************************************/ + +NTSTATUS _netr_LogonSamLogon(pipes_struct *p, + struct netr_LogonSamLogon *r) +{ + NTSTATUS status; + struct netr_LogonSamLogonWithFlags r2; + uint32_t flags = 0; + + r2.in.server_name = r->in.server_name; + r2.in.computer_name = r->in.computer_name; + r2.in.credential = r->in.credential; + r2.in.logon_level = r->in.logon_level; + r2.in.logon = r->in.logon; + r2.in.validation_level = r->in.validation_level; + r2.in.return_authenticator = r->in.return_authenticator; + r2.in.flags = &flags; + r2.out.validation = r->out.validation; + r2.out.authoritative = r->out.authoritative; + r2.out.flags = &flags; + r2.out.return_authenticator = r->out.return_authenticator; + + status = _netr_LogonSamLogonWithFlags(p, &r2); + return status; } @@ -1080,7 +1384,17 @@ NTSTATUS _netr_LogonSamLogon(pipes_struct *p, NTSTATUS _netr_LogonSamLogonEx(pipes_struct *p, struct netr_LogonSamLogonEx *r) { - struct netr_LogonSamLogon q; + NTSTATUS status; + struct netlogon_creds_CredentialState *creds = NULL; + + become_root(); + status = schannel_get_creds_state(p->mem_ctx, + NULL, lp_private_dir(), + r->in.computer_name, &creds); + unbecome_root(); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* Only allow this if the pipe is protected. */ if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) { @@ -1089,20 +1403,10 @@ NTSTATUS _netr_LogonSamLogonEx(pipes_struct *p, return NT_STATUS_INVALID_PARAMETER; } - q.in.server_name = r->in.server_name; - q.in.computer_name = r->in.computer_name; - q.in.logon_level = r->in.logon_level; - q.in.logon = r->in.logon; - q.in.validation_level = r->in.validation_level; - /* we do not handle the flags */ - /* = r->in.flags; */ - - q.out.validation = r->out.validation; - q.out.authoritative = r->out.authoritative; - /* we do not handle the flags */ - /* = r->out.flags; */ + status = _netr_LogonSamLogon_base(p, r, creds); + TALLOC_FREE(creds); - return _netr_LogonSamLogon(p, &q); + return status; } /************************************************************************* @@ -1188,21 +1492,132 @@ NTSTATUS _netr_AccountSync(pipes_struct *p, /**************************************************************** ****************************************************************/ +static bool wb_getdcname(TALLOC_CTX *mem_ctx, + const char *domain, + const char **dcname, + uint32_t flags, + WERROR *werr) +{ + wbcErr result; + struct wbcDomainControllerInfo *dc_info = NULL; + + result = wbcLookupDomainController(domain, + flags, + &dc_info); + switch (result) { + case WBC_ERR_SUCCESS: + break; + case WBC_ERR_WINBIND_NOT_AVAILABLE: + return false; + case WBC_ERR_DOMAIN_NOT_FOUND: + *werr = WERR_NO_SUCH_DOMAIN; + return true; + default: + *werr = WERR_DOMAIN_CONTROLLER_NOT_FOUND; + return true; + } + + *dcname = talloc_strdup(mem_ctx, dc_info->dc_name); + wbcFreeMemory(dc_info); + if (!*dcname) { + *werr = WERR_NOMEM; + return false; + } + + *werr = WERR_OK; + + return true; +} + +/**************************************************************** + _netr_GetDcName +****************************************************************/ + WERROR _netr_GetDcName(pipes_struct *p, struct netr_GetDcName *r) { - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; + NTSTATUS status; + WERROR werr; + uint32_t flags; + struct netr_DsRGetDCNameInfo *info; + bool ret; + + ret = wb_getdcname(p->mem_ctx, + r->in.domainname, + r->out.dcname, + WBC_LOOKUP_DC_IS_FLAT_NAME | + WBC_LOOKUP_DC_RETURN_FLAT_NAME | + WBC_LOOKUP_DC_PDC_REQUIRED, + &werr); + if (ret == true) { + return werr; + } + + flags = DS_PDC_REQUIRED | DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME; + + status = dsgetdcname(p->mem_ctx, + smbd_messaging_context(), + r->in.domainname, + NULL, + NULL, + flags, + &info); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc); + talloc_free(info); + if (!*r->out.dcname) { + return WERR_NOMEM; + } + + return WERR_OK; } /**************************************************************** + _netr_GetAnyDCName ****************************************************************/ WERROR _netr_GetAnyDCName(pipes_struct *p, struct netr_GetAnyDCName *r) { - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; + NTSTATUS status; + WERROR werr; + uint32_t flags; + struct netr_DsRGetDCNameInfo *info; + bool ret; + + ret = wb_getdcname(p->mem_ctx, + r->in.domainname, + r->out.dcname, + WBC_LOOKUP_DC_IS_FLAT_NAME | + WBC_LOOKUP_DC_RETURN_FLAT_NAME, + &werr); + if (ret == true) { + return werr; + } + + flags = DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME; + + status = dsgetdcname(p->mem_ctx, + smbd_messaging_context(), + r->in.domainname, + NULL, + NULL, + flags, + &info); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc); + talloc_free(info); + if (!*r->out.dcname) { + return WERR_NOMEM; + } + + return WERR_OK; } /**************************************************************** @@ -1317,16 +1732,6 @@ NTSTATUS _netr_LogonGetDomainInfo(pipes_struct *p, /**************************************************************** ****************************************************************/ -NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p, - struct netr_ServerPasswordSet2 *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - WERROR _netr_ServerPasswordGet(pipes_struct *p, struct netr_ServerPasswordGet *r) { @@ -1447,18 +1852,8 @@ WERROR _netr_DsRGetForestTrustInformation(pipes_struct *p, /**************************************************************** ****************************************************************/ -WERROR _netr_GetForestTrustInformation(pipes_struct *p, - struct netr_GetForestTrustInformation *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_LogonSamLogonWithFlags(pipes_struct *p, - struct netr_LogonSamLogonWithFlags *r) +NTSTATUS _netr_GetForestTrustInformation(pipes_struct *p, + struct netr_GetForestTrustInformation *r) { p->rng_fault_state = true; return NT_STATUS_NOT_IMPLEMENTED;