2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "libcli/security/security.h"
37 #include "rpc_server/samr/proto.h"
38 #include "../lib/util/util_ldb.h"
39 #include "param/param.h"
41 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
43 #define QUERY_STRING(msg, field, attr) \
44 info->field.string = samdb_result_string(msg, attr, "");
45 #define QUERY_UINT(msg, field, attr) \
46 info->field = samdb_result_uint(msg, attr, 0);
47 #define QUERY_RID(msg, field, attr) \
48 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
49 #define QUERY_UINT64(msg, field, attr) \
50 info->field = samdb_result_uint64(msg, attr, 0);
51 #define QUERY_APASSC(msg, field, attr) \
52 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
53 a_state->domain_state->domain_dn, msg, attr);
54 #define QUERY_FPASSC(msg, field, attr) \
55 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg);
57 #define QUERY_LHOURS(msg, field, attr) \
58 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
59 #define QUERY_AFLAGS(msg, field, attr) \
60 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
61 #define QUERY_PARAMETERS(msg, field, attr) \
62 info->field = samdb_result_parameters(mem_ctx, msg, attr);
65 /* these are used to make the Set[User|Group]Info code easier to follow */
67 #define SET_STRING(msg, field, attr) do { \
68 struct ldb_message_element *set_el; \
69 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
70 if (r->in.info->field.string[0] == '\0') { \
71 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
72 return NT_STATUS_NO_MEMORY; \
75 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
76 return NT_STATUS_NO_MEMORY; \
78 set_el = ldb_msg_find_element(msg, attr); \
79 set_el->flags = LDB_FLAG_MOD_REPLACE; \
82 #define SET_UINT(msg, field, attr) do { \
83 struct ldb_message_element *set_el; \
84 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
85 return NT_STATUS_NO_MEMORY; \
87 set_el = ldb_msg_find_element(msg, attr); \
88 set_el->flags = LDB_FLAG_MOD_REPLACE; \
91 #define SET_INT64(msg, field, attr) do { \
92 struct ldb_message_element *set_el; \
93 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
94 return NT_STATUS_NO_MEMORY; \
96 set_el = ldb_msg_find_element(msg, attr); \
97 set_el->flags = LDB_FLAG_MOD_REPLACE; \
100 #define SET_UINT64(msg, field, attr) do { \
101 struct ldb_message_element *set_el; \
102 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
103 return NT_STATUS_NO_MEMORY; \
105 set_el = ldb_msg_find_element(msg, attr); \
106 set_el->flags = LDB_FLAG_MOD_REPLACE; \
109 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
111 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
112 return NT_STATUS_INVALID_PARAMETER; \
116 /* Set account flags, discarding flags that cannot be set with SAMR */
117 #define SET_AFLAGS(msg, field, attr) do { \
118 struct ldb_message_element *set_el; \
119 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
120 return NT_STATUS_INVALID_PARAMETER; \
122 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
127 return NT_STATUS_NO_MEMORY; \
129 set_el = ldb_msg_find_element(msg, attr); \
130 set_el->flags = LDB_FLAG_MOD_REPLACE; \
133 #define SET_LHOURS(msg, field, attr) do { \
134 struct ldb_message_element *set_el; \
135 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
136 return NT_STATUS_NO_MEMORY; \
138 set_el = ldb_msg_find_element(msg, attr); \
139 set_el->flags = LDB_FLAG_MOD_REPLACE; \
142 #define SET_PARAMETERS(msg, field, attr) do { \
143 struct ldb_message_element *set_el; \
144 if (r->in.info->field.length != 0) { \
145 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
146 return NT_STATUS_NO_MEMORY; \
148 set_el = ldb_msg_find_element(msg, attr); \
149 set_el->flags = LDB_FLAG_MOD_REPLACE; \
158 create a connection to the SAM database
160 static NTSTATUS
dcesrv_samr_Connect(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
161 struct samr_Connect
*r
)
163 struct samr_connect_state
*c_state
;
164 struct dcesrv_handle
*handle
;
166 ZERO_STRUCTP(r
->out
.connect_handle
);
168 c_state
= talloc(dce_call
->conn
, struct samr_connect_state
);
170 return NT_STATUS_NO_MEMORY
;
173 /* make sure the sam database is accessible */
174 c_state
->sam_ctx
= samdb_connect(c_state
, dce_call
->event_ctx
, dce_call
->conn
->dce_ctx
->lp_ctx
, dce_call
->conn
->auth_state
.session_info
);
175 if (c_state
->sam_ctx
== NULL
) {
176 talloc_free(c_state
);
177 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
181 handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_CONNECT
);
183 talloc_free(c_state
);
184 return NT_STATUS_NO_MEMORY
;
187 handle
->data
= talloc_steal(handle
, c_state
);
189 c_state
->access_mask
= r
->in
.access_mask
;
190 *r
->out
.connect_handle
= handle
->wire_handle
;
199 static NTSTATUS
dcesrv_samr_Close(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
200 struct samr_Close
*r
)
202 struct dcesrv_handle
*h
;
204 *r
->out
.handle
= *r
->in
.handle
;
206 DCESRV_PULL_HANDLE(h
, r
->in
.handle
, DCESRV_HANDLE_ANY
);
210 ZERO_STRUCTP(r
->out
.handle
);
219 static NTSTATUS
dcesrv_samr_SetSecurity(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
220 struct samr_SetSecurity
*r
)
222 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
229 static NTSTATUS
dcesrv_samr_QuerySecurity(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
230 struct samr_QuerySecurity
*r
)
232 struct dcesrv_handle
*h
;
233 struct sec_desc_buf
*sd
;
235 *r
->out
.sdbuf
= NULL
;
237 DCESRV_PULL_HANDLE(h
, r
->in
.handle
, DCESRV_HANDLE_ANY
);
239 sd
= talloc(mem_ctx
, struct sec_desc_buf
);
241 return NT_STATUS_NO_MEMORY
;
244 sd
->sd
= samdb_default_security_descriptor(mem_ctx
);
255 we refuse this operation completely. If a admin wants to shutdown samr
256 in Samba then they should use the samba admin tools to disable the samr pipe
258 static NTSTATUS
dcesrv_samr_Shutdown(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
259 struct samr_Shutdown
*r
)
261 return NT_STATUS_ACCESS_DENIED
;
268 this maps from a domain name to a SID
270 static NTSTATUS
dcesrv_samr_LookupDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
271 struct samr_LookupDomain
*r
)
273 struct samr_connect_state
*c_state
;
274 struct dcesrv_handle
*h
;
276 const char * const dom_attrs
[] = { "objectSid", NULL
};
277 struct ldb_message
**dom_msgs
;
282 DCESRV_PULL_HANDLE(h
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
286 if (r
->in
.domain_name
->string
== NULL
) {
287 return NT_STATUS_INVALID_PARAMETER
;
290 if (strcasecmp(r
->in
.domain_name
->string
, "BUILTIN") == 0) {
291 ret
= gendb_search(c_state
->sam_ctx
,
292 mem_ctx
, NULL
, &dom_msgs
, dom_attrs
,
293 "(objectClass=builtinDomain)");
294 } else if (strcasecmp_m(r
->in
.domain_name
->string
, lp_sam_name(dce_call
->conn
->dce_ctx
->lp_ctx
)) == 0) {
295 ret
= gendb_search_dn(c_state
->sam_ctx
,
296 mem_ctx
, ldb_get_default_basedn(c_state
->sam_ctx
),
297 &dom_msgs
, dom_attrs
);
299 return NT_STATUS_NO_SUCH_DOMAIN
;
302 return NT_STATUS_NO_SUCH_DOMAIN
;
305 sid
= samdb_result_dom_sid(mem_ctx
, dom_msgs
[0],
309 return NT_STATUS_NO_SUCH_DOMAIN
;
321 list the domains in the SAM
323 static NTSTATUS
dcesrv_samr_EnumDomains(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
324 struct samr_EnumDomains
*r
)
326 struct samr_connect_state
*c_state
;
327 struct dcesrv_handle
*h
;
328 struct samr_SamArray
*array
;
331 *r
->out
.resume_handle
= 0;
333 *r
->out
.num_entries
= 0;
335 DCESRV_PULL_HANDLE(h
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
339 *r
->out
.resume_handle
= 2;
341 start_i
= *r
->in
.resume_handle
;
344 /* search past end of list is not an error for this call */
348 array
= talloc(mem_ctx
, struct samr_SamArray
);
350 return NT_STATUS_NO_MEMORY
;
354 array
->entries
= NULL
;
356 array
->entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, 2 - start_i
);
357 if (array
->entries
== NULL
) {
358 return NT_STATUS_NO_MEMORY
;
361 for (i
=0;i
<2-start_i
;i
++) {
362 array
->entries
[i
].idx
= start_i
+ i
;
364 array
->entries
[i
].name
.string
= lp_sam_name(dce_call
->conn
->dce_ctx
->lp_ctx
);
366 array
->entries
[i
].name
.string
= "BUILTIN";
371 *r
->out
.num_entries
= i
;
372 array
->count
= *r
->out
.num_entries
;
381 static NTSTATUS
dcesrv_samr_OpenDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
382 struct samr_OpenDomain
*r
)
384 struct dcesrv_handle
*h_conn
, *h_domain
;
385 struct samr_connect_state
*c_state
;
386 struct samr_domain_state
*d_state
;
387 const char * const dom_attrs
[] = { "cn", NULL
};
388 struct ldb_message
**dom_msgs
;
391 ZERO_STRUCTP(r
->out
.domain_handle
);
393 DCESRV_PULL_HANDLE(h_conn
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
395 c_state
= h_conn
->data
;
397 if (r
->in
.sid
== NULL
) {
398 return NT_STATUS_INVALID_PARAMETER
;
401 d_state
= talloc(c_state
, struct samr_domain_state
);
403 return NT_STATUS_NO_MEMORY
;
406 d_state
->domain_sid
= talloc_steal(d_state
, r
->in
.sid
);
408 if (dom_sid_equal(d_state
->domain_sid
, dom_sid_parse_talloc(mem_ctx
, SID_BUILTIN
))) {
409 d_state
->builtin
= true;
410 d_state
->domain_name
= "BUILTIN";
412 d_state
->builtin
= false;
413 d_state
->domain_name
= lp_sam_name(dce_call
->conn
->dce_ctx
->lp_ctx
);
416 ret
= gendb_search(c_state
->sam_ctx
,
417 mem_ctx
, ldb_get_default_basedn(c_state
->sam_ctx
), &dom_msgs
, dom_attrs
,
419 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
422 talloc_free(d_state
);
423 return NT_STATUS_NO_SUCH_DOMAIN
;
424 } else if (ret
> 1) {
425 talloc_free(d_state
);
426 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
427 } else if (ret
== -1) {
428 talloc_free(d_state
);
429 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx
, r
->in
.sid
), ldb_errstring(c_state
->sam_ctx
)));
430 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
433 d_state
->domain_dn
= talloc_steal(d_state
, dom_msgs
[0]->dn
);
434 d_state
->role
= lp_server_role(dce_call
->conn
->dce_ctx
->lp_ctx
);
435 d_state
->connect_state
= talloc_reference(d_state
, c_state
);
436 d_state
->sam_ctx
= c_state
->sam_ctx
;
437 d_state
->access_mask
= r
->in
.access_mask
;
439 d_state
->lp_ctx
= dce_call
->conn
->dce_ctx
->lp_ctx
;
441 h_domain
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_DOMAIN
);
443 talloc_free(d_state
);
444 return NT_STATUS_NO_MEMORY
;
447 h_domain
->data
= talloc_steal(h_domain
, d_state
);
449 *r
->out
.domain_handle
= h_domain
->wire_handle
;
457 static NTSTATUS
dcesrv_samr_info_DomInfo1(struct samr_domain_state
*state
,
459 struct ldb_message
**dom_msgs
,
460 struct samr_DomInfo1
*info
)
462 info
->min_password_length
=
463 samdb_result_uint(dom_msgs
[0], "minPwdLength", 0);
464 info
->password_history_length
=
465 samdb_result_uint(dom_msgs
[0], "pwdHistoryLength", 0);
466 info
->password_properties
=
467 samdb_result_uint(dom_msgs
[0], "pwdProperties", 0);
468 info
->max_password_age
=
469 samdb_result_int64(dom_msgs
[0], "maxPwdAge", 0);
470 info
->min_password_age
=
471 samdb_result_int64(dom_msgs
[0], "minPwdAge", 0);
479 static NTSTATUS
dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state
*state
,
481 struct ldb_message
**dom_msgs
,
482 struct samr_DomGeneralInformation
*info
)
484 /* This pulls the NetBIOS name from the
485 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
487 info
->primary
.string
= samdb_result_fsmo_name(state
->sam_ctx
, mem_ctx
, dom_msgs
[0], "fSMORoleOwner");
489 if (!info
->primary
.string
) {
490 info
->primary
.string
= lp_netbios_name(state
->lp_ctx
);
493 info
->force_logoff_time
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "forceLogoff",
494 0x8000000000000000LL
);
496 info
->oem_information
.string
= samdb_result_string(dom_msgs
[0], "oEMInformation", NULL
);
497 info
->domain_name
.string
= state
->domain_name
;
499 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
501 switch (state
->role
) {
502 case ROLE_DOMAIN_CONTROLLER
:
503 /* This pulls the NetBIOS name from the
504 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
506 if (samdb_is_pdc(state
->sam_ctx
)) {
507 info
->role
= SAMR_ROLE_DOMAIN_PDC
;
509 info
->role
= SAMR_ROLE_DOMAIN_BDC
;
512 case ROLE_DOMAIN_MEMBER
:
513 info
->role
= SAMR_ROLE_DOMAIN_MEMBER
;
515 case ROLE_STANDALONE
:
516 info
->role
= SAMR_ROLE_STANDALONE
;
520 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
521 info
->num_users
= samdb_search_count(state
->sam_ctx
, mem_ctx
, state
->domain_dn
,
522 "(objectClass=user)");
523 info
->num_groups
= samdb_search_count(state
->sam_ctx
, mem_ctx
, state
->domain_dn
,
524 "(&(objectClass=group)(sAMAccountType=%u))",
526 info
->num_aliases
= samdb_search_count(state
->sam_ctx
, mem_ctx
, state
->domain_dn
,
527 "(&(objectClass=group)(sAMAccountType=%u))",
536 static NTSTATUS
dcesrv_samr_info_DomInfo3(struct samr_domain_state
*state
,
538 struct ldb_message
**dom_msgs
,
539 struct samr_DomInfo3
*info
)
541 info
->force_logoff_time
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "forceLogoff",
542 0x8000000000000000LL
);
550 static NTSTATUS
dcesrv_samr_info_DomOEMInformation(struct samr_domain_state
*state
,
552 struct ldb_message
**dom_msgs
,
553 struct samr_DomOEMInformation
*info
)
555 info
->oem_information
.string
= samdb_result_string(dom_msgs
[0], "oEMInformation", NULL
);
563 static NTSTATUS
dcesrv_samr_info_DomInfo5(struct samr_domain_state
*state
,
565 struct ldb_message
**dom_msgs
,
566 struct samr_DomInfo5
*info
)
568 info
->domain_name
.string
= state
->domain_name
;
576 static NTSTATUS
dcesrv_samr_info_DomInfo6(struct samr_domain_state
*state
,
578 struct ldb_message
**dom_msgs
,
579 struct samr_DomInfo6
*info
)
581 /* This pulls the NetBIOS name from the
582 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
584 info
->primary
.string
= samdb_result_fsmo_name(state
->sam_ctx
, mem_ctx
,
585 dom_msgs
[0], "fSMORoleOwner");
587 if (!info
->primary
.string
) {
588 info
->primary
.string
= lp_netbios_name(state
->lp_ctx
);
597 static NTSTATUS
dcesrv_samr_info_DomInfo7(struct samr_domain_state
*state
,
599 struct ldb_message
**dom_msgs
,
600 struct samr_DomInfo7
*info
)
603 switch (state
->role
) {
604 case ROLE_DOMAIN_CONTROLLER
:
605 /* This pulls the NetBIOS name from the
606 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
608 if (samdb_is_pdc(state
->sam_ctx
)) {
609 info
->role
= SAMR_ROLE_DOMAIN_PDC
;
611 info
->role
= SAMR_ROLE_DOMAIN_BDC
;
614 case ROLE_DOMAIN_MEMBER
:
615 info
->role
= SAMR_ROLE_DOMAIN_MEMBER
;
617 case ROLE_STANDALONE
:
618 info
->role
= SAMR_ROLE_STANDALONE
;
628 static NTSTATUS
dcesrv_samr_info_DomInfo8(struct samr_domain_state
*state
,
630 struct ldb_message
**dom_msgs
,
631 struct samr_DomInfo8
*info
)
633 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
636 info
->domain_create_time
= ldb_msg_find_attr_as_uint(dom_msgs
[0], "creationTime",
645 static NTSTATUS
dcesrv_samr_info_DomInfo9(struct samr_domain_state
*state
,
647 struct ldb_message
**dom_msgs
,
648 struct samr_DomInfo9
*info
)
650 info
->domain_server_state
= DOMAIN_SERVER_ENABLED
;
658 static NTSTATUS
dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state
*state
,
660 struct ldb_message
**dom_msgs
,
661 struct samr_DomGeneralInformation2
*info
)
664 status
= dcesrv_samr_info_DomGeneralInformation(state
, mem_ctx
, dom_msgs
, &info
->general
);
665 if (!NT_STATUS_IS_OK(status
)) {
669 info
->lockout_duration
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutDuration",
671 info
->lockout_window
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockOutObservationWindow",
673 info
->lockout_threshold
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutThreshold", 0);
681 static NTSTATUS
dcesrv_samr_info_DomInfo12(struct samr_domain_state
*state
,
683 struct ldb_message
**dom_msgs
,
684 struct samr_DomInfo12
*info
)
686 info
->lockout_duration
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutDuration",
688 info
->lockout_window
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockOutObservationWindow",
690 info
->lockout_threshold
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutThreshold", 0);
698 static NTSTATUS
dcesrv_samr_info_DomInfo13(struct samr_domain_state
*state
,
700 struct ldb_message
**dom_msgs
,
701 struct samr_DomInfo13
*info
)
703 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
706 info
->domain_create_time
= ldb_msg_find_attr_as_uint(dom_msgs
[0], "creationTime",
709 info
->modified_count_at_last_promotion
= 0;
717 static NTSTATUS
dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
718 struct samr_QueryDomainInfo
*r
)
720 struct dcesrv_handle
*h
;
721 struct samr_domain_state
*d_state
;
722 union samr_DomainInfo
*info
;
724 struct ldb_message
**dom_msgs
;
725 const char * const *attrs
= NULL
;
729 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
733 info
= talloc(mem_ctx
, union samr_DomainInfo
);
735 return NT_STATUS_NO_MEMORY
;
738 switch (r
->in
.level
) {
741 static const char * const attrs2
[] = { "minPwdLength",
752 static const char * const attrs2
[] = {"forceLogoff",
762 static const char * const attrs2
[] = {"forceLogoff",
769 static const char * const attrs2
[] = {"oEMInformation",
781 static const char * const attrs2
[] = {"fSMORoleOwner",
793 static const char * const attrs2
[] = { "modifiedCount",
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 /* some levels don't need a search */
836 ret
= gendb_search_dn(d_state
->sam_ctx
, mem_ctx
,
837 d_state
->domain_dn
, &dom_msgs
, attrs
);
839 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
847 switch (r
->in
.level
) {
849 return dcesrv_samr_info_DomInfo1(d_state
, mem_ctx
, dom_msgs
,
852 return dcesrv_samr_info_DomGeneralInformation(d_state
, mem_ctx
, dom_msgs
,
855 return dcesrv_samr_info_DomInfo3(d_state
, mem_ctx
, dom_msgs
,
858 return dcesrv_samr_info_DomOEMInformation(d_state
, mem_ctx
, dom_msgs
,
861 return dcesrv_samr_info_DomInfo5(d_state
, mem_ctx
, dom_msgs
,
864 return dcesrv_samr_info_DomInfo6(d_state
, mem_ctx
, dom_msgs
,
867 return dcesrv_samr_info_DomInfo7(d_state
, mem_ctx
, dom_msgs
,
870 return dcesrv_samr_info_DomInfo8(d_state
, mem_ctx
, dom_msgs
,
873 return dcesrv_samr_info_DomInfo9(d_state
, mem_ctx
, dom_msgs
,
876 return dcesrv_samr_info_DomGeneralInformation2(d_state
, mem_ctx
, dom_msgs
,
879 return dcesrv_samr_info_DomInfo12(d_state
, mem_ctx
, dom_msgs
,
882 return dcesrv_samr_info_DomInfo13(d_state
, mem_ctx
, dom_msgs
,
886 return NT_STATUS_INVALID_INFO_CLASS
;
893 static NTSTATUS
dcesrv_samr_SetDomainInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
894 struct samr_SetDomainInfo
*r
)
896 struct dcesrv_handle
*h
;
897 struct samr_domain_state
*d_state
;
898 struct ldb_message
*msg
;
900 struct ldb_context
*sam_ctx
;
902 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
905 sam_ctx
= d_state
->sam_ctx
;
907 msg
= ldb_msg_new(mem_ctx
);
909 return NT_STATUS_NO_MEMORY
;
912 msg
->dn
= talloc_reference(mem_ctx
, d_state
->domain_dn
);
914 return NT_STATUS_NO_MEMORY
;
917 switch (r
->in
.level
) {
919 SET_UINT (msg
, info1
.min_password_length
, "minPwdLength");
920 SET_UINT (msg
, info1
.password_history_length
, "pwdHistoryLength");
921 SET_UINT (msg
, info1
.password_properties
, "pwdProperties");
922 SET_INT64 (msg
, info1
.max_password_age
, "maxPwdAge");
923 SET_INT64 (msg
, info1
.min_password_age
, "minPwdAge");
926 SET_UINT64 (msg
, info3
.force_logoff_time
, "forceLogoff");
929 SET_STRING(msg
, oem
.oem_information
, "oEMInformation");
935 /* No op, we don't know where to set these */
940 SET_INT64 (msg
, info12
.lockout_duration
, "lockoutDuration");
941 SET_INT64 (msg
, info12
.lockout_window
, "lockOutObservationWindow");
942 SET_INT64 (msg
, info12
.lockout_threshold
, "lockoutThreshold");
946 /* many info classes are not valid for SetDomainInfo */
947 return NT_STATUS_INVALID_INFO_CLASS
;
950 /* modify the samdb record */
951 ret
= ldb_modify(sam_ctx
, msg
);
953 DEBUG(1,("Failed to modify record %s: %s\n",
954 ldb_dn_get_linearized(d_state
->domain_dn
),
955 ldb_errstring(sam_ctx
)));
957 /* we really need samdb.c to return NTSTATUS */
958 return NT_STATUS_UNSUCCESSFUL
;
965 samr_CreateDomainGroup
967 static NTSTATUS
dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
968 struct samr_CreateDomainGroup
*r
)
970 struct samr_domain_state
*d_state
;
971 struct samr_account_state
*a_state
;
972 struct dcesrv_handle
*h
;
974 struct ldb_message
*msg
;
976 const char *groupname
;
977 struct dcesrv_handle
*g_handle
;
980 ZERO_STRUCTP(r
->out
.group_handle
);
983 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
987 if (d_state
->builtin
) {
988 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
989 return NT_STATUS_ACCESS_DENIED
;
992 groupname
= r
->in
.name
->string
;
994 if (groupname
== NULL
) {
995 return NT_STATUS_INVALID_PARAMETER
;
998 /* check if the group already exists */
999 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1001 "(&(sAMAccountName=%s)(objectclass=group))",
1002 ldb_binary_encode_string(mem_ctx
, groupname
));
1004 return NT_STATUS_GROUP_EXISTS
;
1007 msg
= ldb_msg_new(mem_ctx
);
1009 return NT_STATUS_NO_MEMORY
;
1012 /* add core elements to the ldb_message for the user */
1013 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1014 ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,CN=Users", groupname
);
1016 return NT_STATUS_NO_MEMORY
;
1018 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName", groupname
);
1019 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass", "group");
1021 /* create the group */
1022 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1026 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1027 DEBUG(0,("Failed to create group record %s: %s\n",
1028 ldb_dn_get_linearized(msg
->dn
),
1029 ldb_errstring(d_state
->sam_ctx
)));
1030 return NT_STATUS_GROUP_EXISTS
;
1031 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1032 DEBUG(0,("Failed to create group record %s: %s\n",
1033 ldb_dn_get_linearized(msg
->dn
),
1034 ldb_errstring(d_state
->sam_ctx
)));
1035 return NT_STATUS_ACCESS_DENIED
;
1037 DEBUG(0,("Failed to create group record %s: %s\n",
1038 ldb_dn_get_linearized(msg
->dn
),
1039 ldb_errstring(d_state
->sam_ctx
)));
1040 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1043 a_state
= talloc(d_state
, struct samr_account_state
);
1045 return NT_STATUS_NO_MEMORY
;
1047 a_state
->sam_ctx
= d_state
->sam_ctx
;
1048 a_state
->access_mask
= r
->in
.access_mask
;
1049 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1050 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1052 /* retrieve the sid for the group just created */
1053 sid
= samdb_search_dom_sid(d_state
->sam_ctx
, a_state
,
1054 msg
->dn
, "objectSid", NULL
);
1056 return NT_STATUS_UNSUCCESSFUL
;
1059 a_state
->account_name
= talloc_strdup(a_state
, groupname
);
1060 if (!a_state
->account_name
) {
1061 return NT_STATUS_NO_MEMORY
;
1064 /* create the policy handle */
1065 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_GROUP
);
1067 return NT_STATUS_NO_MEMORY
;
1070 g_handle
->data
= talloc_steal(g_handle
, a_state
);
1072 *r
->out
.group_handle
= g_handle
->wire_handle
;
1073 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1075 return NT_STATUS_OK
;
1080 comparison function for sorting SamEntry array
1082 static int compare_SamEntry(struct samr_SamEntry
*e1
, struct samr_SamEntry
*e2
)
1084 return e1
->idx
- e2
->idx
;
1088 samr_EnumDomainGroups
1090 static NTSTATUS
dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1091 struct samr_EnumDomainGroups
*r
)
1093 struct dcesrv_handle
*h
;
1094 struct samr_domain_state
*d_state
;
1095 struct ldb_message
**res
;
1096 int ldb_cnt
, count
, i
, first
;
1097 struct samr_SamEntry
*entries
;
1098 const char * const attrs
[3] = { "objectSid", "sAMAccountName", NULL
};
1099 struct samr_SamArray
*sam
;
1101 *r
->out
.resume_handle
= 0;
1103 *r
->out
.num_entries
= 0;
1105 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1109 /* search for all domain groups in this domain. This could possibly be
1110 cached and resumed based on resume_key */
1111 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1112 d_state
->domain_dn
, &res
, attrs
,
1113 d_state
->domain_sid
,
1114 "(&(grouptype=%d)(objectclass=group))",
1115 GTYPE_SECURITY_GLOBAL_GROUP
);
1116 if (ldb_cnt
== -1) {
1117 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1120 /* convert to SamEntry format */
1121 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, ldb_cnt
);
1123 return NT_STATUS_NO_MEMORY
;
1128 for (i
=0;i
<ldb_cnt
;i
++) {
1129 struct dom_sid
*group_sid
;
1131 group_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
1133 if (group_sid
== NULL
)
1136 entries
[count
].idx
=
1137 group_sid
->sub_auths
[group_sid
->num_auths
-1];
1138 entries
[count
].name
.string
=
1139 samdb_result_string(res
[i
], "sAMAccountName", "");
1143 /* sort the results by rid */
1144 qsort(entries
, count
, sizeof(struct samr_SamEntry
),
1145 (comparison_fn_t
)compare_SamEntry
);
1147 /* find the first entry to return */
1149 first
<count
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1152 /* return the rest, limit by max_size. Note that we
1153 use the w2k3 element size value of 54 */
1154 *r
->out
.num_entries
= count
- first
;
1155 *r
->out
.num_entries
= MIN(*r
->out
.num_entries
,
1156 1+(r
->in
.max_size
/SAMR_ENUM_USERS_MULTIPLIER
));
1158 sam
= talloc(mem_ctx
, struct samr_SamArray
);
1160 return NT_STATUS_NO_MEMORY
;
1163 sam
->entries
= entries
+first
;
1164 sam
->count
= *r
->out
.num_entries
;
1168 if (*r
->out
.num_entries
< count
- first
) {
1169 *r
->out
.resume_handle
= entries
[first
+*r
->out
.num_entries
-1].idx
;
1170 return STATUS_MORE_ENTRIES
;
1173 return NT_STATUS_OK
;
1180 This call uses transactions to ensure we don't get a new conflicting
1181 user while we are processing this, and to ensure the user either
1182 completly exists, or does not.
1184 static NTSTATUS
dcesrv_samr_CreateUser2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1185 struct samr_CreateUser2
*r
)
1187 struct samr_domain_state
*d_state
;
1188 struct samr_account_state
*a_state
;
1189 struct dcesrv_handle
*h
;
1191 struct ldb_message
*msg
;
1192 struct dom_sid
*sid
;
1193 const char *account_name
;
1194 struct dcesrv_handle
*u_handle
;
1196 const char *container
, *obj_class
=NULL
;
1200 const char *attrs
[] = {
1202 "userAccountControl",
1206 uint32_t user_account_control
;
1208 struct ldb_message
**msgs
;
1210 ZERO_STRUCTP(r
->out
.user_handle
);
1211 *r
->out
.access_granted
= 0;
1214 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1218 if (d_state
->builtin
) {
1219 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1220 return NT_STATUS_ACCESS_DENIED
;
1221 } else if (r
->in
.acct_flags
== ACB_DOMTRUST
) {
1222 /* Domain trust accounts must be created by the LSA calls */
1223 return NT_STATUS_ACCESS_DENIED
;
1225 account_name
= r
->in
.account_name
->string
;
1227 if (account_name
== NULL
) {
1228 return NT_STATUS_INVALID_PARAMETER
;
1232 * Start a transaction, so we can query and do a subsequent atomic
1236 ret
= ldb_transaction_start(d_state
->sam_ctx
);
1238 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1239 ldb_errstring(d_state
->sam_ctx
)));
1240 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1243 /* check if the user already exists */
1244 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1246 "(&(sAMAccountName=%s)(objectclass=user))",
1247 ldb_binary_encode_string(mem_ctx
, account_name
));
1249 ldb_transaction_cancel(d_state
->sam_ctx
);
1250 return NT_STATUS_USER_EXISTS
;
1253 msg
= ldb_msg_new(mem_ctx
);
1255 ldb_transaction_cancel(d_state
->sam_ctx
);
1256 return NT_STATUS_NO_MEMORY
;
1259 cn_name
= talloc_strdup(mem_ctx
, account_name
);
1261 ldb_transaction_cancel(d_state
->sam_ctx
);
1262 return NT_STATUS_NO_MEMORY
;
1265 cn_name_len
= strlen(cn_name
);
1267 /* This must be one of these values *only* */
1268 if (r
->in
.acct_flags
== ACB_NORMAL
) {
1269 container
= "CN=Users";
1272 } else if (r
->in
.acct_flags
== ACB_WSTRUST
) {
1273 if (cn_name
[cn_name_len
- 1] != '$') {
1274 ldb_transaction_cancel(d_state
->sam_ctx
);
1275 return NT_STATUS_FOOBAR
;
1277 cn_name
[cn_name_len
- 1] = '\0';
1278 container
= "CN=Computers";
1279 obj_class
= "computer";
1280 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
,
1281 "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS
);
1283 } else if (r
->in
.acct_flags
== ACB_SVRTRUST
) {
1284 if (cn_name
[cn_name_len
- 1] != '$') {
1285 ldb_transaction_cancel(d_state
->sam_ctx
);
1286 return NT_STATUS_FOOBAR
;
1288 cn_name
[cn_name_len
- 1] = '\0';
1289 container
= "OU=Domain Controllers";
1290 obj_class
= "computer";
1291 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
,
1292 "primaryGroupID", DOMAIN_RID_DCS
);
1294 ldb_transaction_cancel(d_state
->sam_ctx
);
1295 return NT_STATUS_INVALID_PARAMETER
;
1298 /* add core elements to the ldb_message for the user */
1299 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1300 if ( ! ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,%s", cn_name
, container
)) {
1301 ldb_transaction_cancel(d_state
->sam_ctx
);
1302 return NT_STATUS_FOOBAR
;
1305 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName",
1307 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass",
1310 /* create the user */
1311 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1315 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1316 ldb_transaction_cancel(d_state
->sam_ctx
);
1317 DEBUG(0,("Failed to create user record %s: %s\n",
1318 ldb_dn_get_linearized(msg
->dn
),
1319 ldb_errstring(d_state
->sam_ctx
)));
1320 return NT_STATUS_USER_EXISTS
;
1321 case LDB_ERR_UNWILLING_TO_PERFORM
:
1322 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1323 ldb_transaction_cancel(d_state
->sam_ctx
);
1324 DEBUG(0,("Failed to create user record %s: %s\n",
1325 ldb_dn_get_linearized(msg
->dn
),
1326 ldb_errstring(d_state
->sam_ctx
)));
1327 return NT_STATUS_ACCESS_DENIED
;
1329 ldb_transaction_cancel(d_state
->sam_ctx
);
1330 DEBUG(0,("Failed to create user record %s: %s\n",
1331 ldb_dn_get_linearized(msg
->dn
),
1332 ldb_errstring(d_state
->sam_ctx
)));
1333 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1336 a_state
= talloc(d_state
, struct samr_account_state
);
1338 ldb_transaction_cancel(d_state
->sam_ctx
);
1339 return NT_STATUS_NO_MEMORY
;
1341 a_state
->sam_ctx
= d_state
->sam_ctx
;
1342 a_state
->access_mask
= r
->in
.access_mask
;
1343 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1344 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1346 /* retrieve the sid and account control bits for the user just created */
1347 ret
= gendb_search_dn(d_state
->sam_ctx
, a_state
,
1348 msg
->dn
, &msgs
, attrs
);
1351 ldb_transaction_cancel(d_state
->sam_ctx
);
1352 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1353 ldb_dn_get_linearized(msg
->dn
)));
1354 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1356 sid
= samdb_result_dom_sid(mem_ctx
, msgs
[0], "objectSid");
1358 ldb_transaction_cancel(d_state
->sam_ctx
);
1359 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1360 ldb_dn_get_linearized(msg
->dn
)));
1361 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1364 /* Change the account control to be the correct account type.
1365 * The default is for a workstation account */
1366 user_account_control
= samdb_result_uint(msgs
[0], "userAccountControl", 0);
1367 user_account_control
= (user_account_control
&
1368 ~(UF_NORMAL_ACCOUNT
|
1369 UF_INTERDOMAIN_TRUST_ACCOUNT
|
1370 UF_WORKSTATION_TRUST_ACCOUNT
|
1371 UF_SERVER_TRUST_ACCOUNT
));
1372 user_account_control
|= ds_acb2uf(r
->in
.acct_flags
);
1375 msg
= ldb_msg_new(mem_ctx
);
1377 ldb_transaction_cancel(d_state
->sam_ctx
);
1378 return NT_STATUS_NO_MEMORY
;
1381 msg
->dn
= ldb_dn_copy(msg
, a_state
->account_dn
);
1383 if (samdb_msg_add_uint(a_state
->sam_ctx
, mem_ctx
, msg
,
1384 "userAccountControl",
1385 user_account_control
) != 0) {
1386 ldb_transaction_cancel(d_state
->sam_ctx
);
1387 return NT_STATUS_NO_MEMORY
;
1390 /* modify the samdb record */
1391 ret
= samdb_replace(a_state
->sam_ctx
, mem_ctx
, msg
);
1393 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1394 ldb_dn_get_linearized(msg
->dn
),
1395 ldb_errstring(d_state
->sam_ctx
)));
1396 ldb_transaction_cancel(d_state
->sam_ctx
);
1398 /* we really need samdb.c to return NTSTATUS */
1399 return NT_STATUS_UNSUCCESSFUL
;
1402 ret
= ldb_transaction_commit(d_state
->sam_ctx
);
1404 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1405 ldb_dn_get_linearized(msg
->dn
),
1406 ldb_errstring(d_state
->sam_ctx
)));
1407 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1410 a_state
->account_name
= talloc_steal(a_state
, account_name
);
1411 if (!a_state
->account_name
) {
1412 return NT_STATUS_NO_MEMORY
;
1415 /* create the policy handle */
1416 u_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_USER
);
1418 return NT_STATUS_NO_MEMORY
;
1421 u_handle
->data
= talloc_steal(u_handle
, a_state
);
1423 *r
->out
.user_handle
= u_handle
->wire_handle
;
1424 *r
->out
.access_granted
= 0xf07ff; /* TODO: fix access mask calculations */
1426 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1428 return NT_STATUS_OK
;
1435 static NTSTATUS
dcesrv_samr_CreateUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1436 struct samr_CreateUser
*r
)
1438 struct samr_CreateUser2 r2
;
1439 uint32_t access_granted
= 0;
1442 /* a simple wrapper around samr_CreateUser2 works nicely */
1443 r2
.in
.domain_handle
= r
->in
.domain_handle
;
1444 r2
.in
.account_name
= r
->in
.account_name
;
1445 r2
.in
.acct_flags
= ACB_NORMAL
;
1446 r2
.in
.access_mask
= r
->in
.access_mask
;
1447 r2
.out
.user_handle
= r
->out
.user_handle
;
1448 r2
.out
.access_granted
= &access_granted
;
1449 r2
.out
.rid
= r
->out
.rid
;
1451 return dcesrv_samr_CreateUser2(dce_call
, mem_ctx
, &r2
);
1455 samr_EnumDomainUsers
1457 static NTSTATUS
dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1458 struct samr_EnumDomainUsers
*r
)
1460 struct dcesrv_handle
*h
;
1461 struct samr_domain_state
*d_state
;
1462 struct ldb_result
*res
;
1463 int ret
, num_filtered_entries
, i
, first
;
1464 struct samr_SamEntry
*entries
;
1465 const char * const attrs
[] = { "objectSid", "sAMAccountName",
1466 "userAccountControl", NULL
};
1467 struct samr_SamArray
*sam
;
1469 *r
->out
.resume_handle
= 0;
1471 *r
->out
.num_entries
= 0;
1473 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1477 /* don't have to worry about users in the builtin domain, as there are none */
1478 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
, d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
, "objectClass=user");
1480 if (ret
!= LDB_SUCCESS
) {
1481 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1482 ldb_dn_get_linearized(d_state
->domain_dn
), ldb_errstring(d_state
->sam_ctx
)));
1483 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1486 /* convert to SamEntry format */
1487 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, res
->count
);
1489 return NT_STATUS_NO_MEMORY
;
1491 num_filtered_entries
= 0;
1492 for (i
=0;i
<res
->count
;i
++) {
1493 /* Check if a mask has been requested */
1494 if (r
->in
.acct_flags
1495 && ((samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
, res
->msgs
[i
],
1496 d_state
->domain_dn
) & r
->in
.acct_flags
) == 0)) {
1499 entries
[num_filtered_entries
].idx
= samdb_result_rid_from_sid(mem_ctx
, res
->msgs
[i
], "objectSid", 0);
1500 entries
[num_filtered_entries
].name
.string
= samdb_result_string(res
->msgs
[i
], "sAMAccountName", "");
1501 num_filtered_entries
++;
1504 /* sort the results by rid */
1505 qsort(entries
, num_filtered_entries
, sizeof(struct samr_SamEntry
),
1506 (comparison_fn_t
)compare_SamEntry
);
1508 /* find the first entry to return */
1510 first
<num_filtered_entries
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1513 /* return the rest, limit by max_size. Note that we
1514 use the w2k3 element size value of 54 */
1515 *r
->out
.num_entries
= num_filtered_entries
- first
;
1516 *r
->out
.num_entries
= MIN(*r
->out
.num_entries
,
1517 1+(r
->in
.max_size
/SAMR_ENUM_USERS_MULTIPLIER
));
1519 sam
= talloc(mem_ctx
, struct samr_SamArray
);
1521 return NT_STATUS_NO_MEMORY
;
1524 sam
->entries
= entries
+first
;
1525 sam
->count
= *r
->out
.num_entries
;
1529 if (first
== num_filtered_entries
) {
1530 return NT_STATUS_OK
;
1533 if (*r
->out
.num_entries
< num_filtered_entries
- first
) {
1534 *r
->out
.resume_handle
= entries
[first
+*r
->out
.num_entries
-1].idx
;
1535 return STATUS_MORE_ENTRIES
;
1538 return NT_STATUS_OK
;
1545 static NTSTATUS
dcesrv_samr_CreateDomAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1546 struct samr_CreateDomAlias
*r
)
1548 struct samr_domain_state
*d_state
;
1549 struct samr_account_state
*a_state
;
1550 struct dcesrv_handle
*h
;
1551 const char *alias_name
, *name
;
1552 struct ldb_message
*msg
;
1553 struct dom_sid
*sid
;
1554 struct dcesrv_handle
*a_handle
;
1557 ZERO_STRUCTP(r
->out
.alias_handle
);
1560 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1564 if (d_state
->builtin
) {
1565 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1566 return NT_STATUS_ACCESS_DENIED
;
1569 alias_name
= r
->in
.alias_name
->string
;
1571 if (alias_name
== NULL
) {
1572 return NT_STATUS_INVALID_PARAMETER
;
1575 /* Check if alias already exists */
1576 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1578 "(sAMAccountName=%s)(objectclass=group))",
1579 ldb_binary_encode_string(mem_ctx
, alias_name
));
1582 return NT_STATUS_ALIAS_EXISTS
;
1585 msg
= ldb_msg_new(mem_ctx
);
1587 return NT_STATUS_NO_MEMORY
;
1590 /* add core elements to the ldb_message for the alias */
1591 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1592 ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,CN=Users", alias_name
);
1594 return NT_STATUS_NO_MEMORY
;
1597 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName", alias_name
);
1598 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass", "group");
1599 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1601 /* create the alias */
1602 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1606 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1607 return NT_STATUS_ALIAS_EXISTS
;
1608 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1609 return NT_STATUS_ACCESS_DENIED
;
1611 DEBUG(0,("Failed to create alias record %s: %s\n",
1612 ldb_dn_get_linearized(msg
->dn
),
1613 ldb_errstring(d_state
->sam_ctx
)));
1614 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1617 a_state
= talloc(d_state
, struct samr_account_state
);
1619 return NT_STATUS_NO_MEMORY
;
1622 a_state
->sam_ctx
= d_state
->sam_ctx
;
1623 a_state
->access_mask
= r
->in
.access_mask
;
1624 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1625 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1627 /* retrieve the sid for the alias just created */
1628 sid
= samdb_search_dom_sid(d_state
->sam_ctx
, a_state
,
1629 msg
->dn
, "objectSid", NULL
);
1631 a_state
->account_name
= talloc_strdup(a_state
, alias_name
);
1632 if (!a_state
->account_name
) {
1633 return NT_STATUS_NO_MEMORY
;
1636 /* create the policy handle */
1637 a_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_ALIAS
);
1638 if (a_handle
== NULL
)
1639 return NT_STATUS_NO_MEMORY
;
1641 a_handle
->data
= talloc_steal(a_handle
, a_state
);
1643 *r
->out
.alias_handle
= a_handle
->wire_handle
;
1645 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1647 return NT_STATUS_OK
;
1652 samr_EnumDomainAliases
1654 static NTSTATUS
dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1655 struct samr_EnumDomainAliases
*r
)
1657 struct dcesrv_handle
*h
;
1658 struct samr_domain_state
*d_state
;
1659 struct ldb_message
**res
;
1660 int ldb_cnt
, count
, i
, first
;
1661 struct samr_SamEntry
*entries
;
1662 const char * const attrs
[3] = { "objectSid", "sAMAccountName", NULL
};
1663 struct samr_SamArray
*sam
;
1665 *r
->out
.resume_handle
= 0;
1667 *r
->out
.num_entries
= 0;
1669 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1673 /* search for all domain groups in this domain. This could possibly be
1674 cached and resumed based on resume_key */
1675 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1678 d_state
->domain_sid
,
1679 "(&(|(grouptype=%d)(grouptype=%d)))"
1680 "(objectclass=group))",
1681 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
1682 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1683 if (ldb_cnt
== -1) {
1684 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1687 return NT_STATUS_OK
;
1690 /* convert to SamEntry format */
1691 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, ldb_cnt
);
1693 return NT_STATUS_NO_MEMORY
;
1698 for (i
=0;i
<ldb_cnt
;i
++) {
1699 struct dom_sid
*alias_sid
;
1701 alias_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
1704 if (alias_sid
== NULL
)
1707 entries
[count
].idx
=
1708 alias_sid
->sub_auths
[alias_sid
->num_auths
-1];
1709 entries
[count
].name
.string
=
1710 samdb_result_string(res
[i
], "sAMAccountName", "");
1714 /* sort the results by rid */
1715 qsort(entries
, count
, sizeof(struct samr_SamEntry
),
1716 (comparison_fn_t
)compare_SamEntry
);
1718 /* find the first entry to return */
1720 first
<count
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1723 if (first
== count
) {
1724 return NT_STATUS_OK
;
1727 *r
->out
.num_entries
= count
- first
;
1728 *r
->out
.num_entries
= MIN(*r
->out
.num_entries
, 1000);
1730 sam
= talloc(mem_ctx
, struct samr_SamArray
);
1732 return NT_STATUS_NO_MEMORY
;
1735 sam
->entries
= entries
+first
;
1736 sam
->count
= *r
->out
.num_entries
;
1740 if (*r
->out
.num_entries
< count
- first
) {
1741 *r
->out
.resume_handle
=
1742 entries
[first
+*r
->out
.num_entries
-1].idx
;
1743 return STATUS_MORE_ENTRIES
;
1746 return NT_STATUS_OK
;
1751 samr_GetAliasMembership
1753 static NTSTATUS
dcesrv_samr_GetAliasMembership(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1754 struct samr_GetAliasMembership
*r
)
1756 struct dcesrv_handle
*h
;
1757 struct samr_domain_state
*d_state
;
1758 struct ldb_message
**res
;
1761 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1765 if (r
->in
.sids
->num_sids
> 0) {
1767 const char * const attrs
[2] = { "objectSid", NULL
};
1769 filter
= talloc_asprintf(mem_ctx
,
1770 "(&(|(grouptype=%d)(grouptype=%d))"
1771 "(objectclass=group)(|",
1772 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
1773 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1775 return NT_STATUS_NO_MEMORY
;
1777 for (i
=0; i
<r
->in
.sids
->num_sids
; i
++) {
1778 const char *memberdn
;
1781 samdb_search_string(d_state
->sam_ctx
,
1783 "distinguishedName",
1785 ldap_encode_ndr_dom_sid(mem_ctx
,
1786 r
->in
.sids
->sids
[i
].sid
));
1788 if (memberdn
== NULL
)
1791 filter
= talloc_asprintf(mem_ctx
, "%s(member=%s)",
1794 return NT_STATUS_NO_MEMORY
;
1797 count
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1798 d_state
->domain_dn
, &res
, attrs
,
1799 d_state
->domain_sid
, "%s))", filter
);
1801 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1804 r
->out
.rids
->count
= 0;
1805 r
->out
.rids
->ids
= talloc_array(mem_ctx
, uint32_t, count
);
1806 if (r
->out
.rids
->ids
== NULL
)
1807 return NT_STATUS_NO_MEMORY
;
1809 for (i
=0; i
<count
; i
++) {
1810 struct dom_sid
*alias_sid
;
1812 alias_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
], "objectSid");
1814 if (alias_sid
== NULL
) {
1815 DEBUG(0, ("Could not find objectSid\n"));
1819 r
->out
.rids
->ids
[r
->out
.rids
->count
] =
1820 alias_sid
->sub_auths
[alias_sid
->num_auths
-1];
1821 r
->out
.rids
->count
+= 1;
1824 return NT_STATUS_OK
;
1831 static NTSTATUS
dcesrv_samr_LookupNames(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1832 struct samr_LookupNames
*r
)
1834 struct dcesrv_handle
*h
;
1835 struct samr_domain_state
*d_state
;
1837 NTSTATUS status
= NT_STATUS_OK
;
1838 const char * const attrs
[] = { "sAMAccountType", "objectSid", NULL
};
1841 ZERO_STRUCTP(r
->out
.rids
);
1842 ZERO_STRUCTP(r
->out
.types
);
1844 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1848 if (r
->in
.num_names
== 0) {
1849 return NT_STATUS_OK
;
1852 r
->out
.rids
->ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_names
);
1853 r
->out
.types
->ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_names
);
1854 if (!r
->out
.rids
->ids
|| !r
->out
.types
->ids
) {
1855 return NT_STATUS_NO_MEMORY
;
1857 r
->out
.rids
->count
= r
->in
.num_names
;
1858 r
->out
.types
->count
= r
->in
.num_names
;
1862 for (i
=0;i
<r
->in
.num_names
;i
++) {
1863 struct ldb_message
**res
;
1864 struct dom_sid
*sid
;
1865 uint32_t atype
, rtype
;
1867 r
->out
.rids
->ids
[i
] = 0;
1868 r
->out
.types
->ids
[i
] = SID_NAME_UNKNOWN
;
1870 count
= gendb_search(d_state
->sam_ctx
, mem_ctx
, d_state
->domain_dn
, &res
, attrs
,
1871 "sAMAccountName=%s",
1872 ldb_binary_encode_string(mem_ctx
, r
->in
.names
[i
].string
));
1874 status
= STATUS_SOME_UNMAPPED
;
1878 sid
= samdb_result_dom_sid(mem_ctx
, res
[0], "objectSid");
1880 status
= STATUS_SOME_UNMAPPED
;
1884 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
1886 status
= STATUS_SOME_UNMAPPED
;
1890 rtype
= ds_atype_map(atype
);
1892 if (rtype
== SID_NAME_UNKNOWN
) {
1893 status
= STATUS_SOME_UNMAPPED
;
1897 r
->out
.rids
->ids
[i
] = sid
->sub_auths
[sid
->num_auths
-1];
1898 r
->out
.types
->ids
[i
] = rtype
;
1902 if (num_mapped
== 0) {
1903 return NT_STATUS_NONE_MAPPED
;
1912 static NTSTATUS
dcesrv_samr_LookupRids(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1913 struct samr_LookupRids
*r
)
1915 struct dcesrv_handle
*h
;
1916 struct samr_domain_state
*d_state
;
1918 NTSTATUS status
= NT_STATUS_OK
;
1919 struct lsa_String
*names
;
1922 ZERO_STRUCTP(r
->out
.names
);
1923 ZERO_STRUCTP(r
->out
.types
);
1925 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1929 if (r
->in
.num_rids
== 0)
1930 return NT_STATUS_OK
;
1932 names
= talloc_array(mem_ctx
, struct lsa_String
, r
->in
.num_rids
);
1933 ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_rids
);
1935 if ((names
== NULL
) || (ids
== NULL
))
1936 return NT_STATUS_NO_MEMORY
;
1940 for (i
=0; i
<r
->in
.num_rids
; i
++) {
1941 struct ldb_message
**res
;
1943 const char * const attrs
[] = { "sAMAccountType",
1944 "sAMAccountName", NULL
};
1946 struct dom_sid
*sid
;
1948 ids
[i
] = SID_NAME_UNKNOWN
;
1950 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
,
1953 names
[i
].string
= NULL
;
1954 status
= STATUS_SOME_UNMAPPED
;
1958 count
= gendb_search(d_state
->sam_ctx
, mem_ctx
,
1959 d_state
->domain_dn
, &res
, attrs
,
1961 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
1963 names
[i
].string
= NULL
;
1964 status
= STATUS_SOME_UNMAPPED
;
1968 names
[i
].string
= samdb_result_string(res
[0], "sAMAccountName",
1971 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
1973 status
= STATUS_SOME_UNMAPPED
;
1977 ids
[i
] = ds_atype_map(atype
);
1979 if (ids
[i
] == SID_NAME_UNKNOWN
) {
1980 status
= STATUS_SOME_UNMAPPED
;
1985 r
->out
.names
->names
= names
;
1986 r
->out
.names
->count
= r
->in
.num_rids
;
1988 r
->out
.types
->ids
= ids
;
1989 r
->out
.types
->count
= r
->in
.num_rids
;
1998 static NTSTATUS
dcesrv_samr_OpenGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1999 struct samr_OpenGroup
*r
)
2001 struct samr_domain_state
*d_state
;
2002 struct samr_account_state
*a_state
;
2003 struct dcesrv_handle
*h
;
2004 const char *groupname
;
2005 struct dom_sid
*sid
;
2006 struct ldb_message
**msgs
;
2007 struct dcesrv_handle
*g_handle
;
2008 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2011 ZERO_STRUCTP(r
->out
.group_handle
);
2013 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2017 /* form the group SID */
2018 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2020 return NT_STATUS_NO_MEMORY
;
2023 /* search for the group record */
2024 ret
= gendb_search(d_state
->sam_ctx
,
2025 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2026 "(&(objectSid=%s)(objectclass=group)"
2028 ldap_encode_ndr_dom_sid(mem_ctx
, sid
),
2029 GTYPE_SECURITY_GLOBAL_GROUP
);
2031 return NT_STATUS_NO_SUCH_GROUP
;
2034 DEBUG(0,("Found %d records matching sid %s\n",
2035 ret
, dom_sid_string(mem_ctx
, sid
)));
2036 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2039 groupname
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2040 if (groupname
== NULL
) {
2041 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2042 dom_sid_string(mem_ctx
, sid
)));
2043 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2046 a_state
= talloc(d_state
, struct samr_account_state
);
2048 return NT_STATUS_NO_MEMORY
;
2050 a_state
->sam_ctx
= d_state
->sam_ctx
;
2051 a_state
->access_mask
= r
->in
.access_mask
;
2052 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2053 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2054 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2055 a_state
->account_name
= talloc_strdup(a_state
, groupname
);
2056 if (!a_state
->account_name
) {
2057 return NT_STATUS_NO_MEMORY
;
2060 /* create the policy handle */
2061 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_GROUP
);
2063 return NT_STATUS_NO_MEMORY
;
2066 g_handle
->data
= talloc_steal(g_handle
, a_state
);
2068 *r
->out
.group_handle
= g_handle
->wire_handle
;
2070 return NT_STATUS_OK
;
2076 static NTSTATUS
dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2077 struct samr_QueryGroupInfo
*r
)
2079 struct dcesrv_handle
*h
;
2080 struct samr_account_state
*a_state
;
2081 struct ldb_message
*msg
;
2082 struct ldb_result
*res
;
2083 const char * const attrs
[4] = { "sAMAccountName", "description",
2084 "numMembers", NULL
};
2086 union samr_GroupInfo
*info
;
2088 *r
->out
.info
= NULL
;
2090 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2094 ret
= ldb_search(a_state
->sam_ctx
, mem_ctx
, &res
, a_state
->account_dn
,
2095 LDB_SCOPE_SUBTREE
, attrs
, "objectClass=*");
2097 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
2098 return NT_STATUS_NO_SUCH_GROUP
;
2099 } else if (ret
!= LDB_SUCCESS
) {
2100 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state
->sam_ctx
)));
2101 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2104 if (res
->count
!= 1) {
2105 DEBUG(2, ("Error finding group info, got %d entries\n", res
->count
));
2107 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2111 /* allocate the info structure */
2112 info
= talloc_zero(mem_ctx
, union samr_GroupInfo
);
2114 return NT_STATUS_NO_MEMORY
;
2117 /* Fill in the level */
2118 switch (r
->in
.level
) {
2120 QUERY_STRING(msg
, all
.name
, "sAMAccountName");
2121 info
->all
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2122 QUERY_UINT (msg
, all
.num_members
, "numMembers")
2123 QUERY_STRING(msg
, all
.description
, "description");
2126 QUERY_STRING(msg
, name
, "sAMAccountName");
2128 case GROUPINFOATTRIBUTES
:
2129 info
->attributes
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2131 case GROUPINFODESCRIPTION
:
2132 QUERY_STRING(msg
, description
, "description");
2135 QUERY_STRING(msg
, all2
.name
, "sAMAccountName");
2136 info
->all
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2137 QUERY_UINT (msg
, all2
.num_members
, "numMembers")
2138 QUERY_STRING(msg
, all2
.description
, "description");
2142 return NT_STATUS_INVALID_INFO_CLASS
;
2145 *r
->out
.info
= info
;
2147 return NT_STATUS_OK
;
2154 static NTSTATUS
dcesrv_samr_SetGroupInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2155 struct samr_SetGroupInfo
*r
)
2157 struct dcesrv_handle
*h
;
2158 struct samr_account_state
*g_state
;
2159 struct ldb_message
*msg
;
2160 struct ldb_context
*sam_ctx
;
2163 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2166 sam_ctx
= g_state
->sam_ctx
;
2168 msg
= ldb_msg_new(mem_ctx
);
2170 return NT_STATUS_NO_MEMORY
;
2173 msg
->dn
= ldb_dn_copy(mem_ctx
, g_state
->account_dn
);
2175 return NT_STATUS_NO_MEMORY
;
2178 switch (r
->in
.level
) {
2179 case GROUPINFODESCRIPTION
:
2180 SET_STRING(msg
, description
, "description");
2183 /* On W2k3 this does not change the name, it changes the
2184 * sAMAccountName attribute */
2185 SET_STRING(msg
, name
, "sAMAccountName");
2187 case GROUPINFOATTRIBUTES
:
2188 /* This does not do anything obviously visible in W2k3 LDAP */
2189 return NT_STATUS_OK
;
2191 return NT_STATUS_INVALID_INFO_CLASS
;
2194 /* modify the samdb record */
2195 ret
= ldb_modify(g_state
->sam_ctx
, msg
);
2197 /* we really need samdb.c to return NTSTATUS */
2198 return NT_STATUS_UNSUCCESSFUL
;
2201 return NT_STATUS_OK
;
2208 static NTSTATUS
dcesrv_samr_AddGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2209 struct samr_AddGroupMember
*r
)
2211 struct dcesrv_handle
*h
;
2212 struct samr_account_state
*a_state
;
2213 struct samr_domain_state
*d_state
;
2214 struct ldb_message
*mod
;
2215 struct dom_sid
*membersid
;
2216 const char *memberdn
;
2217 struct ldb_result
*res
;
2218 const char * const attrs
[] = { NULL
};
2221 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2224 d_state
= a_state
->domain_state
;
2226 membersid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2227 if (membersid
== NULL
)
2228 return NT_STATUS_NO_MEMORY
;
2230 /* In native mode, AD can also nest domain groups. Not sure yet
2231 * whether this is also available via RPC. */
2232 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
,
2233 d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
,
2234 "(&(objectSid=%s)(objectclass=user))",
2235 ldap_encode_ndr_dom_sid(mem_ctx
, membersid
));
2238 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2241 if (res
->count
== 0) {
2242 return NT_STATUS_NO_SUCH_USER
;
2245 if (res
->count
> 1) {
2246 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2249 memberdn
= ldb_dn_alloc_linearized(mem_ctx
, res
->msgs
[0]->dn
);
2251 if (memberdn
== NULL
)
2252 return NT_STATUS_NO_MEMORY
;
2254 mod
= ldb_msg_new(mem_ctx
);
2256 return NT_STATUS_NO_MEMORY
;
2259 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2261 if (samdb_msg_add_addval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2263 return NT_STATUS_UNSUCCESSFUL
;
2265 ret
= ldb_modify(a_state
->sam_ctx
, mod
);
2268 return NT_STATUS_OK
;
2269 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
:
2270 return NT_STATUS_MEMBER_IN_GROUP
;
2271 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
2272 return NT_STATUS_ACCESS_DENIED
;
2274 return NT_STATUS_UNSUCCESSFUL
;
2281 samr_DeleteDomainGroup
2283 static NTSTATUS
dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2284 struct samr_DeleteDomainGroup
*r
)
2286 struct dcesrv_handle
*h
;
2287 struct samr_account_state
*a_state
;
2290 *r
->out
.group_handle
= *r
->in
.group_handle
;
2292 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2296 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2298 return NT_STATUS_UNSUCCESSFUL
;
2301 ZERO_STRUCTP(r
->out
.group_handle
);
2303 return NT_STATUS_OK
;
2308 samr_DeleteGroupMember
2310 static NTSTATUS
dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2311 struct samr_DeleteGroupMember
*r
)
2313 struct dcesrv_handle
*h
;
2314 struct samr_account_state
*a_state
;
2315 struct samr_domain_state
*d_state
;
2316 struct ldb_message
*mod
;
2317 struct dom_sid
*membersid
;
2318 const char *memberdn
;
2319 struct ldb_result
*res
;
2320 const char * const attrs
[] = { NULL
};
2323 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2326 d_state
= a_state
->domain_state
;
2328 membersid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2329 if (membersid
== NULL
)
2330 return NT_STATUS_NO_MEMORY
;
2332 /* In native mode, AD can also nest domain groups. Not sure yet
2333 * whether this is also available via RPC. */
2334 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
,
2335 d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
,
2336 "(&(objectSid=%s)(objectclass=user))",
2337 ldap_encode_ndr_dom_sid(mem_ctx
, membersid
));
2340 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2343 if (res
->count
== 0) {
2344 return NT_STATUS_NO_SUCH_USER
;
2347 if (res
->count
> 1) {
2348 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2351 memberdn
= ldb_dn_alloc_linearized(mem_ctx
, res
->msgs
[0]->dn
);
2353 if (memberdn
== NULL
)
2354 return NT_STATUS_NO_MEMORY
;
2356 mod
= ldb_msg_new(mem_ctx
);
2358 return NT_STATUS_NO_MEMORY
;
2361 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2363 if (samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2365 return NT_STATUS_NO_MEMORY
;
2368 ret
= ldb_modify(a_state
->sam_ctx
, mod
);
2371 return NT_STATUS_OK
;
2372 case LDB_ERR_NO_SUCH_ATTRIBUTE
:
2373 return NT_STATUS_MEMBER_NOT_IN_GROUP
;
2374 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
2375 return NT_STATUS_ACCESS_DENIED
;
2377 return NT_STATUS_UNSUCCESSFUL
;
2383 samr_QueryGroupMember
2385 static NTSTATUS
dcesrv_samr_QueryGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2386 struct samr_QueryGroupMember
*r
)
2388 struct dcesrv_handle
*h
;
2389 struct samr_account_state
*a_state
;
2390 struct ldb_message
**res
;
2391 struct ldb_message_element
*el
;
2392 struct samr_RidTypeArray
*array
;
2393 const char * const attrs
[2] = { "member", NULL
};
2396 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2400 /* pull the member attribute */
2401 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2402 a_state
->account_dn
, &res
, attrs
);
2405 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2408 array
= talloc(mem_ctx
, struct samr_RidTypeArray
);
2411 return NT_STATUS_NO_MEMORY
;
2413 ZERO_STRUCTP(array
);
2415 el
= ldb_msg_find_element(res
[0], "member");
2420 array
->count
= el
->num_values
;
2422 array
->rids
= talloc_array(mem_ctx
, uint32_t,
2424 if (array
->rids
== NULL
)
2425 return NT_STATUS_NO_MEMORY
;
2427 array
->types
= talloc_array(mem_ctx
, uint32_t,
2429 if (array
->types
== NULL
)
2430 return NT_STATUS_NO_MEMORY
;
2432 for (i
=0; i
<el
->num_values
; i
++) {
2433 struct ldb_message
**res2
;
2434 const char * const attrs2
[2] = { "objectSid", NULL
};
2435 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2436 ldb_dn_from_ldb_val(mem_ctx
, a_state
->sam_ctx
, &el
->values
[i
]),
2439 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2442 samdb_result_rid_from_sid(mem_ctx
, res2
[0],
2445 if (array
->rids
[i
] == 0)
2446 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2448 array
->types
[i
] = 7; /* RID type of some kind, not sure what the value means. */
2452 *r
->out
.rids
= array
;
2454 return NT_STATUS_OK
;
2459 samr_SetMemberAttributesOfGroup
2461 static NTSTATUS
dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2462 struct samr_SetMemberAttributesOfGroup
*r
)
2464 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
2471 static NTSTATUS
dcesrv_samr_OpenAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2472 struct samr_OpenAlias
*r
)
2474 struct samr_domain_state
*d_state
;
2475 struct samr_account_state
*a_state
;
2476 struct dcesrv_handle
*h
;
2477 const char *alias_name
;
2478 struct dom_sid
*sid
;
2479 struct ldb_message
**msgs
;
2480 struct dcesrv_handle
*g_handle
;
2481 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2484 ZERO_STRUCTP(r
->out
.alias_handle
);
2486 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2490 /* form the alias SID */
2491 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2493 return NT_STATUS_NO_MEMORY
;
2495 /* search for the group record */
2496 ret
= gendb_search(d_state
->sam_ctx
,
2497 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2498 "(&(objectSid=%s)(objectclass=group)"
2499 "(|(grouptype=%d)(grouptype=%d)))",
2500 ldap_encode_ndr_dom_sid(mem_ctx
, sid
),
2501 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
2502 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
2504 return NT_STATUS_NO_SUCH_ALIAS
;
2507 DEBUG(0,("Found %d records matching sid %s\n",
2508 ret
, dom_sid_string(mem_ctx
, sid
)));
2509 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2512 alias_name
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2513 if (alias_name
== NULL
) {
2514 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2515 dom_sid_string(mem_ctx
, sid
)));
2516 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2519 a_state
= talloc(d_state
, struct samr_account_state
);
2521 return NT_STATUS_NO_MEMORY
;
2523 a_state
->sam_ctx
= d_state
->sam_ctx
;
2524 a_state
->access_mask
= r
->in
.access_mask
;
2525 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2526 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2527 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2528 a_state
->account_name
= talloc_strdup(a_state
, alias_name
);
2529 if (!a_state
->account_name
) {
2530 return NT_STATUS_NO_MEMORY
;
2533 /* create the policy handle */
2534 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_ALIAS
);
2536 return NT_STATUS_NO_MEMORY
;
2539 g_handle
->data
= talloc_steal(g_handle
, a_state
);
2541 *r
->out
.alias_handle
= g_handle
->wire_handle
;
2543 return NT_STATUS_OK
;
2550 static NTSTATUS
dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2551 struct samr_QueryAliasInfo
*r
)
2553 struct dcesrv_handle
*h
;
2554 struct samr_account_state
*a_state
;
2555 struct ldb_message
*msg
, **res
;
2556 const char * const attrs
[4] = { "sAMAccountName", "description",
2557 "numMembers", NULL
};
2559 union samr_AliasInfo
*info
;
2561 *r
->out
.info
= NULL
;
2563 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2567 /* pull all the alias attributes */
2568 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2569 a_state
->account_dn
,&res
, attrs
);
2571 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2575 /* allocate the info structure */
2576 info
= talloc_zero(mem_ctx
, union samr_AliasInfo
);
2578 return NT_STATUS_NO_MEMORY
;
2581 switch(r
->in
.level
) {
2583 QUERY_STRING(msg
, all
.name
, "sAMAccountName");
2584 QUERY_UINT (msg
, all
.num_members
, "numMembers");
2585 QUERY_STRING(msg
, all
.description
, "description");
2588 QUERY_STRING(msg
, name
, "sAMAccountName");
2590 case ALIASINFODESCRIPTION
:
2591 QUERY_STRING(msg
, description
, "description");
2595 return NT_STATUS_INVALID_INFO_CLASS
;
2598 *r
->out
.info
= info
;
2600 return NT_STATUS_OK
;
2607 static NTSTATUS
dcesrv_samr_SetAliasInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2608 struct samr_SetAliasInfo
*r
)
2610 struct dcesrv_handle
*h
;
2611 struct samr_account_state
*a_state
;
2612 struct ldb_message
*msg
;
2613 struct ldb_context
*sam_ctx
;
2616 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2619 sam_ctx
= a_state
->sam_ctx
;
2621 msg
= ldb_msg_new(mem_ctx
);
2623 return NT_STATUS_NO_MEMORY
;
2626 msg
->dn
= ldb_dn_copy(mem_ctx
, a_state
->account_dn
);
2628 return NT_STATUS_NO_MEMORY
;
2631 switch (r
->in
.level
) {
2632 case ALIASINFODESCRIPTION
:
2633 SET_STRING(msg
, description
, "description");
2636 /* On W2k3 this does not change the name, it changes the
2637 * sAMAccountName attribute */
2638 SET_STRING(msg
, name
, "sAMAccountName");
2641 return NT_STATUS_INVALID_INFO_CLASS
;
2644 /* modify the samdb record */
2645 ret
= ldb_modify(a_state
->sam_ctx
, msg
);
2647 /* we really need samdb.c to return NTSTATUS */
2648 return NT_STATUS_UNSUCCESSFUL
;
2651 return NT_STATUS_OK
;
2658 static NTSTATUS
dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2659 struct samr_DeleteDomAlias
*r
)
2661 struct dcesrv_handle
*h
;
2662 struct samr_account_state
*a_state
;
2665 *r
->out
.alias_handle
= *r
->in
.alias_handle
;
2667 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2671 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2673 return NT_STATUS_UNSUCCESSFUL
;
2676 ZERO_STRUCTP(r
->out
.alias_handle
);
2678 return NT_STATUS_OK
;
2685 static NTSTATUS
dcesrv_samr_AddAliasMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2686 struct samr_AddAliasMember
*r
)
2688 struct dcesrv_handle
*h
;
2689 struct samr_account_state
*a_state
;
2690 struct samr_domain_state
*d_state
;
2691 struct ldb_message
*mod
;
2692 struct ldb_message
**msgs
;
2693 const char * const attrs
[] = { NULL
};
2694 struct ldb_dn
*memberdn
= NULL
;
2698 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2701 d_state
= a_state
->domain_state
;
2703 ret
= gendb_search(d_state
->sam_ctx
, mem_ctx
, NULL
,
2704 &msgs
, attrs
, "(objectsid=%s)",
2705 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
2708 memberdn
= msgs
[0]->dn
;
2709 } else if (ret
> 1) {
2710 DEBUG(0,("Found %d records matching sid %s\n",
2711 ret
, dom_sid_string(mem_ctx
, r
->in
.sid
)));
2712 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2713 } else if (ret
== 0) {
2714 status
= samdb_create_foreign_security_principal(
2715 d_state
->sam_ctx
, mem_ctx
, r
->in
.sid
, &memberdn
);
2716 if (!NT_STATUS_IS_OK(status
)) {
2720 DEBUG(0, ("samdb_search returned %d: %s\n", ret
, ldb_errstring(d_state
->sam_ctx
)));
2723 if (memberdn
== NULL
) {
2724 DEBUG(0, ("Could not find memberdn\n"));
2725 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2728 mod
= ldb_msg_new(mem_ctx
);
2730 return NT_STATUS_NO_MEMORY
;
2733 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2735 if (samdb_msg_add_addval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2736 ldb_dn_alloc_linearized(mem_ctx
, memberdn
)) != 0)
2737 return NT_STATUS_UNSUCCESSFUL
;
2739 if (ldb_modify(a_state
->sam_ctx
, mod
) != 0)
2740 return NT_STATUS_UNSUCCESSFUL
;
2742 return NT_STATUS_OK
;
2747 samr_DeleteAliasMember
2749 static NTSTATUS
dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2750 struct samr_DeleteAliasMember
*r
)
2752 struct dcesrv_handle
*h
;
2753 struct samr_account_state
*a_state
;
2754 struct samr_domain_state
*d_state
;
2755 struct ldb_message
*mod
;
2756 const char *memberdn
;
2758 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2761 d_state
= a_state
->domain_state
;
2763 memberdn
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
2764 "distinguishedName", "(objectSid=%s)",
2765 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
2767 if (memberdn
== NULL
)
2768 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2770 mod
= ldb_msg_new(mem_ctx
);
2772 return NT_STATUS_NO_MEMORY
;
2775 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2777 if (samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2779 return NT_STATUS_UNSUCCESSFUL
;
2781 if (ldb_modify(a_state
->sam_ctx
, mod
) != 0)
2782 return NT_STATUS_UNSUCCESSFUL
;
2784 return NT_STATUS_OK
;
2789 samr_GetMembersInAlias
2791 static NTSTATUS
dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2792 struct samr_GetMembersInAlias
*r
)
2794 struct dcesrv_handle
*h
;
2795 struct samr_account_state
*a_state
;
2796 struct samr_domain_state
*d_state
;
2797 struct ldb_message
**msgs
;
2798 struct lsa_SidPtr
*sids
;
2799 struct ldb_message_element
*el
;
2800 const char * const attrs
[2] = { "member", NULL
};
2803 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2806 d_state
= a_state
->domain_state
;
2808 ret
= gendb_search_dn(d_state
->sam_ctx
, mem_ctx
,
2809 a_state
->account_dn
, &msgs
, attrs
);
2812 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2813 } else if (ret
== 0) {
2814 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2815 } else if (ret
!= 1) {
2816 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2819 r
->out
.sids
->num_sids
= 0;
2820 r
->out
.sids
->sids
= NULL
;
2822 el
= ldb_msg_find_element(msgs
[0], "member");
2827 sids
= talloc_array(mem_ctx
, struct lsa_SidPtr
,
2831 return NT_STATUS_NO_MEMORY
;
2833 for (i
=0; i
<el
->num_values
; i
++) {
2834 struct ldb_message
**msgs2
;
2835 const char * const attrs2
[2] = { "objectSid", NULL
};
2836 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2837 ldb_dn_from_ldb_val(mem_ctx
, a_state
->sam_ctx
, &el
->values
[i
]),
2840 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2842 sids
[i
].sid
= samdb_result_dom_sid(mem_ctx
, msgs2
[0],
2845 if (sids
[i
].sid
== NULL
)
2846 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2848 r
->out
.sids
->num_sids
= el
->num_values
;
2849 r
->out
.sids
->sids
= sids
;
2852 return NT_STATUS_OK
;
2858 static NTSTATUS
dcesrv_samr_OpenUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2859 struct samr_OpenUser
*r
)
2861 struct samr_domain_state
*d_state
;
2862 struct samr_account_state
*a_state
;
2863 struct dcesrv_handle
*h
;
2864 const char *account_name
;
2865 struct dom_sid
*sid
;
2866 struct ldb_message
**msgs
;
2867 struct dcesrv_handle
*u_handle
;
2868 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2871 ZERO_STRUCTP(r
->out
.user_handle
);
2873 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2877 /* form the users SID */
2878 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2880 return NT_STATUS_NO_MEMORY
;
2883 /* search for the user record */
2884 ret
= gendb_search(d_state
->sam_ctx
,
2885 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2886 "(&(objectSid=%s)(objectclass=user))",
2887 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
2889 return NT_STATUS_NO_SUCH_USER
;
2892 DEBUG(0,("Found %d records matching sid %s\n", ret
,
2893 dom_sid_string(mem_ctx
, sid
)));
2894 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2897 account_name
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2898 if (account_name
== NULL
) {
2899 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2900 dom_sid_string(mem_ctx
, sid
)));
2901 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2904 a_state
= talloc(mem_ctx
, struct samr_account_state
);
2906 return NT_STATUS_NO_MEMORY
;
2908 a_state
->sam_ctx
= d_state
->sam_ctx
;
2909 a_state
->access_mask
= r
->in
.access_mask
;
2910 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2911 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2912 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2913 a_state
->account_name
= talloc_strdup(a_state
, account_name
);
2914 if (!a_state
->account_name
) {
2915 return NT_STATUS_NO_MEMORY
;
2918 /* create the policy handle */
2919 u_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_USER
);
2921 return NT_STATUS_NO_MEMORY
;
2924 u_handle
->data
= talloc_steal(u_handle
, a_state
);
2926 *r
->out
.user_handle
= u_handle
->wire_handle
;
2928 return NT_STATUS_OK
;
2936 static NTSTATUS
dcesrv_samr_DeleteUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2937 struct samr_DeleteUser
*r
)
2939 struct dcesrv_handle
*h
;
2940 struct samr_account_state
*a_state
;
2943 *r
->out
.user_handle
= *r
->in
.user_handle
;
2945 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
2949 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2951 DEBUG(1, ("Failed to delete user: %s: %s\n",
2952 ldb_dn_get_linearized(a_state
->account_dn
),
2953 ldb_errstring(a_state
->sam_ctx
)));
2954 return NT_STATUS_UNSUCCESSFUL
;
2957 ZERO_STRUCTP(r
->out
.user_handle
);
2959 return NT_STATUS_OK
;
2966 static NTSTATUS
dcesrv_samr_QueryUserInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2967 struct samr_QueryUserInfo
*r
)
2969 struct dcesrv_handle
*h
;
2970 struct samr_account_state
*a_state
;
2971 struct ldb_message
*msg
, **res
;
2973 struct ldb_context
*sam_ctx
;
2975 const char * const *attrs
= NULL
;
2976 union samr_UserInfo
*info
;
2978 *r
->out
.info
= NULL
;
2980 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
2983 sam_ctx
= a_state
->sam_ctx
;
2985 /* fill in the reply */
2986 switch (r
->in
.level
) {
2989 static const char * const attrs2
[] = {"sAMAccountName",
3000 static const char * const attrs2
[] = {"comment",
3009 static const char * const attrs2
[] = {"sAMAccountName",
3024 "userAccountControl",
3031 static const char * const attrs2
[] = {"logonHours",
3038 static const char * const attrs2
[] = {"sAMAccountName",
3055 "userAccountControl",
3062 static const char * const attrs2
[] = {"sAMAccountName",
3070 static const char * const attrs2
[] = {"sAMAccountName",
3077 static const char * const attrs2
[] = {"displayName",
3084 static const char * const attrs2
[] = {"primaryGroupID",
3091 static const char * const attrs2
[] = {"homeDirectory",
3099 static const char * const attrs2
[] = {"scriptPath",
3106 static const char * const attrs2
[] = {"profilePath",
3113 static const char * const attrs2
[] = {"description",
3120 static const char * const attrs2
[] = {"userWorkstations",
3127 static const char * const attrs2
[] = {"userAccountControl",
3135 static const char * const attrs2
[] = {"accountExpires",
3142 static const char * const attrs2
[] = {"userParameters",
3149 static const char * const attrs2
[] = {"lastLogon",
3165 "userAccountControl",
3177 /* pull all the user attributes */
3178 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
3179 a_state
->account_dn
,&res
, attrs
);
3181 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3185 /* allocate the info structure */
3186 info
= talloc_zero(mem_ctx
, union samr_UserInfo
);
3188 return NT_STATUS_NO_MEMORY
;
3191 /* fill in the reply */
3192 switch (r
->in
.level
) {
3194 QUERY_STRING(msg
, info1
.account_name
, "sAMAccountName");
3195 QUERY_STRING(msg
, info1
.full_name
, "displayName");
3196 QUERY_UINT (msg
, info1
.primary_gid
, "primaryGroupID");
3197 QUERY_STRING(msg
, info1
.description
, "description");
3198 QUERY_STRING(msg
, info1
.comment
, "comment");
3202 QUERY_STRING(msg
, info2
.comment
, "comment");
3203 QUERY_UINT (msg
, info2
.country_code
, "countryCode");
3204 QUERY_UINT (msg
, info2
.code_page
, "codePage");
3208 QUERY_STRING(msg
, info3
.account_name
, "sAMAccountName");
3209 QUERY_STRING(msg
, info3
.full_name
, "displayName");
3210 QUERY_RID (msg
, info3
.rid
, "objectSid");
3211 QUERY_UINT (msg
, info3
.primary_gid
, "primaryGroupID");
3212 QUERY_STRING(msg
, info3
.home_directory
, "homeDirectory");
3213 QUERY_STRING(msg
, info3
.home_drive
, "homeDrive");
3214 QUERY_STRING(msg
, info3
.logon_script
, "scriptPath");
3215 QUERY_STRING(msg
, info3
.profile_path
, "profilePath");
3216 QUERY_STRING(msg
, info3
.workstations
, "userWorkstations");
3217 QUERY_UINT64(msg
, info3
.last_logon
, "lastLogon");
3218 QUERY_UINT64(msg
, info3
.last_logoff
, "lastLogoff");
3219 QUERY_UINT64(msg
, info3
.last_password_change
, "pwdLastSet");
3220 QUERY_APASSC(msg
, info3
.allow_password_change
, "pwdLastSet");
3221 QUERY_FPASSC(msg
, info3
.force_password_change
, "pwdLastSet");
3222 QUERY_LHOURS(msg
, info3
.logon_hours
, "logonHours");
3223 QUERY_UINT (msg
, info3
.bad_password_count
, "badPwdCount");
3224 QUERY_UINT (msg
, info3
.logon_count
, "logonCount");
3225 QUERY_AFLAGS(msg
, info3
.acct_flags
, "userAccountControl");
3229 QUERY_LHOURS(msg
, info4
.logon_hours
, "logonHours");
3233 QUERY_STRING(msg
, info5
.account_name
, "sAMAccountName");
3234 QUERY_STRING(msg
, info5
.full_name
, "displayName");
3235 QUERY_RID (msg
, info5
.rid
, "objectSid");
3236 QUERY_UINT (msg
, info5
.primary_gid
, "primaryGroupID");
3237 QUERY_STRING(msg
, info5
.home_directory
, "homeDirectory");
3238 QUERY_STRING(msg
, info5
.home_drive
, "homeDrive");
3239 QUERY_STRING(msg
, info5
.logon_script
, "scriptPath");
3240 QUERY_STRING(msg
, info5
.profile_path
, "profilePath");
3241 QUERY_STRING(msg
, info5
.description
, "description");
3242 QUERY_STRING(msg
, info5
.workstations
, "userWorkstations");
3243 QUERY_UINT64(msg
, info5
.last_logon
, "lastLogon");
3244 QUERY_UINT64(msg
, info5
.last_logoff
, "lastLogoff");
3245 QUERY_LHOURS(msg
, info5
.logon_hours
, "logonHours");
3246 QUERY_UINT (msg
, info5
.bad_password_count
, "badPwdCount");
3247 QUERY_UINT (msg
, info5
.logon_count
, "logonCount");
3248 QUERY_UINT64(msg
, info5
.last_password_change
, "pwdLastSet");
3249 QUERY_UINT64(msg
, info5
.acct_expiry
, "accountExpires");
3250 QUERY_AFLAGS(msg
, info5
.acct_flags
, "userAccountControl");
3254 QUERY_STRING(msg
, info6
.account_name
, "sAMAccountName");
3255 QUERY_STRING(msg
, info6
.full_name
, "displayName");
3259 QUERY_STRING(msg
, info7
.account_name
, "sAMAccountName");
3263 QUERY_STRING(msg
, info8
.full_name
, "displayName");
3267 QUERY_UINT (msg
, info9
.primary_gid
, "primaryGroupID");
3271 QUERY_STRING(msg
, info10
.home_directory
,"homeDirectory");
3272 QUERY_STRING(msg
, info10
.home_drive
, "homeDrive");
3276 QUERY_STRING(msg
, info11
.logon_script
, "scriptPath");
3280 QUERY_STRING(msg
, info12
.profile_path
, "profilePath");
3284 QUERY_STRING(msg
, info13
.description
, "description");
3288 QUERY_STRING(msg
, info14
.workstations
, "userWorkstations");
3292 QUERY_AFLAGS(msg
, info16
.acct_flags
, "userAccountControl");
3296 QUERY_UINT64(msg
, info17
.acct_expiry
, "accountExpires");
3300 QUERY_PARAMETERS(msg
, info20
.parameters
, "userParameters");
3304 QUERY_UINT64(msg
, info21
.last_logon
, "lastLogon");
3305 QUERY_UINT64(msg
, info21
.last_logoff
, "lastLogoff");
3306 QUERY_UINT64(msg
, info21
.last_password_change
, "pwdLastSet");
3307 QUERY_UINT64(msg
, info21
.acct_expiry
, "accountExpires");
3308 QUERY_APASSC(msg
, info21
.allow_password_change
,"pwdLastSet");
3309 QUERY_FPASSC(msg
, info21
.force_password_change
,"pwdLastSet");
3310 QUERY_STRING(msg
, info21
.account_name
, "sAMAccountName");
3311 QUERY_STRING(msg
, info21
.full_name
, "displayName");
3312 QUERY_STRING(msg
, info21
.home_directory
, "homeDirectory");
3313 QUERY_STRING(msg
, info21
.home_drive
, "homeDrive");
3314 QUERY_STRING(msg
, info21
.logon_script
, "scriptPath");
3315 QUERY_STRING(msg
, info21
.profile_path
, "profilePath");
3316 QUERY_STRING(msg
, info21
.description
, "description");
3317 QUERY_STRING(msg
, info21
.workstations
, "userWorkstations");
3318 QUERY_STRING(msg
, info21
.comment
, "comment");
3319 QUERY_PARAMETERS(msg
, info21
.parameters
, "userParameters");
3320 QUERY_RID (msg
, info21
.rid
, "objectSid");
3321 QUERY_UINT (msg
, info21
.primary_gid
, "primaryGroupID");
3322 QUERY_AFLAGS(msg
, info21
.acct_flags
, "userAccountControl");
3323 info
->info21
.fields_present
= 0x00FFFFFF;
3324 QUERY_LHOURS(msg
, info21
.logon_hours
, "logonHours");
3325 QUERY_UINT (msg
, info21
.bad_password_count
, "badPwdCount");
3326 QUERY_UINT (msg
, info21
.logon_count
, "logonCount");
3327 QUERY_UINT (msg
, info21
.country_code
, "countryCode");
3328 QUERY_UINT (msg
, info21
.code_page
, "codePage");
3334 return NT_STATUS_INVALID_INFO_CLASS
;
3337 *r
->out
.info
= info
;
3339 return NT_STATUS_OK
;
3346 static NTSTATUS
dcesrv_samr_SetUserInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3347 struct samr_SetUserInfo
*r
)
3349 struct dcesrv_handle
*h
;
3350 struct samr_account_state
*a_state
;
3351 struct ldb_message
*msg
;
3353 NTSTATUS status
= NT_STATUS_OK
;
3354 struct ldb_context
*sam_ctx
;
3356 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3359 sam_ctx
= a_state
->sam_ctx
;
3361 msg
= ldb_msg_new(mem_ctx
);
3363 return NT_STATUS_NO_MEMORY
;
3366 msg
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
3368 return NT_STATUS_NO_MEMORY
;
3371 switch (r
->in
.level
) {
3373 SET_STRING(msg
, info2
.comment
, "comment");
3374 SET_UINT (msg
, info2
.country_code
, "countryCode");
3375 SET_UINT (msg
, info2
.code_page
, "codePage");
3379 SET_LHOURS(msg
, info4
.logon_hours
, "logonHours");
3383 SET_STRING(msg
, info6
.account_name
, "samAccountName");
3384 SET_STRING(msg
, info6
.full_name
, "displayName");
3388 SET_STRING(msg
, info7
.account_name
, "samAccountName");
3392 SET_STRING(msg
, info8
.full_name
, "displayName");
3396 SET_UINT(msg
, info9
.primary_gid
, "primaryGroupID");
3400 SET_STRING(msg
, info10
.home_directory
, "homeDirectory");
3401 SET_STRING(msg
, info10
.home_drive
, "homeDrive");
3405 SET_STRING(msg
, info11
.logon_script
, "scriptPath");
3409 SET_STRING(msg
, info12
.profile_path
, "profilePath");
3413 SET_STRING(msg
, info13
.description
, "description");
3417 SET_STRING(msg
, info14
.workstations
, "userWorkstations");
3421 SET_AFLAGS(msg
, info16
.acct_flags
, "userAccountControl");
3425 SET_UINT64(msg
, info17
.acct_expiry
, "accountExpires");
3429 SET_PARAMETERS(msg
, info20
.parameters
, "userParameters");
3433 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3434 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3435 SET_UINT64(msg
, info21
.acct_expiry
, "accountExpires");
3436 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3437 SET_STRING(msg
, info21
.account_name
, "samAccountName");
3438 IFSET(SAMR_FIELD_FULL_NAME
)
3439 SET_STRING(msg
, info21
.full_name
, "displayName");
3440 IFSET(SAMR_FIELD_HOME_DIRECTORY
)
3441 SET_STRING(msg
, info21
.home_directory
, "homeDirectory");
3442 IFSET(SAMR_FIELD_HOME_DRIVE
)
3443 SET_STRING(msg
, info21
.home_drive
, "homeDrive");
3444 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3445 SET_STRING(msg
, info21
.logon_script
, "scriptPath");
3446 IFSET(SAMR_FIELD_PROFILE_PATH
)
3447 SET_STRING(msg
, info21
.profile_path
, "profilePath");
3448 IFSET(SAMR_FIELD_DESCRIPTION
)
3449 SET_STRING(msg
, info21
.description
, "description");
3450 IFSET(SAMR_FIELD_WORKSTATIONS
)
3451 SET_STRING(msg
, info21
.workstations
, "userWorkstations");
3452 IFSET(SAMR_FIELD_COMMENT
)
3453 SET_STRING(msg
, info21
.comment
, "comment");
3454 IFSET(SAMR_FIELD_PARAMETERS
)
3455 SET_PARAMETERS(msg
, info21
.parameters
, "userParameters");
3456 IFSET(SAMR_FIELD_PRIMARY_GID
)
3457 SET_UINT(msg
, info21
.primary_gid
, "primaryGroupID");
3458 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3459 SET_AFLAGS(msg
, info21
.acct_flags
, "userAccountControl");
3460 IFSET(SAMR_FIELD_LOGON_HOURS
)
3461 SET_LHOURS(msg
, info21
.logon_hours
, "logonHours");
3462 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3463 SET_UINT (msg
, info21
.country_code
, "countryCode");
3464 IFSET(SAMR_FIELD_CODE_PAGE
)
3465 SET_UINT (msg
, info21
.code_page
, "codePage");
3470 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3471 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3472 SET_UINT64(msg
, info23
.info
.acct_expiry
, "accountExpires");
3473 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3474 SET_STRING(msg
, info23
.info
.account_name
, "samAccountName");
3475 IFSET(SAMR_FIELD_FULL_NAME
)
3476 SET_STRING(msg
, info23
.info
.full_name
, "displayName");
3477 IFSET(SAMR_FIELD_HOME_DIRECTORY
)
3478 SET_STRING(msg
, info23
.info
.home_directory
, "homeDirectory");
3479 IFSET(SAMR_FIELD_HOME_DRIVE
)
3480 SET_STRING(msg
, info23
.info
.home_drive
, "homeDrive");
3481 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3482 SET_STRING(msg
, info23
.info
.logon_script
, "scriptPath");
3483 IFSET(SAMR_FIELD_PROFILE_PATH
)
3484 SET_STRING(msg
, info23
.info
.profile_path
, "profilePath");
3485 IFSET(SAMR_FIELD_DESCRIPTION
)
3486 SET_STRING(msg
, info23
.info
.description
, "description");
3487 IFSET(SAMR_FIELD_WORKSTATIONS
)
3488 SET_STRING(msg
, info23
.info
.workstations
, "userWorkstations");
3489 IFSET(SAMR_FIELD_COMMENT
)
3490 SET_STRING(msg
, info23
.info
.comment
, "comment");
3491 IFSET(SAMR_FIELD_PARAMETERS
)
3492 SET_PARAMETERS(msg
, info23
.info
.parameters
, "userParameters");
3493 IFSET(SAMR_FIELD_PRIMARY_GID
)
3494 SET_UINT(msg
, info23
.info
.primary_gid
, "primaryGroupID");
3495 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3496 SET_AFLAGS(msg
, info23
.info
.acct_flags
, "userAccountControl");
3497 IFSET(SAMR_FIELD_LOGON_HOURS
)
3498 SET_LHOURS(msg
, info23
.info
.logon_hours
, "logonHours");
3499 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3500 SET_UINT (msg
, info23
.info
.country_code
, "countryCode");
3501 IFSET(SAMR_FIELD_CODE_PAGE
)
3502 SET_UINT (msg
, info23
.info
.code_page
, "codePage");
3504 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT
) {
3505 status
= samr_set_password(dce_call
,
3507 a_state
->account_dn
,
3508 a_state
->domain_state
->domain_dn
,
3510 &r
->in
.info
->info23
.password
);
3511 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT
) {
3512 status
= samr_set_password(dce_call
,
3514 a_state
->account_dn
,
3515 a_state
->domain_state
->domain_dn
,
3517 &r
->in
.info
->info23
.password
);
3522 /* the set password levels are handled separately */
3524 status
= samr_set_password(dce_call
,
3526 a_state
->account_dn
,
3527 a_state
->domain_state
->domain_dn
,
3529 &r
->in
.info
->info24
.password
);
3533 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3534 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3535 SET_UINT64(msg
, info25
.info
.acct_expiry
, "accountExpires");
3536 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3537 SET_STRING(msg
, info25
.info
.account_name
, "samAccountName");
3538 IFSET(SAMR_FIELD_FULL_NAME
)
3539 SET_STRING(msg
, info25
.info
.full_name
, "displayName");
3540 IFSET(SAMR_FIELD_HOME_DIRECTORY
)
3541 SET_STRING(msg
, info25
.info
.home_directory
, "homeDirectory");
3542 IFSET(SAMR_FIELD_HOME_DRIVE
)
3543 SET_STRING(msg
, info25
.info
.home_drive
, "homeDrive");
3544 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3545 SET_STRING(msg
, info25
.info
.logon_script
, "scriptPath");
3546 IFSET(SAMR_FIELD_PROFILE_PATH
)
3547 SET_STRING(msg
, info25
.info
.profile_path
, "profilePath");
3548 IFSET(SAMR_FIELD_DESCRIPTION
)
3549 SET_STRING(msg
, info25
.info
.description
, "description");
3550 IFSET(SAMR_FIELD_WORKSTATIONS
)
3551 SET_STRING(msg
, info25
.info
.workstations
, "userWorkstations");
3552 IFSET(SAMR_FIELD_COMMENT
)
3553 SET_STRING(msg
, info25
.info
.comment
, "comment");
3554 IFSET(SAMR_FIELD_PARAMETERS
)
3555 SET_PARAMETERS(msg
, info25
.info
.parameters
, "userParameters");
3556 IFSET(SAMR_FIELD_PRIMARY_GID
)
3557 SET_UINT(msg
, info25
.info
.primary_gid
, "primaryGroupID");
3558 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3559 SET_AFLAGS(msg
, info25
.info
.acct_flags
, "userAccountControl");
3560 IFSET(SAMR_FIELD_LOGON_HOURS
)
3561 SET_LHOURS(msg
, info25
.info
.logon_hours
, "logonHours");
3562 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3563 SET_UINT (msg
, info25
.info
.country_code
, "countryCode");
3564 IFSET(SAMR_FIELD_CODE_PAGE
)
3565 SET_UINT (msg
, info25
.info
.code_page
, "codePage");
3567 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT
) {
3568 status
= samr_set_password_ex(dce_call
,
3570 a_state
->account_dn
,
3571 a_state
->domain_state
->domain_dn
,
3573 &r
->in
.info
->info25
.password
);
3574 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT
) {
3575 status
= samr_set_password_ex(dce_call
,
3577 a_state
->account_dn
,
3578 a_state
->domain_state
->domain_dn
,
3580 &r
->in
.info
->info25
.password
);
3585 /* the set password levels are handled separately */
3587 status
= samr_set_password_ex(dce_call
,
3589 a_state
->account_dn
,
3590 a_state
->domain_state
->domain_dn
,
3592 &r
->in
.info
->info26
.password
);
3597 /* many info classes are not valid for SetUserInfo */
3598 return NT_STATUS_INVALID_INFO_CLASS
;
3601 if (!NT_STATUS_IS_OK(status
)) {
3605 /* modify the samdb record */
3606 ret
= ldb_modify(a_state
->sam_ctx
, msg
);
3608 DEBUG(1,("Failed to modify record %s: %s\n",
3609 ldb_dn_get_linearized(a_state
->account_dn
),
3610 ldb_errstring(a_state
->sam_ctx
)));
3612 /* we really need samdb.c to return NTSTATUS */
3613 return NT_STATUS_UNSUCCESSFUL
;
3616 return NT_STATUS_OK
;
3621 samr_GetGroupsForUser
3623 static NTSTATUS
dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3624 struct samr_GetGroupsForUser
*r
)
3626 struct dcesrv_handle
*h
;
3627 struct samr_account_state
*a_state
;
3628 struct samr_domain_state
*d_state
;
3629 struct ldb_message
**res
;
3630 const char * const attrs
[2] = { "objectSid", NULL
};
3631 struct samr_RidWithAttributeArray
*array
;
3634 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3637 d_state
= a_state
->domain_state
;
3639 count
= samdb_search_domain(a_state
->sam_ctx
, mem_ctx
,
3640 d_state
->domain_dn
, &res
,
3641 attrs
, d_state
->domain_sid
,
3642 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3643 ldb_dn_get_linearized(a_state
->account_dn
),
3644 GTYPE_SECURITY_GLOBAL_GROUP
);
3646 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3648 array
= talloc(mem_ctx
, struct samr_RidWithAttributeArray
);
3650 return NT_STATUS_NO_MEMORY
;
3655 array
->rids
= talloc_array(mem_ctx
, struct samr_RidWithAttribute
,
3657 if (array
->rids
== NULL
)
3658 return NT_STATUS_NO_MEMORY
;
3660 /* Adds the primary group */
3661 array
->rids
[0].rid
= samdb_search_uint(a_state
->sam_ctx
, mem_ctx
,
3662 ~0, a_state
->account_dn
,
3663 "primaryGroupID", NULL
);
3664 array
->rids
[0].attributes
= SE_GROUP_MANDATORY
3665 | SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3668 /* Adds the additional groups */
3669 for (i
= 0; i
< count
; i
++) {
3670 struct dom_sid
*group_sid
;
3672 group_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
], "objectSid");
3673 if (group_sid
== NULL
) {
3674 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3678 array
->rids
[i
+ 1].rid
=
3679 group_sid
->sub_auths
[group_sid
->num_auths
-1];
3680 array
->rids
[i
+ 1].attributes
= SE_GROUP_MANDATORY
3681 | SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3685 *r
->out
.rids
= array
;
3687 return NT_STATUS_OK
;
3692 samr_QueryDisplayInfo
3694 static NTSTATUS
dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3695 struct samr_QueryDisplayInfo
*r
)
3697 struct dcesrv_handle
*h
;
3698 struct samr_domain_state
*d_state
;
3699 struct ldb_message
**res
;
3700 int ldb_cnt
, count
, i
;
3701 const char * const attrs
[] = { "objectSid", "sAMAccountName",
3702 "displayName", "description", "userAccountControl",
3703 "pwdLastSet", NULL
};
3704 struct samr_DispEntryFull
*entriesFull
= NULL
;
3705 struct samr_DispEntryFullGroup
*entriesFullGroup
= NULL
;
3706 struct samr_DispEntryAscii
*entriesAscii
= NULL
;
3707 struct samr_DispEntryGeneral
*entriesGeneral
= NULL
;
3710 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
3714 switch (r
->in
.level
) {
3717 filter
= talloc_asprintf(mem_ctx
, "(&(objectclass=user)"
3718 "(sAMAccountType=%u))",
3719 ATYPE_NORMAL_ACCOUNT
);
3722 filter
= talloc_asprintf(mem_ctx
, "(&(objectclass=user)"
3723 "(sAMAccountType=%u))",
3724 ATYPE_WORKSTATION_TRUST
);
3728 filter
= talloc_asprintf(mem_ctx
, "(&(grouptype=%d)"
3729 "(objectclass=group))",
3730 GTYPE_SECURITY_GLOBAL_GROUP
);
3733 return NT_STATUS_INVALID_INFO_CLASS
;
3736 /* search for all requested objects in this domain. This could
3737 possibly be cached and resumed based on resume_key */
3738 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
3739 d_state
->domain_dn
, &res
, attrs
,
3740 d_state
->domain_sid
, "%s", filter
);
3741 if (ldb_cnt
== -1) {
3742 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3744 if (ldb_cnt
== 0 || r
->in
.max_entries
== 0) {
3745 return NT_STATUS_OK
;
3748 switch (r
->in
.level
) {
3750 entriesGeneral
= talloc_array(mem_ctx
,
3751 struct samr_DispEntryGeneral
,
3755 entriesFull
= talloc_array(mem_ctx
,
3756 struct samr_DispEntryFull
,
3760 entriesFullGroup
= talloc_array(mem_ctx
,
3761 struct samr_DispEntryFullGroup
,
3766 entriesAscii
= talloc_array(mem_ctx
,
3767 struct samr_DispEntryAscii
,
3772 if ((entriesGeneral
== NULL
) && (entriesFull
== NULL
) &&
3773 (entriesAscii
== NULL
) && (entriesFullGroup
== NULL
))
3774 return NT_STATUS_NO_MEMORY
;
3778 for (i
=0; i
<ldb_cnt
; i
++) {
3779 struct dom_sid
*objectsid
;
3781 objectsid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
3783 if (objectsid
== NULL
)
3786 switch(r
->in
.level
) {
3788 entriesGeneral
[count
].idx
= count
+ 1;
3789 entriesGeneral
[count
].rid
=
3790 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3791 entriesGeneral
[count
].acct_flags
=
3792 samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
,
3794 d_state
->domain_dn
);
3795 entriesGeneral
[count
].account_name
.string
=
3796 samdb_result_string(res
[i
],
3797 "sAMAccountName", "");
3798 entriesGeneral
[count
].full_name
.string
=
3799 samdb_result_string(res
[i
], "displayName", "");
3800 entriesGeneral
[count
].description
.string
=
3801 samdb_result_string(res
[i
], "description", "");
3804 entriesFull
[count
].idx
= count
+ 1;
3805 entriesFull
[count
].rid
=
3806 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3808 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3809 entriesFull
[count
].acct_flags
=
3810 samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
,
3812 d_state
->domain_dn
) | ACB_NORMAL
;
3813 entriesFull
[count
].account_name
.string
=
3814 samdb_result_string(res
[i
], "sAMAccountName",
3816 entriesFull
[count
].description
.string
=
3817 samdb_result_string(res
[i
], "description", "");
3820 entriesFullGroup
[count
].idx
= count
+ 1;
3821 entriesFullGroup
[count
].rid
=
3822 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3823 /* We get a "7" here for groups */
3824 entriesFullGroup
[count
].acct_flags
3825 = SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3826 entriesFullGroup
[count
].account_name
.string
=
3827 samdb_result_string(res
[i
], "sAMAccountName",
3829 entriesFullGroup
[count
].description
.string
=
3830 samdb_result_string(res
[i
], "description", "");
3834 entriesAscii
[count
].idx
= count
+ 1;
3835 entriesAscii
[count
].account_name
.string
=
3836 samdb_result_string(res
[i
], "sAMAccountName",
3844 *r
->out
.total_size
= count
;
3846 if (r
->in
.start_idx
>= count
) {
3847 *r
->out
.returned_size
= 0;
3848 switch(r
->in
.level
) {
3850 r
->out
.info
->info1
.count
= *r
->out
.returned_size
;
3851 r
->out
.info
->info1
.entries
= NULL
;
3854 r
->out
.info
->info2
.count
= *r
->out
.returned_size
;
3855 r
->out
.info
->info2
.entries
= NULL
;
3858 r
->out
.info
->info3
.count
= *r
->out
.returned_size
;
3859 r
->out
.info
->info3
.entries
= NULL
;
3862 r
->out
.info
->info4
.count
= *r
->out
.returned_size
;
3863 r
->out
.info
->info4
.entries
= NULL
;
3866 r
->out
.info
->info5
.count
= *r
->out
.returned_size
;
3867 r
->out
.info
->info5
.entries
= NULL
;
3871 *r
->out
.returned_size
= MIN(count
- r
->in
.start_idx
,
3873 switch(r
->in
.level
) {
3875 r
->out
.info
->info1
.count
= *r
->out
.returned_size
;
3876 r
->out
.info
->info1
.entries
=
3877 &(entriesGeneral
[r
->in
.start_idx
]);
3880 r
->out
.info
->info2
.count
= *r
->out
.returned_size
;
3881 r
->out
.info
->info2
.entries
=
3882 &(entriesFull
[r
->in
.start_idx
]);
3885 r
->out
.info
->info3
.count
= *r
->out
.returned_size
;
3886 r
->out
.info
->info3
.entries
=
3887 &(entriesFullGroup
[r
->in
.start_idx
]);
3890 r
->out
.info
->info4
.count
= *r
->out
.returned_size
;
3891 r
->out
.info
->info4
.entries
=
3892 &(entriesAscii
[r
->in
.start_idx
]);
3895 r
->out
.info
->info5
.count
= *r
->out
.returned_size
;
3896 r
->out
.info
->info5
.entries
=
3897 &(entriesAscii
[r
->in
.start_idx
]);
3902 return (*r
->out
.returned_size
< (count
- r
->in
.start_idx
)) ?
3903 STATUS_MORE_ENTRIES
: NT_STATUS_OK
;
3908 samr_GetDisplayEnumerationIndex
3910 static NTSTATUS
dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3911 struct samr_GetDisplayEnumerationIndex
*r
)
3913 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
3918 samr_TestPrivateFunctionsDomain
3920 static NTSTATUS
dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3921 struct samr_TestPrivateFunctionsDomain
*r
)
3923 return NT_STATUS_NOT_IMPLEMENTED
;
3928 samr_TestPrivateFunctionsUser
3930 static NTSTATUS
dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3931 struct samr_TestPrivateFunctionsUser
*r
)
3933 return NT_STATUS_NOT_IMPLEMENTED
;
3940 static NTSTATUS
dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3941 struct samr_GetUserPwInfo
*r
)
3943 struct dcesrv_handle
*h
;
3944 struct samr_account_state
*a_state
;
3946 ZERO_STRUCTP(r
->out
.info
);
3948 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3952 r
->out
.info
->min_password_length
= samdb_search_uint(a_state
->sam_ctx
,
3953 mem_ctx
, 0, a_state
->domain_state
->domain_dn
, "minPwdLength",
3955 r
->out
.info
->password_properties
= samdb_search_uint(a_state
->sam_ctx
,
3956 mem_ctx
, 0, a_state
->account_dn
, "pwdProperties", NULL
);
3958 return NT_STATUS_OK
;
3963 samr_RemoveMemberFromForeignDomain
3965 static NTSTATUS
dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3966 struct samr_RemoveMemberFromForeignDomain
*r
)
3968 struct dcesrv_handle
*h
;
3969 struct samr_domain_state
*d_state
;
3970 const char *memberdn
;
3971 struct ldb_message
**res
;
3972 const char * const attrs
[3] = { "distinguishedName", "objectSid", NULL
};
3975 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
3979 memberdn
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
3980 "distinguishedName", "(objectSid=%s)",
3981 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
3983 if (memberdn
== NULL
) {
3984 return NT_STATUS_OK
;
3987 /* TODO: Does this call only remove alias members, or does it do this
3988 * for domain groups as well? */
3990 count
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
3991 d_state
->domain_dn
, &res
, attrs
,
3992 d_state
->domain_sid
,
3993 "(&(member=%s)(objectClass=group)"
3994 "(|(groupType=%d)(groupType=%d)))",
3996 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
3997 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
4000 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
4002 for (i
=0; i
<count
; i
++) {
4003 struct ldb_message
*mod
;
4005 mod
= ldb_msg_new(mem_ctx
);
4007 return NT_STATUS_NO_MEMORY
;
4010 mod
->dn
= samdb_result_dn(d_state
->sam_ctx
, mod
, res
[i
], "distinguishedName", NULL
);
4011 if (mod
->dn
== NULL
) {
4016 if (samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
,
4017 "member", memberdn
) != 0)
4018 return NT_STATUS_NO_MEMORY
;
4020 if (ldb_modify(d_state
->sam_ctx
, mod
) != 0)
4021 return NT_STATUS_UNSUCCESSFUL
;
4026 return NT_STATUS_OK
;
4031 samr_QueryDomainInfo2
4033 just an alias for samr_QueryDomainInfo
4035 static NTSTATUS
dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4036 struct samr_QueryDomainInfo2
*r
)
4038 struct samr_QueryDomainInfo r1
;
4041 ZERO_STRUCT(r1
.out
);
4042 r1
.in
.domain_handle
= r
->in
.domain_handle
;
4043 r1
.in
.level
= r
->in
.level
;
4044 r1
.out
.info
= r
->out
.info
;
4046 status
= dcesrv_samr_QueryDomainInfo(dce_call
, mem_ctx
, &r1
);
4055 just an alias for samr_QueryUserInfo
4057 static NTSTATUS
dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4058 struct samr_QueryUserInfo2
*r
)
4060 struct samr_QueryUserInfo r1
;
4063 r1
.in
.user_handle
= r
->in
.user_handle
;
4064 r1
.in
.level
= r
->in
.level
;
4065 r1
.out
.info
= r
->out
.info
;
4067 status
= dcesrv_samr_QueryUserInfo(dce_call
, mem_ctx
, &r1
);
4074 samr_QueryDisplayInfo2
4076 static NTSTATUS
dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4077 struct samr_QueryDisplayInfo2
*r
)
4079 struct samr_QueryDisplayInfo q
;
4082 q
.in
.domain_handle
= r
->in
.domain_handle
;
4083 q
.in
.level
= r
->in
.level
;
4084 q
.in
.start_idx
= r
->in
.start_idx
;
4085 q
.in
.max_entries
= r
->in
.max_entries
;
4086 q
.in
.buf_size
= r
->in
.buf_size
;
4087 q
.out
.total_size
= r
->out
.total_size
;
4088 q
.out
.returned_size
= r
->out
.returned_size
;
4089 q
.out
.info
= r
->out
.info
;
4091 result
= dcesrv_samr_QueryDisplayInfo(dce_call
, mem_ctx
, &q
);
4098 samr_GetDisplayEnumerationIndex2
4100 static NTSTATUS
dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4101 struct samr_GetDisplayEnumerationIndex2
*r
)
4103 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4108 samr_QueryDisplayInfo3
4110 static NTSTATUS
dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4111 struct samr_QueryDisplayInfo3
*r
)
4113 struct samr_QueryDisplayInfo q
;
4116 q
.in
.domain_handle
= r
->in
.domain_handle
;
4117 q
.in
.level
= r
->in
.level
;
4118 q
.in
.start_idx
= r
->in
.start_idx
;
4119 q
.in
.max_entries
= r
->in
.max_entries
;
4120 q
.in
.buf_size
= r
->in
.buf_size
;
4121 q
.out
.total_size
= r
->out
.total_size
;
4122 q
.out
.returned_size
= r
->out
.returned_size
;
4123 q
.out
.info
= r
->out
.info
;
4125 result
= dcesrv_samr_QueryDisplayInfo(dce_call
, mem_ctx
, &q
);
4132 samr_AddMultipleMembersToAlias
4134 static NTSTATUS
dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4135 struct samr_AddMultipleMembersToAlias
*r
)
4137 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4142 samr_RemoveMultipleMembersFromAlias
4144 static NTSTATUS
dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4145 struct samr_RemoveMultipleMembersFromAlias
*r
)
4147 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4154 this fetches the default password properties for a domain
4156 note that w2k3 completely ignores the domain name in this call, and
4157 always returns the information for the servers primary domain
4159 static NTSTATUS
dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4160 struct samr_GetDomPwInfo
*r
)
4162 struct ldb_message
**msgs
;
4164 const char * const attrs
[] = {"minPwdLength", "pwdProperties", NULL
};
4165 struct ldb_context
*sam_ctx
;
4167 ZERO_STRUCTP(r
->out
.info
);
4169 sam_ctx
= samdb_connect(mem_ctx
, dce_call
->event_ctx
, dce_call
->conn
->dce_ctx
->lp_ctx
, dce_call
->conn
->auth_state
.session_info
);
4170 if (sam_ctx
== NULL
) {
4171 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
4174 /* The domain name in this call is ignored */
4175 ret
= gendb_search_dn(sam_ctx
,
4176 mem_ctx
, NULL
, &msgs
, attrs
);
4178 return NT_STATUS_NO_SUCH_DOMAIN
;
4182 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
4185 r
->out
.info
->min_password_length
= samdb_result_uint(msgs
[0],
4187 r
->out
.info
->password_properties
= samdb_result_uint(msgs
[0],
4188 "pwdProperties", 1);
4192 talloc_free(sam_ctx
);
4193 return NT_STATUS_OK
;
4200 static NTSTATUS
dcesrv_samr_Connect2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4201 struct samr_Connect2
*r
)
4203 struct samr_Connect c
;
4205 c
.in
.system_name
= NULL
;
4206 c
.in
.access_mask
= r
->in
.access_mask
;
4207 c
.out
.connect_handle
= r
->out
.connect_handle
;
4209 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4216 just an alias for samr_SetUserInfo
4218 static NTSTATUS
dcesrv_samr_SetUserInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4219 struct samr_SetUserInfo2
*r
)
4221 struct samr_SetUserInfo r2
;
4223 r2
.in
.user_handle
= r
->in
.user_handle
;
4224 r2
.in
.level
= r
->in
.level
;
4225 r2
.in
.info
= r
->in
.info
;
4227 return dcesrv_samr_SetUserInfo(dce_call
, mem_ctx
, &r2
);
4232 samr_SetBootKeyInformation
4234 static NTSTATUS
dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4235 struct samr_SetBootKeyInformation
*r
)
4237 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4242 samr_GetBootKeyInformation
4244 static NTSTATUS
dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4245 struct samr_GetBootKeyInformation
*r
)
4247 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4254 static NTSTATUS
dcesrv_samr_Connect3(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4255 struct samr_Connect3
*r
)
4257 struct samr_Connect c
;
4259 c
.in
.system_name
= NULL
;
4260 c
.in
.access_mask
= r
->in
.access_mask
;
4261 c
.out
.connect_handle
= r
->out
.connect_handle
;
4263 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4270 static NTSTATUS
dcesrv_samr_Connect4(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4271 struct samr_Connect4
*r
)
4273 struct samr_Connect c
;
4275 c
.in
.system_name
= NULL
;
4276 c
.in
.access_mask
= r
->in
.access_mask
;
4277 c
.out
.connect_handle
= r
->out
.connect_handle
;
4279 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4286 static NTSTATUS
dcesrv_samr_Connect5(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4287 struct samr_Connect5
*r
)
4289 struct samr_Connect c
;
4292 c
.in
.system_name
= NULL
;
4293 c
.in
.access_mask
= r
->in
.access_mask
;
4294 c
.out
.connect_handle
= r
->out
.connect_handle
;
4296 status
= dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4298 r
->out
.info_out
->info1
.client_version
= SAMR_CONNECT_AFTER_W2K
;
4299 r
->out
.info_out
->info1
.unknown2
= 0;
4300 *r
->out
.level_out
= r
->in
.level_in
;
4309 static NTSTATUS
dcesrv_samr_RidToSid(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4310 struct samr_RidToSid
*r
)
4312 struct samr_domain_state
*d_state
;
4313 struct dcesrv_handle
*h
;
4315 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
4319 /* form the users SID */
4320 *r
->out
.sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
4322 return NT_STATUS_NO_MEMORY
;
4325 return NT_STATUS_OK
;
4330 samr_SetDsrmPassword
4332 static NTSTATUS
dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4333 struct samr_SetDsrmPassword
*r
)
4335 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4340 samr_ValidatePassword
4342 static NTSTATUS
dcesrv_samr_ValidatePassword(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4343 struct samr_ValidatePassword
*r
)
4345 /* just say it's OK for now - we need to hook this into our
4346 password strength code later */
4347 DEBUG(0,(__location__
": Faking samr_ValidatePassword reply\n"));
4348 (*r
->out
.rep
) = talloc_zero(mem_ctx
, union samr_ValidatePasswordRep
);
4349 return NT_STATUS_OK
;
4353 /* include the generated boilerplate */
4354 #include "librpc/gen_ndr/ndr_samr_s.c"