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;
1534 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1538 filter = talloc_asprintf(mem_ctx,
1539 "(&(|(grouptype=%d)(grouptype=%d))"
1540 "(objectclass=group)(|",
1541 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1542 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1543 if (filter == NULL) {
1544 return NT_STATUS_NO_MEMORY;
1547 for (i=0; i<r->in.sids->num_sids; i++) {
1548 const char *memberdn;
1550 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1551 "distinguishedName",
1553 ldap_encode_ndr_dom_sid(mem_ctx,
1554 r->in.sids->sids[i].sid));
1555 if (memberdn == NULL) {
1559 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1561 if (filter == NULL) {
1562 return NT_STATUS_NO_MEMORY;
1566 /* Find out if we had at least one valid member SID passed - otherwise
1567 * just skip the search. */
1568 if (strstr(filter, "member") != NULL) {
1569 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1570 &res, attrs, d_state->domain_sid,
1573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1577 r->out.rids->count = 0;
1578 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1579 if (r->out.rids->ids == NULL)
1580 return NT_STATUS_NO_MEMORY;
1582 for (i=0; i<count; i++) {
1583 struct dom_sid *alias_sid;
1585 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1586 if (alias_sid == NULL) {
1587 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1590 r->out.rids->ids[r->out.rids->count] =
1591 alias_sid->sub_auths[alias_sid->num_auths-1];
1592 r->out.rids->count += 1;
1595 return NT_STATUS_OK;
1602 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1603 struct samr_LookupNames *r)
1605 struct dcesrv_handle *h;
1606 struct samr_domain_state *d_state;
1607 uint32_t i, num_mapped;
1608 NTSTATUS status = NT_STATUS_OK;
1609 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1612 ZERO_STRUCTP(r->out.rids);
1613 ZERO_STRUCTP(r->out.types);
1615 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1619 if (r->in.num_names == 0) {
1620 return NT_STATUS_OK;
1623 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1624 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1625 if (!r->out.rids->ids || !r->out.types->ids) {
1626 return NT_STATUS_NO_MEMORY;
1628 r->out.rids->count = r->in.num_names;
1629 r->out.types->count = r->in.num_names;
1633 for (i=0;i<r->in.num_names;i++) {
1634 struct ldb_message **res;
1635 struct dom_sid *sid;
1636 uint32_t atype, rtype;
1638 r->out.rids->ids[i] = 0;
1639 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1641 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1642 "sAMAccountName=%s",
1643 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1645 status = STATUS_SOME_UNMAPPED;
1649 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1651 status = STATUS_SOME_UNMAPPED;
1655 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1657 status = STATUS_SOME_UNMAPPED;
1661 rtype = ds_atype_map(atype);
1663 if (rtype == SID_NAME_UNKNOWN) {
1664 status = STATUS_SOME_UNMAPPED;
1668 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1669 r->out.types->ids[i] = rtype;
1673 if (num_mapped == 0) {
1674 return NT_STATUS_NONE_MAPPED;
1683 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1684 struct samr_LookupRids *r)
1687 struct dcesrv_handle *h;
1688 struct samr_domain_state *d_state;
1690 struct lsa_String *lsa_names;
1691 enum lsa_SidType *ids;
1693 ZERO_STRUCTP(r->out.names);
1694 ZERO_STRUCTP(r->out.types);
1696 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1700 if (r->in.num_rids == 0)
1701 return NT_STATUS_OK;
1703 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1704 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1705 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1707 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1708 return NT_STATUS_NO_MEMORY;
1710 r->out.names->names = lsa_names;
1711 r->out.names->count = r->in.num_rids;
1713 r->out.types->ids = (uint32_t *) ids;
1714 r->out.types->count = r->in.num_rids;
1716 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1717 r->in.num_rids, r->in.rids, names, ids);
1718 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1720 for (i = 0; i < r->in.num_rids; i++) {
1721 lsa_names[i].string = names[i];
1731 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1732 struct samr_OpenGroup *r)
1734 struct samr_domain_state *d_state;
1735 struct samr_account_state *a_state;
1736 struct dcesrv_handle *h;
1737 const char *groupname;
1738 struct dom_sid *sid;
1739 struct ldb_message **msgs;
1740 struct dcesrv_handle *g_handle;
1741 const char * const attrs[2] = { "sAMAccountName", NULL };
1744 ZERO_STRUCTP(r->out.group_handle);
1746 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1750 /* form the group SID */
1751 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1753 return NT_STATUS_NO_MEMORY;
1756 /* search for the group record */
1757 if (d_state->builtin) {
1758 ret = gendb_search(d_state->sam_ctx,
1759 mem_ctx, d_state->domain_dn, &msgs, attrs,
1760 "(&(objectSid=%s)(objectClass=group)"
1762 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1763 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
1765 ret = gendb_search(d_state->sam_ctx,
1766 mem_ctx, d_state->domain_dn, &msgs, attrs,
1767 "(&(objectSid=%s)(objectClass=group)"
1768 "(|(groupType=%d)(groupType=%d)))",
1769 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1770 GTYPE_SECURITY_UNIVERSAL_GROUP,
1771 GTYPE_SECURITY_GLOBAL_GROUP);
1774 return NT_STATUS_NO_SUCH_GROUP;
1777 DEBUG(0,("Found %d records matching sid %s\n",
1778 ret, dom_sid_string(mem_ctx, sid)));
1779 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1782 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1783 if (groupname == NULL) {
1784 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1785 dom_sid_string(mem_ctx, sid)));
1786 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1789 a_state = talloc(mem_ctx, struct samr_account_state);
1791 return NT_STATUS_NO_MEMORY;
1793 a_state->sam_ctx = d_state->sam_ctx;
1794 a_state->access_mask = r->in.access_mask;
1795 a_state->domain_state = talloc_reference(a_state, d_state);
1796 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1797 a_state->account_sid = talloc_steal(a_state, sid);
1798 a_state->account_name = talloc_strdup(a_state, groupname);
1799 if (!a_state->account_name) {
1800 return NT_STATUS_NO_MEMORY;
1803 /* create the policy handle */
1804 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1806 return NT_STATUS_NO_MEMORY;
1809 g_handle->data = talloc_steal(g_handle, a_state);
1811 *r->out.group_handle = g_handle->wire_handle;
1813 return NT_STATUS_OK;
1819 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1820 struct samr_QueryGroupInfo *r)
1822 struct dcesrv_handle *h;
1823 struct samr_account_state *a_state;
1824 struct ldb_message *msg, **res;
1825 const char * const attrs[4] = { "sAMAccountName", "description",
1826 "numMembers", NULL };
1828 union samr_GroupInfo *info;
1830 *r->out.info = NULL;
1832 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1836 /* pull all the group attributes */
1837 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1838 a_state->account_dn, &res, attrs);
1840 return NT_STATUS_NO_SUCH_GROUP;
1843 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1847 /* allocate the info structure */
1848 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1850 return NT_STATUS_NO_MEMORY;
1853 /* Fill in the level */
1854 switch (r->in.level) {
1856 QUERY_STRING(msg, all.name, "sAMAccountName");
1857 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1858 QUERY_UINT (msg, all.num_members, "numMembers")
1859 QUERY_STRING(msg, all.description, "description");
1862 QUERY_STRING(msg, name, "sAMAccountName");
1864 case GROUPINFOATTRIBUTES:
1865 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1867 case GROUPINFODESCRIPTION:
1868 QUERY_STRING(msg, description, "description");
1871 QUERY_STRING(msg, all2.name, "sAMAccountName");
1872 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1873 QUERY_UINT (msg, all2.num_members, "numMembers")
1874 QUERY_STRING(msg, all2.description, "description");
1878 return NT_STATUS_INVALID_INFO_CLASS;
1881 *r->out.info = info;
1883 return NT_STATUS_OK;
1890 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1891 struct samr_SetGroupInfo *r)
1893 struct dcesrv_handle *h;
1894 struct samr_account_state *g_state;
1895 struct ldb_message *msg;
1898 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1902 msg = ldb_msg_new(mem_ctx);
1904 return NT_STATUS_NO_MEMORY;
1907 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1909 return NT_STATUS_NO_MEMORY;
1912 switch (r->in.level) {
1913 case GROUPINFODESCRIPTION:
1914 SET_STRING(msg, description, "description");
1917 /* On W2k3 this does not change the name, it changes the
1918 * sAMAccountName attribute */
1919 SET_STRING(msg, name, "sAMAccountName");
1921 case GROUPINFOATTRIBUTES:
1922 /* This does not do anything obviously visible in W2k3 LDAP */
1923 return NT_STATUS_OK;
1925 return NT_STATUS_INVALID_INFO_CLASS;
1928 /* modify the samdb record */
1929 ret = ldb_modify(g_state->sam_ctx, msg);
1930 if (ret != LDB_SUCCESS) {
1931 return dsdb_ldb_err_to_ntstatus(ret);
1934 return NT_STATUS_OK;
1941 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1942 struct samr_AddGroupMember *r)
1944 struct dcesrv_handle *h;
1945 struct samr_account_state *a_state;
1946 struct samr_domain_state *d_state;
1947 struct ldb_message *mod;
1948 struct dom_sid *membersid;
1949 const char *memberdn;
1950 struct ldb_result *res;
1951 const char * const attrs[] = { NULL };
1954 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1957 d_state = a_state->domain_state;
1959 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1960 if (membersid == NULL) {
1961 return NT_STATUS_NO_MEMORY;
1964 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1965 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1966 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1968 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1970 if (ret != LDB_SUCCESS) {
1971 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1974 if (res->count == 0) {
1975 return NT_STATUS_NO_SUCH_USER;
1978 if (res->count > 1) {
1979 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1982 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1984 if (memberdn == NULL)
1985 return NT_STATUS_NO_MEMORY;
1987 mod = ldb_msg_new(mem_ctx);
1989 return NT_STATUS_NO_MEMORY;
1992 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1994 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1996 if (ret != LDB_SUCCESS) {
1997 return dsdb_ldb_err_to_ntstatus(ret);
2000 ret = ldb_modify(a_state->sam_ctx, mod);
2003 return NT_STATUS_OK;
2004 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2005 return NT_STATUS_MEMBER_IN_GROUP;
2006 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2007 return NT_STATUS_ACCESS_DENIED;
2009 return dsdb_ldb_err_to_ntstatus(ret);
2015 samr_DeleteDomainGroup
2017 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2018 struct samr_DeleteDomainGroup *r)
2020 struct dcesrv_handle *h;
2021 struct samr_account_state *a_state;
2024 *r->out.group_handle = *r->in.group_handle;
2026 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2030 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2031 if (ret != LDB_SUCCESS) {
2032 return dsdb_ldb_err_to_ntstatus(ret);
2036 ZERO_STRUCTP(r->out.group_handle);
2038 return NT_STATUS_OK;
2043 samr_DeleteGroupMember
2045 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2046 struct samr_DeleteGroupMember *r)
2048 struct dcesrv_handle *h;
2049 struct samr_account_state *a_state;
2050 struct samr_domain_state *d_state;
2051 struct ldb_message *mod;
2052 struct dom_sid *membersid;
2053 const char *memberdn;
2054 struct ldb_result *res;
2055 const char * const attrs[] = { NULL };
2058 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2061 d_state = a_state->domain_state;
2063 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2064 if (membersid == NULL) {
2065 return NT_STATUS_NO_MEMORY;
2068 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2069 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2070 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2072 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2074 if (ret != LDB_SUCCESS) {
2075 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2078 if (res->count == 0) {
2079 return NT_STATUS_NO_SUCH_USER;
2082 if (res->count > 1) {
2083 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2086 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2088 if (memberdn == NULL)
2089 return NT_STATUS_NO_MEMORY;
2091 mod = ldb_msg_new(mem_ctx);
2093 return NT_STATUS_NO_MEMORY;
2096 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2098 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2100 if (ret != LDB_SUCCESS) {
2101 return NT_STATUS_NO_MEMORY;
2104 ret = ldb_modify(a_state->sam_ctx, mod);
2107 return NT_STATUS_OK;
2108 case LDB_ERR_UNWILLING_TO_PERFORM:
2109 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2110 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2111 return NT_STATUS_ACCESS_DENIED;
2113 return dsdb_ldb_err_to_ntstatus(ret);
2119 samr_QueryGroupMember
2121 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2122 struct samr_QueryGroupMember *r)
2124 struct dcesrv_handle *h;
2125 struct samr_account_state *a_state;
2126 struct samr_domain_state *d_state;
2127 struct samr_RidAttrArray *array;
2128 unsigned int i, num_members;
2129 struct dom_sid *members;
2132 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2135 d_state = a_state->domain_state;
2137 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2138 a_state->account_dn, &members,
2140 if (!NT_STATUS_IS_OK(status)) {
2144 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2145 if (array == NULL) {
2146 return NT_STATUS_NO_MEMORY;
2149 if (num_members == 0) {
2150 *r->out.rids = array;
2152 return NT_STATUS_OK;
2155 array->rids = talloc_array(array, uint32_t, num_members);
2156 if (array->rids == NULL) {
2157 return NT_STATUS_NO_MEMORY;
2160 array->attributes = talloc_array(array, uint32_t, num_members);
2161 if (array->attributes == NULL) {
2162 return NT_STATUS_NO_MEMORY;
2166 for (i=0; i<num_members; i++) {
2167 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2171 status = dom_sid_split_rid(NULL, &members[i], NULL,
2172 &array->rids[array->count]);
2173 if (!NT_STATUS_IS_OK(status)) {
2177 array->attributes[array->count] = SE_GROUP_MANDATORY |
2178 SE_GROUP_ENABLED_BY_DEFAULT |
2183 *r->out.rids = array;
2185 return NT_STATUS_OK;
2190 samr_SetMemberAttributesOfGroup
2192 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2193 struct samr_SetMemberAttributesOfGroup *r)
2195 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2202 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2203 struct samr_OpenAlias *r)
2205 struct samr_domain_state *d_state;
2206 struct samr_account_state *a_state;
2207 struct dcesrv_handle *h;
2208 const char *alias_name;
2209 struct dom_sid *sid;
2210 struct ldb_message **msgs;
2211 struct dcesrv_handle *g_handle;
2212 const char * const attrs[2] = { "sAMAccountName", NULL };
2215 ZERO_STRUCTP(r->out.alias_handle);
2217 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2221 /* form the alias SID */
2222 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2224 return NT_STATUS_NO_MEMORY;
2226 /* search for the group record */
2227 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2228 "(&(objectSid=%s)(objectclass=group)"
2229 "(|(grouptype=%d)(grouptype=%d)))",
2230 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2231 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2232 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2234 return NT_STATUS_NO_SUCH_ALIAS;
2237 DEBUG(0,("Found %d records matching sid %s\n",
2238 ret, dom_sid_string(mem_ctx, sid)));
2239 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2242 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2243 if (alias_name == NULL) {
2244 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2245 dom_sid_string(mem_ctx, sid)));
2246 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2249 a_state = talloc(mem_ctx, struct samr_account_state);
2251 return NT_STATUS_NO_MEMORY;
2253 a_state->sam_ctx = d_state->sam_ctx;
2254 a_state->access_mask = r->in.access_mask;
2255 a_state->domain_state = talloc_reference(a_state, d_state);
2256 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2257 a_state->account_sid = talloc_steal(a_state, sid);
2258 a_state->account_name = talloc_strdup(a_state, alias_name);
2259 if (!a_state->account_name) {
2260 return NT_STATUS_NO_MEMORY;
2263 /* create the policy handle */
2264 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2266 return NT_STATUS_NO_MEMORY;
2269 g_handle->data = talloc_steal(g_handle, a_state);
2271 *r->out.alias_handle = g_handle->wire_handle;
2273 return NT_STATUS_OK;
2280 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2281 struct samr_QueryAliasInfo *r)
2283 struct dcesrv_handle *h;
2284 struct samr_account_state *a_state;
2285 struct ldb_message *msg, **res;
2286 const char * const attrs[4] = { "sAMAccountName", "description",
2287 "numMembers", NULL };
2289 union samr_AliasInfo *info;
2291 *r->out.info = NULL;
2293 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2297 /* pull all the alias attributes */
2298 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2299 a_state->account_dn, &res, attrs);
2301 return NT_STATUS_NO_SUCH_ALIAS;
2304 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2308 /* allocate the info structure */
2309 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2311 return NT_STATUS_NO_MEMORY;
2314 switch(r->in.level) {
2316 QUERY_STRING(msg, all.name, "sAMAccountName");
2317 QUERY_UINT (msg, all.num_members, "numMembers");
2318 QUERY_STRING(msg, all.description, "description");
2321 QUERY_STRING(msg, name, "sAMAccountName");
2323 case ALIASINFODESCRIPTION:
2324 QUERY_STRING(msg, description, "description");
2328 return NT_STATUS_INVALID_INFO_CLASS;
2331 *r->out.info = info;
2333 return NT_STATUS_OK;
2340 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2341 struct samr_SetAliasInfo *r)
2343 struct dcesrv_handle *h;
2344 struct samr_account_state *a_state;
2345 struct ldb_message *msg;
2348 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2352 msg = ldb_msg_new(mem_ctx);
2354 return NT_STATUS_NO_MEMORY;
2357 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2359 return NT_STATUS_NO_MEMORY;
2362 switch (r->in.level) {
2363 case ALIASINFODESCRIPTION:
2364 SET_STRING(msg, description, "description");
2367 /* On W2k3 this does not change the name, it changes the
2368 * sAMAccountName attribute */
2369 SET_STRING(msg, name, "sAMAccountName");
2372 return NT_STATUS_INVALID_INFO_CLASS;
2375 /* modify the samdb record */
2376 ret = ldb_modify(a_state->sam_ctx, msg);
2377 if (ret != LDB_SUCCESS) {
2378 return dsdb_ldb_err_to_ntstatus(ret);
2381 return NT_STATUS_OK;
2388 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2389 struct samr_DeleteDomAlias *r)
2391 struct dcesrv_handle *h;
2392 struct samr_account_state *a_state;
2395 *r->out.alias_handle = *r->in.alias_handle;
2397 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2401 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2402 if (ret != LDB_SUCCESS) {
2403 return dsdb_ldb_err_to_ntstatus(ret);
2407 ZERO_STRUCTP(r->out.alias_handle);
2409 return NT_STATUS_OK;
2416 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2417 struct samr_AddAliasMember *r)
2419 struct dcesrv_handle *h;
2420 struct samr_account_state *a_state;
2421 struct samr_domain_state *d_state;
2422 struct ldb_message *mod;
2423 struct ldb_message **msgs;
2424 const char * const attrs[] = { NULL };
2425 struct ldb_dn *memberdn = NULL;
2429 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2432 d_state = a_state->domain_state;
2434 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2435 &msgs, attrs, "(objectsid=%s)",
2436 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2439 memberdn = msgs[0]->dn;
2440 } else if (ret == 0) {
2441 status = samdb_create_foreign_security_principal(
2442 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2443 if (!NT_STATUS_IS_OK(status)) {
2447 DEBUG(0,("Found %d records matching sid %s\n",
2448 ret, dom_sid_string(mem_ctx, r->in.sid)));
2449 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2452 if (memberdn == NULL) {
2453 DEBUG(0, ("Could not find memberdn\n"));
2454 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2457 mod = ldb_msg_new(mem_ctx);
2459 return NT_STATUS_NO_MEMORY;
2462 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2464 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2465 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2466 if (ret != LDB_SUCCESS) {
2467 return dsdb_ldb_err_to_ntstatus(ret);
2470 ret = ldb_modify(a_state->sam_ctx, mod);
2473 return NT_STATUS_OK;
2474 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2475 return NT_STATUS_MEMBER_IN_GROUP;
2476 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2477 return NT_STATUS_ACCESS_DENIED;
2479 return dsdb_ldb_err_to_ntstatus(ret);
2485 samr_DeleteAliasMember
2487 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2488 struct samr_DeleteAliasMember *r)
2490 struct dcesrv_handle *h;
2491 struct samr_account_state *a_state;
2492 struct samr_domain_state *d_state;
2493 struct ldb_message *mod;
2494 const char *memberdn;
2497 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2500 d_state = a_state->domain_state;
2502 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2503 "distinguishedName", "(objectSid=%s)",
2504 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2505 if (memberdn == NULL) {
2506 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2509 mod = ldb_msg_new(mem_ctx);
2511 return NT_STATUS_NO_MEMORY;
2514 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2516 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2518 if (ret != LDB_SUCCESS) {
2519 return dsdb_ldb_err_to_ntstatus(ret);
2522 ret = ldb_modify(a_state->sam_ctx, mod);
2525 return NT_STATUS_OK;
2526 case LDB_ERR_UNWILLING_TO_PERFORM:
2527 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2528 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2529 return NT_STATUS_ACCESS_DENIED;
2531 return dsdb_ldb_err_to_ntstatus(ret);
2537 samr_GetMembersInAlias
2539 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2540 struct samr_GetMembersInAlias *r)
2542 struct dcesrv_handle *h;
2543 struct samr_account_state *a_state;
2544 struct samr_domain_state *d_state;
2545 struct lsa_SidPtr *array;
2546 unsigned int i, num_members;
2547 struct dom_sid *members;
2550 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2553 d_state = a_state->domain_state;
2555 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2556 a_state->account_dn, &members,
2558 if (!NT_STATUS_IS_OK(status)) {
2562 if (num_members == 0) {
2563 r->out.sids->sids = NULL;
2565 return NT_STATUS_OK;
2568 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2569 if (array == NULL) {
2570 return NT_STATUS_NO_MEMORY;
2573 for (i=0; i<num_members; i++) {
2574 array[i].sid = &members[i];
2577 r->out.sids->num_sids = num_members;
2578 r->out.sids->sids = array;
2580 return NT_STATUS_OK;
2586 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2587 struct samr_OpenUser *r)
2589 struct samr_domain_state *d_state;
2590 struct samr_account_state *a_state;
2591 struct dcesrv_handle *h;
2592 const char *account_name;
2593 struct dom_sid *sid;
2594 struct ldb_message **msgs;
2595 struct dcesrv_handle *u_handle;
2596 const char * const attrs[2] = { "sAMAccountName", NULL };
2599 ZERO_STRUCTP(r->out.user_handle);
2601 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2605 /* form the users SID */
2606 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2608 return NT_STATUS_NO_MEMORY;
2611 /* search for the user record */
2612 ret = gendb_search(d_state->sam_ctx,
2613 mem_ctx, d_state->domain_dn, &msgs, attrs,
2614 "(&(objectSid=%s)(objectclass=user))",
2615 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2617 return NT_STATUS_NO_SUCH_USER;
2620 DEBUG(0,("Found %d records matching sid %s\n", ret,
2621 dom_sid_string(mem_ctx, sid)));
2622 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2625 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2626 if (account_name == NULL) {
2627 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2628 dom_sid_string(mem_ctx, sid)));
2629 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2632 a_state = talloc(mem_ctx, struct samr_account_state);
2634 return NT_STATUS_NO_MEMORY;
2636 a_state->sam_ctx = d_state->sam_ctx;
2637 a_state->access_mask = r->in.access_mask;
2638 a_state->domain_state = talloc_reference(a_state, d_state);
2639 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2640 a_state->account_sid = talloc_steal(a_state, sid);
2641 a_state->account_name = talloc_strdup(a_state, account_name);
2642 if (!a_state->account_name) {
2643 return NT_STATUS_NO_MEMORY;
2646 /* create the policy handle */
2647 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2649 return NT_STATUS_NO_MEMORY;
2652 u_handle->data = talloc_steal(u_handle, a_state);
2654 *r->out.user_handle = u_handle->wire_handle;
2656 return NT_STATUS_OK;
2664 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2665 struct samr_DeleteUser *r)
2667 struct dcesrv_handle *h;
2668 struct samr_account_state *a_state;
2671 *r->out.user_handle = *r->in.user_handle;
2673 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2677 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2678 if (ret != LDB_SUCCESS) {
2679 DEBUG(1, ("Failed to delete user: %s: %s\n",
2680 ldb_dn_get_linearized(a_state->account_dn),
2681 ldb_errstring(a_state->sam_ctx)));
2682 return dsdb_ldb_err_to_ntstatus(ret);
2686 ZERO_STRUCTP(r->out.user_handle);
2688 return NT_STATUS_OK;
2695 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2696 struct samr_QueryUserInfo *r)
2698 struct dcesrv_handle *h;
2699 struct samr_account_state *a_state;
2700 struct ldb_message *msg, **res;
2702 struct ldb_context *sam_ctx;
2704 const char * const *attrs = NULL;
2705 union samr_UserInfo *info;
2709 *r->out.info = NULL;
2711 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2714 sam_ctx = a_state->sam_ctx;
2716 /* fill in the reply */
2717 switch (r->in.level) {
2720 static const char * const attrs2[] = {"sAMAccountName",
2731 static const char * const attrs2[] = {"comment",
2740 static const char * const attrs2[] = {"sAMAccountName",
2756 "userAccountControl",
2757 "msDS-User-Account-Control-Computed",
2764 static const char * const attrs2[] = {"logonHours",
2771 static const char * const attrs2[] = {"sAMAccountName",
2789 "userAccountControl",
2790 "msDS-User-Account-Control-Computed",
2797 static const char * const attrs2[] = {"sAMAccountName",
2805 static const char * const attrs2[] = {"sAMAccountName",
2812 static const char * const attrs2[] = {"displayName",
2819 static const char * const attrs2[] = {"primaryGroupID",
2826 static const char * const attrs2[] = {"homeDirectory",
2834 static const char * const attrs2[] = {"scriptPath",
2841 static const char * const attrs2[] = {"profilePath",
2848 static const char * const attrs2[] = {"description",
2855 static const char * const attrs2[] = {"userWorkstations",
2862 static const char * const attrs2[] = {"userAccountControl",
2863 "msDS-User-Account-Control-Computed",
2871 static const char * const attrs2[] = {"accountExpires",
2878 return NT_STATUS_NOT_SUPPORTED;
2882 static const char * const attrs2[] = {"userParameters",
2889 static const char * const attrs2[] = {"lastLogon",
2905 "userAccountControl",
2906 "msDS-User-Account-Control-Computed",
2922 return NT_STATUS_NOT_SUPPORTED;
2926 return NT_STATUS_INVALID_INFO_CLASS;
2930 /* pull all the user attributes */
2931 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2932 a_state->account_dn, &res, attrs);
2934 return NT_STATUS_NO_SUCH_USER;
2937 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2941 /* allocate the info structure */
2942 info = talloc_zero(mem_ctx, union samr_UserInfo);
2944 return NT_STATUS_NO_MEMORY;
2947 /* fill in the reply */
2948 switch (r->in.level) {
2950 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2951 QUERY_STRING(msg, info1.full_name, "displayName");
2952 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2953 QUERY_STRING(msg, info1.description, "description");
2954 QUERY_STRING(msg, info1.comment, "comment");
2958 QUERY_STRING(msg, info2.comment, "comment");
2959 QUERY_UINT (msg, info2.country_code, "countryCode");
2960 QUERY_UINT (msg, info2.code_page, "codePage");
2964 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2965 QUERY_STRING(msg, info3.full_name, "displayName");
2966 QUERY_RID (msg, info3.rid, "objectSid");
2967 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2968 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2969 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2970 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2971 QUERY_STRING(msg, info3.profile_path, "profilePath");
2972 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2973 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2974 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2975 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2976 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2977 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2978 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2979 /* level 3 gives the raw badPwdCount value */
2980 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2981 QUERY_UINT (msg, info3.logon_count, "logonCount");
2982 QUERY_AFLAGS(msg, info3.acct_flags, "msDS-User-Account-Control-Computed");
2986 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2990 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2991 QUERY_STRING(msg, info5.full_name, "displayName");
2992 QUERY_RID (msg, info5.rid, "objectSid");
2993 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2994 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2995 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2996 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2997 QUERY_STRING(msg, info5.profile_path, "profilePath");
2998 QUERY_STRING(msg, info5.description, "description");
2999 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3000 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3001 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3002 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3003 QUERY_BPWDCT(msg, info5.bad_password_count, "badPwdCount");
3004 QUERY_UINT (msg, info5.logon_count, "logonCount");
3005 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3006 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3007 QUERY_AFLAGS(msg, info5.acct_flags, "msDS-User-Account-Control-Computed");
3011 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3012 QUERY_STRING(msg, info6.full_name, "displayName");
3016 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3020 QUERY_STRING(msg, info8.full_name, "displayName");
3024 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3028 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3029 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3033 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3037 QUERY_STRING(msg, info12.profile_path, "profilePath");
3041 QUERY_STRING(msg, info13.description, "description");
3045 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3049 QUERY_AFLAGS(msg, info16.acct_flags, "msDS-User-Account-Control-Computed");
3053 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3057 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
3058 if (!NT_STATUS_IS_OK(status)) {
3065 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3066 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3067 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3068 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3069 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3070 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3071 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3072 QUERY_STRING(msg, info21.full_name, "displayName");
3073 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3074 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3075 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3076 QUERY_STRING(msg, info21.profile_path, "profilePath");
3077 QUERY_STRING(msg, info21.description, "description");
3078 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3079 QUERY_STRING(msg, info21.comment, "comment");
3080 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
3081 if (!NT_STATUS_IS_OK(status)) {
3086 QUERY_RID (msg, info21.rid, "objectSid");
3087 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3088 QUERY_AFLAGS(msg, info21.acct_flags, "msDS-User-Account-Control-Computed");
3089 info->info21.fields_present = 0x08FFFFFF;
3090 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3091 QUERY_BPWDCT(msg, info21.bad_password_count, "badPwdCount");
3092 QUERY_UINT (msg, info21.logon_count, "logonCount");
3093 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3094 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3096 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3098 QUERY_UINT (msg, info21.country_code, "countryCode");
3099 QUERY_UINT (msg, info21.code_page, "codePage");
3105 return NT_STATUS_INVALID_INFO_CLASS;
3108 *r->out.info = info;
3110 return NT_STATUS_OK;
3117 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3118 struct samr_SetUserInfo *r)
3120 struct dcesrv_handle *h;
3121 struct samr_account_state *a_state;
3122 struct ldb_message *msg;
3124 NTSTATUS status = NT_STATUS_OK;
3125 struct ldb_context *sam_ctx;
3127 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3130 sam_ctx = a_state->sam_ctx;
3132 msg = ldb_msg_new(mem_ctx);
3134 return NT_STATUS_NO_MEMORY;
3137 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3139 return NT_STATUS_NO_MEMORY;
3142 switch (r->in.level) {
3144 SET_STRING(msg, info2.comment, "comment");
3145 SET_UINT (msg, info2.country_code, "countryCode");
3146 SET_UINT (msg, info2.code_page, "codePage");
3150 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3154 SET_STRING(msg, info6.account_name, "samAccountName");
3155 SET_STRING(msg, info6.full_name, "displayName");
3159 SET_STRING(msg, info7.account_name, "samAccountName");
3163 SET_STRING(msg, info8.full_name, "displayName");
3167 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3171 SET_STRING(msg, info10.home_directory, "homeDirectory");
3172 SET_STRING(msg, info10.home_drive, "homeDrive");
3176 SET_STRING(msg, info11.logon_script, "scriptPath");
3180 SET_STRING(msg, info12.profile_path, "profilePath");
3184 SET_STRING(msg, info13.description, "description");
3188 SET_STRING(msg, info14.workstations, "userWorkstations");
3192 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3196 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3200 status = samr_set_password_buffers(dce_call,
3202 a_state->account_dn,
3203 a_state->domain_state->domain_dn,
3205 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3206 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3207 if (!NT_STATUS_IS_OK(status)) {
3211 if (r->in.info->info18.password_expired > 0) {
3212 struct ldb_message_element *set_el;
3213 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3214 return NT_STATUS_NO_MEMORY;
3216 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3217 set_el->flags = LDB_FLAG_MOD_REPLACE;
3222 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3226 if (r->in.info->info21.fields_present == 0)
3227 return NT_STATUS_INVALID_PARAMETER;
3229 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3230 IFSET(SAMR_FIELD_LAST_LOGON)
3231 SET_UINT64(msg, info21.last_logon, "lastLogon");
3232 IFSET(SAMR_FIELD_LAST_LOGOFF)
3233 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3234 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3235 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3236 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3237 SET_STRING(msg, info21.account_name, "samAccountName");
3238 IFSET(SAMR_FIELD_FULL_NAME)
3239 SET_STRING(msg, info21.full_name, "displayName");
3240 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3241 SET_STRING(msg, info21.home_directory, "homeDirectory");
3242 IFSET(SAMR_FIELD_HOME_DRIVE)
3243 SET_STRING(msg, info21.home_drive, "homeDrive");
3244 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3245 SET_STRING(msg, info21.logon_script, "scriptPath");
3246 IFSET(SAMR_FIELD_PROFILE_PATH)
3247 SET_STRING(msg, info21.profile_path, "profilePath");
3248 IFSET(SAMR_FIELD_DESCRIPTION)
3249 SET_STRING(msg, info21.description, "description");
3250 IFSET(SAMR_FIELD_WORKSTATIONS)
3251 SET_STRING(msg, info21.workstations, "userWorkstations");
3252 IFSET(SAMR_FIELD_COMMENT)
3253 SET_STRING(msg, info21.comment, "comment");
3254 IFSET(SAMR_FIELD_PARAMETERS)
3255 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3256 IFSET(SAMR_FIELD_PRIMARY_GID)
3257 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3258 IFSET(SAMR_FIELD_ACCT_FLAGS)
3259 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3260 IFSET(SAMR_FIELD_LOGON_HOURS)
3261 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3262 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3263 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3264 IFSET(SAMR_FIELD_NUM_LOGONS)
3265 SET_UINT (msg, info21.logon_count, "logonCount");
3266 IFSET(SAMR_FIELD_COUNTRY_CODE)
3267 SET_UINT (msg, info21.country_code, "countryCode");
3268 IFSET(SAMR_FIELD_CODE_PAGE)
3269 SET_UINT (msg, info21.code_page, "codePage");
3271 /* password change fields */
3272 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3273 return NT_STATUS_ACCESS_DENIED;
3275 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3276 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3277 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3279 if (r->in.info->info21.lm_password_set) {
3280 if ((r->in.info->info21.lm_owf_password.length != 16)
3281 || (r->in.info->info21.lm_owf_password.size != 16)) {
3282 return NT_STATUS_INVALID_PARAMETER;
3285 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3287 if (r->in.info->info21.nt_password_set) {
3288 if ((r->in.info->info21.nt_owf_password.length != 16)
3289 || (r->in.info->info21.nt_owf_password.size != 16)) {
3290 return NT_STATUS_INVALID_PARAMETER;
3293 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3295 status = samr_set_password_buffers(dce_call,
3297 a_state->account_dn,
3298 a_state->domain_state->domain_dn,
3302 if (!NT_STATUS_IS_OK(status)) {
3308 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3310 struct ldb_message_element *set_el;
3311 if (r->in.info->info21.password_expired
3312 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3313 unix_to_nt_time(&t, time(NULL));
3315 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3316 "pwdLastSet", t) != LDB_SUCCESS) {
3317 return NT_STATUS_NO_MEMORY;
3319 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3320 set_el->flags = LDB_FLAG_MOD_REPLACE;
3326 if (r->in.info->info23.info.fields_present == 0)
3327 return NT_STATUS_INVALID_PARAMETER;
3329 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3330 IFSET(SAMR_FIELD_LAST_LOGON)
3331 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3332 IFSET(SAMR_FIELD_LAST_LOGOFF)
3333 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3334 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3335 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3336 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3337 SET_STRING(msg, info23.info.account_name, "samAccountName");
3338 IFSET(SAMR_FIELD_FULL_NAME)
3339 SET_STRING(msg, info23.info.full_name, "displayName");
3340 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3341 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3342 IFSET(SAMR_FIELD_HOME_DRIVE)
3343 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3344 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3345 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3346 IFSET(SAMR_FIELD_PROFILE_PATH)
3347 SET_STRING(msg, info23.info.profile_path, "profilePath");
3348 IFSET(SAMR_FIELD_DESCRIPTION)
3349 SET_STRING(msg, info23.info.description, "description");
3350 IFSET(SAMR_FIELD_WORKSTATIONS)
3351 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3352 IFSET(SAMR_FIELD_COMMENT)
3353 SET_STRING(msg, info23.info.comment, "comment");
3354 IFSET(SAMR_FIELD_PARAMETERS)
3355 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3356 IFSET(SAMR_FIELD_PRIMARY_GID)
3357 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3358 IFSET(SAMR_FIELD_ACCT_FLAGS)
3359 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3360 IFSET(SAMR_FIELD_LOGON_HOURS)
3361 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3362 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3363 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3364 IFSET(SAMR_FIELD_NUM_LOGONS)
3365 SET_UINT (msg, info23.info.logon_count, "logonCount");
3367 IFSET(SAMR_FIELD_COUNTRY_CODE)
3368 SET_UINT (msg, info23.info.country_code, "countryCode");
3369 IFSET(SAMR_FIELD_CODE_PAGE)
3370 SET_UINT (msg, info23.info.code_page, "codePage");
3372 /* password change fields */
3373 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3374 return NT_STATUS_ACCESS_DENIED;
3376 IFSET(SAMR_FIELD_NT_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);
3383 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3384 status = samr_set_password(dce_call,
3386 a_state->account_dn,
3387 a_state->domain_state->domain_dn,
3389 &r->in.info->info23.password);
3391 if (!NT_STATUS_IS_OK(status)) {
3395 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3397 struct ldb_message_element *set_el;
3398 if (r->in.info->info23.info.password_expired
3399 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3400 unix_to_nt_time(&t, time(NULL));
3402 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3403 "pwdLastSet", t) != LDB_SUCCESS) {
3404 return NT_STATUS_NO_MEMORY;
3406 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3407 set_el->flags = LDB_FLAG_MOD_REPLACE;
3412 /* the set password levels are handled separately */
3414 status = samr_set_password(dce_call,
3416 a_state->account_dn,
3417 a_state->domain_state->domain_dn,
3419 &r->in.info->info24.password);
3420 if (!NT_STATUS_IS_OK(status)) {
3424 if (r->in.info->info24.password_expired > 0) {
3425 struct ldb_message_element *set_el;
3426 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3427 return NT_STATUS_NO_MEMORY;
3429 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3430 set_el->flags = LDB_FLAG_MOD_REPLACE;
3435 if (r->in.info->info25.info.fields_present == 0)
3436 return NT_STATUS_INVALID_PARAMETER;
3438 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3439 IFSET(SAMR_FIELD_LAST_LOGON)
3440 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3441 IFSET(SAMR_FIELD_LAST_LOGOFF)
3442 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3443 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3444 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3445 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3446 SET_STRING(msg, info25.info.account_name, "samAccountName");
3447 IFSET(SAMR_FIELD_FULL_NAME)
3448 SET_STRING(msg, info25.info.full_name, "displayName");
3449 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3450 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3451 IFSET(SAMR_FIELD_HOME_DRIVE)
3452 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3453 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3454 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3455 IFSET(SAMR_FIELD_PROFILE_PATH)
3456 SET_STRING(msg, info25.info.profile_path, "profilePath");
3457 IFSET(SAMR_FIELD_DESCRIPTION)
3458 SET_STRING(msg, info25.info.description, "description");
3459 IFSET(SAMR_FIELD_WORKSTATIONS)
3460 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3461 IFSET(SAMR_FIELD_COMMENT)
3462 SET_STRING(msg, info25.info.comment, "comment");
3463 IFSET(SAMR_FIELD_PARAMETERS)
3464 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3465 IFSET(SAMR_FIELD_PRIMARY_GID)
3466 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3467 IFSET(SAMR_FIELD_ACCT_FLAGS)
3468 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3469 IFSET(SAMR_FIELD_LOGON_HOURS)
3470 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3471 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3472 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3473 IFSET(SAMR_FIELD_NUM_LOGONS)
3474 SET_UINT (msg, info25.info.logon_count, "logonCount");
3475 IFSET(SAMR_FIELD_COUNTRY_CODE)
3476 SET_UINT (msg, info25.info.country_code, "countryCode");
3477 IFSET(SAMR_FIELD_CODE_PAGE)
3478 SET_UINT (msg, info25.info.code_page, "codePage");
3480 /* password change fields */
3481 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3482 return NT_STATUS_ACCESS_DENIED;
3484 IFSET(SAMR_FIELD_NT_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);
3491 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3492 status = samr_set_password_ex(dce_call,
3494 a_state->account_dn,
3495 a_state->domain_state->domain_dn,
3497 &r->in.info->info25.password);
3499 if (!NT_STATUS_IS_OK(status)) {
3503 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3505 struct ldb_message_element *set_el;
3506 if (r->in.info->info25.info.password_expired
3507 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3508 unix_to_nt_time(&t, time(NULL));
3510 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3511 "pwdLastSet", t) != LDB_SUCCESS) {
3512 return NT_STATUS_NO_MEMORY;
3514 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3515 set_el->flags = LDB_FLAG_MOD_REPLACE;
3520 /* the set password levels are handled separately */
3522 status = samr_set_password_ex(dce_call,
3524 a_state->account_dn,
3525 a_state->domain_state->domain_dn,
3527 &r->in.info->info26.password);
3528 if (!NT_STATUS_IS_OK(status)) {
3532 if (r->in.info->info26.password_expired > 0) {
3534 struct ldb_message_element *set_el;
3535 if (r->in.info->info26.password_expired
3536 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3537 unix_to_nt_time(&t, time(NULL));
3539 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3540 "pwdLastSet", t) != LDB_SUCCESS) {
3541 return NT_STATUS_NO_MEMORY;
3543 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3544 set_el->flags = LDB_FLAG_MOD_REPLACE;
3549 /* many info classes are not valid for SetUserInfo */
3550 return NT_STATUS_INVALID_INFO_CLASS;
3553 if (!NT_STATUS_IS_OK(status)) {
3557 /* modify the samdb record */
3558 if (msg->num_elements > 0) {
3559 ret = ldb_modify(a_state->sam_ctx, msg);
3560 if (ret != LDB_SUCCESS) {
3561 DEBUG(1,("Failed to modify record %s: %s\n",
3562 ldb_dn_get_linearized(a_state->account_dn),
3563 ldb_errstring(a_state->sam_ctx)));
3565 return dsdb_ldb_err_to_ntstatus(ret);
3569 return NT_STATUS_OK;
3574 samr_GetGroupsForUser
3576 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3577 struct samr_GetGroupsForUser *r)
3579 struct dcesrv_handle *h;
3580 struct samr_account_state *a_state;
3581 struct samr_domain_state *d_state;
3582 struct ldb_message **res;
3583 const char * const attrs[2] = { "objectSid", NULL };
3584 struct samr_RidWithAttributeArray *array;
3586 char membersidstr[DOM_SID_STR_BUFLEN];
3588 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3591 d_state = a_state->domain_state;
3593 dom_sid_string_buf(a_state->account_sid,
3594 membersidstr, sizeof(membersidstr)),
3596 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3597 d_state->domain_dn, &res,
3598 attrs, d_state->domain_sid,
3599 "(&(member=<SID=%s>)"
3600 "(|(grouptype=%d)(grouptype=%d))"
3601 "(objectclass=group))",
3603 GTYPE_SECURITY_UNIVERSAL_GROUP,
3604 GTYPE_SECURITY_GLOBAL_GROUP);
3606 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3608 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3610 return NT_STATUS_NO_MEMORY;
3615 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3617 if (array->rids == NULL)
3618 return NT_STATUS_NO_MEMORY;
3620 /* Adds the primary group */
3621 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3622 ~0, a_state->account_dn,
3623 "primaryGroupID", NULL);
3624 array->rids[0].attributes = SE_GROUP_MANDATORY
3625 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3628 /* Adds the additional groups */
3629 for (i = 0; i < count; i++) {
3630 struct dom_sid *group_sid;
3632 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3633 if (group_sid == NULL) {
3634 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3637 array->rids[i + 1].rid =
3638 group_sid->sub_auths[group_sid->num_auths-1];
3639 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3640 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3644 *r->out.rids = array;
3646 return NT_STATUS_OK;
3651 samr_QueryDisplayInfo
3653 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3654 struct samr_QueryDisplayInfo *r)
3656 struct dcesrv_handle *h;
3657 struct samr_domain_state *d_state;
3658 struct ldb_result *res;
3661 const char * const attrs[] = { "objectSid", "sAMAccountName",
3662 "displayName", "description", "userAccountControl",
3663 "pwdLastSet", NULL };
3664 struct samr_DispEntryFull *entriesFull = NULL;
3665 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3666 struct samr_DispEntryAscii *entriesAscii = NULL;
3667 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3671 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3675 switch (r->in.level) {
3678 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3679 "(sAMAccountType=%d))",
3680 ATYPE_NORMAL_ACCOUNT);
3683 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3684 "(sAMAccountType=%d))",
3685 ATYPE_WORKSTATION_TRUST);
3689 filter = talloc_asprintf(mem_ctx,
3690 "(&(|(groupType=%d)(groupType=%d))"
3691 "(objectClass=group))",
3692 GTYPE_SECURITY_UNIVERSAL_GROUP,
3693 GTYPE_SECURITY_GLOBAL_GROUP);
3696 return NT_STATUS_INVALID_INFO_CLASS;
3699 /* search for all requested objects in all domains. This could
3700 possibly be cached and resumed based on resume_key */
3701 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, ldb_get_default_basedn(d_state->sam_ctx),
3702 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3703 if (ret != LDB_SUCCESS) {
3704 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3706 if ((res->count == 0) || (r->in.max_entries == 0)) {
3707 return NT_STATUS_OK;
3710 switch (r->in.level) {
3712 entriesGeneral = talloc_array(mem_ctx,
3713 struct samr_DispEntryGeneral,
3717 entriesFull = talloc_array(mem_ctx,
3718 struct samr_DispEntryFull,
3722 entriesFullGroup = talloc_array(mem_ctx,
3723 struct samr_DispEntryFullGroup,
3728 entriesAscii = talloc_array(mem_ctx,
3729 struct samr_DispEntryAscii,
3734 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3735 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3736 return NT_STATUS_NO_MEMORY;
3740 for (i = 0; i < res->count; i++) {
3741 struct dom_sid *objectsid;
3743 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3745 if (objectsid == NULL)
3748 switch(r->in.level) {
3750 entriesGeneral[count].idx = count + 1;
3751 entriesGeneral[count].rid =
3752 objectsid->sub_auths[objectsid->num_auths-1];
3753 entriesGeneral[count].acct_flags =
3754 samdb_result_acct_flags(res->msgs[i], NULL);
3755 entriesGeneral[count].account_name.string =
3756 ldb_msg_find_attr_as_string(res->msgs[i],
3757 "sAMAccountName", "");
3758 entriesGeneral[count].full_name.string =
3759 ldb_msg_find_attr_as_string(res->msgs[i],
3761 entriesGeneral[count].description.string =
3762 ldb_msg_find_attr_as_string(res->msgs[i],
3766 entriesFull[count].idx = count + 1;
3767 entriesFull[count].rid =
3768 objectsid->sub_auths[objectsid->num_auths-1];
3770 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3771 entriesFull[count].acct_flags =
3772 samdb_result_acct_flags(res->msgs[i],
3774 entriesFull[count].account_name.string =
3775 ldb_msg_find_attr_as_string(res->msgs[i],
3776 "sAMAccountName", "");
3777 entriesFull[count].description.string =
3778 ldb_msg_find_attr_as_string(res->msgs[i],
3782 entriesFullGroup[count].idx = count + 1;
3783 entriesFullGroup[count].rid =
3784 objectsid->sub_auths[objectsid->num_auths-1];
3785 /* We get a "7" here for groups */
3786 entriesFullGroup[count].acct_flags
3787 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3788 entriesFullGroup[count].account_name.string =
3789 ldb_msg_find_attr_as_string(res->msgs[i],
3790 "sAMAccountName", "");
3791 entriesFullGroup[count].description.string =
3792 ldb_msg_find_attr_as_string(res->msgs[i],
3797 entriesAscii[count].idx = count + 1;
3798 entriesAscii[count].account_name.string =
3799 ldb_msg_find_attr_as_string(res->msgs[i],
3800 "sAMAccountName", "");
3807 *r->out.total_size = count;
3809 if (r->in.start_idx >= count) {
3810 *r->out.returned_size = 0;
3811 switch(r->in.level) {
3813 r->out.info->info1.count = *r->out.returned_size;
3814 r->out.info->info1.entries = NULL;
3817 r->out.info->info2.count = *r->out.returned_size;
3818 r->out.info->info2.entries = NULL;
3821 r->out.info->info3.count = *r->out.returned_size;
3822 r->out.info->info3.entries = NULL;
3825 r->out.info->info4.count = *r->out.returned_size;
3826 r->out.info->info4.entries = NULL;
3829 r->out.info->info5.count = *r->out.returned_size;
3830 r->out.info->info5.entries = NULL;
3834 *r->out.returned_size = MIN(count - r->in.start_idx,
3836 switch(r->in.level) {
3838 r->out.info->info1.count = *r->out.returned_size;
3839 r->out.info->info1.entries =
3840 &(entriesGeneral[r->in.start_idx]);
3843 r->out.info->info2.count = *r->out.returned_size;
3844 r->out.info->info2.entries =
3845 &(entriesFull[r->in.start_idx]);
3848 r->out.info->info3.count = *r->out.returned_size;
3849 r->out.info->info3.entries =
3850 &(entriesFullGroup[r->in.start_idx]);
3853 r->out.info->info4.count = *r->out.returned_size;
3854 r->out.info->info4.entries =
3855 &(entriesAscii[r->in.start_idx]);
3858 r->out.info->info5.count = *r->out.returned_size;
3859 r->out.info->info5.entries =
3860 &(entriesAscii[r->in.start_idx]);
3865 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3866 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3871 samr_GetDisplayEnumerationIndex
3873 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3874 struct samr_GetDisplayEnumerationIndex *r)
3876 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3881 samr_TestPrivateFunctionsDomain
3883 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3884 struct samr_TestPrivateFunctionsDomain *r)
3886 return NT_STATUS_NOT_IMPLEMENTED;
3891 samr_TestPrivateFunctionsUser
3893 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3894 struct samr_TestPrivateFunctionsUser *r)
3896 return NT_STATUS_NOT_IMPLEMENTED;
3903 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3904 struct samr_GetUserPwInfo *r)
3906 struct dcesrv_handle *h;
3907 struct samr_account_state *a_state;
3909 ZERO_STRUCTP(r->out.info);
3911 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3915 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3916 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3918 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3919 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3921 return NT_STATUS_OK;
3926 samr_RemoveMemberFromForeignDomain
3928 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3929 TALLOC_CTX *mem_ctx,
3930 struct samr_RemoveMemberFromForeignDomain *r)
3932 struct dcesrv_handle *h;
3933 struct samr_domain_state *d_state;
3934 const char *memberdn;
3935 struct ldb_message **res;
3936 const char *no_attrs[] = { NULL };
3939 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3943 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3944 "distinguishedName", "(objectSid=%s)",
3945 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3947 if (memberdn == NULL) {
3948 return NT_STATUS_OK;
3951 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3952 d_state->domain_dn, &res, no_attrs,
3953 d_state->domain_sid,
3954 "(&(member=%s)(objectClass=group)"
3955 "(|(groupType=%d)(groupType=%d)))",
3957 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3958 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3961 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3963 for (i=0; i<count; i++) {
3964 struct ldb_message *mod;
3967 mod = ldb_msg_new(mem_ctx);
3969 return NT_STATUS_NO_MEMORY;
3972 mod->dn = res[i]->dn;
3974 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3975 "member", memberdn) != LDB_SUCCESS)
3976 return NT_STATUS_NO_MEMORY;
3978 ret = ldb_modify(d_state->sam_ctx, mod);
3980 if (ret != LDB_SUCCESS) {
3981 return dsdb_ldb_err_to_ntstatus(ret);
3985 return NT_STATUS_OK;
3990 samr_QueryDomainInfo2
3992 just an alias for samr_QueryDomainInfo
3994 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3995 struct samr_QueryDomainInfo2 *r)
3997 struct samr_QueryDomainInfo r1;
4000 ZERO_STRUCT(r1.out);
4001 r1.in.domain_handle = r->in.domain_handle;
4002 r1.in.level = r->in.level;
4003 r1.out.info = r->out.info;
4005 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4014 just an alias for samr_QueryUserInfo
4016 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4017 struct samr_QueryUserInfo2 *r)
4019 struct samr_QueryUserInfo r1;
4022 r1 = (struct samr_QueryUserInfo) {
4023 .in.user_handle = r->in.user_handle,
4024 .in.level = r->in.level,
4025 .out.info = r->out.info
4028 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4035 samr_QueryDisplayInfo2
4037 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4038 struct samr_QueryDisplayInfo2 *r)
4040 struct samr_QueryDisplayInfo q;
4043 q.in.domain_handle = r->in.domain_handle;
4044 q.in.level = r->in.level;
4045 q.in.start_idx = r->in.start_idx;
4046 q.in.max_entries = r->in.max_entries;
4047 q.in.buf_size = r->in.buf_size;
4048 q.out.total_size = r->out.total_size;
4049 q.out.returned_size = r->out.returned_size;
4050 q.out.info = r->out.info;
4052 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4059 samr_GetDisplayEnumerationIndex2
4061 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4062 struct samr_GetDisplayEnumerationIndex2 *r)
4064 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4069 samr_QueryDisplayInfo3
4071 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4072 struct samr_QueryDisplayInfo3 *r)
4074 struct samr_QueryDisplayInfo q;
4077 q.in.domain_handle = r->in.domain_handle;
4078 q.in.level = r->in.level;
4079 q.in.start_idx = r->in.start_idx;
4080 q.in.max_entries = r->in.max_entries;
4081 q.in.buf_size = r->in.buf_size;
4082 q.out.total_size = r->out.total_size;
4083 q.out.returned_size = r->out.returned_size;
4084 q.out.info = r->out.info;
4086 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4093 samr_AddMultipleMembersToAlias
4095 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4096 struct samr_AddMultipleMembersToAlias *r)
4098 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4103 samr_RemoveMultipleMembersFromAlias
4105 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4106 struct samr_RemoveMultipleMembersFromAlias *r)
4108 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4115 this fetches the default password properties for a domain
4117 note that w2k3 completely ignores the domain name in this call, and
4118 always returns the information for the servers primary domain
4120 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4121 struct samr_GetDomPwInfo *r)
4123 struct ldb_message **msgs;
4125 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4126 struct ldb_context *sam_ctx;
4128 ZERO_STRUCTP(r->out.info);
4130 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4131 dce_call->conn->dce_ctx->lp_ctx,
4132 dce_call->conn->auth_state.session_info, 0);
4133 if (sam_ctx == NULL) {
4134 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4137 /* The domain name in this call is ignored */
4138 ret = gendb_search_dn(sam_ctx,
4139 mem_ctx, NULL, &msgs, attrs);
4141 talloc_free(sam_ctx);
4143 return NT_STATUS_NO_SUCH_DOMAIN;
4147 talloc_free(sam_ctx);
4149 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4152 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4154 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4155 "pwdProperties", 1);
4158 talloc_unlink(mem_ctx, sam_ctx);
4160 return NT_STATUS_OK;
4167 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4168 struct samr_Connect2 *r)
4170 struct samr_Connect c;
4172 c.in.system_name = NULL;
4173 c.in.access_mask = r->in.access_mask;
4174 c.out.connect_handle = r->out.connect_handle;
4176 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4183 just an alias for samr_SetUserInfo
4185 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4186 struct samr_SetUserInfo2 *r)
4188 struct samr_SetUserInfo r2;
4190 r2.in.user_handle = r->in.user_handle;
4191 r2.in.level = r->in.level;
4192 r2.in.info = r->in.info;
4194 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4199 samr_SetBootKeyInformation
4201 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4202 struct samr_SetBootKeyInformation *r)
4204 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4209 samr_GetBootKeyInformation
4211 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4212 struct samr_GetBootKeyInformation *r)
4214 /* Windows Server 2008 returns this */
4215 return NT_STATUS_NOT_SUPPORTED;
4222 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4223 struct samr_Connect3 *r)
4225 struct samr_Connect c;
4227 c.in.system_name = NULL;
4228 c.in.access_mask = r->in.access_mask;
4229 c.out.connect_handle = r->out.connect_handle;
4231 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4238 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4239 struct samr_Connect4 *r)
4241 struct samr_Connect c;
4243 c.in.system_name = NULL;
4244 c.in.access_mask = r->in.access_mask;
4245 c.out.connect_handle = r->out.connect_handle;
4247 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4254 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4255 struct samr_Connect5 *r)
4257 struct samr_Connect c;
4260 c.in.system_name = NULL;
4261 c.in.access_mask = r->in.access_mask;
4262 c.out.connect_handle = r->out.connect_handle;
4264 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4266 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4267 r->out.info_out->info1.unknown2 = 0;
4268 *r->out.level_out = r->in.level_in;
4277 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4278 struct samr_RidToSid *r)
4280 struct samr_domain_state *d_state;
4281 struct dcesrv_handle *h;
4283 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4287 /* form the users SID */
4288 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4290 return NT_STATUS_NO_MEMORY;
4293 return NT_STATUS_OK;
4298 samr_SetDsrmPassword
4300 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4301 struct samr_SetDsrmPassword *r)
4303 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4308 samr_ValidatePassword
4310 For now the call checks the password complexity (if active) and the minimum
4311 password length on level 2 and 3. Level 1 is ignored for now.
4313 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4314 TALLOC_CTX *mem_ctx,
4315 struct samr_ValidatePassword *r)
4317 struct samr_GetDomPwInfo r2;
4318 struct samr_PwInfo pwInfo;
4320 enum samr_ValidationStatus res;
4322 enum dcerpc_transport_t transport =
4323 dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
4325 if (transport != NCACN_IP_TCP && transport != NCALRPC) {
4326 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4329 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4331 r2.in.domain_name = NULL;
4332 r2.out.info = &pwInfo;
4333 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4334 if (!NT_STATUS_IS_OK(status)) {
4338 switch (r->in.level) {
4339 case NetValidateAuthentication:
4340 /* we don't support this yet */
4341 return NT_STATUS_NOT_SUPPORTED;
4343 case NetValidatePasswordChange:
4344 password = data_blob_const(r->in.req->req2.password.string,
4345 r->in.req->req2.password.length);
4346 res = samdb_check_password(&password,
4347 pwInfo.password_properties,
4348 pwInfo.min_password_length);
4349 (*r->out.rep)->ctr2.status = res;
4351 case NetValidatePasswordReset:
4352 password = data_blob_const(r->in.req->req3.password.string,
4353 r->in.req->req3.password.length);
4354 res = samdb_check_password(&password,
4355 pwInfo.password_properties,
4356 pwInfo.min_password_length);
4357 (*r->out.rep)->ctr3.status = res;
4360 return NT_STATUS_INVALID_INFO_CLASS;
4364 return NT_STATUS_OK;
4368 /* include the generated boilerplate */
4369 #include "librpc/gen_ndr/ndr_samr_s.c"