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 "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
43 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
45 #define QUERY_STRING(msg, field, attr) \
46 info->field.string = samdb_result_string(msg, attr, "");
47 #define QUERY_UINT(msg, field, attr) \
48 info->field = samdb_result_uint(msg, attr, 0);
49 #define QUERY_RID(msg, field, attr) \
50 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
51 #define QUERY_UINT64(msg, field, attr) \
52 info->field = samdb_result_uint64(msg, attr, 0);
53 #define QUERY_APASSC(msg, field, attr) \
54 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
55 a_state->domain_state->domain_dn, msg, attr);
56 #define QUERY_FPASSC(msg, field, attr) \
57 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
58 a_state->domain_state->domain_dn, msg);
59 #define QUERY_LHOURS(msg, field, attr) \
60 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
61 #define QUERY_AFLAGS(msg, field, attr) \
62 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
63 #define QUERY_PARAMETERS(msg, field, attr) \
64 info->field = samdb_result_parameters(mem_ctx, msg, attr);
67 /* these are used to make the Set[User|Group]Info code easier to follow */
69 #define SET_STRING(msg, field, attr) do { \
70 struct ldb_message_element *set_el; \
71 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
72 if (r->in.info->field.string[0] == '\0') { \
73 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
74 return NT_STATUS_NO_MEMORY; \
77 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
78 return NT_STATUS_NO_MEMORY; \
80 set_el = ldb_msg_find_element(msg, attr); \
81 set_el->flags = LDB_FLAG_MOD_REPLACE; \
84 #define SET_UINT(msg, field, attr) do { \
85 struct ldb_message_element *set_el; \
86 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
87 return NT_STATUS_NO_MEMORY; \
89 set_el = ldb_msg_find_element(msg, attr); \
90 set_el->flags = LDB_FLAG_MOD_REPLACE; \
93 #define SET_INT64(msg, field, attr) do { \
94 struct ldb_message_element *set_el; \
95 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
96 return NT_STATUS_NO_MEMORY; \
98 set_el = ldb_msg_find_element(msg, attr); \
99 set_el->flags = LDB_FLAG_MOD_REPLACE; \
102 #define SET_UINT64(msg, field, attr) do { \
103 struct ldb_message_element *set_el; \
104 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
105 return NT_STATUS_NO_MEMORY; \
107 set_el = ldb_msg_find_element(msg, attr); \
108 set_el->flags = LDB_FLAG_MOD_REPLACE; \
111 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
113 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
114 return NT_STATUS_INVALID_PARAMETER; \
118 /* Set account flags, discarding flags that cannot be set with SAMR */
119 #define SET_AFLAGS(msg, field, attr) do { \
120 struct ldb_message_element *set_el; \
121 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
122 return NT_STATUS_INVALID_PARAMETER; \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
128 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
129 return NT_STATUS_NO_MEMORY; \
131 set_el = ldb_msg_find_element(msg, attr); \
132 set_el->flags = LDB_FLAG_MOD_REPLACE; \
135 #define SET_LHOURS(msg, field, attr) do { \
136 struct ldb_message_element *set_el; \
137 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
138 return NT_STATUS_NO_MEMORY; \
140 set_el = ldb_msg_find_element(msg, attr); \
141 set_el->flags = LDB_FLAG_MOD_REPLACE; \
144 #define SET_PARAMETERS(msg, field, attr) do { \
145 struct ldb_message_element *set_el; \
146 if (r->in.info->field.length != 0) { \
147 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
148 return NT_STATUS_NO_MEMORY; \
150 set_el = ldb_msg_find_element(msg, attr); \
151 set_el->flags = LDB_FLAG_MOD_REPLACE; \
160 create a connection to the SAM database
162 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
163 struct samr_Connect *r)
165 struct samr_connect_state *c_state;
166 struct dcesrv_handle *handle;
168 ZERO_STRUCTP(r->out.connect_handle);
170 c_state = talloc(mem_ctx, struct samr_connect_state);
172 return NT_STATUS_NO_MEMORY;
175 /* make sure the sam database is accessible */
176 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);
177 if (c_state->sam_ctx == NULL) {
178 talloc_free(c_state);
179 return NT_STATUS_INVALID_SYSTEM_SERVICE;
183 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
185 talloc_free(c_state);
186 return NT_STATUS_NO_MEMORY;
189 handle->data = talloc_steal(handle, c_state);
191 c_state->access_mask = r->in.access_mask;
192 *r->out.connect_handle = handle->wire_handle;
201 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
202 struct samr_Close *r)
204 struct dcesrv_handle *h;
206 *r->out.handle = *r->in.handle;
208 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
212 ZERO_STRUCTP(r->out.handle);
221 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
222 struct samr_SetSecurity *r)
224 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
231 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
232 struct samr_QuerySecurity *r)
234 struct dcesrv_handle *h;
235 struct sec_desc_buf *sd;
237 *r->out.sdbuf = NULL;
239 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
241 sd = talloc(mem_ctx, struct sec_desc_buf);
243 return NT_STATUS_NO_MEMORY;
246 sd->sd = samdb_default_security_descriptor(mem_ctx);
257 we refuse this operation completely. If a admin wants to shutdown samr
258 in Samba then they should use the samba admin tools to disable the samr pipe
260 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
261 struct samr_Shutdown *r)
263 return NT_STATUS_ACCESS_DENIED;
270 this maps from a domain name to a SID
272 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
273 struct samr_LookupDomain *r)
275 struct samr_connect_state *c_state;
276 struct dcesrv_handle *h;
278 const char * const dom_attrs[] = { "objectSid", NULL};
279 struct ldb_message **dom_msgs;
284 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
288 if (r->in.domain_name->string == NULL) {
289 return NT_STATUS_INVALID_PARAMETER;
292 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
293 ret = gendb_search(c_state->sam_ctx,
294 mem_ctx, NULL, &dom_msgs, dom_attrs,
295 "(objectClass=builtinDomain)");
296 } else if (strcasecmp_m(r->in.domain_name->string, lp_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
297 ret = gendb_search_dn(c_state->sam_ctx,
298 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
299 &dom_msgs, dom_attrs);
301 return NT_STATUS_NO_SUCH_DOMAIN;
304 return NT_STATUS_NO_SUCH_DOMAIN;
307 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
311 return NT_STATUS_NO_SUCH_DOMAIN;
323 list the domains in the SAM
325 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
326 struct samr_EnumDomains *r)
328 struct samr_connect_state *c_state;
329 struct dcesrv_handle *h;
330 struct samr_SamArray *array;
333 *r->out.resume_handle = 0;
335 *r->out.num_entries = 0;
337 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
341 *r->out.resume_handle = 2;
343 start_i = *r->in.resume_handle;
346 /* search past end of list is not an error for this call */
350 array = talloc(mem_ctx, struct samr_SamArray);
352 return NT_STATUS_NO_MEMORY;
356 array->entries = NULL;
358 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
359 if (array->entries == NULL) {
360 return NT_STATUS_NO_MEMORY;
363 for (i=0;i<2-start_i;i++) {
364 array->entries[i].idx = start_i + i;
366 array->entries[i].name.string = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
368 array->entries[i].name.string = "BUILTIN";
373 *r->out.num_entries = i;
374 array->count = *r->out.num_entries;
383 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
384 struct samr_OpenDomain *r)
386 struct dcesrv_handle *h_conn, *h_domain;
387 struct samr_connect_state *c_state;
388 struct samr_domain_state *d_state;
389 const char * const dom_attrs[] = { "cn", NULL};
390 struct ldb_message **dom_msgs;
393 ZERO_STRUCTP(r->out.domain_handle);
395 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
397 c_state = h_conn->data;
399 if (r->in.sid == NULL) {
400 return NT_STATUS_INVALID_PARAMETER;
403 d_state = talloc(mem_ctx, struct samr_domain_state);
405 return NT_STATUS_NO_MEMORY;
408 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
410 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
411 d_state->builtin = true;
412 d_state->domain_name = "BUILTIN";
414 d_state->builtin = false;
415 d_state->domain_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
418 ret = gendb_search(c_state->sam_ctx,
419 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
421 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
424 talloc_free(d_state);
425 return NT_STATUS_NO_SUCH_DOMAIN;
426 } else if (ret > 1) {
427 talloc_free(d_state);
428 return NT_STATUS_INTERNAL_DB_CORRUPTION;
429 } else if (ret == -1) {
430 talloc_free(d_state);
431 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
432 return NT_STATUS_INTERNAL_DB_CORRUPTION;
435 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
436 d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
437 d_state->connect_state = talloc_reference(d_state, c_state);
438 d_state->sam_ctx = c_state->sam_ctx;
439 d_state->access_mask = r->in.access_mask;
441 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
443 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
445 talloc_free(d_state);
446 return NT_STATUS_NO_MEMORY;
449 h_domain->data = talloc_steal(h_domain, d_state);
451 *r->out.domain_handle = h_domain->wire_handle;
459 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
461 struct ldb_message **dom_msgs,
462 struct samr_DomInfo1 *info)
464 info->min_password_length =
465 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
466 info->password_history_length =
467 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
468 info->password_properties =
469 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
470 info->max_password_age =
471 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
472 info->min_password_age =
473 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
481 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
483 struct ldb_message **dom_msgs,
484 struct samr_DomGeneralInformation *info)
486 /* This pulls the NetBIOS name from the
487 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
489 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
491 if (!info->primary.string) {
492 info->primary.string = lp_netbios_name(state->lp_ctx);
495 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
496 0x8000000000000000LL);
498 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
499 info->domain_name.string = state->domain_name;
501 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
503 switch (state->role) {
504 case ROLE_DOMAIN_CONTROLLER:
505 /* This pulls the NetBIOS name from the
506 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
508 if (samdb_is_pdc(state->sam_ctx)) {
509 info->role = SAMR_ROLE_DOMAIN_PDC;
511 info->role = SAMR_ROLE_DOMAIN_BDC;
514 case ROLE_DOMAIN_MEMBER:
515 info->role = SAMR_ROLE_DOMAIN_MEMBER;
517 case ROLE_STANDALONE:
518 info->role = SAMR_ROLE_STANDALONE;
522 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
523 info->num_users = samdb_search_count(state->sam_ctx, state->domain_dn,
524 "(objectClass=user)");
525 info->num_groups = samdb_search_count(state->sam_ctx, state->domain_dn,
526 "(&(objectClass=group)(groupType=%u))",
527 GTYPE_SECURITY_GLOBAL_GROUP);
528 info->num_aliases = samdb_search_count(state->sam_ctx, state->domain_dn,
529 "(&(objectClass=group)(groupType=%u))",
530 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
538 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
540 struct ldb_message **dom_msgs,
541 struct samr_DomInfo3 *info)
543 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
544 0x8000000000000000LL);
552 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
554 struct ldb_message **dom_msgs,
555 struct samr_DomOEMInformation *info)
557 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
565 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
567 struct ldb_message **dom_msgs,
568 struct samr_DomInfo5 *info)
570 info->domain_name.string = state->domain_name;
578 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
580 struct ldb_message **dom_msgs,
581 struct samr_DomInfo6 *info)
583 /* This pulls the NetBIOS name from the
584 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
586 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
587 dom_msgs[0], "fSMORoleOwner");
589 if (!info->primary.string) {
590 info->primary.string = lp_netbios_name(state->lp_ctx);
599 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
601 struct ldb_message **dom_msgs,
602 struct samr_DomInfo7 *info)
605 switch (state->role) {
606 case ROLE_DOMAIN_CONTROLLER:
607 /* This pulls the NetBIOS name from the
608 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
610 if (samdb_is_pdc(state->sam_ctx)) {
611 info->role = SAMR_ROLE_DOMAIN_PDC;
613 info->role = SAMR_ROLE_DOMAIN_BDC;
616 case ROLE_DOMAIN_MEMBER:
617 info->role = SAMR_ROLE_DOMAIN_MEMBER;
619 case ROLE_STANDALONE:
620 info->role = SAMR_ROLE_STANDALONE;
630 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
632 struct ldb_message **dom_msgs,
633 struct samr_DomInfo8 *info)
635 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
638 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
647 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
649 struct ldb_message **dom_msgs,
650 struct samr_DomInfo9 *info)
652 info->domain_server_state = DOMAIN_SERVER_ENABLED;
660 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
662 struct ldb_message **dom_msgs,
663 struct samr_DomGeneralInformation2 *info)
666 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
667 if (!NT_STATUS_IS_OK(status)) {
671 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
673 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
675 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
683 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
685 struct ldb_message **dom_msgs,
686 struct samr_DomInfo12 *info)
688 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
690 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
692 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
700 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
702 struct ldb_message **dom_msgs,
703 struct samr_DomInfo13 *info)
705 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
708 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
711 info->modified_count_at_last_promotion = 0;
719 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
720 struct samr_QueryDomainInfo *r)
722 struct dcesrv_handle *h;
723 struct samr_domain_state *d_state;
724 union samr_DomainInfo *info;
726 struct ldb_message **dom_msgs;
727 const char * const *attrs = NULL;
731 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
735 info = talloc(mem_ctx, union samr_DomainInfo);
737 return NT_STATUS_NO_MEMORY;
740 switch (r->in.level) {
743 static const char * const attrs2[] = { "minPwdLength",
754 static const char * const attrs2[] = {"forceLogoff",
764 static const char * const attrs2[] = {"forceLogoff",
771 static const char * const attrs2[] = {"oEMInformation",
783 static const char * const attrs2[] = {"fSMORoleOwner",
795 static const char * const attrs2[] = { "modifiedCount",
808 static const char * const attrs2[] = { "oEMInformation",
812 "lockOutObservationWindow",
820 static const char * const attrs2[] = { "lockoutDuration",
821 "lockOutObservationWindow",
829 static const char * const attrs2[] = { "modifiedCount",
837 return NT_STATUS_INVALID_INFO_CLASS;
841 /* some levels don't need a search */
844 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
845 d_state->domain_dn, &dom_msgs, attrs);
847 return NT_STATUS_INTERNAL_DB_CORRUPTION;
855 switch (r->in.level) {
857 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
860 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
863 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
866 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
869 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
872 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
875 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
878 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
881 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
884 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
887 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
890 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
893 return NT_STATUS_INVALID_INFO_CLASS;
901 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
902 struct samr_SetDomainInfo *r)
904 struct dcesrv_handle *h;
905 struct samr_domain_state *d_state;
906 struct ldb_message *msg;
908 struct ldb_context *sam_ctx;
910 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
913 sam_ctx = d_state->sam_ctx;
915 msg = ldb_msg_new(mem_ctx);
917 return NT_STATUS_NO_MEMORY;
920 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
922 return NT_STATUS_NO_MEMORY;
925 switch (r->in.level) {
927 SET_UINT (msg, info1.min_password_length, "minPwdLength");
928 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
929 SET_UINT (msg, info1.password_properties, "pwdProperties");
930 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
931 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
934 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
937 SET_STRING(msg, oem.oem_information, "oEMInformation");
943 /* No op, we don't know where to set these */
948 * It is not possible to set lockout_duration < lockout_window.
949 * (The test is the other way around since the negative numbers
953 * This check should be moved to the backend, i.e. to some
954 * ldb module under dsdb/samdb/ldb_modules/ .
956 * This constraint is documented here for the samr rpc service:
957 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
958 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
960 * And here for the ldap backend:
961 * MS-ADTS 3.1.1.5.3.2 Constraints
962 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
964 if (r->in.info->info12.lockout_duration >
965 r->in.info->info12.lockout_window)
967 return NT_STATUS_INVALID_PARAMETER;
969 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
970 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
971 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
975 /* many info classes are not valid for SetDomainInfo */
976 return NT_STATUS_INVALID_INFO_CLASS;
979 /* modify the samdb record */
980 ret = ldb_modify(sam_ctx, msg);
981 if (ret != LDB_SUCCESS) {
982 DEBUG(1,("Failed to modify record %s: %s\n",
983 ldb_dn_get_linearized(d_state->domain_dn),
984 ldb_errstring(sam_ctx)));
986 /* we really need samdb.c to return NTSTATUS */
987 return NT_STATUS_UNSUCCESSFUL;
994 samr_CreateDomainGroup
996 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
997 struct samr_CreateDomainGroup *r)
999 struct samr_domain_state *d_state;
1000 struct samr_account_state *a_state;
1001 struct dcesrv_handle *h;
1003 struct ldb_message *msg;
1004 struct dom_sid *sid;
1005 const char *groupname;
1006 struct dcesrv_handle *g_handle;
1009 ZERO_STRUCTP(r->out.group_handle);
1012 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1016 if (d_state->builtin) {
1017 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1018 return NT_STATUS_ACCESS_DENIED;
1021 groupname = r->in.name->string;
1023 if (groupname == NULL) {
1024 return NT_STATUS_INVALID_PARAMETER;
1027 /* check if the group already exists */
1028 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1030 "(&(sAMAccountName=%s)(objectclass=group))",
1031 ldb_binary_encode_string(mem_ctx, groupname));
1033 return NT_STATUS_GROUP_EXISTS;
1036 msg = ldb_msg_new(mem_ctx);
1038 return NT_STATUS_NO_MEMORY;
1041 /* add core elements to the ldb_message for the user */
1042 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1043 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1045 return NT_STATUS_NO_MEMORY;
1047 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1048 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1050 /* create the group */
1051 ret = ldb_add(d_state->sam_ctx, msg);
1055 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1056 DEBUG(0,("Failed to create group record %s: %s\n",
1057 ldb_dn_get_linearized(msg->dn),
1058 ldb_errstring(d_state->sam_ctx)));
1059 return NT_STATUS_GROUP_EXISTS;
1060 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1061 DEBUG(0,("Failed to create group record %s: %s\n",
1062 ldb_dn_get_linearized(msg->dn),
1063 ldb_errstring(d_state->sam_ctx)));
1064 return NT_STATUS_ACCESS_DENIED;
1066 DEBUG(0,("Failed to create group record %s: %s\n",
1067 ldb_dn_get_linearized(msg->dn),
1068 ldb_errstring(d_state->sam_ctx)));
1069 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1072 a_state = talloc(mem_ctx, struct samr_account_state);
1074 return NT_STATUS_NO_MEMORY;
1076 a_state->sam_ctx = d_state->sam_ctx;
1077 a_state->access_mask = r->in.access_mask;
1078 a_state->domain_state = talloc_reference(a_state, d_state);
1079 a_state->account_dn = talloc_steal(a_state, msg->dn);
1081 /* retrieve the sid for the group just created */
1082 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1083 msg->dn, "objectSid", NULL);
1085 return NT_STATUS_UNSUCCESSFUL;
1088 a_state->account_name = talloc_strdup(a_state, groupname);
1089 if (!a_state->account_name) {
1090 return NT_STATUS_NO_MEMORY;
1093 /* create the policy handle */
1094 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1096 return NT_STATUS_NO_MEMORY;
1099 g_handle->data = talloc_steal(g_handle, a_state);
1101 *r->out.group_handle = g_handle->wire_handle;
1102 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1104 return NT_STATUS_OK;
1109 comparison function for sorting SamEntry array
1111 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1113 return e1->idx - e2->idx;
1117 samr_EnumDomainGroups
1119 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1120 struct samr_EnumDomainGroups *r)
1122 struct dcesrv_handle *h;
1123 struct samr_domain_state *d_state;
1124 struct ldb_message **res;
1126 uint32_t first, count;
1127 struct samr_SamEntry *entries;
1128 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1129 struct samr_SamArray *sam;
1131 *r->out.resume_handle = 0;
1133 *r->out.num_entries = 0;
1135 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1139 /* search for all domain groups in this domain. This could possibly be
1140 cached and resumed based on resume_key */
1141 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1142 d_state->domain_dn, &res, attrs,
1143 d_state->domain_sid,
1144 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1145 GTYPE_SECURITY_UNIVERSAL_GROUP,
1146 GTYPE_SECURITY_GLOBAL_GROUP);
1147 if (ldb_cnt == -1) {
1148 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1151 /* convert to SamEntry format */
1152 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1154 return NT_STATUS_NO_MEMORY;
1159 for (i=0;i<ldb_cnt;i++) {
1160 struct dom_sid *group_sid;
1162 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1164 if (group_sid == NULL)
1167 entries[count].idx =
1168 group_sid->sub_auths[group_sid->num_auths-1];
1169 entries[count].name.string =
1170 samdb_result_string(res[i], "sAMAccountName", "");
1174 /* sort the results by rid */
1175 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1177 /* find the first entry to return */
1179 first<count && entries[first].idx <= *r->in.resume_handle;
1182 /* return the rest, limit by max_size. Note that we
1183 use the w2k3 element size value of 54 */
1184 *r->out.num_entries = count - first;
1185 *r->out.num_entries = MIN(*r->out.num_entries,
1186 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1188 sam = talloc(mem_ctx, struct samr_SamArray);
1190 return NT_STATUS_NO_MEMORY;
1193 sam->entries = entries+first;
1194 sam->count = *r->out.num_entries;
1198 if (*r->out.num_entries < count - first) {
1199 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1200 return STATUS_MORE_ENTRIES;
1203 return NT_STATUS_OK;
1210 This call uses transactions to ensure we don't get a new conflicting
1211 user while we are processing this, and to ensure the user either
1212 completly exists, or does not.
1214 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1215 struct samr_CreateUser2 *r)
1218 struct samr_domain_state *d_state;
1219 struct samr_account_state *a_state;
1220 struct dcesrv_handle *h;
1222 struct dom_sid *sid;
1223 struct dcesrv_handle *u_handle;
1224 const char *account_name;
1226 ZERO_STRUCTP(r->out.user_handle);
1227 *r->out.access_granted = 0;
1230 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1234 if (d_state->builtin) {
1235 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1236 return NT_STATUS_ACCESS_DENIED;
1237 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1238 /* Domain trust accounts must be created by the LSA calls */
1239 return NT_STATUS_ACCESS_DENIED;
1241 account_name = r->in.account_name->string;
1243 if (account_name == NULL) {
1244 return NT_STATUS_INVALID_PARAMETER;
1247 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, &sid, &dn);
1248 if (!NT_STATUS_IS_OK(status)) {
1251 a_state = talloc(mem_ctx, struct samr_account_state);
1253 ldb_transaction_cancel(d_state->sam_ctx);
1254 return NT_STATUS_NO_MEMORY;
1256 a_state->sam_ctx = d_state->sam_ctx;
1257 a_state->access_mask = r->in.access_mask;
1258 a_state->domain_state = talloc_reference(a_state, d_state);
1259 a_state->account_dn = talloc_steal(a_state, dn);
1261 a_state->account_name = talloc_steal(a_state, account_name);
1262 if (!a_state->account_name) {
1263 return NT_STATUS_NO_MEMORY;
1266 /* create the policy handle */
1267 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1269 return NT_STATUS_NO_MEMORY;
1272 u_handle->data = talloc_steal(u_handle, a_state);
1274 *r->out.user_handle = u_handle->wire_handle;
1275 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1277 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1279 return NT_STATUS_OK;
1286 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1287 struct samr_CreateUser *r)
1289 struct samr_CreateUser2 r2;
1290 uint32_t access_granted = 0;
1293 /* a simple wrapper around samr_CreateUser2 works nicely */
1294 r2.in.domain_handle = r->in.domain_handle;
1295 r2.in.account_name = r->in.account_name;
1296 r2.in.acct_flags = ACB_NORMAL;
1297 r2.in.access_mask = r->in.access_mask;
1298 r2.out.user_handle = r->out.user_handle;
1299 r2.out.access_granted = &access_granted;
1300 r2.out.rid = r->out.rid;
1302 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1306 samr_EnumDomainUsers
1308 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1309 struct samr_EnumDomainUsers *r)
1311 struct dcesrv_handle *h;
1312 struct samr_domain_state *d_state;
1313 struct ldb_result *res;
1316 uint32_t num_filtered_entries, first;
1317 struct samr_SamEntry *entries;
1318 const char * const attrs[] = { "objectSid", "sAMAccountName",
1319 "userAccountControl", NULL };
1320 struct samr_SamArray *sam;
1322 *r->out.resume_handle = 0;
1324 *r->out.num_entries = 0;
1326 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1330 /* don't have to worry about users in the builtin domain, as there are none */
1331 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1333 if (ret != LDB_SUCCESS) {
1334 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1335 ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1336 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1339 /* convert to SamEntry format */
1340 entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1342 return NT_STATUS_NO_MEMORY;
1344 num_filtered_entries = 0;
1345 for (i=0;i<res->count;i++) {
1346 /* Check if a mask has been requested */
1347 if (r->in.acct_flags
1348 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i],
1349 d_state->domain_dn) & r->in.acct_flags) == 0)) {
1352 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1353 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1354 num_filtered_entries++;
1357 /* sort the results by rid */
1358 TYPESAFE_QSORT(entries, num_filtered_entries, compare_SamEntry);
1360 /* find the first entry to return */
1362 first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1365 /* return the rest, limit by max_size. Note that we
1366 use the w2k3 element size value of 54 */
1367 *r->out.num_entries = num_filtered_entries - first;
1368 *r->out.num_entries = MIN(*r->out.num_entries,
1369 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1371 sam = talloc(mem_ctx, struct samr_SamArray);
1373 return NT_STATUS_NO_MEMORY;
1376 sam->entries = entries+first;
1377 sam->count = *r->out.num_entries;
1381 if (first == num_filtered_entries) {
1382 return NT_STATUS_OK;
1385 if (*r->out.num_entries < num_filtered_entries - first) {
1386 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1387 return STATUS_MORE_ENTRIES;
1390 return NT_STATUS_OK;
1397 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1398 struct samr_CreateDomAlias *r)
1400 struct samr_domain_state *d_state;
1401 struct samr_account_state *a_state;
1402 struct dcesrv_handle *h;
1403 const char *alias_name, *name;
1404 struct ldb_message *msg;
1405 struct dom_sid *sid;
1406 struct dcesrv_handle *a_handle;
1409 ZERO_STRUCTP(r->out.alias_handle);
1412 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1416 if (d_state->builtin) {
1417 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1418 return NT_STATUS_ACCESS_DENIED;
1421 alias_name = r->in.alias_name->string;
1423 if (alias_name == NULL) {
1424 return NT_STATUS_INVALID_PARAMETER;
1427 /* Check if alias already exists */
1428 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1430 "(sAMAccountName=%s)(objectclass=group))",
1431 ldb_binary_encode_string(mem_ctx, alias_name));
1434 return NT_STATUS_ALIAS_EXISTS;
1437 msg = ldb_msg_new(mem_ctx);
1439 return NT_STATUS_NO_MEMORY;
1442 /* add core elements to the ldb_message for the alias */
1443 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1444 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1446 return NT_STATUS_NO_MEMORY;
1449 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1450 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1451 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1453 /* create the alias */
1454 ret = ldb_add(d_state->sam_ctx, msg);
1458 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1459 return NT_STATUS_ALIAS_EXISTS;
1460 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1461 return NT_STATUS_ACCESS_DENIED;
1463 DEBUG(0,("Failed to create alias record %s: %s\n",
1464 ldb_dn_get_linearized(msg->dn),
1465 ldb_errstring(d_state->sam_ctx)));
1466 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1469 a_state = talloc(mem_ctx, struct samr_account_state);
1471 return NT_STATUS_NO_MEMORY;
1474 a_state->sam_ctx = d_state->sam_ctx;
1475 a_state->access_mask = r->in.access_mask;
1476 a_state->domain_state = talloc_reference(a_state, d_state);
1477 a_state->account_dn = talloc_steal(a_state, msg->dn);
1479 /* retrieve the sid for the alias just created */
1480 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1481 msg->dn, "objectSid", NULL);
1483 a_state->account_name = talloc_strdup(a_state, alias_name);
1484 if (!a_state->account_name) {
1485 return NT_STATUS_NO_MEMORY;
1488 /* create the policy handle */
1489 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1490 if (a_handle == NULL)
1491 return NT_STATUS_NO_MEMORY;
1493 a_handle->data = talloc_steal(a_handle, a_state);
1495 *r->out.alias_handle = a_handle->wire_handle;
1497 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1499 return NT_STATUS_OK;
1504 samr_EnumDomainAliases
1506 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1507 struct samr_EnumDomainAliases *r)
1509 struct dcesrv_handle *h;
1510 struct samr_domain_state *d_state;
1511 struct ldb_message **res;
1513 uint32_t first, count;
1514 struct samr_SamEntry *entries;
1515 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1516 struct samr_SamArray *sam;
1518 *r->out.resume_handle = 0;
1520 *r->out.num_entries = 0;
1522 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1526 /* search for all domain groups in this domain. This could possibly be
1527 cached and resumed based on resume_key */
1528 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1531 d_state->domain_sid,
1532 "(&(|(grouptype=%d)(grouptype=%d)))"
1533 "(objectclass=group))",
1534 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1535 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1536 if (ldb_cnt == -1) {
1537 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1540 return NT_STATUS_OK;
1543 /* convert to SamEntry format */
1544 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1546 return NT_STATUS_NO_MEMORY;
1551 for (i=0;i<ldb_cnt;i++) {
1552 struct dom_sid *alias_sid;
1554 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1557 if (alias_sid == NULL)
1560 entries[count].idx =
1561 alias_sid->sub_auths[alias_sid->num_auths-1];
1562 entries[count].name.string =
1563 samdb_result_string(res[i], "sAMAccountName", "");
1567 /* sort the results by rid */
1568 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1570 /* find the first entry to return */
1572 first<count && entries[first].idx <= *r->in.resume_handle;
1575 if (first == count) {
1576 return NT_STATUS_OK;
1579 *r->out.num_entries = count - first;
1580 *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1582 sam = talloc(mem_ctx, struct samr_SamArray);
1584 return NT_STATUS_NO_MEMORY;
1587 sam->entries = entries+first;
1588 sam->count = *r->out.num_entries;
1592 if (*r->out.num_entries < count - first) {
1593 *r->out.resume_handle =
1594 entries[first+*r->out.num_entries-1].idx;
1595 return STATUS_MORE_ENTRIES;
1598 return NT_STATUS_OK;
1603 samr_GetAliasMembership
1605 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1606 struct samr_GetAliasMembership *r)
1608 struct dcesrv_handle *h;
1609 struct samr_domain_state *d_state;
1610 struct ldb_message **res;
1613 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1617 if (r->in.sids->num_sids > 0) {
1619 const char * const attrs[2] = { "objectSid", NULL };
1621 filter = talloc_asprintf(mem_ctx,
1622 "(&(|(grouptype=%d)(grouptype=%d))"
1623 "(objectclass=group)(|",
1624 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1625 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1627 return NT_STATUS_NO_MEMORY;
1629 for (i=0; i<r->in.sids->num_sids; i++) {
1630 const char *memberdn;
1633 samdb_search_string(d_state->sam_ctx,
1635 "distinguishedName",
1637 ldap_encode_ndr_dom_sid(mem_ctx,
1638 r->in.sids->sids[i].sid));
1640 if (memberdn == NULL)
1643 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1646 return NT_STATUS_NO_MEMORY;
1649 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1650 d_state->domain_dn, &res, attrs,
1651 d_state->domain_sid, "%s))", filter);
1653 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1656 r->out.rids->count = 0;
1657 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1658 if (r->out.rids->ids == NULL)
1659 return NT_STATUS_NO_MEMORY;
1661 for (i=0; i<count; i++) {
1662 struct dom_sid *alias_sid;
1664 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1666 if (alias_sid == NULL) {
1667 DEBUG(0, ("Could not find objectSid\n"));
1671 r->out.rids->ids[r->out.rids->count] =
1672 alias_sid->sub_auths[alias_sid->num_auths-1];
1673 r->out.rids->count += 1;
1676 return NT_STATUS_OK;
1683 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1684 struct samr_LookupNames *r)
1686 struct dcesrv_handle *h;
1687 struct samr_domain_state *d_state;
1688 uint32_t i, num_mapped;
1689 NTSTATUS status = NT_STATUS_OK;
1690 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1693 ZERO_STRUCTP(r->out.rids);
1694 ZERO_STRUCTP(r->out.types);
1696 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1700 if (r->in.num_names == 0) {
1701 return NT_STATUS_OK;
1704 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1705 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1706 if (!r->out.rids->ids || !r->out.types->ids) {
1707 return NT_STATUS_NO_MEMORY;
1709 r->out.rids->count = r->in.num_names;
1710 r->out.types->count = r->in.num_names;
1714 for (i=0;i<r->in.num_names;i++) {
1715 struct ldb_message **res;
1716 struct dom_sid *sid;
1717 uint32_t atype, rtype;
1719 r->out.rids->ids[i] = 0;
1720 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1722 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1723 "sAMAccountName=%s",
1724 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1726 status = STATUS_SOME_UNMAPPED;
1730 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1732 status = STATUS_SOME_UNMAPPED;
1736 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1738 status = STATUS_SOME_UNMAPPED;
1742 rtype = ds_atype_map(atype);
1744 if (rtype == SID_NAME_UNKNOWN) {
1745 status = STATUS_SOME_UNMAPPED;
1749 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1750 r->out.types->ids[i] = rtype;
1754 if (num_mapped == 0) {
1755 return NT_STATUS_NONE_MAPPED;
1764 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1765 struct samr_LookupRids *r)
1767 struct dcesrv_handle *h;
1768 struct samr_domain_state *d_state;
1770 NTSTATUS status = NT_STATUS_OK;
1771 struct lsa_String *names;
1774 ZERO_STRUCTP(r->out.names);
1775 ZERO_STRUCTP(r->out.types);
1777 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1781 if (r->in.num_rids == 0)
1782 return NT_STATUS_OK;
1784 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1785 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1787 if ((names == NULL) || (ids == NULL))
1788 return NT_STATUS_NO_MEMORY;
1790 for (i=0; i<r->in.num_rids; i++) {
1791 struct ldb_message **res;
1793 const char * const attrs[] = { "sAMAccountType",
1794 "sAMAccountName", NULL };
1796 struct dom_sid *sid;
1798 ids[i] = SID_NAME_UNKNOWN;
1800 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid,
1803 names[i].string = NULL;
1804 status = STATUS_SOME_UNMAPPED;
1808 count = gendb_search(d_state->sam_ctx, mem_ctx,
1809 d_state->domain_dn, &res, attrs,
1811 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1813 names[i].string = NULL;
1814 status = STATUS_SOME_UNMAPPED;
1818 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1821 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1823 status = STATUS_SOME_UNMAPPED;
1827 ids[i] = ds_atype_map(atype);
1829 if (ids[i] == SID_NAME_UNKNOWN) {
1830 status = STATUS_SOME_UNMAPPED;
1835 r->out.names->names = names;
1836 r->out.names->count = r->in.num_rids;
1838 r->out.types->ids = ids;
1839 r->out.types->count = r->in.num_rids;
1848 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1849 struct samr_OpenGroup *r)
1851 struct samr_domain_state *d_state;
1852 struct samr_account_state *a_state;
1853 struct dcesrv_handle *h;
1854 const char *groupname;
1855 struct dom_sid *sid;
1856 struct ldb_message **msgs;
1857 struct dcesrv_handle *g_handle;
1858 const char * const attrs[2] = { "sAMAccountName", NULL };
1861 ZERO_STRUCTP(r->out.group_handle);
1863 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1867 /* form the group SID */
1868 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1870 return NT_STATUS_NO_MEMORY;
1873 /* search for the group record */
1874 ret = gendb_search(d_state->sam_ctx,
1875 mem_ctx, d_state->domain_dn, &msgs, attrs,
1876 "(&(objectSid=%s)(objectClass=group)"
1877 "(|(groupType=%d)(groupType=%d)))",
1878 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1879 GTYPE_SECURITY_UNIVERSAL_GROUP,
1880 GTYPE_SECURITY_GLOBAL_GROUP);
1882 return NT_STATUS_NO_SUCH_GROUP;
1885 DEBUG(0,("Found %d records matching sid %s\n",
1886 ret, dom_sid_string(mem_ctx, sid)));
1887 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1890 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1891 if (groupname == NULL) {
1892 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1893 dom_sid_string(mem_ctx, sid)));
1894 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1897 a_state = talloc(mem_ctx, struct samr_account_state);
1899 return NT_STATUS_NO_MEMORY;
1901 a_state->sam_ctx = d_state->sam_ctx;
1902 a_state->access_mask = r->in.access_mask;
1903 a_state->domain_state = talloc_reference(a_state, d_state);
1904 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1905 a_state->account_sid = talloc_steal(a_state, sid);
1906 a_state->account_name = talloc_strdup(a_state, groupname);
1907 if (!a_state->account_name) {
1908 return NT_STATUS_NO_MEMORY;
1911 /* create the policy handle */
1912 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1914 return NT_STATUS_NO_MEMORY;
1917 g_handle->data = talloc_steal(g_handle, a_state);
1919 *r->out.group_handle = g_handle->wire_handle;
1921 return NT_STATUS_OK;
1927 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1928 struct samr_QueryGroupInfo *r)
1930 struct dcesrv_handle *h;
1931 struct samr_account_state *a_state;
1932 struct ldb_message *msg;
1933 struct ldb_result *res;
1934 const char * const attrs[4] = { "sAMAccountName", "description",
1935 "numMembers", NULL };
1937 union samr_GroupInfo *info;
1939 *r->out.info = NULL;
1941 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1945 ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn,
1946 LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
1948 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1949 return NT_STATUS_NO_SUCH_GROUP;
1950 } else if (ret != LDB_SUCCESS) {
1951 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
1952 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1955 if (res->count != 1) {
1956 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
1958 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1962 /* allocate the info structure */
1963 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1965 return NT_STATUS_NO_MEMORY;
1968 /* Fill in the level */
1969 switch (r->in.level) {
1971 QUERY_STRING(msg, all.name, "sAMAccountName");
1972 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1973 QUERY_UINT (msg, all.num_members, "numMembers")
1974 QUERY_STRING(msg, all.description, "description");
1977 QUERY_STRING(msg, name, "sAMAccountName");
1979 case GROUPINFOATTRIBUTES:
1980 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1982 case GROUPINFODESCRIPTION:
1983 QUERY_STRING(msg, description, "description");
1986 QUERY_STRING(msg, all2.name, "sAMAccountName");
1987 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1988 QUERY_UINT (msg, all2.num_members, "numMembers")
1989 QUERY_STRING(msg, all2.description, "description");
1993 return NT_STATUS_INVALID_INFO_CLASS;
1996 *r->out.info = info;
1998 return NT_STATUS_OK;
2005 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2006 struct samr_SetGroupInfo *r)
2008 struct dcesrv_handle *h;
2009 struct samr_account_state *g_state;
2010 struct ldb_message *msg;
2011 struct ldb_context *sam_ctx;
2014 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2017 sam_ctx = g_state->sam_ctx;
2019 msg = ldb_msg_new(mem_ctx);
2021 return NT_STATUS_NO_MEMORY;
2024 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2026 return NT_STATUS_NO_MEMORY;
2029 switch (r->in.level) {
2030 case GROUPINFODESCRIPTION:
2031 SET_STRING(msg, description, "description");
2034 /* On W2k3 this does not change the name, it changes the
2035 * sAMAccountName attribute */
2036 SET_STRING(msg, name, "sAMAccountName");
2038 case GROUPINFOATTRIBUTES:
2039 /* This does not do anything obviously visible in W2k3 LDAP */
2040 return NT_STATUS_OK;
2042 return NT_STATUS_INVALID_INFO_CLASS;
2045 /* modify the samdb record */
2046 ret = ldb_modify(g_state->sam_ctx, msg);
2047 if (ret != LDB_SUCCESS) {
2048 /* we really need samdb.c to return NTSTATUS */
2049 return NT_STATUS_UNSUCCESSFUL;
2052 return NT_STATUS_OK;
2059 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2060 struct samr_AddGroupMember *r)
2062 struct dcesrv_handle *h;
2063 struct samr_account_state *a_state;
2064 struct samr_domain_state *d_state;
2065 struct ldb_message *mod;
2066 struct dom_sid *membersid;
2067 const char *memberdn;
2068 struct ldb_result *res;
2069 const char * const attrs[] = { NULL };
2072 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2075 d_state = a_state->domain_state;
2077 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2078 if (membersid == NULL) {
2079 return NT_STATUS_NO_MEMORY;
2082 /* In native mode, AD can also nest domain groups. Not sure yet
2083 * whether this is also available via RPC. */
2084 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2085 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2086 "(&(objectSid=%s)(objectclass=user))",
2087 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2089 if (ret != LDB_SUCCESS) {
2090 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2093 if (res->count == 0) {
2094 return NT_STATUS_NO_SUCH_USER;
2097 if (res->count > 1) {
2098 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2101 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2103 if (memberdn == NULL)
2104 return NT_STATUS_NO_MEMORY;
2106 mod = ldb_msg_new(mem_ctx);
2108 return NT_STATUS_NO_MEMORY;
2111 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2113 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2115 if (ret != LDB_SUCCESS) {
2116 return NT_STATUS_UNSUCCESSFUL;
2119 ret = ldb_modify(a_state->sam_ctx, mod);
2122 return NT_STATUS_OK;
2123 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2124 return NT_STATUS_MEMBER_IN_GROUP;
2125 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2126 return NT_STATUS_ACCESS_DENIED;
2128 return NT_STATUS_UNSUCCESSFUL;
2134 samr_DeleteDomainGroup
2136 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2137 struct samr_DeleteDomainGroup *r)
2139 struct dcesrv_handle *h;
2140 struct samr_account_state *a_state;
2143 *r->out.group_handle = *r->in.group_handle;
2145 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2149 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2150 if (ret != LDB_SUCCESS) {
2151 return NT_STATUS_UNSUCCESSFUL;
2155 ZERO_STRUCTP(r->out.group_handle);
2157 return NT_STATUS_OK;
2162 samr_DeleteGroupMember
2164 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2165 struct samr_DeleteGroupMember *r)
2167 struct dcesrv_handle *h;
2168 struct samr_account_state *a_state;
2169 struct samr_domain_state *d_state;
2170 struct ldb_message *mod;
2171 struct dom_sid *membersid;
2172 const char *memberdn;
2173 struct ldb_result *res;
2174 const char * const attrs[] = { NULL };
2177 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2180 d_state = a_state->domain_state;
2182 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2183 if (membersid == NULL)
2184 return NT_STATUS_NO_MEMORY;
2186 /* In native mode, AD can also nest domain groups. Not sure yet
2187 * whether this is also available via RPC. */
2188 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2189 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2190 "(&(objectSid=%s)(objectclass=user))",
2191 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2193 if (ret != LDB_SUCCESS) {
2194 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2197 if (res->count == 0) {
2198 return NT_STATUS_NO_SUCH_USER;
2201 if (res->count > 1) {
2202 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2205 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2207 if (memberdn == NULL)
2208 return NT_STATUS_NO_MEMORY;
2210 mod = ldb_msg_new(mem_ctx);
2212 return NT_STATUS_NO_MEMORY;
2215 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2217 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2219 if (ret != LDB_SUCCESS) {
2220 return NT_STATUS_NO_MEMORY;
2223 ret = ldb_modify(a_state->sam_ctx, mod);
2226 return NT_STATUS_OK;
2227 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2228 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2229 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2230 return NT_STATUS_ACCESS_DENIED;
2232 return NT_STATUS_UNSUCCESSFUL;
2238 samr_QueryGroupMember
2240 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2241 struct samr_QueryGroupMember *r)
2243 struct dcesrv_handle *h;
2244 struct samr_account_state *a_state;
2245 struct ldb_message **res;
2246 struct ldb_message_element *el;
2247 struct samr_RidTypeArray *array;
2248 const char * const attrs[2] = { "member", NULL };
2251 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2255 /* pull the member attribute */
2256 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2257 a_state->account_dn, &res, attrs);
2260 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2263 array = talloc(mem_ctx, struct samr_RidTypeArray);
2266 return NT_STATUS_NO_MEMORY;
2268 ZERO_STRUCTP(array);
2270 el = ldb_msg_find_element(res[0], "member");
2275 array->count = el->num_values;
2277 array->rids = talloc_array(mem_ctx, uint32_t,
2279 if (array->rids == NULL)
2280 return NT_STATUS_NO_MEMORY;
2282 array->types = talloc_array(mem_ctx, uint32_t,
2284 if (array->types == NULL)
2285 return NT_STATUS_NO_MEMORY;
2287 for (i=0; i<el->num_values; i++) {
2288 struct ldb_message **res2;
2289 const char * const attrs2[2] = { "objectSid", NULL };
2290 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2291 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2294 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2297 samdb_result_rid_from_sid(mem_ctx, res2[0],
2300 if (array->rids[i] == 0)
2301 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2303 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2307 *r->out.rids = array;
2309 return NT_STATUS_OK;
2314 samr_SetMemberAttributesOfGroup
2316 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2317 struct samr_SetMemberAttributesOfGroup *r)
2319 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2326 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2327 struct samr_OpenAlias *r)
2329 struct samr_domain_state *d_state;
2330 struct samr_account_state *a_state;
2331 struct dcesrv_handle *h;
2332 const char *alias_name;
2333 struct dom_sid *sid;
2334 struct ldb_message **msgs;
2335 struct dcesrv_handle *g_handle;
2336 const char * const attrs[2] = { "sAMAccountName", NULL };
2339 ZERO_STRUCTP(r->out.alias_handle);
2341 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2345 /* form the alias SID */
2346 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2348 return NT_STATUS_NO_MEMORY;
2350 /* search for the group record */
2351 ret = gendb_search(d_state->sam_ctx,
2352 mem_ctx, d_state->domain_dn, &msgs, attrs,
2353 "(&(objectSid=%s)(objectclass=group)"
2354 "(|(grouptype=%d)(grouptype=%d)))",
2355 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2356 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2357 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2359 return NT_STATUS_NO_SUCH_ALIAS;
2362 DEBUG(0,("Found %d records matching sid %s\n",
2363 ret, dom_sid_string(mem_ctx, sid)));
2364 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2367 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2368 if (alias_name == NULL) {
2369 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2370 dom_sid_string(mem_ctx, sid)));
2371 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2374 a_state = talloc(mem_ctx, struct samr_account_state);
2376 return NT_STATUS_NO_MEMORY;
2378 a_state->sam_ctx = d_state->sam_ctx;
2379 a_state->access_mask = r->in.access_mask;
2380 a_state->domain_state = talloc_reference(a_state, d_state);
2381 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2382 a_state->account_sid = talloc_steal(a_state, sid);
2383 a_state->account_name = talloc_strdup(a_state, alias_name);
2384 if (!a_state->account_name) {
2385 return NT_STATUS_NO_MEMORY;
2388 /* create the policy handle */
2389 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2391 return NT_STATUS_NO_MEMORY;
2394 g_handle->data = talloc_steal(g_handle, a_state);
2396 *r->out.alias_handle = g_handle->wire_handle;
2398 return NT_STATUS_OK;
2405 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2406 struct samr_QueryAliasInfo *r)
2408 struct dcesrv_handle *h;
2409 struct samr_account_state *a_state;
2410 struct ldb_message *msg, **res;
2411 const char * const attrs[4] = { "sAMAccountName", "description",
2412 "numMembers", NULL };
2414 union samr_AliasInfo *info;
2416 *r->out.info = NULL;
2418 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2422 /* pull all the alias attributes */
2423 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2424 a_state->account_dn ,&res, attrs);
2426 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2430 /* allocate the info structure */
2431 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2433 return NT_STATUS_NO_MEMORY;
2436 switch(r->in.level) {
2438 QUERY_STRING(msg, all.name, "sAMAccountName");
2439 QUERY_UINT (msg, all.num_members, "numMembers");
2440 QUERY_STRING(msg, all.description, "description");
2443 QUERY_STRING(msg, name, "sAMAccountName");
2445 case ALIASINFODESCRIPTION:
2446 QUERY_STRING(msg, description, "description");
2450 return NT_STATUS_INVALID_INFO_CLASS;
2453 *r->out.info = info;
2455 return NT_STATUS_OK;
2462 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2463 struct samr_SetAliasInfo *r)
2465 struct dcesrv_handle *h;
2466 struct samr_account_state *a_state;
2467 struct ldb_message *msg;
2468 struct ldb_context *sam_ctx;
2471 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2474 sam_ctx = a_state->sam_ctx;
2476 msg = ldb_msg_new(mem_ctx);
2478 return NT_STATUS_NO_MEMORY;
2481 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2483 return NT_STATUS_NO_MEMORY;
2486 switch (r->in.level) {
2487 case ALIASINFODESCRIPTION:
2488 SET_STRING(msg, description, "description");
2491 /* On W2k3 this does not change the name, it changes the
2492 * sAMAccountName attribute */
2493 SET_STRING(msg, name, "sAMAccountName");
2496 return NT_STATUS_INVALID_INFO_CLASS;
2499 /* modify the samdb record */
2500 ret = ldb_modify(a_state->sam_ctx, msg);
2501 if (ret != LDB_SUCCESS) {
2502 /* we really need samdb.c to return NTSTATUS */
2503 return NT_STATUS_UNSUCCESSFUL;
2506 return NT_STATUS_OK;
2513 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2514 struct samr_DeleteDomAlias *r)
2516 struct dcesrv_handle *h;
2517 struct samr_account_state *a_state;
2520 *r->out.alias_handle = *r->in.alias_handle;
2522 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2526 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2527 if (ret != LDB_SUCCESS) {
2528 return NT_STATUS_UNSUCCESSFUL;
2532 ZERO_STRUCTP(r->out.alias_handle);
2534 return NT_STATUS_OK;
2541 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2542 struct samr_AddAliasMember *r)
2544 struct dcesrv_handle *h;
2545 struct samr_account_state *a_state;
2546 struct samr_domain_state *d_state;
2547 struct ldb_message *mod;
2548 struct ldb_message **msgs;
2549 const char * const attrs[] = { NULL };
2550 struct ldb_dn *memberdn = NULL;
2554 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2557 d_state = a_state->domain_state;
2559 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2560 &msgs, attrs, "(objectsid=%s)",
2561 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2564 memberdn = msgs[0]->dn;
2565 } else if (ret > 1) {
2566 DEBUG(0,("Found %d records matching sid %s\n",
2567 ret, dom_sid_string(mem_ctx, r->in.sid)));
2568 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2569 } else if (ret == 0) {
2570 status = samdb_create_foreign_security_principal(
2571 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2572 if (!NT_STATUS_IS_OK(status)) {
2576 DEBUG(0, ("samdb_search returned %d: %s\n", ret,
2577 ldb_errstring(d_state->sam_ctx)));
2580 if (memberdn == NULL) {
2581 DEBUG(0, ("Could not find memberdn\n"));
2582 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2585 mod = ldb_msg_new(mem_ctx);
2587 return NT_STATUS_NO_MEMORY;
2590 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2592 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2593 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2594 if (ret != LDB_SUCCESS) {
2595 return NT_STATUS_UNSUCCESSFUL;
2598 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2599 return NT_STATUS_UNSUCCESSFUL;
2602 return NT_STATUS_OK;
2607 samr_DeleteAliasMember
2609 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2610 struct samr_DeleteAliasMember *r)
2612 struct dcesrv_handle *h;
2613 struct samr_account_state *a_state;
2614 struct samr_domain_state *d_state;
2615 struct ldb_message *mod;
2616 const char *memberdn;
2619 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2622 d_state = a_state->domain_state;
2624 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2625 "distinguishedName", "(objectSid=%s)",
2626 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2628 if (memberdn == NULL)
2629 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2631 mod = ldb_msg_new(mem_ctx);
2633 return NT_STATUS_NO_MEMORY;
2636 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2638 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2640 if (ret != LDB_SUCCESS)
2641 return NT_STATUS_UNSUCCESSFUL;
2643 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2644 return NT_STATUS_UNSUCCESSFUL;
2646 return NT_STATUS_OK;
2651 samr_GetMembersInAlias
2653 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2654 struct samr_GetMembersInAlias *r)
2656 struct dcesrv_handle *h;
2657 struct samr_account_state *a_state;
2658 struct samr_domain_state *d_state;
2659 struct ldb_message **msgs;
2660 struct lsa_SidPtr *sids;
2661 struct ldb_message_element *el;
2662 const char * const attrs[2] = { "member", NULL};
2665 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2668 d_state = a_state->domain_state;
2670 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2671 a_state->account_dn, &msgs, attrs);
2674 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2675 } else if (ret == 0) {
2676 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2677 } else if (ret != 1) {
2678 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2681 r->out.sids->num_sids = 0;
2682 r->out.sids->sids = NULL;
2684 el = ldb_msg_find_element(msgs[0], "member");
2689 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2693 return NT_STATUS_NO_MEMORY;
2695 for (i=0; i<el->num_values; i++) {
2696 struct ldb_message **msgs2;
2697 const char * const attrs2[2] = { "objectSid", NULL };
2698 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2699 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2702 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2704 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2707 if (sids[i].sid == NULL)
2708 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2710 r->out.sids->num_sids = el->num_values;
2711 r->out.sids->sids = sids;
2714 return NT_STATUS_OK;
2720 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2721 struct samr_OpenUser *r)
2723 struct samr_domain_state *d_state;
2724 struct samr_account_state *a_state;
2725 struct dcesrv_handle *h;
2726 const char *account_name;
2727 struct dom_sid *sid;
2728 struct ldb_message **msgs;
2729 struct dcesrv_handle *u_handle;
2730 const char * const attrs[2] = { "sAMAccountName", NULL };
2733 ZERO_STRUCTP(r->out.user_handle);
2735 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2739 /* form the users SID */
2740 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2742 return NT_STATUS_NO_MEMORY;
2745 /* search for the user record */
2746 ret = gendb_search(d_state->sam_ctx,
2747 mem_ctx, d_state->domain_dn, &msgs, attrs,
2748 "(&(objectSid=%s)(objectclass=user))",
2749 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2751 return NT_STATUS_NO_SUCH_USER;
2754 DEBUG(0,("Found %d records matching sid %s\n", ret,
2755 dom_sid_string(mem_ctx, sid)));
2756 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2759 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2760 if (account_name == NULL) {
2761 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2762 dom_sid_string(mem_ctx, sid)));
2763 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2766 a_state = talloc(mem_ctx, struct samr_account_state);
2768 return NT_STATUS_NO_MEMORY;
2770 a_state->sam_ctx = d_state->sam_ctx;
2771 a_state->access_mask = r->in.access_mask;
2772 a_state->domain_state = talloc_reference(a_state, d_state);
2773 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2774 a_state->account_sid = talloc_steal(a_state, sid);
2775 a_state->account_name = talloc_strdup(a_state, account_name);
2776 if (!a_state->account_name) {
2777 return NT_STATUS_NO_MEMORY;
2780 /* create the policy handle */
2781 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2783 return NT_STATUS_NO_MEMORY;
2786 u_handle->data = talloc_steal(u_handle, a_state);
2788 *r->out.user_handle = u_handle->wire_handle;
2790 return NT_STATUS_OK;
2798 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2799 struct samr_DeleteUser *r)
2801 struct dcesrv_handle *h;
2802 struct samr_account_state *a_state;
2805 *r->out.user_handle = *r->in.user_handle;
2807 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2811 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2812 if (ret != LDB_SUCCESS) {
2813 DEBUG(1, ("Failed to delete user: %s: %s\n",
2814 ldb_dn_get_linearized(a_state->account_dn),
2815 ldb_errstring(a_state->sam_ctx)));
2816 return NT_STATUS_UNSUCCESSFUL;
2820 ZERO_STRUCTP(r->out.user_handle);
2822 return NT_STATUS_OK;
2829 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2830 struct samr_QueryUserInfo *r)
2832 struct dcesrv_handle *h;
2833 struct samr_account_state *a_state;
2834 struct ldb_message *msg, **res;
2836 struct ldb_context *sam_ctx;
2838 const char * const *attrs = NULL;
2839 union samr_UserInfo *info;
2841 *r->out.info = NULL;
2843 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2846 sam_ctx = a_state->sam_ctx;
2848 /* fill in the reply */
2849 switch (r->in.level) {
2852 static const char * const attrs2[] = {"sAMAccountName",
2863 static const char * const attrs2[] = {"comment",
2872 static const char * const attrs2[] = {"sAMAccountName",
2887 "userAccountControl",
2894 static const char * const attrs2[] = {"logonHours",
2901 static const char * const attrs2[] = {"sAMAccountName",
2918 "userAccountControl",
2925 static const char * const attrs2[] = {"sAMAccountName",
2933 static const char * const attrs2[] = {"sAMAccountName",
2940 static const char * const attrs2[] = {"displayName",
2947 static const char * const attrs2[] = {"primaryGroupID",
2954 static const char * const attrs2[] = {"homeDirectory",
2962 static const char * const attrs2[] = {"scriptPath",
2969 static const char * const attrs2[] = {"profilePath",
2976 static const char * const attrs2[] = {"description",
2983 static const char * const attrs2[] = {"userWorkstations",
2990 static const char * const attrs2[] = {"userAccountControl",
2998 static const char * const attrs2[] = {"accountExpires",
3005 return NT_STATUS_NOT_SUPPORTED;
3009 static const char * const attrs2[] = {"userParameters",
3016 static const char * const attrs2[] = {"lastLogon",
3032 "userAccountControl",
3047 return NT_STATUS_NOT_SUPPORTED;
3051 return NT_STATUS_INVALID_INFO_CLASS;
3055 /* pull all the user attributes */
3056 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3057 a_state->account_dn ,&res, attrs);
3059 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3063 /* allocate the info structure */
3064 info = talloc_zero(mem_ctx, union samr_UserInfo);
3066 return NT_STATUS_NO_MEMORY;
3069 /* fill in the reply */
3070 switch (r->in.level) {
3072 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3073 QUERY_STRING(msg, info1.full_name, "displayName");
3074 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3075 QUERY_STRING(msg, info1.description, "description");
3076 QUERY_STRING(msg, info1.comment, "comment");
3080 QUERY_STRING(msg, info2.comment, "comment");
3081 QUERY_UINT (msg, info2.country_code, "countryCode");
3082 QUERY_UINT (msg, info2.code_page, "codePage");
3086 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3087 QUERY_STRING(msg, info3.full_name, "displayName");
3088 QUERY_RID (msg, info3.rid, "objectSid");
3089 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3090 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3091 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3092 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3093 QUERY_STRING(msg, info3.profile_path, "profilePath");
3094 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3095 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3096 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3097 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3098 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3099 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3100 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3101 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3102 QUERY_UINT (msg, info3.logon_count, "logonCount");
3103 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3107 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3111 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3112 QUERY_STRING(msg, info5.full_name, "displayName");
3113 QUERY_RID (msg, info5.rid, "objectSid");
3114 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3115 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3116 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3117 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3118 QUERY_STRING(msg, info5.profile_path, "profilePath");
3119 QUERY_STRING(msg, info5.description, "description");
3120 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3121 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3122 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3123 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3124 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3125 QUERY_UINT (msg, info5.logon_count, "logonCount");
3126 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3127 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3128 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3132 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3133 QUERY_STRING(msg, info6.full_name, "displayName");
3137 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3141 QUERY_STRING(msg, info8.full_name, "displayName");
3145 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3149 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3150 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3154 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3158 QUERY_STRING(msg, info12.profile_path, "profilePath");
3162 QUERY_STRING(msg, info13.description, "description");
3166 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3170 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3174 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3178 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3182 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3183 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3184 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3185 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3186 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3187 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3188 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3189 QUERY_STRING(msg, info21.full_name, "displayName");
3190 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3191 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3192 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3193 QUERY_STRING(msg, info21.profile_path, "profilePath");
3194 QUERY_STRING(msg, info21.description, "description");
3195 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3196 QUERY_STRING(msg, info21.comment, "comment");
3197 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3198 QUERY_RID (msg, info21.rid, "objectSid");
3199 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3200 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3201 info->info21.fields_present = 0x00FFFFFF;
3202 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3203 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3204 QUERY_UINT (msg, info21.logon_count, "logonCount");
3205 QUERY_UINT (msg, info21.country_code, "countryCode");
3206 QUERY_UINT (msg, info21.code_page, "codePage");
3212 return NT_STATUS_INVALID_INFO_CLASS;
3215 *r->out.info = info;
3217 return NT_STATUS_OK;
3224 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3225 struct samr_SetUserInfo *r)
3227 struct dcesrv_handle *h;
3228 struct samr_account_state *a_state;
3229 struct ldb_message *msg;
3231 NTSTATUS status = NT_STATUS_OK;
3232 struct ldb_context *sam_ctx;
3234 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3237 sam_ctx = a_state->sam_ctx;
3239 msg = ldb_msg_new(mem_ctx);
3241 return NT_STATUS_NO_MEMORY;
3244 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3246 return NT_STATUS_NO_MEMORY;
3249 switch (r->in.level) {
3251 SET_STRING(msg, info2.comment, "comment");
3252 SET_UINT (msg, info2.country_code, "countryCode");
3253 SET_UINT (msg, info2.code_page, "codePage");
3257 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3261 SET_STRING(msg, info6.account_name, "samAccountName");
3262 SET_STRING(msg, info6.full_name, "displayName");
3266 SET_STRING(msg, info7.account_name, "samAccountName");
3270 SET_STRING(msg, info8.full_name, "displayName");
3274 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3278 SET_STRING(msg, info10.home_directory, "homeDirectory");
3279 SET_STRING(msg, info10.home_drive, "homeDrive");
3283 SET_STRING(msg, info11.logon_script, "scriptPath");
3287 SET_STRING(msg, info12.profile_path, "profilePath");
3291 SET_STRING(msg, info13.description, "description");
3295 SET_STRING(msg, info14.workstations, "userWorkstations");
3299 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3303 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3307 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3311 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3312 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3313 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3314 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3315 SET_STRING(msg, info21.account_name, "samAccountName");
3316 IFSET(SAMR_FIELD_FULL_NAME)
3317 SET_STRING(msg, info21.full_name, "displayName");
3318 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3319 SET_STRING(msg, info21.home_directory, "homeDirectory");
3320 IFSET(SAMR_FIELD_HOME_DRIVE)
3321 SET_STRING(msg, info21.home_drive, "homeDrive");
3322 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3323 SET_STRING(msg, info21.logon_script, "scriptPath");
3324 IFSET(SAMR_FIELD_PROFILE_PATH)
3325 SET_STRING(msg, info21.profile_path, "profilePath");
3326 IFSET(SAMR_FIELD_DESCRIPTION)
3327 SET_STRING(msg, info21.description, "description");
3328 IFSET(SAMR_FIELD_WORKSTATIONS)
3329 SET_STRING(msg, info21.workstations, "userWorkstations");
3330 IFSET(SAMR_FIELD_COMMENT)
3331 SET_STRING(msg, info21.comment, "comment");
3332 IFSET(SAMR_FIELD_PARAMETERS)
3333 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3334 IFSET(SAMR_FIELD_PRIMARY_GID)
3335 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3336 IFSET(SAMR_FIELD_ACCT_FLAGS)
3337 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3338 IFSET(SAMR_FIELD_LOGON_HOURS)
3339 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3340 IFSET(SAMR_FIELD_COUNTRY_CODE)
3341 SET_UINT (msg, info21.country_code, "countryCode");
3342 IFSET(SAMR_FIELD_CODE_PAGE)
3343 SET_UINT (msg, info21.code_page, "codePage");
3348 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3349 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3350 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3351 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3352 SET_STRING(msg, info23.info.account_name, "samAccountName");
3353 IFSET(SAMR_FIELD_FULL_NAME)
3354 SET_STRING(msg, info23.info.full_name, "displayName");
3355 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3356 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3357 IFSET(SAMR_FIELD_HOME_DRIVE)
3358 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3359 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3360 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3361 IFSET(SAMR_FIELD_PROFILE_PATH)
3362 SET_STRING(msg, info23.info.profile_path, "profilePath");
3363 IFSET(SAMR_FIELD_DESCRIPTION)
3364 SET_STRING(msg, info23.info.description, "description");
3365 IFSET(SAMR_FIELD_WORKSTATIONS)
3366 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3367 IFSET(SAMR_FIELD_COMMENT)
3368 SET_STRING(msg, info23.info.comment, "comment");
3369 IFSET(SAMR_FIELD_PARAMETERS)
3370 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3371 IFSET(SAMR_FIELD_PRIMARY_GID)
3372 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3373 IFSET(SAMR_FIELD_ACCT_FLAGS)
3374 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3375 IFSET(SAMR_FIELD_LOGON_HOURS)
3376 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3377 IFSET(SAMR_FIELD_COUNTRY_CODE)
3378 SET_UINT (msg, info23.info.country_code, "countryCode");
3379 IFSET(SAMR_FIELD_CODE_PAGE)
3380 SET_UINT (msg, info23.info.code_page, "codePage");
3382 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3383 status = samr_set_password(dce_call,
3385 a_state->account_dn,
3386 a_state->domain_state->domain_dn,
3388 &r->in.info->info23.password);
3389 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3390 status = samr_set_password(dce_call,
3392 a_state->account_dn,
3393 a_state->domain_state->domain_dn,
3395 &r->in.info->info23.password);
3400 /* the set password levels are handled separately */
3402 status = samr_set_password(dce_call,
3404 a_state->account_dn,
3405 a_state->domain_state->domain_dn,
3407 &r->in.info->info24.password);
3411 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3412 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3413 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3414 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3415 SET_STRING(msg, info25.info.account_name, "samAccountName");
3416 IFSET(SAMR_FIELD_FULL_NAME)
3417 SET_STRING(msg, info25.info.full_name, "displayName");
3418 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3419 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3420 IFSET(SAMR_FIELD_HOME_DRIVE)
3421 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3422 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3423 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3424 IFSET(SAMR_FIELD_PROFILE_PATH)
3425 SET_STRING(msg, info25.info.profile_path, "profilePath");
3426 IFSET(SAMR_FIELD_DESCRIPTION)
3427 SET_STRING(msg, info25.info.description, "description");
3428 IFSET(SAMR_FIELD_WORKSTATIONS)
3429 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3430 IFSET(SAMR_FIELD_COMMENT)
3431 SET_STRING(msg, info25.info.comment, "comment");
3432 IFSET(SAMR_FIELD_PARAMETERS)
3433 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3434 IFSET(SAMR_FIELD_PRIMARY_GID)
3435 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3436 IFSET(SAMR_FIELD_ACCT_FLAGS)
3437 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3438 IFSET(SAMR_FIELD_LOGON_HOURS)
3439 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3440 IFSET(SAMR_FIELD_COUNTRY_CODE)
3441 SET_UINT (msg, info25.info.country_code, "countryCode");
3442 IFSET(SAMR_FIELD_CODE_PAGE)
3443 SET_UINT (msg, info25.info.code_page, "codePage");
3445 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3446 status = samr_set_password_ex(dce_call,
3448 a_state->account_dn,
3449 a_state->domain_state->domain_dn,
3451 &r->in.info->info25.password);
3452 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3453 status = samr_set_password_ex(dce_call,
3455 a_state->account_dn,
3456 a_state->domain_state->domain_dn,
3458 &r->in.info->info25.password);
3463 /* the set password levels are handled separately */
3465 status = samr_set_password_ex(dce_call,
3467 a_state->account_dn,
3468 a_state->domain_state->domain_dn,
3470 &r->in.info->info26.password);
3475 /* many info classes are not valid for SetUserInfo */
3476 return NT_STATUS_INVALID_INFO_CLASS;
3479 if (!NT_STATUS_IS_OK(status)) {
3483 /* modify the samdb record */
3484 if (msg->num_elements > 0) {
3485 ret = ldb_modify(a_state->sam_ctx, msg);
3486 if (ret != LDB_SUCCESS) {
3487 DEBUG(1,("Failed to modify record %s: %s\n",
3488 ldb_dn_get_linearized(a_state->account_dn),
3489 ldb_errstring(a_state->sam_ctx)));
3491 /* we really need samdb.c to return NTSTATUS */
3492 return NT_STATUS_UNSUCCESSFUL;
3496 return NT_STATUS_OK;
3501 samr_GetGroupsForUser
3503 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3504 struct samr_GetGroupsForUser *r)
3506 struct dcesrv_handle *h;
3507 struct samr_account_state *a_state;
3508 struct samr_domain_state *d_state;
3509 struct ldb_message **res;
3510 const char * const attrs[2] = { "objectSid", NULL };
3511 struct samr_RidWithAttributeArray *array;
3514 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3517 d_state = a_state->domain_state;
3519 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3520 d_state->domain_dn, &res,
3521 attrs, d_state->domain_sid,
3522 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3523 ldb_dn_get_linearized(a_state->account_dn),
3524 GTYPE_SECURITY_GLOBAL_GROUP);
3526 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3528 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3530 return NT_STATUS_NO_MEMORY;
3535 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3537 if (array->rids == NULL)
3538 return NT_STATUS_NO_MEMORY;
3540 /* Adds the primary group */
3541 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3542 ~0, a_state->account_dn,
3543 "primaryGroupID", NULL);
3544 array->rids[0].attributes = SE_GROUP_MANDATORY
3545 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3548 /* Adds the additional groups */
3549 for (i = 0; i < count; i++) {
3550 struct dom_sid *group_sid;
3552 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3553 if (group_sid == NULL) {
3554 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3558 array->rids[i + 1].rid =
3559 group_sid->sub_auths[group_sid->num_auths-1];
3560 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3561 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3565 *r->out.rids = array;
3567 return NT_STATUS_OK;
3572 samr_QueryDisplayInfo
3574 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3575 struct samr_QueryDisplayInfo *r)
3577 struct dcesrv_handle *h;
3578 struct samr_domain_state *d_state;
3579 struct ldb_message **res;
3582 const char * const attrs[] = { "objectSid", "sAMAccountName",
3583 "displayName", "description", "userAccountControl",
3584 "pwdLastSet", NULL };
3585 struct samr_DispEntryFull *entriesFull = NULL;
3586 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3587 struct samr_DispEntryAscii *entriesAscii = NULL;
3588 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3591 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3595 switch (r->in.level) {
3598 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3599 "(sAMAccountType=%u))",
3600 ATYPE_NORMAL_ACCOUNT);
3603 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3604 "(sAMAccountType=%u))",
3605 ATYPE_WORKSTATION_TRUST);
3609 filter = talloc_asprintf(mem_ctx,
3610 "(&(|(groupType=%d)(groupType=%d))"
3611 "(objectClass=group))",
3612 GTYPE_SECURITY_UNIVERSAL_GROUP,
3613 GTYPE_SECURITY_GLOBAL_GROUP);
3616 return NT_STATUS_INVALID_INFO_CLASS;
3619 /* search for all requested objects in this domain. This could
3620 possibly be cached and resumed based on resume_key */
3621 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3622 d_state->domain_dn, &res, attrs,
3623 d_state->domain_sid, "%s", filter);
3624 if (ldb_cnt == -1) {
3625 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3627 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3628 return NT_STATUS_OK;
3631 switch (r->in.level) {
3633 entriesGeneral = talloc_array(mem_ctx,
3634 struct samr_DispEntryGeneral,
3638 entriesFull = talloc_array(mem_ctx,
3639 struct samr_DispEntryFull,
3643 entriesFullGroup = talloc_array(mem_ctx,
3644 struct samr_DispEntryFullGroup,
3649 entriesAscii = talloc_array(mem_ctx,
3650 struct samr_DispEntryAscii,
3655 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3656 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3657 return NT_STATUS_NO_MEMORY;
3661 for (i=0; i<ldb_cnt; i++) {
3662 struct dom_sid *objectsid;
3664 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3666 if (objectsid == NULL)
3669 switch(r->in.level) {
3671 entriesGeneral[count].idx = count + 1;
3672 entriesGeneral[count].rid =
3673 objectsid->sub_auths[objectsid->num_auths-1];
3674 entriesGeneral[count].acct_flags =
3675 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3677 d_state->domain_dn);
3678 entriesGeneral[count].account_name.string =
3679 samdb_result_string(res[i],
3680 "sAMAccountName", "");
3681 entriesGeneral[count].full_name.string =
3682 samdb_result_string(res[i], "displayName", "");
3683 entriesGeneral[count].description.string =
3684 samdb_result_string(res[i], "description", "");
3687 entriesFull[count].idx = count + 1;
3688 entriesFull[count].rid =
3689 objectsid->sub_auths[objectsid->num_auths-1];
3691 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3692 entriesFull[count].acct_flags =
3693 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3695 d_state->domain_dn) | ACB_NORMAL;
3696 entriesFull[count].account_name.string =
3697 samdb_result_string(res[i], "sAMAccountName",
3699 entriesFull[count].description.string =
3700 samdb_result_string(res[i], "description", "");
3703 entriesFullGroup[count].idx = count + 1;
3704 entriesFullGroup[count].rid =
3705 objectsid->sub_auths[objectsid->num_auths-1];
3706 /* We get a "7" here for groups */
3707 entriesFullGroup[count].acct_flags
3708 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3709 entriesFullGroup[count].account_name.string =
3710 samdb_result_string(res[i], "sAMAccountName",
3712 entriesFullGroup[count].description.string =
3713 samdb_result_string(res[i], "description", "");
3717 entriesAscii[count].idx = count + 1;
3718 entriesAscii[count].account_name.string =
3719 samdb_result_string(res[i], "sAMAccountName",
3727 *r->out.total_size = count;
3729 if (r->in.start_idx >= count) {
3730 *r->out.returned_size = 0;
3731 switch(r->in.level) {
3733 r->out.info->info1.count = *r->out.returned_size;
3734 r->out.info->info1.entries = NULL;
3737 r->out.info->info2.count = *r->out.returned_size;
3738 r->out.info->info2.entries = NULL;
3741 r->out.info->info3.count = *r->out.returned_size;
3742 r->out.info->info3.entries = NULL;
3745 r->out.info->info4.count = *r->out.returned_size;
3746 r->out.info->info4.entries = NULL;
3749 r->out.info->info5.count = *r->out.returned_size;
3750 r->out.info->info5.entries = NULL;
3754 *r->out.returned_size = MIN(count - r->in.start_idx,
3756 switch(r->in.level) {
3758 r->out.info->info1.count = *r->out.returned_size;
3759 r->out.info->info1.entries =
3760 &(entriesGeneral[r->in.start_idx]);
3763 r->out.info->info2.count = *r->out.returned_size;
3764 r->out.info->info2.entries =
3765 &(entriesFull[r->in.start_idx]);
3768 r->out.info->info3.count = *r->out.returned_size;
3769 r->out.info->info3.entries =
3770 &(entriesFullGroup[r->in.start_idx]);
3773 r->out.info->info4.count = *r->out.returned_size;
3774 r->out.info->info4.entries =
3775 &(entriesAscii[r->in.start_idx]);
3778 r->out.info->info5.count = *r->out.returned_size;
3779 r->out.info->info5.entries =
3780 &(entriesAscii[r->in.start_idx]);
3785 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3786 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3791 samr_GetDisplayEnumerationIndex
3793 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3794 struct samr_GetDisplayEnumerationIndex *r)
3796 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3801 samr_TestPrivateFunctionsDomain
3803 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3804 struct samr_TestPrivateFunctionsDomain *r)
3806 return NT_STATUS_NOT_IMPLEMENTED;
3811 samr_TestPrivateFunctionsUser
3813 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3814 struct samr_TestPrivateFunctionsUser *r)
3816 return NT_STATUS_NOT_IMPLEMENTED;
3823 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3824 struct samr_GetUserPwInfo *r)
3826 struct dcesrv_handle *h;
3827 struct samr_account_state *a_state;
3829 ZERO_STRUCTP(r->out.info);
3831 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3835 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3836 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3838 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3839 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3841 return NT_STATUS_OK;
3846 samr_RemoveMemberFromForeignDomain
3848 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3849 struct samr_RemoveMemberFromForeignDomain *r)
3851 struct dcesrv_handle *h;
3852 struct samr_domain_state *d_state;
3853 const char *memberdn;
3854 struct ldb_message **res;
3855 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3858 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3862 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3863 "distinguishedName", "(objectSid=%s)",
3864 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3866 if (memberdn == NULL) {
3867 return NT_STATUS_OK;
3870 /* TODO: Does this call only remove alias members, or does it do this
3871 * for domain groups as well? */
3873 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3874 d_state->domain_dn, &res, attrs,
3875 d_state->domain_sid,
3876 "(&(member=%s)(objectClass=group)"
3877 "(|(groupType=%d)(groupType=%d)))",
3879 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3880 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3883 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3885 for (i=0; i<count; i++) {
3886 struct ldb_message *mod;
3888 mod = ldb_msg_new(mem_ctx);
3890 return NT_STATUS_NO_MEMORY;
3893 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
3894 if (mod->dn == NULL) {
3899 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3900 "member", memberdn) != LDB_SUCCESS)
3901 return NT_STATUS_NO_MEMORY;
3903 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
3904 return NT_STATUS_UNSUCCESSFUL;
3909 return NT_STATUS_OK;
3914 samr_QueryDomainInfo2
3916 just an alias for samr_QueryDomainInfo
3918 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3919 struct samr_QueryDomainInfo2 *r)
3921 struct samr_QueryDomainInfo r1;
3924 ZERO_STRUCT(r1.out);
3925 r1.in.domain_handle = r->in.domain_handle;
3926 r1.in.level = r->in.level;
3927 r1.out.info = r->out.info;
3929 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3938 just an alias for samr_QueryUserInfo
3940 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3941 struct samr_QueryUserInfo2 *r)
3943 struct samr_QueryUserInfo r1;
3946 r1.in.user_handle = r->in.user_handle;
3947 r1.in.level = r->in.level;
3948 r1.out.info = r->out.info;
3950 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3957 samr_QueryDisplayInfo2
3959 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3960 struct samr_QueryDisplayInfo2 *r)
3962 struct samr_QueryDisplayInfo q;
3965 q.in.domain_handle = r->in.domain_handle;
3966 q.in.level = r->in.level;
3967 q.in.start_idx = r->in.start_idx;
3968 q.in.max_entries = r->in.max_entries;
3969 q.in.buf_size = r->in.buf_size;
3970 q.out.total_size = r->out.total_size;
3971 q.out.returned_size = r->out.returned_size;
3972 q.out.info = r->out.info;
3974 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3981 samr_GetDisplayEnumerationIndex2
3983 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3984 struct samr_GetDisplayEnumerationIndex2 *r)
3986 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3991 samr_QueryDisplayInfo3
3993 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3994 struct samr_QueryDisplayInfo3 *r)
3996 struct samr_QueryDisplayInfo q;
3999 q.in.domain_handle = r->in.domain_handle;
4000 q.in.level = r->in.level;
4001 q.in.start_idx = r->in.start_idx;
4002 q.in.max_entries = r->in.max_entries;
4003 q.in.buf_size = r->in.buf_size;
4004 q.out.total_size = r->out.total_size;
4005 q.out.returned_size = r->out.returned_size;
4006 q.out.info = r->out.info;
4008 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4015 samr_AddMultipleMembersToAlias
4017 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4018 struct samr_AddMultipleMembersToAlias *r)
4020 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4025 samr_RemoveMultipleMembersFromAlias
4027 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4028 struct samr_RemoveMultipleMembersFromAlias *r)
4030 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4037 this fetches the default password properties for a domain
4039 note that w2k3 completely ignores the domain name in this call, and
4040 always returns the information for the servers primary domain
4042 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4043 struct samr_GetDomPwInfo *r)
4045 struct ldb_message **msgs;
4047 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4048 struct ldb_context *sam_ctx;
4050 ZERO_STRUCTP(r->out.info);
4052 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4053 dce_call->conn->dce_ctx->lp_ctx,
4054 dce_call->conn->auth_state.session_info);
4055 if (sam_ctx == NULL) {
4056 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4059 /* The domain name in this call is ignored */
4060 ret = gendb_search_dn(sam_ctx,
4061 mem_ctx, NULL, &msgs, attrs);
4063 talloc_free(sam_ctx);
4065 return NT_STATUS_NO_SUCH_DOMAIN;
4069 talloc_free(sam_ctx);
4071 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4074 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4076 r->out.info->password_properties = samdb_result_uint(msgs[0],
4077 "pwdProperties", 1);
4080 talloc_unlink(mem_ctx, sam_ctx);
4082 return NT_STATUS_OK;
4089 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4090 struct samr_Connect2 *r)
4092 struct samr_Connect c;
4094 c.in.system_name = NULL;
4095 c.in.access_mask = r->in.access_mask;
4096 c.out.connect_handle = r->out.connect_handle;
4098 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4105 just an alias for samr_SetUserInfo
4107 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4108 struct samr_SetUserInfo2 *r)
4110 struct samr_SetUserInfo r2;
4112 r2.in.user_handle = r->in.user_handle;
4113 r2.in.level = r->in.level;
4114 r2.in.info = r->in.info;
4116 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4121 samr_SetBootKeyInformation
4123 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4124 struct samr_SetBootKeyInformation *r)
4126 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4131 samr_GetBootKeyInformation
4133 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4134 struct samr_GetBootKeyInformation *r)
4136 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4143 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4144 struct samr_Connect3 *r)
4146 struct samr_Connect c;
4148 c.in.system_name = NULL;
4149 c.in.access_mask = r->in.access_mask;
4150 c.out.connect_handle = r->out.connect_handle;
4152 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4159 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4160 struct samr_Connect4 *r)
4162 struct samr_Connect c;
4164 c.in.system_name = NULL;
4165 c.in.access_mask = r->in.access_mask;
4166 c.out.connect_handle = r->out.connect_handle;
4168 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4175 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4176 struct samr_Connect5 *r)
4178 struct samr_Connect c;
4181 c.in.system_name = NULL;
4182 c.in.access_mask = r->in.access_mask;
4183 c.out.connect_handle = r->out.connect_handle;
4185 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4187 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4188 r->out.info_out->info1.unknown2 = 0;
4189 *r->out.level_out = r->in.level_in;
4198 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4199 struct samr_RidToSid *r)
4201 struct samr_domain_state *d_state;
4202 struct dcesrv_handle *h;
4204 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4208 /* form the users SID */
4209 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4211 return NT_STATUS_NO_MEMORY;
4214 return NT_STATUS_OK;
4219 samr_SetDsrmPassword
4221 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4222 struct samr_SetDsrmPassword *r)
4224 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4229 samr_ValidatePassword
4231 For now the call checks the password complexity (if active) and the minimum
4232 password length on level 2 and 3. Level 1 is ignored for now.
4234 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4235 TALLOC_CTX *mem_ctx,
4236 struct samr_ValidatePassword *r)
4238 struct samr_GetDomPwInfo r2;
4239 struct samr_PwInfo pwInfo;
4241 enum samr_ValidationStatus res;
4244 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4246 r2.in.domain_name = NULL;
4247 r2.out.info = &pwInfo;
4248 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4249 if (!NT_STATUS_IS_OK(status)) {
4253 switch (r->in.level) {
4254 case NetValidateAuthentication:
4255 /* we don't support this yet */
4256 return NT_STATUS_NOT_SUPPORTED;
4258 case NetValidatePasswordChange:
4259 password = data_blob_const(r->in.req->req2.password.string,
4260 r->in.req->req2.password.length);
4261 res = samdb_check_password(&password,
4262 pwInfo.password_properties,
4263 pwInfo.min_password_length);
4264 (*r->out.rep)->ctr2.status = res;
4266 case NetValidatePasswordReset:
4267 password = data_blob_const(r->in.req->req3.password.string,
4268 r->in.req->req3.password.length);
4269 res = samdb_check_password(&password,
4270 pwInfo.password_properties,
4271 pwInfo.min_password_length);
4272 (*r->out.rep)->ctr3.status = res;
4275 return NT_STATUS_INVALID_INFO_CLASS;
4279 return NT_STATUS_OK;
4283 /* include the generated boilerplate */
4284 #include "librpc/gen_ndr/ndr_samr_s.c"