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