* 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
/* This is the implementation of the netlogon pipe. */
#include "includes.h"
-#include "../libcli/auth/libcli_auth.h"
-#include "../libcli/auth/schannel_state.h"
#include "../libcli/auth/schannel.h"
+#include "../librpc/gen_ndr/srv_netlogon.h"
extern userdom_struct current_user_info;
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
****************************************************************/
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:
return WERR_INVALID_PARAM;
}
+ acct_ctrl = pdb_get_acct_ctrl(p->server_info->sam_account);
+
+ switch (r->in.function_code) {
+ 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;
+ }
+
tc_status = WERR_NO_SUCH_DOMAIN;
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;
+ }
+
+ 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;
+ }
+
+ 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;
case NETLOGON_CONTROL_REDISCOVER:
+ if (!r->in.data || !r->in.data->domain) {
+ return WERR_NOT_SUPPORTED;
+ }
+
domain = r->in.data->domain;
if (!is_trusted_domain(domain)) {
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",
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;
}
/* Store off the state so we can continue after client disconnect. */
become_root();
- status = schannel_store_session_key(p->mem_ctx, creds);
+ status = schannel_save_creds_state(p->mem_ctx,
+ NULL, lp_private_dir(), creds);
unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
return _netr_ServerAuthenticate3(p, &a);
}
+/*************************************************************************
+ * If schannel is required for this call test that it actually is available.
+ *************************************************************************/
+static NTSTATUS schannel_check_required(struct pipe_auth_data *auth_info,
+ const char *computer_name,
+ bool integrity, bool privacy)
+{
+ if (auth_info && auth_info->auth_type == PIPE_AUTH_TYPE_SCHANNEL) {
+ if (!privacy && !integrity) {
+ return NT_STATUS_OK;
+ }
+
+ if ((!privacy && integrity) &&
+ auth_info->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
+ return NT_STATUS_OK;
+ }
+
+ if ((privacy || integrity) &&
+ auth_info->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* test didn't pass */
+ DEBUG(0, ("schannel_check_required: [%s] is not using schannel\n",
+ computer_name));
+
+ return NT_STATUS_ACCESS_DENIED;
+}
+
/*************************************************************************
*************************************************************************/
struct netlogon_creds_CredentialState **creds_out)
{
NTSTATUS status;
- struct tdb_context *tdb;
bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
- bool schannel_in_use = (p->auth.auth_type == PIPE_AUTH_TYPE_SCHANNEL) ? true:false; /* &&
- (p->auth.auth_level == DCERPC_AUTH_LEVEL_INTEGRITY ||
- p->auth.auth_level == DCERPC_AUTH_LEVEL_PRIVACY); */
- tdb = open_schannel_session_store(mem_ctx);
- if (!tdb) {
- return NT_STATUS_ACCESS_DENIED;
+ if (schannel_global_required) {
+ status = schannel_check_required(&p->auth,
+ computer_name,
+ false, false);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
- status = schannel_creds_server_step_check_tdb(tdb, mem_ctx,
- computer_name,
- schannel_global_required,
- schannel_in_use,
- received_authenticator,
- return_authenticator,
- creds_out);
- tdb_close(tdb);
+ status = schannel_check_creds_state(mem_ctx, NULL,
+ lp_private_dir(),
+ computer_name,
+ received_authenticator,
+ return_authenticator,
+ creds_out);
return status;
}
NTSTATUS status = NT_STATUS_OK;
union netr_LogonLevel *logon = r->in.logon;
const char *nt_username, *nt_domain, *nt_workstation;
- auth_usersupplied_info *user_info = NULL;
- auth_serversupplied_info *server_info = NULL;
+ 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;
struct netlogon_creds_CredentialState *creds = NULL;
become_root();
- status = schannel_fetch_session_key(p->mem_ctx, r->in.computer_name, &creds);
+ 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;
/****************************************************************
****************************************************************/
+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;
}
/****************************************************************
/****************************************************************
****************************************************************/
-WERROR _netr_GetForestTrustInformation(pipes_struct *p,
- struct netr_GetForestTrustInformation *r)
+NTSTATUS _netr_GetForestTrustInformation(pipes_struct *p,
+ struct netr_GetForestTrustInformation *r)
{
p->rng_fault_state = true;
- return WERR_NOT_SUPPORTED;
+ return NT_STATUS_NOT_IMPLEMENTED;
}
/****************************************************************