summaryrefslogtreecommitdiff
path: root/source4/rpc_server/lsa
diff options
context:
space:
mode:
Diffstat (limited to 'source4/rpc_server/lsa')
-rw-r--r--source4/rpc_server/lsa/dcesrv_lsa.c3176
-rw-r--r--source4/rpc_server/lsa/lsa.h68
-rw-r--r--source4/rpc_server/lsa/lsa_init.c243
-rw-r--r--source4/rpc_server/lsa/lsa_lookup.c932
4 files changed, 4419 insertions, 0 deletions
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
new file mode 100644
index 0000000000..a1ca3b4a46
--- /dev/null
+++ b/source4/rpc_server/lsa/dcesrv_lsa.c
@@ -0,0 +1,3176 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the lsarpc pipe
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
+
+ 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 "rpc_server/lsa/lsa.h"
+#include "util/util_ldb.h"
+#include "libcli/ldap/ldap_ndr.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "lib/crypto/crypto.h"
+
+/*
+ this type allows us to distinguish handle types
+*/
+
+/*
+ state associated with a lsa_OpenAccount() operation
+*/
+struct lsa_account_state {
+ struct lsa_policy_state *policy;
+ uint32_t access_mask;
+ struct dom_sid *account_sid;
+};
+
+
+/*
+ state associated with a lsa_OpenSecret() operation
+*/
+struct lsa_secret_state {
+ struct lsa_policy_state *policy;
+ uint32_t access_mask;
+ struct ldb_dn *secret_dn;
+ struct ldb_context *sam_ldb;
+ bool global;
+};
+
+/*
+ state associated with a lsa_OpenTrustedDomain() operation
+*/
+struct lsa_trusted_domain_state {
+ struct lsa_policy_state *policy;
+ uint32_t access_mask;
+ struct ldb_dn *trusted_domain_dn;
+ struct ldb_dn *trusted_domain_user_dn;
+};
+
+static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_EnumAccountRights *r);
+
+static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_policy_state *state,
+ int ldb_flag,
+ struct dom_sid *sid,
+ const struct lsa_RightSet *rights);
+
+/*
+ lsa_Close
+*/
+static NTSTATUS dcesrv_lsa_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_Close *r)
+{
+ struct dcesrv_handle *h;
+
+ *r->out.handle = *r->in.handle;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
+
+ talloc_free(h);
+
+ ZERO_STRUCTP(r->out.handle);
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_Delete
+*/
+static NTSTATUS dcesrv_lsa_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_Delete *r)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+
+/*
+ lsa_DeleteObject
+*/
+static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_DeleteObject *r)
+{
+ struct dcesrv_handle *h;
+ int ret;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
+
+ if (h->wire_handle.handle_type == LSA_HANDLE_SECRET) {
+ struct lsa_secret_state *secret_state = h->data;
+
+ /* Ensure user is permitted to delete this... */
+ switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+ {
+ case SECURITY_SYSTEM:
+ case SECURITY_ADMINISTRATOR:
+ break;
+ default:
+ /* Users and annonymous are not allowed delete things */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ ret = ldb_delete(secret_state->sam_ldb,
+ secret_state->secret_dn);
+ talloc_free(h);
+ if (ret != 0) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ ZERO_STRUCTP(r->out.handle);
+
+ return NT_STATUS_OK;
+ } else if (h->wire_handle.handle_type == LSA_HANDLE_TRUSTED_DOMAIN) {
+ struct lsa_trusted_domain_state *trusted_domain_state = h->data;
+ ret = ldb_transaction_start(trusted_domain_state->policy->sam_ldb);
+ if (ret != 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ ret = ldb_delete(trusted_domain_state->policy->sam_ldb,
+ trusted_domain_state->trusted_domain_dn);
+ if (ret != 0) {
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (trusted_domain_state->trusted_domain_user_dn) {
+ ret = ldb_delete(trusted_domain_state->policy->sam_ldb,
+ trusted_domain_state->trusted_domain_user_dn);
+ if (ret != 0) {
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
+ ret = ldb_transaction_commit(trusted_domain_state->policy->sam_ldb);
+ if (ret != 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ talloc_free(h);
+ ZERO_STRUCTP(r->out.handle);
+
+ return NT_STATUS_OK;
+ } else if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) {
+ struct lsa_RightSet *rights;
+ struct lsa_account_state *astate;
+ struct lsa_EnumAccountRights r2;
+ NTSTATUS status;
+
+ rights = talloc(mem_ctx, struct lsa_RightSet);
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
+
+ astate = h->data;
+
+ r2.in.handle = &astate->policy->handle->wire_handle;
+ r2.in.sid = astate->account_sid;
+ r2.out.rights = rights;
+
+ status = dcesrv_lsa_EnumAccountRights(dce_call, mem_ctx, &r2);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
+ LDB_FLAG_MOD_DELETE, astate->account_sid,
+ r2.out.rights);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ZERO_STRUCTP(r->out.handle);
+ }
+
+ return NT_STATUS_INVALID_HANDLE;
+}
+
+
+/*
+ lsa_EnumPrivs
+*/
+static NTSTATUS dcesrv_lsa_EnumPrivs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_EnumPrivs *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+ int i;
+ const char *privname;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ i = *r->in.resume_handle;
+ if (i == 0) i = 1;
+
+ while ((privname = sec_privilege_name(i)) &&
+ r->out.privs->count < r->in.max_count) {
+ struct lsa_PrivEntry *e;
+
+ r->out.privs->privs = talloc_realloc(r->out.privs,
+ r->out.privs->privs,
+ struct lsa_PrivEntry,
+ r->out.privs->count+1);
+ if (r->out.privs->privs == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ e = &r->out.privs->privs[r->out.privs->count];
+ e->luid.low = i;
+ e->luid.high = 0;
+ e->name.string = privname;
+ r->out.privs->count++;
+ i++;
+ }
+
+ *r->out.resume_handle = i;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_QuerySecObj
+*/
+static NTSTATUS dcesrv_lsa_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_QuerySecurity *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_SetSecObj
+*/
+static NTSTATUS dcesrv_lsa_SetSecObj(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_SetSecObj *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_ChangePassword
+*/
+static NTSTATUS dcesrv_lsa_ChangePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_ChangePassword *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+/*
+ dssetup_DsRoleGetPrimaryDomainInformation
+
+ This is not an LSA call, but is the only call left on the DSSETUP
+ pipe (after the pipe was truncated), and needs lsa_get_policy_state
+*/
+static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleGetPrimaryDomainInformation *r)
+{
+ union dssetup_DsRoleInfo *info;
+
+ info = talloc(mem_ctx, union dssetup_DsRoleInfo);
+ W_ERROR_HAVE_NO_MEMORY(info);
+
+ switch (r->in.level) {
+ case DS_ROLE_BASIC_INFORMATION:
+ {
+ enum dssetup_DsRole role = DS_ROLE_STANDALONE_SERVER;
+ uint32_t flags = 0;
+ const char *domain = NULL;
+ const char *dns_domain = NULL;
+ const char *forest = NULL;
+ struct GUID domain_guid;
+ struct lsa_policy_state *state;
+
+ NTSTATUS status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ntstatus_to_werror(status);
+ }
+
+ ZERO_STRUCT(domain_guid);
+
+ switch (lp_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
+ case ROLE_STANDALONE:
+ role = DS_ROLE_STANDALONE_SERVER;
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ role = DS_ROLE_MEMBER_SERVER;
+ break;
+ case ROLE_DOMAIN_CONTROLLER:
+ if (samdb_is_pdc(state->sam_ldb)) {
+ role = DS_ROLE_PRIMARY_DC;
+ } else {
+ role = DS_ROLE_BACKUP_DC;
+ }
+ break;
+ }
+
+ switch (lp_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
+ case ROLE_STANDALONE:
+ domain = talloc_strdup(mem_ctx, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));
+ W_ERROR_HAVE_NO_MEMORY(domain);
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ domain = talloc_strdup(mem_ctx, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));
+ W_ERROR_HAVE_NO_MEMORY(domain);
+ /* TODO: what is with dns_domain and forest and guid? */
+ break;
+ case ROLE_DOMAIN_CONTROLLER:
+ flags = DS_ROLE_PRIMARY_DS_RUNNING;
+
+ if (state->mixed_domain == 1) {
+ flags |= DS_ROLE_PRIMARY_DS_MIXED_MODE;
+ }
+
+ domain = state->domain_name;
+ dns_domain = state->domain_dns;
+ forest = state->forest_dns;
+
+ domain_guid = state->domain_guid;
+ flags |= DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT;
+ break;
+ }
+
+ info->basic.role = role;
+ info->basic.flags = flags;
+ info->basic.domain = domain;
+ info->basic.dns_domain = dns_domain;
+ info->basic.forest = forest;
+ info->basic.domain_guid = domain_guid;
+
+ r->out.info = info;
+ return WERR_OK;
+ }
+ case DS_ROLE_UPGRADE_STATUS:
+ {
+ info->upgrade.upgrading = DS_ROLE_NOT_UPGRADING;
+ info->upgrade.previous_role = DS_ROLE_PREVIOUS_UNKNOWN;
+
+ r->out.info = info;
+ return WERR_OK;
+ }
+ case DS_ROLE_OP_STATUS:
+ {
+ info->opstatus.status = DS_ROLE_OP_IDLE;
+
+ r->out.info = info;
+ return WERR_OK;
+ }
+ default:
+ return WERR_INVALID_PARAM;
+ }
+
+ return WERR_INVALID_PARAM;
+}
+
+
+/*
+ fill in the AccountDomain info
+*/
+static NTSTATUS dcesrv_lsa_info_AccountDomain(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
+ struct lsa_DomainInfo *info)
+{
+ info->name.string = state->domain_name;
+ info->sid = state->domain_sid;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ fill in the DNS domain info
+*/
+static NTSTATUS dcesrv_lsa_info_DNS(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
+ struct lsa_DnsDomainInfo *info)
+{
+ info->name.string = state->domain_name;
+ info->sid = state->domain_sid;
+ info->dns_domain.string = state->domain_dns;
+ info->dns_forest.string = state->forest_dns;
+ info->domain_guid = state->domain_guid;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_QueryInfoPolicy2
+*/
+static NTSTATUS dcesrv_lsa_QueryInfoPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_QueryInfoPolicy2 *r)
+{
+ struct lsa_policy_state *state;
+ struct dcesrv_handle *h;
+
+ r->out.info = NULL;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ r->out.info = talloc(mem_ctx, union lsa_PolicyInformation);
+ if (!r->out.info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(r->out.info);
+
+ switch (r->in.level) {
+ case LSA_POLICY_INFO_DOMAIN:
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
+ return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &r->out.info->account_domain);
+
+ case LSA_POLICY_INFO_DNS:
+ return dcesrv_lsa_info_DNS(state, mem_ctx, &r->out.info->dns);
+ case LSA_POLICY_INFO_DB:
+ case LSA_POLICY_INFO_AUDIT_FULL_SET:
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_INVALID_INFO_CLASS;
+}
+
+/*
+ lsa_QueryInfoPolicy
+*/
+static NTSTATUS dcesrv_lsa_QueryInfoPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_QueryInfoPolicy *r)
+{
+ struct lsa_QueryInfoPolicy2 r2;
+ NTSTATUS status;
+
+ r2.in.handle = r->in.handle;
+ r2.in.level = r->in.level;
+
+ status = dcesrv_lsa_QueryInfoPolicy2(dce_call, mem_ctx, &r2);
+
+ r->out.info = r2.out.info;
+
+ return status;
+}
+
+/*
+ lsa_SetInfoPolicy
+*/
+static NTSTATUS dcesrv_lsa_SetInfoPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_SetInfoPolicy *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_ClearAuditLog
+*/
+static NTSTATUS dcesrv_lsa_ClearAuditLog(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_ClearAuditLog *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CreateAccount
+
+ This call does not seem to have any long-term effects, hence no database operations
+*/
+static NTSTATUS dcesrv_lsa_CreateAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CreateAccount *r)
+{
+ struct lsa_account_state *astate;
+
+ struct lsa_policy_state *state;
+ struct dcesrv_handle *h, *ah;
+
+ ZERO_STRUCTP(r->out.acct_handle);
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ astate = talloc(dce_call->conn, struct lsa_account_state);
+ if (astate == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ astate->account_sid = dom_sid_dup(astate, r->in.sid);
+ if (astate->account_sid == NULL) {
+ talloc_free(astate);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ astate->policy = talloc_reference(astate, state);
+ astate->access_mask = r->in.access_mask;
+
+ ah = dcesrv_handle_new(dce_call->context, LSA_HANDLE_ACCOUNT);
+ if (!ah) {
+ talloc_free(astate);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ah->data = talloc_steal(ah, astate);
+
+ *r->out.acct_handle = ah->wire_handle;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_EnumAccounts
+*/
+static NTSTATUS dcesrv_lsa_EnumAccounts(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_EnumAccounts *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+ int ret, i;
+ struct ldb_message **res;
+ const char * const attrs[] = { "objectSid", NULL};
+ uint32_t count;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ /* NOTE: This call must only return accounts that have at least
+ one privilege set
+ */
+ ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs,
+ "(&(objectSid=*)(privilege=*))");
+ if (ret < 0) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (*r->in.resume_handle >= ret) {
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ count = ret - *r->in.resume_handle;
+ if (count > r->in.num_entries) {
+ count = r->in.num_entries;
+ }
+
+ if (count == 0) {
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ r->out.sids->sids = talloc_array(r->out.sids, struct lsa_SidPtr, count);
+ if (r->out.sids->sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<count;i++) {
+ r->out.sids->sids[i].sid =
+ samdb_result_dom_sid(r->out.sids->sids,
+ res[i + *r->in.resume_handle],
+ "objectSid");
+ NT_STATUS_HAVE_NO_MEMORY(r->out.sids->sids[i].sid);
+ }
+
+ r->out.sids->num_sids = count;
+ *r->out.resume_handle = count + *r->in.resume_handle;
+
+ return NT_STATUS_OK;
+
+}
+
+
+/*
+ lsa_CreateTrustedDomainEx2
+*/
+static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_CreateTrustedDomainEx2 *r,
+ int op)
+{
+ struct dcesrv_handle *policy_handle;
+ struct lsa_policy_state *policy_state;
+ struct lsa_trusted_domain_state *trusted_domain_state;
+ struct dcesrv_handle *handle;
+ struct ldb_message **msgs, *msg, *msg_user;
+ const char *attrs[] = {
+ NULL
+ };
+ const char *netbios_name;
+ const char *dns_name;
+ const char *name;
+ DATA_BLOB session_key = data_blob(NULL, 0);
+ DATA_BLOB trustAuthIncoming, trustAuthOutgoing, auth_blob;
+ struct trustAuthInAndOutBlob auth_struct;
+ int ret;
+ NTSTATUS nt_status;
+ enum ndr_err_code ndr_err;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.policy_handle, LSA_HANDLE_POLICY);
+ ZERO_STRUCTP(r->out.trustdom_handle);
+
+ policy_state = policy_handle->data;
+
+ nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ netbios_name = r->in.info->netbios_name.string;
+ if (!netbios_name) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ dns_name = r->in.info->domain_name.string;
+
+ trusted_domain_state = talloc(mem_ctx, struct lsa_trusted_domain_state);
+ if (!trusted_domain_state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ trusted_domain_state->policy = policy_state;
+
+ if (strcasecmp(netbios_name, "BUILTIN") == 0
+ || (dns_name && strcasecmp(dns_name, "BUILTIN") == 0)
+ || (dom_sid_in_domain(policy_state->builtin_sid, r->in.info->sid))) {
+ return NT_STATUS_INVALID_PARAMETER;;
+ }
+
+ if (strcasecmp(netbios_name, policy_state->domain_name) == 0
+ || strcasecmp(netbios_name, policy_state->domain_dns) == 0
+ || (dns_name && strcasecmp(dns_name, policy_state->domain_dns) == 0)
+ || (dns_name && strcasecmp(dns_name, policy_state->domain_name) == 0)
+ || (dom_sid_equal(policy_state->domain_sid, r->in.info->sid))) {
+ return NT_STATUS_CURRENT_DOMAIN_NOT_ALLOWED;
+ }
+
+ /* While this is a REF pointer, some of the functions that wrap this don't provide this */
+ if (op == NDR_LSA_CREATETRUSTEDDOMAIN) {
+ /* No secrets are created at this time, for this function */
+ auth_struct.outgoing.count = 0;
+ auth_struct.incoming.count = 0;
+ } else {
+ auth_blob = data_blob_const(r->in.auth_info->auth_blob.data, r->in.auth_info->auth_blob.size);
+ arcfour_crypt_blob(auth_blob.data, auth_blob.length, &session_key);
+ ndr_err = ndr_pull_struct_blob(&auth_blob, mem_ctx,
+ lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
+ &auth_struct,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInAndOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (auth_struct.incoming.count) {
+ ndr_err = ndr_push_struct_blob(&trustAuthIncoming, mem_ctx,
+ lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
+ &auth_struct.incoming,
+ (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ trustAuthIncoming = data_blob(NULL, 0);
+ }
+
+ if (auth_struct.outgoing.count) {
+ ndr_err = ndr_push_struct_blob(&trustAuthOutgoing, mem_ctx,
+ lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
+ &auth_struct.outgoing,
+ (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ trustAuthOutgoing = data_blob(NULL, 0);
+ }
+
+ ret = ldb_transaction_start(policy_state->sam_ldb);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (dns_name) {
+ char *dns_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
+ char *netbios_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
+ /* search for the trusted_domain record */
+ ret = gendb_search(policy_state->sam_ldb,
+ mem_ctx, policy_state->system_dn, &msgs, attrs,
+ "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)(trustPartner=%s))(objectclass=trustedDomain))",
+ dns_encoded, dns_encoded, dns_encoded, netbios_encoded, netbios_encoded, netbios_encoded);
+ if (ret > 0) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+ } else {
+ char *netbios_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
+ /* search for the trusted_domain record */
+ ret = gendb_search(policy_state->sam_ldb,
+ mem_ctx, policy_state->system_dn, &msgs, attrs,
+ "(&(|(flatname=%s)(cn=%s)(trustPartner=%s))(objectclass=trustedDomain))",
+ netbios_encoded, netbios_encoded, netbios_encoded);
+ if (ret > 0) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+ }
+
+ if (ret < 0 ) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ name = dns_name ? dns_name : netbios_name;
+
+ msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg->dn = ldb_dn_copy(mem_ctx, policy_state->system_dn);
+ if ( ! ldb_dn_add_child_fmt(msg->dn, "cn=%s", name)) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "flatname", netbios_name);
+
+ if (r->in.info->sid) {
+ const char *sid_string = dom_sid_string(mem_ctx, r->in.info->sid);
+ if (!sid_string) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "securityIdentifier", sid_string);
+ }
+
+ samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "objectClass", "trustedDomain");
+
+ samdb_msg_add_int(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustType", r->in.info->trust_type);
+
+ samdb_msg_add_int(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustAttributes", r->in.info->trust_attributes);
+
+ samdb_msg_add_int(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustDirection", r->in.info->trust_direction);
+
+ if (dns_name) {
+ samdb_msg_add_string(trusted_domain_state->policy->sam_ldb, mem_ctx, msg, "trustPartner", dns_name);
+ }
+
+ if (trustAuthIncoming.data) {
+ ret = ldb_msg_add_value(msg, "trustAuthIncoming", &trustAuthIncoming, NULL);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ if (trustAuthOutgoing.data) {
+ ret = ldb_msg_add_value(msg, "trustAuthOutgoing", &trustAuthOutgoing, NULL);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msg->dn);
+
+ /* create the trusted_domain */
+ ret = ldb_add(trusted_domain_state->policy->sam_ldb, msg);
+ switch (ret) {
+ case LDB_SUCCESS:
+ break;
+ case LDB_ERR_ENTRY_ALREADY_EXISTS:
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+ return NT_STATUS_DOMAIN_EXISTS;
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+ return NT_STATUS_ACCESS_DENIED;
+ default:
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ DEBUG(0,("Failed to create user record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (r->in.info->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
+ msg_user = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Inbound trusts must also create a cn=users object to match */
+
+ trusted_domain_state->trusted_domain_user_dn = msg_user->dn
+ = ldb_dn_copy(trusted_domain_state, policy_state->domain_dn);
+ if ( ! ldb_dn_add_child_fmt(msg_user->dn, "cn=users")) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if ( ! ldb_dn_add_child_fmt(msg_user->dn, "cn=%s", netbios_name)) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ldb_msg_add_string(msg_user, "objectClass", "user");
+
+ ldb_msg_add_steal_string(msg_user, "samAccountName",
+ talloc_asprintf(mem_ctx, "%s$", netbios_name));
+
+ if (samdb_msg_add_uint(trusted_domain_state->policy->sam_ldb, mem_ctx, msg_user,
+ "userAccountControl",
+ UF_INTERDOMAIN_TRUST_ACCOUNT) != 0) {
+ ldb_transaction_cancel(policy_state->sam_ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (auth_struct.incoming.count) {
+ int i;
+ for (i=0; i < auth_struct.incoming.count; i++ ) {
+ if (auth_struct.incoming.current->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
+ samdb_msg_add_hash(trusted_domain_state->policy->sam_ldb,
+ mem_ctx, msg_user, "unicodePwd",
+ &auth_struct.incoming.current->array[i].AuthInfo.nt4owf.password);
+ } else if (auth_struct.incoming.current->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
+ struct samr_Password hash;
+/*
+ . We cannot do this, as windows chooses to send in random passwords here, that won't convert to UTF8
+ samdb_msg_add_string(trusted_domain_state->policy->sam_ldb,
+ mem_ctx, msg_user, "userPassword",
+ auth_struct.incoming.current->array[i].AuthInfo.clear.password);
+*/
+ mdfour(hash.hash, auth_struct.incoming.current->array[i].AuthInfo.clear.password,
+ auth_struct.incoming.current->array[i].AuthInfo.clear.size);
+ samdb_msg_add_hash(trusted_domain_state->policy->sam_ldb,
+ mem_ctx, msg_user, "unicodePwd",
+ &hash);
+ }
+ }
+ }
+
+ /* create the cn=users trusted_domain account */
+ ret = ldb_add(trusted_domain_state->policy->sam_ldb, msg_user);
+ switch (ret) {
+ case LDB_SUCCESS:
+ break;
+ case LDB_ERR_ENTRY_ALREADY_EXISTS:
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+ ldb_dn_get_linearized(msg_user->dn),
+ ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+ return NT_STATUS_DOMAIN_EXISTS;
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+ ldb_dn_get_linearized(msg_user->dn),
+ ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+ return NT_STATUS_ACCESS_DENIED;
+ default:
+ ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+ DEBUG(0,("Failed to create user record %s: %s\n",
+ ldb_dn_get_linearized(msg_user->dn),
+ ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ }
+
+ ret = ldb_transaction_commit(policy_state->sam_ldb);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_TRUSTED_DOMAIN);
+ if (!handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ handle->data = talloc_steal(handle, trusted_domain_state);
+
+ trusted_domain_state->access_mask = r->in.access_mask;
+ trusted_domain_state->policy = talloc_reference(trusted_domain_state, policy_state);
+
+ *r->out.trustdom_handle = handle->wire_handle;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_CreateTrustedDomainEx2
+*/
+static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx2(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_CreateTrustedDomainEx2 *r)
+{
+ return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, r, NDR_LSA_CREATETRUSTEDDOMAINEX2);
+}
+/*
+ lsa_CreateTrustedDomainEx
+*/
+static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_CreateTrustedDomainEx *r)
+{
+ struct lsa_CreateTrustedDomainEx2 r2;
+
+ r2.in.policy_handle = r->in.policy_handle;
+ r2.in.info = r->in.info;
+ r2.in.auth_info = r->in.auth_info;
+ r2.out.trustdom_handle = r->out.trustdom_handle;
+ return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, &r2, NDR_LSA_CREATETRUSTEDDOMAINEX);
+}
+
+/*
+ lsa_CreateTrustedDomain
+*/
+static NTSTATUS dcesrv_lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CreateTrustedDomain *r)
+{
+ struct lsa_CreateTrustedDomainEx2 r2;
+
+ r2.in.policy_handle = r->in.policy_handle;
+ r2.in.info = talloc(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
+ if (!r2.in.info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r2.in.info->domain_name.string = NULL;
+ r2.in.info->netbios_name = r->in.info->name;
+ r2.in.info->sid = r->in.info->sid;
+ r2.in.info->trust_direction = LSA_TRUST_DIRECTION_OUTBOUND;
+ r2.in.info->trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
+ r2.in.info->trust_attributes = 0;
+
+ r2.in.access_mask = r->in.access_mask;
+ r2.out.trustdom_handle = r->out.trustdom_handle;
+
+ return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, &r2, NDR_LSA_CREATETRUSTEDDOMAIN);
+
+}
+
+/*
+ lsa_OpenTrustedDomain
+*/
+static NTSTATUS dcesrv_lsa_OpenTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_OpenTrustedDomain *r)
+{
+ struct dcesrv_handle *policy_handle;
+
+ struct lsa_policy_state *policy_state;
+ struct lsa_trusted_domain_state *trusted_domain_state;
+ struct dcesrv_handle *handle;
+ struct ldb_message **msgs;
+ const char *attrs[] = {
+ "trustDirection",
+ "flatname",
+ NULL
+ };
+
+ const char *sid_string;
+ int ret;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+ ZERO_STRUCTP(r->out.trustdom_handle);
+ policy_state = policy_handle->data;
+
+ trusted_domain_state = talloc(mem_ctx, struct lsa_trusted_domain_state);
+ if (!trusted_domain_state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ trusted_domain_state->policy = policy_state;
+
+ sid_string = dom_sid_string(mem_ctx, r->in.sid);
+ if (!sid_string) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* search for the trusted_domain record */
+ ret = gendb_search(trusted_domain_state->policy->sam_ldb,
+ mem_ctx, policy_state->system_dn, &msgs, attrs,
+ "(&(securityIdentifier=%s)(objectclass=trustedDomain))",
+ sid_string);
+ if (ret == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (ret != 1) {
+ DEBUG(0,("Found %d records matching DN %s\n", ret,
+ ldb_dn_get_linearized(policy_state->system_dn)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msgs[0]->dn);
+
+ trusted_domain_state->trusted_domain_user_dn = NULL;
+
+ if (ldb_msg_find_attr_as_int(msgs[0], "trustDirection", 0) & LSA_TRUST_DIRECTION_INBOUND) {
+ const char *flatname = ldb_binary_encode_string(mem_ctx, ldb_msg_find_attr_as_string(msgs[0], "flatname", NULL));
+ /* search for the trusted_domain record */
+ ret = gendb_search(trusted_domain_state->policy->sam_ldb,
+ mem_ctx, policy_state->domain_dn, &msgs, attrs,
+ "(&(samaccountname=%s$)(objectclass=user)(userAccountControl:1.2.840.113556.1.4.803:=%d))",
+ flatname, UF_INTERDOMAIN_TRUST_ACCOUNT);
+ if (ret == 1) {
+ trusted_domain_state->trusted_domain_user_dn = talloc_steal(trusted_domain_state, msgs[0]->dn);
+ }
+ }
+ handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_TRUSTED_DOMAIN);
+ if (!handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ handle->data = talloc_steal(handle, trusted_domain_state);
+
+ trusted_domain_state->access_mask = r->in.access_mask;
+ trusted_domain_state->policy = talloc_reference(trusted_domain_state, policy_state);
+
+ *r->out.trustdom_handle = handle->wire_handle;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_OpenTrustedDomainByName
+*/
+static NTSTATUS dcesrv_lsa_OpenTrustedDomainByName(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_OpenTrustedDomainByName *r)
+{
+ struct dcesrv_handle *policy_handle;
+
+ struct lsa_policy_state *policy_state;
+ struct lsa_trusted_domain_state *trusted_domain_state;
+ struct dcesrv_handle *handle;
+ struct ldb_message **msgs;
+ const char *attrs[] = {
+ NULL
+ };
+
+ int ret;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+ ZERO_STRUCTP(r->out.trustdom_handle);
+ policy_state = policy_handle->data;
+
+ if (!r->in.name.string) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ trusted_domain_state = talloc(mem_ctx, struct lsa_trusted_domain_state);
+ if (!trusted_domain_state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ trusted_domain_state->policy = policy_state;
+
+ /* search for the trusted_domain record */
+ ret = gendb_search(trusted_domain_state->policy->sam_ldb,
+ mem_ctx, policy_state->system_dn, &msgs, attrs,
+ "(&(flatname=%s)(objectclass=trustedDomain))",
+ ldb_binary_encode_string(mem_ctx, r->in.name.string));
+ if (ret == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (ret != 1) {
+ DEBUG(0,("Found %d records matching DN %s\n", ret,
+ ldb_dn_get_linearized(policy_state->system_dn)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msgs[0]->dn);
+
+ handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_TRUSTED_DOMAIN);
+ if (!handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ handle->data = talloc_steal(handle, trusted_domain_state);
+
+ trusted_domain_state->access_mask = r->in.access_mask;
+ trusted_domain_state->policy = talloc_reference(trusted_domain_state, policy_state);
+
+ *r->out.trustdom_handle = handle->wire_handle;
+
+ return NT_STATUS_OK;
+}
+
+
+
+/*
+ lsa_SetTrustedDomainInfo
+*/
+static NTSTATUS dcesrv_lsa_SetTrustedDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_SetTrustedDomainInfo *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+
+/*
+ lsa_SetInfomrationTrustedDomain
+*/
+static NTSTATUS dcesrv_lsa_SetInformationTrustedDomain(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_SetInformationTrustedDomain *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_DeleteTrustedDomain
+*/
+static NTSTATUS dcesrv_lsa_DeleteTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_DeleteTrustedDomain *r)
+{
+ NTSTATUS status;
+ struct lsa_OpenTrustedDomain open;
+ struct lsa_DeleteObject delete;
+ struct dcesrv_handle *h;
+
+ open.in.handle = r->in.handle;
+ open.in.sid = r->in.dom_sid;
+ open.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ open.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
+ if (!open.out.trustdom_handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &open);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DCESRV_PULL_HANDLE(h, open.out.trustdom_handle, DCESRV_HANDLE_ANY);
+ talloc_steal(mem_ctx, h);
+
+ delete.in.handle = open.out.trustdom_handle;
+ delete.out.handle = open.out.trustdom_handle;
+ status = dcesrv_lsa_DeleteObject(dce_call, mem_ctx, &delete);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fill_trust_domain_ex(TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg,
+ struct lsa_TrustDomainInfoInfoEx *info_ex)
+{
+ info_ex->domain_name.string
+ = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
+ info_ex->netbios_name.string
+ = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
+ info_ex->sid
+ = samdb_result_dom_sid(mem_ctx, msg, "securityIdentifier");
+ info_ex->trust_direction
+ = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
+ info_ex->trust_type
+ = ldb_msg_find_attr_as_int(msg, "trustType", 0);
+ info_ex->trust_attributes
+ = ldb_msg_find_attr_as_int(msg, "trustAttributes", 0);
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_QueryTrustedDomainInfo
+*/
+static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_QueryTrustedDomainInfo *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_trusted_domain_state *trusted_domain_state;
+ struct ldb_message *msg;
+ int ret;
+ struct ldb_message **res;
+ const char *attrs[] = {
+ "flatname",
+ "trustPartner",
+ "securityIdentifier",
+ "trustDirection",
+ "trustType",
+ "trustAttributes",
+ "msDs-supportedEncryptionTypes",
+ NULL
+ };
+
+ DCESRV_PULL_HANDLE(h, r->in.trustdom_handle, LSA_HANDLE_TRUSTED_DOMAIN);
+
+ trusted_domain_state = h->data;
+
+ /* pull all the user attributes */
+ ret = gendb_search_dn(trusted_domain_state->policy->sam_ldb, mem_ctx,
+ trusted_domain_state->trusted_domain_dn, &res, attrs);
+ if (ret != 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ msg = res[0];
+
+ r->out.info = talloc(mem_ctx, union lsa_TrustedDomainInfo);
+ if (!r->out.info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ switch (r->in.level) {
+ case LSA_TRUSTED_DOMAIN_INFO_NAME:
+ r->out.info->name.netbios_name.string
+ = samdb_result_string(msg, "flatname", NULL);
+ break;
+ case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET:
+ r->out.info->posix_offset.posix_offset
+ = samdb_result_uint(msg, "posixOffset", 0);
+ break;
+#if 0 /* Win2k3 doesn't implement this */
+ case LSA_TRUSTED_DOMAIN_INFO_BASIC:
+ r->out.info->info_basic.netbios_name.string
+ = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
+ r->out.info->info_basic.sid
+ = samdb_result_dom_sid(mem_ctx, msg, "securityIdentifier");
+ break;
+#endif
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX:
+ return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->info_ex);
+
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO:
+ ZERO_STRUCT(r->out.info->full_info);
+ return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->full_info.info_ex);
+
+ case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_2_INTERNAL:
+ ZERO_STRUCT(r->out.info->full_info2_internal);
+ r->out.info->full_info2_internal.posix_offset.posix_offset
+ = samdb_result_uint(msg, "posixOffset", 0);
+ return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->full_info2_internal.info.info_ex);
+
+ case LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRTYPION_TYPES:
+ r->out.info->enc_types.enc_types
+ = samdb_result_uint(msg, "msDs-supportedEncryptionTypes", KERB_ENCTYPE_RC4_HMAC_MD5);
+ break;
+
+ case LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS:
+ case LSA_TRUSTED_DOMAIN_INFO_INFO_EX2_INTERNAL:
+ /* oops, we don't want to return the info after all */
+ talloc_free(r->out.info);
+ r->out.info = NULL;
+ return NT_STATUS_INVALID_PARAMETER;
+ default:
+ /* oops, we don't want to return the info after all */
+ talloc_free(r->out.info);
+ r->out.info = NULL;
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_QueryTrustedDomainInfoBySid
+*/
+static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfoBySid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_QueryTrustedDomainInfoBySid *r)
+{
+ NTSTATUS status;
+ struct lsa_OpenTrustedDomain open;
+ struct lsa_QueryTrustedDomainInfo query;
+ struct dcesrv_handle *h;
+ open.in.handle = r->in.handle;
+ open.in.sid = r->in.dom_sid;
+ open.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ open.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
+ if (!open.out.trustdom_handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &open);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Ensure this handle goes away at the end of this call */
+ DCESRV_PULL_HANDLE(h, open.out.trustdom_handle, DCESRV_HANDLE_ANY);
+ talloc_steal(mem_ctx, h);
+
+ query.in.trustdom_handle = open.out.trustdom_handle;
+ query.in.level = r->in.level;
+ status = dcesrv_lsa_QueryTrustedDomainInfo(dce_call, mem_ctx, &query);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ r->out.info = query.out.info;
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_SetTrustedDomainInfoByName
+*/
+static NTSTATUS dcesrv_lsa_SetTrustedDomainInfoByName(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_SetTrustedDomainInfoByName *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+/*
+ lsa_QueryTrustedDomainInfoByName
+*/
+static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfoByName(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_QueryTrustedDomainInfoByName *r)
+{
+ NTSTATUS status;
+ struct lsa_OpenTrustedDomainByName open;
+ struct lsa_QueryTrustedDomainInfo query;
+ struct dcesrv_handle *h;
+ open.in.handle = r->in.handle;
+ open.in.name = r->in.trusted_domain;
+ open.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ open.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
+ if (!open.out.trustdom_handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = dcesrv_lsa_OpenTrustedDomainByName(dce_call, mem_ctx, &open);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Ensure this handle goes away at the end of this call */
+ DCESRV_PULL_HANDLE(h, open.out.trustdom_handle, DCESRV_HANDLE_ANY);
+ talloc_steal(mem_ctx, h);
+
+ query.in.trustdom_handle = open.out.trustdom_handle;
+ query.in.level = r->in.level;
+ status = dcesrv_lsa_QueryTrustedDomainInfo(dce_call, mem_ctx, &query);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ r->out.info = query.out.info;
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_CloseTrustedDomainEx
+*/
+static NTSTATUS dcesrv_lsa_CloseTrustedDomainEx(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_CloseTrustedDomainEx *r)
+{
+ /* The result of a bad hair day from an IDL programmer? Not
+ * implmented in Win2k3. You should always just lsa_Close
+ * anyway. */
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/*
+ comparison function for sorting lsa_DomainInformation array
+*/
+static int compare_DomainInfo(struct lsa_DomainInfo *e1, struct lsa_DomainInfo *e2)
+{
+ return strcasecmp_m(e1->name.string, e2->name.string);
+}
+
+/*
+ lsa_EnumTrustDom
+*/
+static NTSTATUS dcesrv_lsa_EnumTrustDom(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_EnumTrustDom *r)
+{
+ struct dcesrv_handle *policy_handle;
+ struct lsa_DomainInfo *entries;
+ struct lsa_policy_state *policy_state;
+ struct ldb_message **domains;
+ const char *attrs[] = {
+ "flatname",
+ "securityIdentifier",
+ NULL
+ };
+
+
+ int count, i;
+
+ *r->out.resume_handle = 0;
+
+ r->out.domains->domains = NULL;
+ r->out.domains->count = 0;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+
+ policy_state = policy_handle->data;
+
+ /* search for all users in this domain. This could possibly be cached and
+ resumed based on resume_key */
+ count = gendb_search(policy_state->sam_ldb, mem_ctx, policy_state->system_dn, &domains, attrs,
+ "objectclass=trustedDomain");
+ if (count == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ /* convert to lsa_TrustInformation format */
+ entries = talloc_array(mem_ctx, struct lsa_DomainInfo, count);
+ if (!entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<count;i++) {
+ entries[i].sid = samdb_result_dom_sid(mem_ctx, domains[i], "securityIdentifier");
+ entries[i].name.string = samdb_result_string(domains[i], "flatname", NULL);
+ }
+
+ /* sort the results by name */
+ qsort(entries, count, sizeof(*entries),
+ (comparison_fn_t)compare_DomainInfo);
+
+ if (*r->in.resume_handle >= count) {
+ *r->out.resume_handle = -1;
+
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ /* return the rest, limit by max_size. Note that we
+ use the w2k3 element size value of 60 */
+ r->out.domains->count = count - *r->in.resume_handle;
+ r->out.domains->count = MIN(r->out.domains->count,
+ 1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_MULTIPLIER));
+
+ r->out.domains->domains = entries + *r->in.resume_handle;
+ r->out.domains->count = r->out.domains->count;
+
+ if (r->out.domains->count < count - *r->in.resume_handle) {
+ *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count;
+ return STATUS_MORE_ENTRIES;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ comparison function for sorting lsa_DomainInformation array
+*/
+static int compare_TrustDomainInfoInfoEx(struct lsa_TrustDomainInfoInfoEx *e1, struct lsa_TrustDomainInfoInfoEx *e2)
+{
+ return strcasecmp_m(e1->netbios_name.string, e2->netbios_name.string);
+}
+
+/*
+ lsa_EnumTrustedDomainsEx
+*/
+static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_EnumTrustedDomainsEx *r)
+{
+ struct dcesrv_handle *policy_handle;
+ struct lsa_TrustDomainInfoInfoEx *entries;
+ struct lsa_policy_state *policy_state;
+ struct ldb_message **domains;
+ const char *attrs[] = {
+ "flatname",
+ "trustPartner",
+ "securityIdentifier",
+ "trustDirection",
+ "trustType",
+ "trustAttributes",
+ NULL
+ };
+ NTSTATUS nt_status;
+
+ int count, i;
+
+ *r->out.resume_handle = 0;
+
+ r->out.domains->domains = NULL;
+ r->out.domains->count = 0;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+
+ policy_state = policy_handle->data;
+
+ /* search for all users in this domain. This could possibly be cached and
+ resumed based on resume_key */
+ count = gendb_search(policy_state->sam_ldb, mem_ctx, policy_state->system_dn, &domains, attrs,
+ "objectclass=trustedDomain");
+ if (count == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ /* convert to lsa_DomainInformation format */
+ entries = talloc_array(mem_ctx, struct lsa_TrustDomainInfoInfoEx, count);
+ if (!entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<count;i++) {
+ nt_status = fill_trust_domain_ex(mem_ctx, domains[i], &entries[i]);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+ }
+
+ /* sort the results by name */
+ qsort(entries, count, sizeof(*entries),
+ (comparison_fn_t)compare_TrustDomainInfoInfoEx);
+
+ if (*r->in.resume_handle >= count) {
+ *r->out.resume_handle = -1;
+
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ /* return the rest, limit by max_size. Note that we
+ use the w2k3 element size value of 60 */
+ r->out.domains->count = count - *r->in.resume_handle;
+ r->out.domains->count = MIN(r->out.domains->count,
+ 1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER));
+
+ r->out.domains->domains = entries + *r->in.resume_handle;
+ r->out.domains->count = r->out.domains->count;
+
+ if (r->out.domains->count < count - *r->in.resume_handle) {
+ *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count;
+ return STATUS_MORE_ENTRIES;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_OpenAccount
+*/
+static NTSTATUS dcesrv_lsa_OpenAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_OpenAccount *r)
+{
+ struct dcesrv_handle *h, *ah;
+ struct lsa_policy_state *state;
+ struct lsa_account_state *astate;
+
+ ZERO_STRUCTP(r->out.acct_handle);
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ astate = talloc(dce_call->conn, struct lsa_account_state);
+ if (astate == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ astate->account_sid = dom_sid_dup(astate, r->in.sid);
+ if (astate->account_sid == NULL) {
+ talloc_free(astate);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ astate->policy = talloc_reference(astate, state);
+ astate->access_mask = r->in.access_mask;
+
+ ah = dcesrv_handle_new(dce_call->context, LSA_HANDLE_ACCOUNT);
+ if (!ah) {
+ talloc_free(astate);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ah->data = talloc_steal(ah, astate);
+
+ *r->out.acct_handle = ah->wire_handle;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_EnumPrivsAccount
+*/
+static NTSTATUS dcesrv_lsa_EnumPrivsAccount(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_EnumPrivsAccount *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_account_state *astate;
+ int ret, i;
+ struct ldb_message **res;
+ const char * const attrs[] = { "privilege", NULL};
+ struct ldb_message_element *el;
+ const char *sidstr;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
+
+ astate = h->data;
+
+ r->out.privs = talloc(mem_ctx, struct lsa_PrivilegeSet);
+ r->out.privs->count = 0;
+ r->out.privs->unknown = 0;
+ r->out.privs->set = NULL;
+
+ sidstr = ldap_encode_ndr_dom_sid(mem_ctx, astate->account_sid);
+ if (sidstr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = gendb_search(astate->policy->sam_ldb, mem_ctx, NULL, &res, attrs,
+ "objectSid=%s", sidstr);
+ if (ret != 1) {
+ return NT_STATUS_OK;
+ }
+
+ el = ldb_msg_find_element(res[0], "privilege");
+ if (el == NULL || el->num_values == 0) {
+ return NT_STATUS_OK;
+ }
+
+ r->out.privs->set = talloc_array(r->out.privs,
+ struct lsa_LUIDAttribute, el->num_values);
+ if (r->out.privs->set == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ int id = sec_privilege_id((const char *)el->values[i].data);
+ if (id == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ r->out.privs->set[i].attribute = 0;
+ r->out.privs->set[i].luid.low = id;
+ r->out.privs->set[i].luid.high = 0;
+ }
+
+ r->out.privs->count = el->num_values;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_EnumAccountRights
+*/
+static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_EnumAccountRights *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+ int ret, i;
+ struct ldb_message **res;
+ const char * const attrs[] = { "privilege", NULL};
+ const char *sidstr;
+ struct ldb_message_element *el;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ sidstr = ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid);
+ if (sidstr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs,
+ "(&(objectSid=%s)(privilege=*))", sidstr);
+ if (ret == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ if (ret > 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ if (ret == -1) {
+ DEBUG(3, ("searching for account rights for SID: %s failed: %s",
+ dom_sid_string(mem_ctx, r->in.sid),
+ ldb_errstring(state->sam_ldb)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ el = ldb_msg_find_element(res[0], "privilege");
+ if (el == NULL || el->num_values == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ r->out.rights->count = el->num_values;
+ r->out.rights->names = talloc_array(r->out.rights,
+ struct lsa_StringLarge, r->out.rights->count);
+ if (r->out.rights->names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ r->out.rights->names[i].string = (const char *)el->values[i].data;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+
+/*
+ helper for lsa_AddAccountRights and lsa_RemoveAccountRights
+*/
+static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_policy_state *state,
+ int ldb_flag,
+ struct dom_sid *sid,
+ const struct lsa_RightSet *rights)
+{
+ const char *sidstr;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ int i, ret;
+ struct lsa_EnumAccountRights r2;
+
+ sidstr = ldap_encode_ndr_dom_sid(mem_ctx, sid);
+ if (sidstr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg->dn = samdb_search_dn(state->sam_ldb, mem_ctx,
+ NULL, "objectSid=%s", sidstr);
+ if (msg->dn == NULL) {
+ NTSTATUS status;
+ if (ldb_flag == LDB_FLAG_MOD_DELETE) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ status = samdb_create_foreign_security_principal(state->sam_ldb, mem_ctx,
+ sid, &msg->dn);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ if (ldb_msg_add_empty(msg, "privilege", ldb_flag, NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ldb_flag == LDB_FLAG_MOD_ADD) {
+ NTSTATUS status;
+
+ r2.in.handle = &state->handle->wire_handle;
+ r2.in.sid = sid;
+ r2.out.rights = talloc(mem_ctx, struct lsa_RightSet);
+
+ status = dcesrv_lsa_EnumAccountRights(dce_call, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ ZERO_STRUCTP(r2.out.rights);
+ }
+ }
+
+ for (i=0;i<rights->count;i++) {
+ if (sec_privilege_id(rights->names[i].string) == -1) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ if (ldb_flag == LDB_FLAG_MOD_ADD) {
+ int j;
+ for (j=0;j<r2.out.rights->count;j++) {
+ if (strcasecmp_m(r2.out.rights->names[j].string,
+ rights->names[i].string) == 0) {
+ break;
+ }
+ }
+ if (j != r2.out.rights->count) continue;
+ }
+
+ ret = ldb_msg_add_string(msg, "privilege", rights->names[i].string);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ el = ldb_msg_find_element(msg, "privilege");
+ if (!el) {
+ return NT_STATUS_OK;
+ }
+
+ ret = ldb_modify(state->sam_ldb, msg);
+ if (ret != 0) {
+ if (ldb_flag == LDB_FLAG_MOD_DELETE && ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ DEBUG(3, ("Could not %s attributes from %s: %s",
+ ldb_flag == LDB_FLAG_MOD_DELETE ? "delete" : "add",
+ ldb_dn_get_linearized(msg->dn), ldb_errstring(state->sam_ldb)));
+ return NT_STATUS_UNEXPECTED_IO_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_AddPrivilegesToAccount
+*/
+static NTSTATUS dcesrv_lsa_AddPrivilegesToAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_AddPrivilegesToAccount *r)
+{
+ struct lsa_RightSet rights;
+ struct dcesrv_handle *h;
+ struct lsa_account_state *astate;
+ int i;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
+
+ astate = h->data;
+
+ rights.count = r->in.privs->count;
+ rights.names = talloc_array(mem_ctx, struct lsa_StringLarge, rights.count);
+ if (rights.names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<rights.count;i++) {
+ int id = r->in.privs->set[i].luid.low;
+ if (r->in.privs->set[i].luid.high) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+ rights.names[i].string = sec_privilege_name(id);
+ if (rights.names[i].string == NULL) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+ }
+
+ return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
+ LDB_FLAG_MOD_ADD, astate->account_sid,
+ &rights);
+}
+
+
+/*
+ lsa_RemovePrivilegesFromAccount
+*/
+static NTSTATUS dcesrv_lsa_RemovePrivilegesFromAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_RemovePrivilegesFromAccount *r)
+{
+ struct lsa_RightSet *rights;
+ struct dcesrv_handle *h;
+ struct lsa_account_state *astate;
+ int i;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
+
+ astate = h->data;
+
+ rights = talloc(mem_ctx, struct lsa_RightSet);
+
+ if (r->in.remove_all == 1 &&
+ r->in.privs == NULL) {
+ struct lsa_EnumAccountRights r2;
+ NTSTATUS status;
+
+ r2.in.handle = &astate->policy->handle->wire_handle;
+ r2.in.sid = astate->account_sid;
+ r2.out.rights = rights;
+
+ status = dcesrv_lsa_EnumAccountRights(dce_call, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
+ LDB_FLAG_MOD_DELETE, astate->account_sid,
+ r2.out.rights);
+ }
+
+ if (r->in.remove_all != 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ rights->count = r->in.privs->count;
+ rights->names = talloc_array(mem_ctx, struct lsa_StringLarge, rights->count);
+ if (rights->names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<rights->count;i++) {
+ int id = r->in.privs->set[i].luid.low;
+ if (r->in.privs->set[i].luid.high) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+ rights->names[i].string = sec_privilege_name(id);
+ if (rights->names[i].string == NULL) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+ }
+
+ return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
+ LDB_FLAG_MOD_DELETE, astate->account_sid,
+ rights);
+}
+
+
+/*
+ lsa_GetQuotasForAccount
+*/
+static NTSTATUS dcesrv_lsa_GetQuotasForAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_GetQuotasForAccount *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_SetQuotasForAccount
+*/
+static NTSTATUS dcesrv_lsa_SetQuotasForAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_SetQuotasForAccount *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_GetSystemAccessAccount
+*/
+static NTSTATUS dcesrv_lsa_GetSystemAccessAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_GetSystemAccessAccount *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_SetSystemAccessAccount
+*/
+static NTSTATUS dcesrv_lsa_SetSystemAccessAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_SetSystemAccessAccount *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CreateSecret
+*/
+static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CreateSecret *r)
+{
+ struct dcesrv_handle *policy_handle;
+ struct lsa_policy_state *policy_state;
+ struct lsa_secret_state *secret_state;
+ struct dcesrv_handle *handle;
+ struct ldb_message **msgs, *msg;
+ const char *errstr;
+ const char *attrs[] = {
+ NULL
+ };
+
+ const char *name;
+
+ int ret;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+ ZERO_STRUCTP(r->out.sec_handle);
+
+ switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+ {
+ case SECURITY_SYSTEM:
+ case SECURITY_ADMINISTRATOR:
+ break;
+ default:
+ /* Users and annonymous are not allowed create secrets */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ policy_state = policy_handle->data;
+
+ if (!r->in.name.string) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ secret_state = talloc(mem_ctx, struct lsa_secret_state);
+ if (!secret_state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ secret_state->policy = policy_state;
+
+ msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (strncmp("G$", r->in.name.string, 2) == 0) {
+ const char *name2;
+ name = &r->in.name.string[2];
+ /* We need to connect to the database as system, as this is one of the rare RPC calls that must read the secrets (and this is denied otherwise) */
+ secret_state->sam_ldb = talloc_reference(secret_state,
+ samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(secret_state, dce_call->conn->dce_ctx->lp_ctx)));
+ secret_state->global = true;
+
+ if (strlen(name) < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ name2 = talloc_asprintf(mem_ctx, "%s Secret", ldb_binary_encode_string(mem_ctx, name));
+ /* search for the secret record */
+ ret = gendb_search(secret_state->sam_ldb,
+ mem_ctx, policy_state->system_dn, &msgs, attrs,
+ "(&(cn=%s)(objectclass=secret))",
+ name2);
+ if (ret > 0) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if (ret == -1) {
+ DEBUG(0,("Failure searching for CN=%s: %s\n",
+ name2, ldb_errstring(secret_state->sam_ldb)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ msg->dn = ldb_dn_copy(mem_ctx, policy_state->system_dn);
+ if (!name2 || ! ldb_dn_add_child_fmt(msg->dn, "cn=%s", name2)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ samdb_msg_add_string(secret_state->sam_ldb, mem_ctx, msg, "cn", name2);
+
+ } else {
+ secret_state->global = false;
+
+ name = r->in.name.string;
+ if (strlen(name) < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ secret_state->sam_ldb = talloc_reference(secret_state,
+ secrets_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx));
+ /* search for the secret record */
+ ret = gendb_search(secret_state->sam_ldb, mem_ctx,
+ ldb_dn_new(mem_ctx, secret_state->sam_ldb, "cn=LSA Secrets"),
+ &msgs, attrs,
+ "(&(cn=%s)(objectclass=secret))",
+ ldb_binary_encode_string(mem_ctx, name));
+ if (ret > 0) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if (ret == -1) {
+ DEBUG(0,("Failure searching for CN=%s: %s\n",
+ name, ldb_errstring(secret_state->sam_ldb)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ msg->dn = ldb_dn_new_fmt(mem_ctx, secret_state->sam_ldb, "cn=%s,cn=LSA Secrets", name);
+ samdb_msg_add_string(secret_state->sam_ldb, mem_ctx, msg, "cn", name);
+ }
+
+ /* pull in all the template attributes. Note this is always from the global samdb */
+ ret = samdb_copy_template(secret_state->policy->sam_ldb, msg,
+ "secret", &errstr);
+ if (ret != 0) {
+ DEBUG(0,("Failed to load TemplateSecret from samdb: %s\n",
+ errstr));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ samdb_msg_add_string(secret_state->sam_ldb, mem_ctx, msg, "objectClass", "secret");
+
+ secret_state->secret_dn = talloc_reference(secret_state, msg->dn);
+
+ /* create the secret */
+ ret = ldb_add(secret_state->sam_ldb, msg);
+ if (ret != 0) {
+ DEBUG(0,("Failed to create secret record %s: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ ldb_errstring(secret_state->sam_ldb)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_SECRET);
+ if (!handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ handle->data = talloc_steal(handle, secret_state);
+
+ secret_state->access_mask = r->in.access_mask;
+ secret_state->policy = talloc_reference(secret_state, policy_state);
+
+ *r->out.sec_handle = handle->wire_handle;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_OpenSecret
+*/
+static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_OpenSecret *r)
+{
+ struct dcesrv_handle *policy_handle;
+
+ struct lsa_policy_state *policy_state;
+ struct lsa_secret_state *secret_state;
+ struct dcesrv_handle *handle;
+ struct ldb_message **msgs;
+ const char *attrs[] = {
+ NULL
+ };
+
+ const char *name;
+
+ int ret;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+ ZERO_STRUCTP(r->out.sec_handle);
+ policy_state = policy_handle->data;
+
+ if (!r->in.name.string) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+ {
+ case SECURITY_SYSTEM:
+ case SECURITY_ADMINISTRATOR:
+ break;
+ default:
+ /* Users and annonymous are not allowed to access secrets */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ secret_state = talloc(mem_ctx, struct lsa_secret_state);
+ if (!secret_state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ secret_state->policy = policy_state;
+
+ if (strncmp("G$", r->in.name.string, 2) == 0) {
+ name = &r->in.name.string[2];
+ /* We need to connect to the database as system, as this is one of the rare RPC calls that must read the secrets (and this is denied otherwise) */
+ secret_state->sam_ldb = talloc_reference(secret_state,
+ samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(secret_state, dce_call->conn->dce_ctx->lp_ctx)));
+ secret_state->global = true;
+
+ if (strlen(name) < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* search for the secret record */
+ ret = gendb_search(secret_state->sam_ldb,
+ mem_ctx, policy_state->system_dn, &msgs, attrs,
+ "(&(cn=%s Secret)(objectclass=secret))",
+ ldb_binary_encode_string(mem_ctx, name));
+ if (ret == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (ret != 1) {
+ DEBUG(0,("Found %d records matching DN %s\n", ret,
+ ldb_dn_get_linearized(policy_state->system_dn)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ } else {
+ secret_state->global = false;
+ secret_state->sam_ldb = talloc_reference(secret_state,
+ secrets_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx));
+
+ name = r->in.name.string;
+ if (strlen(name) < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* search for the secret record */
+ ret = gendb_search(secret_state->sam_ldb, mem_ctx,
+ ldb_dn_new(mem_ctx, secret_state->sam_ldb, "cn=LSA Secrets"),
+ &msgs, attrs,
+ "(&(cn=%s)(objectclass=secret))",
+ ldb_binary_encode_string(mem_ctx, name));
+ if (ret == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (ret != 1) {
+ DEBUG(0,("Found %d records matching CN=%s\n",
+ ret, ldb_binary_encode_string(mem_ctx, name)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ }
+
+ secret_state->secret_dn = talloc_reference(secret_state, msgs[0]->dn);
+
+ handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_SECRET);
+ if (!handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ handle->data = talloc_steal(handle, secret_state);
+
+ secret_state->access_mask = r->in.access_mask;
+ secret_state->policy = talloc_reference(secret_state, policy_state);
+
+ *r->out.sec_handle = handle->wire_handle;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_SetSecret
+*/
+static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_SetSecret *r)
+{
+
+ struct dcesrv_handle *h;
+ struct lsa_secret_state *secret_state;
+ struct ldb_message *msg;
+ DATA_BLOB session_key;
+ DATA_BLOB crypt_secret, secret;
+ struct ldb_val val;
+ int ret;
+ NTSTATUS status = NT_STATUS_OK;
+
+ struct timeval now = timeval_current();
+ NTTIME nt_now = timeval_to_nttime(&now);
+
+ DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
+
+ secret_state = h->data;
+
+ msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg->dn = talloc_reference(mem_ctx, secret_state->secret_dn);
+ if (!msg->dn) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (r->in.old_val) {
+ /* Decrypt */
+ crypt_secret.data = r->in.old_val->data;
+ crypt_secret.length = r->in.old_val->size;
+
+ status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ val.data = secret.data;
+ val.length = secret.length;
+
+ /* set value */
+ if (samdb_msg_add_value(secret_state->sam_ldb,
+ mem_ctx, msg, "priorValue", &val) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* set old value mtime */
+ if (samdb_msg_add_uint64(secret_state->sam_ldb,
+ mem_ctx, msg, "priorSetTime", nt_now) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ } else {
+ /* If the old value is not set, then migrate the
+ * current value to the old value */
+ const struct ldb_val *old_val;
+ NTTIME last_set_time;
+ struct ldb_message **res;
+ const char *attrs[] = {
+ "currentValue",
+ "lastSetTime",
+ NULL
+ };
+
+ /* search for the secret record */
+ ret = gendb_search_dn(secret_state->sam_ldb,mem_ctx,
+ secret_state->secret_dn, &res, attrs);
+ if (ret == 0) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (ret != 1) {
+ DEBUG(0,("Found %d records matching dn=%s\n", ret,
+ ldb_dn_get_linearized(secret_state->secret_dn)));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ old_val = ldb_msg_find_ldb_val(res[0], "currentValue");
+ last_set_time = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);
+
+ if (old_val) {
+ /* set old value */
+ if (samdb_msg_add_value(secret_state->sam_ldb,
+ mem_ctx, msg, "priorValue",
+ old_val) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ if (samdb_msg_add_delete(secret_state->sam_ldb,
+ mem_ctx, msg, "priorValue")) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ }
+
+ /* set old value mtime */
+ if (ldb_msg_find_ldb_val(res[0], "lastSetTime")) {
+ if (samdb_msg_add_uint64(secret_state->sam_ldb,
+ mem_ctx, msg, "priorSetTime", last_set_time) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ if (samdb_msg_add_uint64(secret_state->sam_ldb,
+ mem_ctx, msg, "priorSetTime", nt_now) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+
+ if (r->in.new_val) {
+ /* Decrypt */
+ crypt_secret.data = r->in.new_val->data;
+ crypt_secret.length = r->in.new_val->size;
+
+ status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ val.data = secret.data;
+ val.length = secret.length;
+
+ /* set value */
+ if (samdb_msg_add_value(secret_state->sam_ldb,
+ mem_ctx, msg, "currentValue", &val) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* set new value mtime */
+ if (samdb_msg_add_uint64(secret_state->sam_ldb,
+ mem_ctx, msg, "lastSetTime", nt_now) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ } else {
+ /* NULL out the NEW value */
+ if (samdb_msg_add_uint64(secret_state->sam_ldb,
+ mem_ctx, msg, "lastSetTime", nt_now) != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (samdb_msg_add_delete(secret_state->sam_ldb,
+ mem_ctx, msg, "currentValue")) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ /* modify the samdb record */
+ ret = samdb_replace(secret_state->sam_ldb, mem_ctx, msg);
+ if (ret != 0) {
+ /* we really need samdb.c to return NTSTATUS */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_QuerySecret
+*/
+static NTSTATUS dcesrv_lsa_QuerySecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_QuerySecret *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_secret_state *secret_state;
+ struct ldb_message *msg;
+ DATA_BLOB session_key;
+ DATA_BLOB crypt_secret, secret;
+ int ret;
+ struct ldb_message **res;
+ const char *attrs[] = {
+ "currentValue",
+ "priorValue",
+ "lastSetTime",
+ "priorSetTime",
+ NULL
+ };
+
+ NTSTATUS nt_status;
+
+ DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
+
+ /* Ensure user is permitted to read this... */
+ switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+ {
+ case SECURITY_SYSTEM:
+ case SECURITY_ADMINISTRATOR:
+ break;
+ default:
+ /* Users and annonymous are not allowed to read secrets */
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ secret_state = h->data;
+
+ /* pull all the user attributes */
+ ret = gendb_search_dn(secret_state->sam_ldb, mem_ctx,
+ secret_state->secret_dn, &res, attrs);
+ if (ret != 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ msg = res[0];
+
+ nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ if (r->in.old_val) {
+ const struct ldb_val *prior_val;
+ r->out.old_val = talloc_zero(mem_ctx, struct lsa_DATA_BUF_PTR);
+ if (!r->out.old_val) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ prior_val = ldb_msg_find_ldb_val(res[0], "priorValue");
+
+ if (prior_val && prior_val->length) {
+ secret.data = prior_val->data;
+ secret.length = prior_val->length;
+
+ /* Encrypt */
+ crypt_secret = sess_encrypt_blob(mem_ctx, &secret, &session_key);
+ if (!crypt_secret.length) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.old_val->buf = talloc(mem_ctx, struct lsa_DATA_BUF);
+ if (!r->out.old_val->buf) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.old_val->buf->size = crypt_secret.length;
+ r->out.old_val->buf->length = crypt_secret.length;
+ r->out.old_val->buf->data = crypt_secret.data;
+ }
+ }
+
+ if (r->in.old_mtime) {
+ r->out.old_mtime = talloc(mem_ctx, NTTIME);
+ if (!r->out.old_mtime) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *r->out.old_mtime = ldb_msg_find_attr_as_uint64(res[0], "priorSetTime", 0);
+ }
+
+ if (r->in.new_val) {
+ const struct ldb_val *new_val;
+ r->out.new_val = talloc_zero(mem_ctx, struct lsa_DATA_BUF_PTR);
+ if (!r->out.new_val) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ new_val = ldb_msg_find_ldb_val(res[0], "currentValue");
+
+ if (new_val && new_val->length) {
+ secret.data = new_val->data;
+ secret.length = new_val->length;
+
+ /* Encrypt */
+ crypt_secret = sess_encrypt_blob(mem_ctx, &secret, &session_key);
+ if (!crypt_secret.length) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.new_val->buf = talloc(mem_ctx, struct lsa_DATA_BUF);
+ if (!r->out.new_val->buf) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.new_val->buf->length = crypt_secret.length;
+ r->out.new_val->buf->size = crypt_secret.length;
+ r->out.new_val->buf->data = crypt_secret.data;
+ }
+ }
+
+ if (r->in.new_mtime) {
+ r->out.new_mtime = talloc(mem_ctx, NTTIME);
+ if (!r->out.new_mtime) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *r->out.new_mtime = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_LookupPrivValue
+*/
+static NTSTATUS dcesrv_lsa_LookupPrivValue(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupPrivValue *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+ int id;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ id = sec_privilege_id(r->in.name->string);
+ if (id == -1) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ r->out.luid->low = id;
+ r->out.luid->high = 0;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_LookupPrivName
+*/
+static NTSTATUS dcesrv_lsa_LookupPrivName(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupPrivName *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+ const char *privname;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ if (r->in.luid->high != 0) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ privname = sec_privilege_name(r->in.luid->low);
+ if (privname == NULL) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ r->out.name = talloc(mem_ctx, struct lsa_StringLarge);
+ if (r->out.name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.name->string = privname;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_LookupPrivDisplayName
+*/
+static NTSTATUS dcesrv_lsa_LookupPrivDisplayName(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupPrivDisplayName *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+ int id;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ id = sec_privilege_id(r->in.name->string);
+ if (id == -1) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ r->out.disp_name = talloc(mem_ctx, struct lsa_StringLarge);
+ if (r->out.disp_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->out.disp_name->string = sec_privilege_display_name(id, r->in.language_id);
+ if (r->out.disp_name->string == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_EnumAccountsWithUserRight
+*/
+static NTSTATUS dcesrv_lsa_EnumAccountsWithUserRight(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_EnumAccountsWithUserRight *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+ int ret, i;
+ struct ldb_message **res;
+ const char * const attrs[] = { "objectSid", NULL};
+ const char *privname;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ if (r->in.name == NULL) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ privname = r->in.name->string;
+ if (sec_privilege_id(privname) == -1) {
+ return NT_STATUS_NO_SUCH_PRIVILEGE;
+ }
+
+ ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs,
+ "privilege=%s", privname);
+ if (ret == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ if (ret == 0) {
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+
+ r->out.sids->sids = talloc_array(r->out.sids, struct lsa_SidPtr, ret);
+ if (r->out.sids->sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<ret;i++) {
+ r->out.sids->sids[i].sid = samdb_result_dom_sid(r->out.sids->sids,
+ res[i], "objectSid");
+ NT_STATUS_HAVE_NO_MEMORY(r->out.sids->sids[i].sid);
+ }
+ r->out.sids->num_sids = ret;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_AddAccountRights
+*/
+static NTSTATUS dcesrv_lsa_AddAccountRights(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_AddAccountRights *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, state,
+ LDB_FLAG_MOD_ADD,
+ r->in.sid, r->in.rights);
+}
+
+
+/*
+ lsa_RemoveAccountRights
+*/
+static NTSTATUS dcesrv_lsa_RemoveAccountRights(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_RemoveAccountRights *r)
+{
+ struct dcesrv_handle *h;
+ struct lsa_policy_state *state;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, state,
+ LDB_FLAG_MOD_DELETE,
+ r->in.sid, r->in.rights);
+}
+
+
+/*
+ lsa_StorePrivateData
+*/
+static NTSTATUS dcesrv_lsa_StorePrivateData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_StorePrivateData *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_RetrievePrivateData
+*/
+static NTSTATUS dcesrv_lsa_RetrievePrivateData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_RetrievePrivateData *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_GetUserName
+*/
+static NTSTATUS dcesrv_lsa_GetUserName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_GetUserName *r)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ const char *account_name;
+ const char *authority_name;
+ struct lsa_String *_account_name;
+ struct lsa_StringPointer *_authority_name = NULL;
+
+ /* this is what w2k3 does */
+ r->out.account_name = r->in.account_name;
+ r->out.authority_name = r->in.authority_name;
+
+ if (r->in.account_name && r->in.account_name->string) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (r->in.authority_name &&
+ r->in.authority_name->string &&
+ r->in.authority_name->string->string) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ account_name = talloc_reference(mem_ctx, dce_call->conn->auth_state.session_info->server_info->account_name);
+ authority_name = talloc_reference(mem_ctx, dce_call->conn->auth_state.session_info->server_info->domain_name);
+
+ _account_name = talloc(mem_ctx, struct lsa_String);
+ NT_STATUS_HAVE_NO_MEMORY(_account_name);
+ _account_name->string = account_name;
+
+ if (r->in.authority_name) {
+ _authority_name = talloc(mem_ctx, struct lsa_StringPointer);
+ NT_STATUS_HAVE_NO_MEMORY(_authority_name);
+ _authority_name->string = talloc(mem_ctx, struct lsa_String);
+ NT_STATUS_HAVE_NO_MEMORY(_authority_name->string);
+ _authority_name->string->string = authority_name;
+ }
+
+ r->out.account_name = _account_name;
+ r->out.authority_name = _authority_name;
+
+ return status;
+}
+
+/*
+ lsa_SetInfoPolicy2
+*/
+static NTSTATUS dcesrv_lsa_SetInfoPolicy2(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_SetInfoPolicy2 *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+/*
+ lsa_QueryDomainInformationPolicy
+*/
+static NTSTATUS dcesrv_lsa_QueryDomainInformationPolicy(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_QueryDomainInformationPolicy *r)
+{
+ r->out.info = talloc(mem_ctx, union lsa_DomainInformationPolicy);
+ if (!r->out.info) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (r->in.level) {
+ case LSA_DOMAIN_INFO_POLICY_EFS:
+ talloc_free(r->out.info);
+ r->out.info = NULL;
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ case LSA_DOMAIN_INFO_POLICY_KERBEROS:
+ {
+ struct lsa_DomainInfoKerberos *k = &r->out.info->kerberos_info;
+ struct smb_krb5_context *smb_krb5_context;
+ int ret = smb_krb5_init_context(mem_ctx,
+ dce_call->event_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
+ &smb_krb5_context);
+ if (ret != 0) {
+ talloc_free(r->out.info);
+ r->out.info = NULL;
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ k->enforce_restrictions = 0; /* FIXME, details missing from MS-LSAD 2.2.53 */
+ k->service_tkt_lifetime = 0; /* Need to find somewhere to store this, and query in KDC too */
+ k->user_tkt_lifetime = 0; /* Need to find somewhere to store this, and query in KDC too */
+ k->user_tkt_renewaltime = 0; /* Need to find somewhere to store this, and query in KDC too */
+ k->clock_skew = krb5_get_max_time_skew(smb_krb5_context->krb5_context);
+ talloc_free(smb_krb5_context);
+ return NT_STATUS_OK;
+ }
+ default:
+ talloc_free(r->out.info);
+ r->out.info = NULL;
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+}
+
+/*
+ lsa_SetDomInfoPolicy
+*/
+static NTSTATUS dcesrv_lsa_SetDomainInformationPolicy(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_SetDomainInformationPolicy *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+/*
+ lsa_TestCall
+*/
+static NTSTATUS dcesrv_lsa_TestCall(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_TestCall *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+/*
+ lsa_CREDRWRITE
+*/
+static NTSTATUS dcesrv_lsa_CREDRWRITE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRWRITE *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRREAD
+*/
+static NTSTATUS dcesrv_lsa_CREDRREAD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRREAD *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRENUMERATE
+*/
+static NTSTATUS dcesrv_lsa_CREDRENUMERATE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRENUMERATE *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRWRITEDOMAINCREDENTIALS
+*/
+static NTSTATUS dcesrv_lsa_CREDRWRITEDOMAINCREDENTIALS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRWRITEDOMAINCREDENTIALS *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRREADDOMAINCREDENTIALS
+*/
+static NTSTATUS dcesrv_lsa_CREDRREADDOMAINCREDENTIALS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRREADDOMAINCREDENTIALS *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRDELETE
+*/
+static NTSTATUS dcesrv_lsa_CREDRDELETE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRDELETE *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRGETTARGETINFO
+*/
+static NTSTATUS dcesrv_lsa_CREDRGETTARGETINFO(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRGETTARGETINFO *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRPROFILELOADED
+*/
+static NTSTATUS dcesrv_lsa_CREDRPROFILELOADED(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRPROFILELOADED *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRGETSESSIONTYPES
+*/
+static NTSTATUS dcesrv_lsa_CREDRGETSESSIONTYPES(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRGETSESSIONTYPES *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_LSARREGISTERAUDITEVENT
+*/
+static NTSTATUS dcesrv_lsa_LSARREGISTERAUDITEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSARREGISTERAUDITEVENT *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_LSARGENAUDITEVENT
+*/
+static NTSTATUS dcesrv_lsa_LSARGENAUDITEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSARGENAUDITEVENT *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_LSARUNREGISTERAUDITEVENT
+*/
+static NTSTATUS dcesrv_lsa_LSARUNREGISTERAUDITEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSARUNREGISTERAUDITEVENT *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_lsaRQueryForestTrustInformation
+*/
+static NTSTATUS dcesrv_lsa_lsaRQueryForestTrustInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_lsaRQueryForestTrustInformation *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_LSARSETFORESTTRUSTINFORMATION
+*/
+static NTSTATUS dcesrv_lsa_LSARSETFORESTTRUSTINFORMATION(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSARSETFORESTTRUSTINFORMATION *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_CREDRRENAME
+*/
+static NTSTATUS dcesrv_lsa_CREDRRENAME(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_CREDRRENAME *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+
+/*
+ lsa_LSAROPENPOLICYSCE
+*/
+static NTSTATUS dcesrv_lsa_LSAROPENPOLICYSCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSAROPENPOLICYSCE *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_LSARADTREGISTERSECURITYEVENTSOURCE
+*/
+static NTSTATUS dcesrv_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE
+*/
+static NTSTATUS dcesrv_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ lsa_LSARADTREPORTSECURITYEVENT
+*/
+static NTSTATUS dcesrv_lsa_LSARADTREPORTSECURITYEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LSARADTREPORTSECURITYEVENT *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_lsa_s.c"
+
+
+
+/*****************************************
+NOTE! The remaining calls below were
+removed in w2k3, so the DCESRV_FAULT()
+replies are the correct implementation. Do
+not try and fill these in with anything else
+******************************************/
+
+/*
+ dssetup_DsRoleDnsNameToFlatName
+*/
+static WERROR dcesrv_dssetup_DsRoleDnsNameToFlatName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleDnsNameToFlatName *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleDcAsDc
+*/
+static WERROR dcesrv_dssetup_DsRoleDcAsDc(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleDcAsDc *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleDcAsReplica
+*/
+static WERROR dcesrv_dssetup_DsRoleDcAsReplica(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleDcAsReplica *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleDemoteDc
+*/
+static WERROR dcesrv_dssetup_DsRoleDemoteDc(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleDemoteDc *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleGetDcOperationProgress
+*/
+static WERROR dcesrv_dssetup_DsRoleGetDcOperationProgress(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleGetDcOperationProgress *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleGetDcOperationResults
+*/
+static WERROR dcesrv_dssetup_DsRoleGetDcOperationResults(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleGetDcOperationResults *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleCancel
+*/
+static WERROR dcesrv_dssetup_DsRoleCancel(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleCancel *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleServerSaveStateForUpgrade
+*/
+static WERROR dcesrv_dssetup_DsRoleServerSaveStateForUpgrade(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleServerSaveStateForUpgrade *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleUpgradeDownlevelServer
+*/
+static WERROR dcesrv_dssetup_DsRoleUpgradeDownlevelServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleUpgradeDownlevelServer *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/*
+ dssetup_DsRoleAbortDownlevelServerUpgrade
+*/
+static WERROR dcesrv_dssetup_DsRoleAbortDownlevelServerUpgrade(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct dssetup_DsRoleAbortDownlevelServerUpgrade *r)
+{
+ DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+}
+
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_dssetup_s.c"
+
+NTSTATUS dcerpc_server_lsa_init(void)
+{
+ NTSTATUS ret;
+
+ ret = dcerpc_server_dssetup_init();
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ ret = dcerpc_server_lsarpc_init();
+ if (!NT_STATUS_IS_OK(ret)) {
+ return ret;
+ }
+ return ret;
+}
diff --git a/source4/rpc_server/lsa/lsa.h b/source4/rpc_server/lsa/lsa.h
new file mode 100644
index 0000000000..b7c41486a2
--- /dev/null
+++ b/source4/rpc_server/lsa/lsa.h
@@ -0,0 +1,68 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the lsarpc pipe
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 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 "auth/auth.h"
+#include "dsdb/samdb/samdb.h"
+#include "libcli/ldap/ldap_ndr.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "libcli/security/security.h"
+#include "libcli/auth/libcli_auth.h"
+#include "param/secrets.h"
+#include "util/util_ldb.h"
+#include "librpc/gen_ndr/ndr_dssetup.h"
+#include "param/param.h"
+
+/*
+ state associated with a lsa_OpenPolicy() operation
+*/
+struct lsa_policy_state {
+ struct dcesrv_handle *handle;
+ struct ldb_context *sam_ldb;
+ uint32_t access_mask;
+ struct ldb_dn *domain_dn;
+ struct ldb_dn *forest_dn;
+ struct ldb_dn *builtin_dn;
+ struct ldb_dn *system_dn;
+ const char *domain_name;
+ const char *domain_dns;
+ const char *forest_dns;
+ struct dom_sid *domain_sid;
+ struct GUID domain_guid;
+ struct dom_sid *builtin_sid;
+ struct dom_sid *nt_authority_sid;
+ struct dom_sid *creator_owner_domain_sid;
+ struct dom_sid *world_domain_sid;
+ int mixed_domain;
+};
+
+enum lsa_handle {
+ LSA_HANDLE_POLICY,
+ LSA_HANDLE_ACCOUNT,
+ LSA_HANDLE_SECRET,
+ LSA_HANDLE_TRUSTED_DOMAIN
+};
+
+#include "rpc_server/lsa/proto.h"
+
diff --git a/source4/rpc_server/lsa/lsa_init.c b/source4/rpc_server/lsa/lsa_init.c
new file mode 100644
index 0000000000..0dc21fd9c5
--- /dev/null
+++ b/source4/rpc_server/lsa/lsa_init.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the lsarpc pipe
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2007
+
+ 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 "rpc_server/lsa/lsa.h"
+
+NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_policy_state **_state)
+{
+ struct lsa_policy_state *state;
+ struct ldb_dn *partitions_basedn;
+ struct ldb_result *dom_res;
+ const char *dom_attrs[] = {
+ "objectSid",
+ "objectGUID",
+ "nTMixedDomain",
+ "fSMORoleOwner",
+ NULL
+ };
+ struct ldb_result *ref_res;
+ struct ldb_result *forest_ref_res;
+ const char *ref_attrs[] = {
+ "nETBIOSName",
+ "dnsRoot",
+ NULL
+ };
+ int ret;
+
+ state = talloc(mem_ctx, struct lsa_policy_state);
+ if (!state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* make sure the sam database is accessible */
+ state->sam_ldb = samdb_connect(state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+ if (state->sam_ldb == NULL) {
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+
+ partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx);
+
+ /* work out the domain_dn - useful for so many calls its worth
+ fetching here */
+ state->domain_dn = samdb_base_dn(state->sam_ldb);
+ if (!state->domain_dn) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* work out the forest root_dn - useful for so many calls its worth
+ fetching here */
+ state->forest_dn = samdb_root_dn(state->sam_ldb);
+ if (!state->forest_dn) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = ldb_search(state->sam_ldb, state->domain_dn, LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
+
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+ talloc_steal(mem_ctx, dom_res);
+ if (dom_res->count != 1) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid");
+ if (!state->domain_sid) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->domain_guid = samdb_result_guid(dom_res->msgs[0], "objectGUID");
+ if (!state->domain_sid) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->mixed_domain = ldb_msg_find_attr_as_uint(dom_res->msgs[0], "nTMixedDomain", 0);
+
+ talloc_free(dom_res);
+
+ ret = ldb_search_exp_fmt(state->sam_ldb, state, &ref_res,
+ partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs,
+ "(&(objectclass=crossRef)(ncName=%s))",
+ ldb_dn_get_linearized(state->domain_dn));
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ref_res);
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+ if (ref_res->count != 1) {
+ talloc_free(ref_res);
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->domain_name = ldb_msg_find_attr_as_string(ref_res->msgs[0], "nETBIOSName", NULL);
+ if (!state->domain_name) {
+ talloc_free(ref_res);
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+ talloc_steal(state, state->domain_name);
+
+ state->domain_dns = ldb_msg_find_attr_as_string(ref_res->msgs[0], "dnsRoot", NULL);
+ if (!state->domain_dns) {
+ talloc_free(ref_res);
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+ talloc_steal(state, state->domain_dns);
+
+ talloc_free(ref_res);
+
+ ret = ldb_search_exp_fmt(state->sam_ldb, state, &forest_ref_res,
+ partitions_basedn, LDB_SCOPE_SUBTREE, ref_attrs,
+ "(&(objectclass=crossRef)(ncName=%s))",
+ ldb_dn_get_linearized(state->forest_dn));
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(forest_ref_res);
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+ if (forest_ref_res->count != 1) {
+ talloc_free(forest_ref_res);
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->forest_dns = ldb_msg_find_attr_as_string(forest_ref_res->msgs[0], "dnsRoot", NULL);
+ if (!state->forest_dns) {
+ talloc_free(forest_ref_res);
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+ talloc_steal(state, state->forest_dns);
+
+ talloc_free(forest_ref_res);
+
+ /* work out the builtin_dn - useful for so many calls its worth
+ fetching here */
+ state->builtin_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(objectClass=builtinDomain)");
+ if (!state->builtin_dn) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ /* work out the system_dn - useful for so many calls its worth
+ fetching here */
+ state->system_dn = samdb_search_dn(state->sam_ldb, state,
+ state->domain_dn, "(&(objectClass=container)(cn=System))");
+ if (!state->system_dn) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN);
+ if (!state->builtin_sid) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->nt_authority_sid = dom_sid_parse_talloc(state, SID_NT_AUTHORITY);
+ if (!state->nt_authority_sid) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->creator_owner_domain_sid = dom_sid_parse_talloc(state, SID_CREATOR_OWNER_DOMAIN);
+ if (!state->creator_owner_domain_sid) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ state->world_domain_sid = dom_sid_parse_talloc(state, SID_WORLD_DOMAIN);
+ if (!state->world_domain_sid) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ *_state = state;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_OpenPolicy2
+*/
+NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_OpenPolicy2 *r)
+{
+ NTSTATUS status;
+ struct lsa_policy_state *state;
+ struct dcesrv_handle *handle;
+
+ ZERO_STRUCTP(r->out.handle);
+
+ status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_POLICY);
+ if (!handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ handle->data = talloc_steal(handle, state);
+
+ state->access_mask = r->in.access_mask;
+ state->handle = handle;
+ *r->out.handle = handle->wire_handle;
+
+ /* note that we have completely ignored the attr element of
+ the OpenPolicy. As far as I can tell, this is what w2k3
+ does */
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_OpenPolicy
+ a wrapper around lsa_OpenPolicy2
+*/
+NTSTATUS dcesrv_lsa_OpenPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_OpenPolicy *r)
+{
+ struct lsa_OpenPolicy2 r2;
+
+ r2.in.system_name = NULL;
+ r2.in.attr = r->in.attr;
+ r2.in.access_mask = r->in.access_mask;
+ r2.out.handle = r->out.handle;
+
+ return dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &r2);
+}
+
+
diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c
new file mode 100644
index 0000000000..30bceb8139
--- /dev/null
+++ b/source4/rpc_server/lsa/lsa_lookup.c
@@ -0,0 +1,932 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the lsarpc pipe
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2007
+
+ 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 "rpc_server/lsa/lsa.h"
+
+static const struct {
+ const char *domain;
+ const char *name;
+ const char *sid;
+ int rtype;
+} well_known[] = {
+ {
+ .name = "EVERYONE",
+ .sid = SID_WORLD,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .name = "CREATOR OWNER",
+ .sid = SID_CREATOR_OWNER,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .name = "CREATOR GROUP",
+ .sid = SID_CREATOR_GROUP,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Dialup",
+ .sid = SID_NT_DIALUP,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Network",
+ .sid = SID_NT_NETWORK,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Batch",
+ .sid = SID_NT_BATCH,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Interactive",
+ .sid = SID_NT_INTERACTIVE,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Service",
+ .sid = SID_NT_SERVICE,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "ANONYMOUS LOGON",
+ .sid = SID_NT_ANONYMOUS,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Proxy",
+ .sid = SID_NT_PROXY,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "ServerLogon",
+ .sid = SID_NT_ENTERPRISE_DCS,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Self",
+ .sid = SID_NT_SELF,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Authenticated Users",
+ .sid = SID_NT_AUTHENTICATED_USERS,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Restricted",
+ .sid = SID_NT_RESTRICTED,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Termainal Server User",
+ .sid = SID_NT_TERMINAL_SERVER_USERS,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Remote Interactive Logon",
+ .sid = SID_NT_REMOTE_INTERACTIVE,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "This Organization",
+ .sid = SID_NT_THIS_ORGANISATION,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "SYSTEM",
+ .sid = SID_NT_SYSTEM,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Local Service",
+ .sid = SID_NT_LOCAL_SERVICE,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .name = "Network Service",
+ .sid = SID_NT_NETWORK_SERVICE,
+ .rtype = SID_NAME_WKN_GRP,
+ },
+ {
+ .sid = NULL,
+ }
+};
+
+static NTSTATUS lookup_well_known_names(TALLOC_CTX *mem_ctx, const char *domain,
+ const char *name, const char **authority_name,
+ struct dom_sid **sid, uint32_t *rtype)
+{
+ int i;
+ for (i=0; well_known[i].sid; i++) {
+ if (domain) {
+ if (strcasecmp_m(domain, well_known[i].domain) == 0
+ && strcasecmp_m(name, well_known[i].name) == 0) {
+ *authority_name = well_known[i].domain;
+ *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid);
+ *rtype = well_known[i].rtype;
+ return NT_STATUS_OK;
+ }
+ } else {
+ if (strcasecmp_m(name, well_known[i].name) == 0) {
+ *authority_name = well_known[i].domain;
+ *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid);
+ *rtype = well_known[i].rtype;
+ return NT_STATUS_OK;
+ }
+ }
+ }
+ return NT_STATUS_NOT_FOUND;
+}
+
+static NTSTATUS lookup_well_known_sids(TALLOC_CTX *mem_ctx,
+ const char *sid_str, const char **authority_name,
+ const char **name, uint32_t *rtype)
+{
+ int i;
+ for (i=0; well_known[i].sid; i++) {
+ if (strcasecmp_m(sid_str, well_known[i].sid) == 0) {
+ *authority_name = well_known[i].domain;
+ *name = well_known[i].name;
+ *rtype = well_known[i].rtype;
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_NOT_FOUND;
+}
+
+/*
+ lookup a SID for 1 name
+*/
+static NTSTATUS dcesrv_lsa_lookup_name(struct event_context *ev_ctx,
+ struct loadparm_context *lp_ctx,
+ struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
+ const char *name, const char **authority_name,
+ struct dom_sid **sid, enum lsa_SidType *rtype)
+{
+ int ret, atype, i;
+ struct ldb_message **res;
+ const char * const attrs[] = { "objectSid", "sAMAccountType", NULL};
+ const char *p;
+ const char *domain;
+ const char *username;
+ struct ldb_dn *domain_dn;
+ struct dom_sid *domain_sid;
+ NTSTATUS status;
+
+ p = strchr_m(name, '\\');
+ if (p != NULL) {
+ domain = talloc_strndup(mem_ctx, name, p-name);
+ if (!domain) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ username = p + 1;
+ } else if (strchr_m(name, '@')) {
+ status = crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status)));
+ return status;
+ }
+ } else {
+ domain = NULL;
+ username = name;
+ }
+
+ if (!domain) {
+ /* Look up table of well known names */
+ status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype);
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
+ }
+
+ if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) {
+ *authority_name = NAME_NT_AUTHORITY;
+ *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
+ *rtype = SID_NAME_DOMAIN;
+ return NT_STATUS_OK;
+ }
+ if (strcasecmp_m(username, NAME_BUILTIN) == 0) {
+ *authority_name = NAME_BUILTIN;
+ *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
+ *rtype = SID_NAME_DOMAIN;
+ return NT_STATUS_OK;
+ }
+ if (strcasecmp_m(username, state->domain_dns) == 0) {
+ *authority_name = state->domain_name;
+ *sid = state->domain_sid;
+ *rtype = SID_NAME_DOMAIN;
+ return NT_STATUS_OK;
+ }
+ if (strcasecmp_m(username, state->domain_name) == 0) {
+ *authority_name = state->domain_name;
+ *sid = state->domain_sid;
+ *rtype = SID_NAME_DOMAIN;
+ return NT_STATUS_OK;
+ }
+
+ /* Perhaps this is a well known user? */
+ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username);
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Perhaps this is a BUILTIN user? */
+ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username);
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* OK, I give up - perhaps we need to assume the user is in our domain? */
+ name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username);
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return STATUS_SOME_UNMAPPED;
+ } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) {
+ if (!*username) {
+ *authority_name = NAME_NT_AUTHORITY;
+ *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
+ *rtype = SID_NAME_DOMAIN;
+ return NT_STATUS_OK;
+ }
+
+ /* Look up table of well known names */
+ return lookup_well_known_names(mem_ctx, domain, username, authority_name,
+ sid, rtype);
+ } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) {
+ *authority_name = NAME_BUILTIN;
+ domain_dn = state->builtin_dn;
+ } else if (strcasecmp_m(domain, state->domain_dns) == 0) {
+ *authority_name = state->domain_name;
+ domain_dn = state->domain_dn;
+ } else if (strcasecmp_m(domain, state->domain_name) == 0) {
+ *authority_name = state->domain_name;
+ domain_dn = state->domain_dn;
+ } else {
+ /* Not local, need to ask winbind in future */
+ return STATUS_SOME_UNMAPPED;
+ }
+
+ ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs);
+ if (ret == 1) {
+ domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
+ if (domain_sid == NULL) {
+ return NT_STATUS_INVALID_SID;
+ }
+ } else {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ if (!*username) {
+ *sid = domain_sid;
+ *rtype = SID_NAME_DOMAIN;
+ return NT_STATUS_OK;
+ }
+
+ ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs,
+ "(&(sAMAccountName=%s)(objectSid=*))",
+ ldb_binary_encode_string(mem_ctx, username));
+ if (ret == -1) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ for (i=0; i < ret; i++) {
+ *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
+ if (*sid == NULL) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ /* Check that this is in the domain */
+ if (!dom_sid_in_domain(domain_sid, *sid)) {
+ continue;
+ }
+
+ atype = samdb_result_uint(res[i], "sAMAccountType", 0);
+
+ *rtype = samdb_atype_map(atype);
+ if (*rtype == SID_NAME_UNKNOWN) {
+ return STATUS_SOME_UNMAPPED;
+ }
+
+ return NT_STATUS_OK;
+ }
+
+ /* need to check for an allocated sid */
+
+ return NT_STATUS_INVALID_SID;
+}
+
+
+/*
+ add to the lsa_RefDomainList for LookupSids and LookupNames
+*/
+static NTSTATUS dcesrv_lsa_authority_list(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
+ enum lsa_SidType rtype,
+ const char *authority_name,
+ struct dom_sid *sid,
+ struct lsa_RefDomainList *domains,
+ uint32_t *sid_index)
+{
+ struct dom_sid *authority_sid;
+ int i;
+
+ if (rtype != SID_NAME_DOMAIN) {
+ authority_sid = dom_sid_dup(mem_ctx, sid);
+ if (authority_sid == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ authority_sid->num_auths--;
+ } else {
+ authority_sid = sid;
+ }
+
+ /* see if we've already done this authority name */
+ for (i=0;i<domains->count;i++) {
+ if (strcasecmp_m(authority_name, domains->domains[i].name.string) == 0) {
+ *sid_index = i;
+ return NT_STATUS_OK;
+ }
+ }
+
+ domains->domains = talloc_realloc(domains,
+ domains->domains,
+ struct lsa_DomainInfo,
+ domains->count+1);
+ if (domains->domains == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ domains->domains[i].name.string = authority_name;
+ domains->domains[i].sid = authority_sid;
+ domains->count++;
+ domains->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER * domains->count;
+ *sid_index = i;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lookup a name for 1 SID
+*/
+static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
+ struct dom_sid *sid, const char *sid_str,
+ const char **authority_name,
+ const char **name, enum lsa_SidType *rtype)
+{
+ NTSTATUS status;
+ int ret;
+ uint32_t atype;
+ struct ldb_message **res;
+ struct ldb_dn *domain_dn;
+ const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "cn", NULL};
+
+ status = lookup_well_known_sids(mem_ctx, sid_str, authority_name, name, rtype);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (dom_sid_in_domain(state->domain_sid, sid)) {
+ *authority_name = state->domain_name;
+ domain_dn = state->domain_dn;
+ } else if (dom_sid_in_domain(state->builtin_sid, sid)) {
+ *authority_name = NAME_BUILTIN;
+ domain_dn = state->builtin_dn;
+ } else {
+ /* Not well known, our domain or built in */
+
+ /* In future, we must look at SID histories, and at trusted domains via winbind */
+
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs,
+ "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid));
+ if (ret == 1) {
+ *name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL);
+ if (!*name) {
+ *name = ldb_msg_find_attr_as_string(res[0], "cn", NULL);
+ if (!*name) {
+ *name = talloc_strdup(mem_ctx, sid_str);
+ NT_STATUS_HAVE_NO_MEMORY(*name);
+ }
+ }
+
+ atype = samdb_result_uint(res[0], "sAMAccountType", 0);
+
+ *rtype = samdb_atype_map(atype);
+
+ return NT_STATUS_OK;
+ }
+
+ /* need to re-add a check for an allocated sid */
+
+ return NT_STATUS_NOT_FOUND;
+}
+
+
+/*
+ lsa_LookupSids2
+*/
+NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupSids2 *r)
+{
+ struct lsa_policy_state *state;
+ int i;
+ NTSTATUS status = NT_STATUS_OK;
+
+ r->out.domains = NULL;
+
+ status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList);
+ if (r->out.domains == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->out.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2);
+ if (r->out.names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *r->out.count = 0;
+
+ r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName2,
+ r->in.sids->num_sids);
+ if (r->out.names->names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<r->in.sids->num_sids;i++) {
+ struct dom_sid *sid = r->in.sids->sids[i].sid;
+ char *sid_str = dom_sid_string(mem_ctx, sid);
+ const char *name, *authority_name;
+ enum lsa_SidType rtype;
+ uint32_t sid_index;
+ NTSTATUS status2;
+
+ r->out.names->count++;
+
+ r->out.names->names[i].sid_type = SID_NAME_UNKNOWN;
+ r->out.names->names[i].name.string = sid_str;
+ r->out.names->names[i].sid_index = 0xFFFFFFFF;
+ r->out.names->names[i].unknown = 0;
+
+ if (sid_str == NULL) {
+ r->out.names->names[i].name.string = "(SIDERROR)";
+ status = STATUS_SOME_UNMAPPED;
+ continue;
+ }
+
+ status2 = dcesrv_lsa_lookup_sid(state, mem_ctx, sid, sid_str,
+ &authority_name, &name, &rtype);
+ if (!NT_STATUS_IS_OK(status2)) {
+ status = STATUS_SOME_UNMAPPED;
+ continue;
+ }
+
+ /* set up the authority table */
+ status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype,
+ authority_name, sid,
+ r->out.domains, &sid_index);
+ if (!NT_STATUS_IS_OK(status2)) {
+ return status2;
+ }
+
+ r->out.names->names[i].sid_type = rtype;
+ r->out.names->names[i].name.string = name;
+ r->out.names->names[i].sid_index = sid_index;
+ r->out.names->names[i].unknown = 0;
+
+ (*r->out.count)++;
+ }
+
+ if (*r->out.count == 0) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+ if (*r->out.count != r->in.sids->num_sids) {
+ return STATUS_SOME_UNMAPPED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ lsa_LookupSids3
+
+ Identical to LookupSids2, but doesn't take a policy handle
+
+*/
+NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupSids3 *r)
+{
+ struct lsa_LookupSids2 r2;
+ struct lsa_OpenPolicy2 pol;
+ NTSTATUS status;
+ struct dcesrv_handle *h;
+
+ /* No policy handle on the wire, so make one up here */
+ r2.in.handle = talloc(mem_ctx, struct policy_handle);
+ if (!r2.in.handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pol.out.handle = r2.in.handle;
+ pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ pol.in.attr = NULL;
+ pol.in.system_name = NULL;
+ status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* ensure this handle goes away at the end of this call */
+ DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY);
+ talloc_steal(mem_ctx, h);
+
+ r2.in.sids = r->in.sids;
+ r2.in.names = r->in.names;
+ r2.in.level = r->in.level;
+ r2.in.count = r->in.count;
+ r2.in.unknown1 = r->in.unknown1;
+ r2.in.unknown2 = r->in.unknown2;
+ r2.out.count = r->out.count;
+ r2.out.names = r->out.names;
+
+ status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
+ if (dce_call->fault_code != 0) {
+ return status;
+ }
+
+ r->out.domains = r2.out.domains;
+ r->out.names = r2.out.names;
+ r->out.count = r2.out.count;
+
+ return status;
+}
+
+
+/*
+ lsa_LookupSids
+*/
+NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LookupSids *r)
+{
+ struct lsa_LookupSids2 r2;
+ NTSTATUS status;
+ int i;
+
+ r2.in.handle = r->in.handle;
+ r2.in.sids = r->in.sids;
+ r2.in.names = NULL;
+ r2.in.level = r->in.level;
+ r2.in.count = r->in.count;
+ r2.in.unknown1 = 0;
+ r2.in.unknown2 = 0;
+ r2.out.count = r->out.count;
+ r2.out.names = NULL;
+
+ status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
+ if (dce_call->fault_code != 0) {
+ return status;
+ }
+
+ r->out.domains = r2.out.domains;
+ if (!r2.out.names) {
+ r->out.names = NULL;
+ return status;
+ }
+
+ r->out.names = talloc(mem_ctx, struct lsa_TransNameArray);
+ if (r->out.names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.names->count = r2.out.names->count;
+ r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName,
+ r->out.names->count);
+ if (r->out.names->names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<r->out.names->count;i++) {
+ r->out.names->names[i].sid_type = r2.out.names->names[i].sid_type;
+ r->out.names->names[i].name.string = r2.out.names->names[i].name.string;
+ r->out.names->names[i].sid_index = r2.out.names->names[i].sid_index;
+ }
+
+ return status;
+}
+
+
+/*
+ lsa_LookupNames3
+*/
+NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupNames3 *r)
+{
+ struct lsa_policy_state *policy_state;
+ struct dcesrv_handle *policy_handle;
+ int i;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+
+ DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+
+ policy_state = policy_handle->data;
+
+ r->out.domains = NULL;
+
+ r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList);
+ if (r->out.domains == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3);
+ if (r->out.sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *r->out.count = 0;
+
+ r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3,
+ r->in.num_names);
+ if (r->out.sids->sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<r->in.num_names;i++) {
+ const char *name = r->in.names[i].string;
+ const char *authority_name;
+ struct dom_sid *sid;
+ uint32_t sid_index;
+ enum lsa_SidType rtype;
+ NTSTATUS status2;
+
+ r->out.sids->count++;
+
+ r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN;
+ r->out.sids->sids[i].sid = NULL;
+ r->out.sids->sids[i].sid_index = 0xFFFFFFFF;
+ r->out.sids->sids[i].unknown = 0;
+
+ status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, policy_state, mem_ctx, name, &authority_name, &sid, &rtype);
+ if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) {
+ continue;
+ }
+
+ status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, authority_name,
+ sid, r->out.domains, &sid_index);
+ if (!NT_STATUS_IS_OK(status2)) {
+ return status2;
+ }
+
+ r->out.sids->sids[i].sid_type = rtype;
+ r->out.sids->sids[i].sid = sid;
+ r->out.sids->sids[i].sid_index = sid_index;
+ r->out.sids->sids[i].unknown = 0;
+
+ (*r->out.count)++;
+ }
+
+ if (*r->out.count == 0) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+ if (*r->out.count != r->in.num_names) {
+ return STATUS_SOME_UNMAPPED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_LookupNames4
+
+ Identical to LookupNames3, but doesn't take a policy handle
+
+*/
+NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LookupNames4 *r)
+{
+ struct lsa_LookupNames3 r2;
+ struct lsa_OpenPolicy2 pol;
+ NTSTATUS status;
+ struct dcesrv_handle *h;
+
+ /* No policy handle on the wire, so make one up here */
+ r2.in.handle = talloc(mem_ctx, struct policy_handle);
+ if (!r2.in.handle) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pol.out.handle = r2.in.handle;
+ pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ pol.in.attr = NULL;
+ pol.in.system_name = NULL;
+ status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* ensure this handle goes away at the end of this call */
+ DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY);
+ talloc_steal(mem_ctx, h);
+
+ r2.in.num_names = r->in.num_names;
+ r2.in.names = r->in.names;
+ r2.in.sids = r->in.sids;
+ r2.in.count = r->in.count;
+ r2.in.unknown1 = r->in.unknown1;
+ r2.in.unknown2 = r->in.unknown2;
+ r2.out.domains = r->out.domains;
+ r2.out.sids = r->out.sids;
+ r2.out.count = r->out.count;
+
+ status = dcesrv_lsa_LookupNames3(dce_call, mem_ctx, &r2);
+ if (dce_call->fault_code != 0) {
+ return status;
+ }
+
+ r->out.domains = r2.out.domains;
+ r->out.sids = r2.out.sids;
+ r->out.count = r2.out.count;
+ return status;
+}
+
+/*
+ lsa_LookupNames2
+*/
+NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupNames2 *r)
+{
+ struct lsa_policy_state *state;
+ struct dcesrv_handle *h;
+ int i;
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+
+ r->out.domains = NULL;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
+
+ state = h->data;
+
+ r->out.domains = talloc_zero(mem_ctx, struct lsa_RefDomainList);
+ if (r->out.domains == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2);
+ if (r->out.sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *r->out.count = 0;
+
+ r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2,
+ r->in.num_names);
+ if (r->out.sids->sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<r->in.num_names;i++) {
+ const char *name = r->in.names[i].string;
+ const char *authority_name;
+ struct dom_sid *sid;
+ uint32_t rtype, sid_index;
+ NTSTATUS status2;
+
+ r->out.sids->count++;
+
+ r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN;
+ r->out.sids->sids[i].rid = 0xFFFFFFFF;
+ r->out.sids->sids[i].sid_index = 0xFFFFFFFF;
+ r->out.sids->sids[i].unknown = 0;
+
+ status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, state, mem_ctx, name,
+ &authority_name, &sid, &rtype);
+ if (!NT_STATUS_IS_OK(status2)) {
+ continue;
+ }
+
+ status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, authority_name,
+ sid, r->out.domains, &sid_index);
+ if (!NT_STATUS_IS_OK(status2)) {
+ return status2;
+ }
+
+ r->out.sids->sids[i].sid_type = rtype;
+ r->out.sids->sids[i].rid = sid->sub_auths[sid->num_auths-1];
+ r->out.sids->sids[i].sid_index = sid_index;
+ r->out.sids->sids[i].unknown = 0;
+
+ (*r->out.count)++;
+ }
+
+ if (*r->out.count == 0) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+ if (*r->out.count != r->in.num_names) {
+ return STATUS_SOME_UNMAPPED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_LookupNames
+*/
+NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct lsa_LookupNames *r)
+{
+ struct lsa_LookupNames2 r2;
+ NTSTATUS status;
+ int i;
+
+ r2.in.handle = r->in.handle;
+ r2.in.num_names = r->in.num_names;
+ r2.in.names = r->in.names;
+ r2.in.sids = NULL;
+ r2.in.level = r->in.level;
+ r2.in.count = r->in.count;
+ r2.in.unknown1 = 0;
+ r2.in.unknown2 = 0;
+ r2.out.count = r->out.count;
+
+ status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2);
+ if (dce_call->fault_code != 0) {
+ return status;
+ }
+
+ r->out.domains = r2.out.domains;
+ r->out.sids = talloc(mem_ctx, struct lsa_TransSidArray);
+ if (r->out.sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.sids->count = r2.out.sids->count;
+ r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid,
+ r->out.sids->count);
+ if (r->out.sids->sids == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<r->out.sids->count;i++) {
+ r->out.sids->sids[i].sid_type = r2.out.sids->sids[i].sid_type;
+ r->out.sids->sids[i].rid = r2.out.sids->sids[i].rid;
+ r->out.sids->sids[i].sid_index = r2.out.sids->sids[i].sid_index;
+ }
+
+ return status;
+}
+