2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
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/>.
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
44 #define DCESRV_INTERFACE_SAMR_BIND(call, iface) \
45 dcesrv_interface_samr_bind(call, iface)
46 static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_call_state *dce_call,
47 const struct dcesrv_interface *iface)
49 return dcesrv_interface_bind_reject_connect(dce_call, iface);
52 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
54 #define QUERY_STRING(msg, field, attr) \
55 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
56 #define QUERY_UINT(msg, field, attr) \
57 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
58 #define QUERY_RID(msg, field, attr) \
59 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
60 #define QUERY_UINT64(msg, field, attr) \
61 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
62 #define QUERY_APASSC(msg, field, attr) \
63 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
64 a_state->domain_state->domain_dn, msg, attr);
65 #define QUERY_FPASSC(msg, field, attr) \
66 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
67 a_state->domain_state->domain_dn, msg);
68 #define QUERY_BPWDCT(msg, field, attr) \
69 info->field = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx, \
70 a_state->domain_state->domain_dn, msg);
71 #define QUERY_LHOURS(msg, field, attr) \
72 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
73 #define QUERY_AFLAGS(msg, field, attr) \
74 info->field = samdb_result_acct_flags(msg, attr);
77 /* these are used to make the Set[User|Group]Info code easier to follow */
79 #define SET_STRING(msg, field, attr) do { \
80 struct ldb_message_element *set_el; \
81 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
82 if (r->in.info->field.string[0] == '\0') { \
83 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
84 return NT_STATUS_NO_MEMORY; \
87 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
88 return NT_STATUS_NO_MEMORY; \
90 set_el = ldb_msg_find_element(msg, attr); \
91 set_el->flags = LDB_FLAG_MOD_REPLACE; \
94 #define SET_UINT(msg, field, attr) do { \
95 struct ldb_message_element *set_el; \
96 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
97 return NT_STATUS_NO_MEMORY; \
99 set_el = ldb_msg_find_element(msg, attr); \
100 set_el->flags = LDB_FLAG_MOD_REPLACE; \
103 #define SET_INT64(msg, field, attr) do { \
104 struct ldb_message_element *set_el; \
105 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
106 return NT_STATUS_NO_MEMORY; \
108 set_el = ldb_msg_find_element(msg, attr); \
109 set_el->flags = LDB_FLAG_MOD_REPLACE; \
112 #define SET_UINT64(msg, field, attr) do { \
113 struct ldb_message_element *set_el; \
114 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
115 return NT_STATUS_NO_MEMORY; \
117 set_el = ldb_msg_find_element(msg, attr); \
118 set_el->flags = LDB_FLAG_MOD_REPLACE; \
121 /* Set account flags, discarding flags that cannot be set with SAMR */
122 #define SET_AFLAGS(msg, field, attr) do { \
123 struct ldb_message_element *set_el; \
124 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
125 return NT_STATUS_NO_MEMORY; \
127 set_el = ldb_msg_find_element(msg, attr); \
128 set_el->flags = LDB_FLAG_MOD_REPLACE; \
131 #define SET_LHOURS(msg, field, attr) do { \
132 struct ldb_message_element *set_el; \
133 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
134 return NT_STATUS_NO_MEMORY; \
136 set_el = ldb_msg_find_element(msg, attr); \
137 set_el->flags = LDB_FLAG_MOD_REPLACE; \
140 #define SET_PARAMETERS(msg, field, attr) do { \
141 struct ldb_message_element *set_el; \
142 if (r->in.info->field.length != 0) { \
143 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
144 return NT_STATUS_NO_MEMORY; \
146 set_el = ldb_msg_find_element(msg, attr); \
147 set_el->flags = LDB_FLAG_MOD_REPLACE; \
156 create a connection to the SAM database
158 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
159 struct samr_Connect *r)
161 struct samr_connect_state *c_state;
162 struct dcesrv_handle *handle;
164 ZERO_STRUCTP(r->out.connect_handle);
166 c_state = talloc(mem_ctx, struct samr_connect_state);
168 return NT_STATUS_NO_MEMORY;
171 /* make sure the sam database is accessible */
172 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0);
173 if (c_state->sam_ctx == NULL) {
174 talloc_free(c_state);
175 return NT_STATUS_INVALID_SYSTEM_SERVICE;
179 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
181 talloc_free(c_state);
182 return NT_STATUS_NO_MEMORY;
185 handle->data = talloc_steal(handle, c_state);
187 c_state->access_mask = r->in.access_mask;
188 *r->out.connect_handle = handle->wire_handle;
197 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
198 struct samr_Close *r)
200 struct dcesrv_handle *h;
202 *r->out.handle = *r->in.handle;
204 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
208 ZERO_STRUCTP(r->out.handle);
217 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
218 struct samr_SetSecurity *r)
220 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
227 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
228 struct samr_QuerySecurity *r)
230 struct dcesrv_handle *h;
231 struct sec_desc_buf *sd;
233 *r->out.sdbuf = NULL;
235 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
237 sd = talloc(mem_ctx, struct sec_desc_buf);
239 return NT_STATUS_NO_MEMORY;
242 sd->sd = samdb_default_security_descriptor(mem_ctx);
253 we refuse this operation completely. If a admin wants to shutdown samr
254 in Samba then they should use the samba admin tools to disable the samr pipe
256 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
257 struct samr_Shutdown *r)
259 return NT_STATUS_ACCESS_DENIED;
266 this maps from a domain name to a SID
268 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
269 struct samr_LookupDomain *r)
271 struct samr_connect_state *c_state;
272 struct dcesrv_handle *h;
274 const char * const dom_attrs[] = { "objectSid", NULL};
275 struct ldb_message **dom_msgs;
280 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
284 if (r->in.domain_name->string == NULL) {
285 return NT_STATUS_INVALID_PARAMETER;
288 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
289 ret = gendb_search(c_state->sam_ctx,
290 mem_ctx, NULL, &dom_msgs, dom_attrs,
291 "(objectClass=builtinDomain)");
292 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
293 ret = gendb_search_dn(c_state->sam_ctx,
294 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
295 &dom_msgs, dom_attrs);
297 return NT_STATUS_NO_SUCH_DOMAIN;
300 return NT_STATUS_NO_SUCH_DOMAIN;
303 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
307 return NT_STATUS_NO_SUCH_DOMAIN;
319 list the domains in the SAM
321 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
322 struct samr_EnumDomains *r)
324 struct dcesrv_handle *h;
325 struct samr_SamArray *array;
328 *r->out.resume_handle = 0;
330 *r->out.num_entries = 0;
332 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
334 *r->out.resume_handle = 2;
336 start_i = *r->in.resume_handle;
339 /* search past end of list is not an error for this call */
343 array = talloc(mem_ctx, struct samr_SamArray);
345 return NT_STATUS_NO_MEMORY;
349 array->entries = NULL;
351 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
352 if (array->entries == NULL) {
353 return NT_STATUS_NO_MEMORY;
356 for (i=0;i<2-start_i;i++) {
357 array->entries[i].idx = start_i + i;
359 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
361 array->entries[i].name.string = "BUILTIN";
366 *r->out.num_entries = i;
367 array->count = *r->out.num_entries;
376 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
377 struct samr_OpenDomain *r)
379 struct dcesrv_handle *h_conn, *h_domain;
380 struct samr_connect_state *c_state;
381 struct samr_domain_state *d_state;
382 const char * const dom_attrs[] = { "cn", NULL};
383 struct ldb_message **dom_msgs;
386 ZERO_STRUCTP(r->out.domain_handle);
388 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
390 c_state = h_conn->data;
392 if (r->in.sid == NULL) {
393 return NT_STATUS_INVALID_PARAMETER;
396 d_state = talloc(mem_ctx, struct samr_domain_state);
398 return NT_STATUS_NO_MEMORY;
401 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
403 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
404 d_state->builtin = true;
405 d_state->domain_name = "BUILTIN";
407 d_state->builtin = false;
408 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
411 ret = gendb_search(c_state->sam_ctx,
412 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
414 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
417 talloc_free(d_state);
418 return NT_STATUS_NO_SUCH_DOMAIN;
419 } else if (ret > 1) {
420 talloc_free(d_state);
421 return NT_STATUS_INTERNAL_DB_CORRUPTION;
422 } else if (ret == -1) {
423 talloc_free(d_state);
424 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
425 return NT_STATUS_INTERNAL_DB_CORRUPTION;
428 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
429 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
430 d_state->connect_state = talloc_reference(d_state, c_state);
431 d_state->sam_ctx = c_state->sam_ctx;
432 d_state->access_mask = r->in.access_mask;
434 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
436 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
438 talloc_free(d_state);
439 return NT_STATUS_NO_MEMORY;
442 h_domain->data = talloc_steal(h_domain, d_state);
444 *r->out.domain_handle = h_domain->wire_handle;
452 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
454 struct ldb_message **dom_msgs,
455 struct samr_DomInfo1 *info)
457 info->min_password_length =
458 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
459 info->password_history_length =
460 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
461 info->password_properties =
462 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
463 info->max_password_age =
464 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
465 info->min_password_age =
466 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
474 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
476 struct ldb_message **dom_msgs,
477 struct samr_DomGeneralInformation *info)
479 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
480 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
484 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
485 0x8000000000000000LL);
487 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
490 info->domain_name.string = state->domain_name;
492 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
494 switch (state->role) {
495 case ROLE_ACTIVE_DIRECTORY_DC:
496 /* This pulls the NetBIOS name from the
497 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
499 if (samdb_is_pdc(state->sam_ctx)) {
500 info->role = SAMR_ROLE_DOMAIN_PDC;
502 info->role = SAMR_ROLE_DOMAIN_BDC;
505 case ROLE_DOMAIN_PDC:
506 case ROLE_DOMAIN_BDC:
508 return NT_STATUS_INTERNAL_ERROR;
509 case ROLE_DOMAIN_MEMBER:
510 info->role = SAMR_ROLE_DOMAIN_MEMBER;
512 case ROLE_STANDALONE:
513 info->role = SAMR_ROLE_STANDALONE;
517 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx,
519 "(objectClass=user)");
520 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx,
522 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
523 GTYPE_SECURITY_UNIVERSAL_GROUP,
524 GTYPE_SECURITY_GLOBAL_GROUP);
525 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx,
527 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
528 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
529 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
537 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
539 struct ldb_message **dom_msgs,
540 struct samr_DomInfo3 *info)
542 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
543 0x8000000000000000LL);
551 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
553 struct ldb_message **dom_msgs,
554 struct samr_DomOEMInformation *info)
556 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
566 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
568 struct ldb_message **dom_msgs,
569 struct samr_DomInfo5 *info)
571 info->domain_name.string = state->domain_name;
579 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
581 struct ldb_message **dom_msgs,
582 struct samr_DomInfo6 *info)
584 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
585 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
595 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
597 struct ldb_message **dom_msgs,
598 struct samr_DomInfo7 *info)
601 switch (state->role) {
602 case ROLE_ACTIVE_DIRECTORY_DC:
603 /* This pulls the NetBIOS name from the
604 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
606 if (samdb_is_pdc(state->sam_ctx)) {
607 info->role = SAMR_ROLE_DOMAIN_PDC;
609 info->role = SAMR_ROLE_DOMAIN_BDC;
612 case ROLE_DOMAIN_PDC:
613 case ROLE_DOMAIN_BDC:
615 return NT_STATUS_INTERNAL_ERROR;
616 case ROLE_DOMAIN_MEMBER:
617 info->role = SAMR_ROLE_DOMAIN_MEMBER;
619 case ROLE_STANDALONE:
620 info->role = SAMR_ROLE_STANDALONE;
630 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
632 struct ldb_message **dom_msgs,
633 struct samr_DomInfo8 *info)
635 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
638 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
647 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
649 struct ldb_message **dom_msgs,
650 struct samr_DomInfo9 *info)
652 info->domain_server_state = DOMAIN_SERVER_ENABLED;
660 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
662 struct ldb_message **dom_msgs,
663 struct samr_DomGeneralInformation2 *info)
666 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
667 if (!NT_STATUS_IS_OK(status)) {
671 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
673 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
675 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
683 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
685 struct ldb_message **dom_msgs,
686 struct samr_DomInfo12 *info)
688 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
690 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
692 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
700 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
702 struct ldb_message **dom_msgs,
703 struct samr_DomInfo13 *info)
705 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
708 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
711 info->modified_count_at_last_promotion = 0;
719 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
721 struct samr_QueryDomainInfo *r)
723 struct dcesrv_handle *h;
724 struct samr_domain_state *d_state;
725 union samr_DomainInfo *info;
727 struct ldb_message **dom_msgs;
728 const char * const *attrs = NULL;
732 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
736 switch (r->in.level) {
739 static const char * const attrs2[] = { "minPwdLength",
750 static const char * const attrs2[] = {"forceLogoff",
760 static const char * const attrs2[] = {"forceLogoff",
767 static const char * const attrs2[] = {"oEMInformation",
779 static const char * const attrs2[] = { "domainReplica",
791 static const char * const attrs2[] = { "modifiedCount",
804 static const char * const attrs2[] = { "oEMInformation",
808 "lockOutObservationWindow",
816 static const char * const attrs2[] = { "lockoutDuration",
817 "lockOutObservationWindow",
825 static const char * const attrs2[] = { "modifiedCount",
833 return NT_STATUS_INVALID_INFO_CLASS;
837 /* some levels don't need a search */
840 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
841 d_state->domain_dn, &dom_msgs, attrs);
843 return NT_STATUS_NO_SUCH_DOMAIN;
846 return NT_STATUS_INTERNAL_DB_CORRUPTION;
850 /* allocate the info structure */
851 info = talloc_zero(mem_ctx, union samr_DomainInfo);
853 return NT_STATUS_NO_MEMORY;
858 switch (r->in.level) {
860 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
863 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
866 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
869 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
872 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
875 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
878 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
881 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
884 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
887 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
890 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
893 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
896 return NT_STATUS_INVALID_INFO_CLASS;
904 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
905 struct samr_SetDomainInfo *r)
907 struct dcesrv_handle *h;
908 struct samr_domain_state *d_state;
909 struct ldb_message *msg;
911 struct ldb_context *sam_ctx;
913 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
916 sam_ctx = d_state->sam_ctx;
918 msg = ldb_msg_new(mem_ctx);
920 return NT_STATUS_NO_MEMORY;
923 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
925 return NT_STATUS_NO_MEMORY;
928 switch (r->in.level) {
930 SET_UINT (msg, info1.min_password_length, "minPwdLength");
931 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
932 SET_UINT (msg, info1.password_properties, "pwdProperties");
933 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
934 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
937 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
940 SET_STRING(msg, oem.oem_information, "oEMInformation");
946 /* No op, we don't know where to set these */
951 * It is not possible to set lockout_duration < lockout_window.
952 * (The test is the other way around since the negative numbers
956 * This check should be moved to the backend, i.e. to some
957 * ldb module under dsdb/samdb/ldb_modules/ .
959 * This constraint is documented here for the samr rpc service:
960 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
961 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
963 * And here for the ldap backend:
964 * MS-ADTS 3.1.1.5.3.2 Constraints
965 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
967 if (r->in.info->info12.lockout_duration >
968 r->in.info->info12.lockout_window)
970 return NT_STATUS_INVALID_PARAMETER;
972 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
973 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
974 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
978 /* many info classes are not valid for SetDomainInfo */
979 return NT_STATUS_INVALID_INFO_CLASS;
982 /* modify the samdb record */
983 ret = ldb_modify(sam_ctx, msg);
984 if (ret != LDB_SUCCESS) {
985 DEBUG(1,("Failed to modify record %s: %s\n",
986 ldb_dn_get_linearized(d_state->domain_dn),
987 ldb_errstring(sam_ctx)));
988 return dsdb_ldb_err_to_ntstatus(ret);
995 samr_CreateDomainGroup
997 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
998 struct samr_CreateDomainGroup *r)
1001 struct samr_domain_state *d_state;
1002 struct samr_account_state *a_state;
1003 struct dcesrv_handle *h;
1004 const char *groupname;
1005 struct dom_sid *group_sid;
1006 struct ldb_dn *group_dn;
1007 struct dcesrv_handle *g_handle;
1009 ZERO_STRUCTP(r->out.group_handle);
1012 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1016 if (d_state->builtin) {
1017 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1018 return NT_STATUS_ACCESS_DENIED;
1021 groupname = r->in.name->string;
1023 if (groupname == NULL) {
1024 return NT_STATUS_INVALID_PARAMETER;
1027 status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1028 if (!NT_STATUS_IS_OK(status)) {
1032 a_state = talloc(mem_ctx, struct samr_account_state);
1034 return NT_STATUS_NO_MEMORY;
1036 a_state->sam_ctx = d_state->sam_ctx;
1037 a_state->access_mask = r->in.access_mask;
1038 a_state->domain_state = talloc_reference(a_state, d_state);
1039 a_state->account_dn = talloc_steal(a_state, group_dn);
1041 a_state->account_name = talloc_steal(a_state, groupname);
1043 /* create the policy handle */
1044 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1046 return NT_STATUS_NO_MEMORY;
1049 g_handle->data = talloc_steal(g_handle, a_state);
1051 *r->out.group_handle = g_handle->wire_handle;
1052 *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1054 return NT_STATUS_OK;
1059 comparison function for sorting SamEntry array
1061 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1063 return e1->idx - e2->idx;
1067 samr_EnumDomainGroups
1069 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1070 struct samr_EnumDomainGroups *r)
1072 struct dcesrv_handle *h;
1073 struct samr_domain_state *d_state;
1074 struct ldb_message **res;
1076 uint32_t first, count;
1077 struct samr_SamEntry *entries;
1078 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1079 struct samr_SamArray *sam;
1081 *r->out.resume_handle = 0;
1083 *r->out.num_entries = 0;
1085 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1089 /* search for all domain groups in this domain. This could possibly be
1090 cached and resumed based on resume_key */
1091 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1092 d_state->domain_dn, &res, attrs,
1093 d_state->domain_sid,
1094 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1095 GTYPE_SECURITY_UNIVERSAL_GROUP,
1096 GTYPE_SECURITY_GLOBAL_GROUP);
1098 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1101 /* convert to SamEntry format */
1102 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1104 return NT_STATUS_NO_MEMORY;
1109 for (i=0;i<ldb_cnt;i++) {
1110 struct dom_sid *group_sid;
1112 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1114 if (group_sid == NULL) {
1115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1118 entries[count].idx =
1119 group_sid->sub_auths[group_sid->num_auths-1];
1120 entries[count].name.string =
1121 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1125 /* sort the results by rid */
1126 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1128 /* find the first entry to return */
1130 first<count && entries[first].idx <= *r->in.resume_handle;
1133 /* return the rest, limit by max_size. Note that we
1134 use the w2k3 element size value of 54 */
1135 *r->out.num_entries = count - first;
1136 *r->out.num_entries = MIN(*r->out.num_entries,
1137 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1139 sam = talloc(mem_ctx, struct samr_SamArray);
1141 return NT_STATUS_NO_MEMORY;
1144 sam->entries = entries+first;
1145 sam->count = *r->out.num_entries;
1149 if (first == count) {
1150 return NT_STATUS_OK;
1153 if (*r->out.num_entries < count - first) {
1154 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1155 return STATUS_MORE_ENTRIES;
1158 return NT_STATUS_OK;
1165 This call uses transactions to ensure we don't get a new conflicting
1166 user while we are processing this, and to ensure the user either
1167 completly exists, or does not.
1169 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1170 struct samr_CreateUser2 *r)
1173 struct samr_domain_state *d_state;
1174 struct samr_account_state *a_state;
1175 struct dcesrv_handle *h;
1177 struct dom_sid *sid;
1178 struct dcesrv_handle *u_handle;
1179 const char *account_name;
1181 ZERO_STRUCTP(r->out.user_handle);
1182 *r->out.access_granted = 0;
1185 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1189 if (d_state->builtin) {
1190 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1191 return NT_STATUS_ACCESS_DENIED;
1192 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1193 /* Domain trust accounts must be created by the LSA calls */
1194 return NT_STATUS_ACCESS_DENIED;
1196 account_name = r->in.account_name->string;
1198 if (account_name == NULL) {
1199 return NT_STATUS_INVALID_PARAMETER;
1202 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
1204 if (!NT_STATUS_IS_OK(status)) {
1207 a_state = talloc(mem_ctx, struct samr_account_state);
1209 return NT_STATUS_NO_MEMORY;
1211 a_state->sam_ctx = d_state->sam_ctx;
1212 a_state->access_mask = r->in.access_mask;
1213 a_state->domain_state = talloc_reference(a_state, d_state);
1214 a_state->account_dn = talloc_steal(a_state, dn);
1216 a_state->account_name = talloc_steal(a_state, account_name);
1217 if (!a_state->account_name) {
1218 return NT_STATUS_NO_MEMORY;
1221 /* create the policy handle */
1222 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1224 return NT_STATUS_NO_MEMORY;
1227 u_handle->data = talloc_steal(u_handle, a_state);
1229 *r->out.user_handle = u_handle->wire_handle;
1230 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1232 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1234 return NT_STATUS_OK;
1241 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1242 struct samr_CreateUser *r)
1244 struct samr_CreateUser2 r2;
1245 uint32_t access_granted = 0;
1248 /* a simple wrapper around samr_CreateUser2 works nicely */
1250 r2 = (struct samr_CreateUser2) {
1251 .in.domain_handle = r->in.domain_handle,
1252 .in.account_name = r->in.account_name,
1253 .in.acct_flags = ACB_NORMAL,
1254 .in.access_mask = r->in.access_mask,
1255 .out.user_handle = r->out.user_handle,
1256 .out.access_granted = &access_granted,
1257 .out.rid = r->out.rid
1260 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1264 samr_EnumDomainUsers
1266 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1267 struct samr_EnumDomainUsers *r)
1269 struct dcesrv_handle *h;
1270 struct samr_domain_state *d_state;
1271 struct ldb_message **res;
1273 uint32_t first, count;
1274 struct samr_SamEntry *entries;
1275 const char * const attrs[] = { "objectSid", "sAMAccountName",
1276 "userAccountControl", NULL };
1277 struct samr_SamArray *sam;
1279 *r->out.resume_handle = 0;
1281 *r->out.num_entries = 0;
1283 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1287 /* search for all domain users in this domain. This could possibly be
1288 cached and resumed on resume_key */
1289 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1292 d_state->domain_sid,
1293 "(objectClass=user)");
1295 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1298 /* convert to SamEntry format */
1299 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1301 return NT_STATUS_NO_MEMORY;
1306 for (i=0;i<ldb_cnt;i++) {
1307 /* Check if a mask has been requested */
1308 if (r->in.acct_flags
1309 && ((samdb_result_acct_flags(res[i], NULL) & r->in.acct_flags) == 0)) {
1312 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1314 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1315 "sAMAccountName", "");
1319 /* sort the results by rid */
1320 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1322 /* find the first entry to return */
1324 first<count && entries[first].idx <= *r->in.resume_handle;
1327 /* return the rest, limit by max_size. Note that we
1328 use the w2k3 element size value of 54 */
1329 *r->out.num_entries = count - first;
1330 *r->out.num_entries = MIN(*r->out.num_entries,
1331 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1333 sam = talloc(mem_ctx, struct samr_SamArray);
1335 return NT_STATUS_NO_MEMORY;
1338 sam->entries = entries+first;
1339 sam->count = *r->out.num_entries;
1343 if (first == count) {
1344 return NT_STATUS_OK;
1347 if (*r->out.num_entries < count - first) {
1348 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1349 return STATUS_MORE_ENTRIES;
1352 return NT_STATUS_OK;
1359 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1360 struct samr_CreateDomAlias *r)
1362 struct samr_domain_state *d_state;
1363 struct samr_account_state *a_state;
1364 struct dcesrv_handle *h;
1365 const char *alias_name;
1366 struct dom_sid *sid;
1367 struct dcesrv_handle *a_handle;
1371 ZERO_STRUCTP(r->out.alias_handle);
1374 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1378 if (d_state->builtin) {
1379 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1380 return NT_STATUS_ACCESS_DENIED;
1383 alias_name = r->in.alias_name->string;
1385 if (alias_name == NULL) {
1386 return NT_STATUS_INVALID_PARAMETER;
1389 status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1390 if (!NT_STATUS_IS_OK(status)) {
1394 a_state = talloc(mem_ctx, struct samr_account_state);
1396 return NT_STATUS_NO_MEMORY;
1399 a_state->sam_ctx = d_state->sam_ctx;
1400 a_state->access_mask = r->in.access_mask;
1401 a_state->domain_state = talloc_reference(a_state, d_state);
1402 a_state->account_dn = talloc_steal(a_state, dn);
1404 a_state->account_name = talloc_steal(a_state, alias_name);
1406 /* create the policy handle */
1407 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1408 if (a_handle == NULL)
1409 return NT_STATUS_NO_MEMORY;
1411 a_handle->data = talloc_steal(a_handle, a_state);
1413 *r->out.alias_handle = a_handle->wire_handle;
1415 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1417 return NT_STATUS_OK;
1422 samr_EnumDomainAliases
1424 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1425 struct samr_EnumDomainAliases *r)
1427 struct dcesrv_handle *h;
1428 struct samr_domain_state *d_state;
1429 struct ldb_message **res;
1431 uint32_t first, count;
1432 struct samr_SamEntry *entries;
1433 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1434 struct samr_SamArray *sam;
1436 *r->out.resume_handle = 0;
1438 *r->out.num_entries = 0;
1440 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1444 /* search for all domain aliases in this domain. This could possibly be
1445 cached and resumed based on resume_key */
1446 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1448 d_state->domain_sid,
1449 "(&(|(grouptype=%d)(grouptype=%d)))"
1450 "(objectclass=group))",
1451 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1452 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1454 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1457 /* convert to SamEntry format */
1458 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1460 return NT_STATUS_NO_MEMORY;
1465 for (i=0;i<ldb_cnt;i++) {
1466 struct dom_sid *alias_sid;
1468 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1471 if (alias_sid == NULL) {
1472 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1475 entries[count].idx =
1476 alias_sid->sub_auths[alias_sid->num_auths-1];
1477 entries[count].name.string =
1478 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1482 /* sort the results by rid */
1483 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1485 /* find the first entry to return */
1487 first<count && entries[first].idx <= *r->in.resume_handle;
1490 /* return the rest, limit by max_size. Note that we
1491 use the w2k3 element size value of 54 */
1492 *r->out.num_entries = count - first;
1493 *r->out.num_entries = MIN(*r->out.num_entries,
1494 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1496 sam = talloc(mem_ctx, struct samr_SamArray);
1498 return NT_STATUS_NO_MEMORY;
1501 sam->entries = entries+first;
1502 sam->count = *r->out.num_entries;
1506 if (first == count) {
1507 return NT_STATUS_OK;
1510 if (*r->out.num_entries < count - first) {
1511 *r->out.resume_handle =
1512 entries[first+*r->out.num_entries-1].idx;
1513 return STATUS_MORE_ENTRIES;
1516 return NT_STATUS_OK;
1521 samr_GetAliasMembership
1523 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1524 struct samr_GetAliasMembership *r)
1526 struct dcesrv_handle *h;
1527 struct samr_domain_state *d_state;
1529 const char * const attrs[] = { "objectSid", NULL };
1530 struct ldb_message **res;
1533 char membersidstr[DOM_SID_STR_BUFLEN];
1535 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1539 filter = talloc_asprintf(mem_ctx,
1540 "(&(|(grouptype=%d)(grouptype=%d))"
1541 "(objectclass=group)(|",
1542 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1543 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1544 if (filter == NULL) {
1545 return NT_STATUS_NO_MEMORY;
1548 for (i=0; i<r->in.sids->num_sids; i++) {
1549 dom_sid_string_buf(r->in.sids->sids[i].sid,
1550 membersidstr, sizeof(membersidstr));
1552 filter = talloc_asprintf_append(filter, "(member=<SID=%s>)",
1554 if (filter == NULL) {
1555 return NT_STATUS_NO_MEMORY;
1559 /* Find out if we had at least one valid member SID passed - otherwise
1560 * just skip the search. */
1561 if (strstr(filter, "member") != NULL) {
1562 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1563 &res, attrs, d_state->domain_sid,
1566 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1570 r->out.rids->count = 0;
1571 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1572 if (r->out.rids->ids == NULL)
1573 return NT_STATUS_NO_MEMORY;
1575 for (i=0; i<count; i++) {
1576 struct dom_sid *alias_sid;
1578 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1579 if (alias_sid == NULL) {
1580 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1583 r->out.rids->ids[r->out.rids->count] =
1584 alias_sid->sub_auths[alias_sid->num_auths-1];
1585 r->out.rids->count += 1;
1588 return NT_STATUS_OK;
1595 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1596 struct samr_LookupNames *r)
1598 struct dcesrv_handle *h;
1599 struct samr_domain_state *d_state;
1600 uint32_t i, num_mapped;
1601 NTSTATUS status = NT_STATUS_OK;
1602 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1605 ZERO_STRUCTP(r->out.rids);
1606 ZERO_STRUCTP(r->out.types);
1608 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1612 if (r->in.num_names == 0) {
1613 return NT_STATUS_OK;
1616 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1617 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1618 if (!r->out.rids->ids || !r->out.types->ids) {
1619 return NT_STATUS_NO_MEMORY;
1621 r->out.rids->count = r->in.num_names;
1622 r->out.types->count = r->in.num_names;
1626 for (i=0;i<r->in.num_names;i++) {
1627 struct ldb_message **res;
1628 struct dom_sid *sid;
1629 uint32_t atype, rtype;
1631 r->out.rids->ids[i] = 0;
1632 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1634 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1635 "sAMAccountName=%s",
1636 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1638 status = STATUS_SOME_UNMAPPED;
1642 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1644 status = STATUS_SOME_UNMAPPED;
1648 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1650 status = STATUS_SOME_UNMAPPED;
1654 rtype = ds_atype_map(atype);
1656 if (rtype == SID_NAME_UNKNOWN) {
1657 status = STATUS_SOME_UNMAPPED;
1661 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1662 r->out.types->ids[i] = rtype;
1666 if (num_mapped == 0) {
1667 return NT_STATUS_NONE_MAPPED;
1676 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1677 struct samr_LookupRids *r)
1680 struct dcesrv_handle *h;
1681 struct samr_domain_state *d_state;
1683 struct lsa_String *lsa_names;
1684 enum lsa_SidType *ids;
1686 ZERO_STRUCTP(r->out.names);
1687 ZERO_STRUCTP(r->out.types);
1689 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1693 if (r->in.num_rids == 0)
1694 return NT_STATUS_OK;
1696 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1697 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1698 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1700 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1701 return NT_STATUS_NO_MEMORY;
1703 r->out.names->names = lsa_names;
1704 r->out.names->count = r->in.num_rids;
1706 r->out.types->ids = (uint32_t *) ids;
1707 r->out.types->count = r->in.num_rids;
1709 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1710 r->in.num_rids, r->in.rids, names, ids);
1711 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1713 for (i = 0; i < r->in.num_rids; i++) {
1714 lsa_names[i].string = names[i];
1724 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1725 struct samr_OpenGroup *r)
1727 struct samr_domain_state *d_state;
1728 struct samr_account_state *a_state;
1729 struct dcesrv_handle *h;
1730 const char *groupname;
1731 struct dom_sid *sid;
1732 struct ldb_message **msgs;
1733 struct dcesrv_handle *g_handle;
1734 const char * const attrs[2] = { "sAMAccountName", NULL };
1737 ZERO_STRUCTP(r->out.group_handle);
1739 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1743 /* form the group SID */
1744 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1746 return NT_STATUS_NO_MEMORY;
1749 /* search for the group record */
1750 if (d_state->builtin) {
1751 ret = gendb_search(d_state->sam_ctx,
1752 mem_ctx, d_state->domain_dn, &msgs, attrs,
1753 "(&(objectSid=%s)(objectClass=group)"
1755 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1756 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
1758 ret = gendb_search(d_state->sam_ctx,
1759 mem_ctx, d_state->domain_dn, &msgs, attrs,
1760 "(&(objectSid=%s)(objectClass=group)"
1761 "(|(groupType=%d)(groupType=%d)))",
1762 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1763 GTYPE_SECURITY_UNIVERSAL_GROUP,
1764 GTYPE_SECURITY_GLOBAL_GROUP);
1767 return NT_STATUS_NO_SUCH_GROUP;
1770 DEBUG(0,("Found %d records matching sid %s\n",
1771 ret, dom_sid_string(mem_ctx, sid)));
1772 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1775 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1776 if (groupname == NULL) {
1777 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1778 dom_sid_string(mem_ctx, sid)));
1779 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1782 a_state = talloc(mem_ctx, struct samr_account_state);
1784 return NT_STATUS_NO_MEMORY;
1786 a_state->sam_ctx = d_state->sam_ctx;
1787 a_state->access_mask = r->in.access_mask;
1788 a_state->domain_state = talloc_reference(a_state, d_state);
1789 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1790 a_state->account_sid = talloc_steal(a_state, sid);
1791 a_state->account_name = talloc_strdup(a_state, groupname);
1792 if (!a_state->account_name) {
1793 return NT_STATUS_NO_MEMORY;
1796 /* create the policy handle */
1797 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1799 return NT_STATUS_NO_MEMORY;
1802 g_handle->data = talloc_steal(g_handle, a_state);
1804 *r->out.group_handle = g_handle->wire_handle;
1806 return NT_STATUS_OK;
1812 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1813 struct samr_QueryGroupInfo *r)
1815 struct dcesrv_handle *h;
1816 struct samr_account_state *a_state;
1817 struct ldb_message *msg, **res;
1818 const char * const attrs[4] = { "sAMAccountName", "description",
1819 "numMembers", NULL };
1821 union samr_GroupInfo *info;
1823 *r->out.info = NULL;
1825 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1829 /* pull all the group attributes */
1830 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1831 a_state->account_dn, &res, attrs);
1833 return NT_STATUS_NO_SUCH_GROUP;
1836 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1840 /* allocate the info structure */
1841 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1843 return NT_STATUS_NO_MEMORY;
1846 /* Fill in the level */
1847 switch (r->in.level) {
1849 QUERY_STRING(msg, all.name, "sAMAccountName");
1850 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1851 QUERY_UINT (msg, all.num_members, "numMembers")
1852 QUERY_STRING(msg, all.description, "description");
1855 QUERY_STRING(msg, name, "sAMAccountName");
1857 case GROUPINFOATTRIBUTES:
1858 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1860 case GROUPINFODESCRIPTION:
1861 QUERY_STRING(msg, description, "description");
1864 QUERY_STRING(msg, all2.name, "sAMAccountName");
1865 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1866 QUERY_UINT (msg, all2.num_members, "numMembers")
1867 QUERY_STRING(msg, all2.description, "description");
1871 return NT_STATUS_INVALID_INFO_CLASS;
1874 *r->out.info = info;
1876 return NT_STATUS_OK;
1883 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1884 struct samr_SetGroupInfo *r)
1886 struct dcesrv_handle *h;
1887 struct samr_account_state *g_state;
1888 struct ldb_message *msg;
1891 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1895 msg = ldb_msg_new(mem_ctx);
1897 return NT_STATUS_NO_MEMORY;
1900 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1902 return NT_STATUS_NO_MEMORY;
1905 switch (r->in.level) {
1906 case GROUPINFODESCRIPTION:
1907 SET_STRING(msg, description, "description");
1910 /* On W2k3 this does not change the name, it changes the
1911 * sAMAccountName attribute */
1912 SET_STRING(msg, name, "sAMAccountName");
1914 case GROUPINFOATTRIBUTES:
1915 /* This does not do anything obviously visible in W2k3 LDAP */
1916 return NT_STATUS_OK;
1918 return NT_STATUS_INVALID_INFO_CLASS;
1921 /* modify the samdb record */
1922 ret = ldb_modify(g_state->sam_ctx, msg);
1923 if (ret != LDB_SUCCESS) {
1924 return dsdb_ldb_err_to_ntstatus(ret);
1927 return NT_STATUS_OK;
1934 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1935 struct samr_AddGroupMember *r)
1937 struct dcesrv_handle *h;
1938 struct samr_account_state *a_state;
1939 struct samr_domain_state *d_state;
1940 struct ldb_message *mod;
1941 struct dom_sid *membersid;
1942 const char *memberdn;
1943 struct ldb_result *res;
1944 const char * const attrs[] = { NULL };
1947 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1950 d_state = a_state->domain_state;
1952 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1953 if (membersid == NULL) {
1954 return NT_STATUS_NO_MEMORY;
1957 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1958 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1959 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1961 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1963 if (ret != LDB_SUCCESS) {
1964 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1967 if (res->count == 0) {
1968 return NT_STATUS_NO_SUCH_USER;
1971 if (res->count > 1) {
1972 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1975 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1977 if (memberdn == NULL)
1978 return NT_STATUS_NO_MEMORY;
1980 mod = ldb_msg_new(mem_ctx);
1982 return NT_STATUS_NO_MEMORY;
1985 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1987 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1989 if (ret != LDB_SUCCESS) {
1990 return dsdb_ldb_err_to_ntstatus(ret);
1993 ret = ldb_modify(a_state->sam_ctx, mod);
1996 return NT_STATUS_OK;
1997 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1998 return NT_STATUS_MEMBER_IN_GROUP;
1999 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2000 return NT_STATUS_ACCESS_DENIED;
2002 return dsdb_ldb_err_to_ntstatus(ret);
2008 samr_DeleteDomainGroup
2010 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2011 struct samr_DeleteDomainGroup *r)
2013 struct dcesrv_handle *h;
2014 struct samr_account_state *a_state;
2017 *r->out.group_handle = *r->in.group_handle;
2019 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2023 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2024 if (ret != LDB_SUCCESS) {
2025 return dsdb_ldb_err_to_ntstatus(ret);
2029 ZERO_STRUCTP(r->out.group_handle);
2031 return NT_STATUS_OK;
2036 samr_DeleteGroupMember
2038 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2039 struct samr_DeleteGroupMember *r)
2041 struct dcesrv_handle *h;
2042 struct samr_account_state *a_state;
2043 struct samr_domain_state *d_state;
2044 struct ldb_message *mod;
2045 struct dom_sid *membersid;
2046 const char *memberdn;
2047 struct ldb_result *res;
2048 const char * const attrs[] = { NULL };
2051 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2054 d_state = a_state->domain_state;
2056 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2057 if (membersid == NULL) {
2058 return NT_STATUS_NO_MEMORY;
2061 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2062 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2063 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2065 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2067 if (ret != LDB_SUCCESS) {
2068 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2071 if (res->count == 0) {
2072 return NT_STATUS_NO_SUCH_USER;
2075 if (res->count > 1) {
2076 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2079 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2081 if (memberdn == NULL)
2082 return NT_STATUS_NO_MEMORY;
2084 mod = ldb_msg_new(mem_ctx);
2086 return NT_STATUS_NO_MEMORY;
2089 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2091 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2093 if (ret != LDB_SUCCESS) {
2094 return NT_STATUS_NO_MEMORY;
2097 ret = ldb_modify(a_state->sam_ctx, mod);
2100 return NT_STATUS_OK;
2101 case LDB_ERR_UNWILLING_TO_PERFORM:
2102 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2103 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2104 return NT_STATUS_ACCESS_DENIED;
2106 return dsdb_ldb_err_to_ntstatus(ret);
2112 samr_QueryGroupMember
2114 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2115 struct samr_QueryGroupMember *r)
2117 struct dcesrv_handle *h;
2118 struct samr_account_state *a_state;
2119 struct samr_domain_state *d_state;
2120 struct samr_RidAttrArray *array;
2121 unsigned int i, num_members;
2122 struct dom_sid *members;
2125 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2128 d_state = a_state->domain_state;
2130 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2131 a_state->account_dn, &members,
2133 if (!NT_STATUS_IS_OK(status)) {
2137 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2138 if (array == NULL) {
2139 return NT_STATUS_NO_MEMORY;
2142 if (num_members == 0) {
2143 *r->out.rids = array;
2145 return NT_STATUS_OK;
2148 array->rids = talloc_array(array, uint32_t, num_members);
2149 if (array->rids == NULL) {
2150 return NT_STATUS_NO_MEMORY;
2153 array->attributes = talloc_array(array, uint32_t, num_members);
2154 if (array->attributes == NULL) {
2155 return NT_STATUS_NO_MEMORY;
2159 for (i=0; i<num_members; i++) {
2160 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2164 status = dom_sid_split_rid(NULL, &members[i], NULL,
2165 &array->rids[array->count]);
2166 if (!NT_STATUS_IS_OK(status)) {
2170 array->attributes[array->count] = SE_GROUP_MANDATORY |
2171 SE_GROUP_ENABLED_BY_DEFAULT |
2176 *r->out.rids = array;
2178 return NT_STATUS_OK;
2183 samr_SetMemberAttributesOfGroup
2185 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2186 struct samr_SetMemberAttributesOfGroup *r)
2188 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2195 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2196 struct samr_OpenAlias *r)
2198 struct samr_domain_state *d_state;
2199 struct samr_account_state *a_state;
2200 struct dcesrv_handle *h;
2201 const char *alias_name;
2202 struct dom_sid *sid;
2203 struct ldb_message **msgs;
2204 struct dcesrv_handle *g_handle;
2205 const char * const attrs[2] = { "sAMAccountName", NULL };
2208 ZERO_STRUCTP(r->out.alias_handle);
2210 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2214 /* form the alias SID */
2215 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2217 return NT_STATUS_NO_MEMORY;
2219 /* search for the group record */
2220 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2221 "(&(objectSid=%s)(objectclass=group)"
2222 "(|(grouptype=%d)(grouptype=%d)))",
2223 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2224 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2225 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2227 return NT_STATUS_NO_SUCH_ALIAS;
2230 DEBUG(0,("Found %d records matching sid %s\n",
2231 ret, dom_sid_string(mem_ctx, sid)));
2232 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2235 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2236 if (alias_name == NULL) {
2237 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2238 dom_sid_string(mem_ctx, sid)));
2239 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2242 a_state = talloc(mem_ctx, struct samr_account_state);
2244 return NT_STATUS_NO_MEMORY;
2246 a_state->sam_ctx = d_state->sam_ctx;
2247 a_state->access_mask = r->in.access_mask;
2248 a_state->domain_state = talloc_reference(a_state, d_state);
2249 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2250 a_state->account_sid = talloc_steal(a_state, sid);
2251 a_state->account_name = talloc_strdup(a_state, alias_name);
2252 if (!a_state->account_name) {
2253 return NT_STATUS_NO_MEMORY;
2256 /* create the policy handle */
2257 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2259 return NT_STATUS_NO_MEMORY;
2262 g_handle->data = talloc_steal(g_handle, a_state);
2264 *r->out.alias_handle = g_handle->wire_handle;
2266 return NT_STATUS_OK;
2273 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2274 struct samr_QueryAliasInfo *r)
2276 struct dcesrv_handle *h;
2277 struct samr_account_state *a_state;
2278 struct ldb_message *msg, **res;
2279 const char * const attrs[4] = { "sAMAccountName", "description",
2280 "numMembers", NULL };
2282 union samr_AliasInfo *info;
2284 *r->out.info = NULL;
2286 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2290 /* pull all the alias attributes */
2291 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2292 a_state->account_dn, &res, attrs);
2294 return NT_STATUS_NO_SUCH_ALIAS;
2297 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2301 /* allocate the info structure */
2302 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2304 return NT_STATUS_NO_MEMORY;
2307 switch(r->in.level) {
2309 QUERY_STRING(msg, all.name, "sAMAccountName");
2310 QUERY_UINT (msg, all.num_members, "numMembers");
2311 QUERY_STRING(msg, all.description, "description");
2314 QUERY_STRING(msg, name, "sAMAccountName");
2316 case ALIASINFODESCRIPTION:
2317 QUERY_STRING(msg, description, "description");
2321 return NT_STATUS_INVALID_INFO_CLASS;
2324 *r->out.info = info;
2326 return NT_STATUS_OK;
2333 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2334 struct samr_SetAliasInfo *r)
2336 struct dcesrv_handle *h;
2337 struct samr_account_state *a_state;
2338 struct ldb_message *msg;
2341 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2345 msg = ldb_msg_new(mem_ctx);
2347 return NT_STATUS_NO_MEMORY;
2350 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2352 return NT_STATUS_NO_MEMORY;
2355 switch (r->in.level) {
2356 case ALIASINFODESCRIPTION:
2357 SET_STRING(msg, description, "description");
2360 /* On W2k3 this does not change the name, it changes the
2361 * sAMAccountName attribute */
2362 SET_STRING(msg, name, "sAMAccountName");
2365 return NT_STATUS_INVALID_INFO_CLASS;
2368 /* modify the samdb record */
2369 ret = ldb_modify(a_state->sam_ctx, msg);
2370 if (ret != LDB_SUCCESS) {
2371 return dsdb_ldb_err_to_ntstatus(ret);
2374 return NT_STATUS_OK;
2381 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2382 struct samr_DeleteDomAlias *r)
2384 struct dcesrv_handle *h;
2385 struct samr_account_state *a_state;
2388 *r->out.alias_handle = *r->in.alias_handle;
2390 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2394 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2395 if (ret != LDB_SUCCESS) {
2396 return dsdb_ldb_err_to_ntstatus(ret);
2400 ZERO_STRUCTP(r->out.alias_handle);
2402 return NT_STATUS_OK;
2409 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2410 struct samr_AddAliasMember *r)
2412 struct dcesrv_handle *h;
2413 struct samr_account_state *a_state;
2414 struct samr_domain_state *d_state;
2415 struct ldb_message *mod;
2416 struct ldb_message **msgs;
2417 const char * const attrs[] = { NULL };
2418 struct ldb_dn *memberdn = NULL;
2422 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2425 d_state = a_state->domain_state;
2427 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2428 &msgs, attrs, "(objectsid=%s)",
2429 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2432 memberdn = msgs[0]->dn;
2433 } else if (ret == 0) {
2434 status = samdb_create_foreign_security_principal(
2435 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2436 if (!NT_STATUS_IS_OK(status)) {
2440 DEBUG(0,("Found %d records matching sid %s\n",
2441 ret, dom_sid_string(mem_ctx, r->in.sid)));
2442 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2445 if (memberdn == NULL) {
2446 DEBUG(0, ("Could not find memberdn\n"));
2447 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2450 mod = ldb_msg_new(mem_ctx);
2452 return NT_STATUS_NO_MEMORY;
2455 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2457 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2458 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2459 if (ret != LDB_SUCCESS) {
2460 return dsdb_ldb_err_to_ntstatus(ret);
2463 ret = ldb_modify(a_state->sam_ctx, mod);
2466 return NT_STATUS_OK;
2467 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2468 return NT_STATUS_MEMBER_IN_GROUP;
2469 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2470 return NT_STATUS_ACCESS_DENIED;
2472 return dsdb_ldb_err_to_ntstatus(ret);
2478 samr_DeleteAliasMember
2480 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2481 struct samr_DeleteAliasMember *r)
2483 struct dcesrv_handle *h;
2484 struct samr_account_state *a_state;
2485 struct samr_domain_state *d_state;
2486 struct ldb_message *mod;
2487 const char *memberdn;
2490 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2493 d_state = a_state->domain_state;
2495 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2496 "distinguishedName", "(objectSid=%s)",
2497 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2498 if (memberdn == NULL) {
2499 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2502 mod = ldb_msg_new(mem_ctx);
2504 return NT_STATUS_NO_MEMORY;
2507 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2509 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2511 if (ret != LDB_SUCCESS) {
2512 return dsdb_ldb_err_to_ntstatus(ret);
2515 ret = ldb_modify(a_state->sam_ctx, mod);
2518 return NT_STATUS_OK;
2519 case LDB_ERR_UNWILLING_TO_PERFORM:
2520 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2521 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2522 return NT_STATUS_ACCESS_DENIED;
2524 return dsdb_ldb_err_to_ntstatus(ret);
2530 samr_GetMembersInAlias
2532 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2533 struct samr_GetMembersInAlias *r)
2535 struct dcesrv_handle *h;
2536 struct samr_account_state *a_state;
2537 struct samr_domain_state *d_state;
2538 struct lsa_SidPtr *array;
2539 unsigned int i, num_members;
2540 struct dom_sid *members;
2543 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2546 d_state = a_state->domain_state;
2548 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2549 a_state->account_dn, &members,
2551 if (!NT_STATUS_IS_OK(status)) {
2555 if (num_members == 0) {
2556 r->out.sids->sids = NULL;
2558 return NT_STATUS_OK;
2561 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2562 if (array == NULL) {
2563 return NT_STATUS_NO_MEMORY;
2566 for (i=0; i<num_members; i++) {
2567 array[i].sid = &members[i];
2570 r->out.sids->num_sids = num_members;
2571 r->out.sids->sids = array;
2573 return NT_STATUS_OK;
2579 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2580 struct samr_OpenUser *r)
2582 struct samr_domain_state *d_state;
2583 struct samr_account_state *a_state;
2584 struct dcesrv_handle *h;
2585 const char *account_name;
2586 struct dom_sid *sid;
2587 struct ldb_message **msgs;
2588 struct dcesrv_handle *u_handle;
2589 const char * const attrs[2] = { "sAMAccountName", NULL };
2592 ZERO_STRUCTP(r->out.user_handle);
2594 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2598 /* form the users SID */
2599 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2601 return NT_STATUS_NO_MEMORY;
2604 /* search for the user record */
2605 ret = gendb_search(d_state->sam_ctx,
2606 mem_ctx, d_state->domain_dn, &msgs, attrs,
2607 "(&(objectSid=%s)(objectclass=user))",
2608 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2610 return NT_STATUS_NO_SUCH_USER;
2613 DEBUG(0,("Found %d records matching sid %s\n", ret,
2614 dom_sid_string(mem_ctx, sid)));
2615 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2618 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2619 if (account_name == NULL) {
2620 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2621 dom_sid_string(mem_ctx, sid)));
2622 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2625 a_state = talloc(mem_ctx, struct samr_account_state);
2627 return NT_STATUS_NO_MEMORY;
2629 a_state->sam_ctx = d_state->sam_ctx;
2630 a_state->access_mask = r->in.access_mask;
2631 a_state->domain_state = talloc_reference(a_state, d_state);
2632 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2633 a_state->account_sid = talloc_steal(a_state, sid);
2634 a_state->account_name = talloc_strdup(a_state, account_name);
2635 if (!a_state->account_name) {
2636 return NT_STATUS_NO_MEMORY;
2639 /* create the policy handle */
2640 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2642 return NT_STATUS_NO_MEMORY;
2645 u_handle->data = talloc_steal(u_handle, a_state);
2647 *r->out.user_handle = u_handle->wire_handle;
2649 return NT_STATUS_OK;
2657 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2658 struct samr_DeleteUser *r)
2660 struct dcesrv_handle *h;
2661 struct samr_account_state *a_state;
2664 *r->out.user_handle = *r->in.user_handle;
2666 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2670 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2671 if (ret != LDB_SUCCESS) {
2672 DEBUG(1, ("Failed to delete user: %s: %s\n",
2673 ldb_dn_get_linearized(a_state->account_dn),
2674 ldb_errstring(a_state->sam_ctx)));
2675 return dsdb_ldb_err_to_ntstatus(ret);
2679 ZERO_STRUCTP(r->out.user_handle);
2681 return NT_STATUS_OK;
2688 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2689 struct samr_QueryUserInfo *r)
2691 struct dcesrv_handle *h;
2692 struct samr_account_state *a_state;
2693 struct ldb_message *msg, **res;
2695 struct ldb_context *sam_ctx;
2697 const char * const *attrs = NULL;
2698 union samr_UserInfo *info;
2702 *r->out.info = NULL;
2704 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2707 sam_ctx = a_state->sam_ctx;
2709 /* fill in the reply */
2710 switch (r->in.level) {
2713 static const char * const attrs2[] = {"sAMAccountName",
2724 static const char * const attrs2[] = {"comment",
2733 static const char * const attrs2[] = {"sAMAccountName",
2749 "userAccountControl",
2750 "msDS-User-Account-Control-Computed",
2757 static const char * const attrs2[] = {"logonHours",
2764 static const char * const attrs2[] = {"sAMAccountName",
2782 "userAccountControl",
2783 "msDS-User-Account-Control-Computed",
2790 static const char * const attrs2[] = {"sAMAccountName",
2798 static const char * const attrs2[] = {"sAMAccountName",
2805 static const char * const attrs2[] = {"displayName",
2812 static const char * const attrs2[] = {"primaryGroupID",
2819 static const char * const attrs2[] = {"homeDirectory",
2827 static const char * const attrs2[] = {"scriptPath",
2834 static const char * const attrs2[] = {"profilePath",
2841 static const char * const attrs2[] = {"description",
2848 static const char * const attrs2[] = {"userWorkstations",
2855 static const char * const attrs2[] = {"userAccountControl",
2856 "msDS-User-Account-Control-Computed",
2864 static const char * const attrs2[] = {"accountExpires",
2871 return NT_STATUS_NOT_SUPPORTED;
2875 static const char * const attrs2[] = {"userParameters",
2882 static const char * const attrs2[] = {"lastLogon",
2898 "userAccountControl",
2899 "msDS-User-Account-Control-Computed",
2915 return NT_STATUS_NOT_SUPPORTED;
2919 return NT_STATUS_INVALID_INFO_CLASS;
2923 /* pull all the user attributes */
2924 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2925 a_state->account_dn, &res, attrs);
2927 return NT_STATUS_NO_SUCH_USER;
2930 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2934 /* allocate the info structure */
2935 info = talloc_zero(mem_ctx, union samr_UserInfo);
2937 return NT_STATUS_NO_MEMORY;
2940 /* fill in the reply */
2941 switch (r->in.level) {
2943 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2944 QUERY_STRING(msg, info1.full_name, "displayName");
2945 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2946 QUERY_STRING(msg, info1.description, "description");
2947 QUERY_STRING(msg, info1.comment, "comment");
2951 QUERY_STRING(msg, info2.comment, "comment");
2952 QUERY_UINT (msg, info2.country_code, "countryCode");
2953 QUERY_UINT (msg, info2.code_page, "codePage");
2957 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2958 QUERY_STRING(msg, info3.full_name, "displayName");
2959 QUERY_RID (msg, info3.rid, "objectSid");
2960 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2961 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2962 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2963 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2964 QUERY_STRING(msg, info3.profile_path, "profilePath");
2965 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2966 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2967 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2968 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2969 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2970 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2971 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2972 /* level 3 gives the raw badPwdCount value */
2973 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2974 QUERY_UINT (msg, info3.logon_count, "logonCount");
2975 QUERY_AFLAGS(msg, info3.acct_flags, "msDS-User-Account-Control-Computed");
2979 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2983 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2984 QUERY_STRING(msg, info5.full_name, "displayName");
2985 QUERY_RID (msg, info5.rid, "objectSid");
2986 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2987 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2988 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2989 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2990 QUERY_STRING(msg, info5.profile_path, "profilePath");
2991 QUERY_STRING(msg, info5.description, "description");
2992 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2993 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2994 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2995 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2996 QUERY_BPWDCT(msg, info5.bad_password_count, "badPwdCount");
2997 QUERY_UINT (msg, info5.logon_count, "logonCount");
2998 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2999 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3000 QUERY_AFLAGS(msg, info5.acct_flags, "msDS-User-Account-Control-Computed");
3004 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3005 QUERY_STRING(msg, info6.full_name, "displayName");
3009 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3013 QUERY_STRING(msg, info8.full_name, "displayName");
3017 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3021 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3022 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3026 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3030 QUERY_STRING(msg, info12.profile_path, "profilePath");
3034 QUERY_STRING(msg, info13.description, "description");
3038 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3042 QUERY_AFLAGS(msg, info16.acct_flags, "msDS-User-Account-Control-Computed");
3046 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3050 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
3051 if (!NT_STATUS_IS_OK(status)) {
3058 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3059 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3060 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3061 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3062 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3063 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3064 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3065 QUERY_STRING(msg, info21.full_name, "displayName");
3066 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3067 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3068 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3069 QUERY_STRING(msg, info21.profile_path, "profilePath");
3070 QUERY_STRING(msg, info21.description, "description");
3071 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3072 QUERY_STRING(msg, info21.comment, "comment");
3073 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
3074 if (!NT_STATUS_IS_OK(status)) {
3079 QUERY_RID (msg, info21.rid, "objectSid");
3080 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3081 QUERY_AFLAGS(msg, info21.acct_flags, "msDS-User-Account-Control-Computed");
3082 info->info21.fields_present = 0x08FFFFFF;
3083 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3084 QUERY_BPWDCT(msg, info21.bad_password_count, "badPwdCount");
3085 QUERY_UINT (msg, info21.logon_count, "logonCount");
3086 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3087 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3089 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3091 QUERY_UINT (msg, info21.country_code, "countryCode");
3092 QUERY_UINT (msg, info21.code_page, "codePage");
3098 return NT_STATUS_INVALID_INFO_CLASS;
3101 *r->out.info = info;
3103 return NT_STATUS_OK;
3110 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3111 struct samr_SetUserInfo *r)
3113 struct dcesrv_handle *h;
3114 struct samr_account_state *a_state;
3115 struct ldb_message *msg;
3117 NTSTATUS status = NT_STATUS_OK;
3118 struct ldb_context *sam_ctx;
3120 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3123 sam_ctx = a_state->sam_ctx;
3125 msg = ldb_msg_new(mem_ctx);
3127 return NT_STATUS_NO_MEMORY;
3130 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3132 return NT_STATUS_NO_MEMORY;
3135 switch (r->in.level) {
3137 SET_STRING(msg, info2.comment, "comment");
3138 SET_UINT (msg, info2.country_code, "countryCode");
3139 SET_UINT (msg, info2.code_page, "codePage");
3143 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3147 SET_STRING(msg, info6.account_name, "samAccountName");
3148 SET_STRING(msg, info6.full_name, "displayName");
3152 SET_STRING(msg, info7.account_name, "samAccountName");
3156 SET_STRING(msg, info8.full_name, "displayName");
3160 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3164 SET_STRING(msg, info10.home_directory, "homeDirectory");
3165 SET_STRING(msg, info10.home_drive, "homeDrive");
3169 SET_STRING(msg, info11.logon_script, "scriptPath");
3173 SET_STRING(msg, info12.profile_path, "profilePath");
3177 SET_STRING(msg, info13.description, "description");
3181 SET_STRING(msg, info14.workstations, "userWorkstations");
3185 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3189 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3193 status = samr_set_password_buffers(dce_call,
3195 a_state->account_dn,
3196 a_state->domain_state->domain_dn,
3198 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3199 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3200 if (!NT_STATUS_IS_OK(status)) {
3204 if (r->in.info->info18.password_expired > 0) {
3205 struct ldb_message_element *set_el;
3206 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3207 return NT_STATUS_NO_MEMORY;
3209 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3210 set_el->flags = LDB_FLAG_MOD_REPLACE;
3215 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3219 if (r->in.info->info21.fields_present == 0)
3220 return NT_STATUS_INVALID_PARAMETER;
3222 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3223 IFSET(SAMR_FIELD_LAST_LOGON)
3224 SET_UINT64(msg, info21.last_logon, "lastLogon");
3225 IFSET(SAMR_FIELD_LAST_LOGOFF)
3226 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3227 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3228 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3229 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3230 SET_STRING(msg, info21.account_name, "samAccountName");
3231 IFSET(SAMR_FIELD_FULL_NAME)
3232 SET_STRING(msg, info21.full_name, "displayName");
3233 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3234 SET_STRING(msg, info21.home_directory, "homeDirectory");
3235 IFSET(SAMR_FIELD_HOME_DRIVE)
3236 SET_STRING(msg, info21.home_drive, "homeDrive");
3237 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3238 SET_STRING(msg, info21.logon_script, "scriptPath");
3239 IFSET(SAMR_FIELD_PROFILE_PATH)
3240 SET_STRING(msg, info21.profile_path, "profilePath");
3241 IFSET(SAMR_FIELD_DESCRIPTION)
3242 SET_STRING(msg, info21.description, "description");
3243 IFSET(SAMR_FIELD_WORKSTATIONS)
3244 SET_STRING(msg, info21.workstations, "userWorkstations");
3245 IFSET(SAMR_FIELD_COMMENT)
3246 SET_STRING(msg, info21.comment, "comment");
3247 IFSET(SAMR_FIELD_PARAMETERS)
3248 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3249 IFSET(SAMR_FIELD_PRIMARY_GID)
3250 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3251 IFSET(SAMR_FIELD_ACCT_FLAGS)
3252 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3253 IFSET(SAMR_FIELD_LOGON_HOURS)
3254 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3255 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3256 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3257 IFSET(SAMR_FIELD_NUM_LOGONS)
3258 SET_UINT (msg, info21.logon_count, "logonCount");
3259 IFSET(SAMR_FIELD_COUNTRY_CODE)
3260 SET_UINT (msg, info21.country_code, "countryCode");
3261 IFSET(SAMR_FIELD_CODE_PAGE)
3262 SET_UINT (msg, info21.code_page, "codePage");
3264 /* password change fields */
3265 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3266 return NT_STATUS_ACCESS_DENIED;
3268 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3269 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3270 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3272 if (r->in.info->info21.lm_password_set) {
3273 if ((r->in.info->info21.lm_owf_password.length != 16)
3274 || (r->in.info->info21.lm_owf_password.size != 16)) {
3275 return NT_STATUS_INVALID_PARAMETER;
3278 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3280 if (r->in.info->info21.nt_password_set) {
3281 if ((r->in.info->info21.nt_owf_password.length != 16)
3282 || (r->in.info->info21.nt_owf_password.size != 16)) {
3283 return NT_STATUS_INVALID_PARAMETER;
3286 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3288 status = samr_set_password_buffers(dce_call,
3290 a_state->account_dn,
3291 a_state->domain_state->domain_dn,
3295 if (!NT_STATUS_IS_OK(status)) {
3301 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3303 struct ldb_message_element *set_el;
3304 if (r->in.info->info21.password_expired
3305 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3306 unix_to_nt_time(&t, time(NULL));
3308 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3309 "pwdLastSet", t) != LDB_SUCCESS) {
3310 return NT_STATUS_NO_MEMORY;
3312 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3313 set_el->flags = LDB_FLAG_MOD_REPLACE;
3319 if (r->in.info->info23.info.fields_present == 0)
3320 return NT_STATUS_INVALID_PARAMETER;
3322 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3323 IFSET(SAMR_FIELD_LAST_LOGON)
3324 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3325 IFSET(SAMR_FIELD_LAST_LOGOFF)
3326 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3327 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3328 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3329 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3330 SET_STRING(msg, info23.info.account_name, "samAccountName");
3331 IFSET(SAMR_FIELD_FULL_NAME)
3332 SET_STRING(msg, info23.info.full_name, "displayName");
3333 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3334 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3335 IFSET(SAMR_FIELD_HOME_DRIVE)
3336 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3337 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3338 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3339 IFSET(SAMR_FIELD_PROFILE_PATH)
3340 SET_STRING(msg, info23.info.profile_path, "profilePath");
3341 IFSET(SAMR_FIELD_DESCRIPTION)
3342 SET_STRING(msg, info23.info.description, "description");
3343 IFSET(SAMR_FIELD_WORKSTATIONS)
3344 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3345 IFSET(SAMR_FIELD_COMMENT)
3346 SET_STRING(msg, info23.info.comment, "comment");
3347 IFSET(SAMR_FIELD_PARAMETERS)
3348 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3349 IFSET(SAMR_FIELD_PRIMARY_GID)
3350 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3351 IFSET(SAMR_FIELD_ACCT_FLAGS)
3352 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3353 IFSET(SAMR_FIELD_LOGON_HOURS)
3354 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3355 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3356 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3357 IFSET(SAMR_FIELD_NUM_LOGONS)
3358 SET_UINT (msg, info23.info.logon_count, "logonCount");
3360 IFSET(SAMR_FIELD_COUNTRY_CODE)
3361 SET_UINT (msg, info23.info.country_code, "countryCode");
3362 IFSET(SAMR_FIELD_CODE_PAGE)
3363 SET_UINT (msg, info23.info.code_page, "codePage");
3365 /* password change fields */
3366 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3367 return NT_STATUS_ACCESS_DENIED;
3369 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3370 status = samr_set_password(dce_call,
3372 a_state->account_dn,
3373 a_state->domain_state->domain_dn,
3375 &r->in.info->info23.password);
3376 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3377 status = samr_set_password(dce_call,
3379 a_state->account_dn,
3380 a_state->domain_state->domain_dn,
3382 &r->in.info->info23.password);
3384 if (!NT_STATUS_IS_OK(status)) {
3388 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3390 struct ldb_message_element *set_el;
3391 if (r->in.info->info23.info.password_expired
3392 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3393 unix_to_nt_time(&t, time(NULL));
3395 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3396 "pwdLastSet", t) != LDB_SUCCESS) {
3397 return NT_STATUS_NO_MEMORY;
3399 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3400 set_el->flags = LDB_FLAG_MOD_REPLACE;
3405 /* the set password levels are handled separately */
3407 status = samr_set_password(dce_call,
3409 a_state->account_dn,
3410 a_state->domain_state->domain_dn,
3412 &r->in.info->info24.password);
3413 if (!NT_STATUS_IS_OK(status)) {
3417 if (r->in.info->info24.password_expired > 0) {
3418 struct ldb_message_element *set_el;
3419 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3420 return NT_STATUS_NO_MEMORY;
3422 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3423 set_el->flags = LDB_FLAG_MOD_REPLACE;
3428 if (r->in.info->info25.info.fields_present == 0)
3429 return NT_STATUS_INVALID_PARAMETER;
3431 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3432 IFSET(SAMR_FIELD_LAST_LOGON)
3433 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3434 IFSET(SAMR_FIELD_LAST_LOGOFF)
3435 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3436 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3437 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3438 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3439 SET_STRING(msg, info25.info.account_name, "samAccountName");
3440 IFSET(SAMR_FIELD_FULL_NAME)
3441 SET_STRING(msg, info25.info.full_name, "displayName");
3442 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3443 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3444 IFSET(SAMR_FIELD_HOME_DRIVE)
3445 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3446 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3447 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3448 IFSET(SAMR_FIELD_PROFILE_PATH)
3449 SET_STRING(msg, info25.info.profile_path, "profilePath");
3450 IFSET(SAMR_FIELD_DESCRIPTION)
3451 SET_STRING(msg, info25.info.description, "description");
3452 IFSET(SAMR_FIELD_WORKSTATIONS)
3453 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3454 IFSET(SAMR_FIELD_COMMENT)
3455 SET_STRING(msg, info25.info.comment, "comment");
3456 IFSET(SAMR_FIELD_PARAMETERS)
3457 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3458 IFSET(SAMR_FIELD_PRIMARY_GID)
3459 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3460 IFSET(SAMR_FIELD_ACCT_FLAGS)
3461 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3462 IFSET(SAMR_FIELD_LOGON_HOURS)
3463 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3464 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3465 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3466 IFSET(SAMR_FIELD_NUM_LOGONS)
3467 SET_UINT (msg, info25.info.logon_count, "logonCount");
3468 IFSET(SAMR_FIELD_COUNTRY_CODE)
3469 SET_UINT (msg, info25.info.country_code, "countryCode");
3470 IFSET(SAMR_FIELD_CODE_PAGE)
3471 SET_UINT (msg, info25.info.code_page, "codePage");
3473 /* password change fields */
3474 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3475 return NT_STATUS_ACCESS_DENIED;
3477 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3478 status = samr_set_password_ex(dce_call,
3480 a_state->account_dn,
3481 a_state->domain_state->domain_dn,
3483 &r->in.info->info25.password);
3484 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3485 status = samr_set_password_ex(dce_call,
3487 a_state->account_dn,
3488 a_state->domain_state->domain_dn,
3490 &r->in.info->info25.password);
3492 if (!NT_STATUS_IS_OK(status)) {
3496 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3498 struct ldb_message_element *set_el;
3499 if (r->in.info->info25.info.password_expired
3500 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3501 unix_to_nt_time(&t, time(NULL));
3503 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3504 "pwdLastSet", t) != LDB_SUCCESS) {
3505 return NT_STATUS_NO_MEMORY;
3507 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3508 set_el->flags = LDB_FLAG_MOD_REPLACE;
3513 /* the set password levels are handled separately */
3515 status = samr_set_password_ex(dce_call,
3517 a_state->account_dn,
3518 a_state->domain_state->domain_dn,
3520 &r->in.info->info26.password);
3521 if (!NT_STATUS_IS_OK(status)) {
3525 if (r->in.info->info26.password_expired > 0) {
3527 struct ldb_message_element *set_el;
3528 if (r->in.info->info26.password_expired
3529 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3530 unix_to_nt_time(&t, time(NULL));
3532 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3533 "pwdLastSet", t) != LDB_SUCCESS) {
3534 return NT_STATUS_NO_MEMORY;
3536 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3537 set_el->flags = LDB_FLAG_MOD_REPLACE;
3542 /* many info classes are not valid for SetUserInfo */
3543 return NT_STATUS_INVALID_INFO_CLASS;
3546 if (!NT_STATUS_IS_OK(status)) {
3550 /* modify the samdb record */
3551 if (msg->num_elements > 0) {
3552 ret = ldb_modify(a_state->sam_ctx, msg);
3553 if (ret != LDB_SUCCESS) {
3554 DEBUG(1,("Failed to modify record %s: %s\n",
3555 ldb_dn_get_linearized(a_state->account_dn),
3556 ldb_errstring(a_state->sam_ctx)));
3558 return dsdb_ldb_err_to_ntstatus(ret);
3562 return NT_STATUS_OK;
3567 samr_GetGroupsForUser
3569 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3570 struct samr_GetGroupsForUser *r)
3572 struct dcesrv_handle *h;
3573 struct samr_account_state *a_state;
3574 struct samr_domain_state *d_state;
3575 struct ldb_message **res;
3576 const char * const attrs[2] = { "objectSid", NULL };
3577 struct samr_RidWithAttributeArray *array;
3579 char membersidstr[DOM_SID_STR_BUFLEN];
3581 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3584 d_state = a_state->domain_state;
3586 dom_sid_string_buf(a_state->account_sid,
3587 membersidstr, sizeof(membersidstr)),
3589 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3590 d_state->domain_dn, &res,
3591 attrs, d_state->domain_sid,
3592 "(&(member=<SID=%s>)"
3593 "(|(grouptype=%d)(grouptype=%d))"
3594 "(objectclass=group))",
3596 GTYPE_SECURITY_UNIVERSAL_GROUP,
3597 GTYPE_SECURITY_GLOBAL_GROUP);
3599 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3601 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3603 return NT_STATUS_NO_MEMORY;
3608 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3610 if (array->rids == NULL)
3611 return NT_STATUS_NO_MEMORY;
3613 /* Adds the primary group */
3614 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3615 ~0, a_state->account_dn,
3616 "primaryGroupID", NULL);
3617 array->rids[0].attributes = SE_GROUP_MANDATORY
3618 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3621 /* Adds the additional groups */
3622 for (i = 0; i < count; i++) {
3623 struct dom_sid *group_sid;
3625 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3626 if (group_sid == NULL) {
3627 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3630 array->rids[i + 1].rid =
3631 group_sid->sub_auths[group_sid->num_auths-1];
3632 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3633 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3637 *r->out.rids = array;
3639 return NT_STATUS_OK;
3644 samr_QueryDisplayInfo
3646 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3647 struct samr_QueryDisplayInfo *r)
3649 struct dcesrv_handle *h;
3650 struct samr_domain_state *d_state;
3651 struct ldb_result *res;
3654 const char * const attrs[] = { "objectSid", "sAMAccountName",
3655 "displayName", "description", "userAccountControl",
3656 "pwdLastSet", NULL };
3657 struct samr_DispEntryFull *entriesFull = NULL;
3658 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3659 struct samr_DispEntryAscii *entriesAscii = NULL;
3660 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3664 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3668 switch (r->in.level) {
3671 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3672 "(sAMAccountType=%d))",
3673 ATYPE_NORMAL_ACCOUNT);
3676 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3677 "(sAMAccountType=%d))",
3678 ATYPE_WORKSTATION_TRUST);
3682 filter = talloc_asprintf(mem_ctx,
3683 "(&(|(groupType=%d)(groupType=%d))"
3684 "(objectClass=group))",
3685 GTYPE_SECURITY_UNIVERSAL_GROUP,
3686 GTYPE_SECURITY_GLOBAL_GROUP);
3689 return NT_STATUS_INVALID_INFO_CLASS;
3692 /* search for all requested objects in all domains. This could
3693 possibly be cached and resumed based on resume_key */
3694 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, ldb_get_default_basedn(d_state->sam_ctx),
3695 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3696 if (ret != LDB_SUCCESS) {
3697 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3699 if ((res->count == 0) || (r->in.max_entries == 0)) {
3700 return NT_STATUS_OK;
3703 switch (r->in.level) {
3705 entriesGeneral = talloc_array(mem_ctx,
3706 struct samr_DispEntryGeneral,
3710 entriesFull = talloc_array(mem_ctx,
3711 struct samr_DispEntryFull,
3715 entriesFullGroup = talloc_array(mem_ctx,
3716 struct samr_DispEntryFullGroup,
3721 entriesAscii = talloc_array(mem_ctx,
3722 struct samr_DispEntryAscii,
3727 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3728 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3729 return NT_STATUS_NO_MEMORY;
3733 for (i = 0; i < res->count; i++) {
3734 struct dom_sid *objectsid;
3736 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3738 if (objectsid == NULL)
3741 switch(r->in.level) {
3743 entriesGeneral[count].idx = count + 1;
3744 entriesGeneral[count].rid =
3745 objectsid->sub_auths[objectsid->num_auths-1];
3746 entriesGeneral[count].acct_flags =
3747 samdb_result_acct_flags(res->msgs[i], NULL);
3748 entriesGeneral[count].account_name.string =
3749 ldb_msg_find_attr_as_string(res->msgs[i],
3750 "sAMAccountName", "");
3751 entriesGeneral[count].full_name.string =
3752 ldb_msg_find_attr_as_string(res->msgs[i],
3754 entriesGeneral[count].description.string =
3755 ldb_msg_find_attr_as_string(res->msgs[i],
3759 entriesFull[count].idx = count + 1;
3760 entriesFull[count].rid =
3761 objectsid->sub_auths[objectsid->num_auths-1];
3763 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3764 entriesFull[count].acct_flags =
3765 samdb_result_acct_flags(res->msgs[i],
3767 entriesFull[count].account_name.string =
3768 ldb_msg_find_attr_as_string(res->msgs[i],
3769 "sAMAccountName", "");
3770 entriesFull[count].description.string =
3771 ldb_msg_find_attr_as_string(res->msgs[i],
3775 entriesFullGroup[count].idx = count + 1;
3776 entriesFullGroup[count].rid =
3777 objectsid->sub_auths[objectsid->num_auths-1];
3778 /* We get a "7" here for groups */
3779 entriesFullGroup[count].acct_flags
3780 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3781 entriesFullGroup[count].account_name.string =
3782 ldb_msg_find_attr_as_string(res->msgs[i],
3783 "sAMAccountName", "");
3784 entriesFullGroup[count].description.string =
3785 ldb_msg_find_attr_as_string(res->msgs[i],
3790 entriesAscii[count].idx = count + 1;
3791 entriesAscii[count].account_name.string =
3792 ldb_msg_find_attr_as_string(res->msgs[i],
3793 "sAMAccountName", "");
3800 *r->out.total_size = count;
3802 if (r->in.start_idx >= count) {
3803 *r->out.returned_size = 0;
3804 switch(r->in.level) {
3806 r->out.info->info1.count = *r->out.returned_size;
3807 r->out.info->info1.entries = NULL;
3810 r->out.info->info2.count = *r->out.returned_size;
3811 r->out.info->info2.entries = NULL;
3814 r->out.info->info3.count = *r->out.returned_size;
3815 r->out.info->info3.entries = NULL;
3818 r->out.info->info4.count = *r->out.returned_size;
3819 r->out.info->info4.entries = NULL;
3822 r->out.info->info5.count = *r->out.returned_size;
3823 r->out.info->info5.entries = NULL;
3827 *r->out.returned_size = MIN(count - r->in.start_idx,
3829 switch(r->in.level) {
3831 r->out.info->info1.count = *r->out.returned_size;
3832 r->out.info->info1.entries =
3833 &(entriesGeneral[r->in.start_idx]);
3836 r->out.info->info2.count = *r->out.returned_size;
3837 r->out.info->info2.entries =
3838 &(entriesFull[r->in.start_idx]);
3841 r->out.info->info3.count = *r->out.returned_size;
3842 r->out.info->info3.entries =
3843 &(entriesFullGroup[r->in.start_idx]);
3846 r->out.info->info4.count = *r->out.returned_size;
3847 r->out.info->info4.entries =
3848 &(entriesAscii[r->in.start_idx]);
3851 r->out.info->info5.count = *r->out.returned_size;
3852 r->out.info->info5.entries =
3853 &(entriesAscii[r->in.start_idx]);
3858 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3859 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3864 samr_GetDisplayEnumerationIndex
3866 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3867 struct samr_GetDisplayEnumerationIndex *r)
3869 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3874 samr_TestPrivateFunctionsDomain
3876 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3877 struct samr_TestPrivateFunctionsDomain *r)
3879 return NT_STATUS_NOT_IMPLEMENTED;
3884 samr_TestPrivateFunctionsUser
3886 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3887 struct samr_TestPrivateFunctionsUser *r)
3889 return NT_STATUS_NOT_IMPLEMENTED;
3896 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3897 struct samr_GetUserPwInfo *r)
3899 struct dcesrv_handle *h;
3900 struct samr_account_state *a_state;
3902 ZERO_STRUCTP(r->out.info);
3904 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3908 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3909 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3911 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3912 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3914 return NT_STATUS_OK;
3919 samr_RemoveMemberFromForeignDomain
3921 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3922 TALLOC_CTX *mem_ctx,
3923 struct samr_RemoveMemberFromForeignDomain *r)
3925 struct dcesrv_handle *h;
3926 struct samr_domain_state *d_state;
3927 const char *memberdn;
3928 struct ldb_message **res;
3929 const char *no_attrs[] = { NULL };
3932 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3936 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3937 "distinguishedName", "(objectSid=%s)",
3938 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3940 if (memberdn == NULL) {
3941 return NT_STATUS_OK;
3944 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3945 d_state->domain_dn, &res, no_attrs,
3946 d_state->domain_sid,
3947 "(&(member=%s)(objectClass=group)"
3948 "(|(groupType=%d)(groupType=%d)))",
3950 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3951 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3954 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3956 for (i=0; i<count; i++) {
3957 struct ldb_message *mod;
3960 mod = ldb_msg_new(mem_ctx);
3962 return NT_STATUS_NO_MEMORY;
3965 mod->dn = res[i]->dn;
3967 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3968 "member", memberdn) != LDB_SUCCESS)
3969 return NT_STATUS_NO_MEMORY;
3971 ret = ldb_modify(d_state->sam_ctx, mod);
3973 if (ret != LDB_SUCCESS) {
3974 return dsdb_ldb_err_to_ntstatus(ret);
3978 return NT_STATUS_OK;
3983 samr_QueryDomainInfo2
3985 just an alias for samr_QueryDomainInfo
3987 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3988 struct samr_QueryDomainInfo2 *r)
3990 struct samr_QueryDomainInfo r1;
3993 ZERO_STRUCT(r1.out);
3994 r1.in.domain_handle = r->in.domain_handle;
3995 r1.in.level = r->in.level;
3996 r1.out.info = r->out.info;
3998 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4007 just an alias for samr_QueryUserInfo
4009 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4010 struct samr_QueryUserInfo2 *r)
4012 struct samr_QueryUserInfo r1;
4015 r1 = (struct samr_QueryUserInfo) {
4016 .in.user_handle = r->in.user_handle,
4017 .in.level = r->in.level,
4018 .out.info = r->out.info
4021 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4028 samr_QueryDisplayInfo2
4030 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4031 struct samr_QueryDisplayInfo2 *r)
4033 struct samr_QueryDisplayInfo q;
4036 q.in.domain_handle = r->in.domain_handle;
4037 q.in.level = r->in.level;
4038 q.in.start_idx = r->in.start_idx;
4039 q.in.max_entries = r->in.max_entries;
4040 q.in.buf_size = r->in.buf_size;
4041 q.out.total_size = r->out.total_size;
4042 q.out.returned_size = r->out.returned_size;
4043 q.out.info = r->out.info;
4045 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4052 samr_GetDisplayEnumerationIndex2
4054 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4055 struct samr_GetDisplayEnumerationIndex2 *r)
4057 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4062 samr_QueryDisplayInfo3
4064 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4065 struct samr_QueryDisplayInfo3 *r)
4067 struct samr_QueryDisplayInfo q;
4070 q.in.domain_handle = r->in.domain_handle;
4071 q.in.level = r->in.level;
4072 q.in.start_idx = r->in.start_idx;
4073 q.in.max_entries = r->in.max_entries;
4074 q.in.buf_size = r->in.buf_size;
4075 q.out.total_size = r->out.total_size;
4076 q.out.returned_size = r->out.returned_size;
4077 q.out.info = r->out.info;
4079 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4086 samr_AddMultipleMembersToAlias
4088 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4089 struct samr_AddMultipleMembersToAlias *r)
4091 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4096 samr_RemoveMultipleMembersFromAlias
4098 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4099 struct samr_RemoveMultipleMembersFromAlias *r)
4101 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4108 this fetches the default password properties for a domain
4110 note that w2k3 completely ignores the domain name in this call, and
4111 always returns the information for the servers primary domain
4113 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4114 struct samr_GetDomPwInfo *r)
4116 struct ldb_message **msgs;
4118 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4119 struct ldb_context *sam_ctx;
4121 ZERO_STRUCTP(r->out.info);
4123 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4124 dce_call->conn->dce_ctx->lp_ctx,
4125 dce_call->conn->auth_state.session_info, 0);
4126 if (sam_ctx == NULL) {
4127 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4130 /* The domain name in this call is ignored */
4131 ret = gendb_search_dn(sam_ctx,
4132 mem_ctx, NULL, &msgs, attrs);
4134 talloc_free(sam_ctx);
4136 return NT_STATUS_NO_SUCH_DOMAIN;
4140 talloc_free(sam_ctx);
4142 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4145 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4147 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4148 "pwdProperties", 1);
4151 talloc_unlink(mem_ctx, sam_ctx);
4153 return NT_STATUS_OK;
4160 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4161 struct samr_Connect2 *r)
4163 struct samr_Connect c;
4165 c.in.system_name = NULL;
4166 c.in.access_mask = r->in.access_mask;
4167 c.out.connect_handle = r->out.connect_handle;
4169 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4176 just an alias for samr_SetUserInfo
4178 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4179 struct samr_SetUserInfo2 *r)
4181 struct samr_SetUserInfo r2;
4183 r2.in.user_handle = r->in.user_handle;
4184 r2.in.level = r->in.level;
4185 r2.in.info = r->in.info;
4187 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4192 samr_SetBootKeyInformation
4194 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4195 struct samr_SetBootKeyInformation *r)
4197 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4202 samr_GetBootKeyInformation
4204 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4205 struct samr_GetBootKeyInformation *r)
4207 /* Windows Server 2008 returns this */
4208 return NT_STATUS_NOT_SUPPORTED;
4215 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4216 struct samr_Connect3 *r)
4218 struct samr_Connect c;
4220 c.in.system_name = NULL;
4221 c.in.access_mask = r->in.access_mask;
4222 c.out.connect_handle = r->out.connect_handle;
4224 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4231 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4232 struct samr_Connect4 *r)
4234 struct samr_Connect c;
4236 c.in.system_name = NULL;
4237 c.in.access_mask = r->in.access_mask;
4238 c.out.connect_handle = r->out.connect_handle;
4240 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4247 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4248 struct samr_Connect5 *r)
4250 struct samr_Connect c;
4253 c.in.system_name = NULL;
4254 c.in.access_mask = r->in.access_mask;
4255 c.out.connect_handle = r->out.connect_handle;
4257 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4259 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4260 r->out.info_out->info1.unknown2 = 0;
4261 *r->out.level_out = r->in.level_in;
4270 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4271 struct samr_RidToSid *r)
4273 struct samr_domain_state *d_state;
4274 struct dcesrv_handle *h;
4276 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4280 /* form the users SID */
4281 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4283 return NT_STATUS_NO_MEMORY;
4286 return NT_STATUS_OK;
4291 samr_SetDsrmPassword
4293 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4294 struct samr_SetDsrmPassword *r)
4296 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4301 samr_ValidatePassword
4303 For now the call checks the password complexity (if active) and the minimum
4304 password length on level 2 and 3. Level 1 is ignored for now.
4306 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4307 TALLOC_CTX *mem_ctx,
4308 struct samr_ValidatePassword *r)
4310 struct samr_GetDomPwInfo r2;
4311 struct samr_PwInfo pwInfo;
4313 enum samr_ValidationStatus res;
4315 enum dcerpc_transport_t transport =
4316 dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
4318 if (transport != NCACN_IP_TCP && transport != NCALRPC) {
4319 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4322 if (dce_call->conn->auth_state.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
4323 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4326 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4328 r2.in.domain_name = NULL;
4329 r2.out.info = &pwInfo;
4330 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4331 if (!NT_STATUS_IS_OK(status)) {
4335 switch (r->in.level) {
4336 case NetValidateAuthentication:
4337 /* we don't support this yet */
4338 return NT_STATUS_NOT_SUPPORTED;
4340 case NetValidatePasswordChange:
4341 password = data_blob_const(r->in.req->req2.password.string,
4342 r->in.req->req2.password.length);
4343 res = samdb_check_password(&password,
4344 pwInfo.password_properties,
4345 pwInfo.min_password_length);
4346 (*r->out.rep)->ctr2.status = res;
4348 case NetValidatePasswordReset:
4349 password = data_blob_const(r->in.req->req3.password.string,
4350 r->in.req->req3.password.length);
4351 res = samdb_check_password(&password,
4352 pwInfo.password_properties,
4353 pwInfo.min_password_length);
4354 (*r->out.rep)->ctr3.status = res;
4357 return NT_STATUS_INVALID_INFO_CLASS;
4361 return NT_STATUS_OK;
4365 /* include the generated boilerplate */
4366 #include "librpc/gen_ndr/ndr_samr_s.c"