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"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "libcli/security/security.h"
37 #include "rpc_server/samr/proto.h"
38 #include "../lib/util/util_ldb.h"
39 #include "param/param.h"
41 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
43 #define QUERY_STRING(msg, field, attr) \
44 info->field.string = samdb_result_string(msg, attr, "");
45 #define QUERY_UINT(msg, field, attr) \
46 info->field = samdb_result_uint(msg, attr, 0);
47 #define QUERY_RID(msg, field, attr) \
48 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
49 #define QUERY_UINT64(msg, field, attr) \
50 info->field = samdb_result_uint64(msg, attr, 0);
51 #define QUERY_APASSC(msg, field, attr) \
52 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
53 a_state->domain_state->domain_dn, msg, attr);
54 #define QUERY_FPASSC(msg, field, attr) \
55 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg);
57 #define QUERY_LHOURS(msg, field, attr) \
58 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
59 #define QUERY_AFLAGS(msg, field, attr) \
60 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
61 #define QUERY_PARAMETERS(msg, field, attr) \
62 info->field = samdb_result_parameters(mem_ctx, msg, attr);
65 /* these are used to make the Set[User|Group]Info code easier to follow */
67 #define SET_STRING(msg, field, attr) do { \
68 struct ldb_message_element *set_el; \
69 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
70 if (r->in.info->field.string[0] == '\0') { \
71 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
72 return NT_STATUS_NO_MEMORY; \
75 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
76 return NT_STATUS_NO_MEMORY; \
78 set_el = ldb_msg_find_element(msg, attr); \
79 set_el->flags = LDB_FLAG_MOD_REPLACE; \
82 #define SET_UINT(msg, field, attr) do { \
83 struct ldb_message_element *set_el; \
84 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
85 return NT_STATUS_NO_MEMORY; \
87 set_el = ldb_msg_find_element(msg, attr); \
88 set_el->flags = LDB_FLAG_MOD_REPLACE; \
91 #define SET_INT64(msg, field, attr) do { \
92 struct ldb_message_element *set_el; \
93 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
94 return NT_STATUS_NO_MEMORY; \
96 set_el = ldb_msg_find_element(msg, attr); \
97 set_el->flags = LDB_FLAG_MOD_REPLACE; \
100 #define SET_UINT64(msg, field, attr) do { \
101 struct ldb_message_element *set_el; \
102 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
103 return NT_STATUS_NO_MEMORY; \
105 set_el = ldb_msg_find_element(msg, attr); \
106 set_el->flags = LDB_FLAG_MOD_REPLACE; \
109 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
111 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
112 return NT_STATUS_INVALID_PARAMETER; \
116 /* Set account flags, discarding flags that cannot be set with SAMR */
117 #define SET_AFLAGS(msg, field, attr) do { \
118 struct ldb_message_element *set_el; \
119 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
120 return NT_STATUS_INVALID_PARAMETER; \
122 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
127 return NT_STATUS_NO_MEMORY; \
129 set_el = ldb_msg_find_element(msg, attr); \
130 set_el->flags = LDB_FLAG_MOD_REPLACE; \
133 #define SET_LHOURS(msg, field, attr) do { \
134 struct ldb_message_element *set_el; \
135 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
136 return NT_STATUS_NO_MEMORY; \
138 set_el = ldb_msg_find_element(msg, attr); \
139 set_el->flags = LDB_FLAG_MOD_REPLACE; \
142 #define SET_PARAMETERS(msg, field, attr) do { \
143 struct ldb_message_element *set_el; \
144 if (r->in.info->field.length != 0) { \
145 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
146 return NT_STATUS_NO_MEMORY; \
148 set_el = ldb_msg_find_element(msg, attr); \
149 set_el->flags = LDB_FLAG_MOD_REPLACE; \
158 create a connection to the SAM database
160 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
161 struct samr_Connect *r)
163 struct samr_connect_state *c_state;
164 struct dcesrv_handle *handle;
166 ZERO_STRUCTP(r->out.connect_handle);
168 c_state = talloc(mem_ctx, struct samr_connect_state);
170 return NT_STATUS_NO_MEMORY;
173 /* make sure the sam database is accessible */
174 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);
175 if (c_state->sam_ctx == NULL) {
176 talloc_free(c_state);
177 return NT_STATUS_INVALID_SYSTEM_SERVICE;
181 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
183 talloc_free(c_state);
184 return NT_STATUS_NO_MEMORY;
187 handle->data = talloc_steal(handle, c_state);
189 c_state->access_mask = r->in.access_mask;
190 *r->out.connect_handle = handle->wire_handle;
199 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
200 struct samr_Close *r)
202 struct dcesrv_handle *h;
204 *r->out.handle = *r->in.handle;
206 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
210 ZERO_STRUCTP(r->out.handle);
219 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
220 struct samr_SetSecurity *r)
222 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
229 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
230 struct samr_QuerySecurity *r)
232 struct dcesrv_handle *h;
233 struct sec_desc_buf *sd;
235 *r->out.sdbuf = NULL;
237 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
239 sd = talloc(mem_ctx, struct sec_desc_buf);
241 return NT_STATUS_NO_MEMORY;
244 sd->sd = samdb_default_security_descriptor(mem_ctx);
255 we refuse this operation completely. If a admin wants to shutdown samr
256 in Samba then they should use the samba admin tools to disable the samr pipe
258 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
259 struct samr_Shutdown *r)
261 return NT_STATUS_ACCESS_DENIED;
268 this maps from a domain name to a SID
270 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
271 struct samr_LookupDomain *r)
273 struct samr_connect_state *c_state;
274 struct dcesrv_handle *h;
276 const char * const dom_attrs[] = { "objectSid", NULL};
277 struct ldb_message **dom_msgs;
282 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
286 if (r->in.domain_name->string == NULL) {
287 return NT_STATUS_INVALID_PARAMETER;
290 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
291 ret = gendb_search(c_state->sam_ctx,
292 mem_ctx, NULL, &dom_msgs, dom_attrs,
293 "(objectClass=builtinDomain)");
294 } else if (strcasecmp_m(r->in.domain_name->string, lp_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
295 ret = gendb_search_dn(c_state->sam_ctx,
296 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
297 &dom_msgs, dom_attrs);
299 return NT_STATUS_NO_SUCH_DOMAIN;
302 return NT_STATUS_NO_SUCH_DOMAIN;
305 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
309 return NT_STATUS_NO_SUCH_DOMAIN;
321 list the domains in the SAM
323 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
324 struct samr_EnumDomains *r)
326 struct samr_connect_state *c_state;
327 struct dcesrv_handle *h;
328 struct samr_SamArray *array;
331 *r->out.resume_handle = 0;
333 *r->out.num_entries = 0;
335 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
339 *r->out.resume_handle = 2;
341 start_i = *r->in.resume_handle;
344 /* search past end of list is not an error for this call */
348 array = talloc(mem_ctx, struct samr_SamArray);
350 return NT_STATUS_NO_MEMORY;
354 array->entries = NULL;
356 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
357 if (array->entries == NULL) {
358 return NT_STATUS_NO_MEMORY;
361 for (i=0;i<2-start_i;i++) {
362 array->entries[i].idx = start_i + i;
364 array->entries[i].name.string = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
366 array->entries[i].name.string = "BUILTIN";
371 *r->out.num_entries = i;
372 array->count = *r->out.num_entries;
381 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
382 struct samr_OpenDomain *r)
384 struct dcesrv_handle *h_conn, *h_domain;
385 struct samr_connect_state *c_state;
386 struct samr_domain_state *d_state;
387 const char * const dom_attrs[] = { "cn", NULL};
388 struct ldb_message **dom_msgs;
391 ZERO_STRUCTP(r->out.domain_handle);
393 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
395 c_state = h_conn->data;
397 if (r->in.sid == NULL) {
398 return NT_STATUS_INVALID_PARAMETER;
401 d_state = talloc(mem_ctx, struct samr_domain_state);
403 return NT_STATUS_NO_MEMORY;
406 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
408 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
409 d_state->builtin = true;
410 d_state->domain_name = "BUILTIN";
412 d_state->builtin = false;
413 d_state->domain_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
416 ret = gendb_search(c_state->sam_ctx,
417 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
419 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
422 talloc_free(d_state);
423 return NT_STATUS_NO_SUCH_DOMAIN;
424 } else if (ret > 1) {
425 talloc_free(d_state);
426 return NT_STATUS_INTERNAL_DB_CORRUPTION;
427 } else if (ret == -1) {
428 talloc_free(d_state);
429 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
430 return NT_STATUS_INTERNAL_DB_CORRUPTION;
433 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
434 d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
435 d_state->connect_state = talloc_reference(d_state, c_state);
436 d_state->sam_ctx = c_state->sam_ctx;
437 d_state->access_mask = r->in.access_mask;
439 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
441 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
443 talloc_free(d_state);
444 return NT_STATUS_NO_MEMORY;
447 h_domain->data = talloc_steal(h_domain, d_state);
449 *r->out.domain_handle = h_domain->wire_handle;
457 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
459 struct ldb_message **dom_msgs,
460 struct samr_DomInfo1 *info)
462 info->min_password_length =
463 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
464 info->password_history_length =
465 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
466 info->password_properties =
467 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
468 info->max_password_age =
469 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
470 info->min_password_age =
471 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
479 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
481 struct ldb_message **dom_msgs,
482 struct samr_DomGeneralInformation *info)
484 /* This pulls the NetBIOS name from the
485 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
487 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
489 if (!info->primary.string) {
490 info->primary.string = lp_netbios_name(state->lp_ctx);
493 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
494 0x8000000000000000LL);
496 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
497 info->domain_name.string = state->domain_name;
499 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
501 switch (state->role) {
502 case ROLE_DOMAIN_CONTROLLER:
503 /* This pulls the NetBIOS name from the
504 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
506 if (samdb_is_pdc(state->sam_ctx)) {
507 info->role = SAMR_ROLE_DOMAIN_PDC;
509 info->role = SAMR_ROLE_DOMAIN_BDC;
512 case ROLE_DOMAIN_MEMBER:
513 info->role = SAMR_ROLE_DOMAIN_MEMBER;
515 case ROLE_STANDALONE:
516 info->role = SAMR_ROLE_STANDALONE;
520 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
521 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
522 "(objectClass=user)");
523 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
524 "(&(objectClass=group)(sAMAccountType=%u))",
526 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
527 "(&(objectClass=group)(sAMAccountType=%u))",
536 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
538 struct ldb_message **dom_msgs,
539 struct samr_DomInfo3 *info)
541 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
542 0x8000000000000000LL);
550 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
552 struct ldb_message **dom_msgs,
553 struct samr_DomOEMInformation *info)
555 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
563 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
565 struct ldb_message **dom_msgs,
566 struct samr_DomInfo5 *info)
568 info->domain_name.string = state->domain_name;
576 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
578 struct ldb_message **dom_msgs,
579 struct samr_DomInfo6 *info)
581 /* This pulls the NetBIOS name from the
582 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
584 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
585 dom_msgs[0], "fSMORoleOwner");
587 if (!info->primary.string) {
588 info->primary.string = lp_netbios_name(state->lp_ctx);
597 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
599 struct ldb_message **dom_msgs,
600 struct samr_DomInfo7 *info)
603 switch (state->role) {
604 case ROLE_DOMAIN_CONTROLLER:
605 /* This pulls the NetBIOS name from the
606 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
608 if (samdb_is_pdc(state->sam_ctx)) {
609 info->role = SAMR_ROLE_DOMAIN_PDC;
611 info->role = SAMR_ROLE_DOMAIN_BDC;
614 case ROLE_DOMAIN_MEMBER:
615 info->role = SAMR_ROLE_DOMAIN_MEMBER;
617 case ROLE_STANDALONE:
618 info->role = SAMR_ROLE_STANDALONE;
628 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
630 struct ldb_message **dom_msgs,
631 struct samr_DomInfo8 *info)
633 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
636 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
645 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
647 struct ldb_message **dom_msgs,
648 struct samr_DomInfo9 *info)
650 info->domain_server_state = DOMAIN_SERVER_ENABLED;
658 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
660 struct ldb_message **dom_msgs,
661 struct samr_DomGeneralInformation2 *info)
664 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
665 if (!NT_STATUS_IS_OK(status)) {
669 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
671 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
673 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
681 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
683 struct ldb_message **dom_msgs,
684 struct samr_DomInfo12 *info)
686 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
688 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
690 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
698 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
700 struct ldb_message **dom_msgs,
701 struct samr_DomInfo13 *info)
703 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
706 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
709 info->modified_count_at_last_promotion = 0;
717 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
718 struct samr_QueryDomainInfo *r)
720 struct dcesrv_handle *h;
721 struct samr_domain_state *d_state;
722 union samr_DomainInfo *info;
724 struct ldb_message **dom_msgs;
725 const char * const *attrs = NULL;
729 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
733 info = talloc(mem_ctx, union samr_DomainInfo);
735 return NT_STATUS_NO_MEMORY;
738 switch (r->in.level) {
741 static const char * const attrs2[] = { "minPwdLength",
752 static const char * const attrs2[] = {"forceLogoff",
762 static const char * const attrs2[] = {"forceLogoff",
769 static const char * const attrs2[] = {"oEMInformation",
781 static const char * const attrs2[] = {"fSMORoleOwner",
793 static const char * const attrs2[] = { "modifiedCount",
806 static const char * const attrs2[] = { "oEMInformation",
810 "lockOutObservationWindow",
818 static const char * const attrs2[] = { "lockoutDuration",
819 "lockOutObservationWindow",
827 static const char * const attrs2[] = { "modifiedCount",
835 return NT_STATUS_INVALID_INFO_CLASS;
839 /* some levels don't need a search */
842 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
843 d_state->domain_dn, &dom_msgs, attrs);
845 return NT_STATUS_INTERNAL_DB_CORRUPTION;
853 switch (r->in.level) {
855 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
858 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
861 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
864 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
867 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
870 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
873 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
876 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
879 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
882 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
885 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
888 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
891 return NT_STATUS_INVALID_INFO_CLASS;
899 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
900 struct samr_SetDomainInfo *r)
902 struct dcesrv_handle *h;
903 struct samr_domain_state *d_state;
904 struct ldb_message *msg;
906 struct ldb_context *sam_ctx;
908 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
911 sam_ctx = d_state->sam_ctx;
913 msg = ldb_msg_new(mem_ctx);
915 return NT_STATUS_NO_MEMORY;
918 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
920 return NT_STATUS_NO_MEMORY;
923 switch (r->in.level) {
925 SET_UINT (msg, info1.min_password_length, "minPwdLength");
926 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
927 SET_UINT (msg, info1.password_properties, "pwdProperties");
928 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
929 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
932 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
935 SET_STRING(msg, oem.oem_information, "oEMInformation");
941 /* No op, we don't know where to set these */
946 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
947 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
948 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
952 /* many info classes are not valid for SetDomainInfo */
953 return NT_STATUS_INVALID_INFO_CLASS;
956 /* modify the samdb record */
957 ret = ldb_modify(sam_ctx, msg);
958 if (ret != LDB_SUCCESS) {
959 DEBUG(1,("Failed to modify record %s: %s\n",
960 ldb_dn_get_linearized(d_state->domain_dn),
961 ldb_errstring(sam_ctx)));
963 /* we really need samdb.c to return NTSTATUS */
964 return NT_STATUS_UNSUCCESSFUL;
971 samr_CreateDomainGroup
973 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
974 struct samr_CreateDomainGroup *r)
976 struct samr_domain_state *d_state;
977 struct samr_account_state *a_state;
978 struct dcesrv_handle *h;
980 struct ldb_message *msg;
982 const char *groupname;
983 struct dcesrv_handle *g_handle;
986 ZERO_STRUCTP(r->out.group_handle);
989 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
993 if (d_state->builtin) {
994 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
995 return NT_STATUS_ACCESS_DENIED;
998 groupname = r->in.name->string;
1000 if (groupname == NULL) {
1001 return NT_STATUS_INVALID_PARAMETER;
1004 /* check if the group already exists */
1005 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1007 "(&(sAMAccountName=%s)(objectclass=group))",
1008 ldb_binary_encode_string(mem_ctx, groupname));
1010 return NT_STATUS_GROUP_EXISTS;
1013 msg = ldb_msg_new(mem_ctx);
1015 return NT_STATUS_NO_MEMORY;
1018 /* add core elements to the ldb_message for the user */
1019 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1020 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1022 return NT_STATUS_NO_MEMORY;
1024 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1025 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1027 /* create the group */
1028 ret = ldb_add(d_state->sam_ctx, msg);
1032 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1033 DEBUG(0,("Failed to create group record %s: %s\n",
1034 ldb_dn_get_linearized(msg->dn),
1035 ldb_errstring(d_state->sam_ctx)));
1036 return NT_STATUS_GROUP_EXISTS;
1037 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1038 DEBUG(0,("Failed to create group record %s: %s\n",
1039 ldb_dn_get_linearized(msg->dn),
1040 ldb_errstring(d_state->sam_ctx)));
1041 return NT_STATUS_ACCESS_DENIED;
1043 DEBUG(0,("Failed to create group record %s: %s\n",
1044 ldb_dn_get_linearized(msg->dn),
1045 ldb_errstring(d_state->sam_ctx)));
1046 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1049 a_state = talloc(mem_ctx, struct samr_account_state);
1051 return NT_STATUS_NO_MEMORY;
1053 a_state->sam_ctx = d_state->sam_ctx;
1054 a_state->access_mask = r->in.access_mask;
1055 a_state->domain_state = talloc_reference(a_state, d_state);
1056 a_state->account_dn = talloc_steal(a_state, msg->dn);
1058 /* retrieve the sid for the group just created */
1059 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1060 msg->dn, "objectSid", NULL);
1062 return NT_STATUS_UNSUCCESSFUL;
1065 a_state->account_name = talloc_strdup(a_state, groupname);
1066 if (!a_state->account_name) {
1067 return NT_STATUS_NO_MEMORY;
1070 /* create the policy handle */
1071 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1073 return NT_STATUS_NO_MEMORY;
1076 g_handle->data = talloc_steal(g_handle, a_state);
1078 *r->out.group_handle = g_handle->wire_handle;
1079 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1081 return NT_STATUS_OK;
1086 comparison function for sorting SamEntry array
1088 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1090 return e1->idx - e2->idx;
1094 samr_EnumDomainGroups
1096 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1097 struct samr_EnumDomainGroups *r)
1099 struct dcesrv_handle *h;
1100 struct samr_domain_state *d_state;
1101 struct ldb_message **res;
1102 int ldb_cnt, count, i, first;
1103 struct samr_SamEntry *entries;
1104 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1105 struct samr_SamArray *sam;
1107 *r->out.resume_handle = 0;
1109 *r->out.num_entries = 0;
1111 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1115 /* search for all domain groups in this domain. This could possibly be
1116 cached and resumed based on resume_key */
1117 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1118 d_state->domain_dn, &res, attrs,
1119 d_state->domain_sid,
1120 "(&(grouptype=%d)(objectclass=group))",
1121 GTYPE_SECURITY_GLOBAL_GROUP);
1122 if (ldb_cnt == -1) {
1123 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1126 /* convert to SamEntry format */
1127 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1129 return NT_STATUS_NO_MEMORY;
1134 for (i=0;i<ldb_cnt;i++) {
1135 struct dom_sid *group_sid;
1137 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1139 if (group_sid == NULL)
1142 entries[count].idx =
1143 group_sid->sub_auths[group_sid->num_auths-1];
1144 entries[count].name.string =
1145 samdb_result_string(res[i], "sAMAccountName", "");
1149 /* sort the results by rid */
1150 qsort(entries, count, sizeof(struct samr_SamEntry),
1151 (comparison_fn_t)compare_SamEntry);
1153 /* find the first entry to return */
1155 first<count && entries[first].idx <= *r->in.resume_handle;
1158 /* return the rest, limit by max_size. Note that we
1159 use the w2k3 element size value of 54 */
1160 *r->out.num_entries = count - first;
1161 *r->out.num_entries = MIN(*r->out.num_entries,
1162 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1164 sam = talloc(mem_ctx, struct samr_SamArray);
1166 return NT_STATUS_NO_MEMORY;
1169 sam->entries = entries+first;
1170 sam->count = *r->out.num_entries;
1174 if (*r->out.num_entries < count - first) {
1175 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1176 return STATUS_MORE_ENTRIES;
1179 return NT_STATUS_OK;
1186 This call uses transactions to ensure we don't get a new conflicting
1187 user while we are processing this, and to ensure the user either
1188 completly exists, or does not.
1190 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1191 struct samr_CreateUser2 *r)
1193 struct samr_domain_state *d_state;
1194 struct samr_account_state *a_state;
1195 struct dcesrv_handle *h;
1197 struct ldb_message *msg;
1198 struct dom_sid *sid;
1199 const char *account_name;
1200 struct dcesrv_handle *u_handle;
1202 const char *container, *obj_class=NULL;
1206 const char *attrs[] = {
1208 "userAccountControl",
1212 uint32_t user_account_control;
1214 struct ldb_message **msgs;
1216 ZERO_STRUCTP(r->out.user_handle);
1217 *r->out.access_granted = 0;
1220 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1224 if (d_state->builtin) {
1225 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1226 return NT_STATUS_ACCESS_DENIED;
1227 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1228 /* Domain trust accounts must be created by the LSA calls */
1229 return NT_STATUS_ACCESS_DENIED;
1231 account_name = r->in.account_name->string;
1233 if (account_name == NULL) {
1234 return NT_STATUS_INVALID_PARAMETER;
1238 * Start a transaction, so we can query and do a subsequent atomic
1242 ret = ldb_transaction_start(d_state->sam_ctx);
1243 if (ret != LDB_SUCCESS) {
1244 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1245 ldb_errstring(d_state->sam_ctx)));
1246 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1249 /* check if the user already exists */
1250 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1252 "(&(sAMAccountName=%s)(objectclass=user))",
1253 ldb_binary_encode_string(mem_ctx, account_name));
1255 ldb_transaction_cancel(d_state->sam_ctx);
1256 return NT_STATUS_USER_EXISTS;
1259 msg = ldb_msg_new(mem_ctx);
1261 ldb_transaction_cancel(d_state->sam_ctx);
1262 return NT_STATUS_NO_MEMORY;
1265 cn_name = talloc_strdup(mem_ctx, account_name);
1267 ldb_transaction_cancel(d_state->sam_ctx);
1268 return NT_STATUS_NO_MEMORY;
1271 cn_name_len = strlen(cn_name);
1273 /* This must be one of these values *only* */
1274 if (r->in.acct_flags == ACB_NORMAL) {
1275 container = "CN=Users";
1278 } else if (r->in.acct_flags == ACB_WSTRUST) {
1279 if (cn_name[cn_name_len - 1] != '$') {
1280 ldb_transaction_cancel(d_state->sam_ctx);
1281 return NT_STATUS_FOOBAR;
1283 cn_name[cn_name_len - 1] = '\0';
1284 container = "CN=Computers";
1285 obj_class = "computer";
1286 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1287 "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1289 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1290 if (cn_name[cn_name_len - 1] != '$') {
1291 ldb_transaction_cancel(d_state->sam_ctx);
1292 return NT_STATUS_FOOBAR;
1294 cn_name[cn_name_len - 1] = '\0';
1295 container = "OU=Domain Controllers";
1296 obj_class = "computer";
1297 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1298 "primaryGroupID", DOMAIN_RID_DCS);
1300 ldb_transaction_cancel(d_state->sam_ctx);
1301 return NT_STATUS_INVALID_PARAMETER;
1304 /* add core elements to the ldb_message for the user */
1305 msg->dn = ldb_dn_copy(msg, d_state->domain_dn);
1306 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1307 ldb_transaction_cancel(d_state->sam_ctx);
1308 return NT_STATUS_FOOBAR;
1311 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName",
1313 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass",
1316 /* create the user */
1317 ret = ldb_add(d_state->sam_ctx, msg);
1321 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1322 ldb_transaction_cancel(d_state->sam_ctx);
1323 DEBUG(0,("Failed to create user record %s: %s\n",
1324 ldb_dn_get_linearized(msg->dn),
1325 ldb_errstring(d_state->sam_ctx)));
1326 return NT_STATUS_USER_EXISTS;
1327 case LDB_ERR_UNWILLING_TO_PERFORM:
1328 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1329 ldb_transaction_cancel(d_state->sam_ctx);
1330 DEBUG(0,("Failed to create user record %s: %s\n",
1331 ldb_dn_get_linearized(msg->dn),
1332 ldb_errstring(d_state->sam_ctx)));
1333 return NT_STATUS_ACCESS_DENIED;
1335 ldb_transaction_cancel(d_state->sam_ctx);
1336 DEBUG(0,("Failed to create user record %s: %s\n",
1337 ldb_dn_get_linearized(msg->dn),
1338 ldb_errstring(d_state->sam_ctx)));
1339 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1342 a_state = talloc(mem_ctx, struct samr_account_state);
1344 ldb_transaction_cancel(d_state->sam_ctx);
1345 return NT_STATUS_NO_MEMORY;
1347 a_state->sam_ctx = d_state->sam_ctx;
1348 a_state->access_mask = r->in.access_mask;
1349 a_state->domain_state = talloc_reference(a_state, d_state);
1350 a_state->account_dn = talloc_steal(a_state, msg->dn);
1352 /* retrieve the sid and account control bits for the user just created */
1353 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
1354 msg->dn, &msgs, attrs);
1357 ldb_transaction_cancel(d_state->sam_ctx);
1358 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1359 ldb_dn_get_linearized(msg->dn)));
1360 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1362 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1364 ldb_transaction_cancel(d_state->sam_ctx);
1365 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1366 ldb_dn_get_linearized(msg->dn)));
1367 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1370 /* Change the account control to be the correct account type.
1371 * The default is for a workstation account */
1372 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1373 user_account_control = (user_account_control &
1374 ~(UF_NORMAL_ACCOUNT |
1375 UF_INTERDOMAIN_TRUST_ACCOUNT |
1376 UF_WORKSTATION_TRUST_ACCOUNT |
1377 UF_SERVER_TRUST_ACCOUNT));
1378 user_account_control |= ds_acb2uf(r->in.acct_flags);
1381 msg = ldb_msg_new(mem_ctx);
1383 ldb_transaction_cancel(d_state->sam_ctx);
1384 return NT_STATUS_NO_MEMORY;
1387 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1389 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1390 "userAccountControl",
1391 user_account_control) != 0) {
1392 ldb_transaction_cancel(d_state->sam_ctx);
1393 return NT_STATUS_NO_MEMORY;
1396 /* modify the samdb record */
1397 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1398 if (ret != LDB_SUCCESS) {
1399 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1400 ldb_dn_get_linearized(msg->dn),
1401 ldb_errstring(d_state->sam_ctx)));
1402 ldb_transaction_cancel(d_state->sam_ctx);
1404 /* we really need samdb.c to return NTSTATUS */
1405 return NT_STATUS_UNSUCCESSFUL;
1408 ret = ldb_transaction_commit(d_state->sam_ctx);
1409 if (ret != LDB_SUCCESS) {
1410 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1411 ldb_dn_get_linearized(msg->dn),
1412 ldb_errstring(d_state->sam_ctx)));
1413 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1416 a_state->account_name = talloc_steal(a_state, account_name);
1417 if (!a_state->account_name) {
1418 return NT_STATUS_NO_MEMORY;
1421 /* create the policy handle */
1422 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1424 return NT_STATUS_NO_MEMORY;
1427 u_handle->data = talloc_steal(u_handle, a_state);
1429 *r->out.user_handle = u_handle->wire_handle;
1430 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1432 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1434 return NT_STATUS_OK;
1441 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1442 struct samr_CreateUser *r)
1444 struct samr_CreateUser2 r2;
1445 uint32_t access_granted = 0;
1448 /* a simple wrapper around samr_CreateUser2 works nicely */
1449 r2.in.domain_handle = r->in.domain_handle;
1450 r2.in.account_name = r->in.account_name;
1451 r2.in.acct_flags = ACB_NORMAL;
1452 r2.in.access_mask = r->in.access_mask;
1453 r2.out.user_handle = r->out.user_handle;
1454 r2.out.access_granted = &access_granted;
1455 r2.out.rid = r->out.rid;
1457 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1461 samr_EnumDomainUsers
1463 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1464 struct samr_EnumDomainUsers *r)
1466 struct dcesrv_handle *h;
1467 struct samr_domain_state *d_state;
1468 struct ldb_result *res;
1469 int ret, num_filtered_entries, i, first;
1470 struct samr_SamEntry *entries;
1471 const char * const attrs[] = { "objectSid", "sAMAccountName",
1472 "userAccountControl", NULL };
1473 struct samr_SamArray *sam;
1475 *r->out.resume_handle = 0;
1477 *r->out.num_entries = 0;
1479 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1483 /* don't have to worry about users in the builtin domain, as there are none */
1484 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1486 if (ret != LDB_SUCCESS) {
1487 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1488 ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1489 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1492 /* convert to SamEntry format */
1493 entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1495 return NT_STATUS_NO_MEMORY;
1497 num_filtered_entries = 0;
1498 for (i=0;i<res->count;i++) {
1499 /* Check if a mask has been requested */
1500 if (r->in.acct_flags
1501 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i],
1502 d_state->domain_dn) & r->in.acct_flags) == 0)) {
1505 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1506 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1507 num_filtered_entries++;
1510 /* sort the results by rid */
1511 qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry),
1512 (comparison_fn_t)compare_SamEntry);
1514 /* find the first entry to return */
1516 first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1519 /* return the rest, limit by max_size. Note that we
1520 use the w2k3 element size value of 54 */
1521 *r->out.num_entries = num_filtered_entries - first;
1522 *r->out.num_entries = MIN(*r->out.num_entries,
1523 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1525 sam = talloc(mem_ctx, struct samr_SamArray);
1527 return NT_STATUS_NO_MEMORY;
1530 sam->entries = entries+first;
1531 sam->count = *r->out.num_entries;
1535 if (first == num_filtered_entries) {
1536 return NT_STATUS_OK;
1539 if (*r->out.num_entries < num_filtered_entries - first) {
1540 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1541 return STATUS_MORE_ENTRIES;
1544 return NT_STATUS_OK;
1551 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1552 struct samr_CreateDomAlias *r)
1554 struct samr_domain_state *d_state;
1555 struct samr_account_state *a_state;
1556 struct dcesrv_handle *h;
1557 const char *alias_name, *name;
1558 struct ldb_message *msg;
1559 struct dom_sid *sid;
1560 struct dcesrv_handle *a_handle;
1563 ZERO_STRUCTP(r->out.alias_handle);
1566 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1570 if (d_state->builtin) {
1571 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1572 return NT_STATUS_ACCESS_DENIED;
1575 alias_name = r->in.alias_name->string;
1577 if (alias_name == NULL) {
1578 return NT_STATUS_INVALID_PARAMETER;
1581 /* Check if alias already exists */
1582 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1584 "(sAMAccountName=%s)(objectclass=group))",
1585 ldb_binary_encode_string(mem_ctx, alias_name));
1588 return NT_STATUS_ALIAS_EXISTS;
1591 msg = ldb_msg_new(mem_ctx);
1593 return NT_STATUS_NO_MEMORY;
1596 /* add core elements to the ldb_message for the alias */
1597 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1598 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1600 return NT_STATUS_NO_MEMORY;
1603 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1604 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1605 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1607 /* create the alias */
1608 ret = ldb_add(d_state->sam_ctx, msg);
1612 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1613 return NT_STATUS_ALIAS_EXISTS;
1614 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1615 return NT_STATUS_ACCESS_DENIED;
1617 DEBUG(0,("Failed to create alias record %s: %s\n",
1618 ldb_dn_get_linearized(msg->dn),
1619 ldb_errstring(d_state->sam_ctx)));
1620 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1623 a_state = talloc(mem_ctx, struct samr_account_state);
1625 return NT_STATUS_NO_MEMORY;
1628 a_state->sam_ctx = d_state->sam_ctx;
1629 a_state->access_mask = r->in.access_mask;
1630 a_state->domain_state = talloc_reference(a_state, d_state);
1631 a_state->account_dn = talloc_steal(a_state, msg->dn);
1633 /* retrieve the sid for the alias just created */
1634 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1635 msg->dn, "objectSid", NULL);
1637 a_state->account_name = talloc_strdup(a_state, alias_name);
1638 if (!a_state->account_name) {
1639 return NT_STATUS_NO_MEMORY;
1642 /* create the policy handle */
1643 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1644 if (a_handle == NULL)
1645 return NT_STATUS_NO_MEMORY;
1647 a_handle->data = talloc_steal(a_handle, a_state);
1649 *r->out.alias_handle = a_handle->wire_handle;
1651 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1653 return NT_STATUS_OK;
1658 samr_EnumDomainAliases
1660 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1661 struct samr_EnumDomainAliases *r)
1663 struct dcesrv_handle *h;
1664 struct samr_domain_state *d_state;
1665 struct ldb_message **res;
1666 int ldb_cnt, count, i, first;
1667 struct samr_SamEntry *entries;
1668 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1669 struct samr_SamArray *sam;
1671 *r->out.resume_handle = 0;
1673 *r->out.num_entries = 0;
1675 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1679 /* search for all domain groups in this domain. This could possibly be
1680 cached and resumed based on resume_key */
1681 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1684 d_state->domain_sid,
1685 "(&(|(grouptype=%d)(grouptype=%d)))"
1686 "(objectclass=group))",
1687 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1688 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1689 if (ldb_cnt == -1) {
1690 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1693 return NT_STATUS_OK;
1696 /* convert to SamEntry format */
1697 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1699 return NT_STATUS_NO_MEMORY;
1704 for (i=0;i<ldb_cnt;i++) {
1705 struct dom_sid *alias_sid;
1707 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1710 if (alias_sid == NULL)
1713 entries[count].idx =
1714 alias_sid->sub_auths[alias_sid->num_auths-1];
1715 entries[count].name.string =
1716 samdb_result_string(res[i], "sAMAccountName", "");
1720 /* sort the results by rid */
1721 qsort(entries, count, sizeof(struct samr_SamEntry),
1722 (comparison_fn_t)compare_SamEntry);
1724 /* find the first entry to return */
1726 first<count && entries[first].idx <= *r->in.resume_handle;
1729 if (first == count) {
1730 return NT_STATUS_OK;
1733 *r->out.num_entries = count - first;
1734 *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1736 sam = talloc(mem_ctx, struct samr_SamArray);
1738 return NT_STATUS_NO_MEMORY;
1741 sam->entries = entries+first;
1742 sam->count = *r->out.num_entries;
1746 if (*r->out.num_entries < count - first) {
1747 *r->out.resume_handle =
1748 entries[first+*r->out.num_entries-1].idx;
1749 return STATUS_MORE_ENTRIES;
1752 return NT_STATUS_OK;
1757 samr_GetAliasMembership
1759 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1760 struct samr_GetAliasMembership *r)
1762 struct dcesrv_handle *h;
1763 struct samr_domain_state *d_state;
1764 struct ldb_message **res;
1767 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1771 if (r->in.sids->num_sids > 0) {
1773 const char * const attrs[2] = { "objectSid", NULL };
1775 filter = talloc_asprintf(mem_ctx,
1776 "(&(|(grouptype=%d)(grouptype=%d))"
1777 "(objectclass=group)(|",
1778 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1779 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1781 return NT_STATUS_NO_MEMORY;
1783 for (i=0; i<r->in.sids->num_sids; i++) {
1784 const char *memberdn;
1787 samdb_search_string(d_state->sam_ctx,
1789 "distinguishedName",
1791 ldap_encode_ndr_dom_sid(mem_ctx,
1792 r->in.sids->sids[i].sid));
1794 if (memberdn == NULL)
1797 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1800 return NT_STATUS_NO_MEMORY;
1803 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1804 d_state->domain_dn, &res, attrs,
1805 d_state->domain_sid, "%s))", filter);
1807 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1810 r->out.rids->count = 0;
1811 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1812 if (r->out.rids->ids == NULL)
1813 return NT_STATUS_NO_MEMORY;
1815 for (i=0; i<count; i++) {
1816 struct dom_sid *alias_sid;
1818 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1820 if (alias_sid == NULL) {
1821 DEBUG(0, ("Could not find objectSid\n"));
1825 r->out.rids->ids[r->out.rids->count] =
1826 alias_sid->sub_auths[alias_sid->num_auths-1];
1827 r->out.rids->count += 1;
1830 return NT_STATUS_OK;
1837 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1838 struct samr_LookupNames *r)
1840 struct dcesrv_handle *h;
1841 struct samr_domain_state *d_state;
1843 NTSTATUS status = NT_STATUS_OK;
1844 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1847 ZERO_STRUCTP(r->out.rids);
1848 ZERO_STRUCTP(r->out.types);
1850 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1854 if (r->in.num_names == 0) {
1855 return NT_STATUS_OK;
1858 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1859 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1860 if (!r->out.rids->ids || !r->out.types->ids) {
1861 return NT_STATUS_NO_MEMORY;
1863 r->out.rids->count = r->in.num_names;
1864 r->out.types->count = r->in.num_names;
1868 for (i=0;i<r->in.num_names;i++) {
1869 struct ldb_message **res;
1870 struct dom_sid *sid;
1871 uint32_t atype, rtype;
1873 r->out.rids->ids[i] = 0;
1874 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1876 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1877 "sAMAccountName=%s",
1878 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1880 status = STATUS_SOME_UNMAPPED;
1884 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1886 status = STATUS_SOME_UNMAPPED;
1890 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1892 status = STATUS_SOME_UNMAPPED;
1896 rtype = ds_atype_map(atype);
1898 if (rtype == SID_NAME_UNKNOWN) {
1899 status = STATUS_SOME_UNMAPPED;
1903 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1904 r->out.types->ids[i] = rtype;
1908 if (num_mapped == 0) {
1909 return NT_STATUS_NONE_MAPPED;
1918 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1919 struct samr_LookupRids *r)
1921 struct dcesrv_handle *h;
1922 struct samr_domain_state *d_state;
1924 NTSTATUS status = NT_STATUS_OK;
1925 struct lsa_String *names;
1928 ZERO_STRUCTP(r->out.names);
1929 ZERO_STRUCTP(r->out.types);
1931 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1935 if (r->in.num_rids == 0)
1936 return NT_STATUS_OK;
1938 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1939 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1941 if ((names == NULL) || (ids == NULL))
1942 return NT_STATUS_NO_MEMORY;
1946 for (i=0; i<r->in.num_rids; i++) {
1947 struct ldb_message **res;
1949 const char * const attrs[] = { "sAMAccountType",
1950 "sAMAccountName", NULL };
1952 struct dom_sid *sid;
1954 ids[i] = SID_NAME_UNKNOWN;
1956 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid,
1959 names[i].string = NULL;
1960 status = STATUS_SOME_UNMAPPED;
1964 count = gendb_search(d_state->sam_ctx, mem_ctx,
1965 d_state->domain_dn, &res, attrs,
1967 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1969 names[i].string = NULL;
1970 status = STATUS_SOME_UNMAPPED;
1974 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1977 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1979 status = STATUS_SOME_UNMAPPED;
1983 ids[i] = ds_atype_map(atype);
1985 if (ids[i] == SID_NAME_UNKNOWN) {
1986 status = STATUS_SOME_UNMAPPED;
1991 r->out.names->names = names;
1992 r->out.names->count = r->in.num_rids;
1994 r->out.types->ids = ids;
1995 r->out.types->count = r->in.num_rids;
2004 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2005 struct samr_OpenGroup *r)
2007 struct samr_domain_state *d_state;
2008 struct samr_account_state *a_state;
2009 struct dcesrv_handle *h;
2010 const char *groupname;
2011 struct dom_sid *sid;
2012 struct ldb_message **msgs;
2013 struct dcesrv_handle *g_handle;
2014 const char * const attrs[2] = { "sAMAccountName", NULL };
2017 ZERO_STRUCTP(r->out.group_handle);
2019 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2023 /* form the group SID */
2024 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2026 return NT_STATUS_NO_MEMORY;
2029 /* search for the group record */
2030 ret = gendb_search(d_state->sam_ctx,
2031 mem_ctx, d_state->domain_dn, &msgs, attrs,
2032 "(&(objectSid=%s)(objectclass=group)"
2034 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2035 GTYPE_SECURITY_GLOBAL_GROUP);
2037 return NT_STATUS_NO_SUCH_GROUP;
2040 DEBUG(0,("Found %d records matching sid %s\n",
2041 ret, dom_sid_string(mem_ctx, sid)));
2042 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2045 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2046 if (groupname == NULL) {
2047 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2048 dom_sid_string(mem_ctx, sid)));
2049 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2052 a_state = talloc(mem_ctx, struct samr_account_state);
2054 return NT_STATUS_NO_MEMORY;
2056 a_state->sam_ctx = d_state->sam_ctx;
2057 a_state->access_mask = r->in.access_mask;
2058 a_state->domain_state = talloc_reference(a_state, d_state);
2059 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2060 a_state->account_sid = talloc_steal(a_state, sid);
2061 a_state->account_name = talloc_strdup(a_state, groupname);
2062 if (!a_state->account_name) {
2063 return NT_STATUS_NO_MEMORY;
2066 /* create the policy handle */
2067 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2069 return NT_STATUS_NO_MEMORY;
2072 g_handle->data = talloc_steal(g_handle, a_state);
2074 *r->out.group_handle = g_handle->wire_handle;
2076 return NT_STATUS_OK;
2082 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2083 struct samr_QueryGroupInfo *r)
2085 struct dcesrv_handle *h;
2086 struct samr_account_state *a_state;
2087 struct ldb_message *msg;
2088 struct ldb_result *res;
2089 const char * const attrs[4] = { "sAMAccountName", "description",
2090 "numMembers", NULL };
2092 union samr_GroupInfo *info;
2094 *r->out.info = NULL;
2096 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2100 ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn,
2101 LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2103 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2104 return NT_STATUS_NO_SUCH_GROUP;
2105 } else if (ret != LDB_SUCCESS) {
2106 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2107 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2110 if (res->count != 1) {
2111 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2113 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2117 /* allocate the info structure */
2118 info = talloc_zero(mem_ctx, union samr_GroupInfo);
2120 return NT_STATUS_NO_MEMORY;
2123 /* Fill in the level */
2124 switch (r->in.level) {
2126 QUERY_STRING(msg, all.name, "sAMAccountName");
2127 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2128 QUERY_UINT (msg, all.num_members, "numMembers")
2129 QUERY_STRING(msg, all.description, "description");
2132 QUERY_STRING(msg, name, "sAMAccountName");
2134 case GROUPINFOATTRIBUTES:
2135 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2137 case GROUPINFODESCRIPTION:
2138 QUERY_STRING(msg, description, "description");
2141 QUERY_STRING(msg, all2.name, "sAMAccountName");
2142 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2143 QUERY_UINT (msg, all2.num_members, "numMembers")
2144 QUERY_STRING(msg, all2.description, "description");
2148 return NT_STATUS_INVALID_INFO_CLASS;
2151 *r->out.info = info;
2153 return NT_STATUS_OK;
2160 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2161 struct samr_SetGroupInfo *r)
2163 struct dcesrv_handle *h;
2164 struct samr_account_state *g_state;
2165 struct ldb_message *msg;
2166 struct ldb_context *sam_ctx;
2169 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2172 sam_ctx = g_state->sam_ctx;
2174 msg = ldb_msg_new(mem_ctx);
2176 return NT_STATUS_NO_MEMORY;
2179 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2181 return NT_STATUS_NO_MEMORY;
2184 switch (r->in.level) {
2185 case GROUPINFODESCRIPTION:
2186 SET_STRING(msg, description, "description");
2189 /* On W2k3 this does not change the name, it changes the
2190 * sAMAccountName attribute */
2191 SET_STRING(msg, name, "sAMAccountName");
2193 case GROUPINFOATTRIBUTES:
2194 /* This does not do anything obviously visible in W2k3 LDAP */
2195 return NT_STATUS_OK;
2197 return NT_STATUS_INVALID_INFO_CLASS;
2200 /* modify the samdb record */
2201 ret = ldb_modify(g_state->sam_ctx, msg);
2202 if (ret != LDB_SUCCESS) {
2203 /* we really need samdb.c to return NTSTATUS */
2204 return NT_STATUS_UNSUCCESSFUL;
2207 return NT_STATUS_OK;
2214 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2215 struct samr_AddGroupMember *r)
2217 struct dcesrv_handle *h;
2218 struct samr_account_state *a_state;
2219 struct samr_domain_state *d_state;
2220 struct ldb_message *mod;
2221 struct dom_sid *membersid;
2222 const char *memberdn;
2223 struct ldb_result *res;
2224 const char * const attrs[] = { NULL };
2227 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2230 d_state = a_state->domain_state;
2232 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2233 if (membersid == NULL) {
2234 return NT_STATUS_NO_MEMORY;
2237 /* In native mode, AD can also nest domain groups. Not sure yet
2238 * whether this is also available via RPC. */
2239 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2240 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2241 "(&(objectSid=%s)(objectclass=user))",
2242 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2244 if (ret != LDB_SUCCESS) {
2245 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2248 if (res->count == 0) {
2249 return NT_STATUS_NO_SUCH_USER;
2252 if (res->count > 1) {
2253 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2256 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2258 if (memberdn == NULL)
2259 return NT_STATUS_NO_MEMORY;
2261 mod = ldb_msg_new(mem_ctx);
2263 return NT_STATUS_NO_MEMORY;
2266 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2268 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2270 if (ret != LDB_SUCCESS) {
2271 return NT_STATUS_UNSUCCESSFUL;
2274 ret = ldb_modify(a_state->sam_ctx, mod);
2277 return NT_STATUS_OK;
2278 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2279 return NT_STATUS_MEMBER_IN_GROUP;
2280 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2281 return NT_STATUS_ACCESS_DENIED;
2283 return NT_STATUS_UNSUCCESSFUL;
2289 samr_DeleteDomainGroup
2291 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2292 struct samr_DeleteDomainGroup *r)
2294 struct dcesrv_handle *h;
2295 struct samr_account_state *a_state;
2298 *r->out.group_handle = *r->in.group_handle;
2300 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2304 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2305 if (ret != LDB_SUCCESS) {
2306 return NT_STATUS_UNSUCCESSFUL;
2310 ZERO_STRUCTP(r->out.group_handle);
2312 return NT_STATUS_OK;
2317 samr_DeleteGroupMember
2319 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2320 struct samr_DeleteGroupMember *r)
2322 struct dcesrv_handle *h;
2323 struct samr_account_state *a_state;
2324 struct samr_domain_state *d_state;
2325 struct ldb_message *mod;
2326 struct dom_sid *membersid;
2327 const char *memberdn;
2328 struct ldb_result *res;
2329 const char * const attrs[] = { NULL };
2332 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2335 d_state = a_state->domain_state;
2337 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2338 if (membersid == NULL)
2339 return NT_STATUS_NO_MEMORY;
2341 /* In native mode, AD can also nest domain groups. Not sure yet
2342 * whether this is also available via RPC. */
2343 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2344 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2345 "(&(objectSid=%s)(objectclass=user))",
2346 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2348 if (ret != LDB_SUCCESS) {
2349 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2352 if (res->count == 0) {
2353 return NT_STATUS_NO_SUCH_USER;
2356 if (res->count > 1) {
2357 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2360 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2362 if (memberdn == NULL)
2363 return NT_STATUS_NO_MEMORY;
2365 mod = ldb_msg_new(mem_ctx);
2367 return NT_STATUS_NO_MEMORY;
2370 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2372 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2374 if (ret != LDB_SUCCESS) {
2375 return NT_STATUS_NO_MEMORY;
2378 ret = ldb_modify(a_state->sam_ctx, mod);
2381 return NT_STATUS_OK;
2382 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2383 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2384 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2385 return NT_STATUS_ACCESS_DENIED;
2387 return NT_STATUS_UNSUCCESSFUL;
2393 samr_QueryGroupMember
2395 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2396 struct samr_QueryGroupMember *r)
2398 struct dcesrv_handle *h;
2399 struct samr_account_state *a_state;
2400 struct ldb_message **res;
2401 struct ldb_message_element *el;
2402 struct samr_RidTypeArray *array;
2403 const char * const attrs[2] = { "member", NULL };
2406 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2410 /* pull the member attribute */
2411 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2412 a_state->account_dn, &res, attrs);
2415 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2418 array = talloc(mem_ctx, struct samr_RidTypeArray);
2421 return NT_STATUS_NO_MEMORY;
2423 ZERO_STRUCTP(array);
2425 el = ldb_msg_find_element(res[0], "member");
2430 array->count = el->num_values;
2432 array->rids = talloc_array(mem_ctx, uint32_t,
2434 if (array->rids == NULL)
2435 return NT_STATUS_NO_MEMORY;
2437 array->types = talloc_array(mem_ctx, uint32_t,
2439 if (array->types == NULL)
2440 return NT_STATUS_NO_MEMORY;
2442 for (i=0; i<el->num_values; i++) {
2443 struct ldb_message **res2;
2444 const char * const attrs2[2] = { "objectSid", NULL };
2445 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2446 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2449 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2452 samdb_result_rid_from_sid(mem_ctx, res2[0],
2455 if (array->rids[i] == 0)
2456 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2458 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2462 *r->out.rids = array;
2464 return NT_STATUS_OK;
2469 samr_SetMemberAttributesOfGroup
2471 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2472 struct samr_SetMemberAttributesOfGroup *r)
2474 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2481 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2482 struct samr_OpenAlias *r)
2484 struct samr_domain_state *d_state;
2485 struct samr_account_state *a_state;
2486 struct dcesrv_handle *h;
2487 const char *alias_name;
2488 struct dom_sid *sid;
2489 struct ldb_message **msgs;
2490 struct dcesrv_handle *g_handle;
2491 const char * const attrs[2] = { "sAMAccountName", NULL };
2494 ZERO_STRUCTP(r->out.alias_handle);
2496 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2500 /* form the alias SID */
2501 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2503 return NT_STATUS_NO_MEMORY;
2505 /* search for the group record */
2506 ret = gendb_search(d_state->sam_ctx,
2507 mem_ctx, d_state->domain_dn, &msgs, attrs,
2508 "(&(objectSid=%s)(objectclass=group)"
2509 "(|(grouptype=%d)(grouptype=%d)))",
2510 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2511 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2512 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2514 return NT_STATUS_NO_SUCH_ALIAS;
2517 DEBUG(0,("Found %d records matching sid %s\n",
2518 ret, dom_sid_string(mem_ctx, sid)));
2519 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2522 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2523 if (alias_name == NULL) {
2524 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2525 dom_sid_string(mem_ctx, sid)));
2526 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2529 a_state = talloc(mem_ctx, struct samr_account_state);
2531 return NT_STATUS_NO_MEMORY;
2533 a_state->sam_ctx = d_state->sam_ctx;
2534 a_state->access_mask = r->in.access_mask;
2535 a_state->domain_state = talloc_reference(a_state, d_state);
2536 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2537 a_state->account_sid = talloc_steal(a_state, sid);
2538 a_state->account_name = talloc_strdup(a_state, alias_name);
2539 if (!a_state->account_name) {
2540 return NT_STATUS_NO_MEMORY;
2543 /* create the policy handle */
2544 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2546 return NT_STATUS_NO_MEMORY;
2549 g_handle->data = talloc_steal(g_handle, a_state);
2551 *r->out.alias_handle = g_handle->wire_handle;
2553 return NT_STATUS_OK;
2560 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2561 struct samr_QueryAliasInfo *r)
2563 struct dcesrv_handle *h;
2564 struct samr_account_state *a_state;
2565 struct ldb_message *msg, **res;
2566 const char * const attrs[4] = { "sAMAccountName", "description",
2567 "numMembers", NULL };
2569 union samr_AliasInfo *info;
2571 *r->out.info = NULL;
2573 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2577 /* pull all the alias attributes */
2578 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2579 a_state->account_dn ,&res, attrs);
2581 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2585 /* allocate the info structure */
2586 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2588 return NT_STATUS_NO_MEMORY;
2591 switch(r->in.level) {
2593 QUERY_STRING(msg, all.name, "sAMAccountName");
2594 QUERY_UINT (msg, all.num_members, "numMembers");
2595 QUERY_STRING(msg, all.description, "description");
2598 QUERY_STRING(msg, name, "sAMAccountName");
2600 case ALIASINFODESCRIPTION:
2601 QUERY_STRING(msg, description, "description");
2605 return NT_STATUS_INVALID_INFO_CLASS;
2608 *r->out.info = info;
2610 return NT_STATUS_OK;
2617 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2618 struct samr_SetAliasInfo *r)
2620 struct dcesrv_handle *h;
2621 struct samr_account_state *a_state;
2622 struct ldb_message *msg;
2623 struct ldb_context *sam_ctx;
2626 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2629 sam_ctx = a_state->sam_ctx;
2631 msg = ldb_msg_new(mem_ctx);
2633 return NT_STATUS_NO_MEMORY;
2636 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2638 return NT_STATUS_NO_MEMORY;
2641 switch (r->in.level) {
2642 case ALIASINFODESCRIPTION:
2643 SET_STRING(msg, description, "description");
2646 /* On W2k3 this does not change the name, it changes the
2647 * sAMAccountName attribute */
2648 SET_STRING(msg, name, "sAMAccountName");
2651 return NT_STATUS_INVALID_INFO_CLASS;
2654 /* modify the samdb record */
2655 ret = ldb_modify(a_state->sam_ctx, msg);
2656 if (ret != LDB_SUCCESS) {
2657 /* we really need samdb.c to return NTSTATUS */
2658 return NT_STATUS_UNSUCCESSFUL;
2661 return NT_STATUS_OK;
2668 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2669 struct samr_DeleteDomAlias *r)
2671 struct dcesrv_handle *h;
2672 struct samr_account_state *a_state;
2675 *r->out.alias_handle = *r->in.alias_handle;
2677 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2681 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2683 return NT_STATUS_UNSUCCESSFUL;
2687 ZERO_STRUCTP(r->out.alias_handle);
2689 return NT_STATUS_OK;
2696 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2697 struct samr_AddAliasMember *r)
2699 struct dcesrv_handle *h;
2700 struct samr_account_state *a_state;
2701 struct samr_domain_state *d_state;
2702 struct ldb_message *mod;
2703 struct ldb_message **msgs;
2704 const char * const attrs[] = { NULL };
2705 struct ldb_dn *memberdn = NULL;
2709 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2712 d_state = a_state->domain_state;
2714 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2715 &msgs, attrs, "(objectsid=%s)",
2716 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2719 memberdn = msgs[0]->dn;
2720 } else if (ret > 1) {
2721 DEBUG(0,("Found %d records matching sid %s\n",
2722 ret, dom_sid_string(mem_ctx, r->in.sid)));
2723 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2724 } else if (ret == 0) {
2725 status = samdb_create_foreign_security_principal(
2726 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2727 if (!NT_STATUS_IS_OK(status)) {
2731 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2734 if (memberdn == NULL) {
2735 DEBUG(0, ("Could not find memberdn\n"));
2736 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2739 mod = ldb_msg_new(mem_ctx);
2741 return NT_STATUS_NO_MEMORY;
2744 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2746 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2747 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2748 if (ret != LDB_SUCCESS) {
2749 return NT_STATUS_UNSUCCESSFUL;
2752 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2753 return NT_STATUS_UNSUCCESSFUL;
2756 return NT_STATUS_OK;
2761 samr_DeleteAliasMember
2763 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2764 struct samr_DeleteAliasMember *r)
2766 struct dcesrv_handle *h;
2767 struct samr_account_state *a_state;
2768 struct samr_domain_state *d_state;
2769 struct ldb_message *mod;
2770 const char *memberdn;
2773 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2776 d_state = a_state->domain_state;
2778 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2779 "distinguishedName", "(objectSid=%s)",
2780 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2782 if (memberdn == NULL)
2783 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2785 mod = ldb_msg_new(mem_ctx);
2787 return NT_STATUS_NO_MEMORY;
2790 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2792 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2794 if (ret != LDB_SUCCESS)
2795 return NT_STATUS_UNSUCCESSFUL;
2797 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2798 return NT_STATUS_UNSUCCESSFUL;
2800 return NT_STATUS_OK;
2805 samr_GetMembersInAlias
2807 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2808 struct samr_GetMembersInAlias *r)
2810 struct dcesrv_handle *h;
2811 struct samr_account_state *a_state;
2812 struct samr_domain_state *d_state;
2813 struct ldb_message **msgs;
2814 struct lsa_SidPtr *sids;
2815 struct ldb_message_element *el;
2816 const char * const attrs[2] = { "member", NULL};
2819 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2822 d_state = a_state->domain_state;
2824 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2825 a_state->account_dn, &msgs, attrs);
2828 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2829 } else if (ret == 0) {
2830 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2831 } else if (ret != 1) {
2832 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2835 r->out.sids->num_sids = 0;
2836 r->out.sids->sids = NULL;
2838 el = ldb_msg_find_element(msgs[0], "member");
2843 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2847 return NT_STATUS_NO_MEMORY;
2849 for (i=0; i<el->num_values; i++) {
2850 struct ldb_message **msgs2;
2851 const char * const attrs2[2] = { "objectSid", NULL };
2852 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2853 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2856 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2858 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2861 if (sids[i].sid == NULL)
2862 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2864 r->out.sids->num_sids = el->num_values;
2865 r->out.sids->sids = sids;
2868 return NT_STATUS_OK;
2874 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2875 struct samr_OpenUser *r)
2877 struct samr_domain_state *d_state;
2878 struct samr_account_state *a_state;
2879 struct dcesrv_handle *h;
2880 const char *account_name;
2881 struct dom_sid *sid;
2882 struct ldb_message **msgs;
2883 struct dcesrv_handle *u_handle;
2884 const char * const attrs[2] = { "sAMAccountName", NULL };
2887 ZERO_STRUCTP(r->out.user_handle);
2889 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2893 /* form the users SID */
2894 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2896 return NT_STATUS_NO_MEMORY;
2899 /* search for the user record */
2900 ret = gendb_search(d_state->sam_ctx,
2901 mem_ctx, d_state->domain_dn, &msgs, attrs,
2902 "(&(objectSid=%s)(objectclass=user))",
2903 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2905 return NT_STATUS_NO_SUCH_USER;
2908 DEBUG(0,("Found %d records matching sid %s\n", ret,
2909 dom_sid_string(mem_ctx, sid)));
2910 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2913 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2914 if (account_name == NULL) {
2915 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2916 dom_sid_string(mem_ctx, sid)));
2917 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2920 a_state = talloc(mem_ctx, struct samr_account_state);
2922 return NT_STATUS_NO_MEMORY;
2924 a_state->sam_ctx = d_state->sam_ctx;
2925 a_state->access_mask = r->in.access_mask;
2926 a_state->domain_state = talloc_reference(a_state, d_state);
2927 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2928 a_state->account_sid = talloc_steal(a_state, sid);
2929 a_state->account_name = talloc_strdup(a_state, account_name);
2930 if (!a_state->account_name) {
2931 return NT_STATUS_NO_MEMORY;
2934 /* create the policy handle */
2935 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2937 return NT_STATUS_NO_MEMORY;
2940 u_handle->data = talloc_steal(u_handle, a_state);
2942 *r->out.user_handle = u_handle->wire_handle;
2944 return NT_STATUS_OK;
2952 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2953 struct samr_DeleteUser *r)
2955 struct dcesrv_handle *h;
2956 struct samr_account_state *a_state;
2959 *r->out.user_handle = *r->in.user_handle;
2961 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2965 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2966 if (ret != LDB_SUCCESS) {
2967 DEBUG(1, ("Failed to delete user: %s: %s\n",
2968 ldb_dn_get_linearized(a_state->account_dn),
2969 ldb_errstring(a_state->sam_ctx)));
2970 return NT_STATUS_UNSUCCESSFUL;
2974 ZERO_STRUCTP(r->out.user_handle);
2976 return NT_STATUS_OK;
2983 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2984 struct samr_QueryUserInfo *r)
2986 struct dcesrv_handle *h;
2987 struct samr_account_state *a_state;
2988 struct ldb_message *msg, **res;
2990 struct ldb_context *sam_ctx;
2992 const char * const *attrs = NULL;
2993 union samr_UserInfo *info;
2995 *r->out.info = NULL;
2997 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3000 sam_ctx = a_state->sam_ctx;
3002 /* fill in the reply */
3003 switch (r->in.level) {
3006 static const char * const attrs2[] = {"sAMAccountName",
3017 static const char * const attrs2[] = {"comment",
3026 static const char * const attrs2[] = {"sAMAccountName",
3041 "userAccountControl",
3048 static const char * const attrs2[] = {"logonHours",
3055 static const char * const attrs2[] = {"sAMAccountName",
3072 "userAccountControl",
3079 static const char * const attrs2[] = {"sAMAccountName",
3087 static const char * const attrs2[] = {"sAMAccountName",
3094 static const char * const attrs2[] = {"displayName",
3101 static const char * const attrs2[] = {"primaryGroupID",
3108 static const char * const attrs2[] = {"homeDirectory",
3116 static const char * const attrs2[] = {"scriptPath",
3123 static const char * const attrs2[] = {"profilePath",
3130 static const char * const attrs2[] = {"description",
3137 static const char * const attrs2[] = {"userWorkstations",
3144 static const char * const attrs2[] = {"userAccountControl",
3152 static const char * const attrs2[] = {"accountExpires",
3159 return NT_STATUS_NOT_SUPPORTED;
3163 static const char * const attrs2[] = {"userParameters",
3170 static const char * const attrs2[] = {"lastLogon",
3186 "userAccountControl",
3201 return NT_STATUS_NOT_SUPPORTED;
3205 return NT_STATUS_INVALID_INFO_CLASS;
3209 /* pull all the user attributes */
3210 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3211 a_state->account_dn ,&res, attrs);
3213 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3217 /* allocate the info structure */
3218 info = talloc_zero(mem_ctx, union samr_UserInfo);
3220 return NT_STATUS_NO_MEMORY;
3223 /* fill in the reply */
3224 switch (r->in.level) {
3226 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3227 QUERY_STRING(msg, info1.full_name, "displayName");
3228 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3229 QUERY_STRING(msg, info1.description, "description");
3230 QUERY_STRING(msg, info1.comment, "comment");
3234 QUERY_STRING(msg, info2.comment, "comment");
3235 QUERY_UINT (msg, info2.country_code, "countryCode");
3236 QUERY_UINT (msg, info2.code_page, "codePage");
3240 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3241 QUERY_STRING(msg, info3.full_name, "displayName");
3242 QUERY_RID (msg, info3.rid, "objectSid");
3243 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3244 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3245 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3246 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3247 QUERY_STRING(msg, info3.profile_path, "profilePath");
3248 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3249 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3250 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3251 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3252 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3253 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3254 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3255 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3256 QUERY_UINT (msg, info3.logon_count, "logonCount");
3257 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3261 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3265 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3266 QUERY_STRING(msg, info5.full_name, "displayName");
3267 QUERY_RID (msg, info5.rid, "objectSid");
3268 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3269 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3270 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3271 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3272 QUERY_STRING(msg, info5.profile_path, "profilePath");
3273 QUERY_STRING(msg, info5.description, "description");
3274 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3275 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3276 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3277 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3278 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3279 QUERY_UINT (msg, info5.logon_count, "logonCount");
3280 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3281 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3282 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3286 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3287 QUERY_STRING(msg, info6.full_name, "displayName");
3291 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3295 QUERY_STRING(msg, info8.full_name, "displayName");
3299 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3303 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3304 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3308 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3312 QUERY_STRING(msg, info12.profile_path, "profilePath");
3316 QUERY_STRING(msg, info13.description, "description");
3320 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3324 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3328 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3332 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3336 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3337 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3338 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3339 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3340 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3341 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3342 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3343 QUERY_STRING(msg, info21.full_name, "displayName");
3344 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3345 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3346 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3347 QUERY_STRING(msg, info21.profile_path, "profilePath");
3348 QUERY_STRING(msg, info21.description, "description");
3349 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3350 QUERY_STRING(msg, info21.comment, "comment");
3351 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3352 QUERY_RID (msg, info21.rid, "objectSid");
3353 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3354 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3355 info->info21.fields_present = 0x00FFFFFF;
3356 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3357 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3358 QUERY_UINT (msg, info21.logon_count, "logonCount");
3359 QUERY_UINT (msg, info21.country_code, "countryCode");
3360 QUERY_UINT (msg, info21.code_page, "codePage");
3366 return NT_STATUS_INVALID_INFO_CLASS;
3369 *r->out.info = info;
3371 return NT_STATUS_OK;
3378 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3379 struct samr_SetUserInfo *r)
3381 struct dcesrv_handle *h;
3382 struct samr_account_state *a_state;
3383 struct ldb_message *msg;
3385 NTSTATUS status = NT_STATUS_OK;
3386 struct ldb_context *sam_ctx;
3388 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3391 sam_ctx = a_state->sam_ctx;
3393 msg = ldb_msg_new(mem_ctx);
3395 return NT_STATUS_NO_MEMORY;
3398 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3400 return NT_STATUS_NO_MEMORY;
3403 switch (r->in.level) {
3405 SET_STRING(msg, info2.comment, "comment");
3406 SET_UINT (msg, info2.country_code, "countryCode");
3407 SET_UINT (msg, info2.code_page, "codePage");
3411 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3415 SET_STRING(msg, info6.account_name, "samAccountName");
3416 SET_STRING(msg, info6.full_name, "displayName");
3420 SET_STRING(msg, info7.account_name, "samAccountName");
3424 SET_STRING(msg, info8.full_name, "displayName");
3428 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3432 SET_STRING(msg, info10.home_directory, "homeDirectory");
3433 SET_STRING(msg, info10.home_drive, "homeDrive");
3437 SET_STRING(msg, info11.logon_script, "scriptPath");
3441 SET_STRING(msg, info12.profile_path, "profilePath");
3445 SET_STRING(msg, info13.description, "description");
3449 SET_STRING(msg, info14.workstations, "userWorkstations");
3453 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3457 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3461 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3465 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3466 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3467 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3468 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3469 SET_STRING(msg, info21.account_name, "samAccountName");
3470 IFSET(SAMR_FIELD_FULL_NAME)
3471 SET_STRING(msg, info21.full_name, "displayName");
3472 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3473 SET_STRING(msg, info21.home_directory, "homeDirectory");
3474 IFSET(SAMR_FIELD_HOME_DRIVE)
3475 SET_STRING(msg, info21.home_drive, "homeDrive");
3476 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3477 SET_STRING(msg, info21.logon_script, "scriptPath");
3478 IFSET(SAMR_FIELD_PROFILE_PATH)
3479 SET_STRING(msg, info21.profile_path, "profilePath");
3480 IFSET(SAMR_FIELD_DESCRIPTION)
3481 SET_STRING(msg, info21.description, "description");
3482 IFSET(SAMR_FIELD_WORKSTATIONS)
3483 SET_STRING(msg, info21.workstations, "userWorkstations");
3484 IFSET(SAMR_FIELD_COMMENT)
3485 SET_STRING(msg, info21.comment, "comment");
3486 IFSET(SAMR_FIELD_PARAMETERS)
3487 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3488 IFSET(SAMR_FIELD_PRIMARY_GID)
3489 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3490 IFSET(SAMR_FIELD_ACCT_FLAGS)
3491 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3492 IFSET(SAMR_FIELD_LOGON_HOURS)
3493 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3494 IFSET(SAMR_FIELD_COUNTRY_CODE)
3495 SET_UINT (msg, info21.country_code, "countryCode");
3496 IFSET(SAMR_FIELD_CODE_PAGE)
3497 SET_UINT (msg, info21.code_page, "codePage");
3502 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3503 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3504 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3505 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3506 SET_STRING(msg, info23.info.account_name, "samAccountName");
3507 IFSET(SAMR_FIELD_FULL_NAME)
3508 SET_STRING(msg, info23.info.full_name, "displayName");
3509 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3510 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3511 IFSET(SAMR_FIELD_HOME_DRIVE)
3512 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3513 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3514 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3515 IFSET(SAMR_FIELD_PROFILE_PATH)
3516 SET_STRING(msg, info23.info.profile_path, "profilePath");
3517 IFSET(SAMR_FIELD_DESCRIPTION)
3518 SET_STRING(msg, info23.info.description, "description");
3519 IFSET(SAMR_FIELD_WORKSTATIONS)
3520 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3521 IFSET(SAMR_FIELD_COMMENT)
3522 SET_STRING(msg, info23.info.comment, "comment");
3523 IFSET(SAMR_FIELD_PARAMETERS)
3524 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3525 IFSET(SAMR_FIELD_PRIMARY_GID)
3526 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3527 IFSET(SAMR_FIELD_ACCT_FLAGS)
3528 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3529 IFSET(SAMR_FIELD_LOGON_HOURS)
3530 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3531 IFSET(SAMR_FIELD_COUNTRY_CODE)
3532 SET_UINT (msg, info23.info.country_code, "countryCode");
3533 IFSET(SAMR_FIELD_CODE_PAGE)
3534 SET_UINT (msg, info23.info.code_page, "codePage");
3536 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3537 status = samr_set_password(dce_call,
3539 a_state->account_dn,
3540 a_state->domain_state->domain_dn,
3542 &r->in.info->info23.password);
3543 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3544 status = samr_set_password(dce_call,
3546 a_state->account_dn,
3547 a_state->domain_state->domain_dn,
3549 &r->in.info->info23.password);
3554 /* the set password levels are handled separately */
3556 status = samr_set_password(dce_call,
3558 a_state->account_dn,
3559 a_state->domain_state->domain_dn,
3561 &r->in.info->info24.password);
3565 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3566 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3567 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3568 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3569 SET_STRING(msg, info25.info.account_name, "samAccountName");
3570 IFSET(SAMR_FIELD_FULL_NAME)
3571 SET_STRING(msg, info25.info.full_name, "displayName");
3572 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3573 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3574 IFSET(SAMR_FIELD_HOME_DRIVE)
3575 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3576 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3577 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3578 IFSET(SAMR_FIELD_PROFILE_PATH)
3579 SET_STRING(msg, info25.info.profile_path, "profilePath");
3580 IFSET(SAMR_FIELD_DESCRIPTION)
3581 SET_STRING(msg, info25.info.description, "description");
3582 IFSET(SAMR_FIELD_WORKSTATIONS)
3583 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3584 IFSET(SAMR_FIELD_COMMENT)
3585 SET_STRING(msg, info25.info.comment, "comment");
3586 IFSET(SAMR_FIELD_PARAMETERS)
3587 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3588 IFSET(SAMR_FIELD_PRIMARY_GID)
3589 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3590 IFSET(SAMR_FIELD_ACCT_FLAGS)
3591 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3592 IFSET(SAMR_FIELD_LOGON_HOURS)
3593 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3594 IFSET(SAMR_FIELD_COUNTRY_CODE)
3595 SET_UINT (msg, info25.info.country_code, "countryCode");
3596 IFSET(SAMR_FIELD_CODE_PAGE)
3597 SET_UINT (msg, info25.info.code_page, "codePage");
3599 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3600 status = samr_set_password_ex(dce_call,
3602 a_state->account_dn,
3603 a_state->domain_state->domain_dn,
3605 &r->in.info->info25.password);
3606 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3607 status = samr_set_password_ex(dce_call,
3609 a_state->account_dn,
3610 a_state->domain_state->domain_dn,
3612 &r->in.info->info25.password);
3617 /* the set password levels are handled separately */
3619 status = samr_set_password_ex(dce_call,
3621 a_state->account_dn,
3622 a_state->domain_state->domain_dn,
3624 &r->in.info->info26.password);
3629 /* many info classes are not valid for SetUserInfo */
3630 return NT_STATUS_INVALID_INFO_CLASS;
3633 if (!NT_STATUS_IS_OK(status)) {
3637 /* modify the samdb record */
3638 if (msg->num_elements > 0) {
3639 ret = ldb_modify(a_state->sam_ctx, msg);
3640 if (ret != LDB_SUCCESS) {
3641 DEBUG(1,("Failed to modify record %s: %s\n",
3642 ldb_dn_get_linearized(a_state->account_dn),
3643 ldb_errstring(a_state->sam_ctx)));
3645 /* we really need samdb.c to return NTSTATUS */
3646 return NT_STATUS_UNSUCCESSFUL;
3650 return NT_STATUS_OK;
3655 samr_GetGroupsForUser
3657 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3658 struct samr_GetGroupsForUser *r)
3660 struct dcesrv_handle *h;
3661 struct samr_account_state *a_state;
3662 struct samr_domain_state *d_state;
3663 struct ldb_message **res;
3664 const char * const attrs[2] = { "objectSid", NULL };
3665 struct samr_RidWithAttributeArray *array;
3668 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3671 d_state = a_state->domain_state;
3673 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3674 d_state->domain_dn, &res,
3675 attrs, d_state->domain_sid,
3676 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3677 ldb_dn_get_linearized(a_state->account_dn),
3678 GTYPE_SECURITY_GLOBAL_GROUP);
3680 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3682 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3684 return NT_STATUS_NO_MEMORY;
3689 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3691 if (array->rids == NULL)
3692 return NT_STATUS_NO_MEMORY;
3694 /* Adds the primary group */
3695 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3696 ~0, a_state->account_dn,
3697 "primaryGroupID", NULL);
3698 array->rids[0].attributes = SE_GROUP_MANDATORY
3699 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3702 /* Adds the additional groups */
3703 for (i = 0; i < count; i++) {
3704 struct dom_sid *group_sid;
3706 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3707 if (group_sid == NULL) {
3708 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3712 array->rids[i + 1].rid =
3713 group_sid->sub_auths[group_sid->num_auths-1];
3714 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3715 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3719 *r->out.rids = array;
3721 return NT_STATUS_OK;
3726 samr_QueryDisplayInfo
3728 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3729 struct samr_QueryDisplayInfo *r)
3731 struct dcesrv_handle *h;
3732 struct samr_domain_state *d_state;
3733 struct ldb_message **res;
3734 int ldb_cnt, count, i;
3735 const char * const attrs[] = { "objectSid", "sAMAccountName",
3736 "displayName", "description", "userAccountControl",
3737 "pwdLastSet", NULL };
3738 struct samr_DispEntryFull *entriesFull = NULL;
3739 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3740 struct samr_DispEntryAscii *entriesAscii = NULL;
3741 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3744 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3748 switch (r->in.level) {
3751 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3752 "(sAMAccountType=%u))",
3753 ATYPE_NORMAL_ACCOUNT);
3756 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3757 "(sAMAccountType=%u))",
3758 ATYPE_WORKSTATION_TRUST);
3762 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3763 "(objectclass=group))",
3764 GTYPE_SECURITY_GLOBAL_GROUP);
3767 return NT_STATUS_INVALID_INFO_CLASS;
3770 /* search for all requested objects in this domain. This could
3771 possibly be cached and resumed based on resume_key */
3772 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3773 d_state->domain_dn, &res, attrs,
3774 d_state->domain_sid, "%s", filter);
3775 if (ldb_cnt == -1) {
3776 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3778 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3779 return NT_STATUS_OK;
3782 switch (r->in.level) {
3784 entriesGeneral = talloc_array(mem_ctx,
3785 struct samr_DispEntryGeneral,
3789 entriesFull = talloc_array(mem_ctx,
3790 struct samr_DispEntryFull,
3794 entriesFullGroup = talloc_array(mem_ctx,
3795 struct samr_DispEntryFullGroup,
3800 entriesAscii = talloc_array(mem_ctx,
3801 struct samr_DispEntryAscii,
3806 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3807 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3808 return NT_STATUS_NO_MEMORY;
3812 for (i=0; i<ldb_cnt; i++) {
3813 struct dom_sid *objectsid;
3815 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3817 if (objectsid == NULL)
3820 switch(r->in.level) {
3822 entriesGeneral[count].idx = count + 1;
3823 entriesGeneral[count].rid =
3824 objectsid->sub_auths[objectsid->num_auths-1];
3825 entriesGeneral[count].acct_flags =
3826 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3828 d_state->domain_dn);
3829 entriesGeneral[count].account_name.string =
3830 samdb_result_string(res[i],
3831 "sAMAccountName", "");
3832 entriesGeneral[count].full_name.string =
3833 samdb_result_string(res[i], "displayName", "");
3834 entriesGeneral[count].description.string =
3835 samdb_result_string(res[i], "description", "");
3838 entriesFull[count].idx = count + 1;
3839 entriesFull[count].rid =
3840 objectsid->sub_auths[objectsid->num_auths-1];
3842 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3843 entriesFull[count].acct_flags =
3844 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3846 d_state->domain_dn) | ACB_NORMAL;
3847 entriesFull[count].account_name.string =
3848 samdb_result_string(res[i], "sAMAccountName",
3850 entriesFull[count].description.string =
3851 samdb_result_string(res[i], "description", "");
3854 entriesFullGroup[count].idx = count + 1;
3855 entriesFullGroup[count].rid =
3856 objectsid->sub_auths[objectsid->num_auths-1];
3857 /* We get a "7" here for groups */
3858 entriesFullGroup[count].acct_flags
3859 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3860 entriesFullGroup[count].account_name.string =
3861 samdb_result_string(res[i], "sAMAccountName",
3863 entriesFullGroup[count].description.string =
3864 samdb_result_string(res[i], "description", "");
3868 entriesAscii[count].idx = count + 1;
3869 entriesAscii[count].account_name.string =
3870 samdb_result_string(res[i], "sAMAccountName",
3878 *r->out.total_size = count;
3880 if (r->in.start_idx >= count) {
3881 *r->out.returned_size = 0;
3882 switch(r->in.level) {
3884 r->out.info->info1.count = *r->out.returned_size;
3885 r->out.info->info1.entries = NULL;
3888 r->out.info->info2.count = *r->out.returned_size;
3889 r->out.info->info2.entries = NULL;
3892 r->out.info->info3.count = *r->out.returned_size;
3893 r->out.info->info3.entries = NULL;
3896 r->out.info->info4.count = *r->out.returned_size;
3897 r->out.info->info4.entries = NULL;
3900 r->out.info->info5.count = *r->out.returned_size;
3901 r->out.info->info5.entries = NULL;
3905 *r->out.returned_size = MIN(count - r->in.start_idx,
3907 switch(r->in.level) {
3909 r->out.info->info1.count = *r->out.returned_size;
3910 r->out.info->info1.entries =
3911 &(entriesGeneral[r->in.start_idx]);
3914 r->out.info->info2.count = *r->out.returned_size;
3915 r->out.info->info2.entries =
3916 &(entriesFull[r->in.start_idx]);
3919 r->out.info->info3.count = *r->out.returned_size;
3920 r->out.info->info3.entries =
3921 &(entriesFullGroup[r->in.start_idx]);
3924 r->out.info->info4.count = *r->out.returned_size;
3925 r->out.info->info4.entries =
3926 &(entriesAscii[r->in.start_idx]);
3929 r->out.info->info5.count = *r->out.returned_size;
3930 r->out.info->info5.entries =
3931 &(entriesAscii[r->in.start_idx]);
3936 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3937 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3942 samr_GetDisplayEnumerationIndex
3944 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3945 struct samr_GetDisplayEnumerationIndex *r)
3947 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3952 samr_TestPrivateFunctionsDomain
3954 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3955 struct samr_TestPrivateFunctionsDomain *r)
3957 return NT_STATUS_NOT_IMPLEMENTED;
3962 samr_TestPrivateFunctionsUser
3964 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3965 struct samr_TestPrivateFunctionsUser *r)
3967 return NT_STATUS_NOT_IMPLEMENTED;
3974 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3975 struct samr_GetUserPwInfo *r)
3977 struct dcesrv_handle *h;
3978 struct samr_account_state *a_state;
3980 ZERO_STRUCTP(r->out.info);
3982 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3986 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3987 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3989 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3990 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3992 return NT_STATUS_OK;
3997 samr_RemoveMemberFromForeignDomain
3999 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4000 struct samr_RemoveMemberFromForeignDomain *r)
4002 struct dcesrv_handle *h;
4003 struct samr_domain_state *d_state;
4004 const char *memberdn;
4005 struct ldb_message **res;
4006 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
4009 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4013 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4014 "distinguishedName", "(objectSid=%s)",
4015 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4017 if (memberdn == NULL) {
4018 return NT_STATUS_OK;
4021 /* TODO: Does this call only remove alias members, or does it do this
4022 * for domain groups as well? */
4024 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4025 d_state->domain_dn, &res, attrs,
4026 d_state->domain_sid,
4027 "(&(member=%s)(objectClass=group)"
4028 "(|(groupType=%d)(groupType=%d)))",
4030 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4031 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4034 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4036 for (i=0; i<count; i++) {
4037 struct ldb_message *mod;
4039 mod = ldb_msg_new(mem_ctx);
4041 return NT_STATUS_NO_MEMORY;
4044 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4045 if (mod->dn == NULL) {
4050 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4051 "member", memberdn) != 0)
4052 return NT_STATUS_NO_MEMORY;
4054 if (ldb_modify(d_state->sam_ctx, mod) != 0)
4055 return NT_STATUS_UNSUCCESSFUL;
4060 return NT_STATUS_OK;
4065 samr_QueryDomainInfo2
4067 just an alias for samr_QueryDomainInfo
4069 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4070 struct samr_QueryDomainInfo2 *r)
4072 struct samr_QueryDomainInfo r1;
4075 ZERO_STRUCT(r1.out);
4076 r1.in.domain_handle = r->in.domain_handle;
4077 r1.in.level = r->in.level;
4078 r1.out.info = r->out.info;
4080 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4089 just an alias for samr_QueryUserInfo
4091 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4092 struct samr_QueryUserInfo2 *r)
4094 struct samr_QueryUserInfo r1;
4097 r1.in.user_handle = r->in.user_handle;
4098 r1.in.level = r->in.level;
4099 r1.out.info = r->out.info;
4101 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4108 samr_QueryDisplayInfo2
4110 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4111 struct samr_QueryDisplayInfo2 *r)
4113 struct samr_QueryDisplayInfo q;
4116 q.in.domain_handle = r->in.domain_handle;
4117 q.in.level = r->in.level;
4118 q.in.start_idx = r->in.start_idx;
4119 q.in.max_entries = r->in.max_entries;
4120 q.in.buf_size = r->in.buf_size;
4121 q.out.total_size = r->out.total_size;
4122 q.out.returned_size = r->out.returned_size;
4123 q.out.info = r->out.info;
4125 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4132 samr_GetDisplayEnumerationIndex2
4134 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4135 struct samr_GetDisplayEnumerationIndex2 *r)
4137 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4142 samr_QueryDisplayInfo3
4144 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4145 struct samr_QueryDisplayInfo3 *r)
4147 struct samr_QueryDisplayInfo q;
4150 q.in.domain_handle = r->in.domain_handle;
4151 q.in.level = r->in.level;
4152 q.in.start_idx = r->in.start_idx;
4153 q.in.max_entries = r->in.max_entries;
4154 q.in.buf_size = r->in.buf_size;
4155 q.out.total_size = r->out.total_size;
4156 q.out.returned_size = r->out.returned_size;
4157 q.out.info = r->out.info;
4159 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4166 samr_AddMultipleMembersToAlias
4168 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4169 struct samr_AddMultipleMembersToAlias *r)
4171 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4176 samr_RemoveMultipleMembersFromAlias
4178 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4179 struct samr_RemoveMultipleMembersFromAlias *r)
4181 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4188 this fetches the default password properties for a domain
4190 note that w2k3 completely ignores the domain name in this call, and
4191 always returns the information for the servers primary domain
4193 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4194 struct samr_GetDomPwInfo *r)
4196 struct ldb_message **msgs;
4198 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4199 struct ldb_context *sam_ctx;
4201 ZERO_STRUCTP(r->out.info);
4203 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4204 dce_call->conn->dce_ctx->lp_ctx,
4205 dce_call->conn->auth_state.session_info);
4206 if (sam_ctx == NULL) {
4207 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4210 /* The domain name in this call is ignored */
4211 ret = gendb_search_dn(sam_ctx,
4212 mem_ctx, NULL, &msgs, attrs);
4214 talloc_free(sam_ctx);
4216 return NT_STATUS_NO_SUCH_DOMAIN;
4220 talloc_free(sam_ctx);
4222 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4225 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4227 r->out.info->password_properties = samdb_result_uint(msgs[0],
4228 "pwdProperties", 1);
4231 talloc_unlink(mem_ctx, sam_ctx);
4233 return NT_STATUS_OK;
4240 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4241 struct samr_Connect2 *r)
4243 struct samr_Connect c;
4245 c.in.system_name = NULL;
4246 c.in.access_mask = r->in.access_mask;
4247 c.out.connect_handle = r->out.connect_handle;
4249 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4256 just an alias for samr_SetUserInfo
4258 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4259 struct samr_SetUserInfo2 *r)
4261 struct samr_SetUserInfo r2;
4263 r2.in.user_handle = r->in.user_handle;
4264 r2.in.level = r->in.level;
4265 r2.in.info = r->in.info;
4267 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4272 samr_SetBootKeyInformation
4274 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4275 struct samr_SetBootKeyInformation *r)
4277 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4282 samr_GetBootKeyInformation
4284 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4285 struct samr_GetBootKeyInformation *r)
4287 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4294 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4295 struct samr_Connect3 *r)
4297 struct samr_Connect c;
4299 c.in.system_name = NULL;
4300 c.in.access_mask = r->in.access_mask;
4301 c.out.connect_handle = r->out.connect_handle;
4303 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4310 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4311 struct samr_Connect4 *r)
4313 struct samr_Connect c;
4315 c.in.system_name = NULL;
4316 c.in.access_mask = r->in.access_mask;
4317 c.out.connect_handle = r->out.connect_handle;
4319 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4326 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4327 struct samr_Connect5 *r)
4329 struct samr_Connect c;
4332 c.in.system_name = NULL;
4333 c.in.access_mask = r->in.access_mask;
4334 c.out.connect_handle = r->out.connect_handle;
4336 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4338 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4339 r->out.info_out->info1.unknown2 = 0;
4340 *r->out.level_out = r->in.level_in;
4349 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4350 struct samr_RidToSid *r)
4352 struct samr_domain_state *d_state;
4353 struct dcesrv_handle *h;
4355 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4359 /* form the users SID */
4360 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4362 return NT_STATUS_NO_MEMORY;
4365 return NT_STATUS_OK;
4370 samr_SetDsrmPassword
4372 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4373 struct samr_SetDsrmPassword *r)
4375 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4380 samr_ValidatePassword
4382 For now the call checks the password complexity (if active) and the minimum
4383 password length on level 2 and 3. Level 1 is ignored for now.
4385 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4386 TALLOC_CTX *mem_ctx,
4387 struct samr_ValidatePassword *r)
4389 struct samr_GetDomPwInfo r2;
4390 struct samr_PwInfo pwInfo;
4392 enum samr_ValidationStatus res;
4395 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4397 r2.in.domain_name = NULL;
4398 r2.out.info = &pwInfo;
4399 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4400 if (!NT_STATUS_IS_OK(status)) {
4404 switch (r->in.level) {
4405 case NetValidateAuthentication:
4406 /* we don't support this yet */
4407 return NT_STATUS_NOT_SUPPORTED;
4409 case NetValidatePasswordChange:
4410 password = data_blob_const(r->in.req->req2.password.string,
4411 r->in.req->req2.password.length);
4412 res = samdb_check_password(&password,
4413 pwInfo.password_properties,
4414 pwInfo.min_password_length);
4415 (*r->out.rep)->ctr2.status = res;
4417 case NetValidatePasswordReset:
4418 password = data_blob_const(r->in.req->req3.password.string,
4419 r->in.req->req3.password.length);
4420 res = samdb_check_password(&password,
4421 pwInfo.password_properties,
4422 pwInfo.min_password_length);
4423 (*r->out.rep)->ctr3.status = res;
4426 return NT_STATUS_INVALID_INFO_CLASS;
4430 return NT_STATUS_OK;
4434 /* include the generated boilerplate */
4435 #include "librpc/gen_ndr/ndr_samr_s.c"