lsa4: Remove an unused variable
[Samba.git] / source4 / rpc_server / lsa / dcesrv_lsa.c
blob520c65b0e20e8654d320a8d353adebc7215ec032
1 /* need access mask/acl implementation */
3 /*
4 Unix SMB/CIFS implementation.
6 endpoint server for the lsarpc pipe
8 Copyright (C) Andrew Tridgell 2004
9 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "rpc_server/lsa/lsa.h"
26 #include "system/kerberos.h"
27 #include "auth/kerberos/kerberos.h"
28 #include "librpc/gen_ndr/ndr_drsblobs.h"
29 #include "librpc/gen_ndr/ndr_lsa.h"
30 #include "../lib/crypto/crypto.h"
31 #include "lib/util/tsort.h"
32 #include "dsdb/common/util.h"
33 #include "libcli/security/session.h"
34 #include "libcli/lsarpc/util_lsarpc.h"
37 this type allows us to distinguish handle types
41 state associated with a lsa_OpenAccount() operation
43 struct lsa_account_state {
44 struct lsa_policy_state *policy;
45 uint32_t access_mask;
46 struct dom_sid *account_sid;
51 state associated with a lsa_OpenSecret() operation
53 struct lsa_secret_state {
54 struct lsa_policy_state *policy;
55 uint32_t access_mask;
56 struct ldb_dn *secret_dn;
57 struct ldb_context *sam_ldb;
58 bool global;
62 state associated with a lsa_OpenTrustedDomain() operation
64 struct lsa_trusted_domain_state {
65 struct lsa_policy_state *policy;
66 uint32_t access_mask;
67 struct ldb_dn *trusted_domain_dn;
68 struct ldb_dn *trusted_domain_user_dn;
72 this is based on the samba3 function make_lsa_object_sd()
73 It uses the same logic, but with samba4 helper functions
75 static NTSTATUS dcesrv_build_lsa_sd(TALLOC_CTX *mem_ctx,
76 struct security_descriptor **sd,
77 struct dom_sid *sid,
78 uint32_t sid_access)
80 NTSTATUS status;
81 uint32_t rid;
82 struct dom_sid *domain_sid, *domain_admins_sid;
83 const char *domain_admins_sid_str, *sidstr;
84 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
86 status = dom_sid_split_rid(tmp_ctx, sid, &domain_sid, &rid);
87 NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
89 domain_admins_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ADMINS);
90 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_admins_sid, tmp_ctx);
92 domain_admins_sid_str = dom_sid_string(tmp_ctx, domain_admins_sid);
93 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_admins_sid_str, tmp_ctx);
95 sidstr = dom_sid_string(tmp_ctx, sid);
96 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidstr, tmp_ctx);
98 *sd = security_descriptor_dacl_create(mem_ctx,
99 0, sidstr, NULL,
101 SID_WORLD,
102 SEC_ACE_TYPE_ACCESS_ALLOWED,
103 SEC_GENERIC_EXECUTE | SEC_GENERIC_READ, 0,
105 SID_BUILTIN_ADMINISTRATORS,
106 SEC_ACE_TYPE_ACCESS_ALLOWED,
107 SEC_GENERIC_ALL, 0,
109 SID_BUILTIN_ACCOUNT_OPERATORS,
110 SEC_ACE_TYPE_ACCESS_ALLOWED,
111 SEC_GENERIC_ALL, 0,
113 domain_admins_sid_str,
114 SEC_ACE_TYPE_ACCESS_ALLOWED,
115 SEC_GENERIC_ALL, 0,
117 sidstr,
118 SEC_ACE_TYPE_ACCESS_ALLOWED,
119 sid_access, 0,
121 NULL);
122 talloc_free(tmp_ctx);
124 NT_STATUS_HAVE_NO_MEMORY(*sd);
126 return NT_STATUS_OK;
130 static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call,
131 TALLOC_CTX *mem_ctx,
132 struct lsa_EnumAccountRights *r);
134 static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_call,
135 TALLOC_CTX *mem_ctx,
136 struct lsa_policy_state *state,
137 int ldb_flag,
138 struct dom_sid *sid,
139 const struct lsa_RightSet *rights);
142 lsa_Close
144 static NTSTATUS dcesrv_lsa_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
145 struct lsa_Close *r)
147 enum dcerpc_transport_t transport = dce_call->conn->endpoint->ep_description->transport;
148 struct dcesrv_handle *h;
150 if (transport != NCACN_NP && transport != NCALRPC) {
151 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
154 *r->out.handle = *r->in.handle;
156 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
158 talloc_free(h);
160 ZERO_STRUCTP(r->out.handle);
162 return NT_STATUS_OK;
167 lsa_Delete
169 static NTSTATUS dcesrv_lsa_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
170 struct lsa_Delete *r)
172 return NT_STATUS_NOT_SUPPORTED;
177 lsa_DeleteObject
179 static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
180 struct lsa_DeleteObject *r)
182 struct dcesrv_handle *h;
183 int ret;
185 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
187 if (h->wire_handle.handle_type == LSA_HANDLE_SECRET) {
188 struct lsa_secret_state *secret_state = h->data;
190 /* Ensure user is permitted to delete this... */
191 switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL))
193 case SECURITY_SYSTEM:
194 case SECURITY_ADMINISTRATOR:
195 break;
196 default:
197 /* Users and anonymous are not allowed to delete things */
198 return NT_STATUS_ACCESS_DENIED;
201 ret = ldb_delete(secret_state->sam_ldb,
202 secret_state->secret_dn);
203 if (ret != LDB_SUCCESS) {
204 return NT_STATUS_INVALID_HANDLE;
207 ZERO_STRUCTP(r->out.handle);
209 return NT_STATUS_OK;
211 } else if (h->wire_handle.handle_type == LSA_HANDLE_TRUSTED_DOMAIN) {
212 struct lsa_trusted_domain_state *trusted_domain_state =
213 talloc_get_type(h->data, struct lsa_trusted_domain_state);
214 ret = ldb_transaction_start(trusted_domain_state->policy->sam_ldb);
215 if (ret != LDB_SUCCESS) {
216 return NT_STATUS_INTERNAL_DB_CORRUPTION;
219 ret = ldb_delete(trusted_domain_state->policy->sam_ldb,
220 trusted_domain_state->trusted_domain_dn);
221 if (ret != LDB_SUCCESS) {
222 ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
223 return NT_STATUS_INVALID_HANDLE;
226 if (trusted_domain_state->trusted_domain_user_dn) {
227 ret = ldb_delete(trusted_domain_state->policy->sam_ldb,
228 trusted_domain_state->trusted_domain_user_dn);
229 if (ret != LDB_SUCCESS) {
230 ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
231 return NT_STATUS_INVALID_HANDLE;
235 ret = ldb_transaction_commit(trusted_domain_state->policy->sam_ldb);
236 if (ret != LDB_SUCCESS) {
237 return NT_STATUS_INTERNAL_DB_CORRUPTION;
240 ZERO_STRUCTP(r->out.handle);
242 return NT_STATUS_OK;
244 } else if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) {
245 struct lsa_RightSet *rights;
246 struct lsa_account_state *astate;
247 struct lsa_EnumAccountRights r2;
248 NTSTATUS status;
250 rights = talloc(mem_ctx, struct lsa_RightSet);
252 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
254 astate = h->data;
256 r2.in.handle = &astate->policy->handle->wire_handle;
257 r2.in.sid = astate->account_sid;
258 r2.out.rights = rights;
260 /* dcesrv_lsa_EnumAccountRights takes a LSA_HANDLE_POLICY,
261 but we have a LSA_HANDLE_ACCOUNT here, so this call
262 will always fail */
263 status = dcesrv_lsa_EnumAccountRights(dce_call, mem_ctx, &r2);
264 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
265 return NT_STATUS_OK;
268 if (!NT_STATUS_IS_OK(status)) {
269 return status;
272 status = dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
273 LDB_FLAG_MOD_DELETE, astate->account_sid,
274 r2.out.rights);
275 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
276 return NT_STATUS_OK;
279 if (!NT_STATUS_IS_OK(status)) {
280 return status;
283 ZERO_STRUCTP(r->out.handle);
285 return NT_STATUS_OK;
288 return NT_STATUS_INVALID_HANDLE;
293 lsa_EnumPrivs
295 static NTSTATUS dcesrv_lsa_EnumPrivs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
296 struct lsa_EnumPrivs *r)
298 struct dcesrv_handle *h;
299 struct lsa_policy_state *state;
300 uint32_t i;
301 enum sec_privilege priv;
302 const char *privname;
304 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
306 state = h->data;
308 i = *r->in.resume_handle;
310 while (((priv = sec_privilege_from_index(i)) != SEC_PRIV_INVALID) &&
311 r->out.privs->count < r->in.max_count) {
312 struct lsa_PrivEntry *e;
313 privname = sec_privilege_name(priv);
314 r->out.privs->privs = talloc_realloc(r->out.privs,
315 r->out.privs->privs,
316 struct lsa_PrivEntry,
317 r->out.privs->count+1);
318 if (r->out.privs->privs == NULL) {
319 return NT_STATUS_NO_MEMORY;
321 e = &r->out.privs->privs[r->out.privs->count];
322 e->luid.low = priv;
323 e->luid.high = 0;
324 e->name.string = privname;
325 r->out.privs->count++;
326 i++;
329 *r->out.resume_handle = i;
331 return NT_STATUS_OK;
336 lsa_QuerySecObj
338 static NTSTATUS dcesrv_lsa_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
339 struct lsa_QuerySecurity *r)
341 struct dcesrv_handle *h;
342 struct security_descriptor *sd;
343 NTSTATUS status;
344 struct dom_sid *sid;
346 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
348 sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
350 if (h->wire_handle.handle_type == LSA_HANDLE_POLICY) {
351 status = dcesrv_build_lsa_sd(mem_ctx, &sd, sid, 0);
352 } else if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) {
353 status = dcesrv_build_lsa_sd(mem_ctx, &sd, sid,
354 LSA_ACCOUNT_ALL_ACCESS);
355 } else {
356 return NT_STATUS_INVALID_HANDLE;
358 NT_STATUS_NOT_OK_RETURN(status);
360 (*r->out.sdbuf) = talloc(mem_ctx, struct sec_desc_buf);
361 NT_STATUS_HAVE_NO_MEMORY(*r->out.sdbuf);
363 (*r->out.sdbuf)->sd = sd;
365 return NT_STATUS_OK;
370 lsa_SetSecObj
372 static NTSTATUS dcesrv_lsa_SetSecObj(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
373 struct lsa_SetSecObj *r)
375 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
380 lsa_ChangePassword
382 static NTSTATUS dcesrv_lsa_ChangePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
383 struct lsa_ChangePassword *r)
385 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
389 dssetup_DsRoleGetPrimaryDomainInformation
391 This is not an LSA call, but is the only call left on the DSSETUP
392 pipe (after the pipe was truncated), and needs lsa_get_policy_state
394 static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_call_state *dce_call,
395 TALLOC_CTX *mem_ctx,
396 struct dssetup_DsRoleGetPrimaryDomainInformation *r)
398 union dssetup_DsRoleInfo *info;
400 info = talloc_zero(mem_ctx, union dssetup_DsRoleInfo);
401 W_ERROR_HAVE_NO_MEMORY(info);
403 switch (r->in.level) {
404 case DS_ROLE_BASIC_INFORMATION:
406 enum dssetup_DsRole role = DS_ROLE_STANDALONE_SERVER;
407 uint32_t flags = 0;
408 const char *domain = NULL;
409 const char *dns_domain = NULL;
410 const char *forest = NULL;
411 struct GUID domain_guid;
412 struct lsa_policy_state *state;
414 NTSTATUS status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
415 if (!NT_STATUS_IS_OK(status)) {
416 return ntstatus_to_werror(status);
419 ZERO_STRUCT(domain_guid);
421 switch (lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
422 case ROLE_STANDALONE:
423 role = DS_ROLE_STANDALONE_SERVER;
424 break;
425 case ROLE_DOMAIN_MEMBER:
426 role = DS_ROLE_MEMBER_SERVER;
427 break;
428 case ROLE_ACTIVE_DIRECTORY_DC:
429 if (samdb_is_pdc(state->sam_ldb)) {
430 role = DS_ROLE_PRIMARY_DC;
431 } else {
432 role = DS_ROLE_BACKUP_DC;
434 break;
437 switch (lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
438 case ROLE_STANDALONE:
439 domain = talloc_strdup(mem_ctx, lpcfg_workgroup(dce_call->conn->dce_ctx->lp_ctx));
440 W_ERROR_HAVE_NO_MEMORY(domain);
441 break;
442 case ROLE_DOMAIN_MEMBER:
443 domain = talloc_strdup(mem_ctx, lpcfg_workgroup(dce_call->conn->dce_ctx->lp_ctx));
444 W_ERROR_HAVE_NO_MEMORY(domain);
445 /* TODO: what is with dns_domain and forest and guid? */
446 break;
447 case ROLE_ACTIVE_DIRECTORY_DC:
448 flags = DS_ROLE_PRIMARY_DS_RUNNING;
450 if (state->mixed_domain == 1) {
451 flags |= DS_ROLE_PRIMARY_DS_MIXED_MODE;
454 domain = state->domain_name;
455 dns_domain = state->domain_dns;
456 forest = state->forest_dns;
458 domain_guid = state->domain_guid;
459 flags |= DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT;
460 break;
463 info->basic.role = role;
464 info->basic.flags = flags;
465 info->basic.domain = domain;
466 info->basic.dns_domain = dns_domain;
467 info->basic.forest = forest;
468 info->basic.domain_guid = domain_guid;
470 r->out.info = info;
471 return WERR_OK;
473 case DS_ROLE_UPGRADE_STATUS:
475 info->upgrade.upgrading = DS_ROLE_NOT_UPGRADING;
476 info->upgrade.previous_role = DS_ROLE_PREVIOUS_UNKNOWN;
478 r->out.info = info;
479 return WERR_OK;
481 case DS_ROLE_OP_STATUS:
483 info->opstatus.status = DS_ROLE_OP_IDLE;
485 r->out.info = info;
486 return WERR_OK;
488 default:
489 return WERR_INVALID_PARAM;
494 fill in the AccountDomain info
496 static NTSTATUS dcesrv_lsa_info_AccountDomain(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
497 struct lsa_DomainInfo *info)
499 info->name.string = state->domain_name;
500 info->sid = state->domain_sid;
502 return NT_STATUS_OK;
506 fill in the DNS domain info
508 static NTSTATUS dcesrv_lsa_info_DNS(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
509 struct lsa_DnsDomainInfo *info)
511 info->name.string = state->domain_name;
512 info->sid = state->domain_sid;
513 info->dns_domain.string = state->domain_dns;
514 info->dns_forest.string = state->forest_dns;
515 info->domain_guid = state->domain_guid;
517 return NT_STATUS_OK;
521 lsa_QueryInfoPolicy2
523 static NTSTATUS dcesrv_lsa_QueryInfoPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
524 struct lsa_QueryInfoPolicy2 *r)
526 struct lsa_policy_state *state;
527 struct dcesrv_handle *h;
528 union lsa_PolicyInformation *info;
530 *r->out.info = NULL;
532 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
534 state = h->data;
536 info = talloc_zero(mem_ctx, union lsa_PolicyInformation);
537 if (!info) {
538 return NT_STATUS_NO_MEMORY;
540 *r->out.info = info;
542 switch (r->in.level) {
543 case LSA_POLICY_INFO_AUDIT_LOG:
544 /* we don't need to fill in any of this */
545 ZERO_STRUCT(info->audit_log);
546 return NT_STATUS_OK;
547 case LSA_POLICY_INFO_AUDIT_EVENTS:
548 /* we don't need to fill in any of this */
549 ZERO_STRUCT(info->audit_events);
550 return NT_STATUS_OK;
551 case LSA_POLICY_INFO_PD:
552 /* we don't need to fill in any of this */
553 ZERO_STRUCT(info->pd);
554 return NT_STATUS_OK;
556 case LSA_POLICY_INFO_DOMAIN:
557 return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &info->domain);
558 case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
559 return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &info->account_domain);
560 case LSA_POLICY_INFO_L_ACCOUNT_DOMAIN:
561 return dcesrv_lsa_info_AccountDomain(state, mem_ctx, &info->l_account_domain);
563 case LSA_POLICY_INFO_ROLE:
564 info->role.role = LSA_ROLE_PRIMARY;
565 return NT_STATUS_OK;
567 case LSA_POLICY_INFO_DNS:
568 case LSA_POLICY_INFO_DNS_INT:
569 return dcesrv_lsa_info_DNS(state, mem_ctx, &info->dns);
571 case LSA_POLICY_INFO_REPLICA:
572 ZERO_STRUCT(info->replica);
573 return NT_STATUS_OK;
575 case LSA_POLICY_INFO_QUOTA:
576 ZERO_STRUCT(info->quota);
577 return NT_STATUS_OK;
579 case LSA_POLICY_INFO_MOD:
580 case LSA_POLICY_INFO_AUDIT_FULL_SET:
581 case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
582 /* windows gives INVALID_PARAMETER */
583 *r->out.info = NULL;
584 return NT_STATUS_INVALID_PARAMETER;
587 *r->out.info = NULL;
588 return NT_STATUS_INVALID_INFO_CLASS;
592 lsa_QueryInfoPolicy
594 static NTSTATUS dcesrv_lsa_QueryInfoPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
595 struct lsa_QueryInfoPolicy *r)
597 struct lsa_QueryInfoPolicy2 r2;
598 NTSTATUS status;
600 ZERO_STRUCT(r2);
602 r2.in.handle = r->in.handle;
603 r2.in.level = r->in.level;
604 r2.out.info = r->out.info;
606 status = dcesrv_lsa_QueryInfoPolicy2(dce_call, mem_ctx, &r2);
608 return status;
612 lsa_SetInfoPolicy
614 static NTSTATUS dcesrv_lsa_SetInfoPolicy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
615 struct lsa_SetInfoPolicy *r)
617 /* need to support this */
618 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
623 lsa_ClearAuditLog
625 static NTSTATUS dcesrv_lsa_ClearAuditLog(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
626 struct lsa_ClearAuditLog *r)
628 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
633 lsa_CreateAccount
635 This call does not seem to have any long-term effects, hence no database operations
637 we need to talk to the MS product group to find out what this account database means!
639 answer is that the lsa database is totally separate from the SAM and
640 ldap databases. We are going to need a separate ldb to store these
641 accounts. The SIDs on this account bear no relation to the SIDs in
644 static NTSTATUS dcesrv_lsa_CreateAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
645 struct lsa_CreateAccount *r)
647 struct lsa_account_state *astate;
649 struct lsa_policy_state *state;
650 struct dcesrv_handle *h, *ah;
652 ZERO_STRUCTP(r->out.acct_handle);
654 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
656 state = h->data;
658 astate = talloc(dce_call->conn, struct lsa_account_state);
659 if (astate == NULL) {
660 return NT_STATUS_NO_MEMORY;
663 astate->account_sid = dom_sid_dup(astate, r->in.sid);
664 if (astate->account_sid == NULL) {
665 talloc_free(astate);
666 return NT_STATUS_NO_MEMORY;
669 astate->policy = talloc_reference(astate, state);
670 astate->access_mask = r->in.access_mask;
672 ah = dcesrv_handle_new(dce_call->context, LSA_HANDLE_ACCOUNT);
673 if (!ah) {
674 talloc_free(astate);
675 return NT_STATUS_NO_MEMORY;
678 ah->data = talloc_steal(ah, astate);
680 *r->out.acct_handle = ah->wire_handle;
682 return NT_STATUS_OK;
687 lsa_EnumAccounts
689 static NTSTATUS dcesrv_lsa_EnumAccounts(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
690 struct lsa_EnumAccounts *r)
692 struct dcesrv_handle *h;
693 struct lsa_policy_state *state;
694 int ret;
695 struct ldb_message **res;
696 const char * const attrs[] = { "objectSid", NULL};
697 uint32_t count, i;
699 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
701 state = h->data;
703 /* NOTE: This call must only return accounts that have at least
704 one privilege set
706 ret = gendb_search(state->pdb, mem_ctx, NULL, &res, attrs,
707 "(&(objectSid=*)(privilege=*))");
708 if (ret < 0) {
709 return NT_STATUS_INTERNAL_DB_CORRUPTION;
712 if (*r->in.resume_handle >= ret) {
713 return NT_STATUS_NO_MORE_ENTRIES;
716 count = ret - *r->in.resume_handle;
717 if (count > r->in.num_entries) {
718 count = r->in.num_entries;
721 if (count == 0) {
722 return NT_STATUS_NO_MORE_ENTRIES;
725 r->out.sids->sids = talloc_array(r->out.sids, struct lsa_SidPtr, count);
726 if (r->out.sids->sids == NULL) {
727 return NT_STATUS_NO_MEMORY;
730 for (i=0;i<count;i++) {
731 r->out.sids->sids[i].sid =
732 samdb_result_dom_sid(r->out.sids->sids,
733 res[i + *r->in.resume_handle],
734 "objectSid");
735 NT_STATUS_HAVE_NO_MEMORY(r->out.sids->sids[i].sid);
738 r->out.sids->num_sids = count;
739 *r->out.resume_handle = count + *r->in.resume_handle;
741 return NT_STATUS_OK;
744 /* This decrypts and returns Trusted Domain Auth Information Internal data */
745 static NTSTATUS get_trustdom_auth_blob(struct dcesrv_call_state *dce_call,
746 TALLOC_CTX *mem_ctx, DATA_BLOB *auth_blob,
747 struct trustDomainPasswords *auth_struct)
749 DATA_BLOB session_key = data_blob(NULL, 0);
750 enum ndr_err_code ndr_err;
751 NTSTATUS nt_status;
753 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
754 if (!NT_STATUS_IS_OK(nt_status)) {
755 return nt_status;
758 arcfour_crypt_blob(auth_blob->data, auth_blob->length, &session_key);
759 ndr_err = ndr_pull_struct_blob(auth_blob, mem_ctx,
760 auth_struct,
761 (ndr_pull_flags_fn_t)ndr_pull_trustDomainPasswords);
762 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
763 return NT_STATUS_INVALID_PARAMETER;
766 return NT_STATUS_OK;
769 static NTSTATUS get_trustauth_inout_blob(struct dcesrv_call_state *dce_call,
770 TALLOC_CTX *mem_ctx,
771 struct trustAuthInOutBlob *iopw,
772 DATA_BLOB *trustauth_blob)
774 enum ndr_err_code ndr_err;
776 ndr_err = ndr_push_struct_blob(trustauth_blob, mem_ctx,
777 iopw,
778 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
779 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
780 return NT_STATUS_INVALID_PARAMETER;
783 return NT_STATUS_OK;
786 static NTSTATUS add_trust_user(TALLOC_CTX *mem_ctx,
787 struct ldb_context *sam_ldb,
788 struct ldb_dn *base_dn,
789 const char *netbios_name,
790 struct trustAuthInOutBlob *in,
791 struct ldb_dn **user_dn)
793 struct ldb_message *msg;
794 struct ldb_dn *dn;
795 uint32_t i;
796 int ret;
798 dn = ldb_dn_copy(mem_ctx, base_dn);
799 if (!dn) {
800 return NT_STATUS_NO_MEMORY;
802 if (!ldb_dn_add_child_fmt(dn, "cn=%s$,cn=users", netbios_name)) {
803 return NT_STATUS_NO_MEMORY;
806 msg = ldb_msg_new(mem_ctx);
807 if (!msg) {
808 return NT_STATUS_NO_MEMORY;
810 msg->dn = dn;
812 ret = ldb_msg_add_string(msg, "objectClass", "user");
813 if (ret != LDB_SUCCESS) {
814 return NT_STATUS_NO_MEMORY;
817 ret = ldb_msg_add_fmt(msg, "samAccountName", "%s$", netbios_name);
818 if (ret != LDB_SUCCESS) {
819 return NT_STATUS_NO_MEMORY;
822 ret = samdb_msg_add_uint(sam_ldb, msg, msg, "userAccountControl",
823 UF_INTERDOMAIN_TRUST_ACCOUNT);
824 if (ret != LDB_SUCCESS) {
825 return NT_STATUS_NO_MEMORY;
828 for (i = 0; i < in->count; i++) {
829 const char *attribute;
830 struct ldb_val v;
831 switch (in->current.array[i].AuthType) {
832 case TRUST_AUTH_TYPE_NT4OWF:
833 attribute = "unicodePwd";
834 v.data = (uint8_t *)&in->current.array[i].AuthInfo.nt4owf.password;
835 v.length = 16;
836 break;
837 case TRUST_AUTH_TYPE_CLEAR:
838 attribute = "clearTextPassword";
839 v.data = in->current.array[i].AuthInfo.clear.password;
840 v.length = in->current.array[i].AuthInfo.clear.size;
841 break;
842 default:
843 continue;
846 ret = ldb_msg_add_value(msg, attribute, &v, NULL);
847 if (ret != LDB_SUCCESS) {
848 return NT_STATUS_NO_MEMORY;
852 /* create the trusted_domain user account */
853 ret = ldb_add(sam_ldb, msg);
854 if (ret != LDB_SUCCESS) {
855 DEBUG(0,("Failed to create user record %s: %s\n",
856 ldb_dn_get_linearized(msg->dn),
857 ldb_errstring(sam_ldb)));
859 switch (ret) {
860 case LDB_ERR_ENTRY_ALREADY_EXISTS:
861 return NT_STATUS_DOMAIN_EXISTS;
862 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
863 return NT_STATUS_ACCESS_DENIED;
864 default:
865 return NT_STATUS_INTERNAL_DB_CORRUPTION;
869 if (user_dn) {
870 *user_dn = dn;
872 return NT_STATUS_OK;
876 lsa_CreateTrustedDomainEx2
878 static NTSTATUS dcesrv_lsa_CreateTrustedDomain_base(struct dcesrv_call_state *dce_call,
879 TALLOC_CTX *mem_ctx,
880 struct lsa_CreateTrustedDomainEx2 *r,
881 int op,
882 struct lsa_TrustDomainInfoAuthInfo *unencrypted_auth_info)
884 struct dcesrv_handle *policy_handle;
885 struct lsa_policy_state *policy_state;
886 struct lsa_trusted_domain_state *trusted_domain_state;
887 struct dcesrv_handle *handle;
888 struct ldb_message **msgs, *msg;
889 const char *attrs[] = {
890 NULL
892 const char *netbios_name;
893 const char *dns_name;
894 const char *name;
895 DATA_BLOB trustAuthIncoming, trustAuthOutgoing, auth_blob;
896 struct trustDomainPasswords auth_struct;
897 int ret;
898 NTSTATUS nt_status;
899 struct ldb_context *sam_ldb;
901 DCESRV_PULL_HANDLE(policy_handle, r->in.policy_handle, LSA_HANDLE_POLICY);
902 ZERO_STRUCTP(r->out.trustdom_handle);
904 policy_state = policy_handle->data;
905 sam_ldb = policy_state->sam_ldb;
907 netbios_name = r->in.info->netbios_name.string;
908 if (!netbios_name) {
909 return NT_STATUS_INVALID_PARAMETER;
912 dns_name = r->in.info->domain_name.string;
914 trusted_domain_state = talloc_zero(mem_ctx, struct lsa_trusted_domain_state);
915 if (!trusted_domain_state) {
916 return NT_STATUS_NO_MEMORY;
918 trusted_domain_state->policy = policy_state;
920 if (strcasecmp(netbios_name, "BUILTIN") == 0
921 || (dns_name && strcasecmp(dns_name, "BUILTIN") == 0)
922 || (dom_sid_in_domain(policy_state->builtin_sid, r->in.info->sid))) {
923 return NT_STATUS_INVALID_PARAMETER;
926 if (strcasecmp(netbios_name, policy_state->domain_name) == 0
927 || strcasecmp(netbios_name, policy_state->domain_dns) == 0
928 || (dns_name && strcasecmp(dns_name, policy_state->domain_dns) == 0)
929 || (dns_name && strcasecmp(dns_name, policy_state->domain_name) == 0)
930 || (dom_sid_equal(policy_state->domain_sid, r->in.info->sid))) {
931 return NT_STATUS_CURRENT_DOMAIN_NOT_ALLOWED;
934 /* While this is a REF pointer, some of the functions that wrap this don't provide this */
935 if (op == NDR_LSA_CREATETRUSTEDDOMAIN) {
936 /* No secrets are created at this time, for this function */
937 auth_struct.outgoing.count = 0;
938 auth_struct.incoming.count = 0;
939 } else if (op == NDR_LSA_CREATETRUSTEDDOMAINEX2) {
940 auth_blob = data_blob_const(r->in.auth_info_internal->auth_blob.data,
941 r->in.auth_info_internal->auth_blob.size);
942 nt_status = get_trustdom_auth_blob(dce_call, mem_ctx,
943 &auth_blob, &auth_struct);
944 if (!NT_STATUS_IS_OK(nt_status)) {
945 return nt_status;
947 } else if (op == NDR_LSA_CREATETRUSTEDDOMAINEX) {
949 if (unencrypted_auth_info->incoming_count > 1) {
950 return NT_STATUS_INVALID_PARAMETER;
953 /* more investigation required here, do not create secrets for
954 * now */
955 auth_struct.outgoing.count = 0;
956 auth_struct.incoming.count = 0;
957 } else {
958 return NT_STATUS_INVALID_PARAMETER;
961 if (auth_struct.incoming.count) {
962 nt_status = get_trustauth_inout_blob(dce_call, mem_ctx,
963 &auth_struct.incoming,
964 &trustAuthIncoming);
965 if (!NT_STATUS_IS_OK(nt_status)) {
966 return nt_status;
968 } else {
969 trustAuthIncoming = data_blob(NULL, 0);
972 if (auth_struct.outgoing.count) {
973 nt_status = get_trustauth_inout_blob(dce_call, mem_ctx,
974 &auth_struct.outgoing,
975 &trustAuthOutgoing);
976 if (!NT_STATUS_IS_OK(nt_status)) {
977 return nt_status;
979 } else {
980 trustAuthOutgoing = data_blob(NULL, 0);
983 ret = ldb_transaction_start(sam_ldb);
984 if (ret != LDB_SUCCESS) {
985 return NT_STATUS_INTERNAL_DB_CORRUPTION;
988 if (dns_name) {
989 char *dns_encoded = ldb_binary_encode_string(mem_ctx, dns_name);
990 char *netbios_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
991 /* search for the trusted_domain record */
992 ret = gendb_search(sam_ldb,
993 mem_ctx, policy_state->system_dn, &msgs, attrs,
994 "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)(trustPartner=%s))(objectclass=trustedDomain))",
995 dns_encoded, dns_encoded, dns_encoded, netbios_encoded, netbios_encoded, netbios_encoded);
996 if (ret > 0) {
997 ldb_transaction_cancel(sam_ldb);
998 return NT_STATUS_OBJECT_NAME_COLLISION;
1000 } else {
1001 char *netbios_encoded = ldb_binary_encode_string(mem_ctx, netbios_name);
1002 /* search for the trusted_domain record */
1003 ret = gendb_search(sam_ldb,
1004 mem_ctx, policy_state->system_dn, &msgs, attrs,
1005 "(&(|(flatname=%s)(cn=%s)(trustPartner=%s))(objectclass=trustedDomain))",
1006 netbios_encoded, netbios_encoded, netbios_encoded);
1007 if (ret > 0) {
1008 ldb_transaction_cancel(sam_ldb);
1009 return NT_STATUS_OBJECT_NAME_COLLISION;
1013 if (ret < 0 ) {
1014 ldb_transaction_cancel(sam_ldb);
1015 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1018 name = dns_name ? dns_name : netbios_name;
1020 msg = ldb_msg_new(mem_ctx);
1021 if (msg == NULL) {
1022 return NT_STATUS_NO_MEMORY;
1025 msg->dn = ldb_dn_copy(mem_ctx, policy_state->system_dn);
1026 if ( ! ldb_dn_add_child_fmt(msg->dn, "cn=%s", name)) {
1027 ldb_transaction_cancel(sam_ldb);
1028 return NT_STATUS_NO_MEMORY;
1031 ldb_msg_add_string(msg, "flatname", netbios_name);
1033 if (r->in.info->sid) {
1034 ret = samdb_msg_add_dom_sid(sam_ldb, mem_ctx, msg, "securityIdentifier", r->in.info->sid);
1035 if (ret != LDB_SUCCESS) {
1036 ldb_transaction_cancel(sam_ldb);
1037 return NT_STATUS_INVALID_PARAMETER;
1041 ldb_msg_add_string(msg, "objectClass", "trustedDomain");
1043 samdb_msg_add_int(sam_ldb, mem_ctx, msg, "trustType", r->in.info->trust_type);
1045 samdb_msg_add_int(sam_ldb, mem_ctx, msg, "trustAttributes", r->in.info->trust_attributes);
1047 samdb_msg_add_int(sam_ldb, mem_ctx, msg, "trustDirection", r->in.info->trust_direction);
1049 if (dns_name) {
1050 ldb_msg_add_string(msg, "trustPartner", dns_name);
1053 if (trustAuthIncoming.data) {
1054 ret = ldb_msg_add_value(msg, "trustAuthIncoming", &trustAuthIncoming, NULL);
1055 if (ret != LDB_SUCCESS) {
1056 ldb_transaction_cancel(sam_ldb);
1057 return NT_STATUS_NO_MEMORY;
1060 if (trustAuthOutgoing.data) {
1061 ret = ldb_msg_add_value(msg, "trustAuthOutgoing", &trustAuthOutgoing, NULL);
1062 if (ret != LDB_SUCCESS) {
1063 ldb_transaction_cancel(sam_ldb);
1064 return NT_STATUS_NO_MEMORY;
1068 trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msg->dn);
1070 /* create the trusted_domain */
1071 ret = ldb_add(sam_ldb, msg);
1072 switch (ret) {
1073 case LDB_SUCCESS:
1074 break;
1075 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1076 ldb_transaction_cancel(sam_ldb);
1077 DEBUG(0,("Failed to create trusted domain record %s: %s\n",
1078 ldb_dn_get_linearized(msg->dn),
1079 ldb_errstring(sam_ldb)));
1080 return NT_STATUS_DOMAIN_EXISTS;
1081 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1082 ldb_transaction_cancel(sam_ldb);
1083 DEBUG(0,("Failed to create trusted domain record %s: %s\n",
1084 ldb_dn_get_linearized(msg->dn),
1085 ldb_errstring(sam_ldb)));
1086 return NT_STATUS_ACCESS_DENIED;
1087 default:
1088 ldb_transaction_cancel(sam_ldb);
1089 DEBUG(0,("Failed to create user record %s: %s\n",
1090 ldb_dn_get_linearized(msg->dn),
1091 ldb_errstring(sam_ldb)));
1092 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1095 if (r->in.info->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
1096 struct ldb_dn *user_dn;
1097 /* Inbound trusts must also create a cn=users object to match */
1098 nt_status = add_trust_user(mem_ctx, sam_ldb,
1099 policy_state->domain_dn,
1100 netbios_name,
1101 &auth_struct.incoming,
1102 &user_dn);
1103 if (!NT_STATUS_IS_OK(nt_status)) {
1104 ldb_transaction_cancel(sam_ldb);
1105 return nt_status;
1108 /* save the trust user dn */
1109 trusted_domain_state->trusted_domain_user_dn
1110 = talloc_steal(trusted_domain_state, user_dn);
1113 ret = ldb_transaction_commit(sam_ldb);
1114 if (ret != LDB_SUCCESS) {
1115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1118 handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_TRUSTED_DOMAIN);
1119 if (!handle) {
1120 return NT_STATUS_NO_MEMORY;
1123 handle->data = talloc_steal(handle, trusted_domain_state);
1125 trusted_domain_state->access_mask = r->in.access_mask;
1126 trusted_domain_state->policy = talloc_reference(trusted_domain_state, policy_state);
1128 *r->out.trustdom_handle = handle->wire_handle;
1130 return NT_STATUS_OK;
1134 lsa_CreateTrustedDomainEx2
1136 static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx2(struct dcesrv_call_state *dce_call,
1137 TALLOC_CTX *mem_ctx,
1138 struct lsa_CreateTrustedDomainEx2 *r)
1140 return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, r, NDR_LSA_CREATETRUSTEDDOMAINEX2, NULL);
1143 lsa_CreateTrustedDomainEx
1145 static NTSTATUS dcesrv_lsa_CreateTrustedDomainEx(struct dcesrv_call_state *dce_call,
1146 TALLOC_CTX *mem_ctx,
1147 struct lsa_CreateTrustedDomainEx *r)
1149 struct lsa_CreateTrustedDomainEx2 r2;
1151 r2.in.policy_handle = r->in.policy_handle;
1152 r2.in.info = r->in.info;
1153 r2.out.trustdom_handle = r->out.trustdom_handle;
1154 return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, &r2, NDR_LSA_CREATETRUSTEDDOMAINEX, r->in.auth_info);
1158 lsa_CreateTrustedDomain
1160 static NTSTATUS dcesrv_lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1161 struct lsa_CreateTrustedDomain *r)
1163 struct lsa_CreateTrustedDomainEx2 r2;
1165 r2.in.policy_handle = r->in.policy_handle;
1166 r2.in.info = talloc(mem_ctx, struct lsa_TrustDomainInfoInfoEx);
1167 if (!r2.in.info) {
1168 return NT_STATUS_NO_MEMORY;
1171 r2.in.info->domain_name.string = NULL;
1172 r2.in.info->netbios_name = r->in.info->name;
1173 r2.in.info->sid = r->in.info->sid;
1174 r2.in.info->trust_direction = LSA_TRUST_DIRECTION_OUTBOUND;
1175 r2.in.info->trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1176 r2.in.info->trust_attributes = 0;
1178 r2.in.access_mask = r->in.access_mask;
1179 r2.out.trustdom_handle = r->out.trustdom_handle;
1181 return dcesrv_lsa_CreateTrustedDomain_base(dce_call, mem_ctx, &r2, NDR_LSA_CREATETRUSTEDDOMAIN, NULL);
1185 lsa_OpenTrustedDomain
1187 static NTSTATUS dcesrv_lsa_OpenTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1188 struct lsa_OpenTrustedDomain *r)
1190 struct dcesrv_handle *policy_handle;
1192 struct lsa_policy_state *policy_state;
1193 struct lsa_trusted_domain_state *trusted_domain_state;
1194 struct dcesrv_handle *handle;
1195 struct ldb_message **msgs;
1196 const char *attrs[] = {
1197 "trustDirection",
1198 "flatname",
1199 NULL
1202 const char *sid_string;
1203 int ret;
1205 DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
1206 ZERO_STRUCTP(r->out.trustdom_handle);
1207 policy_state = policy_handle->data;
1209 trusted_domain_state = talloc_zero(mem_ctx, struct lsa_trusted_domain_state);
1210 if (!trusted_domain_state) {
1211 return NT_STATUS_NO_MEMORY;
1213 trusted_domain_state->policy = policy_state;
1215 sid_string = dom_sid_string(mem_ctx, r->in.sid);
1216 if (!sid_string) {
1217 return NT_STATUS_NO_MEMORY;
1220 /* search for the trusted_domain record */
1221 ret = gendb_search(trusted_domain_state->policy->sam_ldb,
1222 mem_ctx, policy_state->system_dn, &msgs, attrs,
1223 "(&(securityIdentifier=%s)(objectclass=trustedDomain))",
1224 sid_string);
1225 if (ret == 0) {
1226 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1229 if (ret != 1) {
1230 DEBUG(0,("Found %d records matching DN %s\n", ret,
1231 ldb_dn_get_linearized(policy_state->system_dn)));
1232 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1235 trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msgs[0]->dn);
1237 trusted_domain_state->trusted_domain_user_dn = NULL;
1239 if (ldb_msg_find_attr_as_int(msgs[0], "trustDirection", 0) & LSA_TRUST_DIRECTION_INBOUND) {
1240 const char *flatname = ldb_binary_encode_string(mem_ctx, ldb_msg_find_attr_as_string(msgs[0], "flatname", NULL));
1241 /* search for the trusted_domain record */
1242 ret = gendb_search(trusted_domain_state->policy->sam_ldb,
1243 mem_ctx, policy_state->domain_dn, &msgs, attrs,
1244 "(&(samaccountname=%s$)(objectclass=user)(userAccountControl:1.2.840.113556.1.4.803:=%u))",
1245 flatname, UF_INTERDOMAIN_TRUST_ACCOUNT);
1246 if (ret == 1) {
1247 trusted_domain_state->trusted_domain_user_dn = talloc_steal(trusted_domain_state, msgs[0]->dn);
1250 handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_TRUSTED_DOMAIN);
1251 if (!handle) {
1252 return NT_STATUS_NO_MEMORY;
1255 handle->data = talloc_steal(handle, trusted_domain_state);
1257 trusted_domain_state->access_mask = r->in.access_mask;
1258 trusted_domain_state->policy = talloc_reference(trusted_domain_state, policy_state);
1260 *r->out.trustdom_handle = handle->wire_handle;
1262 return NT_STATUS_OK;
1267 lsa_OpenTrustedDomainByName
1269 static NTSTATUS dcesrv_lsa_OpenTrustedDomainByName(struct dcesrv_call_state *dce_call,
1270 TALLOC_CTX *mem_ctx,
1271 struct lsa_OpenTrustedDomainByName *r)
1273 struct dcesrv_handle *policy_handle;
1275 struct lsa_policy_state *policy_state;
1276 struct lsa_trusted_domain_state *trusted_domain_state;
1277 struct dcesrv_handle *handle;
1278 struct ldb_message **msgs;
1279 const char *attrs[] = {
1280 NULL
1282 char *td_name;
1283 int ret;
1285 DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
1286 ZERO_STRUCTP(r->out.trustdom_handle);
1287 policy_state = policy_handle->data;
1289 if (!r->in.name.string) {
1290 return NT_STATUS_INVALID_PARAMETER;
1293 trusted_domain_state = talloc_zero(mem_ctx, struct lsa_trusted_domain_state);
1294 if (!trusted_domain_state) {
1295 return NT_STATUS_NO_MEMORY;
1297 trusted_domain_state->policy = policy_state;
1299 /* search for the trusted_domain record */
1300 td_name = ldb_binary_encode_string(mem_ctx, r->in.name.string);
1301 ret = gendb_search(trusted_domain_state->policy->sam_ldb,
1302 mem_ctx, policy_state->system_dn, &msgs, attrs,
1303 "(&(|(flatname=%s)(cn=%s)(trustPartner=%s))"
1304 "(objectclass=trustedDomain))",
1305 td_name, td_name, td_name);
1306 if (ret == 0) {
1307 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1310 if (ret != 1) {
1311 DEBUG(0,("Found %d records matching DN %s\n", ret,
1312 ldb_dn_get_linearized(policy_state->system_dn)));
1313 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1316 /* TODO: perform access checks */
1318 trusted_domain_state->trusted_domain_dn = talloc_reference(trusted_domain_state, msgs[0]->dn);
1320 handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_TRUSTED_DOMAIN);
1321 if (!handle) {
1322 return NT_STATUS_NO_MEMORY;
1325 handle->data = talloc_steal(handle, trusted_domain_state);
1327 trusted_domain_state->access_mask = r->in.access_mask;
1328 trusted_domain_state->policy = talloc_reference(trusted_domain_state, policy_state);
1330 *r->out.trustdom_handle = handle->wire_handle;
1332 return NT_STATUS_OK;
1338 lsa_SetTrustedDomainInfo
1340 static NTSTATUS dcesrv_lsa_SetTrustedDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1341 struct lsa_SetTrustedDomainInfo *r)
1343 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1348 /* parameters 4 to 6 are optional if the dn is a dn of a TDO object,
1349 * otherwise at least one must be provided */
1350 static NTSTATUS get_tdo(struct ldb_context *sam, TALLOC_CTX *mem_ctx,
1351 struct ldb_dn *basedn, const char *dns_domain,
1352 const char *netbios, struct dom_sid2 *sid,
1353 struct ldb_message ***msgs)
1355 const char *attrs[] = { "flatname", "trustPartner",
1356 "securityIdentifier", "trustDirection",
1357 "trustType", "trustAttributes",
1358 "trustPosixOffset",
1359 "msDs-supportedEncryptionTypes", NULL };
1360 char *dns = NULL;
1361 char *nbn = NULL;
1362 char *sidstr = NULL;
1363 char *filter;
1364 int ret;
1367 if (dns_domain || netbios || sid) {
1368 filter = talloc_strdup(mem_ctx,
1369 "(&(objectclass=trustedDomain)(|");
1370 } else {
1371 filter = talloc_strdup(mem_ctx,
1372 "(objectclass=trustedDomain)");
1374 if (!filter) {
1375 return NT_STATUS_NO_MEMORY;
1378 if (dns_domain) {
1379 dns = ldb_binary_encode_string(mem_ctx, dns_domain);
1380 if (!dns) {
1381 return NT_STATUS_NO_MEMORY;
1383 filter = talloc_asprintf_append(filter,
1384 "(trustPartner=%s)", dns);
1385 if (!filter) {
1386 return NT_STATUS_NO_MEMORY;
1389 if (netbios) {
1390 nbn = ldb_binary_encode_string(mem_ctx, netbios);
1391 if (!nbn) {
1392 return NT_STATUS_NO_MEMORY;
1394 filter = talloc_asprintf_append(filter,
1395 "(flatname=%s)", nbn);
1396 if (!filter) {
1397 return NT_STATUS_NO_MEMORY;
1400 if (sid) {
1401 sidstr = dom_sid_string(mem_ctx, sid);
1402 if (!sidstr) {
1403 return NT_STATUS_INVALID_PARAMETER;
1405 filter = talloc_asprintf_append(filter,
1406 "(securityIdentifier=%s)",
1407 sidstr);
1408 if (!filter) {
1409 return NT_STATUS_NO_MEMORY;
1412 if (dns_domain || netbios || sid) {
1413 filter = talloc_asprintf_append(filter, "))");
1414 if (!filter) {
1415 return NT_STATUS_NO_MEMORY;
1419 ret = gendb_search(sam, mem_ctx, basedn, msgs, attrs, "%s", filter);
1420 if (ret == 0) {
1421 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1424 if (ret != 1) {
1425 return NT_STATUS_OBJECT_NAME_COLLISION;
1428 return NT_STATUS_OK;
1431 static NTSTATUS update_uint32_t_value(TALLOC_CTX *mem_ctx,
1432 struct ldb_context *sam_ldb,
1433 struct ldb_message *orig,
1434 struct ldb_message *dest,
1435 const char *attribute,
1436 uint32_t value,
1437 uint32_t *orig_value)
1439 const struct ldb_val *orig_val;
1440 uint32_t orig_uint = 0;
1441 unsigned int flags = 0;
1442 int ret;
1444 orig_val = ldb_msg_find_ldb_val(orig, attribute);
1445 if (!orig_val || !orig_val->data) {
1446 /* add new attribute */
1447 flags = LDB_FLAG_MOD_ADD;
1449 } else {
1450 errno = 0;
1451 orig_uint = strtoul((const char *)orig_val->data, NULL, 0);
1452 if (errno != 0 || orig_uint != value) {
1453 /* replace also if can't get value */
1454 flags = LDB_FLAG_MOD_REPLACE;
1458 if (flags == 0) {
1459 /* stored value is identical, nothing to change */
1460 goto done;
1463 ret = ldb_msg_add_empty(dest, attribute, flags, NULL);
1464 if (ret != LDB_SUCCESS) {
1465 return NT_STATUS_NO_MEMORY;
1468 ret = samdb_msg_add_uint(sam_ldb, dest, dest, attribute, value);
1469 if (ret != LDB_SUCCESS) {
1470 return NT_STATUS_NO_MEMORY;
1473 done:
1474 if (orig_value) {
1475 *orig_value = orig_uint;
1477 return NT_STATUS_OK;
1480 static NTSTATUS update_trust_user(TALLOC_CTX *mem_ctx,
1481 struct ldb_context *sam_ldb,
1482 struct ldb_dn *base_dn,
1483 bool delete_user,
1484 const char *netbios_name,
1485 struct trustAuthInOutBlob *in)
1487 const char *attrs[] = { "userAccountControl", NULL };
1488 struct ldb_message **msgs;
1489 struct ldb_message *msg;
1490 uint32_t uac;
1491 uint32_t i;
1492 int ret;
1494 ret = gendb_search(sam_ldb, mem_ctx,
1495 base_dn, &msgs, attrs,
1496 "samAccountName=%s$", netbios_name);
1497 if (ret > 1) {
1498 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1501 if (ret == 0) {
1502 if (delete_user) {
1503 return NT_STATUS_OK;
1506 /* ok no existing user, add it from scratch */
1507 return add_trust_user(mem_ctx, sam_ldb, base_dn,
1508 netbios_name, in, NULL);
1511 /* check user is what we are looking for */
1512 uac = ldb_msg_find_attr_as_uint(msgs[0],
1513 "userAccountControl", 0);
1514 if (!(uac & UF_INTERDOMAIN_TRUST_ACCOUNT)) {
1515 return NT_STATUS_OBJECT_NAME_COLLISION;
1518 if (delete_user) {
1519 ret = ldb_delete(sam_ldb, msgs[0]->dn);
1520 switch (ret) {
1521 case LDB_SUCCESS:
1522 return NT_STATUS_OK;
1523 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1524 return NT_STATUS_ACCESS_DENIED;
1525 default:
1526 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1530 /* entry exists, just modify secret if any */
1531 if (in == NULL || in->count == 0) {
1532 return NT_STATUS_OK;
1535 msg = ldb_msg_new(mem_ctx);
1536 if (!msg) {
1537 return NT_STATUS_NO_MEMORY;
1539 msg->dn = msgs[0]->dn;
1541 for (i = 0; i < in->count; i++) {
1542 const char *attribute;
1543 struct ldb_val v;
1544 switch (in->current.array[i].AuthType) {
1545 case TRUST_AUTH_TYPE_NT4OWF:
1546 attribute = "unicodePwd";
1547 v.data = (uint8_t *)&in->current.array[i].AuthInfo.nt4owf.password;
1548 v.length = 16;
1549 break;
1550 case TRUST_AUTH_TYPE_CLEAR:
1551 attribute = "clearTextPassword";
1552 v.data = in->current.array[i].AuthInfo.clear.password;
1553 v.length = in->current.array[i].AuthInfo.clear.size;
1554 break;
1555 default:
1556 continue;
1559 ret = ldb_msg_add_empty(msg, attribute,
1560 LDB_FLAG_MOD_REPLACE, NULL);
1561 if (ret != LDB_SUCCESS) {
1562 return NT_STATUS_NO_MEMORY;
1565 ret = ldb_msg_add_value(msg, attribute, &v, NULL);
1566 if (ret != LDB_SUCCESS) {
1567 return NT_STATUS_NO_MEMORY;
1571 /* create the trusted_domain user account */
1572 ret = ldb_modify(sam_ldb, msg);
1573 if (ret != LDB_SUCCESS) {
1574 DEBUG(0,("Failed to create user record %s: %s\n",
1575 ldb_dn_get_linearized(msg->dn),
1576 ldb_errstring(sam_ldb)));
1578 switch (ret) {
1579 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1580 return NT_STATUS_DOMAIN_EXISTS;
1581 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1582 return NT_STATUS_ACCESS_DENIED;
1583 default:
1584 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1588 return NT_STATUS_OK;
1592 static NTSTATUS setInfoTrustedDomain_base(struct dcesrv_call_state *dce_call,
1593 struct dcesrv_handle *p_handle,
1594 TALLOC_CTX *mem_ctx,
1595 struct ldb_message *dom_msg,
1596 enum lsa_TrustDomInfoEnum level,
1597 union lsa_TrustedDomainInfo *info)
1599 struct lsa_policy_state *p_state = p_handle->data;
1600 uint32_t *posix_offset = NULL;
1601 struct lsa_TrustDomainInfoInfoEx *info_ex = NULL;
1602 struct lsa_TrustDomainInfoAuthInfo *auth_info = NULL;
1603 struct lsa_TrustDomainInfoAuthInfoInternal *auth_info_int = NULL;
1604 uint32_t *enc_types = NULL;
1605 DATA_BLOB trustAuthIncoming, trustAuthOutgoing, auth_blob;
1606 struct trustDomainPasswords auth_struct;
1607 struct trustAuthInOutBlob *current_passwords = NULL;
1608 NTSTATUS nt_status;
1609 struct ldb_message **msgs;
1610 struct ldb_message *msg;
1611 bool add_outgoing = false;
1612 bool add_incoming = false;
1613 bool del_outgoing = false;
1614 bool del_incoming = false;
1615 bool in_transaction = false;
1616 int ret;
1617 bool am_rodc;
1619 switch (level) {
1620 case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET:
1621 posix_offset = &info->posix_offset.posix_offset;
1622 break;
1623 case LSA_TRUSTED_DOMAIN_INFO_INFO_EX:
1624 info_ex = &info->info_ex;
1625 break;
1626 case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO:
1627 auth_info = &info->auth_info;
1628 break;
1629 case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO:
1630 posix_offset = &info->full_info.posix_offset.posix_offset;
1631 info_ex = &info->full_info.info_ex;
1632 auth_info = &info->full_info.auth_info;
1633 break;
1634 case LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO_INTERNAL:
1635 auth_info_int = &info->auth_info_internal;
1636 break;
1637 case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_INTERNAL:
1638 posix_offset = &info->full_info_internal.posix_offset.posix_offset;
1639 info_ex = &info->full_info_internal.info_ex;
1640 auth_info_int = &info->full_info_internal.auth_info;
1641 break;
1642 case LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES:
1643 enc_types = &info->enc_types.enc_types;
1644 break;
1645 default:
1646 return NT_STATUS_INVALID_PARAMETER;
1649 if (auth_info) {
1650 nt_status = auth_info_2_auth_blob(mem_ctx, auth_info,
1651 &trustAuthIncoming,
1652 &trustAuthOutgoing);
1653 if (!NT_STATUS_IS_OK(nt_status)) {
1654 return nt_status;
1656 if (trustAuthIncoming.data) {
1657 /* This does the decode of some of this twice, but it is easier that way */
1658 nt_status = auth_info_2_trustauth_inout(mem_ctx,
1659 auth_info->incoming_count,
1660 auth_info->incoming_current_auth_info,
1661 NULL,
1662 &current_passwords);
1663 if (!NT_STATUS_IS_OK(nt_status)) {
1664 return nt_status;
1669 /* decode auth_info_int if set */
1670 if (auth_info_int) {
1672 /* now decrypt blob */
1673 auth_blob = data_blob_const(auth_info_int->auth_blob.data,
1674 auth_info_int->auth_blob.size);
1676 nt_status = get_trustdom_auth_blob(dce_call, mem_ctx,
1677 &auth_blob, &auth_struct);
1678 if (!NT_STATUS_IS_OK(nt_status)) {
1679 return nt_status;
1683 if (info_ex) {
1684 /* verify data matches */
1685 if (info_ex->trust_attributes &
1686 LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1687 /* TODO: check what behavior level we have */
1688 if (strcasecmp_m(p_state->domain_dns,
1689 p_state->forest_dns) != 0) {
1690 return NT_STATUS_INVALID_DOMAIN_STATE;
1694 ret = samdb_rodc(p_state->sam_ldb, &am_rodc);
1695 if (ret == LDB_SUCCESS && am_rodc) {
1696 return NT_STATUS_NO_SUCH_DOMAIN;
1699 /* verify only one object matches the dns/netbios/sid
1700 * triplet and that this is the one we already have */
1701 nt_status = get_tdo(p_state->sam_ldb, mem_ctx,
1702 p_state->system_dn,
1703 info_ex->domain_name.string,
1704 info_ex->netbios_name.string,
1705 info_ex->sid, &msgs);
1706 if (!NT_STATUS_IS_OK(nt_status)) {
1707 return nt_status;
1709 if (ldb_dn_compare(dom_msg->dn, msgs[0]->dn) != 0) {
1710 return NT_STATUS_OBJECT_NAME_COLLISION;
1712 talloc_free(msgs);
1715 /* TODO: should we fetch previous values from the existing entry
1716 * and append them ? */
1717 if (auth_info_int && auth_struct.incoming.count) {
1718 nt_status = get_trustauth_inout_blob(dce_call, mem_ctx,
1719 &auth_struct.incoming,
1720 &trustAuthIncoming);
1721 if (!NT_STATUS_IS_OK(nt_status)) {
1722 return nt_status;
1725 current_passwords = &auth_struct.incoming;
1727 } else {
1728 trustAuthIncoming = data_blob(NULL, 0);
1731 if (auth_info_int && auth_struct.outgoing.count) {
1732 nt_status = get_trustauth_inout_blob(dce_call, mem_ctx,
1733 &auth_struct.outgoing,
1734 &trustAuthOutgoing);
1735 if (!NT_STATUS_IS_OK(nt_status)) {
1736 return nt_status;
1738 } else {
1739 trustAuthOutgoing = data_blob(NULL, 0);
1742 msg = ldb_msg_new(mem_ctx);
1743 if (msg == NULL) {
1744 return NT_STATUS_NO_MEMORY;
1746 msg->dn = dom_msg->dn;
1748 if (posix_offset) {
1749 nt_status = update_uint32_t_value(mem_ctx, p_state->sam_ldb,
1750 dom_msg, msg,
1751 "trustPosixOffset",
1752 *posix_offset, NULL);
1753 if (!NT_STATUS_IS_OK(nt_status)) {
1754 return nt_status;
1758 if (info_ex) {
1759 uint32_t origattrs;
1760 uint32_t origdir;
1761 int origtype;
1763 nt_status = update_uint32_t_value(mem_ctx, p_state->sam_ldb,
1764 dom_msg, msg,
1765 "trustDirection",
1766 info_ex->trust_direction,
1767 &origdir);
1768 if (!NT_STATUS_IS_OK(nt_status)) {
1769 return nt_status;
1772 if (info_ex->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
1773 add_incoming = true;
1775 if (info_ex->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
1776 add_outgoing = true;
1779 if ((origdir & LSA_TRUST_DIRECTION_INBOUND) &&
1780 !(info_ex->trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
1781 del_incoming = true;
1783 if ((origdir & LSA_TRUST_DIRECTION_OUTBOUND) &&
1784 !(info_ex->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
1785 del_outgoing = true;
1788 origtype = ldb_msg_find_attr_as_int(dom_msg, "trustType", -1);
1789 if (origtype == -1 || origtype != info_ex->trust_type) {
1790 DEBUG(1, ("Attempted to change trust type! "
1791 "Operation not handled\n"));
1792 return NT_STATUS_INVALID_PARAMETER;
1795 nt_status = update_uint32_t_value(mem_ctx, p_state->sam_ldb,
1796 dom_msg, msg,
1797 "trustAttributes",
1798 info_ex->trust_attributes,
1799 &origattrs);
1800 if (!NT_STATUS_IS_OK(nt_status)) {
1801 return nt_status;
1803 /* TODO: check forestFunctionality from ldb opaque */
1804 /* TODO: check what is set makes sense */
1805 /* for now refuse changes */
1806 if (origattrs == -1 ||
1807 origattrs != info_ex->trust_attributes) {
1808 DEBUG(1, ("Attempted to change trust attributes! "
1809 "Operation not handled\n"));
1810 return NT_STATUS_INVALID_PARAMETER;
1814 if (enc_types) {
1815 nt_status = update_uint32_t_value(mem_ctx, p_state->sam_ldb,
1816 dom_msg, msg,
1817 "msDS-SupportedEncryptionTypes",
1818 *enc_types, NULL);
1819 if (!NT_STATUS_IS_OK(nt_status)) {
1820 return nt_status;
1824 if (add_incoming && trustAuthIncoming.data) {
1825 ret = ldb_msg_add_empty(msg, "trustAuthIncoming",
1826 LDB_FLAG_MOD_REPLACE, NULL);
1827 if (ret != LDB_SUCCESS) {
1828 return NT_STATUS_NO_MEMORY;
1830 ret = ldb_msg_add_value(msg, "trustAuthIncoming",
1831 &trustAuthIncoming, NULL);
1832 if (ret != LDB_SUCCESS) {
1833 return NT_STATUS_NO_MEMORY;
1836 if (add_outgoing && trustAuthOutgoing.data) {
1837 ret = ldb_msg_add_empty(msg, "trustAuthOutgoing",
1838 LDB_FLAG_MOD_REPLACE, NULL);
1839 if (ret != LDB_SUCCESS) {
1840 return NT_STATUS_NO_MEMORY;
1842 ret = ldb_msg_add_value(msg, "trustAuthOutgoing",
1843 &trustAuthOutgoing, NULL);
1844 if (ret != LDB_SUCCESS) {
1845 return NT_STATUS_NO_MEMORY;
1849 /* start transaction */
1850 ret = ldb_transaction_start(p_state->sam_ldb);
1851 if (ret != LDB_SUCCESS) {
1852 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1854 in_transaction = true;
1856 if (msg->num_elements) {
1857 ret = ldb_modify(p_state->sam_ldb, msg);
1858 if (ret != LDB_SUCCESS) {
1859 DEBUG(1,("Failed to modify trusted domain record %s: %s\n",
1860 ldb_dn_get_linearized(msg->dn),
1861 ldb_errstring(p_state->sam_ldb)));
1862 nt_status = dsdb_ldb_err_to_ntstatus(ret);
1863 goto done;
1867 if (add_incoming || del_incoming) {
1868 const char *netbios_name;
1870 netbios_name = ldb_msg_find_attr_as_string(dom_msg,
1871 "flatname", NULL);
1872 if (!netbios_name) {
1873 nt_status = NT_STATUS_INVALID_DOMAIN_STATE;
1874 goto done;
1877 /* We use trustAuthIncoming.data to incidate that auth_struct.incoming is valid */
1878 nt_status = update_trust_user(mem_ctx,
1879 p_state->sam_ldb,
1880 p_state->domain_dn,
1881 del_incoming,
1882 netbios_name,
1883 current_passwords);
1884 if (!NT_STATUS_IS_OK(nt_status)) {
1885 goto done;
1889 /* ok, all fine, commit transaction and return */
1890 ret = ldb_transaction_commit(p_state->sam_ldb);
1891 if (ret != LDB_SUCCESS) {
1892 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1894 in_transaction = false;
1896 nt_status = NT_STATUS_OK;
1898 done:
1899 if (in_transaction) {
1900 ldb_transaction_cancel(p_state->sam_ldb);
1902 return nt_status;
1906 lsa_SetInfomrationTrustedDomain
1908 static NTSTATUS dcesrv_lsa_SetInformationTrustedDomain(
1909 struct dcesrv_call_state *dce_call,
1910 TALLOC_CTX *mem_ctx,
1911 struct lsa_SetInformationTrustedDomain *r)
1913 struct dcesrv_handle *h;
1914 struct lsa_trusted_domain_state *td_state;
1915 struct ldb_message **msgs;
1916 NTSTATUS nt_status;
1918 DCESRV_PULL_HANDLE(h, r->in.trustdom_handle,
1919 LSA_HANDLE_TRUSTED_DOMAIN);
1921 td_state = talloc_get_type(h->data, struct lsa_trusted_domain_state);
1923 /* get the trusted domain object */
1924 nt_status = get_tdo(td_state->policy->sam_ldb, mem_ctx,
1925 td_state->trusted_domain_dn,
1926 NULL, NULL, NULL, &msgs);
1927 if (!NT_STATUS_IS_OK(nt_status)) {
1928 if (NT_STATUS_EQUAL(nt_status,
1929 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1930 return nt_status;
1932 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1935 return setInfoTrustedDomain_base(dce_call, h, mem_ctx,
1936 msgs[0], r->in.level, r->in.info);
1941 lsa_DeleteTrustedDomain
1943 static NTSTATUS dcesrv_lsa_DeleteTrustedDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1944 struct lsa_DeleteTrustedDomain *r)
1946 NTSTATUS status;
1947 struct lsa_OpenTrustedDomain opn;
1948 struct lsa_DeleteObject del;
1949 struct dcesrv_handle *h;
1951 opn.in.handle = r->in.handle;
1952 opn.in.sid = r->in.dom_sid;
1953 opn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
1954 opn.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
1955 if (!opn.out.trustdom_handle) {
1956 return NT_STATUS_NO_MEMORY;
1958 status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &opn);
1959 if (!NT_STATUS_IS_OK(status)) {
1960 return status;
1963 DCESRV_PULL_HANDLE(h, opn.out.trustdom_handle, DCESRV_HANDLE_ANY);
1964 talloc_steal(mem_ctx, h);
1966 del.in.handle = opn.out.trustdom_handle;
1967 del.out.handle = opn.out.trustdom_handle;
1968 status = dcesrv_lsa_DeleteObject(dce_call, mem_ctx, &del);
1969 if (!NT_STATUS_IS_OK(status)) {
1970 return status;
1972 return NT_STATUS_OK;
1975 static NTSTATUS fill_trust_domain_ex(TALLOC_CTX *mem_ctx,
1976 struct ldb_message *msg,
1977 struct lsa_TrustDomainInfoInfoEx *info_ex)
1979 info_ex->domain_name.string
1980 = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
1981 info_ex->netbios_name.string
1982 = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
1983 info_ex->sid
1984 = samdb_result_dom_sid(mem_ctx, msg, "securityIdentifier");
1985 info_ex->trust_direction
1986 = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
1987 info_ex->trust_type
1988 = ldb_msg_find_attr_as_int(msg, "trustType", 0);
1989 info_ex->trust_attributes
1990 = ldb_msg_find_attr_as_int(msg, "trustAttributes", 0);
1991 return NT_STATUS_OK;
1995 lsa_QueryTrustedDomainInfo
1997 static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1998 struct lsa_QueryTrustedDomainInfo *r)
2000 union lsa_TrustedDomainInfo *info = NULL;
2001 struct dcesrv_handle *h;
2002 struct lsa_trusted_domain_state *trusted_domain_state;
2003 struct ldb_message *msg;
2004 int ret;
2005 struct ldb_message **res;
2006 const char *attrs[] = {
2007 "flatname",
2008 "trustPartner",
2009 "securityIdentifier",
2010 "trustDirection",
2011 "trustType",
2012 "trustAttributes",
2013 "msDs-supportedEncryptionTypes",
2014 NULL
2017 DCESRV_PULL_HANDLE(h, r->in.trustdom_handle, LSA_HANDLE_TRUSTED_DOMAIN);
2019 trusted_domain_state = talloc_get_type(h->data, struct lsa_trusted_domain_state);
2021 /* pull all the user attributes */
2022 ret = gendb_search_dn(trusted_domain_state->policy->sam_ldb, mem_ctx,
2023 trusted_domain_state->trusted_domain_dn, &res, attrs);
2024 if (ret != 1) {
2025 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2027 msg = res[0];
2029 info = talloc_zero(mem_ctx, union lsa_TrustedDomainInfo);
2030 if (!info) {
2031 return NT_STATUS_NO_MEMORY;
2033 *r->out.info = info;
2035 switch (r->in.level) {
2036 case LSA_TRUSTED_DOMAIN_INFO_NAME:
2037 info->name.netbios_name.string
2038 = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
2039 break;
2040 case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET:
2041 info->posix_offset.posix_offset
2042 = ldb_msg_find_attr_as_uint(msg, "posixOffset", 0);
2043 break;
2044 #if 0 /* Win2k3 doesn't implement this */
2045 case LSA_TRUSTED_DOMAIN_INFO_BASIC:
2046 r->out.info->info_basic.netbios_name.string
2047 = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
2048 r->out.info->info_basic.sid
2049 = samdb_result_dom_sid(mem_ctx, msg, "securityIdentifier");
2050 break;
2051 #endif
2052 case LSA_TRUSTED_DOMAIN_INFO_INFO_EX:
2053 return fill_trust_domain_ex(mem_ctx, msg, &info->info_ex);
2055 case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO:
2056 ZERO_STRUCT(info->full_info);
2057 return fill_trust_domain_ex(mem_ctx, msg, &info->full_info.info_ex);
2058 case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_2_INTERNAL:
2059 ZERO_STRUCT(info->full_info2_internal);
2060 info->full_info2_internal.posix_offset.posix_offset
2061 = ldb_msg_find_attr_as_uint(msg, "posixOffset", 0);
2062 return fill_trust_domain_ex(mem_ctx, msg, &info->full_info2_internal.info.info_ex);
2064 case LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES:
2065 info->enc_types.enc_types
2066 = ldb_msg_find_attr_as_uint(msg, "msDs-supportedEncryptionTypes", KERB_ENCTYPE_RC4_HMAC_MD5);
2067 break;
2069 case LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS:
2070 case LSA_TRUSTED_DOMAIN_INFO_INFO_EX2_INTERNAL:
2071 /* oops, we don't want to return the info after all */
2072 talloc_free(info);
2073 *r->out.info = NULL;
2074 return NT_STATUS_INVALID_PARAMETER;
2075 default:
2076 /* oops, we don't want to return the info after all */
2077 talloc_free(info);
2078 *r->out.info = NULL;
2079 return NT_STATUS_INVALID_INFO_CLASS;
2082 return NT_STATUS_OK;
2087 lsa_QueryTrustedDomainInfoBySid
2089 static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfoBySid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2090 struct lsa_QueryTrustedDomainInfoBySid *r)
2092 NTSTATUS status;
2093 struct lsa_OpenTrustedDomain opn;
2094 struct lsa_QueryTrustedDomainInfo query;
2095 struct dcesrv_handle *h;
2097 opn.in.handle = r->in.handle;
2098 opn.in.sid = r->in.dom_sid;
2099 opn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
2100 opn.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
2101 if (!opn.out.trustdom_handle) {
2102 return NT_STATUS_NO_MEMORY;
2104 status = dcesrv_lsa_OpenTrustedDomain(dce_call, mem_ctx, &opn);
2105 if (!NT_STATUS_IS_OK(status)) {
2106 return status;
2109 /* Ensure this handle goes away at the end of this call */
2110 DCESRV_PULL_HANDLE(h, opn.out.trustdom_handle, DCESRV_HANDLE_ANY);
2111 talloc_steal(mem_ctx, h);
2113 query.in.trustdom_handle = opn.out.trustdom_handle;
2114 query.in.level = r->in.level;
2115 query.out.info = r->out.info;
2116 status = dcesrv_lsa_QueryTrustedDomainInfo(dce_call, mem_ctx, &query);
2117 if (!NT_STATUS_IS_OK(status)) {
2118 return status;
2121 return NT_STATUS_OK;
2125 lsa_SetTrustedDomainInfoByName
2127 static NTSTATUS dcesrv_lsa_SetTrustedDomainInfoByName(struct dcesrv_call_state *dce_call,
2128 TALLOC_CTX *mem_ctx,
2129 struct lsa_SetTrustedDomainInfoByName *r)
2131 struct dcesrv_handle *policy_handle;
2132 struct lsa_policy_state *policy_state;
2133 struct ldb_message **msgs;
2134 NTSTATUS nt_status;
2136 DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
2137 policy_state = policy_handle->data;
2139 /* get the trusted domain object */
2140 nt_status = get_tdo(policy_state->sam_ldb, mem_ctx,
2141 policy_state->domain_dn,
2142 r->in.trusted_domain->string,
2143 r->in.trusted_domain->string,
2144 NULL, &msgs);
2145 if (!NT_STATUS_IS_OK(nt_status)) {
2146 if (NT_STATUS_EQUAL(nt_status,
2147 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2148 return nt_status;
2150 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2153 return setInfoTrustedDomain_base(dce_call, policy_handle, mem_ctx,
2154 msgs[0], r->in.level, r->in.info);
2158 lsa_QueryTrustedDomainInfoByName
2160 static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfoByName(struct dcesrv_call_state *dce_call,
2161 TALLOC_CTX *mem_ctx,
2162 struct lsa_QueryTrustedDomainInfoByName *r)
2164 NTSTATUS status;
2165 struct lsa_OpenTrustedDomainByName opn;
2166 struct lsa_QueryTrustedDomainInfo query;
2167 struct dcesrv_handle *h;
2169 opn.in.handle = r->in.handle;
2170 opn.in.name = *r->in.trusted_domain;
2171 opn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
2172 opn.out.trustdom_handle = talloc(mem_ctx, struct policy_handle);
2173 if (!opn.out.trustdom_handle) {
2174 return NT_STATUS_NO_MEMORY;
2176 status = dcesrv_lsa_OpenTrustedDomainByName(dce_call, mem_ctx, &opn);
2177 if (!NT_STATUS_IS_OK(status)) {
2178 return status;
2181 /* Ensure this handle goes away at the end of this call */
2182 DCESRV_PULL_HANDLE(h, opn.out.trustdom_handle, DCESRV_HANDLE_ANY);
2183 talloc_steal(mem_ctx, h);
2185 query.in.trustdom_handle = opn.out.trustdom_handle;
2186 query.in.level = r->in.level;
2187 query.out.info = r->out.info;
2188 status = dcesrv_lsa_QueryTrustedDomainInfo(dce_call, mem_ctx, &query);
2189 if (!NT_STATUS_IS_OK(status)) {
2190 return status;
2193 return NT_STATUS_OK;
2197 lsa_CloseTrustedDomainEx
2199 static NTSTATUS dcesrv_lsa_CloseTrustedDomainEx(struct dcesrv_call_state *dce_call,
2200 TALLOC_CTX *mem_ctx,
2201 struct lsa_CloseTrustedDomainEx *r)
2203 /* The result of a bad hair day from an IDL programmer? Not
2204 * implmented in Win2k3. You should always just lsa_Close
2205 * anyway. */
2206 return NT_STATUS_NOT_IMPLEMENTED;
2211 comparison function for sorting lsa_DomainInformation array
2213 static int compare_DomainInfo(struct lsa_DomainInfo *e1, struct lsa_DomainInfo *e2)
2215 return strcasecmp_m(e1->name.string, e2->name.string);
2219 lsa_EnumTrustDom
2221 static NTSTATUS dcesrv_lsa_EnumTrustDom(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2222 struct lsa_EnumTrustDom *r)
2224 struct dcesrv_handle *policy_handle;
2225 struct lsa_DomainInfo *entries;
2226 struct lsa_policy_state *policy_state;
2227 struct ldb_message **domains;
2228 const char *attrs[] = {
2229 "flatname",
2230 "securityIdentifier",
2231 NULL
2235 int count, i;
2237 *r->out.resume_handle = 0;
2239 r->out.domains->domains = NULL;
2240 r->out.domains->count = 0;
2242 DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
2244 policy_state = policy_handle->data;
2246 /* search for all users in this domain. This could possibly be cached and
2247 resumed based on resume_key */
2248 count = gendb_search(policy_state->sam_ldb, mem_ctx, policy_state->system_dn, &domains, attrs,
2249 "objectclass=trustedDomain");
2250 if (count < 0) {
2251 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2254 /* convert to lsa_TrustInformation format */
2255 entries = talloc_array(mem_ctx, struct lsa_DomainInfo, count);
2256 if (!entries) {
2257 return NT_STATUS_NO_MEMORY;
2259 for (i=0;i<count;i++) {
2260 entries[i].sid = samdb_result_dom_sid(mem_ctx, domains[i], "securityIdentifier");
2261 entries[i].name.string = ldb_msg_find_attr_as_string(domains[i], "flatname", NULL);
2264 /* sort the results by name */
2265 TYPESAFE_QSORT(entries, count, compare_DomainInfo);
2267 if (*r->in.resume_handle >= count) {
2268 *r->out.resume_handle = -1;
2270 return NT_STATUS_NO_MORE_ENTRIES;
2273 /* return the rest, limit by max_size. Note that we
2274 use the w2k3 element size value of 60 */
2275 r->out.domains->count = count - *r->in.resume_handle;
2276 r->out.domains->count = MIN(r->out.domains->count,
2277 1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_MULTIPLIER));
2279 r->out.domains->domains = entries + *r->in.resume_handle;
2280 r->out.domains->count = r->out.domains->count;
2282 if (r->out.domains->count < count - *r->in.resume_handle) {
2283 *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count;
2284 return STATUS_MORE_ENTRIES;
2287 /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST
2288 * always be larger than the previous input resume handle, in
2289 * particular when hitting the last query it is vital to set the
2290 * resume handle correctly to avoid infinite client loops, as
2291 * seen e.g. with Windows XP SP3 when resume handle is 0 and
2292 * status is NT_STATUS_OK - gd */
2294 *r->out.resume_handle = (uint32_t)-1;
2296 return NT_STATUS_OK;
2300 comparison function for sorting lsa_DomainInformation array
2302 static int compare_TrustDomainInfoInfoEx(struct lsa_TrustDomainInfoInfoEx *e1, struct lsa_TrustDomainInfoInfoEx *e2)
2304 return strcasecmp_m(e1->netbios_name.string, e2->netbios_name.string);
2308 lsa_EnumTrustedDomainsEx
2310 static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2311 struct lsa_EnumTrustedDomainsEx *r)
2313 struct dcesrv_handle *policy_handle;
2314 struct lsa_TrustDomainInfoInfoEx *entries;
2315 struct lsa_policy_state *policy_state;
2316 struct ldb_message **domains;
2317 const char *attrs[] = {
2318 "flatname",
2319 "trustPartner",
2320 "securityIdentifier",
2321 "trustDirection",
2322 "trustType",
2323 "trustAttributes",
2324 NULL
2326 NTSTATUS nt_status;
2328 int count, i;
2330 *r->out.resume_handle = 0;
2332 r->out.domains->domains = NULL;
2333 r->out.domains->count = 0;
2335 DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
2337 policy_state = policy_handle->data;
2339 /* search for all users in this domain. This could possibly be cached and
2340 resumed based on resume_key */
2341 count = gendb_search(policy_state->sam_ldb, mem_ctx, policy_state->system_dn, &domains, attrs,
2342 "objectclass=trustedDomain");
2343 if (count < 0) {
2344 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2347 /* convert to lsa_DomainInformation format */
2348 entries = talloc_array(mem_ctx, struct lsa_TrustDomainInfoInfoEx, count);
2349 if (!entries) {
2350 return NT_STATUS_NO_MEMORY;
2352 for (i=0;i<count;i++) {
2353 nt_status = fill_trust_domain_ex(mem_ctx, domains[i], &entries[i]);
2354 if (!NT_STATUS_IS_OK(nt_status)) {
2355 return nt_status;
2359 /* sort the results by name */
2360 TYPESAFE_QSORT(entries, count, compare_TrustDomainInfoInfoEx);
2362 if (*r->in.resume_handle >= count) {
2363 *r->out.resume_handle = -1;
2365 return NT_STATUS_NO_MORE_ENTRIES;
2368 /* return the rest, limit by max_size. Note that we
2369 use the w2k3 element size value of 60 */
2370 r->out.domains->count = count - *r->in.resume_handle;
2371 r->out.domains->count = MIN(r->out.domains->count,
2372 1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER));
2374 r->out.domains->domains = entries + *r->in.resume_handle;
2375 r->out.domains->count = r->out.domains->count;
2377 if (r->out.domains->count < count - *r->in.resume_handle) {
2378 *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count;
2379 return STATUS_MORE_ENTRIES;
2382 return NT_STATUS_OK;
2387 lsa_OpenAccount
2389 static NTSTATUS dcesrv_lsa_OpenAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2390 struct lsa_OpenAccount *r)
2392 struct dcesrv_handle *h, *ah;
2393 struct lsa_policy_state *state;
2394 struct lsa_account_state *astate;
2396 ZERO_STRUCTP(r->out.acct_handle);
2398 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
2400 state = h->data;
2402 astate = talloc(dce_call->conn, struct lsa_account_state);
2403 if (astate == NULL) {
2404 return NT_STATUS_NO_MEMORY;
2407 astate->account_sid = dom_sid_dup(astate, r->in.sid);
2408 if (astate->account_sid == NULL) {
2409 talloc_free(astate);
2410 return NT_STATUS_NO_MEMORY;
2413 astate->policy = talloc_reference(astate, state);
2414 astate->access_mask = r->in.access_mask;
2416 ah = dcesrv_handle_new(dce_call->context, LSA_HANDLE_ACCOUNT);
2417 if (!ah) {
2418 talloc_free(astate);
2419 return NT_STATUS_NO_MEMORY;
2422 ah->data = talloc_steal(ah, astate);
2424 *r->out.acct_handle = ah->wire_handle;
2426 return NT_STATUS_OK;
2431 lsa_EnumPrivsAccount
2433 static NTSTATUS dcesrv_lsa_EnumPrivsAccount(struct dcesrv_call_state *dce_call,
2434 TALLOC_CTX *mem_ctx,
2435 struct lsa_EnumPrivsAccount *r)
2437 struct dcesrv_handle *h;
2438 struct lsa_account_state *astate;
2439 int ret;
2440 unsigned int i, j;
2441 struct ldb_message **res;
2442 const char * const attrs[] = { "privilege", NULL};
2443 struct ldb_message_element *el;
2444 const char *sidstr;
2445 struct lsa_PrivilegeSet *privs;
2447 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
2449 astate = h->data;
2451 privs = talloc(mem_ctx, struct lsa_PrivilegeSet);
2452 if (privs == NULL) {
2453 return NT_STATUS_NO_MEMORY;
2455 privs->count = 0;
2456 privs->unknown = 0;
2457 privs->set = NULL;
2459 *r->out.privs = privs;
2461 sidstr = ldap_encode_ndr_dom_sid(mem_ctx, astate->account_sid);
2462 if (sidstr == NULL) {
2463 return NT_STATUS_NO_MEMORY;
2466 ret = gendb_search(astate->policy->pdb, mem_ctx, NULL, &res, attrs,
2467 "objectSid=%s", sidstr);
2468 if (ret < 0) {
2469 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2471 if (ret != 1) {
2472 return NT_STATUS_OK;
2475 el = ldb_msg_find_element(res[0], "privilege");
2476 if (el == NULL || el->num_values == 0) {
2477 return NT_STATUS_OK;
2480 privs->set = talloc_array(privs,
2481 struct lsa_LUIDAttribute, el->num_values);
2482 if (privs->set == NULL) {
2483 return NT_STATUS_NO_MEMORY;
2486 j = 0;
2487 for (i=0;i<el->num_values;i++) {
2488 int id = sec_privilege_id((const char *)el->values[i].data);
2489 if (id == SEC_PRIV_INVALID) {
2490 /* Perhaps an account right, not a privilege */
2491 continue;
2493 privs->set[j].attribute = 0;
2494 privs->set[j].luid.low = id;
2495 privs->set[j].luid.high = 0;
2496 j++;
2499 privs->count = j;
2501 return NT_STATUS_OK;
2505 lsa_EnumAccountRights
2507 static NTSTATUS dcesrv_lsa_EnumAccountRights(struct dcesrv_call_state *dce_call,
2508 TALLOC_CTX *mem_ctx,
2509 struct lsa_EnumAccountRights *r)
2511 struct dcesrv_handle *h;
2512 struct lsa_policy_state *state;
2513 int ret;
2514 unsigned int i;
2515 struct ldb_message **res;
2516 const char * const attrs[] = { "privilege", NULL};
2517 const char *sidstr;
2518 struct ldb_message_element *el;
2520 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
2522 state = h->data;
2524 sidstr = ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid);
2525 if (sidstr == NULL) {
2526 return NT_STATUS_NO_MEMORY;
2529 ret = gendb_search(state->pdb, mem_ctx, NULL, &res, attrs,
2530 "(&(objectSid=%s)(privilege=*))", sidstr);
2531 if (ret == 0) {
2532 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2534 if (ret != 1) {
2535 DEBUG(3, ("searching for account rights for SID: %s failed: %s",
2536 dom_sid_string(mem_ctx, r->in.sid),
2537 ldb_errstring(state->pdb)));
2538 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2541 el = ldb_msg_find_element(res[0], "privilege");
2542 if (el == NULL || el->num_values == 0) {
2543 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2546 r->out.rights->count = el->num_values;
2547 r->out.rights->names = talloc_array(r->out.rights,
2548 struct lsa_StringLarge, r->out.rights->count);
2549 if (r->out.rights->names == NULL) {
2550 return NT_STATUS_NO_MEMORY;
2553 for (i=0;i<el->num_values;i++) {
2554 r->out.rights->names[i].string = (const char *)el->values[i].data;
2557 return NT_STATUS_OK;
2563 helper for lsa_AddAccountRights and lsa_RemoveAccountRights
2565 static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_call,
2566 TALLOC_CTX *mem_ctx,
2567 struct lsa_policy_state *state,
2568 int ldb_flag,
2569 struct dom_sid *sid,
2570 const struct lsa_RightSet *rights)
2572 const char *sidstr, *sidndrstr;
2573 struct ldb_message *msg;
2574 struct ldb_message_element *el;
2575 int ret;
2576 uint32_t i;
2577 struct lsa_EnumAccountRights r2;
2578 char *dnstr;
2580 if (security_session_user_level(dce_call->conn->auth_state.session_info, NULL) <
2581 SECURITY_ADMINISTRATOR) {
2582 DEBUG(0,("lsa_AddRemoveAccount refused for supplied security token\n"));
2583 return NT_STATUS_ACCESS_DENIED;
2586 msg = ldb_msg_new(mem_ctx);
2587 if (msg == NULL) {
2588 return NT_STATUS_NO_MEMORY;
2591 sidndrstr = ldap_encode_ndr_dom_sid(msg, sid);
2592 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidndrstr, msg);
2594 sidstr = dom_sid_string(msg, sid);
2595 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidstr, msg);
2597 dnstr = talloc_asprintf(msg, "sid=%s", sidstr);
2598 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dnstr, msg);
2600 msg->dn = ldb_dn_new(msg, state->pdb, dnstr);
2601 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(msg->dn, msg);
2603 if (LDB_FLAG_MOD_TYPE(ldb_flag) == LDB_FLAG_MOD_ADD) {
2604 NTSTATUS status;
2606 r2.in.handle = &state->handle->wire_handle;
2607 r2.in.sid = sid;
2608 r2.out.rights = talloc(mem_ctx, struct lsa_RightSet);
2610 status = dcesrv_lsa_EnumAccountRights(dce_call, mem_ctx, &r2);
2611 if (!NT_STATUS_IS_OK(status)) {
2612 ZERO_STRUCTP(r2.out.rights);
2616 for (i=0;i<rights->count;i++) {
2617 if (sec_privilege_id(rights->names[i].string) == SEC_PRIV_INVALID) {
2618 if (sec_right_bit(rights->names[i].string) == 0) {
2619 talloc_free(msg);
2620 return NT_STATUS_NO_SUCH_PRIVILEGE;
2623 talloc_free(msg);
2624 return NT_STATUS_NO_SUCH_PRIVILEGE;
2627 if (LDB_FLAG_MOD_TYPE(ldb_flag) == LDB_FLAG_MOD_ADD) {
2628 uint32_t j;
2629 for (j=0;j<r2.out.rights->count;j++) {
2630 if (strcasecmp_m(r2.out.rights->names[j].string,
2631 rights->names[i].string) == 0) {
2632 break;
2635 if (j != r2.out.rights->count) continue;
2638 ret = ldb_msg_add_string(msg, "privilege", rights->names[i].string);
2639 if (ret != LDB_SUCCESS) {
2640 talloc_free(msg);
2641 return NT_STATUS_NO_MEMORY;
2645 el = ldb_msg_find_element(msg, "privilege");
2646 if (!el) {
2647 talloc_free(msg);
2648 return NT_STATUS_OK;
2651 el->flags = ldb_flag;
2653 ret = ldb_modify(state->pdb, msg);
2654 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2655 if (samdb_msg_add_dom_sid(state->pdb, msg, msg, "objectSid", sid) != LDB_SUCCESS) {
2656 talloc_free(msg);
2657 return NT_STATUS_NO_MEMORY;
2659 ldb_msg_add_string(msg, "comment", "added via LSA");
2660 ret = ldb_add(state->pdb, msg);
2662 if (ret != LDB_SUCCESS) {
2663 if (LDB_FLAG_MOD_TYPE(ldb_flag) == LDB_FLAG_MOD_DELETE && ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
2664 talloc_free(msg);
2665 return NT_STATUS_OK;
2667 DEBUG(3, ("Could not %s attributes from %s: %s",
2668 LDB_FLAG_MOD_TYPE(ldb_flag) == LDB_FLAG_MOD_DELETE ? "delete" : "add",
2669 ldb_dn_get_linearized(msg->dn), ldb_errstring(state->pdb)));
2670 talloc_free(msg);
2671 return NT_STATUS_UNEXPECTED_IO_ERROR;
2674 talloc_free(msg);
2675 return NT_STATUS_OK;
2679 lsa_AddPrivilegesToAccount
2681 static NTSTATUS dcesrv_lsa_AddPrivilegesToAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2682 struct lsa_AddPrivilegesToAccount *r)
2684 struct lsa_RightSet rights;
2685 struct dcesrv_handle *h;
2686 struct lsa_account_state *astate;
2687 uint32_t i;
2689 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
2691 astate = h->data;
2693 rights.count = r->in.privs->count;
2694 rights.names = talloc_array(mem_ctx, struct lsa_StringLarge, rights.count);
2695 if (rights.names == NULL) {
2696 return NT_STATUS_NO_MEMORY;
2698 for (i=0;i<rights.count;i++) {
2699 int id = r->in.privs->set[i].luid.low;
2700 if (r->in.privs->set[i].luid.high) {
2701 return NT_STATUS_NO_SUCH_PRIVILEGE;
2703 rights.names[i].string = sec_privilege_name(id);
2704 if (rights.names[i].string == NULL) {
2705 return NT_STATUS_NO_SUCH_PRIVILEGE;
2709 return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
2710 LDB_FLAG_MOD_ADD, astate->account_sid,
2711 &rights);
2716 lsa_RemovePrivilegesFromAccount
2718 static NTSTATUS dcesrv_lsa_RemovePrivilegesFromAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2719 struct lsa_RemovePrivilegesFromAccount *r)
2721 struct lsa_RightSet *rights;
2722 struct dcesrv_handle *h;
2723 struct lsa_account_state *astate;
2724 uint32_t i;
2726 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
2728 astate = h->data;
2730 rights = talloc(mem_ctx, struct lsa_RightSet);
2732 if (r->in.remove_all == 1 &&
2733 r->in.privs == NULL) {
2734 struct lsa_EnumAccountRights r2;
2735 NTSTATUS status;
2737 r2.in.handle = &astate->policy->handle->wire_handle;
2738 r2.in.sid = astate->account_sid;
2739 r2.out.rights = rights;
2741 status = dcesrv_lsa_EnumAccountRights(dce_call, mem_ctx, &r2);
2742 if (!NT_STATUS_IS_OK(status)) {
2743 return status;
2746 return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
2747 LDB_FLAG_MOD_DELETE, astate->account_sid,
2748 r2.out.rights);
2751 if (r->in.remove_all != 0) {
2752 return NT_STATUS_INVALID_PARAMETER;
2755 rights->count = r->in.privs->count;
2756 rights->names = talloc_array(mem_ctx, struct lsa_StringLarge, rights->count);
2757 if (rights->names == NULL) {
2758 return NT_STATUS_NO_MEMORY;
2760 for (i=0;i<rights->count;i++) {
2761 int id = r->in.privs->set[i].luid.low;
2762 if (r->in.privs->set[i].luid.high) {
2763 return NT_STATUS_NO_SUCH_PRIVILEGE;
2765 rights->names[i].string = sec_privilege_name(id);
2766 if (rights->names[i].string == NULL) {
2767 return NT_STATUS_NO_SUCH_PRIVILEGE;
2771 return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, astate->policy,
2772 LDB_FLAG_MOD_DELETE, astate->account_sid,
2773 rights);
2778 lsa_GetQuotasForAccount
2780 static NTSTATUS dcesrv_lsa_GetQuotasForAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2781 struct lsa_GetQuotasForAccount *r)
2783 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2788 lsa_SetQuotasForAccount
2790 static NTSTATUS dcesrv_lsa_SetQuotasForAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2791 struct lsa_SetQuotasForAccount *r)
2793 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2798 lsa_GetSystemAccessAccount
2800 static NTSTATUS dcesrv_lsa_GetSystemAccessAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2801 struct lsa_GetSystemAccessAccount *r)
2803 struct dcesrv_handle *h;
2804 struct lsa_account_state *astate;
2805 int ret;
2806 unsigned int i;
2807 struct ldb_message **res;
2808 const char * const attrs[] = { "privilege", NULL};
2809 struct ldb_message_element *el;
2810 const char *sidstr;
2812 *(r->out.access_mask) = 0x00000000;
2814 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_ACCOUNT);
2816 astate = h->data;
2818 sidstr = ldap_encode_ndr_dom_sid(mem_ctx, astate->account_sid);
2819 if (sidstr == NULL) {
2820 return NT_STATUS_NO_MEMORY;
2823 ret = gendb_search(astate->policy->pdb, mem_ctx, NULL, &res, attrs,
2824 "objectSid=%s", sidstr);
2825 if (ret < 0) {
2826 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2828 if (ret != 1) {
2829 return NT_STATUS_OK;
2832 el = ldb_msg_find_element(res[0], "privilege");
2833 if (el == NULL || el->num_values == 0) {
2834 return NT_STATUS_OK;
2837 for (i=0;i<el->num_values;i++) {
2838 uint32_t right_bit = sec_right_bit((const char *)el->values[i].data);
2839 if (right_bit == 0) {
2840 /* Perhaps an privilege, not a right */
2841 continue;
2843 *(r->out.access_mask) |= right_bit;
2846 return NT_STATUS_OK;
2851 lsa_SetSystemAccessAccount
2853 static NTSTATUS dcesrv_lsa_SetSystemAccessAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2854 struct lsa_SetSystemAccessAccount *r)
2856 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2861 lsa_CreateSecret
2863 static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2864 struct lsa_CreateSecret *r)
2866 struct dcesrv_handle *policy_handle;
2867 struct lsa_policy_state *policy_state;
2868 struct lsa_secret_state *secret_state;
2869 struct dcesrv_handle *handle;
2870 struct ldb_message **msgs, *msg;
2871 const char *attrs[] = {
2872 NULL
2875 const char *name;
2877 int ret;
2879 DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
2880 ZERO_STRUCTP(r->out.sec_handle);
2882 switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL))
2884 case SECURITY_SYSTEM:
2885 case SECURITY_ADMINISTRATOR:
2886 break;
2887 default:
2888 /* Users and annonymous are not allowed create secrets */
2889 return NT_STATUS_ACCESS_DENIED;
2892 policy_state = policy_handle->data;
2894 if (!r->in.name.string) {
2895 return NT_STATUS_INVALID_PARAMETER;
2898 secret_state = talloc(mem_ctx, struct lsa_secret_state);
2899 NT_STATUS_HAVE_NO_MEMORY(secret_state);
2900 secret_state->policy = policy_state;
2902 msg = ldb_msg_new(mem_ctx);
2903 if (msg == NULL) {
2904 return NT_STATUS_NO_MEMORY;
2907 if (strncmp("G$", r->in.name.string, 2) == 0) {
2908 const char *name2;
2910 secret_state->global = true;
2912 name = &r->in.name.string[2];
2913 if (strlen(name) == 0) {
2914 return NT_STATUS_INVALID_PARAMETER;
2917 name2 = talloc_asprintf(mem_ctx, "%s Secret",
2918 ldb_binary_encode_string(mem_ctx, name));
2919 NT_STATUS_HAVE_NO_MEMORY(name2);
2921 /* We need to connect to the database as system, as this is one
2922 * of the rare RPC calls that must read the secrets (and this
2923 * is denied otherwise) */
2924 secret_state->sam_ldb = talloc_reference(secret_state,
2925 samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0));
2926 NT_STATUS_HAVE_NO_MEMORY(secret_state->sam_ldb);
2928 /* search for the secret record */
2929 ret = gendb_search(secret_state->sam_ldb,
2930 mem_ctx, policy_state->system_dn, &msgs, attrs,
2931 "(&(cn=%s)(objectclass=secret))",
2932 name2);
2933 if (ret > 0) {
2934 return NT_STATUS_OBJECT_NAME_COLLISION;
2937 if (ret < 0) {
2938 DEBUG(0,("Failure searching for CN=%s: %s\n",
2939 name2, ldb_errstring(secret_state->sam_ldb)));
2940 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2943 msg->dn = ldb_dn_copy(mem_ctx, policy_state->system_dn);
2944 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
2945 if (!ldb_dn_add_child_fmt(msg->dn, "cn=%s", name2)) {
2946 return NT_STATUS_NO_MEMORY;
2949 ret = ldb_msg_add_string(msg, "cn", name2);
2950 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
2951 } else {
2952 secret_state->global = false;
2954 name = r->in.name.string;
2955 if (strlen(name) == 0) {
2956 return NT_STATUS_INVALID_PARAMETER;
2959 secret_state->sam_ldb = talloc_reference(secret_state,
2960 secrets_db_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
2961 NT_STATUS_HAVE_NO_MEMORY(secret_state->sam_ldb);
2963 /* search for the secret record */
2964 ret = gendb_search(secret_state->sam_ldb, mem_ctx,
2965 ldb_dn_new(mem_ctx, secret_state->sam_ldb, "cn=LSA Secrets"),
2966 &msgs, attrs,
2967 "(&(cn=%s)(objectclass=secret))",
2968 ldb_binary_encode_string(mem_ctx, name));
2969 if (ret > 0) {
2970 return NT_STATUS_OBJECT_NAME_COLLISION;
2973 if (ret < 0) {
2974 DEBUG(0,("Failure searching for CN=%s: %s\n",
2975 name, ldb_errstring(secret_state->sam_ldb)));
2976 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2979 msg->dn = ldb_dn_new_fmt(mem_ctx, secret_state->sam_ldb,
2980 "cn=%s,cn=LSA Secrets", name);
2981 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
2982 ret = ldb_msg_add_string(msg, "cn", name);
2983 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
2986 ret = ldb_msg_add_string(msg, "objectClass", "secret");
2987 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
2989 secret_state->secret_dn = talloc_reference(secret_state, msg->dn);
2990 NT_STATUS_HAVE_NO_MEMORY(secret_state->secret_dn);
2992 /* create the secret */
2993 ret = ldb_add(secret_state->sam_ldb, msg);
2994 if (ret != LDB_SUCCESS) {
2995 DEBUG(0,("Failed to create secret record %s: %s\n",
2996 ldb_dn_get_linearized(msg->dn),
2997 ldb_errstring(secret_state->sam_ldb)));
2998 return NT_STATUS_ACCESS_DENIED;
3001 handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_SECRET);
3002 NT_STATUS_HAVE_NO_MEMORY(handle);
3004 handle->data = talloc_steal(handle, secret_state);
3006 secret_state->access_mask = r->in.access_mask;
3007 secret_state->policy = talloc_reference(secret_state, policy_state);
3008 NT_STATUS_HAVE_NO_MEMORY(secret_state->policy);
3010 *r->out.sec_handle = handle->wire_handle;
3012 return NT_STATUS_OK;
3017 lsa_OpenSecret
3019 static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3020 struct lsa_OpenSecret *r)
3022 struct dcesrv_handle *policy_handle;
3024 struct lsa_policy_state *policy_state;
3025 struct lsa_secret_state *secret_state;
3026 struct dcesrv_handle *handle;
3027 struct ldb_message **msgs;
3028 const char *attrs[] = {
3029 NULL
3032 const char *name;
3034 int ret;
3036 DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
3037 ZERO_STRUCTP(r->out.sec_handle);
3038 policy_state = policy_handle->data;
3040 if (!r->in.name.string) {
3041 return NT_STATUS_INVALID_PARAMETER;
3044 switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL))
3046 case SECURITY_SYSTEM:
3047 case SECURITY_ADMINISTRATOR:
3048 break;
3049 default:
3050 /* Users and annonymous are not allowed to access secrets */
3051 return NT_STATUS_ACCESS_DENIED;
3054 secret_state = talloc(mem_ctx, struct lsa_secret_state);
3055 if (!secret_state) {
3056 return NT_STATUS_NO_MEMORY;
3058 secret_state->policy = policy_state;
3060 if (strncmp("G$", r->in.name.string, 2) == 0) {
3061 name = &r->in.name.string[2];
3062 /* 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) */
3063 secret_state->sam_ldb = talloc_reference(secret_state,
3064 samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0));
3065 secret_state->global = true;
3067 if (strlen(name) < 1) {
3068 return NT_STATUS_INVALID_PARAMETER;
3071 /* search for the secret record */
3072 ret = gendb_search(secret_state->sam_ldb,
3073 mem_ctx, policy_state->system_dn, &msgs, attrs,
3074 "(&(cn=%s Secret)(objectclass=secret))",
3075 ldb_binary_encode_string(mem_ctx, name));
3076 if (ret == 0) {
3077 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3080 if (ret != 1) {
3081 DEBUG(0,("Found %d records matching DN %s\n", ret,
3082 ldb_dn_get_linearized(policy_state->system_dn)));
3083 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3085 } else {
3086 secret_state->global = false;
3087 secret_state->sam_ldb = talloc_reference(secret_state,
3088 secrets_db_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
3090 name = r->in.name.string;
3091 if (strlen(name) < 1) {
3092 return NT_STATUS_INVALID_PARAMETER;
3095 /* search for the secret record */
3096 ret = gendb_search(secret_state->sam_ldb, mem_ctx,
3097 ldb_dn_new(mem_ctx, secret_state->sam_ldb, "cn=LSA Secrets"),
3098 &msgs, attrs,
3099 "(&(cn=%s)(objectclass=secret))",
3100 ldb_binary_encode_string(mem_ctx, name));
3101 if (ret == 0) {
3102 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3105 if (ret != 1) {
3106 DEBUG(0,("Found %d records matching CN=%s\n",
3107 ret, ldb_binary_encode_string(mem_ctx, name)));
3108 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3112 secret_state->secret_dn = talloc_reference(secret_state, msgs[0]->dn);
3114 handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_SECRET);
3115 if (!handle) {
3116 return NT_STATUS_NO_MEMORY;
3119 handle->data = talloc_steal(handle, secret_state);
3121 secret_state->access_mask = r->in.access_mask;
3122 secret_state->policy = talloc_reference(secret_state, policy_state);
3124 *r->out.sec_handle = handle->wire_handle;
3126 return NT_STATUS_OK;
3131 lsa_SetSecret
3133 static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3134 struct lsa_SetSecret *r)
3137 struct dcesrv_handle *h;
3138 struct lsa_secret_state *secret_state;
3139 struct ldb_message *msg;
3140 DATA_BLOB session_key;
3141 DATA_BLOB crypt_secret, secret;
3142 struct ldb_val val;
3143 int ret;
3144 NTSTATUS status = NT_STATUS_OK;
3146 struct timeval now = timeval_current();
3147 NTTIME nt_now = timeval_to_nttime(&now);
3149 DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
3151 secret_state = h->data;
3153 msg = ldb_msg_new(mem_ctx);
3154 if (msg == NULL) {
3155 return NT_STATUS_NO_MEMORY;
3158 msg->dn = talloc_reference(mem_ctx, secret_state->secret_dn);
3159 if (!msg->dn) {
3160 return NT_STATUS_NO_MEMORY;
3162 status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
3163 if (!NT_STATUS_IS_OK(status)) {
3164 return status;
3167 if (r->in.old_val) {
3168 /* Decrypt */
3169 crypt_secret.data = r->in.old_val->data;
3170 crypt_secret.length = r->in.old_val->size;
3172 status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
3173 if (!NT_STATUS_IS_OK(status)) {
3174 return status;
3177 val.data = secret.data;
3178 val.length = secret.length;
3180 /* set value */
3181 if (ldb_msg_add_value(msg, "priorValue", &val, NULL) != LDB_SUCCESS) {
3182 return NT_STATUS_NO_MEMORY;
3185 /* set old value mtime */
3186 if (samdb_msg_add_uint64(secret_state->sam_ldb,
3187 mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
3188 return NT_STATUS_NO_MEMORY;
3191 } else {
3192 /* If the old value is not set, then migrate the
3193 * current value to the old value */
3194 const struct ldb_val *old_val;
3195 NTTIME last_set_time;
3196 struct ldb_message **res;
3197 const char *attrs[] = {
3198 "currentValue",
3199 "lastSetTime",
3200 NULL
3203 /* search for the secret record */
3204 ret = gendb_search_dn(secret_state->sam_ldb,mem_ctx,
3205 secret_state->secret_dn, &res, attrs);
3206 if (ret == 0) {
3207 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3210 if (ret != 1) {
3211 DEBUG(0,("Found %d records matching dn=%s\n", ret,
3212 ldb_dn_get_linearized(secret_state->secret_dn)));
3213 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3216 old_val = ldb_msg_find_ldb_val(res[0], "currentValue");
3217 last_set_time = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);
3219 if (old_val) {
3220 /* set old value */
3221 if (ldb_msg_add_value(msg, "priorValue",
3222 old_val, NULL) != LDB_SUCCESS) {
3223 return NT_STATUS_NO_MEMORY;
3225 } else {
3226 if (samdb_msg_add_delete(secret_state->sam_ldb,
3227 mem_ctx, msg, "priorValue") != LDB_SUCCESS) {
3228 return NT_STATUS_NO_MEMORY;
3232 /* set old value mtime */
3233 if (ldb_msg_find_ldb_val(res[0], "lastSetTime")) {
3234 if (samdb_msg_add_uint64(secret_state->sam_ldb,
3235 mem_ctx, msg, "priorSetTime", last_set_time) != LDB_SUCCESS) {
3236 return NT_STATUS_NO_MEMORY;
3238 } else {
3239 if (samdb_msg_add_uint64(secret_state->sam_ldb,
3240 mem_ctx, msg, "priorSetTime", nt_now) != LDB_SUCCESS) {
3241 return NT_STATUS_NO_MEMORY;
3246 if (r->in.new_val) {
3247 /* Decrypt */
3248 crypt_secret.data = r->in.new_val->data;
3249 crypt_secret.length = r->in.new_val->size;
3251 status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
3252 if (!NT_STATUS_IS_OK(status)) {
3253 return status;
3256 val.data = secret.data;
3257 val.length = secret.length;
3259 /* set value */
3260 if (ldb_msg_add_value(msg, "currentValue", &val, NULL) != LDB_SUCCESS) {
3261 return NT_STATUS_NO_MEMORY;
3264 /* set new value mtime */
3265 if (samdb_msg_add_uint64(secret_state->sam_ldb,
3266 mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
3267 return NT_STATUS_NO_MEMORY;
3269 } else {
3270 /* NULL out the NEW value */
3271 if (samdb_msg_add_uint64(secret_state->sam_ldb,
3272 mem_ctx, msg, "lastSetTime", nt_now) != LDB_SUCCESS) {
3273 return NT_STATUS_NO_MEMORY;
3275 if (samdb_msg_add_delete(secret_state->sam_ldb,
3276 mem_ctx, msg, "currentValue") != LDB_SUCCESS) {
3277 return NT_STATUS_NO_MEMORY;
3281 /* modify the samdb record */
3282 ret = dsdb_replace(secret_state->sam_ldb, msg, 0);
3283 if (ret != LDB_SUCCESS) {
3284 return dsdb_ldb_err_to_ntstatus(ret);
3287 return NT_STATUS_OK;
3292 lsa_QuerySecret
3294 static NTSTATUS dcesrv_lsa_QuerySecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3295 struct lsa_QuerySecret *r)
3297 struct dcesrv_handle *h;
3298 struct lsa_secret_state *secret_state;
3299 struct ldb_message *msg;
3300 DATA_BLOB session_key;
3301 DATA_BLOB crypt_secret, secret;
3302 int ret;
3303 struct ldb_message **res;
3304 const char *attrs[] = {
3305 "currentValue",
3306 "priorValue",
3307 "lastSetTime",
3308 "priorSetTime",
3309 NULL
3312 NTSTATUS nt_status;
3314 DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
3316 /* Ensure user is permitted to read this... */
3317 switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL))
3319 case SECURITY_SYSTEM:
3320 case SECURITY_ADMINISTRATOR:
3321 break;
3322 default:
3323 /* Users and annonymous are not allowed to read secrets */
3324 return NT_STATUS_ACCESS_DENIED;
3327 secret_state = h->data;
3329 /* pull all the user attributes */
3330 ret = gendb_search_dn(secret_state->sam_ldb, mem_ctx,
3331 secret_state->secret_dn, &res, attrs);
3332 if (ret != 1) {
3333 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3335 msg = res[0];
3337 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
3338 if (!NT_STATUS_IS_OK(nt_status)) {
3339 return nt_status;
3342 if (r->in.old_val) {
3343 const struct ldb_val *prior_val;
3344 r->out.old_val = talloc_zero(mem_ctx, struct lsa_DATA_BUF_PTR);
3345 if (!r->out.old_val) {
3346 return NT_STATUS_NO_MEMORY;
3348 prior_val = ldb_msg_find_ldb_val(res[0], "priorValue");
3350 if (prior_val && prior_val->length) {
3351 secret.data = prior_val->data;
3352 secret.length = prior_val->length;
3354 /* Encrypt */
3355 crypt_secret = sess_encrypt_blob(mem_ctx, &secret, &session_key);
3356 if (!crypt_secret.length) {
3357 return NT_STATUS_NO_MEMORY;
3359 r->out.old_val->buf = talloc(mem_ctx, struct lsa_DATA_BUF);
3360 if (!r->out.old_val->buf) {
3361 return NT_STATUS_NO_MEMORY;
3363 r->out.old_val->buf->size = crypt_secret.length;
3364 r->out.old_val->buf->length = crypt_secret.length;
3365 r->out.old_val->buf->data = crypt_secret.data;
3369 if (r->in.old_mtime) {
3370 r->out.old_mtime = talloc(mem_ctx, NTTIME);
3371 if (!r->out.old_mtime) {
3372 return NT_STATUS_NO_MEMORY;
3374 *r->out.old_mtime = ldb_msg_find_attr_as_uint64(res[0], "priorSetTime", 0);
3377 if (r->in.new_val) {
3378 const struct ldb_val *new_val;
3379 r->out.new_val = talloc_zero(mem_ctx, struct lsa_DATA_BUF_PTR);
3380 if (!r->out.new_val) {
3381 return NT_STATUS_NO_MEMORY;
3384 new_val = ldb_msg_find_ldb_val(res[0], "currentValue");
3386 if (new_val && new_val->length) {
3387 secret.data = new_val->data;
3388 secret.length = new_val->length;
3390 /* Encrypt */
3391 crypt_secret = sess_encrypt_blob(mem_ctx, &secret, &session_key);
3392 if (!crypt_secret.length) {
3393 return NT_STATUS_NO_MEMORY;
3395 r->out.new_val->buf = talloc(mem_ctx, struct lsa_DATA_BUF);
3396 if (!r->out.new_val->buf) {
3397 return NT_STATUS_NO_MEMORY;
3399 r->out.new_val->buf->length = crypt_secret.length;
3400 r->out.new_val->buf->size = crypt_secret.length;
3401 r->out.new_val->buf->data = crypt_secret.data;
3405 if (r->in.new_mtime) {
3406 r->out.new_mtime = talloc(mem_ctx, NTTIME);
3407 if (!r->out.new_mtime) {
3408 return NT_STATUS_NO_MEMORY;
3410 *r->out.new_mtime = ldb_msg_find_attr_as_uint64(res[0], "lastSetTime", 0);
3413 return NT_STATUS_OK;
3418 lsa_LookupPrivValue
3420 static NTSTATUS dcesrv_lsa_LookupPrivValue(struct dcesrv_call_state *dce_call,
3421 TALLOC_CTX *mem_ctx,
3422 struct lsa_LookupPrivValue *r)
3424 struct dcesrv_handle *h;
3425 int id;
3427 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
3429 id = sec_privilege_id(r->in.name->string);
3430 if (id == SEC_PRIV_INVALID) {
3431 return NT_STATUS_NO_SUCH_PRIVILEGE;
3434 r->out.luid->low = id;
3435 r->out.luid->high = 0;
3437 return NT_STATUS_OK;
3442 lsa_LookupPrivName
3444 static NTSTATUS dcesrv_lsa_LookupPrivName(struct dcesrv_call_state *dce_call,
3445 TALLOC_CTX *mem_ctx,
3446 struct lsa_LookupPrivName *r)
3448 struct dcesrv_handle *h;
3449 struct lsa_StringLarge *name;
3450 const char *privname;
3452 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
3454 if (r->in.luid->high != 0) {
3455 return NT_STATUS_NO_SUCH_PRIVILEGE;
3458 privname = sec_privilege_name(r->in.luid->low);
3459 if (privname == NULL) {
3460 return NT_STATUS_NO_SUCH_PRIVILEGE;
3463 name = talloc(mem_ctx, struct lsa_StringLarge);
3464 if (name == NULL) {
3465 return NT_STATUS_NO_MEMORY;
3468 name->string = privname;
3470 *r->out.name = name;
3472 return NT_STATUS_OK;
3477 lsa_LookupPrivDisplayName
3479 static NTSTATUS dcesrv_lsa_LookupPrivDisplayName(struct dcesrv_call_state *dce_call,
3480 TALLOC_CTX *mem_ctx,
3481 struct lsa_LookupPrivDisplayName *r)
3483 struct dcesrv_handle *h;
3484 struct lsa_StringLarge *disp_name = NULL;
3485 enum sec_privilege id;
3487 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
3489 id = sec_privilege_id(r->in.name->string);
3490 if (id == SEC_PRIV_INVALID) {
3491 return NT_STATUS_NO_SUCH_PRIVILEGE;
3494 disp_name = talloc(mem_ctx, struct lsa_StringLarge);
3495 if (disp_name == NULL) {
3496 return NT_STATUS_NO_MEMORY;
3499 disp_name->string = sec_privilege_display_name(id, &r->in.language_id);
3500 if (disp_name->string == NULL) {
3501 return NT_STATUS_INTERNAL_ERROR;
3504 *r->out.disp_name = disp_name;
3505 *r->out.returned_language_id = 0;
3507 return NT_STATUS_OK;
3512 lsa_EnumAccountsWithUserRight
3514 static NTSTATUS dcesrv_lsa_EnumAccountsWithUserRight(struct dcesrv_call_state *dce_call,
3515 TALLOC_CTX *mem_ctx,
3516 struct lsa_EnumAccountsWithUserRight *r)
3518 struct dcesrv_handle *h;
3519 struct lsa_policy_state *state;
3520 int ret, i;
3521 struct ldb_message **res;
3522 const char * const attrs[] = { "objectSid", NULL};
3523 const char *privname;
3525 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
3527 state = h->data;
3529 if (r->in.name == NULL) {
3530 return NT_STATUS_NO_SUCH_PRIVILEGE;
3533 privname = r->in.name->string;
3534 if (sec_privilege_id(privname) == SEC_PRIV_INVALID && sec_right_bit(privname) == 0) {
3535 return NT_STATUS_NO_SUCH_PRIVILEGE;
3538 ret = gendb_search(state->pdb, mem_ctx, NULL, &res, attrs,
3539 "privilege=%s", privname);
3540 if (ret < 0) {
3541 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3543 if (ret == 0) {
3544 return NT_STATUS_NO_MORE_ENTRIES;
3547 r->out.sids->sids = talloc_array(r->out.sids, struct lsa_SidPtr, ret);
3548 if (r->out.sids->sids == NULL) {
3549 return NT_STATUS_NO_MEMORY;
3551 for (i=0;i<ret;i++) {
3552 r->out.sids->sids[i].sid = samdb_result_dom_sid(r->out.sids->sids,
3553 res[i], "objectSid");
3554 NT_STATUS_HAVE_NO_MEMORY(r->out.sids->sids[i].sid);
3556 r->out.sids->num_sids = ret;
3558 return NT_STATUS_OK;
3563 lsa_AddAccountRights
3565 static NTSTATUS dcesrv_lsa_AddAccountRights(struct dcesrv_call_state *dce_call,
3566 TALLOC_CTX *mem_ctx,
3567 struct lsa_AddAccountRights *r)
3569 struct dcesrv_handle *h;
3570 struct lsa_policy_state *state;
3572 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
3574 state = h->data;
3576 return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, state,
3577 LDB_FLAG_MOD_ADD,
3578 r->in.sid, r->in.rights);
3583 lsa_RemoveAccountRights
3585 static NTSTATUS dcesrv_lsa_RemoveAccountRights(struct dcesrv_call_state *dce_call,
3586 TALLOC_CTX *mem_ctx,
3587 struct lsa_RemoveAccountRights *r)
3589 struct dcesrv_handle *h;
3590 struct lsa_policy_state *state;
3592 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
3594 state = h->data;
3596 return dcesrv_lsa_AddRemoveAccountRights(dce_call, mem_ctx, state,
3597 LDB_FLAG_MOD_DELETE,
3598 r->in.sid, r->in.rights);
3603 lsa_StorePrivateData
3605 static NTSTATUS dcesrv_lsa_StorePrivateData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3606 struct lsa_StorePrivateData *r)
3608 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3613 lsa_RetrievePrivateData
3615 static NTSTATUS dcesrv_lsa_RetrievePrivateData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3616 struct lsa_RetrievePrivateData *r)
3618 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3623 lsa_GetUserName
3625 static NTSTATUS dcesrv_lsa_GetUserName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3626 struct lsa_GetUserName *r)
3628 enum dcerpc_transport_t transport = dce_call->conn->endpoint->ep_description->transport;
3629 NTSTATUS status = NT_STATUS_OK;
3630 const char *account_name;
3631 const char *authority_name;
3632 struct lsa_String *_account_name;
3633 struct lsa_String *_authority_name = NULL;
3635 if (transport != NCACN_NP && transport != NCALRPC) {
3636 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
3639 /* this is what w2k3 does */
3640 r->out.account_name = r->in.account_name;
3641 r->out.authority_name = r->in.authority_name;
3643 if (r->in.account_name
3644 && *r->in.account_name
3645 /* && *(*r->in.account_name)->string */
3647 return NT_STATUS_INVALID_PARAMETER;
3650 if (r->in.authority_name
3651 && *r->in.authority_name
3652 /* && *(*r->in.authority_name)->string */
3654 return NT_STATUS_INVALID_PARAMETER;
3657 account_name = talloc_reference(mem_ctx, dce_call->conn->auth_state.session_info->info->account_name);
3658 authority_name = talloc_reference(mem_ctx, dce_call->conn->auth_state.session_info->info->domain_name);
3660 _account_name = talloc(mem_ctx, struct lsa_String);
3661 NT_STATUS_HAVE_NO_MEMORY(_account_name);
3662 _account_name->string = account_name;
3664 if (r->in.authority_name) {
3665 _authority_name = talloc(mem_ctx, struct lsa_String);
3666 NT_STATUS_HAVE_NO_MEMORY(_authority_name);
3667 _authority_name->string = authority_name;
3670 *r->out.account_name = _account_name;
3671 if (r->out.authority_name) {
3672 *r->out.authority_name = _authority_name;
3675 return status;
3679 lsa_SetInfoPolicy2
3681 static NTSTATUS dcesrv_lsa_SetInfoPolicy2(struct dcesrv_call_state *dce_call,
3682 TALLOC_CTX *mem_ctx,
3683 struct lsa_SetInfoPolicy2 *r)
3685 /* need to support these */
3686 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3689 static void kdc_get_policy(struct loadparm_context *lp_ctx,
3690 struct smb_krb5_context *smb_krb5_context,
3691 struct lsa_DomainInfoKerberos *k)
3693 time_t svc_tkt_lifetime;
3694 time_t usr_tkt_lifetime;
3695 time_t renewal_lifetime;
3697 /* These should be set and stored via Group Policy, but until then, some defaults are in order */
3699 /* Our KDC always re-validates the client */
3700 k->authentication_options = LSA_POLICY_KERBEROS_VALIDATE_CLIENT;
3702 lpcfg_default_kdc_policy(lp_ctx, &svc_tkt_lifetime,
3703 &usr_tkt_lifetime, &renewal_lifetime);
3705 unix_to_nt_time(&k->service_tkt_lifetime, svc_tkt_lifetime);
3706 unix_to_nt_time(&k->user_tkt_lifetime, usr_tkt_lifetime);
3707 unix_to_nt_time(&k->user_tkt_renewaltime, renewal_lifetime);
3708 #ifdef SAMBA4_USES_HEIMDAL /* MIT lacks krb5_get_max_time_skew.
3709 However in the parent function we basically just did a full
3710 krb5_context init with the only purpose of getting a global
3711 config option (the max skew), it would probably make more sense
3712 to have a lp_ or ldb global option as the samba default */
3713 if (smb_krb5_context) {
3714 unix_to_nt_time(&k->clock_skew,
3715 krb5_get_max_time_skew(smb_krb5_context->krb5_context));
3717 #endif
3718 k->reserved = 0;
3721 lsa_QueryDomainInformationPolicy
3723 static NTSTATUS dcesrv_lsa_QueryDomainInformationPolicy(struct dcesrv_call_state *dce_call,
3724 TALLOC_CTX *mem_ctx,
3725 struct lsa_QueryDomainInformationPolicy *r)
3727 union lsa_DomainInformationPolicy *info;
3729 info = talloc_zero(r->out.info, union lsa_DomainInformationPolicy);
3730 if (!info) {
3731 return NT_STATUS_NO_MEMORY;
3734 switch (r->in.level) {
3735 case LSA_DOMAIN_INFO_POLICY_EFS:
3736 talloc_free(info);
3737 *r->out.info = NULL;
3738 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3739 case LSA_DOMAIN_INFO_POLICY_KERBEROS:
3741 struct lsa_DomainInfoKerberos *k = &info->kerberos_info;
3742 struct smb_krb5_context *smb_krb5_context;
3743 int ret = smb_krb5_init_context(mem_ctx,
3744 dce_call->event_ctx,
3745 dce_call->conn->dce_ctx->lp_ctx,
3746 &smb_krb5_context);
3747 if (ret != 0) {
3748 talloc_free(info);
3749 *r->out.info = NULL;
3750 return NT_STATUS_INTERNAL_ERROR;
3752 kdc_get_policy(dce_call->conn->dce_ctx->lp_ctx,
3753 smb_krb5_context,
3755 talloc_free(smb_krb5_context);
3756 *r->out.info = info;
3757 return NT_STATUS_OK;
3759 default:
3760 talloc_free(info);
3761 *r->out.info = NULL;
3762 return NT_STATUS_INVALID_INFO_CLASS;
3767 lsa_SetDomInfoPolicy
3769 static NTSTATUS dcesrv_lsa_SetDomainInformationPolicy(struct dcesrv_call_state *dce_call,
3770 TALLOC_CTX *mem_ctx,
3771 struct lsa_SetDomainInformationPolicy *r)
3773 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3777 lsa_TestCall
3779 static NTSTATUS dcesrv_lsa_TestCall(struct dcesrv_call_state *dce_call,
3780 TALLOC_CTX *mem_ctx,
3781 struct lsa_TestCall *r)
3783 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3787 lsa_CREDRWRITE
3789 static NTSTATUS dcesrv_lsa_CREDRWRITE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3790 struct lsa_CREDRWRITE *r)
3792 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3797 lsa_CREDRREAD
3799 static NTSTATUS dcesrv_lsa_CREDRREAD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3800 struct lsa_CREDRREAD *r)
3802 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3807 lsa_CREDRENUMERATE
3809 static NTSTATUS dcesrv_lsa_CREDRENUMERATE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3810 struct lsa_CREDRENUMERATE *r)
3812 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3817 lsa_CREDRWRITEDOMAINCREDENTIALS
3819 static NTSTATUS dcesrv_lsa_CREDRWRITEDOMAINCREDENTIALS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3820 struct lsa_CREDRWRITEDOMAINCREDENTIALS *r)
3822 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3827 lsa_CREDRREADDOMAINCREDENTIALS
3829 static NTSTATUS dcesrv_lsa_CREDRREADDOMAINCREDENTIALS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3830 struct lsa_CREDRREADDOMAINCREDENTIALS *r)
3832 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3837 lsa_CREDRDELETE
3839 static NTSTATUS dcesrv_lsa_CREDRDELETE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3840 struct lsa_CREDRDELETE *r)
3842 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3847 lsa_CREDRGETTARGETINFO
3849 static NTSTATUS dcesrv_lsa_CREDRGETTARGETINFO(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3850 struct lsa_CREDRGETTARGETINFO *r)
3852 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3857 lsa_CREDRPROFILELOADED
3859 static NTSTATUS dcesrv_lsa_CREDRPROFILELOADED(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3860 struct lsa_CREDRPROFILELOADED *r)
3862 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3867 lsa_CREDRGETSESSIONTYPES
3869 static NTSTATUS dcesrv_lsa_CREDRGETSESSIONTYPES(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3870 struct lsa_CREDRGETSESSIONTYPES *r)
3872 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3877 lsa_LSARREGISTERAUDITEVENT
3879 static NTSTATUS dcesrv_lsa_LSARREGISTERAUDITEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3880 struct lsa_LSARREGISTERAUDITEVENT *r)
3882 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3887 lsa_LSARGENAUDITEVENT
3889 static NTSTATUS dcesrv_lsa_LSARGENAUDITEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3890 struct lsa_LSARGENAUDITEVENT *r)
3892 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3897 lsa_LSARUNREGISTERAUDITEVENT
3899 static NTSTATUS dcesrv_lsa_LSARUNREGISTERAUDITEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3900 struct lsa_LSARUNREGISTERAUDITEVENT *r)
3902 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3907 lsa_lsaRQueryForestTrustInformation
3909 static NTSTATUS dcesrv_lsa_lsaRQueryForestTrustInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3910 struct lsa_lsaRQueryForestTrustInformation *r)
3912 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3915 #define DNS_CMP_MATCH 0
3916 #define DNS_CMP_FIRST_IS_CHILD 1
3917 #define DNS_CMP_SECOND_IS_CHILD 2
3918 #define DNS_CMP_NO_MATCH 3
3920 /* this function assumes names are well formed DNS names.
3921 * it doesn't validate them */
3922 static int dns_cmp(const char *s1, size_t l1,
3923 const char *s2, size_t l2)
3925 const char *p1, *p2;
3926 size_t t1, t2;
3927 int cret;
3929 if (l1 == l2) {
3930 if (strcasecmp_m(s1, s2) == 0) {
3931 return DNS_CMP_MATCH;
3933 return DNS_CMP_NO_MATCH;
3936 if (l1 > l2) {
3937 p1 = s1;
3938 p2 = s2;
3939 t1 = l1;
3940 t2 = l2;
3941 cret = DNS_CMP_FIRST_IS_CHILD;
3942 } else {
3943 p1 = s2;
3944 p2 = s1;
3945 t1 = l2;
3946 t2 = l1;
3947 cret = DNS_CMP_SECOND_IS_CHILD;
3950 if (p1[t1 - t2 - 1] != '.') {
3951 return DNS_CMP_NO_MATCH;
3954 if (strcasecmp_m(&p1[t1 - t2], p2) == 0) {
3955 return cret;
3958 return DNS_CMP_NO_MATCH;
3961 /* decode all TDOs forest trust info blobs */
3962 static NTSTATUS get_ft_info(TALLOC_CTX *mem_ctx,
3963 struct ldb_message *msg,
3964 struct ForestTrustInfo *info)
3966 const struct ldb_val *ft_blob;
3967 enum ndr_err_code ndr_err;
3969 ft_blob = ldb_msg_find_ldb_val(msg, "msDS-TrustForestTrustInfo");
3970 if (!ft_blob || !ft_blob->data) {
3971 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3973 /* ldb_val is equivalent to DATA_BLOB */
3974 ndr_err = ndr_pull_struct_blob_all(ft_blob, mem_ctx, info,
3975 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
3976 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3977 return NT_STATUS_INVALID_DOMAIN_STATE;
3980 return NT_STATUS_OK;
3983 static NTSTATUS own_ft_info(struct lsa_policy_state *ps,
3984 struct ForestTrustInfo *fti)
3986 struct ForestTrustDataDomainInfo *info;
3987 struct ForestTrustInfoRecord *rec;
3989 fti->version = 1;
3990 fti->count = 2;
3991 fti->records = talloc_array(fti,
3992 struct ForestTrustInfoRecordArmor, 2);
3993 if (!fti->records) {
3994 return NT_STATUS_NO_MEMORY;
3997 /* TLN info */
3998 rec = &fti->records[0].record;
4000 rec->flags = 0;
4001 rec->timestamp = 0;
4002 rec->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME;
4004 rec->data.name.string = talloc_strdup(fti, ps->forest_dns);
4005 if (!rec->data.name.string) {
4006 return NT_STATUS_NO_MEMORY;
4008 rec->data.name.size = strlen(rec->data.name.string);
4010 /* DOMAIN info */
4011 rec = &fti->records[1].record;
4013 rec->flags = 0;
4014 rec->timestamp = 0;
4015 rec->type = LSA_FOREST_TRUST_DOMAIN_INFO;
4017 info = &rec->data.info;
4019 info->sid = *ps->domain_sid;
4020 info->dns_name.string = talloc_strdup(fti, ps->domain_dns);
4021 if (!info->dns_name.string) {
4022 return NT_STATUS_NO_MEMORY;
4024 info->dns_name.size = strlen(info->dns_name.string);
4025 info->netbios_name.string = talloc_strdup(fti, ps->domain_name);
4026 if (!info->netbios_name.string) {
4027 return NT_STATUS_NO_MEMORY;
4029 info->netbios_name.size = strlen(info->netbios_name.string);
4031 return NT_STATUS_OK;
4034 static NTSTATUS make_ft_info(TALLOC_CTX *mem_ctx,
4035 struct lsa_ForestTrustInformation *lfti,
4036 struct ForestTrustInfo *fti)
4038 struct lsa_ForestTrustRecord *lrec;
4039 struct ForestTrustInfoRecord *rec;
4040 struct lsa_StringLarge *tln;
4041 struct lsa_ForestTrustDomainInfo *info;
4042 uint32_t i;
4044 fti->version = 1;
4045 fti->count = lfti->count;
4046 fti->records = talloc_array(mem_ctx,
4047 struct ForestTrustInfoRecordArmor,
4048 fti->count);
4049 if (!fti->records) {
4050 return NT_STATUS_NO_MEMORY;
4052 for (i = 0; i < fti->count; i++) {
4053 lrec = lfti->entries[i];
4054 rec = &fti->records[i].record;
4056 rec->flags = lrec->flags;
4057 rec->timestamp = lrec->time;
4058 rec->type = lrec->type;
4060 switch (lrec->type) {
4061 case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
4062 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
4063 tln = &lrec->forest_trust_data.top_level_name;
4064 rec->data.name.string =
4065 talloc_strdup(mem_ctx, tln->string);
4066 if (!rec->data.name.string) {
4067 return NT_STATUS_NO_MEMORY;
4069 rec->data.name.size = strlen(rec->data.name.string);
4070 break;
4071 case LSA_FOREST_TRUST_DOMAIN_INFO:
4072 info = &lrec->forest_trust_data.domain_info;
4073 rec->data.info.sid = *info->domain_sid;
4074 rec->data.info.dns_name.string =
4075 talloc_strdup(mem_ctx,
4076 info->dns_domain_name.string);
4077 if (!rec->data.info.dns_name.string) {
4078 return NT_STATUS_NO_MEMORY;
4080 rec->data.info.dns_name.size =
4081 strlen(rec->data.info.dns_name.string);
4082 rec->data.info.netbios_name.string =
4083 talloc_strdup(mem_ctx,
4084 info->netbios_domain_name.string);
4085 if (!rec->data.info.netbios_name.string) {
4086 return NT_STATUS_NO_MEMORY;
4088 rec->data.info.netbios_name.size =
4089 strlen(rec->data.info.netbios_name.string);
4090 break;
4091 default:
4092 return NT_STATUS_INVALID_DOMAIN_STATE;
4096 return NT_STATUS_OK;
4099 static NTSTATUS add_collision(struct lsa_ForestTrustCollisionInfo *c_info,
4100 uint32_t idx, uint32_t collision_type,
4101 uint32_t conflict_type, const char *tdo_name);
4103 static NTSTATUS check_ft_info(TALLOC_CTX *mem_ctx,
4104 const char *tdo_name,
4105 struct ForestTrustInfo *tdo_fti,
4106 struct ForestTrustInfo *new_fti,
4107 struct lsa_ForestTrustCollisionInfo *c_info)
4109 struct ForestTrustInfoRecord *nrec;
4110 struct ForestTrustInfoRecord *trec;
4111 const char *dns_name;
4112 const char *nb_name;
4113 struct dom_sid *sid;
4114 const char *tname;
4115 size_t dns_len;
4116 size_t nb_len;
4117 size_t tlen;
4118 NTSTATUS nt_status;
4119 uint32_t new_fti_idx;
4120 uint32_t i;
4121 /* use always TDO type, until we understand when Xref can be used */
4122 uint32_t collision_type = LSA_FOREST_TRUST_COLLISION_TDO;
4123 bool tln_conflict;
4124 bool sid_conflict;
4125 bool nb_conflict;
4126 bool exclusion;
4127 bool ex_rule;
4128 int ret;
4130 for (new_fti_idx = 0; new_fti_idx < new_fti->count; new_fti_idx++) {
4132 nrec = &new_fti->records[new_fti_idx].record;
4133 dns_name = NULL;
4134 tln_conflict = false;
4135 sid_conflict = false;
4136 nb_conflict = false;
4137 exclusion = false;
4139 switch (nrec->type) {
4140 case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
4141 /* exclusions do not conflict by definition */
4142 break;
4144 case FOREST_TRUST_TOP_LEVEL_NAME:
4145 dns_name = nrec->data.name.string;
4146 dns_len = nrec->data.name.size;
4147 break;
4149 case LSA_FOREST_TRUST_DOMAIN_INFO:
4150 dns_name = nrec->data.info.dns_name.string;
4151 dns_len = nrec->data.info.dns_name.size;
4152 nb_name = nrec->data.info.netbios_name.string;
4153 nb_len = nrec->data.info.netbios_name.size;
4154 sid = &nrec->data.info.sid;
4155 break;
4158 if (!dns_name) continue;
4160 /* check if this is already taken and not excluded */
4161 for (i = 0; i < tdo_fti->count; i++) {
4162 trec = &tdo_fti->records[i].record;
4164 switch (trec->type) {
4165 case FOREST_TRUST_TOP_LEVEL_NAME:
4166 ex_rule = false;
4167 tname = trec->data.name.string;
4168 tlen = trec->data.name.size;
4169 break;
4170 case FOREST_TRUST_TOP_LEVEL_NAME_EX:
4171 ex_rule = true;
4172 tname = trec->data.name.string;
4173 tlen = trec->data.name.size;
4174 break;
4175 case FOREST_TRUST_DOMAIN_INFO:
4176 ex_rule = false;
4177 tname = trec->data.info.dns_name.string;
4178 tlen = trec->data.info.dns_name.size;
4180 ret = dns_cmp(dns_name, dns_len, tname, tlen);
4181 switch (ret) {
4182 case DNS_CMP_MATCH:
4183 /* if it matches exclusion,
4184 * it doesn't conflict */
4185 if (ex_rule) {
4186 exclusion = true;
4187 break;
4189 /* fall through */
4190 case DNS_CMP_FIRST_IS_CHILD:
4191 case DNS_CMP_SECOND_IS_CHILD:
4192 tln_conflict = true;
4193 /* fall through */
4194 default:
4195 break;
4198 /* explicit exclusion, no dns name conflict here */
4199 if (exclusion) {
4200 tln_conflict = false;
4203 if (trec->type != FOREST_TRUST_DOMAIN_INFO) {
4204 continue;
4207 /* also test for domain info */
4208 if (!(trec->flags & LSA_SID_DISABLED_ADMIN) &&
4209 dom_sid_compare(&trec->data.info.sid, sid) == 0) {
4210 sid_conflict = true;
4212 if (!(trec->flags & LSA_NB_DISABLED_ADMIN) &&
4213 strcasecmp_m(trec->data.info.netbios_name.string,
4214 nb_name) == 0) {
4215 nb_conflict = true;
4219 if (tln_conflict) {
4220 nt_status = add_collision(c_info, new_fti_idx,
4221 collision_type,
4222 LSA_TLN_DISABLED_CONFLICT,
4223 tdo_name);
4225 if (sid_conflict) {
4226 nt_status = add_collision(c_info, new_fti_idx,
4227 collision_type,
4228 LSA_SID_DISABLED_CONFLICT,
4229 tdo_name);
4231 if (nb_conflict) {
4232 nt_status = add_collision(c_info, new_fti_idx,
4233 collision_type,
4234 LSA_NB_DISABLED_CONFLICT,
4235 tdo_name);
4239 return NT_STATUS_OK;
4242 static NTSTATUS add_collision(struct lsa_ForestTrustCollisionInfo *c_info,
4243 uint32_t idx, uint32_t collision_type,
4244 uint32_t conflict_type, const char *tdo_name)
4246 struct lsa_ForestTrustCollisionRecord **es;
4247 uint32_t i = c_info->count;
4249 es = talloc_realloc(c_info, c_info->entries,
4250 struct lsa_ForestTrustCollisionRecord *, i + 1);
4251 if (!es) {
4252 return NT_STATUS_NO_MEMORY;
4254 c_info->entries = es;
4255 c_info->count = i + 1;
4257 es[i] = talloc(es, struct lsa_ForestTrustCollisionRecord);
4258 if (!es[i]) {
4259 return NT_STATUS_NO_MEMORY;
4262 es[i]->index = idx;
4263 es[i]->type = collision_type;
4264 es[i]->flags.flags = conflict_type;
4265 es[i]->name.string = talloc_strdup(es[i], tdo_name);
4266 if (!es[i]->name.string) {
4267 return NT_STATUS_NO_MEMORY;
4269 es[i]->name.size = strlen(es[i]->name.string);
4271 return NT_STATUS_OK;
4275 lsa_lsaRSetForestTrustInformation
4277 static NTSTATUS dcesrv_lsa_lsaRSetForestTrustInformation(struct dcesrv_call_state *dce_call,
4278 TALLOC_CTX *mem_ctx,
4279 struct lsa_lsaRSetForestTrustInformation *r)
4281 struct dcesrv_handle *h;
4282 struct lsa_policy_state *p_state;
4283 const char *trust_attrs[] = { "trustPartner", "trustAttributes",
4284 "msDS-TrustForestTrustInfo", NULL };
4285 struct ldb_message **dom_res = NULL;
4286 struct ldb_dn *tdo_dn;
4287 struct ldb_message *msg;
4288 int num_res, i;
4289 const char *td_name;
4290 uint32_t trust_attributes;
4291 struct lsa_ForestTrustCollisionInfo *c_info;
4292 struct ForestTrustInfo *nfti;
4293 struct ForestTrustInfo *fti;
4294 DATA_BLOB ft_blob;
4295 enum ndr_err_code ndr_err;
4296 NTSTATUS nt_status;
4297 bool am_rodc;
4298 int ret;
4300 DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
4302 p_state = h->data;
4304 if (strcmp(p_state->domain_dns, p_state->forest_dns)) {
4305 return NT_STATUS_INVALID_DOMAIN_STATE;
4308 /* abort if we are not a PDC */
4309 if (!samdb_is_pdc(p_state->sam_ldb)) {
4310 return NT_STATUS_INVALID_DOMAIN_ROLE;
4313 ret = samdb_rodc(p_state->sam_ldb, &am_rodc);
4314 if (ret == LDB_SUCCESS && am_rodc) {
4315 return NT_STATUS_NO_SUCH_DOMAIN;
4318 /* check caller has TRUSTED_SET_AUTH */
4320 /* fetch all trusted domain objects */
4321 num_res = gendb_search(p_state->sam_ldb, mem_ctx,
4322 p_state->system_dn,
4323 &dom_res, trust_attrs,
4324 "(objectclass=trustedDomain)");
4325 if (num_res == 0) {
4326 return NT_STATUS_NO_SUCH_DOMAIN;
4329 for (i = 0; i < num_res; i++) {
4330 td_name = ldb_msg_find_attr_as_string(dom_res[i],
4331 "trustPartner", NULL);
4332 if (!td_name) {
4333 return NT_STATUS_INVALID_DOMAIN_STATE;
4335 if (strcasecmp_m(td_name,
4336 r->in.trusted_domain_name->string) == 0) {
4337 break;
4340 if (i >= num_res) {
4341 return NT_STATUS_NO_SUCH_DOMAIN;
4344 tdo_dn = dom_res[i]->dn;
4346 trust_attributes = ldb_msg_find_attr_as_uint(dom_res[i],
4347 "trustAttributes", 0);
4348 if (!(trust_attributes & NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
4349 return NT_STATUS_INVALID_PARAMETER;
4352 if (r->in.highest_record_type >= LSA_FOREST_TRUST_RECORD_TYPE_LAST) {
4353 return NT_STATUS_INVALID_PARAMETER;
4356 nfti = talloc(mem_ctx, struct ForestTrustInfo);
4357 if (!nfti) {
4358 return NT_STATUS_NO_MEMORY;
4361 nt_status = make_ft_info(nfti, r->in.forest_trust_info, nfti);
4362 if (!NT_STATUS_IS_OK(nt_status)) {
4363 return nt_status;
4366 c_info = talloc_zero(r->out.collision_info,
4367 struct lsa_ForestTrustCollisionInfo);
4368 if (!c_info) {
4369 return NT_STATUS_NO_MEMORY;
4372 /* first check own info, then other domains */
4373 fti = talloc(mem_ctx, struct ForestTrustInfo);
4374 if (!fti) {
4375 return NT_STATUS_NO_MEMORY;
4378 nt_status = own_ft_info(p_state, fti);
4379 if (!NT_STATUS_IS_OK(nt_status)) {
4380 return nt_status;
4383 nt_status = check_ft_info(c_info, p_state->domain_dns,
4384 fti, nfti, c_info);
4385 if (!NT_STATUS_IS_OK(nt_status)) {
4386 return nt_status;
4389 for (i = 0; i < num_res; i++) {
4390 fti = talloc(mem_ctx, struct ForestTrustInfo);
4391 if (!fti) {
4392 return NT_STATUS_NO_MEMORY;
4395 nt_status = get_ft_info(mem_ctx, dom_res[i], fti);
4396 if (!NT_STATUS_IS_OK(nt_status)) {
4397 if (NT_STATUS_EQUAL(nt_status,
4398 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
4399 continue;
4401 return nt_status;
4404 td_name = ldb_msg_find_attr_as_string(dom_res[i],
4405 "trustPartner", NULL);
4406 if (!td_name) {
4407 return NT_STATUS_INVALID_DOMAIN_STATE;
4410 nt_status = check_ft_info(c_info, td_name, fti, nfti, c_info);
4411 if (!NT_STATUS_IS_OK(nt_status)) {
4412 return nt_status;
4416 *r->out.collision_info = c_info;
4418 if (r->in.check_only != 0) {
4419 return NT_STATUS_OK;
4422 /* not just a check, write info back */
4424 ndr_err = ndr_push_struct_blob(&ft_blob, mem_ctx, nfti,
4425 (ndr_push_flags_fn_t)ndr_push_ForestTrustInfo);
4426 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4427 return NT_STATUS_INVALID_PARAMETER;
4430 msg = ldb_msg_new(mem_ctx);
4431 if (msg == NULL) {
4432 return NT_STATUS_NO_MEMORY;
4435 msg->dn = ldb_dn_copy(mem_ctx, tdo_dn);
4436 if (!msg->dn) {
4437 return NT_STATUS_NO_MEMORY;
4440 ret = ldb_msg_add_empty(msg, "msDS-TrustForestTrustInfo",
4441 LDB_FLAG_MOD_REPLACE, NULL);
4442 if (ret != LDB_SUCCESS) {
4443 return NT_STATUS_NO_MEMORY;
4445 ret = ldb_msg_add_value(msg, "msDS-TrustForestTrustInfo",
4446 &ft_blob, NULL);
4447 if (ret != LDB_SUCCESS) {
4448 return NT_STATUS_NO_MEMORY;
4451 ret = ldb_modify(p_state->sam_ldb, msg);
4452 if (ret != LDB_SUCCESS) {
4453 DEBUG(0, ("Failed to store Forest Trust Info: %s\n",
4454 ldb_errstring(p_state->sam_ldb)));
4456 switch (ret) {
4457 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
4458 return NT_STATUS_ACCESS_DENIED;
4459 default:
4460 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4464 return NT_STATUS_OK;
4468 lsa_CREDRRENAME
4470 static NTSTATUS dcesrv_lsa_CREDRRENAME(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4471 struct lsa_CREDRRENAME *r)
4473 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4479 lsa_LSAROPENPOLICYSCE
4481 static NTSTATUS dcesrv_lsa_LSAROPENPOLICYSCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4482 struct lsa_LSAROPENPOLICYSCE *r)
4484 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4489 lsa_LSARADTREGISTERSECURITYEVENTSOURCE
4491 static NTSTATUS dcesrv_lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4492 struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r)
4494 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4499 lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE
4501 static NTSTATUS dcesrv_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4502 struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r)
4504 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4509 lsa_LSARADTREPORTSECURITYEVENT
4511 static NTSTATUS dcesrv_lsa_LSARADTREPORTSECURITYEVENT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4512 struct lsa_LSARADTREPORTSECURITYEVENT *r)
4514 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4518 /* include the generated boilerplate */
4519 #include "librpc/gen_ndr/ndr_lsa_s.c"
4523 /*****************************************
4524 NOTE! The remaining calls below were
4525 removed in w2k3, so the DCESRV_FAULT()
4526 replies are the correct implementation. Do
4527 not try and fill these in with anything else
4528 ******************************************/
4531 dssetup_DsRoleDnsNameToFlatName
4533 static WERROR dcesrv_dssetup_DsRoleDnsNameToFlatName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4534 struct dssetup_DsRoleDnsNameToFlatName *r)
4536 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4541 dssetup_DsRoleDcAsDc
4543 static WERROR dcesrv_dssetup_DsRoleDcAsDc(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4544 struct dssetup_DsRoleDcAsDc *r)
4546 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4551 dssetup_DsRoleDcAsReplica
4553 static WERROR dcesrv_dssetup_DsRoleDcAsReplica(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4554 struct dssetup_DsRoleDcAsReplica *r)
4556 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4561 dssetup_DsRoleDemoteDc
4563 static WERROR dcesrv_dssetup_DsRoleDemoteDc(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4564 struct dssetup_DsRoleDemoteDc *r)
4566 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4571 dssetup_DsRoleGetDcOperationProgress
4573 static WERROR dcesrv_dssetup_DsRoleGetDcOperationProgress(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4574 struct dssetup_DsRoleGetDcOperationProgress *r)
4576 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4581 dssetup_DsRoleGetDcOperationResults
4583 static WERROR dcesrv_dssetup_DsRoleGetDcOperationResults(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4584 struct dssetup_DsRoleGetDcOperationResults *r)
4586 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4591 dssetup_DsRoleCancel
4593 static WERROR dcesrv_dssetup_DsRoleCancel(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4594 struct dssetup_DsRoleCancel *r)
4596 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4601 dssetup_DsRoleServerSaveStateForUpgrade
4603 static WERROR dcesrv_dssetup_DsRoleServerSaveStateForUpgrade(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4604 struct dssetup_DsRoleServerSaveStateForUpgrade *r)
4606 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4611 dssetup_DsRoleUpgradeDownlevelServer
4613 static WERROR dcesrv_dssetup_DsRoleUpgradeDownlevelServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4614 struct dssetup_DsRoleUpgradeDownlevelServer *r)
4616 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4621 dssetup_DsRoleAbortDownlevelServerUpgrade
4623 static WERROR dcesrv_dssetup_DsRoleAbortDownlevelServerUpgrade(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4624 struct dssetup_DsRoleAbortDownlevelServerUpgrade *r)
4626 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4630 /* include the generated boilerplate */
4631 #include "librpc/gen_ndr/ndr_dssetup_s.c"
4633 NTSTATUS dcerpc_server_lsa_init(void)
4635 NTSTATUS ret;
4637 ret = dcerpc_server_dssetup_init();
4638 if (!NT_STATUS_IS_OK(ret)) {
4639 return ret;
4641 ret = dcerpc_server_lsarpc_init();
4642 if (!NT_STATUS_IS_OK(ret)) {
4643 return ret;
4645 return ret;