-/*
+/*
Unix SMB/CIFS implementation.
endpoint server for the netlogon pipe
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
-
+ Copyright (C) Matthias Dieter Wallnöfer 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
the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "rpc_server/dcerpc_server.h"
-#include "rpc_server/common/common.h"
-#include "lib/ldb/include/ldb.h"
#include "auth/auth.h"
#include "auth/auth_sam_reply.h"
#include "dsdb/samdb/samdb.h"
-#include "../libds/common/flags.h"
-#include "rpc_server/samr/proto.h"
#include "../lib/util/util_ldb.h"
-#include "libcli/auth/libcli_auth.h"
-#include "auth/gensec/schannel.h"
+#include "../libcli/auth/schannel.h"
#include "libcli/security/security.h"
#include "param/param.h"
#include "lib/messaging/irpc.h"
#include "librpc/gen_ndr/ndr_irpc.h"
-#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "cldap_server/cldap_server.h"
+#include "lib/tsocket/tsocket.h"
struct netlogon_server_pipe_state {
struct netr_Credential client_challenge;
struct netr_Credential server_challenge;
};
-
static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_ServerReqChallenge *r)
{
talloc_free(pipe_state);
dce_call->context->private_data = NULL;
}
-
+
pipe_state = talloc(dce_call->context, struct netlogon_server_pipe_state);
NT_STATUS_HAVE_NO_MEMORY(pipe_state);
pipe_state->client_challenge = *r->in.credentials;
- generate_random_buffer(pipe_state->server_challenge.data,
+ generate_random_buffer(pipe_state->server_challenge.data,
sizeof(pipe_state->server_challenge.data));
*r->out.return_credentials = pipe_state->server_challenge;
struct netlogon_server_pipe_state *pipe_state =
talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
struct netlogon_creds_CredentialState *creds;
- struct ldb_context *schannel_ldb;
struct ldb_context *sam_ctx;
struct samr_Password *mach_pwd;
uint32_t user_account_control;
int num_records;
struct ldb_message **msgs;
NTSTATUS nt_status;
- const char *attrs[] = {"unicodePwd", "userAccountControl",
+ const char *attrs[] = {"unicodePwd", "userAccountControl",
"objectSid", NULL};
const char *trust_dom_attrs[] = {"flatname", NULL};
return NT_STATUS_ACCESS_DENIED;
}
- sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
- system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
+ system_session(dce_call->conn->dce_ctx->lp_ctx));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
}
/* pull the user attributes */
- num_records = gendb_search((struct ldb_context *)sam_ctx,
- mem_ctx, NULL, &msgs,
+ num_records = gendb_search(sam_ctx, mem_ctx, NULL, &msgs,
trust_dom_attrs,
- "(&(trustPartner=%s)(objectclass=trustedDomain))",
+ "(&(trustPartner=%s)(objectclass=trustedDomain))",
encoded_account);
-
+
if (num_records == 0) {
- DEBUG(3,("Couldn't find trust [%s] in samdb.\n",
+ DEBUG(3,("Couldn't find trust [%s] in samdb.\n",
encoded_account));
return NT_STATUS_ACCESS_DENIED;
}
-
+
if (num_records > 1) {
DEBUG(0,("Found %d records matching user [%s]\n", num_records, r->in.account_name));
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
-
+
flatname = ldb_msg_find_attr_as_string(msgs[0], "flatname", NULL);
if (!flatname) {
/* No flatname for this trust - we can't proceed */
if (!account_name) {
return NT_STATUS_NO_MEMORY;
}
-
+
} else {
account_name = r->in.account_name;
}
-
+
/* pull the user attributes */
- num_records = gendb_search((struct ldb_context *)sam_ctx, mem_ctx,
- NULL, &msgs, attrs,
- "(&(sAMAccountName=%s)(objectclass=user))",
+ num_records = gendb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs,
+ "(&(sAMAccountName=%s)(objectclass=user))",
ldb_binary_encode_string(mem_ctx, account_name));
if (num_records == 0) {
- DEBUG(3,("Couldn't find user [%s] in samdb.\n",
+ DEBUG(3,("Couldn't find user [%s] in samdb.\n",
r->in.account_name));
return NT_STATUS_ACCESS_DENIED;
}
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
-
user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0);
if (user_account_control & UF_ACCOUNTDISABLE) {
DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", user_account_control));
return NT_STATUS_ACCESS_DENIED;
}
- } else if (r->in.secure_channel_type == SEC_CHAN_DOMAIN ||
+ } else if (r->in.secure_channel_type == SEC_CHAN_DOMAIN ||
r->in.secure_channel_type == SEC_CHAN_DNS_DOMAIN) {
if (!(user_account_control & UF_INTERDOMAIN_TRUST_ACCOUNT)) {
DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", user_account_control));
-
+
return NT_STATUS_ACCESS_DENIED;
}
} else if (r->in.secure_channel_type == SEC_CHAN_BDC) {
return NT_STATUS_ACCESS_DENIED;
}
} else {
- DEBUG(1, ("Client asked for an invalid secure channel type: %d\n",
+ DEBUG(1, ("Client asked for an invalid secure channel type: %d\n",
r->in.secure_channel_type));
return NT_STATUS_ACCESS_DENIED;
}
- *r->out.rid = samdb_result_rid_from_sid(mem_ctx, msgs[0],
+ *r->out.rid = samdb_result_rid_from_sid(mem_ctx, msgs[0],
"objectSid", 0);
mach_pwd = samdb_result_hash(mem_ctx, msgs[0], "unicodePwd");
return NT_STATUS_ACCESS_DENIED;
}
- creds = netlogon_creds_server_init(mem_ctx,
+ creds = netlogon_creds_server_init(mem_ctx,
r->in.account_name,
r->in.computer_name,
r->in.secure_channel_type,
- &pipe_state->client_challenge,
- &pipe_state->server_challenge,
+ &pipe_state->client_challenge,
+ &pipe_state->server_challenge,
mach_pwd,
r->in.credentials,
r->out.return_credentials,
*r->in.negotiate_flags);
-
+
if (!creds) {
return NT_STATUS_ACCESS_DENIED;
}
creds->sid = samdb_result_dom_sid(creds, msgs[0], "objectSid");
- schannel_ldb = schannel_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
- if (!schannel_ldb) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- nt_status = schannel_store_session_key(schannel_ldb, mem_ctx, creds);
- talloc_free(schannel_ldb);
+ nt_status = schannel_save_creds_state(mem_ctx,
+ lpcfg_private_dir(dce_call->conn->dce_ctx->lp_ctx),
+ creds);
return nt_status;
}
-
+
static NTSTATUS dcesrv_netr_ServerAuthenticate(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_ServerAuthenticate *r)
{
struct netr_ServerAuthenticate3 a;
uint32_t rid;
- /* TODO:
+ /* TODO:
* negotiate_flags is used as an [in] parameter
* so it need to be initialised.
*
r3.in.negotiate_flags = r->in.negotiate_flags;
r3.out.negotiate_flags = r->out.negotiate_flags;
r3.out.rid = &rid;
-
+
return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3);
}
/*
- Validate an incoming authenticator against the credentials for the remote machine.
+ * NOTE: The following functions are nearly identical to the ones available in
+ * source3/rpc_server/srv_nelog_nt.c
+ * The reason we keep 2 copies is that they use different structures to
+ * represent the auth_info and the decrpc pipes.
+ */
- The credentials are (re)read and from the schannel database, and
- written back after the caclulations are performed.
+/*
+ * If schannel is required for this call test that it actually is available.
+ */
+static NTSTATUS schannel_check_required(struct dcerpc_auth *auth_info,
+ const char *computer_name,
+ bool integrity, bool privacy)
+{
- The creds_out parameter (if not NULL) returns the credentials, if
- the caller needs some of that information.
+ if (auth_info && auth_info->auth_type == DCERPC_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;
+}
-*/
static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call,
- TALLOC_CTX *mem_ctx,
+ TALLOC_CTX *mem_ctx,
const char *computer_name,
struct netr_Authenticator *received_authenticator,
struct netr_Authenticator *return_authenticator,
- struct netlogon_creds_CredentialState **creds_out)
+ struct netlogon_creds_CredentialState **creds_out)
{
NTSTATUS nt_status;
- struct ldb_context *ldb;
- bool schannel_global_required = false; /* Should be lp_schannel_server() == true */
- bool schannel_in_use = dce_call->conn->auth_state.auth_info
- && dce_call->conn->auth_state.auth_info->auth_type == DCERPC_AUTH_TYPE_SCHANNEL
- && (dce_call->conn->auth_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY
- || dce_call->conn->auth_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_PRIVACY);
-
- ldb = schannel_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
- if (!ldb) {
- return NT_STATUS_ACCESS_DENIED;
+ struct dcerpc_auth *auth_info = dce_call->conn->auth_state.auth_info;
+ bool schannel_global_required = false; /* Should be lpcfg_schannel_server() == true */
+
+ if (schannel_global_required) {
+ nt_status = schannel_check_required(auth_info,
+ computer_name,
+ true, false);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
}
- nt_status = schannel_creds_server_step_check(ldb, mem_ctx,
- computer_name,
- schannel_global_required,
- schannel_in_use,
- received_authenticator,
- return_authenticator, creds_out);
- talloc_free(ldb);
+
+ nt_status = schannel_check_creds_state(mem_ctx,
+ lpcfg_private_dir(dce_call->conn->dce_ctx->lp_ctx),
+ computer_name,
+ received_authenticator,
+ return_authenticator,
+ creds_out);
return nt_status;
}
-/*
+/*
Change the machine account password for the currently connected
client. Supplies only the NT#.
*/
NTSTATUS nt_status;
nt_status = dcesrv_netr_creds_server_step_check(dce_call,
- mem_ctx,
- r->in.computer_name,
+ mem_ctx,
+ r->in.computer_name,
r->in.credential, r->out.return_authenticator,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
netlogon_creds_des_decrypt(creds, r->in.new_password);
/* Using the sid for the account as the key, set the password */
- nt_status = samdb_set_password_sid(sam_ctx, mem_ctx,
+ nt_status = samdb_set_password_sid(sam_ctx, mem_ctx,
creds->sid,
NULL, /* Don't have plaintext */
NULL, r->in.new_password,
return nt_status;
}
-/*
+/*
Change the machine account password for the currently connected
client. Supplies new plaintext.
*/
struct samr_CryptPassword password_buf;
nt_status = dcesrv_netr_creds_server_step_check(dce_call,
- mem_ctx,
- r->in.computer_name,
+ mem_ctx,
+ r->in.computer_name,
r->in.credential, r->out.return_authenticator,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
DEBUG(3,("samr: failed to decode password buffer\n"));
return NT_STATUS_WRONG_PASSWORD;
}
-
+
/* Using the sid for the account as the key, set the password */
nt_status = samdb_set_password_sid(sam_ctx, mem_ctx,
creds->sid,
}
-/*
- netr_LogonUasLogon
+/*
+ netr_LogonUasLogon
*/
static WERROR dcesrv_netr_LogonUasLogon(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonUasLogon *r)
}
-/*
- netr_LogonUasLogoff
+/*
+ netr_LogonUasLogoff
*/
static WERROR dcesrv_netr_LogonUasLogoff(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonUasLogoff *r)
}
-/*
+/*
netr_LogonSamLogon_base
This version of the function allows other wrappers to say 'do not check the credentials'
struct netr_SamInfo2 *sam2;
struct netr_SamInfo3 *sam3;
struct netr_SamInfo6 *sam6;
-
- user_info = talloc(mem_ctx, struct auth_usersupplied_info);
- NT_STATUS_HAVE_NO_MEMORY(user_info);
- user_info->flags = 0;
- user_info->mapped_state = false;
- user_info->remote_host = NULL;
+ user_info = talloc_zero(mem_ctx, struct auth_usersupplied_info);
+ NT_STATUS_HAVE_NO_MEMORY(user_info);
switch (r->in.logon_level) {
case NetlogonInteractiveInformation:
case NetlogonInteractiveTransitiveInformation:
case NetlogonServiceTransitiveInformation:
if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
- netlogon_creds_arcfour_crypt(creds,
+ netlogon_creds_arcfour_crypt(creds,
r->in.logon->password->lmpassword.hash,
sizeof(r->in.logon->password->lmpassword.hash));
- netlogon_creds_arcfour_crypt(creds,
+ netlogon_creds_arcfour_crypt(creds,
r->in.logon->password->ntpassword.hash,
sizeof(r->in.logon->password->ntpassword.hash));
} else {
}
/* TODO: we need to deny anonymous access here */
- nt_status = auth_context_create(mem_ctx,
+ nt_status = auth_context_create(mem_ctx,
dce_call->event_ctx, dce_call->msg_ctx,
dce_call->conn->dce_ctx->lp_ctx,
&auth_context);
user_info->client.account_name = r->in.logon->password->identity_info.account_name.string;
user_info->client.domain_name = r->in.logon->password->identity_info.domain_name.string;
user_info->workstation_name = r->in.logon->password->identity_info.workstation.string;
-
+
user_info->flags |= USER_INFO_INTERACTIVE_LOGON;
user_info->password_state = AUTH_PASSWORD_HASH;
case NetlogonNetworkTransitiveInformation:
/* TODO: we need to deny anonymous access here */
- nt_status = auth_context_create(mem_ctx,
+ nt_status = auth_context_create(mem_ctx,
dce_call->event_ctx, dce_call->msg_ctx,
dce_call->conn->dce_ctx->lp_ctx,
&auth_context);
user_info->client.account_name = r->in.logon->network->identity_info.account_name.string;
user_info->client.domain_name = r->in.logon->network->identity_info.domain_name.string;
user_info->workstation_name = r->in.logon->network->identity_info.workstation.string;
-
+
user_info->password_state = AUTH_PASSWORD_RESPONSE;
user_info->password.response.lanman = data_blob_talloc(mem_ctx, r->in.logon->network->lm.data, r->in.logon->network->lm.length);
user_info->password.response.nt = data_blob_talloc(mem_ctx, r->in.logon->network->nt.data, r->in.logon->network->nt.length);
-
+
break;
-
+
case NetlogonGenericInformation:
{
if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
- netlogon_creds_arcfour_crypt(creds,
+ netlogon_creds_arcfour_crypt(creds,
r->in.logon->generic->data, r->in.logon->generic->length);
} else {
/* Using DES to verify kerberos tickets makes no sense */
struct netr_GenericInfo2 *generic = talloc_zero(mem_ctx, struct netr_GenericInfo2);
NT_STATUS_HAVE_NO_MEMORY(generic);
*r->out.authoritative = 1;
-
+
/* TODO: Describe and deal with these flags */
*r->out.flags = 0;
r->out.validation->generic = generic;
-
+
kdc = irpc_servers_byname(dce_call->msg_ctx, mem_ctx, "kdc_server");
if ((kdc == NULL) || (kdc[0].id == 0)) {
return NT_STATUS_NO_LOGON_SERVERS;
}
-
- check.in.generic_request =
+
+ check.in.generic_request =
data_blob_const(r->in.logon->generic->data,
r->in.logon->generic->length);
-
+
status = irpc_call(dce_call->msg_ctx, kdc[0],
&ndr_table_irpc, NDR_KDC_CHECK_GENERIC_KERBEROS,
&check, mem_ctx);
default:
return NT_STATUS_INVALID_PARAMETER;
}
-
- nt_status = auth_check_password(auth_context, mem_ctx, user_info, &server_info);
- NT_STATUS_NOT_OK_RETURN(nt_status);
- nt_status = auth_convert_server_info_sambaseinfo(mem_ctx, server_info, &sam);
+ nt_status = auth_check_password(auth_context, mem_ctx, user_info, &server_info);
NT_STATUS_NOT_OK_RETURN(nt_status);
- /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
- /* It appears that level 6 is not individually encrypted */
- if ((r->in.validation_level != 6) &&
- memcmp(sam->key.key, zeros, sizeof(sam->key.key)) != 0) {
- /* This key is sent unencrypted without the ARCFOUR flag set */
- if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
- netlogon_creds_arcfour_crypt(creds,
- sam->key.key,
- sizeof(sam->key.key));
- }
- }
-
- /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
- /* It appears that level 6 is not individually encrypted */
- if ((r->in.validation_level != 6) &&
- memcmp(sam->LMSessKey.key, zeros, sizeof(sam->LMSessKey.key)) != 0) {
- if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
- netlogon_creds_arcfour_crypt(creds,
- sam->LMSessKey.key,
- sizeof(sam->LMSessKey.key));
- } else {
- netlogon_creds_des_encrypt_LMKey(creds,
- &sam->LMSessKey);
- }
- }
-
switch (r->in.validation_level) {
case 2:
+ nt_status = auth_convert_server_info_sambaseinfo(mem_ctx, server_info, &sam);
+ NT_STATUS_NOT_OK_RETURN(nt_status);
+
sam2 = talloc_zero(mem_ctx, struct netr_SamInfo2);
NT_STATUS_HAVE_NO_MEMORY(sam2);
sam2->base = *sam;
+
+ /* And put into the talloc tree */
+ talloc_steal(sam2, sam);
r->out.validation->sam2 = sam2;
+
+ sam = &sam2->base;
break;
case 3:
- sam3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
- NT_STATUS_HAVE_NO_MEMORY(sam3);
- sam3->base = *sam;
+ nt_status = auth_convert_server_info_saminfo3(mem_ctx,
+ server_info,
+ &sam3);
+ NT_STATUS_NOT_OK_RETURN(nt_status);
+
r->out.validation->sam3 = sam3;
+
+ sam = &sam3->base;
break;
case 6:
+ nt_status = auth_convert_server_info_saminfo3(mem_ctx,
+ server_info,
+ &sam3);
+ NT_STATUS_NOT_OK_RETURN(nt_status);
+
sam6 = talloc_zero(mem_ctx, struct netr_SamInfo6);
NT_STATUS_HAVE_NO_MEMORY(sam6);
- sam6->base = *sam;
- sam6->forest.string = lp_realm(dce_call->conn->dce_ctx->lp_ctx);
- sam6->principle.string = talloc_asprintf(mem_ctx, "%s@%s",
- sam->account_name.string, sam6->forest.string);
+ sam6->base = sam3->base;
+ sam = &sam6->base;
+ sam6->sidcount = sam3->sidcount;
+ sam6->sids = sam3->sids;
+
+ sam6->dns_domainname.string = lpcfg_dnsdomain(dce_call->conn->dce_ctx->lp_ctx);
+ sam6->principle.string = talloc_asprintf(mem_ctx, "%s@%s",
+ sam->account_name.string, sam6->dns_domainname.string);
NT_STATUS_HAVE_NO_MEMORY(sam6->principle.string);
+ /* And put into the talloc tree */
+ talloc_steal(sam6, sam3);
+
r->out.validation->sam6 = sam6;
break;
break;
}
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ /* It appears that level 6 is not individually encrypted */
+ if ((r->in.validation_level != 6) &&
+ memcmp(sam->key.key, zeros, sizeof(sam->key.key)) != 0) {
+ /* This key is sent unencrypted without the ARCFOUR flag set */
+ if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ netlogon_creds_arcfour_crypt(creds,
+ sam->key.key,
+ sizeof(sam->key.key));
+ }
+ }
+
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ /* It appears that level 6 is not individually encrypted */
+ if ((r->in.validation_level != 6) &&
+ memcmp(sam->LMSessKey.key, zeros, sizeof(sam->LMSessKey.key)) != 0) {
+ if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ netlogon_creds_arcfour_crypt(creds,
+ sam->LMSessKey.key,
+ sizeof(sam->LMSessKey.key));
+ } else {
+ netlogon_creds_des_encrypt_LMKey(creds,
+ &sam->LMSessKey);
+ }
+ }
+
*r->out.authoritative = 1;
/* TODO: Describe and deal with these flags */
}
static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_LogonSamLogonEx *r)
+ struct netr_LogonSamLogonEx *r)
{
NTSTATUS nt_status;
struct netlogon_creds_CredentialState *creds;
- struct ldb_context *ldb = schannel_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
- if (!ldb) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- nt_status = schannel_fetch_session_key(ldb, mem_ctx, r->in.computer_name, &creds);
+
+ nt_status = schannel_get_creds_state(mem_ctx,
+ lpcfg_private_dir(dce_call->conn->dce_ctx->lp_ctx),
+ r->in.computer_name, &creds);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
return dcesrv_netr_LogonSamLogon_base(dce_call, mem_ctx, r, creds);
}
-/*
+/*
netr_LogonSamLogonWithFlags
*/
NT_STATUS_HAVE_NO_MEMORY(return_authenticator);
nt_status = dcesrv_netr_creds_server_step_check(dce_call,
- mem_ctx,
- r->in.computer_name,
+ mem_ctx,
+ r->in.computer_name,
r->in.credential, return_authenticator,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
return nt_status;
}
-/*
+/*
netr_LogonSamLogon
*/
static NTSTATUS dcesrv_netr_LogonSamLogon(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
}
-/*
- netr_LogonSamLogoff
+/*
+ netr_LogonSamLogoff
*/
static NTSTATUS dcesrv_netr_LogonSamLogoff(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonSamLogoff *r)
-/*
- netr_DatabaseDeltas
+/*
+ netr_DatabaseDeltas
*/
static NTSTATUS dcesrv_netr_DatabaseDeltas(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DatabaseDeltas *r)
}
-/*
- netr_DatabaseSync2
+/*
+ netr_DatabaseSync2
*/
static NTSTATUS dcesrv_netr_DatabaseSync2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DatabaseSync2 *r)
}
-/*
- netr_DatabaseSync
+/*
+ netr_DatabaseSync
*/
static NTSTATUS dcesrv_netr_DatabaseSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DatabaseSync *r)
}
-/*
- netr_AccountDeltas
+/*
+ netr_AccountDeltas
*/
static NTSTATUS dcesrv_netr_AccountDeltas(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_AccountDeltas *r)
}
-/*
- netr_AccountSync
+/*
+ netr_AccountSync
*/
static NTSTATUS dcesrv_netr_AccountSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_AccountSync *r)
}
-/*
- netr_GetDcName
+/*
+ netr_GetDcName
*/
static WERROR dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetDcName *r)
{
const char * const attrs[] = { NULL };
- void *sam_ctx;
+ struct ldb_context *sam_ctx;
struct ldb_message **res;
struct ldb_dn *domain_dn;
int ret;
dce_call->conn->dce_ctx->lp_ctx,
dce_call->conn->auth_state.session_info);
if (sam_ctx == NULL) {
- return WERR_DS_SERVICE_UNAVAILABLE;
+ return WERR_DS_UNAVAILABLE;
}
- domain_dn = samdb_domain_to_dn((struct ldb_context *)sam_ctx, mem_ctx,
+ domain_dn = samdb_domain_to_dn(sam_ctx, mem_ctx,
r->in.domainname);
if (domain_dn == NULL) {
- return WERR_DS_SERVICE_UNAVAILABLE;
+ return WERR_DS_UNAVAILABLE;
}
- ret = gendb_search_dn((struct ldb_context *)sam_ctx, mem_ctx,
+ ret = gendb_search_dn(sam_ctx, mem_ctx,
domain_dn, &res, attrs);
if (ret != 1) {
return WERR_NO_SUCH_DOMAIN;
* - check all r->in.* parameters (server_unc is ignored by w2k3!)
*/
dcname = talloc_asprintf(mem_ctx, "\\\\%s",
- lp_netbios_name(dce_call->conn->dce_ctx->lp_ctx));
+ lpcfg_netbios_name(dce_call->conn->dce_ctx->lp_ctx));
W_ERROR_HAVE_NO_MEMORY(dcname);
*r->out.dcname = dcname;
}
-/*
- netr_LogonControl2Ex
+/*
+ netr_LogonControl2Ex
*/
static WERROR dcesrv_netr_LogonControl2Ex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonControl2Ex *r)
}
-/*
- netr_LogonControl
+/*
+ netr_LogonControl
*/
static WERROR dcesrv_netr_LogonControl(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonControl *r)
}
-/*
- netr_LogonControl2
+/*
+ netr_LogonControl2
*/
static WERROR dcesrv_netr_LogonControl2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonControl2 *r)
return werr;
}
+static WERROR fill_trusted_domains_array(TALLOC_CTX *mem_ctx,
+ struct ldb_context *sam_ctx,
+ struct netr_DomainTrustList *trusts,
+ uint32_t trust_flags);
-/*
- netr_GetAnyDCName
+/*
+ netr_GetAnyDCName
*/
static WERROR dcesrv_netr_GetAnyDCName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetAnyDCName *r)
{
- struct netr_GetDcName r2;
+ struct netr_DomainTrustList *trusts;
+ struct ldb_context *sam_ctx;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ uint32_t i;
WERROR werr;
- ZERO_STRUCT(r2);
+ *r->out.dcname = NULL;
- r2.in.logon_server = r->in.logon_server;
- r2.in.domainname = r->in.domainname;
- r2.out.dcname = r->out.dcname;
+ if ((r->in.domainname == NULL) || (r->in.domainname[0] == '\0')) {
+ /* if the domainname parameter wasn't set assume our domain */
+ r->in.domainname = lpcfg_workgroup(lp_ctx);
+ }
- werr = dcesrv_netr_GetDcName(dce_call, mem_ctx, &r2);
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
+ if (sam_ctx == NULL) {
+ return WERR_DS_UNAVAILABLE;
+ }
- return werr;
+ if (strcasecmp(r->in.domainname, lpcfg_workgroup(lp_ctx)) == 0) {
+ /* well we asked for a DC of our own domain */
+ if (samdb_is_pdc(sam_ctx)) {
+ /* we are the PDC of the specified domain */
+ return WERR_NO_SUCH_DOMAIN;
+ }
+
+ *r->out.dcname = talloc_asprintf(mem_ctx, "\\%s",
+ lpcfg_netbios_name(lp_ctx));
+ W_ERROR_HAVE_NO_MEMORY(*r->out.dcname);
+
+ return WERR_OK;
+ }
+
+ /* Okay, now we have to consider the trusted domains */
+
+ trusts = talloc_zero(mem_ctx, struct netr_DomainTrustList);
+ W_ERROR_HAVE_NO_MEMORY(trusts);
+
+ trusts->count = 0;
+
+ werr = fill_trusted_domains_array(mem_ctx, sam_ctx, trusts,
+ NETR_TRUST_FLAG_INBOUND
+ | NETR_TRUST_FLAG_OUTBOUND);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ for (i = 0; i < trusts->count; i++) {
+ if (strcasecmp(r->in.domainname, trusts->array[i].netbios_name) == 0) {
+ /* FIXME: Here we need to find a DC for the specified
+ * trusted domain. */
+
+ /* return WERR_OK; */
+ return WERR_NO_SUCH_DOMAIN;
+ }
+ }
+
+ return WERR_NO_SUCH_DOMAIN;
}
-/*
- netr_DatabaseRedo
+/*
+ netr_DatabaseRedo
*/
static NTSTATUS dcesrv_netr_DatabaseRedo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DatabaseRedo *r)
}
-/*
- netr_NetrEnumerateTurstedDomains
+/*
+ netr_NetrEnumerateTrustedDomains
*/
-static WERROR dcesrv_netr_NetrEnumerateTrustedDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static NTSTATUS dcesrv_netr_NetrEnumerateTrustedDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NetrEnumerateTrustedDomains *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
-/*
+/*
netr_LogonGetCapabilities
*/
static NTSTATUS dcesrv_netr_LogonGetCapabilities(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
}
-/*
- netr_NETRLOGONSETSERVICEBITS
+/*
+ netr_NETRLOGONSETSERVICEBITS
*/
static WERROR dcesrv_netr_NETRLOGONSETSERVICEBITS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NETRLOGONSETSERVICEBITS *r)
}
-/*
- netr_NETRLOGONCOMPUTESERVERDIGEST
+/*
+ netr_NETRLOGONCOMPUTESERVERDIGEST
*/
static WERROR dcesrv_netr_NETRLOGONCOMPUTESERVERDIGEST(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NETRLOGONCOMPUTESERVERDIGEST *r)
}
-/*
- netr_NETRLOGONCOMPUTECLIENTDIGEST
+/*
+ netr_NETRLOGONCOMPUTECLIENTDIGEST
*/
static WERROR dcesrv_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r)
-/*
+/*
netr_DsRGetSiteName
*/
static WERROR dcesrv_netr_DsRGetSiteName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsRGetSiteName *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct ldb_context *sam_ctx;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
+ if (sam_ctx == NULL) {
+ return WERR_DS_UNAVAILABLE;
+ }
+
+ *r->out.site = samdb_server_site_name(sam_ctx, mem_ctx);
+ W_ERROR_HAVE_NO_MEMORY(*r->out.site);
+
+ return WERR_OK;
}
/*
- fill in a netr_DomainTrustInfo from a ldb search result
+ fill in a netr_OneDomainInfo from a ldb search result
*/
-static NTSTATUS fill_domain_trust_info(TALLOC_CTX *mem_ctx,
- struct loadparm_context *lp_ctx,
- struct ldb_context *sam_ctx,
- struct ldb_message *res,
- struct netr_DomainTrustInfo *info,
- bool is_local, bool is_trust_list)
+static NTSTATUS fill_one_domain_info(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct ldb_context *sam_ctx,
+ struct ldb_message *res,
+ struct netr_OneDomainInfo *info,
+ bool is_local, bool is_trust_list)
{
ZERO_STRUCTP(info);
- info->trust_extension.info = talloc_zero(mem_ctx, struct netr_trust_extension);
- info->trust_extension.length = 16;
- info->trust_extension.info->flags =
- NETR_TRUST_FLAG_TREEROOT |
- NETR_TRUST_FLAG_IN_FOREST |
- NETR_TRUST_FLAG_PRIMARY;
-
- info->trust_extension.info->parent_index = 0; /* should be index into array
- of parent */
- info->trust_extension.info->trust_type = LSA_TRUST_TYPE_UPLEVEL; /* should be based on ldb search for trusts */
- info->trust_extension.info->trust_attributes = LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE; /* needs to be based on ldb search */
+ if (is_trust_list) {
+ /* w2k8 only fills this on trusted domains */
+ info->trust_extension.info = talloc_zero(mem_ctx, struct netr_trust_extension);
+ info->trust_extension.length = 16;
+ info->trust_extension.info->flags =
+ NETR_TRUST_FLAG_TREEROOT |
+ NETR_TRUST_FLAG_IN_FOREST |
+ NETR_TRUST_FLAG_PRIMARY |
+ NETR_TRUST_FLAG_NATIVE;
+
+ info->trust_extension.info->parent_index = 0; /* should be index into array
+ of parent */
+ info->trust_extension.info->trust_type = LSA_TRUST_TYPE_UPLEVEL; /* should be based on ldb search for trusts */
+ info->trust_extension.info->trust_attributes = 0; /* TODO: base on ldb search? */
+ }
if (is_trust_list) {
/* MS-NRPC 3.5.4.3.9 - must be set to NULL for trust list */
- info->forest.string = NULL;
+ info->dns_forestname.string = NULL;
} else {
- char *p;
- /* TODO: we need a common function for pulling the forest */
- info->forest.string = ldb_dn_canonical_string(info, ldb_get_root_basedn(sam_ctx));
- if (!info->forest.string) {
- return NT_STATUS_NO_SUCH_DOMAIN;
- }
- p = strchr(info->forest.string, '/');
- if (p) {
- *p = '\0';
- }
+ info->dns_forestname.string = samdb_forest_name(sam_ctx, mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(info->dns_forestname.string);
+ info->dns_forestname.string = talloc_asprintf(mem_ctx, "%s.", info->dns_forestname.string);
+ NT_STATUS_HAVE_NO_MEMORY(info->dns_forestname.string);
}
if (is_local) {
- info->domainname.string = lp_sam_name(lp_ctx);
- info->fulldomainname.string = lp_realm(lp_ctx);
- info->guid = samdb_result_guid(res, "objectGUID");
- info->sid = samdb_result_dom_sid(mem_ctx, res, "objectSid");
+ info->domainname.string = lpcfg_workgroup(lp_ctx);
+ info->dns_domainname.string = lpcfg_dnsdomain(lp_ctx);
+ info->domain_guid = samdb_result_guid(res, "objectGUID");
+ info->domain_sid = samdb_result_dom_sid(mem_ctx, res, "objectSid");
} else {
info->domainname.string = samdb_result_string(res, "flatName", NULL);
- info->fulldomainname.string = samdb_result_string(res, "trustPartner", NULL);
- info->guid = samdb_result_guid(res, "objectGUID");
- info->sid = samdb_result_dom_sid(mem_ctx, res, "securityIdentifier");
+ info->dns_domainname.string = samdb_result_string(res, "trustPartner", NULL);
+ info->domain_guid = samdb_result_guid(res, "objectGUID");
+ info->domain_sid = samdb_result_dom_sid(mem_ctx, res, "securityIdentifier");
+ }
+ if (!is_trust_list) {
+ info->dns_domainname.string = talloc_asprintf(mem_ctx, "%s.", info->dns_domainname.string);
}
return NT_STATUS_OK;
}
-/*
+/*
netr_LogonGetDomainInfo
this is called as part of the ADS domain logon procedure.
It has an important role in convaying details about the client, such
as Operating System, Version, Service Pack etc.
*/
-static NTSTATUS dcesrv_netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_LogonGetDomainInfo *r)
+static NTSTATUS dcesrv_netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx, struct netr_LogonGetDomainInfo *r)
{
- const char * const attrs[] = { "objectSid",
- "objectGUID", "flatName", "securityIdentifier",
- "trustPartner", NULL };
+ struct netlogon_creds_CredentialState *creds;
+ const char * const attrs[] = { "objectSid", "objectGUID", "flatName",
+ "securityIdentifier", "trustPartner", NULL };
+ const char * const attrs2[] = { "dNSHostName",
+ "msDS-SupportedEncryptionTypes", NULL };
+ const char *temp_str, *temp_str2;
+ const char *old_dns_hostname;
struct ldb_context *sam_ctx;
- struct ldb_message **res1, **res2;
- struct netr_DomainInfo1 *info1;
- int ret1, ret2, i;
+ struct ldb_message **res1, **res2, **res3, *new_msg;
+ struct ldb_dn *workstation_dn;
+ struct netr_DomainInformation *domain_info;
+ struct netr_LsaPolicyInformation *lsa_policy_info;
+ struct netr_OsVersionInfoEx *os_version;
+ uint32_t default_supported_enc_types = 0xFFFFFFFF;
+ bool update_dns_hostname = true;
+ int ret, ret3, i;
NTSTATUS status;
- const char *local_domain;
-
status = dcesrv_netr_creds_server_step_check(dce_call,
- mem_ctx,
- r->in.computer_name,
- r->in.credential,
+ mem_ctx,
+ r->in.computer_name,
+ r->in.credential,
r->out.return_authenticator,
- NULL);
+ &creds);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,(__location__ " Bad credentials - error\n"));
}
NT_STATUS_NOT_OK_RETURN(status);
- sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
+ system_session(dce_call->conn->dce_ctx->lp_ctx));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
- /* we need to do two searches. The first will pull our primary
- domain and the second will pull any trusted domains. Our
- primary domain is also a "trusted" domain, so we need to
- put the primary domain into the lists of returned trusts as
- well */
- ret1 = gendb_search_dn(sam_ctx, mem_ctx, samdb_base_dn(sam_ctx), &res1, attrs);
- if (ret1 != 1) {
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
+ switch (r->in.level) {
+ case 1: /* Domain information */
- /* try and find the domain */
- local_domain = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
+ if (r->in.query->workstation_info == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
- ret2 = gendb_search(sam_ctx, mem_ctx, NULL, &res2, attrs, "(objectClass=trustedDomain)");
- if (ret2 == -1) {
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
+ /*
+ * Checks that the computer name parameter without possible "$"
+ * matches as prefix with the DNS hostname in the workstation
+ * info structure.
+ */
+ temp_str = talloc_strndup(mem_ctx,
+ r->in.computer_name,
+ strcspn(r->in.computer_name, "$"));
+ NT_STATUS_HAVE_NO_MEMORY(temp_str);
+ temp_str2 = talloc_strndup(mem_ctx,
+ r->in.query->workstation_info->dns_hostname,
+ strcspn(r->in.query->workstation_info->dns_hostname, "."));
+ NT_STATUS_HAVE_NO_MEMORY(temp_str2);
+ if (strcasecmp(temp_str, temp_str2) != 0) {
+ update_dns_hostname = false;
+ }
- info1 = talloc(mem_ctx, struct netr_DomainInfo1);
- NT_STATUS_HAVE_NO_MEMORY(info1);
+ /* Prepare the workstation DN */
+ workstation_dn = ldb_dn_new_fmt(mem_ctx, sam_ctx, "<SID=%s>",
+ dom_sid_string(mem_ctx, creds->sid));
+ NT_STATUS_HAVE_NO_MEMORY(workstation_dn);
- ZERO_STRUCTP(info1);
+ /* Lookup for attributes in workstation object */
+ ret = gendb_search_dn(sam_ctx, mem_ctx, workstation_dn,
+ &res1, attrs2);
+ if (ret != 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
- info1->num_trusts = ret2 + 1;
- info1->trusts = talloc_array(mem_ctx, struct netr_DomainTrustInfo,
- info1->num_trusts);
- NT_STATUS_HAVE_NO_MEMORY(info1->trusts);
+ /* Gets the old DNS hostname */
+ old_dns_hostname = samdb_result_string(res1[0], "dNSHostName",
+ NULL);
+
+ /*
+ * Updates the DNS hostname when the client wishes that the
+ * server should handle this for him
+ * ("NETR_WS_FLAG_HANDLES_SPN_UPDATE" not set). And this is
+ * obviously only checked when we do already have a
+ * "dNSHostName".
+ * See MS-NRPC section 3.5.4.3.9
+ */
+ if ((old_dns_hostname != NULL) &&
+ (r->in.query->workstation_info->workstation_flags
+ & NETR_WS_FLAG_HANDLES_SPN_UPDATE) != 0) {
+ update_dns_hostname = false;
+ }
- status = fill_domain_trust_info(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, sam_ctx, res1[0], &info1->domaininfo,
- true, false);
- NT_STATUS_NOT_OK_RETURN(status);
+ /* Gets host informations and put them into our directory */
+
+ new_msg = ldb_msg_new(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(new_msg);
+
+ new_msg->dn = workstation_dn;
+
+ /* Sets the OS name */
+ samdb_msg_set_string(sam_ctx, mem_ctx, new_msg,
+ "operatingSystem",
+ r->in.query->workstation_info->os_name.string);
+
+ /*
+ * Sets informations from "os_version". On an empty structure
+ * the values are cleared.
+ */
+ if (r->in.query->workstation_info->os_version.os != NULL) {
+ os_version = &r->in.query->workstation_info->os_version.os->os;
+
+ samdb_msg_set_string(sam_ctx, mem_ctx, new_msg,
+ "operatingSystemServicePack",
+ os_version->CSDVersion);
+
+ samdb_msg_set_string(sam_ctx, mem_ctx, new_msg,
+ "operatingSystemVersion",
+ talloc_asprintf(mem_ctx, "%d.%d (%d)",
+ os_version->MajorVersion,
+ os_version->MinorVersion,
+ os_version->BuildNumber
+ )
+ );
+ } else {
+ samdb_msg_add_delete(sam_ctx, mem_ctx, new_msg,
+ "operatingSystemServicePack");
+
+ samdb_msg_add_delete(sam_ctx, mem_ctx, new_msg,
+ "operatingSystemVersion");
+ }
- for (i=0;i<ret2;i++) {
- status = fill_domain_trust_info(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, sam_ctx, res2[i], &info1->trusts[i],
- false, true);
+ /*
+ * If the boolean "update_dns_hostname" remained true, then we
+ * are fine to start the update.
+ */
+ if (update_dns_hostname) {
+ samdb_msg_set_string(sam_ctx, mem_ctx, new_msg,
+ "dNSHostname",
+ r->in.query->workstation_info->dns_hostname);
+
+ samdb_msg_add_string(sam_ctx, mem_ctx, new_msg,
+ "servicePrincipalName",
+ talloc_asprintf(mem_ctx, "HOST/%s",
+ r->in.computer_name)
+ );
+ samdb_msg_add_string(sam_ctx, mem_ctx, new_msg,
+ "servicePrincipalName",
+ talloc_asprintf(mem_ctx, "HOST/%s",
+ r->in.query->workstation_info->dns_hostname)
+ );
+ }
+
+ if (dsdb_replace(sam_ctx, new_msg, 0) != LDB_SUCCESS) {
+ DEBUG(3,("Impossible to update samdb: %s\n",
+ ldb_errstring(sam_ctx)));
+ }
+
+ talloc_free(new_msg);
+
+ /* Writes back the domain information */
+
+ /* We need to do two searches. The first will pull our primary
+ domain and the second will pull any trusted domains. Our
+ primary domain is also a "trusted" domain, so we need to
+ put the primary domain into the lists of returned trusts as
+ well. */
+ ret = gendb_search_dn(sam_ctx, mem_ctx, ldb_get_default_basedn(sam_ctx),
+ &res2, attrs);
+ if (ret != 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ ret3 = gendb_search(sam_ctx, mem_ctx, NULL, &res3, attrs,
+ "(objectClass=trustedDomain)");
+ if (ret3 == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ domain_info = talloc(mem_ctx, struct netr_DomainInformation);
+ NT_STATUS_HAVE_NO_MEMORY(domain_info);
+
+ ZERO_STRUCTP(domain_info);
+
+ /* Informations about the local and trusted domains */
+
+ status = fill_one_domain_info(mem_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
+ sam_ctx, res2[0], &domain_info->primary_domain,
+ true, false);
NT_STATUS_NOT_OK_RETURN(status);
- }
- status = fill_domain_trust_info(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, sam_ctx, res1[0], &info1->trusts[i],
- true, true);
- NT_STATUS_NOT_OK_RETURN(status);
+ domain_info->trusted_domain_count = ret3 + 1;
+ domain_info->trusted_domains = talloc_array(mem_ctx,
+ struct netr_OneDomainInfo,
+ domain_info->trusted_domain_count);
+ NT_STATUS_HAVE_NO_MEMORY(domain_info->trusted_domains);
+
+ for (i=0;i<ret3;i++) {
+ status = fill_one_domain_info(mem_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
+ sam_ctx, res3[i],
+ &domain_info->trusted_domains[i],
+ false, true);
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ status = fill_one_domain_info(mem_ctx,
+ dce_call->conn->dce_ctx->lp_ctx, sam_ctx, res2[0],
+ &domain_info->trusted_domains[i], true, true);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ /* Sets the supported encryption types */
+ domain_info->supported_enc_types = samdb_result_uint(res1[0],
+ "msDS-SupportedEncryptionTypes",
+ default_supported_enc_types);
+
+ /* Other host domain informations */
+
+ lsa_policy_info = talloc(mem_ctx,
+ struct netr_LsaPolicyInformation);
+ NT_STATUS_HAVE_NO_MEMORY(lsa_policy_info);
+ ZERO_STRUCTP(lsa_policy_info);
+
+ domain_info->lsa_policy = *lsa_policy_info;
- info1->dns_hostname.string = lp_realm(dce_call->conn->dce_ctx->lp_ctx);
- info1->workstation_flags =
- NETR_WS_FLAG_HANDLES_INBOUND_TRUSTS | NETR_WS_FLAG_HANDLES_SPN_UPDATE;
- info1->supported_enc_types = 0; /* w2008 gives this 0 */
+ /* The DNS hostname is only returned back when there is a chance
+ * for a change. */
+ if ((r->in.query->workstation_info->workstation_flags
+ & NETR_WS_FLAG_HANDLES_SPN_UPDATE) != 0) {
+ domain_info->dns_hostname.string = old_dns_hostname;
+ } else {
+ domain_info->dns_hostname.string = NULL;
+ }
- r->out.info->info1 = info1;
+ domain_info->workstation_flags =
+ r->in.query->workstation_info->workstation_flags;
+
+ r->out.info->domain_info = domain_info;
+ break;
+ case 2: /* LSA policy information - not used at the moment */
+ lsa_policy_info = talloc(mem_ctx,
+ struct netr_LsaPolicyInformation);
+ NT_STATUS_HAVE_NO_MEMORY(lsa_policy_info);
+ ZERO_STRUCTP(lsa_policy_info);
+
+ r->out.info->lsa_policy_info = lsa_policy_info;
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ break;
+ }
return NT_STATUS_OK;
}
}
-/*
- netr_NETRLOGONSENDTOSAM
+/*
+ netr_NETRLOGONSENDTOSAM
*/
static WERROR dcesrv_netr_NETRLOGONSENDTOSAM(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NETRLOGONSENDTOSAM *r)
}
-/*
- netr_DsRAddressToSitenamesW
-*/
-static WERROR dcesrv_netr_DsRAddressToSitenamesW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DsRAddressToSitenamesW *r)
-{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
-}
-
-
-/*
+/*
netr_DsRGetDCNameEx2
*/
-static WERROR dcesrv_netr_DsRGetDCNameEx2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DsRGetDCNameEx2 *r)
+static WERROR dcesrv_netr_DsRGetDCNameEx2(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct netr_DsRGetDCNameEx2 *r)
{
- const char * const attrs[] = { "objectGUID", NULL };
struct ldb_context *sam_ctx;
- struct ldb_message **res;
- struct ldb_dn *domain_dn;
- int ret;
struct netr_DsRGetDCNameInfo *info;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const struct tsocket_address *remote_address;
+ char *addr = NULL;
+ const char *server_site_name;
+ char *guid_str;
+ struct netlogon_samlogon_response response;
+ NTSTATUS status;
ZERO_STRUCTP(r->out.info);
- sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
if (sam_ctx == NULL) {
- return WERR_DS_SERVICE_UNAVAILABLE;
+ return WERR_DS_UNAVAILABLE;
}
- /* Win7-beta will send the domain name in the form the user typed, so we have to cope
- with both the short and long form here */
- if (r->in.domain_name != NULL && !lp_is_my_domain_or_realm(dce_call->conn->dce_ctx->lp_ctx,
- r->in.domain_name)) {
- return WERR_NO_SUCH_DOMAIN;
+ remote_address = dcesrv_connection_get_remote_address(dce_call->conn);
+ if (tsocket_address_is_inet(remote_address, "ip")) {
+ addr = tsocket_address_inet_addr_string(remote_address, mem_ctx);
+ W_ERROR_HAVE_NO_MEMORY(addr);
}
- domain_dn = ldb_get_default_basedn(sam_ctx);
- if (domain_dn == NULL) {
- return WERR_DS_SERVICE_UNAVAILABLE;
+ /* "server_unc" is ignored by w2k3 */
+
+ /* Proof server site parameter "site_name" if it was specified */
+ server_site_name = samdb_server_site_name(sam_ctx, mem_ctx);
+ W_ERROR_HAVE_NO_MEMORY(server_site_name);
+ if ((r->in.site_name != NULL) && (strcasecmp(r->in.site_name,
+ server_site_name) != 0)) {
+ return WERR_NO_SUCH_DOMAIN;
}
- ret = gendb_search_dn(sam_ctx, mem_ctx,
- domain_dn, &res, attrs);
- if (ret != 1) {
+ /* TODO: the flags are ignored for now */
+
+ guid_str = r->in.domain_guid != NULL ?
+ GUID_string(mem_ctx, r->in.domain_guid) : NULL;
+
+ status = fill_netlogon_samlogon_response(sam_ctx, mem_ctx,
+ r->in.domain_name,
+ r->in.domain_name,
+ NULL, guid_str,
+ r->in.client_account,
+ r->in.mask, addr,
+ NETLOGON_NT_VERSION_5EX_WITH_IP,
+ lp_ctx, &response, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
}
info = talloc(mem_ctx, struct netr_DsRGetDCNameInfo);
W_ERROR_HAVE_NO_MEMORY(info);
-
- /* TODO: - return real IP address
- * - check all r->in.* parameters (server_unc is ignored by w2k3!)
- */
- info->dc_unc = talloc_asprintf(mem_ctx, "\\\\%s.%s",
- lp_netbios_name(dce_call->conn->dce_ctx->lp_ctx),
- lp_realm(dce_call->conn->dce_ctx->lp_ctx));
+ info->dc_unc = talloc_asprintf(mem_ctx, "\\\\%s",
+ response.data.nt5_ex.pdc_dns_name);
W_ERROR_HAVE_NO_MEMORY(info->dc_unc);
- info->dc_address = talloc_strdup(mem_ctx, "\\\\0.0.0.0");
+ info->dc_address = talloc_asprintf(mem_ctx, "\\\\%s",
+ response.data.nt5_ex.sockaddr.pdc_ip);
W_ERROR_HAVE_NO_MEMORY(info->dc_address);
- info->dc_address_type = DS_ADDRESS_TYPE_INET;
- info->domain_guid = samdb_result_guid(res[0], "objectGUID");
- info->domain_name = lp_realm(dce_call->conn->dce_ctx->lp_ctx);
- info->forest_name = lp_realm(dce_call->conn->dce_ctx->lp_ctx);
- info->dc_flags = DS_DNS_FOREST |
- DS_DNS_DOMAIN |
- DS_DNS_CONTROLLER |
- DS_SERVER_WRITABLE |
- DS_SERVER_CLOSEST |
- DS_SERVER_TIMESERV |
- DS_SERVER_KDC |
- DS_SERVER_DS |
- DS_SERVER_LDAP |
- DS_SERVER_GC |
- DS_SERVER_PDC;
- info->dc_site_name = talloc_strdup(mem_ctx, "Default-First-Site-Name");
- W_ERROR_HAVE_NO_MEMORY(info->dc_site_name);
- info->client_site_name = talloc_strdup(mem_ctx, "Default-First-Site-Name");
- W_ERROR_HAVE_NO_MEMORY(info->client_site_name);
+ info->dc_address_type = DS_ADDRESS_TYPE_INET; /* TODO: make this dynamic? for ipv6 */
+ info->domain_guid = response.data.nt5_ex.domain_uuid;
+ info->domain_name = response.data.nt5_ex.dns_domain;
+ info->forest_name = response.data.nt5_ex.forest;
+ info->dc_flags = response.data.nt5_ex.server_type;
+ info->dc_site_name = response.data.nt5_ex.server_site;
+ info->client_site_name = response.data.nt5_ex.client_site;
*r->out.info = info;
return WERR_OK;
}
-/*
+/*
netr_DsRGetDCNameEx
*/
static WERROR dcesrv_netr_DsRGetDCNameEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
return werr;
}
-/*
+/*
netr_DsRGetDCName
*/
static WERROR dcesrv_netr_DsRGetDCName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
r2.in.mask = 0;
r2.in.domain_name = r->in.domain_name;
r2.in.domain_guid = r->in.domain_guid;
-
+
r2.in.site_name = NULL; /* should fill in from site GUID */
r2.in.flags = r->in.flags;
r2.out.info = r->out.info;
return werr;
}
-/*
- netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN
+/*
+ netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN
*/
static WERROR dcesrv_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r)
}
-/*
- netr_DsRAddressToSitenamesExW
+/*
+ netr_DsRAddressToSitenamesExW
*/
static WERROR dcesrv_netr_DsRAddressToSitenamesExW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DsRAddressToSitenamesExW *r)
+ struct netr_DsRAddressToSitenamesExW *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct ldb_context *sam_ctx;
+ struct netr_DsRAddressToSitenamesExWCtr *ctr;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ sa_family_t sin_family;
+ struct sockaddr_in *addr;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 *addr6;
+ char addr_str[INET6_ADDRSTRLEN];
+#else
+ char addr_str[INET_ADDRSTRLEN];
+#endif
+ char *subnet_name;
+ const char *res;
+ uint32_t i;
+
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
+ if (sam_ctx == NULL) {
+ return WERR_DS_UNAVAILABLE;
+ }
+
+ ctr = talloc(mem_ctx, struct netr_DsRAddressToSitenamesExWCtr);
+ W_ERROR_HAVE_NO_MEMORY(ctr);
+
+ *r->out.ctr = ctr;
+
+ ctr->count = r->in.count;
+ ctr->sitename = talloc_array(ctr, struct lsa_String, ctr->count);
+ W_ERROR_HAVE_NO_MEMORY(ctr->sitename);
+ ctr->subnetname = talloc_array(ctr, struct lsa_String, ctr->count);
+ W_ERROR_HAVE_NO_MEMORY(ctr->subnetname);
+
+ for (i=0; i<ctr->count; i++) {
+ ctr->sitename[i].string = NULL;
+ ctr->subnetname[i].string = NULL;
+
+ if (r->in.addresses[i].size < sizeof(sa_family_t)) {
+ continue;
+ }
+ /* The first two byte of the buffer are reserved for the
+ * "sin_family" but for now only the first one is used. */
+ sin_family = r->in.addresses[i].buffer[0];
+
+ switch (sin_family) {
+ case AF_INET:
+ if (r->in.addresses[i].size < sizeof(struct sockaddr_in)) {
+ continue;
+ }
+ addr = (struct sockaddr_in *) r->in.addresses[i].buffer;
+ res = inet_ntop(AF_INET, &addr->sin_addr,
+ addr_str, sizeof(addr_str));
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (r->in.addresses[i].size < sizeof(struct sockaddr_in6)) {
+ continue;
+ }
+ addr6 = (struct sockaddr_in6 *) r->in.addresses[i].buffer;
+ res = inet_ntop(AF_INET6, &addr6->sin6_addr,
+ addr_str, sizeof(addr_str));
+ break;
+#endif
+ default:
+ continue;
+ }
+
+ if (res == NULL) {
+ continue;
+ }
+
+ ctr->sitename[i].string = samdb_client_site_name(sam_ctx,
+ mem_ctx,
+ addr_str,
+ &subnet_name);
+ W_ERROR_HAVE_NO_MEMORY(ctr->sitename[i].string);
+ ctr->subnetname[i].string = subnet_name;
+ }
+
+ return WERR_OK;
+}
+
+
+/*
+ netr_DsRAddressToSitenamesW
+*/
+static WERROR dcesrv_netr_DsRAddressToSitenamesW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_DsRAddressToSitenamesW *r)
+{
+ struct netr_DsRAddressToSitenamesExW r2;
+ struct netr_DsRAddressToSitenamesWCtr *ctr;
+ uint32_t i;
+ WERROR werr;
+
+ ZERO_STRUCT(r2);
+
+ r2.in.server_name = r->in.server_name;
+ r2.in.count = r->in.count;
+ r2.in.addresses = r->in.addresses;
+
+ r2.out.ctr = talloc(mem_ctx, struct netr_DsRAddressToSitenamesExWCtr *);
+ W_ERROR_HAVE_NO_MEMORY(r2.out.ctr);
+
+ ctr = talloc(mem_ctx, struct netr_DsRAddressToSitenamesWCtr);
+ W_ERROR_HAVE_NO_MEMORY(ctr);
+
+ *r->out.ctr = ctr;
+
+ ctr->count = r->in.count;
+ ctr->sitename = talloc_array(ctr, struct lsa_String, ctr->count);
+ W_ERROR_HAVE_NO_MEMORY(ctr->sitename);
+
+ werr = dcesrv_netr_DsRAddressToSitenamesExW(dce_call, mem_ctx, &r2);
+
+ for (i=0; i<ctr->count; i++) {
+ ctr->sitename[i].string = (*r2.out.ctr)->sitename[i].string;
+ }
+
+ return werr;
}
-/*
+/*
netr_DsrGetDcSiteCoverageW
*/
static WERROR dcesrv_netr_DsrGetDcSiteCoverageW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsrGetDcSiteCoverageW *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct ldb_context *sam_ctx;
+ struct DcSitesCtr *ctr;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
+ if (sam_ctx == NULL) {
+ return WERR_DS_UNAVAILABLE;
+ }
+
+ ctr = talloc(mem_ctx, struct DcSitesCtr);
+ W_ERROR_HAVE_NO_MEMORY(ctr);
+
+ *r->out.ctr = ctr;
+
+ /* For now only return our default site */
+ ctr->num_sites = 1;
+ ctr->sites = talloc_array(ctr, struct lsa_String, ctr->num_sites);
+ W_ERROR_HAVE_NO_MEMORY(ctr->sites);
+ ctr->sites[0].string = samdb_server_site_name(sam_ctx, mem_ctx);
+ W_ERROR_HAVE_NO_MEMORY(ctr->sites[0].string);
+
+ return WERR_OK;
}
-/*
- netr_DsrEnumerateDomainTrusts
+#define GET_CHECK_STR(dest, mem, msg, attr) \
+do {\
+ const char *s; \
+ s = samdb_result_string(msg, attr, NULL); \
+ if (!s) { \
+ DEBUG(0, ("DB Error, TustedDomain entry (%s) " \
+ "without flatname\n", \
+ ldb_dn_get_linearized(msg->dn))); \
+ continue; \
+ } \
+ dest = talloc_strdup(mem, s); \
+ W_ERROR_HAVE_NO_MEMORY(dest); \
+} while(0)
+
+
+static WERROR fill_trusted_domains_array(TALLOC_CTX *mem_ctx,
+ struct ldb_context *sam_ctx,
+ struct netr_DomainTrustList *trusts,
+ uint32_t trust_flags)
+{
+ struct ldb_dn *system_dn;
+ struct ldb_message **dom_res = NULL;
+ const char *trust_attrs[] = { "flatname", "trustPartner",
+ "securityIdentifier", "trustDirection",
+ "trustType", "trustAttributes", NULL };
+ uint32_t n;
+ int i;
+ int ret;
+
+ if (!(trust_flags & (NETR_TRUST_FLAG_INBOUND |
+ NETR_TRUST_FLAG_OUTBOUND))) {
+ return WERR_INVALID_FLAGS;
+ }
+
+ system_dn = samdb_search_dn(sam_ctx, mem_ctx,
+ ldb_get_default_basedn(sam_ctx),
+ "(&(objectClass=container)(cn=System))");
+ if (!system_dn) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ret = gendb_search(sam_ctx, mem_ctx, system_dn,
+ &dom_res, trust_attrs,
+ "(objectclass=trustedDomain)");
+
+ for (i = 0; i < ret; i++) {
+ unsigned int trust_dir;
+ uint32_t flags = 0;
+
+ trust_dir = samdb_result_uint(dom_res[i],
+ "trustDirection", 0);
+
+ if (trust_dir & LSA_TRUST_DIRECTION_INBOUND) {
+ flags |= NETR_TRUST_FLAG_INBOUND;
+ }
+ if (trust_dir & LSA_TRUST_DIRECTION_OUTBOUND) {
+ flags |= NETR_TRUST_FLAG_OUTBOUND;
+ }
+
+ if (!(flags & trust_flags)) {
+ /* this trust direction was not requested */
+ continue;
+ }
+
+ n = trusts->count;
+ trusts->array = talloc_realloc(trusts, trusts->array,
+ struct netr_DomainTrust,
+ n + 1);
+ W_ERROR_HAVE_NO_MEMORY(trusts->array);
+
+ GET_CHECK_STR(trusts->array[n].netbios_name, trusts,
+ dom_res[i], "flatname");
+ GET_CHECK_STR(trusts->array[n].dns_name, trusts,
+ dom_res[i], "trustPartner");
+
+ trusts->array[n].trust_flags = flags;
+ if ((trust_flags & NETR_TRUST_FLAG_IN_FOREST) &&
+ !(flags & NETR_TRUST_FLAG_TREEROOT)) {
+ /* TODO: find if we have parent in the list */
+ trusts->array[n].parent_index = 0;
+ }
+
+ trusts->array[n].trust_type =
+ samdb_result_uint(dom_res[i],
+ "trustType", 0);
+ trusts->array[n].trust_attributes =
+ samdb_result_uint(dom_res[i],
+ "trustAttributes", 0);
+
+ if ((trusts->array[n].trust_type == NETR_TRUST_TYPE_MIT) ||
+ (trusts->array[n].trust_type == NETR_TRUST_TYPE_DCE)) {
+ struct dom_sid zero_sid;
+ ZERO_STRUCT(zero_sid);
+ trusts->array[n].sid =
+ dom_sid_dup(trusts, &zero_sid);
+ } else {
+ trusts->array[n].sid =
+ samdb_result_dom_sid(trusts, dom_res[i],
+ "securityIdentifier");
+ }
+ trusts->array[n].guid = GUID_zero();
+
+ trusts->count = n + 1;
+ }
+
+ talloc_free(dom_res);
+ return WERR_OK;
+}
+
+/*
+ netr_DsrEnumerateDomainTrusts
*/
-static WERROR dcesrv_netr_DsrEnumerateDomainTrusts(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DsrEnumerateDomainTrusts *r)
+static WERROR dcesrv_netr_DsrEnumerateDomainTrusts(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct netr_DsrEnumerateDomainTrusts *r)
{
struct netr_DomainTrustList *trusts;
- void *sam_ctx;
+ struct ldb_context *sam_ctx;
int ret;
struct ldb_message **dom_res;
const char * const dom_attrs[] = { "objectSid", "objectGUID", NULL };
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const char *dnsdomain = lpcfg_dnsdomain(lp_ctx);
+ const char *p;
+ WERROR werr;
- ZERO_STRUCT(r->out);
-
- sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
- if (sam_ctx == NULL) {
- return WERR_GENERAL_FAILURE;
+ if (r->in.trust_flags & 0xFFFFFE00) {
+ return WERR_INVALID_FLAGS;
}
- ret = gendb_search_dn((struct ldb_context *)sam_ctx, mem_ctx, NULL,
- &dom_res, dom_attrs);
- if (ret == -1) {
- return WERR_GENERAL_FAILURE;
+ /* TODO: turn to hard check once we are sure this is 100% correct */
+ if (!r->in.server_name) {
+ DEBUG(3, ("Invalid domain! Expected name in domain [%s]. "
+ "But received NULL!\n", dnsdomain));
+ } else {
+ p = strchr(r->in.server_name, '.');
+ if (!p) {
+ DEBUG(3, ("Invalid domain! Expected name in domain "
+ "[%s]. But received [%s]!\n",
+ dnsdomain, r->in.server_name));
+ p = r->in.server_name;
+ } else {
+ p++;
+ }
+ if (strcasecmp(p, dnsdomain)) {
+ DEBUG(3, ("Invalid domain! Expected name in domain "
+ "[%s]. But received [%s]!\n",
+ dnsdomain, r->in.server_name));
+ }
}
- if (ret != 1) {
+
+ trusts = talloc_zero(mem_ctx, struct netr_DomainTrustList);
+ W_ERROR_HAVE_NO_MEMORY(trusts);
+
+ trusts->count = 0;
+ r->out.trusts = trusts;
+
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
+ if (sam_ctx == NULL) {
return WERR_GENERAL_FAILURE;
}
- trusts = talloc(mem_ctx, struct netr_DomainTrustList);
- W_ERROR_HAVE_NO_MEMORY(trusts);
+ if ((r->in.trust_flags & NETR_TRUST_FLAG_INBOUND) ||
+ (r->in.trust_flags & NETR_TRUST_FLAG_OUTBOUND)) {
- trusts->array = talloc_array(trusts, struct netr_DomainTrust, ret);
- W_ERROR_HAVE_NO_MEMORY(trusts->array);
+ werr = fill_trusted_domains_array(mem_ctx, sam_ctx,
+ trusts, r->in.trust_flags);
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
- trusts->count = 1; /* ?? */
+ /* NOTE: we currently are always the root of the forest */
+ if (r->in.trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
+ uint32_t n = trusts->count;
- r->out.trusts = trusts;
+ ret = gendb_search_dn(sam_ctx, mem_ctx, NULL,
+ &dom_res, dom_attrs);
+ if (ret != 1) {
+ return WERR_GENERAL_FAILURE;
+ }
- /* TODO: add filtering by trust_flags, and correct trust_type
- and attributes */
- trusts->array[0].netbios_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
- trusts->array[0].dns_name = lp_realm(dce_call->conn->dce_ctx->lp_ctx);
- trusts->array[0].trust_flags =
- NETR_TRUST_FLAG_TREEROOT |
- NETR_TRUST_FLAG_IN_FOREST |
- NETR_TRUST_FLAG_PRIMARY;
- trusts->array[0].parent_index = 0;
- trusts->array[0].trust_type = 2;
- trusts->array[0].trust_attributes = 0;
- trusts->array[0].sid = samdb_result_dom_sid(mem_ctx, dom_res[0], "objectSid");
- trusts->array[0].guid = samdb_result_guid(dom_res[0], "objectGUID");
+ trusts->count = n + 1;
+ trusts->array = talloc_realloc(trusts, trusts->array,
+ struct netr_DomainTrust,
+ trusts->count);
+ W_ERROR_HAVE_NO_MEMORY(trusts->array);
+
+ trusts->array[n].netbios_name = lpcfg_workgroup(lp_ctx);
+ trusts->array[n].dns_name = lpcfg_dnsdomain(lp_ctx);
+ trusts->array[n].trust_flags =
+ NETR_TRUST_FLAG_NATIVE |
+ NETR_TRUST_FLAG_TREEROOT |
+ NETR_TRUST_FLAG_IN_FOREST |
+ NETR_TRUST_FLAG_PRIMARY;
+ /* we are always the root domain for now */
+ trusts->array[n].parent_index = 0;
+ trusts->array[n].trust_type = NETR_TRUST_TYPE_UPLEVEL;
+ trusts->array[n].trust_attributes = 0;
+ trusts->array[n].sid = samdb_result_dom_sid(mem_ctx,
+ dom_res[0],
+ "objectSid");
+ trusts->array[n].guid = samdb_result_guid(dom_res[0],
+ "objectGUID");
+ talloc_free(dom_res);
+ }
return WERR_OK;
}
}
-/*
- netr_DsRGetForestTrustInformation
+static WERROR fill_forest_trust_array(TALLOC_CTX *mem_ctx,
+ struct ldb_context *sam_ctx,
+ struct loadparm_context *lp_ctx,
+ struct lsa_ForestTrustInformation *info)
+{
+ struct lsa_ForestTrustDomainInfo *domain_info;
+ struct lsa_ForestTrustRecord *e;
+ struct ldb_message **dom_res;
+ const char * const dom_attrs[] = { "objectSid", NULL };
+ int ret;
+
+ /* we need to provide 2 entries:
+ * 1. the Root Forest name
+ * 2. the Domain Information
+ */
+
+ info->count = 2;
+ info->entries = talloc_array(info, struct lsa_ForestTrustRecord *, 2);
+ W_ERROR_HAVE_NO_MEMORY(info->entries);
+
+ /* Forest root info */
+ e = talloc(info, struct lsa_ForestTrustRecord);
+ W_ERROR_HAVE_NO_MEMORY(e);
+
+ e->flags = 0;
+ e->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME;
+ e->time = 0; /* so far always 0 in trces. */
+ e->forest_trust_data.top_level_name.string = samdb_forest_name(sam_ctx,
+ mem_ctx);
+ W_ERROR_HAVE_NO_MEMORY(e->forest_trust_data.top_level_name.string);
+
+ info->entries[0] = e;
+
+ /* Domain info */
+ e = talloc(info, struct lsa_ForestTrustRecord);
+ W_ERROR_HAVE_NO_MEMORY(e);
+
+ /* get our own domain info */
+ ret = gendb_search_dn(sam_ctx, mem_ctx, NULL, &dom_res, dom_attrs);
+ if (ret != 1) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* TODO: check if disabled and set flags accordingly */
+ e->flags = 0;
+ e->type = LSA_FOREST_TRUST_DOMAIN_INFO;
+ e->time = 0; /* so far always 0 in traces. */
+
+ domain_info = &e->forest_trust_data.domain_info;
+ domain_info->domain_sid = samdb_result_dom_sid(info, dom_res[0],
+ "objectSid");
+ domain_info->dns_domain_name.string = lpcfg_dnsdomain(lp_ctx);
+ domain_info->netbios_domain_name.string = lpcfg_workgroup(lp_ctx);
+
+ info->entries[1] = e;
+
+ talloc_free(dom_res);
+
+ return WERR_OK;
+}
+
+/*
+ netr_DsRGetForestTrustInformation
*/
-static WERROR dcesrv_netr_DsRGetForestTrustInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DsRGetForestTrustInformation *r)
+static WERROR dcesrv_netr_DsRGetForestTrustInformation(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct netr_DsRGetForestTrustInformation *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ struct lsa_ForestTrustInformation *info, **info_ptr;
+ struct ldb_context *sam_ctx;
+ WERROR werr;
+
+ if (r->in.flags & 0xFFFFFFFE) {
+ return WERR_INVALID_FLAGS;
+ }
+
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
+ if (sam_ctx == NULL) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (r->in.flags & DS_GFTI_UPDATE_TDO) {
+ if (!samdb_is_pdc(sam_ctx)) {
+ return WERR_NERR_NOTPRIMARY;
+ }
+
+ if (r->in.trusted_domain_name == NULL) {
+ return WERR_INVALID_FLAGS;
+ }
+
+ /* TODO: establish an schannel connection with
+ * r->in.trusted_domain_name and perform a
+ * netr_GetForestTrustInformation call against it */
+
+ /* for now return not implementd */
+ return WERR_CALL_NOT_IMPLEMENTED;
+ }
+
+ /* TODO: check r->in.server_name is our name */
+
+ info_ptr = talloc(mem_ctx, struct lsa_ForestTrustInformation *);
+ W_ERROR_HAVE_NO_MEMORY(info_ptr);
+
+ info = talloc_zero(info_ptr, struct lsa_ForestTrustInformation);
+ W_ERROR_HAVE_NO_MEMORY(info);
+
+ werr = fill_forest_trust_array(mem_ctx, sam_ctx, lp_ctx, info);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ *info_ptr = info;
+ r->out.forest_trust_info = info_ptr;
+
+ return WERR_OK;
}
/*
netr_GetForestTrustInformation
*/
-static WERROR dcesrv_netr_GetForestTrustInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_GetForestTrustInformation *r)
+static NTSTATUS dcesrv_netr_GetForestTrustInformation(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct netr_GetForestTrustInformation *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ struct netlogon_creds_CredentialState *creds;
+ struct lsa_ForestTrustInformation *info, **info_ptr;
+ struct ldb_context *sam_ctx;
+ NTSTATUS status;
+ WERROR werr;
+
+ status = dcesrv_netr_creds_server_step_check(dce_call,
+ mem_ctx,
+ r->in.computer_name,
+ r->in.credential,
+ r->out.return_authenticator,
+ &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if ((creds->secure_channel_type != SEC_CHAN_DNS_DOMAIN) &&
+ (creds->secure_channel_type != SEC_CHAN_DOMAIN)) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
+ dce_call->conn->auth_state.session_info);
+ if (sam_ctx == NULL) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* TODO: check r->in.server_name is our name */
+
+ info_ptr = talloc(mem_ctx, struct lsa_ForestTrustInformation *);
+ if (!info_ptr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ info = talloc_zero(info_ptr, struct lsa_ForestTrustInformation);
+ if (!info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ werr = fill_forest_trust_array(mem_ctx, sam_ctx, lp_ctx, info);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werror_to_ntstatus(werr);
+ }
+
+ *info_ptr = info;
+ r->out.forest_trust_info = info_ptr;
+
+ return NT_STATUS_OK;
}