+ object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid");
+
+ additional_sids[0] = object_sid;
+
+ werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0],
+ mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto denied;
+ }
+
+ werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0],
+ mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto denied;
+ }
+
+ /*
+ * The SID list needs to include itself as well as the tokenGroups.
+ *
+ * TODO determine if sIDHistory is required for this check
+ */
+ werr = samdb_result_sid_array_ndr(sam_ctx, obj_res->msgs[0],
+ mem_ctx, "tokenGroups", &token_sids,
+ additional_sids, 1);
+ if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
+ goto denied;
+ }
+
+ if (never_reveal_sids &&
+ sid_list_match(token_sids, never_reveal_sids)) {
+ goto denied;
+ }
+
+ if (reveal_sids &&
+ sid_list_match(token_sids, reveal_sids)) {
+ goto allowed;
+ }
+
+denied:
+ return false;
+allowed:
+ return true;
+
+}
+
+/*
+ netr_NetrLogonSendToSam
+*/
+static NTSTATUS dcesrv_netr_NetrLogonSendToSam(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct netr_NetrLogonSendToSam *r)
+{
+ struct netlogon_creds_CredentialState *creds;
+ struct ldb_context *sam_ctx;
+ NTSTATUS nt_status;
+ DATA_BLOB decrypted_blob;
+ enum ndr_err_code ndr_err;
+ struct netr_SendToSamBase base_msg = { 0 };
+
+ nt_status = dcesrv_netr_creds_server_step_check(dce_call,
+ mem_ctx,
+ r->in.computer_name,
+ r->in.credential,
+ r->out.return_authenticator,
+ &creds);
+
+ NT_STATUS_NOT_OK_RETURN(nt_status);
+
+ switch (creds->secure_channel_type) {
+ case SEC_CHAN_BDC:
+ case SEC_CHAN_RODC:
+ break;
+ case SEC_CHAN_WKSTA:
+ case SEC_CHAN_DNS_DOMAIN:
+ case SEC_CHAN_DOMAIN:
+ case SEC_CHAN_NULL:
+ return NT_STATUS_INVALID_PARAMETER;
+ default:
+ DEBUG(1, ("Client asked for an invalid secure channel type: %d\n",
+ creds->secure_channel_type));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ 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),
+ dce_call->conn->remote_address,
+ 0);
+ if (sam_ctx == NULL) {
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+
+ /* Buffer is meant to be 16-bit aligned */
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_decrypt(creds, r->in.opaque_buffer, r->in.buffer_len);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, r->in.opaque_buffer, r->in.buffer_len);
+ }
+
+ decrypted_blob.data = r->in.opaque_buffer;
+ decrypted_blob.length = r->in.buffer_len;
+
+ ndr_err = ndr_pull_struct_blob(&decrypted_blob, mem_ctx, &base_msg,
+ (ndr_pull_flags_fn_t)ndr_pull_netr_SendToSamBase);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ /* We only partially implement SendToSam */
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Now 'send' to SAM */
+ switch (base_msg.message_type) {
+ case SendToSamResetBadPasswordCount:
+ {
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ struct ldb_dn *dn = NULL;
+ int ret = 0;
+
+
+ ret = ldb_transaction_start(sam_ctx);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ret = dsdb_find_dn_by_guid(sam_ctx,
+ mem_ctx,
+ &base_msg.message.reset_bad_password.guid,
+ 0,
+ &dn);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (creds->secure_channel_type == SEC_CHAN_RODC &&
+ !sam_rodc_access_check(sam_ctx, mem_ctx, creds->sid, dn)) {
+ DEBUG(1, ("Client asked to reset bad password on "
+ "an arbitrary user: %s\n",
+ ldb_dn_get_linearized(dn)));
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ msg->dn = dn;
+
+ ret = samdb_msg_add_int(sam_ctx, mem_ctx, msg, "badPwdCount", 0);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ret = dsdb_replace(sam_ctx, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ret = ldb_transaction_commit(sam_ctx);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ break;
+ }
+ default:
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct dcesrv_netr_DsRGetDCName_base_state {
+ struct dcesrv_call_state *dce_call;
+ TALLOC_CTX *mem_ctx;
+
+ struct netr_DsRGetDCNameEx2 r;
+ const char *client_site;
+
+ struct {
+ struct netr_DsRGetDCName *dc;
+ struct netr_DsRGetDCNameEx *dcex;
+ struct netr_DsRGetDCNameEx2 *dcex2;
+ } _r;
+};
+
+static void dcesrv_netr_DsRGetDCName_base_done(struct tevent_req *subreq);
+
+static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName_base_state *state)
+{
+ struct dcesrv_call_state *dce_call = state->dce_call;
+ TALLOC_CTX *mem_ctx = state->mem_ctx;
+ struct netr_DsRGetDCNameEx2 *r = &state->r;
+ struct ldb_context *sam_ctx;
+ struct netr_DsRGetDCNameInfo *info;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const struct tsocket_address *local_address;
+ char *local_addr = NULL;
+ const struct tsocket_address *remote_address;
+ char *remote_addr = NULL;
+ const char *server_site_name;
+ char *guid_str;
+ struct netlogon_samlogon_response response;
+ NTSTATUS status;
+ const char *dc_name = NULL;
+ const char *domain_name = NULL;
+ const char *pdc_ip;
+ bool different_domain = true;
+
+ ZERO_STRUCTP(r->out.info);
+
+ sam_ctx = samdb_connect(state,
+ dce_call->event_ctx,
+ lp_ctx,
+ dce_call->conn->auth_state.session_info,
+ dce_call->conn->remote_address,
+ 0);
+ if (sam_ctx == NULL) {
+ return WERR_DS_UNAVAILABLE;
+ }
+
+ local_address = dcesrv_connection_get_local_address(dce_call->conn);
+ if (tsocket_address_is_inet(local_address, "ip")) {
+ local_addr = tsocket_address_inet_addr_string(local_address, state);
+ W_ERROR_HAVE_NO_MEMORY(local_addr);