endpoint server for the netlogon pipe
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ 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,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "rpc_server/common/common.h"
#include "lib/ldb/include/ldb.h"
#include "auth/auth.h"
-#include "auth/auth_sam.h"
+#include "auth/auth_sam_reply.h"
#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/flags.h"
#include "rpc_server/samr/proto.h"
-#include "db_wrap.h"
+#include "../lib/util/util_ldb.h"
#include "libcli/auth/libcli_auth.h"
#include "auth/gensec/schannel_state.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"
struct server_pipe_state {
struct netr_Credential client_challenge;
{
struct server_pipe_state *pipe_state = dce_call->context->private;
- ZERO_STRUCTP(r->out.credentials);
+ ZERO_STRUCTP(r->out.return_credentials);
/* destroyed on pipe shutdown */
generate_random_buffer(pipe_state->server_challenge.data,
sizeof(pipe_state->server_challenge.data));
- *r->out.credentials = pipe_state->server_challenge;
+ *r->out.return_credentials = pipe_state->server_challenge;
dce_call->context->private = pipe_state;
struct creds_CredentialState *creds;
void *sam_ctx;
struct samr_Password *mach_pwd;
- uint16_t acct_flags;
+ uint32_t user_account_control;
int num_records;
struct ldb_message **msgs;
NTSTATUS nt_status;
const char *attrs[] = {"unicodePwd", "userAccountControl",
"objectSid", NULL};
- ZERO_STRUCTP(r->out.credentials);
+ const char *trust_dom_attrs[] = {"flatname", NULL};
+ const char *account_name;
+
+ ZERO_STRUCTP(r->out.return_credentials);
*r->out.rid = 0;
*r->out.negotiate_flags = *r->in.negotiate_flags;
return NT_STATUS_ACCESS_DENIED;
}
- sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
+ 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));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
+
+ if (r->in.secure_channel_type == SEC_CHAN_DNS_DOMAIN) {
+ char *encoded_account = ldb_binary_encode_string(mem_ctx, r->in.account_name);
+ const char *flatname;
+ if (!encoded_account) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Kill the trailing dot */
+ if (encoded_account[strlen(encoded_account)-1] == '.') {
+ encoded_account[strlen(encoded_account)-1] = '\0';
+ }
+
+ /* pull the user attributes */
+ num_records = gendb_search(sam_ctx, mem_ctx, NULL, &msgs, trust_dom_attrs,
+ "(&(trustPartner=%s)(objectclass=trustedDomain))",
+ encoded_account);
+
+ if (num_records == 0) {
+ 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 */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ account_name = talloc_asprintf(mem_ctx, "%s$", flatname);
+
+ if (!account_name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ } else {
+ account_name = r->in.account_name;
+ }
+
/* pull the user attributes */
num_records = gendb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs,
"(&(sAMAccountName=%s)(objectclass=user))",
- r->in.account_name);
+ ldb_binary_encode_string(mem_ctx, account_name));
if (num_records == 0) {
DEBUG(3,("Couldn't find user [%s] in samdb.\n",
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- acct_flags = samdb_result_acct_flags(msgs[0],
- "userAccountControl");
+
+ user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0);
- if (acct_flags & ACB_DISABLED) {
+ if (user_account_control & UF_ACCOUNTDISABLE) {
DEBUG(1, ("Account [%s] is disabled\n", r->in.account_name));
return NT_STATUS_ACCESS_DENIED;
}
if (r->in.secure_channel_type == SEC_CHAN_WKSTA) {
- if (!(acct_flags & ACB_WSTRUST)) {
- DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", acct_flags));
+ if (!(user_account_control & UF_WORKSTATION_TRUST_ACCOUNT)) {
+ 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) {
- if (!(acct_flags & ACB_DOMTRUST)) {
- DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", acct_flags));
+ } 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) {
- if (!(acct_flags & ACB_SVRTRUST)) {
- DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", acct_flags));
+ if (!(user_account_control & UF_SERVER_TRUST_ACCOUNT)) {
+ DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", user_account_control));
return NT_STATUS_ACCESS_DENIED;
}
} else {
creds_server_init(creds, &pipe_state->client_challenge,
&pipe_state->server_challenge, mach_pwd,
- r->out.credentials,
+ r->out.return_credentials,
*r->in.negotiate_flags);
if (!creds_server_check(creds, r->in.credentials)) {
creds->account_name = talloc_steal(creds, r->in.account_name);
creds->computer_name = talloc_steal(creds, r->in.computer_name);
- creds->domain = talloc_strdup(creds, lp_workgroup());
+ creds->domain = talloc_strdup(creds, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));
creds->secure_channel_type = r->in.secure_channel_type;
/* remember this session key state */
- nt_status = schannel_store_session_key(mem_ctx, creds);
+ nt_status = schannel_store_session_key(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, creds);
return nt_status;
}
r3.in.secure_channel_type = r->in.secure_channel_type;
r3.in.computer_name = r->in.computer_name;
r3.in.credentials = r->in.credentials;
- r3.out.credentials = r->out.credentials;
+ r3.out.return_credentials = r->out.return_credentials;
r3.in.negotiate_flags = &negotiate_flags;
r3.out.negotiate_flags = &negotiate_flags;
r3.out.rid = &rid;
r3.in.secure_channel_type = r->in.secure_channel_type;
r3.in.computer_name = r->in.computer_name;
r3.in.credentials = r->in.credentials;
- r3.out.credentials = r->out.credentials;
+ r3.out.return_credentials = r->out.return_credentials;
r3.in.negotiate_flags = r->in.negotiate_flags;
r3.out.negotiate_flags = r->out.negotiate_flags;
r3.out.rid = &rid;
the caller needs some of that information.
*/
-static NTSTATUS dcesrv_netr_creds_server_step_check(const char *computer_name,
+static NTSTATUS dcesrv_netr_creds_server_step_check(struct event_context *event_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
TALLOC_CTX *mem_ctx,
struct netr_Authenticator *received_authenticator,
struct netr_Authenticator *return_authenticator,
struct ldb_context *ldb;
int ret;
- ldb = schannel_db_connect(mem_ctx);
+ ldb = schannel_db_connect(mem_ctx, event_ctx, lp_ctx);
if (!ldb) {
return NT_STATUS_ACCESS_DENIED;
}
* disconnects) we must update the database every time we
* update the structure */
- nt_status = schannel_fetch_session_key_ldb(ldb, ldb, computer_name, lp_workgroup(),
+ nt_status = schannel_fetch_session_key_ldb(ldb, ldb, computer_name,
+ lp_workgroup(lp_ctx),
&creds);
if (NT_STATUS_IS_OK(nt_status)) {
nt_status = creds_server_step_check(creds,
struct ldb_context *sam_ctx;
NTSTATUS nt_status;
- nt_status = dcesrv_netr_creds_server_step_check(r->in.computer_name, mem_ctx,
- &r->in.credential, &r->out.return_authenticator,
+ nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
+ r->in.computer_name, mem_ctx,
+ r->in.credential, r->out.return_authenticator,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
+ 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));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
- creds_des_decrypt(creds, &r->in.new_password);
+ 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,
creds->sid,
NULL, /* Don't have plaintext */
- NULL, &r->in.new_password,
- False, /* This is not considered a password change */
- False, /* don't restrict this password change (match w2k3) */
+ NULL, r->in.new_password,
+ true, /* Password change */
NULL, NULL);
return nt_status;
}
struct creds_CredentialState *creds;
struct ldb_context *sam_ctx;
NTSTATUS nt_status;
- char new_pass[512];
- uint32_t new_pass_len;
- BOOL ret;
+ DATA_BLOB new_password;
struct samr_CryptPassword password_buf;
- nt_status = dcesrv_netr_creds_server_step_check(r->in.computer_name, mem_ctx,
- &r->in.credential, &r->out.return_authenticator,
- &creds);
+ nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
+ r->in.computer_name, mem_ctx,
+ r->in.credential, r->out.return_authenticator,
+ &creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
+ 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));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
- memcpy(password_buf.data, r->in.new_password.data, 512);
- SIVAL(password_buf.data,512,r->in.new_password.length);
+ memcpy(password_buf.data, r->in.new_password->data, 512);
+ SIVAL(password_buf.data, 512, r->in.new_password->length);
creds_arcfour_crypt(creds, password_buf.data, 516);
- ret = decode_pw_buffer(password_buf.data, new_pass, sizeof(new_pass),
- &new_pass_len, STR_UNICODE);
- if (!ret) {
- DEBUG(3,("netr_ServerPasswordSet2: failed to decode password buffer\n"));
- return NT_STATUS_ACCESS_DENIED;
+ if (!extract_pw_from_buffer(mem_ctx, password_buf.data, &new_password)) {
+ 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,
- new_pass, /* we have plaintext */
+ &new_password, /* we have plaintext */
NULL, NULL,
- False, /* This is not considered a password change */
- False, /* don't restrict this password change (match w2k3) */
+ true, /* Password change */
NULL, NULL);
return nt_status;
}
NT_STATUS_HAVE_NO_MEMORY(user_info);
user_info->flags = 0;
- user_info->mapped_state = False;
+ user_info->mapped_state = false;
user_info->remote_host = NULL;
switch (r->in.logon_level) {
- case 1:
- case 3:
- case 5:
+ case NetlogonInteractiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceTransitiveInformation:
if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
creds_arcfour_crypt(creds,
- r->in.logon.password->lmpassword.hash,
- sizeof(r->in.logon.password->lmpassword.hash));
+ r->in.logon->password->lmpassword.hash,
+ sizeof(r->in.logon->password->lmpassword.hash));
creds_arcfour_crypt(creds,
- r->in.logon.password->ntpassword.hash,
- sizeof(r->in.logon.password->ntpassword.hash));
+ r->in.logon->password->ntpassword.hash,
+ sizeof(r->in.logon->password->ntpassword.hash));
} else {
- creds_des_decrypt(creds, &r->in.logon.password->lmpassword);
- creds_des_decrypt(creds, &r->in.logon.password->ntpassword);
+ creds_des_decrypt(creds, &r->in.logon->password->lmpassword);
+ creds_des_decrypt(creds, &r->in.logon->password->ntpassword);
}
/* TODO: we need to deny anonymous access here */
- nt_status = auth_context_create(mem_ctx, lp_auth_methods(),
+ nt_status = auth_context_create(mem_ctx,
dce_call->event_ctx, dce_call->msg_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
&auth_context);
NT_STATUS_NOT_OK_RETURN(nt_status);
- user_info->logon_parameters = r->in.logon.password->identity_info.parameter_control;
- 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->logon_parameters = r->in.logon->password->identity_info.parameter_control;
+ 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;
user_info->password.hash.lanman = talloc(user_info, struct samr_Password);
NT_STATUS_HAVE_NO_MEMORY(user_info->password.hash.lanman);
- *user_info->password.hash.lanman = r->in.logon.password->lmpassword;
+ *user_info->password.hash.lanman = r->in.logon->password->lmpassword;
user_info->password.hash.nt = talloc(user_info, struct samr_Password);
NT_STATUS_HAVE_NO_MEMORY(user_info->password.hash.nt);
- *user_info->password.hash.nt = r->in.logon.password->ntpassword;
+ *user_info->password.hash.nt = r->in.logon->password->ntpassword;
break;
- case 2:
- case 6:
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
/* TODO: we need to deny anonymous access here */
- nt_status = auth_context_create(mem_ctx, lp_auth_methods(),
+ nt_status = auth_context_create(mem_ctx,
dce_call->event_ctx, dce_call->msg_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
&auth_context);
NT_STATUS_NOT_OK_RETURN(nt_status);
- nt_status = auth_context_set_challenge(auth_context, r->in.logon.network->challenge, "netr_LogonSamLogonWithFlags");
+ nt_status = auth_context_set_challenge(auth_context, r->in.logon->network->challenge, "netr_LogonSamLogonWithFlags");
NT_STATUS_NOT_OK_RETURN(nt_status);
- user_info->logon_parameters = r->in.logon.network->identity_info.parameter_control;
- 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->logon_parameters = r->in.logon->network->identity_info.parameter_control;
+ 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);
+ 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) {
+ creds_arcfour_crypt(creds,
+ r->in.logon->generic->data, r->in.logon->generic->length);
+ } else {
+ /* Using DES to verify kerberos tickets makes no sense */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (strcmp(r->in.logon->generic->package_name.string, "Kerberos") == 0) {
+ NTSTATUS status;
+ struct server_id *kdc;
+ struct kdc_check_generic_kerberos check;
+ 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 =
+ 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);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ generic->length = check.out.generic_reply.length;
+ generic->data = check.out.generic_reply.data;
+ return NT_STATUS_OK;
+ }
+
+ /* Until we get an implemetnation of these other packages */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
default:
return NT_STATUS_INVALID_PARAMETER;
}
sam2 = talloc_zero(mem_ctx, struct netr_SamInfo2);
NT_STATUS_HAVE_NO_MEMORY(sam2);
sam2->base = *sam;
- r->out.validation.sam2 = sam2;
+ r->out.validation->sam2 = sam2;
break;
case 3:
sam3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
NT_STATUS_HAVE_NO_MEMORY(sam3);
sam3->base = *sam;
- r->out.validation.sam3 = sam3;
+ r->out.validation->sam3 = sam3;
break;
case 6:
sam6 = talloc_zero(mem_ctx, struct netr_SamInfo6);
NT_STATUS_HAVE_NO_MEMORY(sam6);
sam6->base = *sam;
- sam6->forest.string = lp_realm();
+ 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);
NT_STATUS_HAVE_NO_MEMORY(sam6->principle.string);
- r->out.validation.sam6 = sam6;
+ r->out.validation->sam6 = sam6;
break;
default:
break;
}
- r->out.authoritative = 1;
+ *r->out.authoritative = 1;
/* TODO: Describe and deal with these flags */
- r->out.flags = 0;
+ *r->out.flags = 0;
return NT_STATUS_OK;
}
{
NTSTATUS nt_status;
struct creds_CredentialState *creds;
- nt_status = schannel_fetch_session_key(mem_ctx, r->in.computer_name, lp_workgroup(), &creds);
+ nt_status = schannel_fetch_session_key(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, r->in.computer_name, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx), &creds);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
return_authenticator = talloc(mem_ctx, struct netr_Authenticator);
NT_STATUS_HAVE_NO_MEMORY(return_authenticator);
- nt_status = dcesrv_netr_creds_server_step_check(r->in.computer_name, mem_ctx,
+ nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
+ r->in.computer_name, mem_ctx,
r->in.credential, return_authenticator,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
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;
nt_status = dcesrv_netr_LogonSamLogon_base(dce_call, mem_ctx, &r2, creds);
r->out.return_authenticator = return_authenticator;
- r->out.validation = r2.out.validation;
- r->out.authoritative = r2.out.authoritative;
- r->out.flags = r2.out.flags;
return nt_status;
}
struct netr_LogonSamLogon *r)
{
struct netr_LogonSamLogonWithFlags r2;
+ uint32_t flags = 0;
NTSTATUS status;
ZERO_STRUCT(r2);
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 = 0;
+ r2.in.flags = &flags;
+ r2.out.validation = r->out.validation;
+ r2.out.authoritative = r->out.authoritative;
+ r2.out.flags = &flags;
status = dcesrv_netr_LogonSamLogonWithFlags(dce_call, mem_ctx, &r2);
r->out.return_authenticator = r2.out.return_authenticator;
- r->out.validation = r2.out.validation;
- r->out.authoritative = r2.out.authoritative;
return status;
}
static NTSTATUS dcesrv_netr_DatabaseSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DatabaseSync *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ /* win2k3 native mode returns "NOT IMPLEMENTED" for this call */
+ return NT_STATUS_NOT_IMPLEMENTED;
}
/*
netr_GetDcName
*/
-static NTSTATUS dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+static WERROR dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetDcName *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ const char * const attrs[] = { NULL };
+ void *sam_ctx;
+ struct ldb_message **res;
+ struct ldb_dn *domain_dn;
+ int ret;
+ const char *dcname;
+
+ 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_DS_SERVICE_UNAVAILABLE;
+ }
+
+ domain_dn = samdb_domain_to_dn(sam_ctx, mem_ctx,
+ r->in.domainname);
+ if (domain_dn == NULL) {
+ return WERR_DS_SERVICE_UNAVAILABLE;
+ }
+
+ ret = gendb_search_dn(sam_ctx, mem_ctx, domain_dn, &res, attrs);
+ if (ret != 1) {
+ return WERR_NO_SUCH_DOMAIN;
+ }
+
+ /* TODO: - return real IP address
+ * - 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));
+ W_ERROR_HAVE_NO_MEMORY(dcname);
+
+ *r->out.dcname = dcname;
+ return WERR_OK;
}
static WERROR dcesrv_netr_GetAnyDCName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetAnyDCName *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct netr_GetDcName r2;
+ WERROR werr;
+
+ ZERO_STRUCT(r2);
+
+ r2.in.logon_server = r->in.logon_server;
+ r2.in.domainname = r->in.domainname;
+ r2.out.dcname = r->out.dcname;
+
+ werr = dcesrv_netr_GetDcName(dce_call, mem_ctx, &r2);
+
+ return werr;
}
static NTSTATUS dcesrv_netr_DatabaseSync2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DatabaseSync2 *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ /* win2k3 native mode returns "NOT IMPLEMENTED" for this call */
+ return NT_STATUS_NOT_IMPLEMENTED;
}
/*
- netr_NETRENUMERATETRUSTEDDOMAINS
+ netr_NetrEnumerateTurstedDomains
*/
-static WERROR dcesrv_netr_NETRENUMERATETRUSTEDDOMAINS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_NETRENUMERATETRUSTEDDOMAINS *r)
+static WERROR 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_NETRLOGONGETTRUSTRID
+/*
+ netr_LogonGetTrustRid
*/
-static WERROR dcesrv_netr_NETRLOGONGETTRUSTRID(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_NETRLOGONGETTRUSTRID *r)
+static WERROR dcesrv_netr_LogonGetTrustRid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_LogonGetTrustRid *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
struct ldb_message *res,
struct ldb_message *ref_res,
struct netr_DomainTrustInfo *info,
- BOOL is_local)
+ 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) {
+ /* MS-NRPC 3.5.4.3.9 - must be set to NULL for trust list */
+ info->forest.string = NULL;
+ } else {
+ /* TODO: we need a common function for pulling the forest */
+ info->forest.string = samdb_result_string(ref_res, "dnsRoot", NULL);
+ }
+
if (is_local) {
info->domainname.string = samdb_result_string(ref_res, "nETBIOSName", NULL);
info->fulldomainname.string = samdb_result_string(ref_res, "dnsRoot", NULL);
- info->forest.string = NULL;
info->guid = samdb_result_guid(res, "objectGUID");
info->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->forest.string = NULL;
info->guid = samdb_result_guid(res, "objectGUID");
info->sid = samdb_result_dom_sid(mem_ctx, res, "securityIdentifier");
}
/*
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)
const char *local_domain;
- status = dcesrv_netr_creds_server_step_check(r->in.computer_name, mem_ctx,
+ status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
+ r->in.computer_name, mem_ctx,
r->in.credential,
r->out.return_authenticator,
NULL);
+ 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->conn->auth_state.session_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);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
info1->num_trusts);
NT_STATUS_HAVE_NO_MEMORY(info1->trusts);
- status = fill_domain_trust_info(mem_ctx, res1[0], ref_res[0], &info1->domaininfo, True);
+ status = fill_domain_trust_info(mem_ctx, res1[0], ref_res[0], &info1->domaininfo,
+ true, false);
NT_STATUS_NOT_OK_RETURN(status);
for (i=0;i<ret2;i++) {
- status = fill_domain_trust_info(mem_ctx, res2[i], NULL, &info1->trusts[i], False);
+ status = fill_domain_trust_info(mem_ctx, res2[i], NULL, &info1->trusts[i],
+ false, true);
NT_STATUS_NOT_OK_RETURN(status);
}
- status = fill_domain_trust_info(mem_ctx, res1[0], ref_res[0], &info1->trusts[i], True);
+ status = fill_domain_trust_info(mem_ctx, res1[0], ref_res[0], &info1->trusts[i],
+ true, true);
NT_STATUS_NOT_OK_RETURN(status);
- r->out.info.info1 = info1;
+ info1->dns_hostname.string = samdb_result_string(ref_res[0], "dnsRoot", NULL);
+ info1->workstation_flags =
+ NETR_WS_FLAG_HANDLES_INBOUND_TRUSTS | NETR_WS_FLAG_HANDLES_SPN_UPDATE;
+ info1->supported_enc_types = 0; /* w2008 gives this 0 */
+
+ r->out.info->info1 = info1;
return NT_STATUS_OK;
}
-/*
- netr_NETRSERVERPASSWORDGET
+/*
+ netr_ServerPasswordGet
*/
-static WERROR dcesrv_netr_NETRSERVERPASSWORDGET(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_NETRSERVERPASSWORDGET *r)
+static WERROR dcesrv_netr_ServerPasswordGet(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_ServerPasswordGet *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
- netr_DSRADDRESSTOSITENAMESW
+ netr_DsRAddressToSitenamesW
*/
-static WERROR dcesrv_netr_DSRADDRESSTOSITENAMESW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DSRADDRESSTOSITENAMESW *r)
+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);
}
const char * const attrs[] = { "dnsDomain", "objectGUID", NULL };
void *sam_ctx;
struct ldb_message **res;
+ struct ldb_dn *domain_dn;
int ret;
+ struct netr_DsRGetDCNameInfo *info;
- ZERO_STRUCT(r->out);
+ ZERO_STRUCTP(r->out.info);
- sam_ctx = samdb_connect(mem_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, dce_call->conn->auth_state.session_info);
if (sam_ctx == NULL) {
return WERR_DS_SERVICE_UNAVAILABLE;
}
- ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs,
- "(&(objectClass=domainDNS)(dnsDomain=%s))",
- r->in.domain_name);
+ domain_dn = samdb_dns_domain_to_dn(sam_ctx, mem_ctx,
+ r->in.domain_name);
+ if (domain_dn == NULL) {
+ return WERR_DS_SERVICE_UNAVAILABLE;
+ }
+
+ ret = gendb_search_dn(sam_ctx, mem_ctx, domain_dn, &res, attrs);
if (ret != 1) {
return WERR_NO_SUCH_DOMAIN;
}
- r->out.info = talloc(mem_ctx, struct netr_DsRGetDCNameInfo);
- W_ERROR_HAVE_NO_MEMORY(r->out.info);
+ 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!)
*/
- r->out.info->dc_unc = talloc_asprintf(mem_ctx, "\\\\%s.%s", lp_netbios_name(),lp_realm());
- W_ERROR_HAVE_NO_MEMORY(r->out.info->dc_unc);
- r->out.info->dc_address = talloc_strdup(mem_ctx, "\\\\0.0.0.0");
- W_ERROR_HAVE_NO_MEMORY(r->out.info->dc_address);
- r->out.info->dc_address_type = 1;
- r->out.info->domain_guid = samdb_result_guid(res[0], "objectGUID");
- r->out.info->domain_name = samdb_result_string(res[0], "dnsDomain", NULL);
- r->out.info->forest_name = samdb_result_string(res[0], "dnsDomain", NULL);
- r->out.info->dc_flags = 0xE00001FD;
- r->out.info->dc_site_name = talloc_strdup(mem_ctx, "Default-First-Site-Name");
- W_ERROR_HAVE_NO_MEMORY(r->out.info->dc_site_name);
- r->out.info->client_site_name = talloc_strdup(mem_ctx, "Default-First-Site-Name");
- W_ERROR_HAVE_NO_MEMORY(r->out.info->client_site_name);
+ 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));
+ W_ERROR_HAVE_NO_MEMORY(info->dc_unc);
+ info->dc_address = talloc_strdup(mem_ctx, "\\\\0.0.0.0");
+ 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 = samdb_result_string(res[0], "dnsDomain", NULL);
+ info->forest_name = samdb_result_string(res[0], "dnsDomain", NULL);
+ 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);
+
+ *r->out.info = info;
return WERR_OK;
}
r2.in.domain_name = r->in.domain_name;
r2.in.site_name = r->in.site_name;
r2.in.flags = r->in.flags;
- r2.out.info = NULL;
+ r2.out.info = r->out.info;
werr = dcesrv_netr_DsRGetDCNameEx2(dce_call, mem_ctx, &r2);
-
- r->out.info = r2.out.info;
-
+
return werr;
}
r2.in.site_name = NULL; /* should fill in from site GUID */
r2.in.flags = r->in.flags;
- r2.out.info = NULL;
+ r2.out.info = r->out.info;
werr = dcesrv_netr_DsRGetDCNameEx2(dce_call, mem_ctx, &r2);
-
- r->out.info = r2.out.info;
-
+
return werr;
}
-
/*
netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN
*/
}
-/*
- netr_NETRENUMERATETRUSTEDDOMAINSEX
+/*
+ netr_NetrEnumerateTrustedDomainsEx
*/
-static WERROR dcesrv_netr_NETRENUMERATETRUSTEDDOMAINSEX(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_NETRENUMERATETRUSTEDDOMAINSEX *r)
+static WERROR dcesrv_netr_NetrEnumerateTrustedDomainsEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_NetrEnumerateTrustedDomainsEx *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
- netr_DSRADDRESSTOSITENAMESEXW
+ netr_DsRAddressToSitenamesExW
*/
-static WERROR dcesrv_netr_DSRADDRESSTOSITENAMESEXW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DSRADDRESSTOSITENAMESEXW *r)
+static WERROR dcesrv_netr_DsRAddressToSitenamesExW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_DsRAddressToSitenamesExW *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
- netr_DSRGETDCSITECOVERAGEW
+ netr_DsrGetDcSiteCoverageW
*/
-static WERROR dcesrv_netr_DSRGETDCSITECOVERAGEW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DSRGETDCSITECOVERAGEW *r)
+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);
}
static WERROR dcesrv_netr_DsrEnumerateDomainTrusts(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsrEnumerateDomainTrusts *r)
{
- struct netr_DomainTrust *trusts;
+ struct netr_DomainTrustList *trusts;
void *sam_ctx;
int ret;
struct ldb_message **dom_res, **ref_res;
ZERO_STRUCT(r->out);
- sam_ctx = samdb_connect(mem_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, dce_call->conn->auth_state.session_info);
if (sam_ctx == NULL) {
return WERR_GENERAL_FAILURE;
}
return WERR_GENERAL_FAILURE;
}
- trusts = talloc_array(mem_ctx, struct netr_DomainTrust, ret);
+ trusts = talloc(mem_ctx, struct netr_DomainTrustList);
W_ERROR_HAVE_NO_MEMORY(trusts);
-
- r->out.count = 1;
+
+ trusts->array = talloc_array(trusts, struct netr_DomainTrust, ret);
+ W_ERROR_HAVE_NO_MEMORY(trusts->array);
+
+ trusts->count = 1; /* ?? */
+
r->out.trusts = trusts;
/* TODO: add filtering by trust_flags, and correct trust_type
and attributes */
- trusts[0].netbios_name = samdb_result_string(ref_res[0], "nETBIOSName", NULL);
- trusts[0].dns_name = samdb_result_string(ref_res[0], "dnsRoot", NULL);
- trusts[0].trust_flags =
+ trusts->array[0].netbios_name = samdb_result_string(ref_res[0], "nETBIOSName", NULL);
+ trusts->array[0].dns_name = samdb_result_string(ref_res[0], "dnsRoot", NULL);
+ trusts->array[0].trust_flags =
NETR_TRUST_FLAG_TREEROOT |
NETR_TRUST_FLAG_IN_FOREST |
NETR_TRUST_FLAG_PRIMARY;
- trusts[0].parent_index = 0;
- trusts[0].trust_type = 2;
- trusts[0].trust_attributes = 0;
- trusts[0].sid = samdb_result_dom_sid(mem_ctx, dom_res[0], "objectSid");
- trusts[0].guid = samdb_result_guid(dom_res[0], "objectGUID");
+ 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");
return WERR_OK;
}
-/*
- netr_DSRDEREGISTERDNSHOSTRECORDS
+/*
+ netr_DsrDeregisterDNSHostRecords
*/
-static WERROR dcesrv_netr_DSRDEREGISTERDNSHOSTRECORDS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_DSRDEREGISTERDNSHOSTRECORDS *r)
+static WERROR dcesrv_netr_DsrDeregisterDNSHostRecords(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_DsrDeregisterDNSHostRecords *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
-/*
- netr_NETRSERVERTRUSTPASSWORDSGET
+/*
+ netr_ServerTrustPasswordsGet
*/
-static WERROR dcesrv_netr_NETRSERVERTRUSTPASSWORDSGET(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_NETRSERVERTRUSTPASSWORDSGET *r)
+static NTSTATUS dcesrv_netr_ServerTrustPasswordsGet(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_ServerTrustPasswordsGet *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
- netr_DSRGETFORESTTRUSTINFORMATION
+ 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);
}
-/*
- netr_NETRGETFORESTTRUSTINFORMATION
+/*
+ netr_GetForestTrustInformation
*/
-static WERROR dcesrv_netr_NETRGETFORESTTRUSTINFORMATION(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_NETRGETFORESTTRUSTINFORMATION *r)
+static WERROR dcesrv_netr_GetForestTrustInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_GetForestTrustInformation *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
-/*
- netr_NETRSERVERGETTRUSTINFO
+/*
+ netr_ServerGetTrustInfo
*/
-static WERROR dcesrv_netr_NETRSERVERGETTRUSTINFO(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct netr_NETRSERVERGETTRUSTINFO *r)
+static NTSTATUS dcesrv_netr_ServerGetTrustInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_ServerGetTrustInfo *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}