2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
44 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
46 #define QUERY_STRING(msg, field, attr) \
47 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
48 #define QUERY_UINT(msg, field, attr) \
49 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
50 #define QUERY_RID(msg, field, attr) \
51 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
52 #define QUERY_UINT64(msg, field, attr) \
53 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
54 #define QUERY_APASSC(msg, field, attr) \
55 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg, attr);
57 #define QUERY_FPASSC(msg, field, attr) \
58 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
59 a_state->domain_state->domain_dn, msg);
60 #define QUERY_LHOURS(msg, field, attr) \
61 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
62 #define QUERY_AFLAGS(msg, field, attr) \
63 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
64 #define QUERY_PARAMETERS(msg, field, attr) \
65 info->field = samdb_result_parameters(mem_ctx, msg, attr);
68 /* these are used to make the Set[User|Group]Info code easier to follow */
70 #define SET_STRING(msg, field, attr) do { \
71 struct ldb_message_element *set_el; \
72 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
73 if (r->in.info->field.string[0] == '\0') { \
74 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
75 return NT_STATUS_NO_MEMORY; \
78 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
79 return NT_STATUS_NO_MEMORY; \
81 set_el = ldb_msg_find_element(msg, attr); \
82 set_el->flags = LDB_FLAG_MOD_REPLACE; \
85 #define SET_UINT(msg, field, attr) do { \
86 struct ldb_message_element *set_el; \
87 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
88 return NT_STATUS_NO_MEMORY; \
90 set_el = ldb_msg_find_element(msg, attr); \
91 set_el->flags = LDB_FLAG_MOD_REPLACE; \
94 #define SET_INT64(msg, field, attr) do { \
95 struct ldb_message_element *set_el; \
96 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
97 return NT_STATUS_NO_MEMORY; \
99 set_el = ldb_msg_find_element(msg, attr); \
100 set_el->flags = LDB_FLAG_MOD_REPLACE; \
103 #define SET_UINT64(msg, field, attr) do { \
104 struct ldb_message_element *set_el; \
105 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
106 return NT_STATUS_NO_MEMORY; \
108 set_el = ldb_msg_find_element(msg, attr); \
109 set_el->flags = LDB_FLAG_MOD_REPLACE; \
112 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
114 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
115 return NT_STATUS_INVALID_PARAMETER; \
119 /* Set account flags, discarding flags that cannot be set with SAMR */
120 #define SET_AFLAGS(msg, field, attr) do { \
121 struct ldb_message_element *set_el; \
122 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
123 return NT_STATUS_INVALID_PARAMETER; \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
128 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
129 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
130 return NT_STATUS_NO_MEMORY; \
132 set_el = ldb_msg_find_element(msg, attr); \
133 set_el->flags = LDB_FLAG_MOD_REPLACE; \
136 #define SET_LHOURS(msg, field, attr) do { \
137 struct ldb_message_element *set_el; \
138 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
139 return NT_STATUS_NO_MEMORY; \
141 set_el = ldb_msg_find_element(msg, attr); \
142 set_el->flags = LDB_FLAG_MOD_REPLACE; \
145 #define SET_PARAMETERS(msg, field, attr) do { \
146 struct ldb_message_element *set_el; \
147 if (r->in.info->field.length != 0) { \
148 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
149 return NT_STATUS_NO_MEMORY; \
151 set_el = ldb_msg_find_element(msg, attr); \
152 set_el->flags = LDB_FLAG_MOD_REPLACE; \
161 create a connection to the SAM database
163 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
164 struct samr_Connect *r)
166 struct samr_connect_state *c_state;
167 struct dcesrv_handle *handle;
169 ZERO_STRUCTP(r->out.connect_handle);
171 c_state = talloc(mem_ctx, struct samr_connect_state);
173 return NT_STATUS_NO_MEMORY;
176 /* make sure the sam database is accessible */
177 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0);
178 if (c_state->sam_ctx == NULL) {
179 talloc_free(c_state);
180 return NT_STATUS_INVALID_SYSTEM_SERVICE;
184 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
186 talloc_free(c_state);
187 return NT_STATUS_NO_MEMORY;
190 handle->data = talloc_steal(handle, c_state);
192 c_state->access_mask = r->in.access_mask;
193 *r->out.connect_handle = handle->wire_handle;
202 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
203 struct samr_Close *r)
205 struct dcesrv_handle *h;
207 *r->out.handle = *r->in.handle;
209 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
213 ZERO_STRUCTP(r->out.handle);
222 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
223 struct samr_SetSecurity *r)
225 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
232 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
233 struct samr_QuerySecurity *r)
235 struct dcesrv_handle *h;
236 struct sec_desc_buf *sd;
238 *r->out.sdbuf = NULL;
240 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
242 sd = talloc(mem_ctx, struct sec_desc_buf);
244 return NT_STATUS_NO_MEMORY;
247 sd->sd = samdb_default_security_descriptor(mem_ctx);
258 we refuse this operation completely. If a admin wants to shutdown samr
259 in Samba then they should use the samba admin tools to disable the samr pipe
261 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
262 struct samr_Shutdown *r)
264 return NT_STATUS_ACCESS_DENIED;
271 this maps from a domain name to a SID
273 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
274 struct samr_LookupDomain *r)
276 struct samr_connect_state *c_state;
277 struct dcesrv_handle *h;
279 const char * const dom_attrs[] = { "objectSid", NULL};
280 struct ldb_message **dom_msgs;
285 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
289 if (r->in.domain_name->string == NULL) {
290 return NT_STATUS_INVALID_PARAMETER;
293 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
294 ret = gendb_search(c_state->sam_ctx,
295 mem_ctx, NULL, &dom_msgs, dom_attrs,
296 "(objectClass=builtinDomain)");
297 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
298 ret = gendb_search_dn(c_state->sam_ctx,
299 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
300 &dom_msgs, dom_attrs);
302 return NT_STATUS_NO_SUCH_DOMAIN;
305 return NT_STATUS_NO_SUCH_DOMAIN;
308 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
312 return NT_STATUS_NO_SUCH_DOMAIN;
324 list the domains in the SAM
326 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
327 struct samr_EnumDomains *r)
329 struct samr_connect_state *c_state;
330 struct dcesrv_handle *h;
331 struct samr_SamArray *array;
334 *r->out.resume_handle = 0;
336 *r->out.num_entries = 0;
338 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
342 *r->out.resume_handle = 2;
344 start_i = *r->in.resume_handle;
347 /* search past end of list is not an error for this call */
351 array = talloc(mem_ctx, struct samr_SamArray);
353 return NT_STATUS_NO_MEMORY;
357 array->entries = NULL;
359 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
360 if (array->entries == NULL) {
361 return NT_STATUS_NO_MEMORY;
364 for (i=0;i<2-start_i;i++) {
365 array->entries[i].idx = start_i + i;
367 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
369 array->entries[i].name.string = "BUILTIN";
374 *r->out.num_entries = i;
375 array->count = *r->out.num_entries;
384 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
385 struct samr_OpenDomain *r)
387 struct dcesrv_handle *h_conn, *h_domain;
388 struct samr_connect_state *c_state;
389 struct samr_domain_state *d_state;
390 const char * const dom_attrs[] = { "cn", NULL};
391 struct ldb_message **dom_msgs;
394 ZERO_STRUCTP(r->out.domain_handle);
396 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
398 c_state = h_conn->data;
400 if (r->in.sid == NULL) {
401 return NT_STATUS_INVALID_PARAMETER;
404 d_state = talloc(mem_ctx, struct samr_domain_state);
406 return NT_STATUS_NO_MEMORY;
409 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
411 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
412 d_state->builtin = true;
413 d_state->domain_name = "BUILTIN";
415 d_state->builtin = false;
416 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
419 ret = gendb_search(c_state->sam_ctx,
420 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
422 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
425 talloc_free(d_state);
426 return NT_STATUS_NO_SUCH_DOMAIN;
427 } else if (ret > 1) {
428 talloc_free(d_state);
429 return NT_STATUS_INTERNAL_DB_CORRUPTION;
430 } else if (ret == -1) {
431 talloc_free(d_state);
432 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
433 return NT_STATUS_INTERNAL_DB_CORRUPTION;
436 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
437 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
438 d_state->connect_state = talloc_reference(d_state, c_state);
439 d_state->sam_ctx = c_state->sam_ctx;
440 d_state->access_mask = r->in.access_mask;
442 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
444 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
446 talloc_free(d_state);
447 return NT_STATUS_NO_MEMORY;
450 h_domain->data = talloc_steal(h_domain, d_state);
452 *r->out.domain_handle = h_domain->wire_handle;
460 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
462 struct ldb_message **dom_msgs,
463 struct samr_DomInfo1 *info)
465 info->min_password_length =
466 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
467 info->password_history_length =
468 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
469 info->password_properties =
470 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
471 info->max_password_age =
472 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
473 info->min_password_age =
474 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
482 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
484 struct ldb_message **dom_msgs,
485 struct samr_DomGeneralInformation *info)
487 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
488 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
492 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
493 0x8000000000000000LL);
495 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
498 info->domain_name.string = state->domain_name;
500 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
502 switch (state->role) {
503 case ROLE_DOMAIN_CONTROLLER:
504 /* This pulls the NetBIOS name from the
505 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
507 if (samdb_is_pdc(state->sam_ctx)) {
508 info->role = SAMR_ROLE_DOMAIN_PDC;
510 info->role = SAMR_ROLE_DOMAIN_BDC;
513 case ROLE_DOMAIN_MEMBER:
514 info->role = SAMR_ROLE_DOMAIN_MEMBER;
516 case ROLE_STANDALONE:
517 info->role = SAMR_ROLE_STANDALONE;
521 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx,
523 "(objectClass=user)");
524 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx,
526 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
527 GTYPE_SECURITY_UNIVERSAL_GROUP,
528 GTYPE_SECURITY_GLOBAL_GROUP);
529 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx,
531 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
532 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
533 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
541 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
543 struct ldb_message **dom_msgs,
544 struct samr_DomInfo3 *info)
546 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
547 0x8000000000000000LL);
555 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
557 struct ldb_message **dom_msgs,
558 struct samr_DomOEMInformation *info)
560 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
570 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
572 struct ldb_message **dom_msgs,
573 struct samr_DomInfo5 *info)
575 info->domain_name.string = state->domain_name;
583 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
585 struct ldb_message **dom_msgs,
586 struct samr_DomInfo6 *info)
588 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
589 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
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,
721 struct samr_QueryDomainInfo *r)
723 struct dcesrv_handle *h;
724 struct samr_domain_state *d_state;
725 union samr_DomainInfo *info;
727 struct ldb_message **dom_msgs;
728 const char * const *attrs = NULL;
732 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
736 switch (r->in.level) {
739 static const char * const attrs2[] = { "minPwdLength",
750 static const char * const attrs2[] = {"forceLogoff",
760 static const char * const attrs2[] = {"forceLogoff",
767 static const char * const attrs2[] = {"oEMInformation",
779 static const char * const attrs2[] = { "domainReplica",
791 static const char * const attrs2[] = { "modifiedCount",
804 static const char * const attrs2[] = { "oEMInformation",
808 "lockOutObservationWindow",
816 static const char * const attrs2[] = { "lockoutDuration",
817 "lockOutObservationWindow",
825 static const char * const attrs2[] = { "modifiedCount",
833 return NT_STATUS_INVALID_INFO_CLASS;
837 /* some levels don't need a search */
840 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
841 d_state->domain_dn, &dom_msgs, attrs);
843 return NT_STATUS_NO_SUCH_DOMAIN;
846 return NT_STATUS_INTERNAL_DB_CORRUPTION;
850 /* allocate the info structure */
851 info = talloc_zero(mem_ctx, union samr_DomainInfo);
853 return NT_STATUS_NO_MEMORY;
858 switch (r->in.level) {
860 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
863 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
866 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
869 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
872 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
875 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
878 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
881 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
884 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
887 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
890 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
893 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
896 return NT_STATUS_INVALID_INFO_CLASS;
904 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
905 struct samr_SetDomainInfo *r)
907 struct dcesrv_handle *h;
908 struct samr_domain_state *d_state;
909 struct ldb_message *msg;
911 struct ldb_context *sam_ctx;
913 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
916 sam_ctx = d_state->sam_ctx;
918 msg = ldb_msg_new(mem_ctx);
920 return NT_STATUS_NO_MEMORY;
923 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
925 return NT_STATUS_NO_MEMORY;
928 switch (r->in.level) {
930 SET_UINT (msg, info1.min_password_length, "minPwdLength");
931 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
932 SET_UINT (msg, info1.password_properties, "pwdProperties");
933 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
934 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
937 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
940 SET_STRING(msg, oem.oem_information, "oEMInformation");
946 /* No op, we don't know where to set these */
951 * It is not possible to set lockout_duration < lockout_window.
952 * (The test is the other way around since the negative numbers
956 * This check should be moved to the backend, i.e. to some
957 * ldb module under dsdb/samdb/ldb_modules/ .
959 * This constraint is documented here for the samr rpc service:
960 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
961 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
963 * And here for the ldap backend:
964 * MS-ADTS 3.1.1.5.3.2 Constraints
965 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
967 if (r->in.info->info12.lockout_duration >
968 r->in.info->info12.lockout_window)
970 return NT_STATUS_INVALID_PARAMETER;
972 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
973 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
974 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
978 /* many info classes are not valid for SetDomainInfo */
979 return NT_STATUS_INVALID_INFO_CLASS;
982 /* modify the samdb record */
983 ret = ldb_modify(sam_ctx, msg);
984 if (ret != LDB_SUCCESS) {
985 DEBUG(1,("Failed to modify record %s: %s\n",
986 ldb_dn_get_linearized(d_state->domain_dn),
987 ldb_errstring(sam_ctx)));
988 return dsdb_ldb_err_to_ntstatus(ret);
995 samr_CreateDomainGroup
997 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
998 struct samr_CreateDomainGroup *r)
1001 struct samr_domain_state *d_state;
1002 struct samr_account_state *a_state;
1003 struct dcesrv_handle *h;
1004 const char *groupname;
1005 struct dom_sid *group_sid;
1006 struct ldb_dn *group_dn;
1007 struct dcesrv_handle *g_handle;
1009 ZERO_STRUCTP(r->out.group_handle);
1012 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1016 if (d_state->builtin) {
1017 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1018 return NT_STATUS_ACCESS_DENIED;
1021 groupname = r->in.name->string;
1023 if (groupname == NULL) {
1024 return NT_STATUS_INVALID_PARAMETER;
1027 status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1028 if (!NT_STATUS_IS_OK(status)) {
1032 a_state = talloc(mem_ctx, struct samr_account_state);
1034 return NT_STATUS_NO_MEMORY;
1036 a_state->sam_ctx = d_state->sam_ctx;
1037 a_state->access_mask = r->in.access_mask;
1038 a_state->domain_state = talloc_reference(a_state, d_state);
1039 a_state->account_dn = talloc_steal(a_state, group_dn);
1041 a_state->account_name = talloc_steal(a_state, groupname);
1043 /* create the policy handle */
1044 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1046 return NT_STATUS_NO_MEMORY;
1049 g_handle->data = talloc_steal(g_handle, a_state);
1051 *r->out.group_handle = g_handle->wire_handle;
1052 *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1054 return NT_STATUS_OK;
1059 comparison function for sorting SamEntry array
1061 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1063 return e1->idx - e2->idx;
1067 samr_EnumDomainGroups
1069 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1070 struct samr_EnumDomainGroups *r)
1072 struct dcesrv_handle *h;
1073 struct samr_domain_state *d_state;
1074 struct ldb_message **res;
1076 uint32_t first, count;
1077 struct samr_SamEntry *entries;
1078 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1079 struct samr_SamArray *sam;
1081 *r->out.resume_handle = 0;
1083 *r->out.num_entries = 0;
1085 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1089 /* search for all domain groups in this domain. This could possibly be
1090 cached and resumed based on resume_key */
1091 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1092 d_state->domain_dn, &res, attrs,
1093 d_state->domain_sid,
1094 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1095 GTYPE_SECURITY_UNIVERSAL_GROUP,
1096 GTYPE_SECURITY_GLOBAL_GROUP);
1098 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1101 /* convert to SamEntry format */
1102 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1104 return NT_STATUS_NO_MEMORY;
1109 for (i=0;i<ldb_cnt;i++) {
1110 struct dom_sid *group_sid;
1112 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1114 if (group_sid == NULL) {
1115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1118 entries[count].idx =
1119 group_sid->sub_auths[group_sid->num_auths-1];
1120 entries[count].name.string =
1121 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1125 /* sort the results by rid */
1126 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1128 /* find the first entry to return */
1130 first<count && entries[first].idx <= *r->in.resume_handle;
1133 /* return the rest, limit by max_size. Note that we
1134 use the w2k3 element size value of 54 */
1135 *r->out.num_entries = count - first;
1136 *r->out.num_entries = MIN(*r->out.num_entries,
1137 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1139 sam = talloc(mem_ctx, struct samr_SamArray);
1141 return NT_STATUS_NO_MEMORY;
1144 sam->entries = entries+first;
1145 sam->count = *r->out.num_entries;
1149 if (first == count) {
1150 return NT_STATUS_OK;
1153 if (*r->out.num_entries < count - first) {
1154 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1155 return STATUS_MORE_ENTRIES;
1158 return NT_STATUS_OK;
1165 This call uses transactions to ensure we don't get a new conflicting
1166 user while we are processing this, and to ensure the user either
1167 completly exists, or does not.
1169 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1170 struct samr_CreateUser2 *r)
1173 struct samr_domain_state *d_state;
1174 struct samr_account_state *a_state;
1175 struct dcesrv_handle *h;
1177 struct dom_sid *sid;
1178 struct dcesrv_handle *u_handle;
1179 const char *account_name;
1181 ZERO_STRUCTP(r->out.user_handle);
1182 *r->out.access_granted = 0;
1185 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1189 if (d_state->builtin) {
1190 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1191 return NT_STATUS_ACCESS_DENIED;
1192 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1193 /* Domain trust accounts must be created by the LSA calls */
1194 return NT_STATUS_ACCESS_DENIED;
1196 account_name = r->in.account_name->string;
1198 if (account_name == NULL) {
1199 return NT_STATUS_INVALID_PARAMETER;
1202 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, &sid, &dn);
1203 if (!NT_STATUS_IS_OK(status)) {
1206 a_state = talloc(mem_ctx, struct samr_account_state);
1208 return NT_STATUS_NO_MEMORY;
1210 a_state->sam_ctx = d_state->sam_ctx;
1211 a_state->access_mask = r->in.access_mask;
1212 a_state->domain_state = talloc_reference(a_state, d_state);
1213 a_state->account_dn = talloc_steal(a_state, dn);
1215 a_state->account_name = talloc_steal(a_state, account_name);
1216 if (!a_state->account_name) {
1217 return NT_STATUS_NO_MEMORY;
1220 /* create the policy handle */
1221 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1223 return NT_STATUS_NO_MEMORY;
1226 u_handle->data = talloc_steal(u_handle, a_state);
1228 *r->out.user_handle = u_handle->wire_handle;
1229 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1231 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1233 return NT_STATUS_OK;
1240 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1241 struct samr_CreateUser *r)
1243 struct samr_CreateUser2 r2;
1244 uint32_t access_granted = 0;
1247 /* a simple wrapper around samr_CreateUser2 works nicely */
1248 r2.in.domain_handle = r->in.domain_handle;
1249 r2.in.account_name = r->in.account_name;
1250 r2.in.acct_flags = ACB_NORMAL;
1251 r2.in.access_mask = r->in.access_mask;
1252 r2.out.user_handle = r->out.user_handle;
1253 r2.out.access_granted = &access_granted;
1254 r2.out.rid = r->out.rid;
1256 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1260 samr_EnumDomainUsers
1262 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1263 struct samr_EnumDomainUsers *r)
1265 struct dcesrv_handle *h;
1266 struct samr_domain_state *d_state;
1267 struct ldb_message **res;
1269 uint32_t first, count;
1270 struct samr_SamEntry *entries;
1271 const char * const attrs[] = { "objectSid", "sAMAccountName",
1272 "userAccountControl", NULL };
1273 struct samr_SamArray *sam;
1275 *r->out.resume_handle = 0;
1277 *r->out.num_entries = 0;
1279 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1283 /* search for all domain users in this domain. This could possibly be
1284 cached and resumed on resume_key */
1285 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1288 d_state->domain_sid,
1289 "(objectClass=user)");
1291 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1294 /* convert to SamEntry format */
1295 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1297 return NT_STATUS_NO_MEMORY;
1302 for (i=0;i<ldb_cnt;i++) {
1303 /* Check if a mask has been requested */
1304 if (r->in.acct_flags
1305 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
1306 res[i], d_state->domain_dn) & r->in.acct_flags) == 0)) {
1309 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1311 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1312 "sAMAccountName", "");
1316 /* sort the results by rid */
1317 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1319 /* find the first entry to return */
1321 first<count && entries[first].idx <= *r->in.resume_handle;
1324 /* return the rest, limit by max_size. Note that we
1325 use the w2k3 element size value of 54 */
1326 *r->out.num_entries = count - first;
1327 *r->out.num_entries = MIN(*r->out.num_entries,
1328 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1330 sam = talloc(mem_ctx, struct samr_SamArray);
1332 return NT_STATUS_NO_MEMORY;
1335 sam->entries = entries+first;
1336 sam->count = *r->out.num_entries;
1340 if (first == count) {
1341 return NT_STATUS_OK;
1344 if (*r->out.num_entries < count - first) {
1345 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1346 return STATUS_MORE_ENTRIES;
1349 return NT_STATUS_OK;
1356 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1357 struct samr_CreateDomAlias *r)
1359 struct samr_domain_state *d_state;
1360 struct samr_account_state *a_state;
1361 struct dcesrv_handle *h;
1362 const char *alias_name;
1363 struct dom_sid *sid;
1364 struct dcesrv_handle *a_handle;
1368 ZERO_STRUCTP(r->out.alias_handle);
1371 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1375 if (d_state->builtin) {
1376 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1377 return NT_STATUS_ACCESS_DENIED;
1380 alias_name = r->in.alias_name->string;
1382 if (alias_name == NULL) {
1383 return NT_STATUS_INVALID_PARAMETER;
1386 status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1387 if (!NT_STATUS_IS_OK(status)) {
1391 a_state = talloc(mem_ctx, struct samr_account_state);
1393 return NT_STATUS_NO_MEMORY;
1396 a_state->sam_ctx = d_state->sam_ctx;
1397 a_state->access_mask = r->in.access_mask;
1398 a_state->domain_state = talloc_reference(a_state, d_state);
1399 a_state->account_dn = talloc_steal(a_state, dn);
1401 a_state->account_name = talloc_steal(a_state, alias_name);
1403 /* create the policy handle */
1404 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1405 if (a_handle == NULL)
1406 return NT_STATUS_NO_MEMORY;
1408 a_handle->data = talloc_steal(a_handle, a_state);
1410 *r->out.alias_handle = a_handle->wire_handle;
1412 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1414 return NT_STATUS_OK;
1419 samr_EnumDomainAliases
1421 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1422 struct samr_EnumDomainAliases *r)
1424 struct dcesrv_handle *h;
1425 struct samr_domain_state *d_state;
1426 struct ldb_message **res;
1428 uint32_t first, count;
1429 struct samr_SamEntry *entries;
1430 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1431 struct samr_SamArray *sam;
1433 *r->out.resume_handle = 0;
1435 *r->out.num_entries = 0;
1437 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1441 /* search for all domain aliases in this domain. This could possibly be
1442 cached and resumed based on resume_key */
1443 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1445 d_state->domain_sid,
1446 "(&(|(grouptype=%d)(grouptype=%d)))"
1447 "(objectclass=group))",
1448 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1449 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1451 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1454 /* convert to SamEntry format */
1455 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1457 return NT_STATUS_NO_MEMORY;
1462 for (i=0;i<ldb_cnt;i++) {
1463 struct dom_sid *alias_sid;
1465 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1468 if (alias_sid == NULL) {
1469 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1472 entries[count].idx =
1473 alias_sid->sub_auths[alias_sid->num_auths-1];
1474 entries[count].name.string =
1475 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1479 /* sort the results by rid */
1480 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1482 /* find the first entry to return */
1484 first<count && entries[first].idx <= *r->in.resume_handle;
1487 /* return the rest, limit by max_size. Note that we
1488 use the w2k3 element size value of 54 */
1489 *r->out.num_entries = count - first;
1490 *r->out.num_entries = MIN(*r->out.num_entries,
1491 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1493 sam = talloc(mem_ctx, struct samr_SamArray);
1495 return NT_STATUS_NO_MEMORY;
1498 sam->entries = entries+first;
1499 sam->count = *r->out.num_entries;
1503 if (first == count) {
1504 return NT_STATUS_OK;
1507 if (*r->out.num_entries < count - first) {
1508 *r->out.resume_handle =
1509 entries[first+*r->out.num_entries-1].idx;
1510 return STATUS_MORE_ENTRIES;
1513 return NT_STATUS_OK;
1518 samr_GetAliasMembership
1520 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1521 struct samr_GetAliasMembership *r)
1523 struct dcesrv_handle *h;
1524 struct samr_domain_state *d_state;
1526 const char * const attrs[] = { "objectSid", NULL };
1527 struct ldb_message **res;
1531 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1535 filter = talloc_asprintf(mem_ctx,
1536 "(&(|(grouptype=%d)(grouptype=%d))"
1537 "(objectclass=group)(|",
1538 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1539 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1540 if (filter == NULL) {
1541 return NT_STATUS_NO_MEMORY;
1544 for (i=0; i<r->in.sids->num_sids; i++) {
1545 const char *memberdn;
1547 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1548 "distinguishedName",
1550 ldap_encode_ndr_dom_sid(mem_ctx,
1551 r->in.sids->sids[i].sid));
1552 if (memberdn == NULL) {
1556 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1558 if (filter == NULL) {
1559 return NT_STATUS_NO_MEMORY;
1563 /* Find out if we had at least one valid member SID passed - otherwise
1564 * just skip the search. */
1565 if (strstr(filter, "member") != NULL) {
1566 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1567 &res, attrs, d_state->domain_sid,
1570 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1574 r->out.rids->count = 0;
1575 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1576 if (r->out.rids->ids == NULL)
1577 return NT_STATUS_NO_MEMORY;
1579 for (i=0; i<count; i++) {
1580 struct dom_sid *alias_sid;
1582 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1583 if (alias_sid == NULL) {
1584 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1587 r->out.rids->ids[r->out.rids->count] =
1588 alias_sid->sub_auths[alias_sid->num_auths-1];
1589 r->out.rids->count += 1;
1592 return NT_STATUS_OK;
1599 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1600 struct samr_LookupNames *r)
1602 struct dcesrv_handle *h;
1603 struct samr_domain_state *d_state;
1604 uint32_t i, num_mapped;
1605 NTSTATUS status = NT_STATUS_OK;
1606 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1609 ZERO_STRUCTP(r->out.rids);
1610 ZERO_STRUCTP(r->out.types);
1612 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1616 if (r->in.num_names == 0) {
1617 return NT_STATUS_OK;
1620 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1621 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1622 if (!r->out.rids->ids || !r->out.types->ids) {
1623 return NT_STATUS_NO_MEMORY;
1625 r->out.rids->count = r->in.num_names;
1626 r->out.types->count = r->in.num_names;
1630 for (i=0;i<r->in.num_names;i++) {
1631 struct ldb_message **res;
1632 struct dom_sid *sid;
1633 uint32_t atype, rtype;
1635 r->out.rids->ids[i] = 0;
1636 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1638 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1639 "sAMAccountName=%s",
1640 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1642 status = STATUS_SOME_UNMAPPED;
1646 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1648 status = STATUS_SOME_UNMAPPED;
1652 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1654 status = STATUS_SOME_UNMAPPED;
1658 rtype = ds_atype_map(atype);
1660 if (rtype == SID_NAME_UNKNOWN) {
1661 status = STATUS_SOME_UNMAPPED;
1665 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1666 r->out.types->ids[i] = rtype;
1670 if (num_mapped == 0) {
1671 return NT_STATUS_NONE_MAPPED;
1680 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1681 struct samr_LookupRids *r)
1684 struct dcesrv_handle *h;
1685 struct samr_domain_state *d_state;
1687 struct lsa_String *lsa_names;
1688 enum lsa_SidType *ids;
1690 ZERO_STRUCTP(r->out.names);
1691 ZERO_STRUCTP(r->out.types);
1693 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1697 if (r->in.num_rids == 0)
1698 return NT_STATUS_OK;
1700 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1701 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1702 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1704 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1705 return NT_STATUS_NO_MEMORY;
1707 r->out.names->names = lsa_names;
1708 r->out.names->count = r->in.num_rids;
1710 r->out.types->ids = (uint32_t *) ids;
1711 r->out.types->count = r->in.num_rids;
1713 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1714 r->in.num_rids, r->in.rids, names, ids);
1715 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1717 for (i = 0; i < r->in.num_rids; i++) {
1718 lsa_names[i].string = names[i];
1728 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1729 struct samr_OpenGroup *r)
1731 struct samr_domain_state *d_state;
1732 struct samr_account_state *a_state;
1733 struct dcesrv_handle *h;
1734 const char *groupname;
1735 struct dom_sid *sid;
1736 struct ldb_message **msgs;
1737 struct dcesrv_handle *g_handle;
1738 const char * const attrs[2] = { "sAMAccountName", NULL };
1741 ZERO_STRUCTP(r->out.group_handle);
1743 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1747 /* form the group SID */
1748 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1750 return NT_STATUS_NO_MEMORY;
1753 /* search for the group record */
1754 ret = gendb_search(d_state->sam_ctx,
1755 mem_ctx, d_state->domain_dn, &msgs, attrs,
1756 "(&(objectSid=%s)(objectClass=group)"
1757 "(|(groupType=%d)(groupType=%d)))",
1758 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1759 GTYPE_SECURITY_UNIVERSAL_GROUP,
1760 GTYPE_SECURITY_GLOBAL_GROUP);
1762 return NT_STATUS_NO_SUCH_GROUP;
1765 DEBUG(0,("Found %d records matching sid %s\n",
1766 ret, dom_sid_string(mem_ctx, sid)));
1767 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1770 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1771 if (groupname == NULL) {
1772 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1773 dom_sid_string(mem_ctx, sid)));
1774 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1777 a_state = talloc(mem_ctx, struct samr_account_state);
1779 return NT_STATUS_NO_MEMORY;
1781 a_state->sam_ctx = d_state->sam_ctx;
1782 a_state->access_mask = r->in.access_mask;
1783 a_state->domain_state = talloc_reference(a_state, d_state);
1784 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1785 a_state->account_sid = talloc_steal(a_state, sid);
1786 a_state->account_name = talloc_strdup(a_state, groupname);
1787 if (!a_state->account_name) {
1788 return NT_STATUS_NO_MEMORY;
1791 /* create the policy handle */
1792 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1794 return NT_STATUS_NO_MEMORY;
1797 g_handle->data = talloc_steal(g_handle, a_state);
1799 *r->out.group_handle = g_handle->wire_handle;
1801 return NT_STATUS_OK;
1807 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1808 struct samr_QueryGroupInfo *r)
1810 struct dcesrv_handle *h;
1811 struct samr_account_state *a_state;
1812 struct ldb_message *msg, **res;
1813 const char * const attrs[4] = { "sAMAccountName", "description",
1814 "numMembers", NULL };
1816 union samr_GroupInfo *info;
1818 *r->out.info = NULL;
1820 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1824 /* pull all the group attributes */
1825 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1826 a_state->account_dn, &res, attrs);
1828 return NT_STATUS_NO_SUCH_GROUP;
1831 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1835 /* allocate the info structure */
1836 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1838 return NT_STATUS_NO_MEMORY;
1841 /* Fill in the level */
1842 switch (r->in.level) {
1844 QUERY_STRING(msg, all.name, "sAMAccountName");
1845 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1846 QUERY_UINT (msg, all.num_members, "numMembers")
1847 QUERY_STRING(msg, all.description, "description");
1850 QUERY_STRING(msg, name, "sAMAccountName");
1852 case GROUPINFOATTRIBUTES:
1853 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1855 case GROUPINFODESCRIPTION:
1856 QUERY_STRING(msg, description, "description");
1859 QUERY_STRING(msg, all2.name, "sAMAccountName");
1860 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1861 QUERY_UINT (msg, all2.num_members, "numMembers")
1862 QUERY_STRING(msg, all2.description, "description");
1866 return NT_STATUS_INVALID_INFO_CLASS;
1869 *r->out.info = info;
1871 return NT_STATUS_OK;
1878 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1879 struct samr_SetGroupInfo *r)
1881 struct dcesrv_handle *h;
1882 struct samr_account_state *g_state;
1883 struct ldb_message *msg;
1884 struct ldb_context *sam_ctx;
1887 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1890 sam_ctx = g_state->sam_ctx;
1892 msg = ldb_msg_new(mem_ctx);
1894 return NT_STATUS_NO_MEMORY;
1897 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1899 return NT_STATUS_NO_MEMORY;
1902 switch (r->in.level) {
1903 case GROUPINFODESCRIPTION:
1904 SET_STRING(msg, description, "description");
1907 /* On W2k3 this does not change the name, it changes the
1908 * sAMAccountName attribute */
1909 SET_STRING(msg, name, "sAMAccountName");
1911 case GROUPINFOATTRIBUTES:
1912 /* This does not do anything obviously visible in W2k3 LDAP */
1913 return NT_STATUS_OK;
1915 return NT_STATUS_INVALID_INFO_CLASS;
1918 /* modify the samdb record */
1919 ret = ldb_modify(g_state->sam_ctx, msg);
1920 if (ret != LDB_SUCCESS) {
1921 return dsdb_ldb_err_to_ntstatus(ret);
1924 return NT_STATUS_OK;
1931 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1932 struct samr_AddGroupMember *r)
1934 struct dcesrv_handle *h;
1935 struct samr_account_state *a_state;
1936 struct samr_domain_state *d_state;
1937 struct ldb_message *mod;
1938 struct dom_sid *membersid;
1939 const char *memberdn;
1940 struct ldb_result *res;
1941 const char * const attrs[] = { NULL };
1944 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1947 d_state = a_state->domain_state;
1949 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1950 if (membersid == NULL) {
1951 return NT_STATUS_NO_MEMORY;
1954 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1955 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1956 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1958 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1960 if (ret != LDB_SUCCESS) {
1961 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1964 if (res->count == 0) {
1965 return NT_STATUS_NO_SUCH_USER;
1968 if (res->count > 1) {
1969 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1972 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1974 if (memberdn == NULL)
1975 return NT_STATUS_NO_MEMORY;
1977 mod = ldb_msg_new(mem_ctx);
1979 return NT_STATUS_NO_MEMORY;
1982 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1984 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1986 if (ret != LDB_SUCCESS) {
1987 return dsdb_ldb_err_to_ntstatus(ret);
1990 ret = ldb_modify(a_state->sam_ctx, mod);
1993 return NT_STATUS_OK;
1994 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1995 return NT_STATUS_MEMBER_IN_GROUP;
1996 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1997 return NT_STATUS_ACCESS_DENIED;
1999 return dsdb_ldb_err_to_ntstatus(ret);
2005 samr_DeleteDomainGroup
2007 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2008 struct samr_DeleteDomainGroup *r)
2010 struct dcesrv_handle *h;
2011 struct samr_account_state *a_state;
2014 *r->out.group_handle = *r->in.group_handle;
2016 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2020 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2021 if (ret != LDB_SUCCESS) {
2022 return dsdb_ldb_err_to_ntstatus(ret);
2026 ZERO_STRUCTP(r->out.group_handle);
2028 return NT_STATUS_OK;
2033 samr_DeleteGroupMember
2035 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2036 struct samr_DeleteGroupMember *r)
2038 struct dcesrv_handle *h;
2039 struct samr_account_state *a_state;
2040 struct samr_domain_state *d_state;
2041 struct ldb_message *mod;
2042 struct dom_sid *membersid;
2043 const char *memberdn;
2044 struct ldb_result *res;
2045 const char * const attrs[] = { NULL };
2048 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2051 d_state = a_state->domain_state;
2053 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2054 if (membersid == NULL) {
2055 return NT_STATUS_NO_MEMORY;
2058 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2059 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2060 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2062 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2064 if (ret != LDB_SUCCESS) {
2065 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2068 if (res->count == 0) {
2069 return NT_STATUS_NO_SUCH_USER;
2072 if (res->count > 1) {
2073 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2076 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2078 if (memberdn == NULL)
2079 return NT_STATUS_NO_MEMORY;
2081 mod = ldb_msg_new(mem_ctx);
2083 return NT_STATUS_NO_MEMORY;
2086 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2088 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2090 if (ret != LDB_SUCCESS) {
2091 return NT_STATUS_NO_MEMORY;
2094 ret = ldb_modify(a_state->sam_ctx, mod);
2097 return NT_STATUS_OK;
2098 case LDB_ERR_UNWILLING_TO_PERFORM:
2099 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2100 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2101 return NT_STATUS_ACCESS_DENIED;
2103 return dsdb_ldb_err_to_ntstatus(ret);
2109 samr_QueryGroupMember
2111 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2112 struct samr_QueryGroupMember *r)
2114 struct dcesrv_handle *h;
2115 struct samr_account_state *a_state;
2116 struct samr_domain_state *d_state;
2117 struct samr_RidAttrArray *array;
2118 unsigned int i, num_members;
2119 struct dom_sid *members;
2122 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2125 d_state = a_state->domain_state;
2127 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2128 a_state->account_dn, &members,
2130 if (!NT_STATUS_IS_OK(status)) {
2134 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2135 if (array == NULL) {
2136 return NT_STATUS_NO_MEMORY;
2139 if (num_members == 0) {
2140 *r->out.rids = array;
2142 return NT_STATUS_OK;
2145 array->rids = talloc_array(array, uint32_t, num_members);
2146 if (array->rids == NULL) {
2147 return NT_STATUS_NO_MEMORY;
2150 array->attributes = talloc_array(array, uint32_t, num_members);
2151 if (array->attributes == NULL) {
2152 return NT_STATUS_NO_MEMORY;
2156 for (i=0; i<num_members; i++) {
2157 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2161 status = dom_sid_split_rid(NULL, &members[i], NULL,
2162 &array->rids[array->count]);
2163 if (!NT_STATUS_IS_OK(status)) {
2167 array->attributes[array->count] = SE_GROUP_MANDATORY |
2168 SE_GROUP_ENABLED_BY_DEFAULT |
2173 *r->out.rids = array;
2175 return NT_STATUS_OK;
2180 samr_SetMemberAttributesOfGroup
2182 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2183 struct samr_SetMemberAttributesOfGroup *r)
2185 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2192 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2193 struct samr_OpenAlias *r)
2195 struct samr_domain_state *d_state;
2196 struct samr_account_state *a_state;
2197 struct dcesrv_handle *h;
2198 const char *alias_name;
2199 struct dom_sid *sid;
2200 struct ldb_message **msgs;
2201 struct dcesrv_handle *g_handle;
2202 const char * const attrs[2] = { "sAMAccountName", NULL };
2205 ZERO_STRUCTP(r->out.alias_handle);
2207 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2211 /* form the alias SID */
2212 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2214 return NT_STATUS_NO_MEMORY;
2216 /* search for the group record */
2217 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2218 "(&(objectSid=%s)(objectclass=group)"
2219 "(|(grouptype=%d)(grouptype=%d)))",
2220 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2221 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2222 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2224 return NT_STATUS_NO_SUCH_ALIAS;
2227 DEBUG(0,("Found %d records matching sid %s\n",
2228 ret, dom_sid_string(mem_ctx, sid)));
2229 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2232 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2233 if (alias_name == NULL) {
2234 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2235 dom_sid_string(mem_ctx, sid)));
2236 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2239 a_state = talloc(mem_ctx, struct samr_account_state);
2241 return NT_STATUS_NO_MEMORY;
2243 a_state->sam_ctx = d_state->sam_ctx;
2244 a_state->access_mask = r->in.access_mask;
2245 a_state->domain_state = talloc_reference(a_state, d_state);
2246 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2247 a_state->account_sid = talloc_steal(a_state, sid);
2248 a_state->account_name = talloc_strdup(a_state, alias_name);
2249 if (!a_state->account_name) {
2250 return NT_STATUS_NO_MEMORY;
2253 /* create the policy handle */
2254 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2256 return NT_STATUS_NO_MEMORY;
2259 g_handle->data = talloc_steal(g_handle, a_state);
2261 *r->out.alias_handle = g_handle->wire_handle;
2263 return NT_STATUS_OK;
2270 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2271 struct samr_QueryAliasInfo *r)
2273 struct dcesrv_handle *h;
2274 struct samr_account_state *a_state;
2275 struct ldb_message *msg, **res;
2276 const char * const attrs[4] = { "sAMAccountName", "description",
2277 "numMembers", NULL };
2279 union samr_AliasInfo *info;
2281 *r->out.info = NULL;
2283 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2287 /* pull all the alias attributes */
2288 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2289 a_state->account_dn, &res, attrs);
2291 return NT_STATUS_NO_SUCH_ALIAS;
2294 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2298 /* allocate the info structure */
2299 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2301 return NT_STATUS_NO_MEMORY;
2304 switch(r->in.level) {
2306 QUERY_STRING(msg, all.name, "sAMAccountName");
2307 QUERY_UINT (msg, all.num_members, "numMembers");
2308 QUERY_STRING(msg, all.description, "description");
2311 QUERY_STRING(msg, name, "sAMAccountName");
2313 case ALIASINFODESCRIPTION:
2314 QUERY_STRING(msg, description, "description");
2318 return NT_STATUS_INVALID_INFO_CLASS;
2321 *r->out.info = info;
2323 return NT_STATUS_OK;
2330 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2331 struct samr_SetAliasInfo *r)
2333 struct dcesrv_handle *h;
2334 struct samr_account_state *a_state;
2335 struct ldb_message *msg;
2336 struct ldb_context *sam_ctx;
2339 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2342 sam_ctx = a_state->sam_ctx;
2344 msg = ldb_msg_new(mem_ctx);
2346 return NT_STATUS_NO_MEMORY;
2349 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2351 return NT_STATUS_NO_MEMORY;
2354 switch (r->in.level) {
2355 case ALIASINFODESCRIPTION:
2356 SET_STRING(msg, description, "description");
2359 /* On W2k3 this does not change the name, it changes the
2360 * sAMAccountName attribute */
2361 SET_STRING(msg, name, "sAMAccountName");
2364 return NT_STATUS_INVALID_INFO_CLASS;
2367 /* modify the samdb record */
2368 ret = ldb_modify(a_state->sam_ctx, msg);
2369 if (ret != LDB_SUCCESS) {
2370 return dsdb_ldb_err_to_ntstatus(ret);
2373 return NT_STATUS_OK;
2380 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2381 struct samr_DeleteDomAlias *r)
2383 struct dcesrv_handle *h;
2384 struct samr_account_state *a_state;
2387 *r->out.alias_handle = *r->in.alias_handle;
2389 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2393 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2394 if (ret != LDB_SUCCESS) {
2395 return dsdb_ldb_err_to_ntstatus(ret);
2399 ZERO_STRUCTP(r->out.alias_handle);
2401 return NT_STATUS_OK;
2408 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2409 struct samr_AddAliasMember *r)
2411 struct dcesrv_handle *h;
2412 struct samr_account_state *a_state;
2413 struct samr_domain_state *d_state;
2414 struct ldb_message *mod;
2415 struct ldb_message **msgs;
2416 const char * const attrs[] = { NULL };
2417 struct ldb_dn *memberdn = NULL;
2421 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2424 d_state = a_state->domain_state;
2426 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2427 &msgs, attrs, "(objectsid=%s)",
2428 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2431 memberdn = msgs[0]->dn;
2432 } else if (ret == 0) {
2433 status = samdb_create_foreign_security_principal(
2434 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2435 if (!NT_STATUS_IS_OK(status)) {
2439 DEBUG(0,("Found %d records matching sid %s\n",
2440 ret, dom_sid_string(mem_ctx, r->in.sid)));
2441 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2444 if (memberdn == NULL) {
2445 DEBUG(0, ("Could not find memberdn\n"));
2446 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2449 mod = ldb_msg_new(mem_ctx);
2451 return NT_STATUS_NO_MEMORY;
2454 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2456 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2457 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2458 if (ret != LDB_SUCCESS) {
2459 return dsdb_ldb_err_to_ntstatus(ret);
2462 ret = ldb_modify(a_state->sam_ctx, mod);
2465 return NT_STATUS_OK;
2466 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2467 return NT_STATUS_MEMBER_IN_GROUP;
2468 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2469 return NT_STATUS_ACCESS_DENIED;
2471 return dsdb_ldb_err_to_ntstatus(ret);
2477 samr_DeleteAliasMember
2479 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2480 struct samr_DeleteAliasMember *r)
2482 struct dcesrv_handle *h;
2483 struct samr_account_state *a_state;
2484 struct samr_domain_state *d_state;
2485 struct ldb_message *mod;
2486 const char *memberdn;
2489 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2492 d_state = a_state->domain_state;
2494 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2495 "distinguishedName", "(objectSid=%s)",
2496 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2497 if (memberdn == NULL) {
2498 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2501 mod = ldb_msg_new(mem_ctx);
2503 return NT_STATUS_NO_MEMORY;
2506 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2508 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2510 if (ret != LDB_SUCCESS) {
2511 return dsdb_ldb_err_to_ntstatus(ret);
2514 ret = ldb_modify(a_state->sam_ctx, mod);
2517 return NT_STATUS_OK;
2518 case LDB_ERR_UNWILLING_TO_PERFORM:
2519 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2520 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2521 return NT_STATUS_ACCESS_DENIED;
2523 return dsdb_ldb_err_to_ntstatus(ret);
2529 samr_GetMembersInAlias
2531 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2532 struct samr_GetMembersInAlias *r)
2534 struct dcesrv_handle *h;
2535 struct samr_account_state *a_state;
2536 struct samr_domain_state *d_state;
2537 struct lsa_SidPtr *array;
2538 unsigned int i, num_members;
2539 struct dom_sid *members;
2542 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2545 d_state = a_state->domain_state;
2547 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2548 a_state->account_dn, &members,
2550 if (!NT_STATUS_IS_OK(status)) {
2554 if (num_members == 0) {
2555 r->out.sids->sids = NULL;
2557 return NT_STATUS_OK;
2560 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2561 if (array == NULL) {
2562 return NT_STATUS_NO_MEMORY;
2565 for (i=0; i<num_members; i++) {
2566 array[i].sid = &members[i];
2569 r->out.sids->num_sids = num_members;
2570 r->out.sids->sids = array;
2572 return NT_STATUS_OK;
2578 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2579 struct samr_OpenUser *r)
2581 struct samr_domain_state *d_state;
2582 struct samr_account_state *a_state;
2583 struct dcesrv_handle *h;
2584 const char *account_name;
2585 struct dom_sid *sid;
2586 struct ldb_message **msgs;
2587 struct dcesrv_handle *u_handle;
2588 const char * const attrs[2] = { "sAMAccountName", NULL };
2591 ZERO_STRUCTP(r->out.user_handle);
2593 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2597 /* form the users SID */
2598 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2600 return NT_STATUS_NO_MEMORY;
2603 /* search for the user record */
2604 ret = gendb_search(d_state->sam_ctx,
2605 mem_ctx, d_state->domain_dn, &msgs, attrs,
2606 "(&(objectSid=%s)(objectclass=user))",
2607 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2609 return NT_STATUS_NO_SUCH_USER;
2612 DEBUG(0,("Found %d records matching sid %s\n", ret,
2613 dom_sid_string(mem_ctx, sid)));
2614 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2617 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2618 if (account_name == NULL) {
2619 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2620 dom_sid_string(mem_ctx, sid)));
2621 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2624 a_state = talloc(mem_ctx, struct samr_account_state);
2626 return NT_STATUS_NO_MEMORY;
2628 a_state->sam_ctx = d_state->sam_ctx;
2629 a_state->access_mask = r->in.access_mask;
2630 a_state->domain_state = talloc_reference(a_state, d_state);
2631 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2632 a_state->account_sid = talloc_steal(a_state, sid);
2633 a_state->account_name = talloc_strdup(a_state, account_name);
2634 if (!a_state->account_name) {
2635 return NT_STATUS_NO_MEMORY;
2638 /* create the policy handle */
2639 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2641 return NT_STATUS_NO_MEMORY;
2644 u_handle->data = talloc_steal(u_handle, a_state);
2646 *r->out.user_handle = u_handle->wire_handle;
2648 return NT_STATUS_OK;
2656 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2657 struct samr_DeleteUser *r)
2659 struct dcesrv_handle *h;
2660 struct samr_account_state *a_state;
2663 *r->out.user_handle = *r->in.user_handle;
2665 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2669 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2670 if (ret != LDB_SUCCESS) {
2671 DEBUG(1, ("Failed to delete user: %s: %s\n",
2672 ldb_dn_get_linearized(a_state->account_dn),
2673 ldb_errstring(a_state->sam_ctx)));
2674 return dsdb_ldb_err_to_ntstatus(ret);
2678 ZERO_STRUCTP(r->out.user_handle);
2680 return NT_STATUS_OK;
2687 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2688 struct samr_QueryUserInfo *r)
2690 struct dcesrv_handle *h;
2691 struct samr_account_state *a_state;
2692 struct ldb_message *msg, **res;
2694 struct ldb_context *sam_ctx;
2696 const char * const *attrs = NULL;
2697 union samr_UserInfo *info;
2699 *r->out.info = NULL;
2701 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2704 sam_ctx = a_state->sam_ctx;
2706 /* fill in the reply */
2707 switch (r->in.level) {
2710 static const char * const attrs2[] = {"sAMAccountName",
2721 static const char * const attrs2[] = {"comment",
2730 static const char * const attrs2[] = {"sAMAccountName",
2745 "userAccountControl",
2752 static const char * const attrs2[] = {"logonHours",
2759 static const char * const attrs2[] = {"sAMAccountName",
2776 "userAccountControl",
2783 static const char * const attrs2[] = {"sAMAccountName",
2791 static const char * const attrs2[] = {"sAMAccountName",
2798 static const char * const attrs2[] = {"displayName",
2805 static const char * const attrs2[] = {"primaryGroupID",
2812 static const char * const attrs2[] = {"homeDirectory",
2820 static const char * const attrs2[] = {"scriptPath",
2827 static const char * const attrs2[] = {"profilePath",
2834 static const char * const attrs2[] = {"description",
2841 static const char * const attrs2[] = {"userWorkstations",
2848 static const char * const attrs2[] = {"userAccountControl",
2856 static const char * const attrs2[] = {"accountExpires",
2863 return NT_STATUS_NOT_SUPPORTED;
2867 static const char * const attrs2[] = {"userParameters",
2874 static const char * const attrs2[] = {"lastLogon",
2890 "userAccountControl",
2905 return NT_STATUS_NOT_SUPPORTED;
2909 return NT_STATUS_INVALID_INFO_CLASS;
2913 /* pull all the user attributes */
2914 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2915 a_state->account_dn, &res, attrs);
2917 return NT_STATUS_NO_SUCH_USER;
2920 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2924 /* allocate the info structure */
2925 info = talloc_zero(mem_ctx, union samr_UserInfo);
2927 return NT_STATUS_NO_MEMORY;
2930 /* fill in the reply */
2931 switch (r->in.level) {
2933 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2934 QUERY_STRING(msg, info1.full_name, "displayName");
2935 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2936 QUERY_STRING(msg, info1.description, "description");
2937 QUERY_STRING(msg, info1.comment, "comment");
2941 QUERY_STRING(msg, info2.comment, "comment");
2942 QUERY_UINT (msg, info2.country_code, "countryCode");
2943 QUERY_UINT (msg, info2.code_page, "codePage");
2947 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2948 QUERY_STRING(msg, info3.full_name, "displayName");
2949 QUERY_RID (msg, info3.rid, "objectSid");
2950 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2951 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2952 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2953 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2954 QUERY_STRING(msg, info3.profile_path, "profilePath");
2955 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2956 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2957 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2958 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2959 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2960 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2961 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2962 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2963 QUERY_UINT (msg, info3.logon_count, "logonCount");
2964 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
2968 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2972 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2973 QUERY_STRING(msg, info5.full_name, "displayName");
2974 QUERY_RID (msg, info5.rid, "objectSid");
2975 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2976 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2977 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2978 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2979 QUERY_STRING(msg, info5.profile_path, "profilePath");
2980 QUERY_STRING(msg, info5.description, "description");
2981 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2982 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2983 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2984 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2985 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
2986 QUERY_UINT (msg, info5.logon_count, "logonCount");
2987 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2988 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
2989 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
2993 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
2994 QUERY_STRING(msg, info6.full_name, "displayName");
2998 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3002 QUERY_STRING(msg, info8.full_name, "displayName");
3006 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3010 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3011 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3015 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3019 QUERY_STRING(msg, info12.profile_path, "profilePath");
3023 QUERY_STRING(msg, info13.description, "description");
3027 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3031 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3035 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3039 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3043 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3044 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3045 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3046 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3047 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3048 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3049 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3050 QUERY_STRING(msg, info21.full_name, "displayName");
3051 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3052 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3053 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3054 QUERY_STRING(msg, info21.profile_path, "profilePath");
3055 QUERY_STRING(msg, info21.description, "description");
3056 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3057 QUERY_STRING(msg, info21.comment, "comment");
3058 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3059 QUERY_RID (msg, info21.rid, "objectSid");
3060 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3061 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3062 info->info21.fields_present = 0x08FFFFFF;
3063 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3064 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3065 QUERY_UINT (msg, info21.logon_count, "logonCount");
3066 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3067 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3069 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3071 QUERY_UINT (msg, info21.country_code, "countryCode");
3072 QUERY_UINT (msg, info21.code_page, "codePage");
3078 return NT_STATUS_INVALID_INFO_CLASS;
3081 *r->out.info = info;
3083 return NT_STATUS_OK;
3090 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3091 struct samr_SetUserInfo *r)
3093 struct dcesrv_handle *h;
3094 struct samr_account_state *a_state;
3095 struct ldb_message *msg;
3097 NTSTATUS status = NT_STATUS_OK;
3098 struct ldb_context *sam_ctx;
3100 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3103 sam_ctx = a_state->sam_ctx;
3105 msg = ldb_msg_new(mem_ctx);
3107 return NT_STATUS_NO_MEMORY;
3110 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3112 return NT_STATUS_NO_MEMORY;
3115 switch (r->in.level) {
3117 SET_STRING(msg, info2.comment, "comment");
3118 SET_UINT (msg, info2.country_code, "countryCode");
3119 SET_UINT (msg, info2.code_page, "codePage");
3123 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3127 SET_STRING(msg, info6.account_name, "samAccountName");
3128 SET_STRING(msg, info6.full_name, "displayName");
3132 SET_STRING(msg, info7.account_name, "samAccountName");
3136 SET_STRING(msg, info8.full_name, "displayName");
3140 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3144 SET_STRING(msg, info10.home_directory, "homeDirectory");
3145 SET_STRING(msg, info10.home_drive, "homeDrive");
3149 SET_STRING(msg, info11.logon_script, "scriptPath");
3153 SET_STRING(msg, info12.profile_path, "profilePath");
3157 SET_STRING(msg, info13.description, "description");
3161 SET_STRING(msg, info14.workstations, "userWorkstations");
3165 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3169 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3173 status = samr_set_password_buffers(dce_call,
3175 a_state->account_dn,
3176 a_state->domain_state->domain_dn,
3178 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3179 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3180 if (!NT_STATUS_IS_OK(status)) {
3184 if (r->in.info->info18.password_expired > 0) {
3185 struct ldb_message_element *set_el;
3186 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3187 return NT_STATUS_NO_MEMORY;
3189 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3190 set_el->flags = LDB_FLAG_MOD_REPLACE;
3195 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3199 if (r->in.info->info21.fields_present == 0)
3200 return NT_STATUS_INVALID_PARAMETER;
3202 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3203 IFSET(SAMR_FIELD_LAST_LOGON)
3204 SET_UINT64(msg, info21.last_logon, "lastLogon");
3205 IFSET(SAMR_FIELD_LAST_LOGOFF)
3206 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3207 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3208 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3209 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3210 SET_STRING(msg, info21.account_name, "samAccountName");
3211 IFSET(SAMR_FIELD_FULL_NAME)
3212 SET_STRING(msg, info21.full_name, "displayName");
3213 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3214 SET_STRING(msg, info21.home_directory, "homeDirectory");
3215 IFSET(SAMR_FIELD_HOME_DRIVE)
3216 SET_STRING(msg, info21.home_drive, "homeDrive");
3217 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3218 SET_STRING(msg, info21.logon_script, "scriptPath");
3219 IFSET(SAMR_FIELD_PROFILE_PATH)
3220 SET_STRING(msg, info21.profile_path, "profilePath");
3221 IFSET(SAMR_FIELD_DESCRIPTION)
3222 SET_STRING(msg, info21.description, "description");
3223 IFSET(SAMR_FIELD_WORKSTATIONS)
3224 SET_STRING(msg, info21.workstations, "userWorkstations");
3225 IFSET(SAMR_FIELD_COMMENT)
3226 SET_STRING(msg, info21.comment, "comment");
3227 IFSET(SAMR_FIELD_PARAMETERS)
3228 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3229 IFSET(SAMR_FIELD_PRIMARY_GID)
3230 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3231 IFSET(SAMR_FIELD_ACCT_FLAGS)
3232 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3233 IFSET(SAMR_FIELD_LOGON_HOURS)
3234 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3235 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3236 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3237 IFSET(SAMR_FIELD_NUM_LOGONS)
3238 SET_UINT (msg, info21.logon_count, "logonCount");
3239 IFSET(SAMR_FIELD_COUNTRY_CODE)
3240 SET_UINT (msg, info21.country_code, "countryCode");
3241 IFSET(SAMR_FIELD_CODE_PAGE)
3242 SET_UINT (msg, info21.code_page, "codePage");
3244 /* password change fields */
3245 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3246 return NT_STATUS_ACCESS_DENIED;
3248 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3249 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3250 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3252 if (r->in.info->info21.lm_password_set) {
3253 if ((r->in.info->info21.lm_owf_password.length != 16)
3254 || (r->in.info->info21.lm_owf_password.size != 16)) {
3255 return NT_STATUS_INVALID_PARAMETER;
3258 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3260 if (r->in.info->info21.nt_password_set) {
3261 if ((r->in.info->info21.nt_owf_password.length != 16)
3262 || (r->in.info->info21.nt_owf_password.size != 16)) {
3263 return NT_STATUS_INVALID_PARAMETER;
3266 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3268 status = samr_set_password_buffers(dce_call,
3270 a_state->account_dn,
3271 a_state->domain_state->domain_dn,
3275 if (!NT_STATUS_IS_OK(status)) {
3281 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3283 struct ldb_message_element *set_el;
3284 if (r->in.info->info21.password_expired
3285 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3286 unix_to_nt_time(&t, time(NULL));
3288 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3289 "pwdLastSet", t) != LDB_SUCCESS) {
3290 return NT_STATUS_NO_MEMORY;
3292 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3293 set_el->flags = LDB_FLAG_MOD_REPLACE;
3299 if (r->in.info->info23.info.fields_present == 0)
3300 return NT_STATUS_INVALID_PARAMETER;
3302 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3303 IFSET(SAMR_FIELD_LAST_LOGON)
3304 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3305 IFSET(SAMR_FIELD_LAST_LOGOFF)
3306 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3307 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3308 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3309 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3310 SET_STRING(msg, info23.info.account_name, "samAccountName");
3311 IFSET(SAMR_FIELD_FULL_NAME)
3312 SET_STRING(msg, info23.info.full_name, "displayName");
3313 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3314 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3315 IFSET(SAMR_FIELD_HOME_DRIVE)
3316 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3317 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3318 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3319 IFSET(SAMR_FIELD_PROFILE_PATH)
3320 SET_STRING(msg, info23.info.profile_path, "profilePath");
3321 IFSET(SAMR_FIELD_DESCRIPTION)
3322 SET_STRING(msg, info23.info.description, "description");
3323 IFSET(SAMR_FIELD_WORKSTATIONS)
3324 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3325 IFSET(SAMR_FIELD_COMMENT)
3326 SET_STRING(msg, info23.info.comment, "comment");
3327 IFSET(SAMR_FIELD_PARAMETERS)
3328 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3329 IFSET(SAMR_FIELD_PRIMARY_GID)
3330 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3331 IFSET(SAMR_FIELD_ACCT_FLAGS)
3332 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3333 IFSET(SAMR_FIELD_LOGON_HOURS)
3334 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3335 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3336 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3337 IFSET(SAMR_FIELD_NUM_LOGONS)
3338 SET_UINT (msg, info23.info.logon_count, "logonCount");
3340 IFSET(SAMR_FIELD_COUNTRY_CODE)
3341 SET_UINT (msg, info23.info.country_code, "countryCode");
3342 IFSET(SAMR_FIELD_CODE_PAGE)
3343 SET_UINT (msg, info23.info.code_page, "codePage");
3345 /* password change fields */
3346 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3347 return NT_STATUS_ACCESS_DENIED;
3349 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3350 status = samr_set_password(dce_call,
3352 a_state->account_dn,
3353 a_state->domain_state->domain_dn,
3355 &r->in.info->info23.password);
3356 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3357 status = samr_set_password(dce_call,
3359 a_state->account_dn,
3360 a_state->domain_state->domain_dn,
3362 &r->in.info->info23.password);
3364 if (!NT_STATUS_IS_OK(status)) {
3368 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3370 struct ldb_message_element *set_el;
3371 if (r->in.info->info23.info.password_expired
3372 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3373 unix_to_nt_time(&t, time(NULL));
3375 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3376 "pwdLastSet", t) != LDB_SUCCESS) {
3377 return NT_STATUS_NO_MEMORY;
3379 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3380 set_el->flags = LDB_FLAG_MOD_REPLACE;
3385 /* the set password levels are handled separately */
3387 status = samr_set_password(dce_call,
3389 a_state->account_dn,
3390 a_state->domain_state->domain_dn,
3392 &r->in.info->info24.password);
3393 if (!NT_STATUS_IS_OK(status)) {
3397 if (r->in.info->info24.password_expired > 0) {
3398 struct ldb_message_element *set_el;
3399 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3400 return NT_STATUS_NO_MEMORY;
3402 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3403 set_el->flags = LDB_FLAG_MOD_REPLACE;
3408 if (r->in.info->info25.info.fields_present == 0)
3409 return NT_STATUS_INVALID_PARAMETER;
3411 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3412 IFSET(SAMR_FIELD_LAST_LOGON)
3413 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3414 IFSET(SAMR_FIELD_LAST_LOGOFF)
3415 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3416 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3417 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3418 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3419 SET_STRING(msg, info25.info.account_name, "samAccountName");
3420 IFSET(SAMR_FIELD_FULL_NAME)
3421 SET_STRING(msg, info25.info.full_name, "displayName");
3422 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3423 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3424 IFSET(SAMR_FIELD_HOME_DRIVE)
3425 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3426 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3427 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3428 IFSET(SAMR_FIELD_PROFILE_PATH)
3429 SET_STRING(msg, info25.info.profile_path, "profilePath");
3430 IFSET(SAMR_FIELD_DESCRIPTION)
3431 SET_STRING(msg, info25.info.description, "description");
3432 IFSET(SAMR_FIELD_WORKSTATIONS)
3433 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3434 IFSET(SAMR_FIELD_COMMENT)
3435 SET_STRING(msg, info25.info.comment, "comment");
3436 IFSET(SAMR_FIELD_PARAMETERS)
3437 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3438 IFSET(SAMR_FIELD_PRIMARY_GID)
3439 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3440 IFSET(SAMR_FIELD_ACCT_FLAGS)
3441 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3442 IFSET(SAMR_FIELD_LOGON_HOURS)
3443 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3444 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3445 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3446 IFSET(SAMR_FIELD_NUM_LOGONS)
3447 SET_UINT (msg, info25.info.logon_count, "logonCount");
3448 IFSET(SAMR_FIELD_COUNTRY_CODE)
3449 SET_UINT (msg, info25.info.country_code, "countryCode");
3450 IFSET(SAMR_FIELD_CODE_PAGE)
3451 SET_UINT (msg, info25.info.code_page, "codePage");
3453 /* password change fields */
3454 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3455 return NT_STATUS_ACCESS_DENIED;
3457 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3458 status = samr_set_password_ex(dce_call,
3460 a_state->account_dn,
3461 a_state->domain_state->domain_dn,
3463 &r->in.info->info25.password);
3464 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3465 status = samr_set_password_ex(dce_call,
3467 a_state->account_dn,
3468 a_state->domain_state->domain_dn,
3470 &r->in.info->info25.password);
3472 if (!NT_STATUS_IS_OK(status)) {
3476 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3478 struct ldb_message_element *set_el;
3479 if (r->in.info->info25.info.password_expired
3480 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3481 unix_to_nt_time(&t, time(NULL));
3483 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3484 "pwdLastSet", t) != LDB_SUCCESS) {
3485 return NT_STATUS_NO_MEMORY;
3487 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3488 set_el->flags = LDB_FLAG_MOD_REPLACE;
3493 /* the set password levels are handled separately */
3495 status = samr_set_password_ex(dce_call,
3497 a_state->account_dn,
3498 a_state->domain_state->domain_dn,
3500 &r->in.info->info26.password);
3501 if (!NT_STATUS_IS_OK(status)) {
3505 if (r->in.info->info26.password_expired > 0) {
3506 struct ldb_message_element *set_el;
3507 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3508 return NT_STATUS_NO_MEMORY;
3510 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3511 set_el->flags = LDB_FLAG_MOD_REPLACE;
3516 /* many info classes are not valid for SetUserInfo */
3517 return NT_STATUS_INVALID_INFO_CLASS;
3520 if (!NT_STATUS_IS_OK(status)) {
3524 /* modify the samdb record */
3525 if (msg->num_elements > 0) {
3526 ret = ldb_modify(a_state->sam_ctx, msg);
3527 if (ret != LDB_SUCCESS) {
3528 DEBUG(1,("Failed to modify record %s: %s\n",
3529 ldb_dn_get_linearized(a_state->account_dn),
3530 ldb_errstring(a_state->sam_ctx)));
3532 return dsdb_ldb_err_to_ntstatus(ret);
3536 return NT_STATUS_OK;
3541 samr_GetGroupsForUser
3543 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3544 struct samr_GetGroupsForUser *r)
3546 struct dcesrv_handle *h;
3547 struct samr_account_state *a_state;
3548 struct samr_domain_state *d_state;
3549 struct ldb_message **res;
3550 const char * const attrs[2] = { "objectSid", NULL };
3551 struct samr_RidWithAttributeArray *array;
3554 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3557 d_state = a_state->domain_state;
3559 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3560 d_state->domain_dn, &res,
3561 attrs, d_state->domain_sid,
3562 "(&(member=%s)(|(grouptype=%d)(grouptype=%d))(objectclass=group))",
3563 ldb_dn_get_linearized(a_state->account_dn),
3564 GTYPE_SECURITY_UNIVERSAL_GROUP,
3565 GTYPE_SECURITY_GLOBAL_GROUP);
3567 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3569 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3571 return NT_STATUS_NO_MEMORY;
3576 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3578 if (array->rids == NULL)
3579 return NT_STATUS_NO_MEMORY;
3581 /* Adds the primary group */
3582 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3583 ~0, a_state->account_dn,
3584 "primaryGroupID", NULL);
3585 array->rids[0].attributes = SE_GROUP_MANDATORY
3586 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3589 /* Adds the additional groups */
3590 for (i = 0; i < count; i++) {
3591 struct dom_sid *group_sid;
3593 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3594 if (group_sid == NULL) {
3595 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3598 array->rids[i + 1].rid =
3599 group_sid->sub_auths[group_sid->num_auths-1];
3600 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3601 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3605 *r->out.rids = array;
3607 return NT_STATUS_OK;
3612 samr_QueryDisplayInfo
3614 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3615 struct samr_QueryDisplayInfo *r)
3617 struct dcesrv_handle *h;
3618 struct samr_domain_state *d_state;
3619 struct ldb_result *res;
3622 const char * const attrs[] = { "objectSid", "sAMAccountName",
3623 "displayName", "description", "userAccountControl",
3624 "pwdLastSet", NULL };
3625 struct samr_DispEntryFull *entriesFull = NULL;
3626 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3627 struct samr_DispEntryAscii *entriesAscii = NULL;
3628 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3632 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3636 switch (r->in.level) {
3639 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3640 "(sAMAccountType=%d))",
3641 ATYPE_NORMAL_ACCOUNT);
3644 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3645 "(sAMAccountType=%d))",
3646 ATYPE_WORKSTATION_TRUST);
3650 filter = talloc_asprintf(mem_ctx,
3651 "(&(|(groupType=%d)(groupType=%d))"
3652 "(objectClass=group))",
3653 GTYPE_SECURITY_UNIVERSAL_GROUP,
3654 GTYPE_SECURITY_GLOBAL_GROUP);
3657 return NT_STATUS_INVALID_INFO_CLASS;
3660 /* search for all requested objects in all domains. This could
3661 possibly be cached and resumed based on resume_key */
3662 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, NULL,
3663 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3664 if (ret != LDB_SUCCESS) {
3665 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3667 if ((res->count == 0) || (r->in.max_entries == 0)) {
3668 return NT_STATUS_OK;
3671 switch (r->in.level) {
3673 entriesGeneral = talloc_array(mem_ctx,
3674 struct samr_DispEntryGeneral,
3678 entriesFull = talloc_array(mem_ctx,
3679 struct samr_DispEntryFull,
3683 entriesFullGroup = talloc_array(mem_ctx,
3684 struct samr_DispEntryFullGroup,
3689 entriesAscii = talloc_array(mem_ctx,
3690 struct samr_DispEntryAscii,
3695 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3696 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3697 return NT_STATUS_NO_MEMORY;
3701 for (i = 0; i < res->count; i++) {
3702 struct dom_sid *objectsid;
3704 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3706 if (objectsid == NULL)
3709 switch(r->in.level) {
3711 entriesGeneral[count].idx = count + 1;
3712 entriesGeneral[count].rid =
3713 objectsid->sub_auths[objectsid->num_auths-1];
3714 entriesGeneral[count].acct_flags =
3715 samdb_result_acct_flags(d_state->sam_ctx,
3718 d_state->domain_dn);
3719 entriesGeneral[count].account_name.string =
3720 ldb_msg_find_attr_as_string(res->msgs[i],
3721 "sAMAccountName", "");
3722 entriesGeneral[count].full_name.string =
3723 ldb_msg_find_attr_as_string(res->msgs[i],
3725 entriesGeneral[count].description.string =
3726 ldb_msg_find_attr_as_string(res->msgs[i],
3730 entriesFull[count].idx = count + 1;
3731 entriesFull[count].rid =
3732 objectsid->sub_auths[objectsid->num_auths-1];
3734 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3735 entriesFull[count].acct_flags =
3736 samdb_result_acct_flags(d_state->sam_ctx,
3739 d_state->domain_dn) | ACB_NORMAL;
3740 entriesFull[count].account_name.string =
3741 ldb_msg_find_attr_as_string(res->msgs[i],
3742 "sAMAccountName", "");
3743 entriesFull[count].description.string =
3744 ldb_msg_find_attr_as_string(res->msgs[i],
3748 entriesFullGroup[count].idx = count + 1;
3749 entriesFullGroup[count].rid =
3750 objectsid->sub_auths[objectsid->num_auths-1];
3751 /* We get a "7" here for groups */
3752 entriesFullGroup[count].acct_flags
3753 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3754 entriesFullGroup[count].account_name.string =
3755 ldb_msg_find_attr_as_string(res->msgs[i],
3756 "sAMAccountName", "");
3757 entriesFullGroup[count].description.string =
3758 ldb_msg_find_attr_as_string(res->msgs[i],
3763 entriesAscii[count].idx = count + 1;
3764 entriesAscii[count].account_name.string =
3765 ldb_msg_find_attr_as_string(res->msgs[i],
3766 "sAMAccountName", "");
3773 *r->out.total_size = count;
3775 if (r->in.start_idx >= count) {
3776 *r->out.returned_size = 0;
3777 switch(r->in.level) {
3779 r->out.info->info1.count = *r->out.returned_size;
3780 r->out.info->info1.entries = NULL;
3783 r->out.info->info2.count = *r->out.returned_size;
3784 r->out.info->info2.entries = NULL;
3787 r->out.info->info3.count = *r->out.returned_size;
3788 r->out.info->info3.entries = NULL;
3791 r->out.info->info4.count = *r->out.returned_size;
3792 r->out.info->info4.entries = NULL;
3795 r->out.info->info5.count = *r->out.returned_size;
3796 r->out.info->info5.entries = NULL;
3800 *r->out.returned_size = MIN(count - r->in.start_idx,
3802 switch(r->in.level) {
3804 r->out.info->info1.count = *r->out.returned_size;
3805 r->out.info->info1.entries =
3806 &(entriesGeneral[r->in.start_idx]);
3809 r->out.info->info2.count = *r->out.returned_size;
3810 r->out.info->info2.entries =
3811 &(entriesFull[r->in.start_idx]);
3814 r->out.info->info3.count = *r->out.returned_size;
3815 r->out.info->info3.entries =
3816 &(entriesFullGroup[r->in.start_idx]);
3819 r->out.info->info4.count = *r->out.returned_size;
3820 r->out.info->info4.entries =
3821 &(entriesAscii[r->in.start_idx]);
3824 r->out.info->info5.count = *r->out.returned_size;
3825 r->out.info->info5.entries =
3826 &(entriesAscii[r->in.start_idx]);
3831 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3832 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3837 samr_GetDisplayEnumerationIndex
3839 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3840 struct samr_GetDisplayEnumerationIndex *r)
3842 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3847 samr_TestPrivateFunctionsDomain
3849 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3850 struct samr_TestPrivateFunctionsDomain *r)
3852 return NT_STATUS_NOT_IMPLEMENTED;
3857 samr_TestPrivateFunctionsUser
3859 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3860 struct samr_TestPrivateFunctionsUser *r)
3862 return NT_STATUS_NOT_IMPLEMENTED;
3869 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3870 struct samr_GetUserPwInfo *r)
3872 struct dcesrv_handle *h;
3873 struct samr_account_state *a_state;
3875 ZERO_STRUCTP(r->out.info);
3877 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3881 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3882 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3884 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3885 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3887 return NT_STATUS_OK;
3892 samr_RemoveMemberFromForeignDomain
3894 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3895 TALLOC_CTX *mem_ctx,
3896 struct samr_RemoveMemberFromForeignDomain *r)
3898 struct dcesrv_handle *h;
3899 struct samr_domain_state *d_state;
3900 const char *memberdn;
3901 struct ldb_message **res;
3902 const char *no_attrs[] = { NULL };
3905 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3909 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3910 "distinguishedName", "(objectSid=%s)",
3911 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3913 if (memberdn == NULL) {
3914 return NT_STATUS_OK;
3917 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3918 d_state->domain_dn, &res, no_attrs,
3919 d_state->domain_sid,
3920 "(&(member=%s)(objectClass=group)"
3921 "(|(groupType=%d)(groupType=%d)))",
3923 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3924 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3927 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3929 for (i=0; i<count; i++) {
3930 struct ldb_message *mod;
3933 mod = ldb_msg_new(mem_ctx);
3935 return NT_STATUS_NO_MEMORY;
3938 mod->dn = res[i]->dn;
3940 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3941 "member", memberdn) != LDB_SUCCESS)
3942 return NT_STATUS_NO_MEMORY;
3944 ret = ldb_modify(d_state->sam_ctx, mod);
3946 if (ret != LDB_SUCCESS) {
3947 return dsdb_ldb_err_to_ntstatus(ret);
3951 return NT_STATUS_OK;
3956 samr_QueryDomainInfo2
3958 just an alias for samr_QueryDomainInfo
3960 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3961 struct samr_QueryDomainInfo2 *r)
3963 struct samr_QueryDomainInfo r1;
3966 ZERO_STRUCT(r1.out);
3967 r1.in.domain_handle = r->in.domain_handle;
3968 r1.in.level = r->in.level;
3969 r1.out.info = r->out.info;
3971 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3980 just an alias for samr_QueryUserInfo
3982 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3983 struct samr_QueryUserInfo2 *r)
3985 struct samr_QueryUserInfo r1;
3988 r1.in.user_handle = r->in.user_handle;
3989 r1.in.level = r->in.level;
3990 r1.out.info = r->out.info;
3992 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3999 samr_QueryDisplayInfo2
4001 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4002 struct samr_QueryDisplayInfo2 *r)
4004 struct samr_QueryDisplayInfo q;
4007 q.in.domain_handle = r->in.domain_handle;
4008 q.in.level = r->in.level;
4009 q.in.start_idx = r->in.start_idx;
4010 q.in.max_entries = r->in.max_entries;
4011 q.in.buf_size = r->in.buf_size;
4012 q.out.total_size = r->out.total_size;
4013 q.out.returned_size = r->out.returned_size;
4014 q.out.info = r->out.info;
4016 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4023 samr_GetDisplayEnumerationIndex2
4025 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4026 struct samr_GetDisplayEnumerationIndex2 *r)
4028 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4033 samr_QueryDisplayInfo3
4035 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4036 struct samr_QueryDisplayInfo3 *r)
4038 struct samr_QueryDisplayInfo q;
4041 q.in.domain_handle = r->in.domain_handle;
4042 q.in.level = r->in.level;
4043 q.in.start_idx = r->in.start_idx;
4044 q.in.max_entries = r->in.max_entries;
4045 q.in.buf_size = r->in.buf_size;
4046 q.out.total_size = r->out.total_size;
4047 q.out.returned_size = r->out.returned_size;
4048 q.out.info = r->out.info;
4050 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4057 samr_AddMultipleMembersToAlias
4059 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4060 struct samr_AddMultipleMembersToAlias *r)
4062 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4067 samr_RemoveMultipleMembersFromAlias
4069 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4070 struct samr_RemoveMultipleMembersFromAlias *r)
4072 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4079 this fetches the default password properties for a domain
4081 note that w2k3 completely ignores the domain name in this call, and
4082 always returns the information for the servers primary domain
4084 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4085 struct samr_GetDomPwInfo *r)
4087 struct ldb_message **msgs;
4089 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4090 struct ldb_context *sam_ctx;
4092 ZERO_STRUCTP(r->out.info);
4094 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4095 dce_call->conn->dce_ctx->lp_ctx,
4096 dce_call->conn->auth_state.session_info, 0);
4097 if (sam_ctx == NULL) {
4098 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4101 /* The domain name in this call is ignored */
4102 ret = gendb_search_dn(sam_ctx,
4103 mem_ctx, NULL, &msgs, attrs);
4105 talloc_free(sam_ctx);
4107 return NT_STATUS_NO_SUCH_DOMAIN;
4111 talloc_free(sam_ctx);
4113 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4116 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4118 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4119 "pwdProperties", 1);
4122 talloc_unlink(mem_ctx, sam_ctx);
4124 return NT_STATUS_OK;
4131 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4132 struct samr_Connect2 *r)
4134 struct samr_Connect c;
4136 c.in.system_name = NULL;
4137 c.in.access_mask = r->in.access_mask;
4138 c.out.connect_handle = r->out.connect_handle;
4140 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4147 just an alias for samr_SetUserInfo
4149 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4150 struct samr_SetUserInfo2 *r)
4152 struct samr_SetUserInfo r2;
4154 r2.in.user_handle = r->in.user_handle;
4155 r2.in.level = r->in.level;
4156 r2.in.info = r->in.info;
4158 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4163 samr_SetBootKeyInformation
4165 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4166 struct samr_SetBootKeyInformation *r)
4168 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4173 samr_GetBootKeyInformation
4175 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4176 struct samr_GetBootKeyInformation *r)
4178 /* Windows Server 2008 returns this */
4179 return NT_STATUS_NOT_SUPPORTED;
4186 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4187 struct samr_Connect3 *r)
4189 struct samr_Connect c;
4191 c.in.system_name = NULL;
4192 c.in.access_mask = r->in.access_mask;
4193 c.out.connect_handle = r->out.connect_handle;
4195 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4202 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4203 struct samr_Connect4 *r)
4205 struct samr_Connect c;
4207 c.in.system_name = NULL;
4208 c.in.access_mask = r->in.access_mask;
4209 c.out.connect_handle = r->out.connect_handle;
4211 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4218 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4219 struct samr_Connect5 *r)
4221 struct samr_Connect c;
4224 c.in.system_name = NULL;
4225 c.in.access_mask = r->in.access_mask;
4226 c.out.connect_handle = r->out.connect_handle;
4228 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4230 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4231 r->out.info_out->info1.unknown2 = 0;
4232 *r->out.level_out = r->in.level_in;
4241 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4242 struct samr_RidToSid *r)
4244 struct samr_domain_state *d_state;
4245 struct dcesrv_handle *h;
4247 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4251 /* form the users SID */
4252 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4254 return NT_STATUS_NO_MEMORY;
4257 return NT_STATUS_OK;
4262 samr_SetDsrmPassword
4264 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4265 struct samr_SetDsrmPassword *r)
4267 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4272 samr_ValidatePassword
4274 For now the call checks the password complexity (if active) and the minimum
4275 password length on level 2 and 3. Level 1 is ignored for now.
4277 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4278 TALLOC_CTX *mem_ctx,
4279 struct samr_ValidatePassword *r)
4281 struct samr_GetDomPwInfo r2;
4282 struct samr_PwInfo pwInfo;
4284 enum samr_ValidationStatus res;
4287 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4289 r2.in.domain_name = NULL;
4290 r2.out.info = &pwInfo;
4291 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4292 if (!NT_STATUS_IS_OK(status)) {
4296 switch (r->in.level) {
4297 case NetValidateAuthentication:
4298 /* we don't support this yet */
4299 return NT_STATUS_NOT_SUPPORTED;
4301 case NetValidatePasswordChange:
4302 password = data_blob_const(r->in.req->req2.password.string,
4303 r->in.req->req2.password.length);
4304 res = samdb_check_password(&password,
4305 pwInfo.password_properties,
4306 pwInfo.min_password_length);
4307 (*r->out.rep)->ctr2.status = res;
4309 case NetValidatePasswordReset:
4310 password = data_blob_const(r->in.req->req3.password.string,
4311 r->in.req->req3.password.length);
4312 res = samdb_check_password(&password,
4313 pwInfo.password_properties,
4314 pwInfo.min_password_length);
4315 (*r->out.rep)->ctr3.status = res;
4318 return NT_STATUS_INVALID_INFO_CLASS;
4322 return NT_STATUS_OK;
4326 /* include the generated boilerplate */
4327 #include "librpc/gen_ndr/ndr_samr_s.c"