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"
40 #include "lib/util/tsort.h"
42 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
44 #define QUERY_STRING(msg, field, attr) \
45 info->field.string = samdb_result_string(msg, attr, "");
46 #define QUERY_UINT(msg, field, attr) \
47 info->field = samdb_result_uint(msg, attr, 0);
48 #define QUERY_RID(msg, field, attr) \
49 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
50 #define QUERY_UINT64(msg, field, attr) \
51 info->field = samdb_result_uint64(msg, attr, 0);
52 #define QUERY_APASSC(msg, field, attr) \
53 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
54 a_state->domain_state->domain_dn, msg, attr);
55 #define QUERY_FPASSC(msg, field, attr) \
56 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
57 a_state->domain_state->domain_dn, msg);
58 #define QUERY_LHOURS(msg, field, attr) \
59 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
60 #define QUERY_AFLAGS(msg, field, attr) \
61 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
62 #define QUERY_PARAMETERS(msg, field, attr) \
63 info->field = samdb_result_parameters(mem_ctx, msg, attr);
66 /* these are used to make the Set[User|Group]Info code easier to follow */
68 #define SET_STRING(msg, field, attr) do { \
69 struct ldb_message_element *set_el; \
70 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
71 if (r->in.info->field.string[0] == '\0') { \
72 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
73 return NT_STATUS_NO_MEMORY; \
76 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
77 return NT_STATUS_NO_MEMORY; \
79 set_el = ldb_msg_find_element(msg, attr); \
80 set_el->flags = LDB_FLAG_MOD_REPLACE; \
83 #define SET_UINT(msg, field, attr) do { \
84 struct ldb_message_element *set_el; \
85 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
86 return NT_STATUS_NO_MEMORY; \
88 set_el = ldb_msg_find_element(msg, attr); \
89 set_el->flags = LDB_FLAG_MOD_REPLACE; \
92 #define SET_INT64(msg, field, attr) do { \
93 struct ldb_message_element *set_el; \
94 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
95 return NT_STATUS_NO_MEMORY; \
97 set_el = ldb_msg_find_element(msg, attr); \
98 set_el->flags = LDB_FLAG_MOD_REPLACE; \
101 #define SET_UINT64(msg, field, attr) do { \
102 struct ldb_message_element *set_el; \
103 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
104 return NT_STATUS_NO_MEMORY; \
106 set_el = ldb_msg_find_element(msg, attr); \
107 set_el->flags = LDB_FLAG_MOD_REPLACE; \
110 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
112 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
113 return NT_STATUS_INVALID_PARAMETER; \
117 /* Set account flags, discarding flags that cannot be set with SAMR */
118 #define SET_AFLAGS(msg, field, attr) do { \
119 struct ldb_message_element *set_el; \
120 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
121 return NT_STATUS_INVALID_PARAMETER; \
123 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
128 return NT_STATUS_NO_MEMORY; \
130 set_el = ldb_msg_find_element(msg, attr); \
131 set_el->flags = LDB_FLAG_MOD_REPLACE; \
134 #define SET_LHOURS(msg, field, attr) do { \
135 struct ldb_message_element *set_el; \
136 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
137 return NT_STATUS_NO_MEMORY; \
139 set_el = ldb_msg_find_element(msg, attr); \
140 set_el->flags = LDB_FLAG_MOD_REPLACE; \
143 #define SET_PARAMETERS(msg, field, attr) do { \
144 struct ldb_message_element *set_el; \
145 if (r->in.info->field.length != 0) { \
146 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
147 return NT_STATUS_NO_MEMORY; \
149 set_el = ldb_msg_find_element(msg, attr); \
150 set_el->flags = LDB_FLAG_MOD_REPLACE; \
159 create a connection to the SAM database
161 static NTSTATUS
dcesrv_samr_Connect(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
162 struct samr_Connect
*r
)
164 struct samr_connect_state
*c_state
;
165 struct dcesrv_handle
*handle
;
167 ZERO_STRUCTP(r
->out
.connect_handle
);
169 c_state
= talloc(mem_ctx
, struct samr_connect_state
);
171 return NT_STATUS_NO_MEMORY
;
174 /* make sure the sam database is accessible */
175 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
);
176 if (c_state
->sam_ctx
== NULL
) {
177 talloc_free(c_state
);
178 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
182 handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_CONNECT
);
184 talloc_free(c_state
);
185 return NT_STATUS_NO_MEMORY
;
188 handle
->data
= talloc_steal(handle
, c_state
);
190 c_state
->access_mask
= r
->in
.access_mask
;
191 *r
->out
.connect_handle
= handle
->wire_handle
;
200 static NTSTATUS
dcesrv_samr_Close(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
201 struct samr_Close
*r
)
203 struct dcesrv_handle
*h
;
205 *r
->out
.handle
= *r
->in
.handle
;
207 DCESRV_PULL_HANDLE(h
, r
->in
.handle
, DCESRV_HANDLE_ANY
);
211 ZERO_STRUCTP(r
->out
.handle
);
220 static NTSTATUS
dcesrv_samr_SetSecurity(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
221 struct samr_SetSecurity
*r
)
223 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
230 static NTSTATUS
dcesrv_samr_QuerySecurity(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
231 struct samr_QuerySecurity
*r
)
233 struct dcesrv_handle
*h
;
234 struct sec_desc_buf
*sd
;
236 *r
->out
.sdbuf
= NULL
;
238 DCESRV_PULL_HANDLE(h
, r
->in
.handle
, DCESRV_HANDLE_ANY
);
240 sd
= talloc(mem_ctx
, struct sec_desc_buf
);
242 return NT_STATUS_NO_MEMORY
;
245 sd
->sd
= samdb_default_security_descriptor(mem_ctx
);
256 we refuse this operation completely. If a admin wants to shutdown samr
257 in Samba then they should use the samba admin tools to disable the samr pipe
259 static NTSTATUS
dcesrv_samr_Shutdown(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
260 struct samr_Shutdown
*r
)
262 return NT_STATUS_ACCESS_DENIED
;
269 this maps from a domain name to a SID
271 static NTSTATUS
dcesrv_samr_LookupDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
272 struct samr_LookupDomain
*r
)
274 struct samr_connect_state
*c_state
;
275 struct dcesrv_handle
*h
;
277 const char * const dom_attrs
[] = { "objectSid", NULL
};
278 struct ldb_message
**dom_msgs
;
283 DCESRV_PULL_HANDLE(h
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
287 if (r
->in
.domain_name
->string
== NULL
) {
288 return NT_STATUS_INVALID_PARAMETER
;
291 if (strcasecmp(r
->in
.domain_name
->string
, "BUILTIN") == 0) {
292 ret
= gendb_search(c_state
->sam_ctx
,
293 mem_ctx
, NULL
, &dom_msgs
, dom_attrs
,
294 "(objectClass=builtinDomain)");
295 } else if (strcasecmp_m(r
->in
.domain_name
->string
, lp_sam_name(dce_call
->conn
->dce_ctx
->lp_ctx
)) == 0) {
296 ret
= gendb_search_dn(c_state
->sam_ctx
,
297 mem_ctx
, ldb_get_default_basedn(c_state
->sam_ctx
),
298 &dom_msgs
, dom_attrs
);
300 return NT_STATUS_NO_SUCH_DOMAIN
;
303 return NT_STATUS_NO_SUCH_DOMAIN
;
306 sid
= samdb_result_dom_sid(mem_ctx
, dom_msgs
[0],
310 return NT_STATUS_NO_SUCH_DOMAIN
;
322 list the domains in the SAM
324 static NTSTATUS
dcesrv_samr_EnumDomains(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
325 struct samr_EnumDomains
*r
)
327 struct samr_connect_state
*c_state
;
328 struct dcesrv_handle
*h
;
329 struct samr_SamArray
*array
;
332 *r
->out
.resume_handle
= 0;
334 *r
->out
.num_entries
= 0;
336 DCESRV_PULL_HANDLE(h
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
340 *r
->out
.resume_handle
= 2;
342 start_i
= *r
->in
.resume_handle
;
345 /* search past end of list is not an error for this call */
349 array
= talloc(mem_ctx
, struct samr_SamArray
);
351 return NT_STATUS_NO_MEMORY
;
355 array
->entries
= NULL
;
357 array
->entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, 2 - start_i
);
358 if (array
->entries
== NULL
) {
359 return NT_STATUS_NO_MEMORY
;
362 for (i
=0;i
<2-start_i
;i
++) {
363 array
->entries
[i
].idx
= start_i
+ i
;
365 array
->entries
[i
].name
.string
= lp_sam_name(dce_call
->conn
->dce_ctx
->lp_ctx
);
367 array
->entries
[i
].name
.string
= "BUILTIN";
372 *r
->out
.num_entries
= i
;
373 array
->count
= *r
->out
.num_entries
;
382 static NTSTATUS
dcesrv_samr_OpenDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
383 struct samr_OpenDomain
*r
)
385 struct dcesrv_handle
*h_conn
, *h_domain
;
386 struct samr_connect_state
*c_state
;
387 struct samr_domain_state
*d_state
;
388 const char * const dom_attrs
[] = { "cn", NULL
};
389 struct ldb_message
**dom_msgs
;
392 ZERO_STRUCTP(r
->out
.domain_handle
);
394 DCESRV_PULL_HANDLE(h_conn
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
396 c_state
= h_conn
->data
;
398 if (r
->in
.sid
== NULL
) {
399 return NT_STATUS_INVALID_PARAMETER
;
402 d_state
= talloc(mem_ctx
, struct samr_domain_state
);
404 return NT_STATUS_NO_MEMORY
;
407 d_state
->domain_sid
= talloc_steal(d_state
, r
->in
.sid
);
409 if (dom_sid_equal(d_state
->domain_sid
, dom_sid_parse_talloc(mem_ctx
, SID_BUILTIN
))) {
410 d_state
->builtin
= true;
411 d_state
->domain_name
= "BUILTIN";
413 d_state
->builtin
= false;
414 d_state
->domain_name
= lp_sam_name(dce_call
->conn
->dce_ctx
->lp_ctx
);
417 ret
= gendb_search(c_state
->sam_ctx
,
418 mem_ctx
, ldb_get_default_basedn(c_state
->sam_ctx
), &dom_msgs
, dom_attrs
,
420 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
423 talloc_free(d_state
);
424 return NT_STATUS_NO_SUCH_DOMAIN
;
425 } else if (ret
> 1) {
426 talloc_free(d_state
);
427 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
428 } else if (ret
== -1) {
429 talloc_free(d_state
);
430 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx
, r
->in
.sid
), ldb_errstring(c_state
->sam_ctx
)));
431 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
434 d_state
->domain_dn
= talloc_steal(d_state
, dom_msgs
[0]->dn
);
435 d_state
->role
= lp_server_role(dce_call
->conn
->dce_ctx
->lp_ctx
);
436 d_state
->connect_state
= talloc_reference(d_state
, c_state
);
437 d_state
->sam_ctx
= c_state
->sam_ctx
;
438 d_state
->access_mask
= r
->in
.access_mask
;
440 d_state
->lp_ctx
= dce_call
->conn
->dce_ctx
->lp_ctx
;
442 h_domain
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_DOMAIN
);
444 talloc_free(d_state
);
445 return NT_STATUS_NO_MEMORY
;
448 h_domain
->data
= talloc_steal(h_domain
, d_state
);
450 *r
->out
.domain_handle
= h_domain
->wire_handle
;
458 static NTSTATUS
dcesrv_samr_info_DomInfo1(struct samr_domain_state
*state
,
460 struct ldb_message
**dom_msgs
,
461 struct samr_DomInfo1
*info
)
463 info
->min_password_length
=
464 samdb_result_uint(dom_msgs
[0], "minPwdLength", 0);
465 info
->password_history_length
=
466 samdb_result_uint(dom_msgs
[0], "pwdHistoryLength", 0);
467 info
->password_properties
=
468 samdb_result_uint(dom_msgs
[0], "pwdProperties", 0);
469 info
->max_password_age
=
470 samdb_result_int64(dom_msgs
[0], "maxPwdAge", 0);
471 info
->min_password_age
=
472 samdb_result_int64(dom_msgs
[0], "minPwdAge", 0);
480 static NTSTATUS
dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state
*state
,
482 struct ldb_message
**dom_msgs
,
483 struct samr_DomGeneralInformation
*info
)
485 /* This pulls the NetBIOS name from the
486 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
488 info
->primary
.string
= samdb_result_fsmo_name(state
->sam_ctx
, mem_ctx
, dom_msgs
[0], "fSMORoleOwner");
490 if (!info
->primary
.string
) {
491 info
->primary
.string
= lp_netbios_name(state
->lp_ctx
);
494 info
->force_logoff_time
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "forceLogoff",
495 0x8000000000000000LL
);
497 info
->oem_information
.string
= samdb_result_string(dom_msgs
[0], "oEMInformation", NULL
);
498 info
->domain_name
.string
= state
->domain_name
;
500 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
502 switch (state
->role
) {
503 case ROLE_DOMAIN_CONTROLLER
:
504 /* This pulls the NetBIOS name from the
505 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
507 if (samdb_is_pdc(state
->sam_ctx
)) {
508 info
->role
= SAMR_ROLE_DOMAIN_PDC
;
510 info
->role
= SAMR_ROLE_DOMAIN_BDC
;
513 case ROLE_DOMAIN_MEMBER
:
514 info
->role
= SAMR_ROLE_DOMAIN_MEMBER
;
516 case ROLE_STANDALONE
:
517 info
->role
= SAMR_ROLE_STANDALONE
;
521 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
522 info
->num_users
= samdb_search_count(state
->sam_ctx
, state
->domain_dn
,
523 "(objectClass=user)");
524 info
->num_groups
= samdb_search_count(state
->sam_ctx
, state
->domain_dn
,
525 "(&(objectClass=group)(groupType=%u))",
526 GTYPE_SECURITY_GLOBAL_GROUP
);
527 info
->num_aliases
= samdb_search_count(state
->sam_ctx
, state
->domain_dn
,
528 "(&(objectClass=group)(groupType=%u))",
529 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
537 static NTSTATUS
dcesrv_samr_info_DomInfo3(struct samr_domain_state
*state
,
539 struct ldb_message
**dom_msgs
,
540 struct samr_DomInfo3
*info
)
542 info
->force_logoff_time
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "forceLogoff",
543 0x8000000000000000LL
);
551 static NTSTATUS
dcesrv_samr_info_DomOEMInformation(struct samr_domain_state
*state
,
553 struct ldb_message
**dom_msgs
,
554 struct samr_DomOEMInformation
*info
)
556 info
->oem_information
.string
= samdb_result_string(dom_msgs
[0], "oEMInformation", NULL
);
564 static NTSTATUS
dcesrv_samr_info_DomInfo5(struct samr_domain_state
*state
,
566 struct ldb_message
**dom_msgs
,
567 struct samr_DomInfo5
*info
)
569 info
->domain_name
.string
= state
->domain_name
;
577 static NTSTATUS
dcesrv_samr_info_DomInfo6(struct samr_domain_state
*state
,
579 struct ldb_message
**dom_msgs
,
580 struct samr_DomInfo6
*info
)
582 /* This pulls the NetBIOS name from the
583 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
585 info
->primary
.string
= samdb_result_fsmo_name(state
->sam_ctx
, mem_ctx
,
586 dom_msgs
[0], "fSMORoleOwner");
588 if (!info
->primary
.string
) {
589 info
->primary
.string
= lp_netbios_name(state
->lp_ctx
);
598 static NTSTATUS
dcesrv_samr_info_DomInfo7(struct samr_domain_state
*state
,
600 struct ldb_message
**dom_msgs
,
601 struct samr_DomInfo7
*info
)
604 switch (state
->role
) {
605 case ROLE_DOMAIN_CONTROLLER
:
606 /* This pulls the NetBIOS name from the
607 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
609 if (samdb_is_pdc(state
->sam_ctx
)) {
610 info
->role
= SAMR_ROLE_DOMAIN_PDC
;
612 info
->role
= SAMR_ROLE_DOMAIN_BDC
;
615 case ROLE_DOMAIN_MEMBER
:
616 info
->role
= SAMR_ROLE_DOMAIN_MEMBER
;
618 case ROLE_STANDALONE
:
619 info
->role
= SAMR_ROLE_STANDALONE
;
629 static NTSTATUS
dcesrv_samr_info_DomInfo8(struct samr_domain_state
*state
,
631 struct ldb_message
**dom_msgs
,
632 struct samr_DomInfo8
*info
)
634 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
637 info
->domain_create_time
= ldb_msg_find_attr_as_uint(dom_msgs
[0], "creationTime",
646 static NTSTATUS
dcesrv_samr_info_DomInfo9(struct samr_domain_state
*state
,
648 struct ldb_message
**dom_msgs
,
649 struct samr_DomInfo9
*info
)
651 info
->domain_server_state
= DOMAIN_SERVER_ENABLED
;
659 static NTSTATUS
dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state
*state
,
661 struct ldb_message
**dom_msgs
,
662 struct samr_DomGeneralInformation2
*info
)
665 status
= dcesrv_samr_info_DomGeneralInformation(state
, mem_ctx
, dom_msgs
, &info
->general
);
666 if (!NT_STATUS_IS_OK(status
)) {
670 info
->lockout_duration
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutDuration",
672 info
->lockout_window
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockOutObservationWindow",
674 info
->lockout_threshold
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutThreshold", 0);
682 static NTSTATUS
dcesrv_samr_info_DomInfo12(struct samr_domain_state
*state
,
684 struct ldb_message
**dom_msgs
,
685 struct samr_DomInfo12
*info
)
687 info
->lockout_duration
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutDuration",
689 info
->lockout_window
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockOutObservationWindow",
691 info
->lockout_threshold
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutThreshold", 0);
699 static NTSTATUS
dcesrv_samr_info_DomInfo13(struct samr_domain_state
*state
,
701 struct ldb_message
**dom_msgs
,
702 struct samr_DomInfo13
*info
)
704 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
707 info
->domain_create_time
= ldb_msg_find_attr_as_uint(dom_msgs
[0], "creationTime",
710 info
->modified_count_at_last_promotion
= 0;
718 static NTSTATUS
dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
719 struct samr_QueryDomainInfo
*r
)
721 struct dcesrv_handle
*h
;
722 struct samr_domain_state
*d_state
;
723 union samr_DomainInfo
*info
;
725 struct ldb_message
**dom_msgs
;
726 const char * const *attrs
= NULL
;
730 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
734 info
= talloc(mem_ctx
, union samr_DomainInfo
);
736 return NT_STATUS_NO_MEMORY
;
739 switch (r
->in
.level
) {
742 static const char * const attrs2
[] = { "minPwdLength",
753 static const char * const attrs2
[] = {"forceLogoff",
763 static const char * const attrs2
[] = {"forceLogoff",
770 static const char * const attrs2
[] = {"oEMInformation",
782 static const char * const attrs2
[] = {"fSMORoleOwner",
794 static const char * const attrs2
[] = { "modifiedCount",
807 static const char * const attrs2
[] = { "oEMInformation",
811 "lockOutObservationWindow",
819 static const char * const attrs2
[] = { "lockoutDuration",
820 "lockOutObservationWindow",
828 static const char * const attrs2
[] = { "modifiedCount",
836 return NT_STATUS_INVALID_INFO_CLASS
;
840 /* some levels don't need a search */
843 ret
= gendb_search_dn(d_state
->sam_ctx
, mem_ctx
,
844 d_state
->domain_dn
, &dom_msgs
, attrs
);
846 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
854 switch (r
->in
.level
) {
856 return dcesrv_samr_info_DomInfo1(d_state
, mem_ctx
, dom_msgs
,
859 return dcesrv_samr_info_DomGeneralInformation(d_state
, mem_ctx
, dom_msgs
,
862 return dcesrv_samr_info_DomInfo3(d_state
, mem_ctx
, dom_msgs
,
865 return dcesrv_samr_info_DomOEMInformation(d_state
, mem_ctx
, dom_msgs
,
868 return dcesrv_samr_info_DomInfo5(d_state
, mem_ctx
, dom_msgs
,
871 return dcesrv_samr_info_DomInfo6(d_state
, mem_ctx
, dom_msgs
,
874 return dcesrv_samr_info_DomInfo7(d_state
, mem_ctx
, dom_msgs
,
877 return dcesrv_samr_info_DomInfo8(d_state
, mem_ctx
, dom_msgs
,
880 return dcesrv_samr_info_DomInfo9(d_state
, mem_ctx
, dom_msgs
,
883 return dcesrv_samr_info_DomGeneralInformation2(d_state
, mem_ctx
, dom_msgs
,
886 return dcesrv_samr_info_DomInfo12(d_state
, mem_ctx
, dom_msgs
,
889 return dcesrv_samr_info_DomInfo13(d_state
, mem_ctx
, dom_msgs
,
892 return NT_STATUS_INVALID_INFO_CLASS
;
900 static NTSTATUS
dcesrv_samr_SetDomainInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
901 struct samr_SetDomainInfo
*r
)
903 struct dcesrv_handle
*h
;
904 struct samr_domain_state
*d_state
;
905 struct ldb_message
*msg
;
907 struct ldb_context
*sam_ctx
;
909 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
912 sam_ctx
= d_state
->sam_ctx
;
914 msg
= ldb_msg_new(mem_ctx
);
916 return NT_STATUS_NO_MEMORY
;
919 msg
->dn
= talloc_reference(mem_ctx
, d_state
->domain_dn
);
921 return NT_STATUS_NO_MEMORY
;
924 switch (r
->in
.level
) {
926 SET_UINT (msg
, info1
.min_password_length
, "minPwdLength");
927 SET_UINT (msg
, info1
.password_history_length
, "pwdHistoryLength");
928 SET_UINT (msg
, info1
.password_properties
, "pwdProperties");
929 SET_INT64 (msg
, info1
.max_password_age
, "maxPwdAge");
930 SET_INT64 (msg
, info1
.min_password_age
, "minPwdAge");
933 SET_UINT64 (msg
, info3
.force_logoff_time
, "forceLogoff");
936 SET_STRING(msg
, oem
.oem_information
, "oEMInformation");
942 /* No op, we don't know where to set these */
947 * It is not possible to set lockout_duration < lockout_window.
948 * (The test is the other way around since the negative numbers
952 * This check should be moved to the backend, i.e. to some
953 * ldb module under dsdb/samdb/ldb_modules/ .
955 * This constraint is documented here for the samr rpc service:
956 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
957 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
959 * And here for the ldap backend:
960 * MS-ADTS 3.1.1.5.3.2 Constraints
961 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
963 if (r
->in
.info
->info12
.lockout_duration
>
964 r
->in
.info
->info12
.lockout_window
)
966 return NT_STATUS_INVALID_PARAMETER
;
968 SET_INT64 (msg
, info12
.lockout_duration
, "lockoutDuration");
969 SET_INT64 (msg
, info12
.lockout_window
, "lockOutObservationWindow");
970 SET_INT64 (msg
, info12
.lockout_threshold
, "lockoutThreshold");
974 /* many info classes are not valid for SetDomainInfo */
975 return NT_STATUS_INVALID_INFO_CLASS
;
978 /* modify the samdb record */
979 ret
= ldb_modify(sam_ctx
, msg
);
980 if (ret
!= LDB_SUCCESS
) {
981 DEBUG(1,("Failed to modify record %s: %s\n",
982 ldb_dn_get_linearized(d_state
->domain_dn
),
983 ldb_errstring(sam_ctx
)));
985 /* we really need samdb.c to return NTSTATUS */
986 return NT_STATUS_UNSUCCESSFUL
;
993 samr_CreateDomainGroup
995 static NTSTATUS
dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
996 struct samr_CreateDomainGroup
*r
)
998 struct samr_domain_state
*d_state
;
999 struct samr_account_state
*a_state
;
1000 struct dcesrv_handle
*h
;
1002 struct ldb_message
*msg
;
1003 struct dom_sid
*sid
;
1004 const char *groupname
;
1005 struct dcesrv_handle
*g_handle
;
1008 ZERO_STRUCTP(r
->out
.group_handle
);
1011 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1015 if (d_state
->builtin
) {
1016 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1017 return NT_STATUS_ACCESS_DENIED
;
1020 groupname
= r
->in
.name
->string
;
1022 if (groupname
== NULL
) {
1023 return NT_STATUS_INVALID_PARAMETER
;
1026 /* check if the group already exists */
1027 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1029 "(&(sAMAccountName=%s)(objectclass=group))",
1030 ldb_binary_encode_string(mem_ctx
, groupname
));
1032 return NT_STATUS_GROUP_EXISTS
;
1035 msg
= ldb_msg_new(mem_ctx
);
1037 return NT_STATUS_NO_MEMORY
;
1040 /* add core elements to the ldb_message for the user */
1041 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1042 ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,CN=Users", groupname
);
1044 return NT_STATUS_NO_MEMORY
;
1046 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName", groupname
);
1047 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass", "group");
1049 /* create the group */
1050 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1054 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1055 DEBUG(0,("Failed to create group record %s: %s\n",
1056 ldb_dn_get_linearized(msg
->dn
),
1057 ldb_errstring(d_state
->sam_ctx
)));
1058 return NT_STATUS_GROUP_EXISTS
;
1059 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1060 DEBUG(0,("Failed to create group record %s: %s\n",
1061 ldb_dn_get_linearized(msg
->dn
),
1062 ldb_errstring(d_state
->sam_ctx
)));
1063 return NT_STATUS_ACCESS_DENIED
;
1065 DEBUG(0,("Failed to create group record %s: %s\n",
1066 ldb_dn_get_linearized(msg
->dn
),
1067 ldb_errstring(d_state
->sam_ctx
)));
1068 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1071 a_state
= talloc(mem_ctx
, struct samr_account_state
);
1073 return NT_STATUS_NO_MEMORY
;
1075 a_state
->sam_ctx
= d_state
->sam_ctx
;
1076 a_state
->access_mask
= r
->in
.access_mask
;
1077 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1078 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1080 /* retrieve the sid for the group just created */
1081 sid
= samdb_search_dom_sid(d_state
->sam_ctx
, a_state
,
1082 msg
->dn
, "objectSid", NULL
);
1084 return NT_STATUS_UNSUCCESSFUL
;
1087 a_state
->account_name
= talloc_strdup(a_state
, groupname
);
1088 if (!a_state
->account_name
) {
1089 return NT_STATUS_NO_MEMORY
;
1092 /* create the policy handle */
1093 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_GROUP
);
1095 return NT_STATUS_NO_MEMORY
;
1098 g_handle
->data
= talloc_steal(g_handle
, a_state
);
1100 *r
->out
.group_handle
= g_handle
->wire_handle
;
1101 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1103 return NT_STATUS_OK
;
1108 comparison function for sorting SamEntry array
1110 static int compare_SamEntry(struct samr_SamEntry
*e1
, struct samr_SamEntry
*e2
)
1112 return e1
->idx
- e2
->idx
;
1116 samr_EnumDomainGroups
1118 static NTSTATUS
dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1119 struct samr_EnumDomainGroups
*r
)
1121 struct dcesrv_handle
*h
;
1122 struct samr_domain_state
*d_state
;
1123 struct ldb_message
**res
;
1124 int ldb_cnt
, count
, i
, first
;
1125 struct samr_SamEntry
*entries
;
1126 const char * const attrs
[3] = { "objectSid", "sAMAccountName", NULL
};
1127 struct samr_SamArray
*sam
;
1129 *r
->out
.resume_handle
= 0;
1131 *r
->out
.num_entries
= 0;
1133 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1137 /* search for all domain groups in this domain. This could possibly be
1138 cached and resumed based on resume_key */
1139 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1140 d_state
->domain_dn
, &res
, attrs
,
1141 d_state
->domain_sid
,
1142 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1143 GTYPE_SECURITY_UNIVERSAL_GROUP
,
1144 GTYPE_SECURITY_GLOBAL_GROUP
);
1145 if (ldb_cnt
== -1) {
1146 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1149 /* convert to SamEntry format */
1150 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, ldb_cnt
);
1152 return NT_STATUS_NO_MEMORY
;
1157 for (i
=0;i
<ldb_cnt
;i
++) {
1158 struct dom_sid
*group_sid
;
1160 group_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
1162 if (group_sid
== NULL
)
1165 entries
[count
].idx
=
1166 group_sid
->sub_auths
[group_sid
->num_auths
-1];
1167 entries
[count
].name
.string
=
1168 samdb_result_string(res
[i
], "sAMAccountName", "");
1172 /* sort the results by rid */
1173 TYPESAFE_QSORT(entries
, count
, compare_SamEntry
);
1175 /* find the first entry to return */
1177 first
<count
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1180 /* return the rest, limit by max_size. Note that we
1181 use the w2k3 element size value of 54 */
1182 *r
->out
.num_entries
= count
- first
;
1183 *r
->out
.num_entries
= MIN(*r
->out
.num_entries
,
1184 1+(r
->in
.max_size
/SAMR_ENUM_USERS_MULTIPLIER
));
1186 sam
= talloc(mem_ctx
, struct samr_SamArray
);
1188 return NT_STATUS_NO_MEMORY
;
1191 sam
->entries
= entries
+first
;
1192 sam
->count
= *r
->out
.num_entries
;
1196 if (*r
->out
.num_entries
< count
- first
) {
1197 *r
->out
.resume_handle
= entries
[first
+*r
->out
.num_entries
-1].idx
;
1198 return STATUS_MORE_ENTRIES
;
1201 return NT_STATUS_OK
;
1208 This call uses transactions to ensure we don't get a new conflicting
1209 user while we are processing this, and to ensure the user either
1210 completly exists, or does not.
1212 static NTSTATUS
dcesrv_samr_CreateUser2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1213 struct samr_CreateUser2
*r
)
1215 struct samr_domain_state
*d_state
;
1216 struct samr_account_state
*a_state
;
1217 struct dcesrv_handle
*h
;
1219 struct ldb_message
*msg
;
1220 struct dom_sid
*sid
;
1221 const char *account_name
;
1222 struct dcesrv_handle
*u_handle
;
1224 const char *container
, *obj_class
=NULL
;
1228 const char *attrs
[] = {
1230 "userAccountControl",
1234 uint32_t user_account_control
;
1236 struct ldb_message
**msgs
;
1238 ZERO_STRUCTP(r
->out
.user_handle
);
1239 *r
->out
.access_granted
= 0;
1242 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1246 if (d_state
->builtin
) {
1247 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1248 return NT_STATUS_ACCESS_DENIED
;
1249 } else if (r
->in
.acct_flags
== ACB_DOMTRUST
) {
1250 /* Domain trust accounts must be created by the LSA calls */
1251 return NT_STATUS_ACCESS_DENIED
;
1253 account_name
= r
->in
.account_name
->string
;
1255 if (account_name
== NULL
) {
1256 return NT_STATUS_INVALID_PARAMETER
;
1260 * Start a transaction, so we can query and do a subsequent atomic
1264 ret
= ldb_transaction_start(d_state
->sam_ctx
);
1265 if (ret
!= LDB_SUCCESS
) {
1266 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1267 ldb_errstring(d_state
->sam_ctx
)));
1268 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1271 /* check if the user already exists */
1272 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1274 "(&(sAMAccountName=%s)(objectclass=user))",
1275 ldb_binary_encode_string(mem_ctx
, account_name
));
1277 ldb_transaction_cancel(d_state
->sam_ctx
);
1278 return NT_STATUS_USER_EXISTS
;
1281 msg
= ldb_msg_new(mem_ctx
);
1283 ldb_transaction_cancel(d_state
->sam_ctx
);
1284 return NT_STATUS_NO_MEMORY
;
1287 cn_name
= talloc_strdup(mem_ctx
, account_name
);
1289 ldb_transaction_cancel(d_state
->sam_ctx
);
1290 return NT_STATUS_NO_MEMORY
;
1293 cn_name_len
= strlen(cn_name
);
1295 /* This must be one of these values *only* */
1296 if (r
->in
.acct_flags
== ACB_NORMAL
) {
1297 container
= "CN=Users";
1300 } else if (r
->in
.acct_flags
== ACB_WSTRUST
) {
1301 if (cn_name
[cn_name_len
- 1] != '$') {
1302 ldb_transaction_cancel(d_state
->sam_ctx
);
1303 return NT_STATUS_FOOBAR
;
1305 cn_name
[cn_name_len
- 1] = '\0';
1306 container
= "CN=Computers";
1307 obj_class
= "computer";
1308 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
,
1309 "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS
);
1311 } else if (r
->in
.acct_flags
== ACB_SVRTRUST
) {
1312 if (cn_name
[cn_name_len
- 1] != '$') {
1313 ldb_transaction_cancel(d_state
->sam_ctx
);
1314 return NT_STATUS_FOOBAR
;
1316 cn_name
[cn_name_len
- 1] = '\0';
1317 container
= "OU=Domain Controllers";
1318 obj_class
= "computer";
1319 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
,
1320 "primaryGroupID", DOMAIN_RID_DCS
);
1322 ldb_transaction_cancel(d_state
->sam_ctx
);
1323 return NT_STATUS_INVALID_PARAMETER
;
1326 /* add core elements to the ldb_message for the user */
1327 msg
->dn
= ldb_dn_copy(msg
, d_state
->domain_dn
);
1328 if ( ! ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,%s", cn_name
, container
)) {
1329 ldb_transaction_cancel(d_state
->sam_ctx
);
1330 return NT_STATUS_FOOBAR
;
1333 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName",
1335 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass",
1338 /* create the user */
1339 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1343 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1344 ldb_transaction_cancel(d_state
->sam_ctx
);
1345 DEBUG(0,("Failed to create user record %s: %s\n",
1346 ldb_dn_get_linearized(msg
->dn
),
1347 ldb_errstring(d_state
->sam_ctx
)));
1348 return NT_STATUS_USER_EXISTS
;
1349 case LDB_ERR_UNWILLING_TO_PERFORM
:
1350 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1351 ldb_transaction_cancel(d_state
->sam_ctx
);
1352 DEBUG(0,("Failed to create user record %s: %s\n",
1353 ldb_dn_get_linearized(msg
->dn
),
1354 ldb_errstring(d_state
->sam_ctx
)));
1355 return NT_STATUS_ACCESS_DENIED
;
1357 ldb_transaction_cancel(d_state
->sam_ctx
);
1358 DEBUG(0,("Failed to create user record %s: %s\n",
1359 ldb_dn_get_linearized(msg
->dn
),
1360 ldb_errstring(d_state
->sam_ctx
)));
1361 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1364 a_state
= talloc(mem_ctx
, struct samr_account_state
);
1366 ldb_transaction_cancel(d_state
->sam_ctx
);
1367 return NT_STATUS_NO_MEMORY
;
1369 a_state
->sam_ctx
= d_state
->sam_ctx
;
1370 a_state
->access_mask
= r
->in
.access_mask
;
1371 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1372 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1374 /* retrieve the sid and account control bits for the user just created */
1375 ret
= gendb_search_dn(d_state
->sam_ctx
, mem_ctx
,
1376 msg
->dn
, &msgs
, attrs
);
1379 ldb_transaction_cancel(d_state
->sam_ctx
);
1380 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1381 ldb_dn_get_linearized(msg
->dn
)));
1382 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1384 sid
= samdb_result_dom_sid(mem_ctx
, msgs
[0], "objectSid");
1386 ldb_transaction_cancel(d_state
->sam_ctx
);
1387 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1388 ldb_dn_get_linearized(msg
->dn
)));
1389 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1392 /* Change the account control to be the correct account type.
1393 * The default is for a workstation account */
1394 user_account_control
= samdb_result_uint(msgs
[0], "userAccountControl", 0);
1395 user_account_control
= (user_account_control
&
1396 ~(UF_NORMAL_ACCOUNT
|
1397 UF_INTERDOMAIN_TRUST_ACCOUNT
|
1398 UF_WORKSTATION_TRUST_ACCOUNT
|
1399 UF_SERVER_TRUST_ACCOUNT
));
1400 user_account_control
|= ds_acb2uf(r
->in
.acct_flags
);
1403 msg
= ldb_msg_new(mem_ctx
);
1405 ldb_transaction_cancel(d_state
->sam_ctx
);
1406 return NT_STATUS_NO_MEMORY
;
1409 msg
->dn
= ldb_dn_copy(msg
, a_state
->account_dn
);
1411 if (samdb_msg_add_uint(a_state
->sam_ctx
, mem_ctx
, msg
,
1412 "userAccountControl",
1413 user_account_control
) != 0) {
1414 ldb_transaction_cancel(d_state
->sam_ctx
);
1415 return NT_STATUS_NO_MEMORY
;
1418 /* modify the samdb record */
1419 ret
= dsdb_replace(a_state
->sam_ctx
, msg
, 0);
1420 if (ret
!= LDB_SUCCESS
) {
1421 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1422 ldb_dn_get_linearized(msg
->dn
),
1423 ldb_errstring(d_state
->sam_ctx
)));
1424 ldb_transaction_cancel(d_state
->sam_ctx
);
1426 /* we really need samdb.c to return NTSTATUS */
1427 return NT_STATUS_UNSUCCESSFUL
;
1430 ret
= ldb_transaction_commit(d_state
->sam_ctx
);
1431 if (ret
!= LDB_SUCCESS
) {
1432 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1433 ldb_dn_get_linearized(msg
->dn
),
1434 ldb_errstring(d_state
->sam_ctx
)));
1435 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1438 a_state
->account_name
= talloc_steal(a_state
, account_name
);
1439 if (!a_state
->account_name
) {
1440 return NT_STATUS_NO_MEMORY
;
1443 /* create the policy handle */
1444 u_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_USER
);
1446 return NT_STATUS_NO_MEMORY
;
1449 u_handle
->data
= talloc_steal(u_handle
, a_state
);
1451 *r
->out
.user_handle
= u_handle
->wire_handle
;
1452 *r
->out
.access_granted
= 0xf07ff; /* TODO: fix access mask calculations */
1454 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1456 return NT_STATUS_OK
;
1463 static NTSTATUS
dcesrv_samr_CreateUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1464 struct samr_CreateUser
*r
)
1466 struct samr_CreateUser2 r2
;
1467 uint32_t access_granted
= 0;
1470 /* a simple wrapper around samr_CreateUser2 works nicely */
1471 r2
.in
.domain_handle
= r
->in
.domain_handle
;
1472 r2
.in
.account_name
= r
->in
.account_name
;
1473 r2
.in
.acct_flags
= ACB_NORMAL
;
1474 r2
.in
.access_mask
= r
->in
.access_mask
;
1475 r2
.out
.user_handle
= r
->out
.user_handle
;
1476 r2
.out
.access_granted
= &access_granted
;
1477 r2
.out
.rid
= r
->out
.rid
;
1479 return dcesrv_samr_CreateUser2(dce_call
, mem_ctx
, &r2
);
1483 samr_EnumDomainUsers
1485 static NTSTATUS
dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1486 struct samr_EnumDomainUsers
*r
)
1488 struct dcesrv_handle
*h
;
1489 struct samr_domain_state
*d_state
;
1490 struct ldb_result
*res
;
1491 int ret
, num_filtered_entries
, i
, first
;
1492 struct samr_SamEntry
*entries
;
1493 const char * const attrs
[] = { "objectSid", "sAMAccountName",
1494 "userAccountControl", NULL
};
1495 struct samr_SamArray
*sam
;
1497 *r
->out
.resume_handle
= 0;
1499 *r
->out
.num_entries
= 0;
1501 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1505 /* don't have to worry about users in the builtin domain, as there are none */
1506 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
, d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
, "objectClass=user");
1508 if (ret
!= LDB_SUCCESS
) {
1509 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1510 ldb_dn_get_linearized(d_state
->domain_dn
), ldb_errstring(d_state
->sam_ctx
)));
1511 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1514 /* convert to SamEntry format */
1515 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, res
->count
);
1517 return NT_STATUS_NO_MEMORY
;
1519 num_filtered_entries
= 0;
1520 for (i
=0;i
<res
->count
;i
++) {
1521 /* Check if a mask has been requested */
1522 if (r
->in
.acct_flags
1523 && ((samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
, res
->msgs
[i
],
1524 d_state
->domain_dn
) & r
->in
.acct_flags
) == 0)) {
1527 entries
[num_filtered_entries
].idx
= samdb_result_rid_from_sid(mem_ctx
, res
->msgs
[i
], "objectSid", 0);
1528 entries
[num_filtered_entries
].name
.string
= samdb_result_string(res
->msgs
[i
], "sAMAccountName", "");
1529 num_filtered_entries
++;
1532 /* sort the results by rid */
1533 TYPESAFE_QSORT(entries
, num_filtered_entries
, compare_SamEntry
);
1535 /* find the first entry to return */
1537 first
<num_filtered_entries
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1540 /* return the rest, limit by max_size. Note that we
1541 use the w2k3 element size value of 54 */
1542 *r
->out
.num_entries
= num_filtered_entries
- first
;
1543 *r
->out
.num_entries
= MIN(*r
->out
.num_entries
,
1544 1+(r
->in
.max_size
/SAMR_ENUM_USERS_MULTIPLIER
));
1546 sam
= talloc(mem_ctx
, struct samr_SamArray
);
1548 return NT_STATUS_NO_MEMORY
;
1551 sam
->entries
= entries
+first
;
1552 sam
->count
= *r
->out
.num_entries
;
1556 if (first
== num_filtered_entries
) {
1557 return NT_STATUS_OK
;
1560 if (*r
->out
.num_entries
< num_filtered_entries
- first
) {
1561 *r
->out
.resume_handle
= entries
[first
+*r
->out
.num_entries
-1].idx
;
1562 return STATUS_MORE_ENTRIES
;
1565 return NT_STATUS_OK
;
1572 static NTSTATUS
dcesrv_samr_CreateDomAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1573 struct samr_CreateDomAlias
*r
)
1575 struct samr_domain_state
*d_state
;
1576 struct samr_account_state
*a_state
;
1577 struct dcesrv_handle
*h
;
1578 const char *alias_name
, *name
;
1579 struct ldb_message
*msg
;
1580 struct dom_sid
*sid
;
1581 struct dcesrv_handle
*a_handle
;
1584 ZERO_STRUCTP(r
->out
.alias_handle
);
1587 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1591 if (d_state
->builtin
) {
1592 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1593 return NT_STATUS_ACCESS_DENIED
;
1596 alias_name
= r
->in
.alias_name
->string
;
1598 if (alias_name
== NULL
) {
1599 return NT_STATUS_INVALID_PARAMETER
;
1602 /* Check if alias already exists */
1603 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1605 "(sAMAccountName=%s)(objectclass=group))",
1606 ldb_binary_encode_string(mem_ctx
, alias_name
));
1609 return NT_STATUS_ALIAS_EXISTS
;
1612 msg
= ldb_msg_new(mem_ctx
);
1614 return NT_STATUS_NO_MEMORY
;
1617 /* add core elements to the ldb_message for the alias */
1618 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1619 ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,CN=Users", alias_name
);
1621 return NT_STATUS_NO_MEMORY
;
1624 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName", alias_name
);
1625 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass", "group");
1626 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1628 /* create the alias */
1629 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1633 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1634 return NT_STATUS_ALIAS_EXISTS
;
1635 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1636 return NT_STATUS_ACCESS_DENIED
;
1638 DEBUG(0,("Failed to create alias record %s: %s\n",
1639 ldb_dn_get_linearized(msg
->dn
),
1640 ldb_errstring(d_state
->sam_ctx
)));
1641 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1644 a_state
= talloc(mem_ctx
, struct samr_account_state
);
1646 return NT_STATUS_NO_MEMORY
;
1649 a_state
->sam_ctx
= d_state
->sam_ctx
;
1650 a_state
->access_mask
= r
->in
.access_mask
;
1651 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1652 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1654 /* retrieve the sid for the alias just created */
1655 sid
= samdb_search_dom_sid(d_state
->sam_ctx
, a_state
,
1656 msg
->dn
, "objectSid", NULL
);
1658 a_state
->account_name
= talloc_strdup(a_state
, alias_name
);
1659 if (!a_state
->account_name
) {
1660 return NT_STATUS_NO_MEMORY
;
1663 /* create the policy handle */
1664 a_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_ALIAS
);
1665 if (a_handle
== NULL
)
1666 return NT_STATUS_NO_MEMORY
;
1668 a_handle
->data
= talloc_steal(a_handle
, a_state
);
1670 *r
->out
.alias_handle
= a_handle
->wire_handle
;
1672 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1674 return NT_STATUS_OK
;
1679 samr_EnumDomainAliases
1681 static NTSTATUS
dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1682 struct samr_EnumDomainAliases
*r
)
1684 struct dcesrv_handle
*h
;
1685 struct samr_domain_state
*d_state
;
1686 struct ldb_message
**res
;
1687 int ldb_cnt
, count
, i
, first
;
1688 struct samr_SamEntry
*entries
;
1689 const char * const attrs
[3] = { "objectSid", "sAMAccountName", NULL
};
1690 struct samr_SamArray
*sam
;
1692 *r
->out
.resume_handle
= 0;
1694 *r
->out
.num_entries
= 0;
1696 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1700 /* search for all domain groups in this domain. This could possibly be
1701 cached and resumed based on resume_key */
1702 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1705 d_state
->domain_sid
,
1706 "(&(|(grouptype=%d)(grouptype=%d)))"
1707 "(objectclass=group))",
1708 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
1709 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1710 if (ldb_cnt
== -1) {
1711 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1714 return NT_STATUS_OK
;
1717 /* convert to SamEntry format */
1718 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, ldb_cnt
);
1720 return NT_STATUS_NO_MEMORY
;
1725 for (i
=0;i
<ldb_cnt
;i
++) {
1726 struct dom_sid
*alias_sid
;
1728 alias_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
1731 if (alias_sid
== NULL
)
1734 entries
[count
].idx
=
1735 alias_sid
->sub_auths
[alias_sid
->num_auths
-1];
1736 entries
[count
].name
.string
=
1737 samdb_result_string(res
[i
], "sAMAccountName", "");
1741 /* sort the results by rid */
1742 TYPESAFE_QSORT(entries
, count
, compare_SamEntry
);
1744 /* find the first entry to return */
1746 first
<count
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1749 if (first
== count
) {
1750 return NT_STATUS_OK
;
1753 *r
->out
.num_entries
= count
- first
;
1754 *r
->out
.num_entries
= MIN(*r
->out
.num_entries
, 1000);
1756 sam
= talloc(mem_ctx
, struct samr_SamArray
);
1758 return NT_STATUS_NO_MEMORY
;
1761 sam
->entries
= entries
+first
;
1762 sam
->count
= *r
->out
.num_entries
;
1766 if (*r
->out
.num_entries
< count
- first
) {
1767 *r
->out
.resume_handle
=
1768 entries
[first
+*r
->out
.num_entries
-1].idx
;
1769 return STATUS_MORE_ENTRIES
;
1772 return NT_STATUS_OK
;
1777 samr_GetAliasMembership
1779 static NTSTATUS
dcesrv_samr_GetAliasMembership(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1780 struct samr_GetAliasMembership
*r
)
1782 struct dcesrv_handle
*h
;
1783 struct samr_domain_state
*d_state
;
1784 struct ldb_message
**res
;
1787 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1791 if (r
->in
.sids
->num_sids
> 0) {
1793 const char * const attrs
[2] = { "objectSid", NULL
};
1795 filter
= talloc_asprintf(mem_ctx
,
1796 "(&(|(grouptype=%d)(grouptype=%d))"
1797 "(objectclass=group)(|",
1798 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
1799 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1801 return NT_STATUS_NO_MEMORY
;
1803 for (i
=0; i
<r
->in
.sids
->num_sids
; i
++) {
1804 const char *memberdn
;
1807 samdb_search_string(d_state
->sam_ctx
,
1809 "distinguishedName",
1811 ldap_encode_ndr_dom_sid(mem_ctx
,
1812 r
->in
.sids
->sids
[i
].sid
));
1814 if (memberdn
== NULL
)
1817 filter
= talloc_asprintf(mem_ctx
, "%s(member=%s)",
1820 return NT_STATUS_NO_MEMORY
;
1823 count
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1824 d_state
->domain_dn
, &res
, attrs
,
1825 d_state
->domain_sid
, "%s))", filter
);
1827 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1830 r
->out
.rids
->count
= 0;
1831 r
->out
.rids
->ids
= talloc_array(mem_ctx
, uint32_t, count
);
1832 if (r
->out
.rids
->ids
== NULL
)
1833 return NT_STATUS_NO_MEMORY
;
1835 for (i
=0; i
<count
; i
++) {
1836 struct dom_sid
*alias_sid
;
1838 alias_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
], "objectSid");
1840 if (alias_sid
== NULL
) {
1841 DEBUG(0, ("Could not find objectSid\n"));
1845 r
->out
.rids
->ids
[r
->out
.rids
->count
] =
1846 alias_sid
->sub_auths
[alias_sid
->num_auths
-1];
1847 r
->out
.rids
->count
+= 1;
1850 return NT_STATUS_OK
;
1857 static NTSTATUS
dcesrv_samr_LookupNames(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1858 struct samr_LookupNames
*r
)
1860 struct dcesrv_handle
*h
;
1861 struct samr_domain_state
*d_state
;
1863 NTSTATUS status
= NT_STATUS_OK
;
1864 const char * const attrs
[] = { "sAMAccountType", "objectSid", NULL
};
1867 ZERO_STRUCTP(r
->out
.rids
);
1868 ZERO_STRUCTP(r
->out
.types
);
1870 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1874 if (r
->in
.num_names
== 0) {
1875 return NT_STATUS_OK
;
1878 r
->out
.rids
->ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_names
);
1879 r
->out
.types
->ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_names
);
1880 if (!r
->out
.rids
->ids
|| !r
->out
.types
->ids
) {
1881 return NT_STATUS_NO_MEMORY
;
1883 r
->out
.rids
->count
= r
->in
.num_names
;
1884 r
->out
.types
->count
= r
->in
.num_names
;
1888 for (i
=0;i
<r
->in
.num_names
;i
++) {
1889 struct ldb_message
**res
;
1890 struct dom_sid
*sid
;
1891 uint32_t atype
, rtype
;
1893 r
->out
.rids
->ids
[i
] = 0;
1894 r
->out
.types
->ids
[i
] = SID_NAME_UNKNOWN
;
1896 count
= gendb_search(d_state
->sam_ctx
, mem_ctx
, d_state
->domain_dn
, &res
, attrs
,
1897 "sAMAccountName=%s",
1898 ldb_binary_encode_string(mem_ctx
, r
->in
.names
[i
].string
));
1900 status
= STATUS_SOME_UNMAPPED
;
1904 sid
= samdb_result_dom_sid(mem_ctx
, res
[0], "objectSid");
1906 status
= STATUS_SOME_UNMAPPED
;
1910 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
1912 status
= STATUS_SOME_UNMAPPED
;
1916 rtype
= ds_atype_map(atype
);
1918 if (rtype
== SID_NAME_UNKNOWN
) {
1919 status
= STATUS_SOME_UNMAPPED
;
1923 r
->out
.rids
->ids
[i
] = sid
->sub_auths
[sid
->num_auths
-1];
1924 r
->out
.types
->ids
[i
] = rtype
;
1928 if (num_mapped
== 0) {
1929 return NT_STATUS_NONE_MAPPED
;
1938 static NTSTATUS
dcesrv_samr_LookupRids(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1939 struct samr_LookupRids
*r
)
1941 struct dcesrv_handle
*h
;
1942 struct samr_domain_state
*d_state
;
1944 NTSTATUS status
= NT_STATUS_OK
;
1945 struct lsa_String
*names
;
1948 ZERO_STRUCTP(r
->out
.names
);
1949 ZERO_STRUCTP(r
->out
.types
);
1951 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1955 if (r
->in
.num_rids
== 0)
1956 return NT_STATUS_OK
;
1958 names
= talloc_array(mem_ctx
, struct lsa_String
, r
->in
.num_rids
);
1959 ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_rids
);
1961 if ((names
== NULL
) || (ids
== NULL
))
1962 return NT_STATUS_NO_MEMORY
;
1964 for (i
=0; i
<r
->in
.num_rids
; i
++) {
1965 struct ldb_message
**res
;
1967 const char * const attrs
[] = { "sAMAccountType",
1968 "sAMAccountName", NULL
};
1970 struct dom_sid
*sid
;
1972 ids
[i
] = SID_NAME_UNKNOWN
;
1974 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
,
1977 names
[i
].string
= NULL
;
1978 status
= STATUS_SOME_UNMAPPED
;
1982 count
= gendb_search(d_state
->sam_ctx
, mem_ctx
,
1983 d_state
->domain_dn
, &res
, attrs
,
1985 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
1987 names
[i
].string
= NULL
;
1988 status
= STATUS_SOME_UNMAPPED
;
1992 names
[i
].string
= samdb_result_string(res
[0], "sAMAccountName",
1995 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
1997 status
= STATUS_SOME_UNMAPPED
;
2001 ids
[i
] = ds_atype_map(atype
);
2003 if (ids
[i
] == SID_NAME_UNKNOWN
) {
2004 status
= STATUS_SOME_UNMAPPED
;
2009 r
->out
.names
->names
= names
;
2010 r
->out
.names
->count
= r
->in
.num_rids
;
2012 r
->out
.types
->ids
= ids
;
2013 r
->out
.types
->count
= r
->in
.num_rids
;
2022 static NTSTATUS
dcesrv_samr_OpenGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2023 struct samr_OpenGroup
*r
)
2025 struct samr_domain_state
*d_state
;
2026 struct samr_account_state
*a_state
;
2027 struct dcesrv_handle
*h
;
2028 const char *groupname
;
2029 struct dom_sid
*sid
;
2030 struct ldb_message
**msgs
;
2031 struct dcesrv_handle
*g_handle
;
2032 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2035 ZERO_STRUCTP(r
->out
.group_handle
);
2037 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2041 /* form the group SID */
2042 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2044 return NT_STATUS_NO_MEMORY
;
2047 /* search for the group record */
2048 ret
= gendb_search(d_state
->sam_ctx
,
2049 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2050 "(&(objectSid=%s)(objectClass=group)"
2051 "(|(groupType=%d)(groupType=%d)))",
2052 ldap_encode_ndr_dom_sid(mem_ctx
, sid
),
2053 GTYPE_SECURITY_UNIVERSAL_GROUP
,
2054 GTYPE_SECURITY_GLOBAL_GROUP
);
2056 return NT_STATUS_NO_SUCH_GROUP
;
2059 DEBUG(0,("Found %d records matching sid %s\n",
2060 ret
, dom_sid_string(mem_ctx
, sid
)));
2061 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2064 groupname
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2065 if (groupname
== NULL
) {
2066 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2067 dom_sid_string(mem_ctx
, sid
)));
2068 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2071 a_state
= talloc(mem_ctx
, struct samr_account_state
);
2073 return NT_STATUS_NO_MEMORY
;
2075 a_state
->sam_ctx
= d_state
->sam_ctx
;
2076 a_state
->access_mask
= r
->in
.access_mask
;
2077 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2078 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2079 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2080 a_state
->account_name
= talloc_strdup(a_state
, groupname
);
2081 if (!a_state
->account_name
) {
2082 return NT_STATUS_NO_MEMORY
;
2085 /* create the policy handle */
2086 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_GROUP
);
2088 return NT_STATUS_NO_MEMORY
;
2091 g_handle
->data
= talloc_steal(g_handle
, a_state
);
2093 *r
->out
.group_handle
= g_handle
->wire_handle
;
2095 return NT_STATUS_OK
;
2101 static NTSTATUS
dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2102 struct samr_QueryGroupInfo
*r
)
2104 struct dcesrv_handle
*h
;
2105 struct samr_account_state
*a_state
;
2106 struct ldb_message
*msg
;
2107 struct ldb_result
*res
;
2108 const char * const attrs
[4] = { "sAMAccountName", "description",
2109 "numMembers", NULL
};
2111 union samr_GroupInfo
*info
;
2113 *r
->out
.info
= NULL
;
2115 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2119 ret
= ldb_search(a_state
->sam_ctx
, mem_ctx
, &res
, a_state
->account_dn
,
2120 LDB_SCOPE_SUBTREE
, attrs
, "objectClass=*");
2122 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
2123 return NT_STATUS_NO_SUCH_GROUP
;
2124 } else if (ret
!= LDB_SUCCESS
) {
2125 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state
->sam_ctx
)));
2126 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2129 if (res
->count
!= 1) {
2130 DEBUG(2, ("Error finding group info, got %d entries\n", res
->count
));
2132 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2136 /* allocate the info structure */
2137 info
= talloc_zero(mem_ctx
, union samr_GroupInfo
);
2139 return NT_STATUS_NO_MEMORY
;
2142 /* Fill in the level */
2143 switch (r
->in
.level
) {
2145 QUERY_STRING(msg
, all
.name
, "sAMAccountName");
2146 info
->all
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2147 QUERY_UINT (msg
, all
.num_members
, "numMembers")
2148 QUERY_STRING(msg
, all
.description
, "description");
2151 QUERY_STRING(msg
, name
, "sAMAccountName");
2153 case GROUPINFOATTRIBUTES
:
2154 info
->attributes
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2156 case GROUPINFODESCRIPTION
:
2157 QUERY_STRING(msg
, description
, "description");
2160 QUERY_STRING(msg
, all2
.name
, "sAMAccountName");
2161 info
->all
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2162 QUERY_UINT (msg
, all2
.num_members
, "numMembers")
2163 QUERY_STRING(msg
, all2
.description
, "description");
2167 return NT_STATUS_INVALID_INFO_CLASS
;
2170 *r
->out
.info
= info
;
2172 return NT_STATUS_OK
;
2179 static NTSTATUS
dcesrv_samr_SetGroupInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2180 struct samr_SetGroupInfo
*r
)
2182 struct dcesrv_handle
*h
;
2183 struct samr_account_state
*g_state
;
2184 struct ldb_message
*msg
;
2185 struct ldb_context
*sam_ctx
;
2188 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2191 sam_ctx
= g_state
->sam_ctx
;
2193 msg
= ldb_msg_new(mem_ctx
);
2195 return NT_STATUS_NO_MEMORY
;
2198 msg
->dn
= ldb_dn_copy(mem_ctx
, g_state
->account_dn
);
2200 return NT_STATUS_NO_MEMORY
;
2203 switch (r
->in
.level
) {
2204 case GROUPINFODESCRIPTION
:
2205 SET_STRING(msg
, description
, "description");
2208 /* On W2k3 this does not change the name, it changes the
2209 * sAMAccountName attribute */
2210 SET_STRING(msg
, name
, "sAMAccountName");
2212 case GROUPINFOATTRIBUTES
:
2213 /* This does not do anything obviously visible in W2k3 LDAP */
2214 return NT_STATUS_OK
;
2216 return NT_STATUS_INVALID_INFO_CLASS
;
2219 /* modify the samdb record */
2220 ret
= ldb_modify(g_state
->sam_ctx
, msg
);
2221 if (ret
!= LDB_SUCCESS
) {
2222 /* we really need samdb.c to return NTSTATUS */
2223 return NT_STATUS_UNSUCCESSFUL
;
2226 return NT_STATUS_OK
;
2233 static NTSTATUS
dcesrv_samr_AddGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2234 struct samr_AddGroupMember
*r
)
2236 struct dcesrv_handle
*h
;
2237 struct samr_account_state
*a_state
;
2238 struct samr_domain_state
*d_state
;
2239 struct ldb_message
*mod
;
2240 struct dom_sid
*membersid
;
2241 const char *memberdn
;
2242 struct ldb_result
*res
;
2243 const char * const attrs
[] = { NULL
};
2246 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2249 d_state
= a_state
->domain_state
;
2251 membersid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2252 if (membersid
== NULL
) {
2253 return NT_STATUS_NO_MEMORY
;
2256 /* In native mode, AD can also nest domain groups. Not sure yet
2257 * whether this is also available via RPC. */
2258 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
,
2259 d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
,
2260 "(&(objectSid=%s)(objectclass=user))",
2261 ldap_encode_ndr_dom_sid(mem_ctx
, membersid
));
2263 if (ret
!= LDB_SUCCESS
) {
2264 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2267 if (res
->count
== 0) {
2268 return NT_STATUS_NO_SUCH_USER
;
2271 if (res
->count
> 1) {
2272 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2275 memberdn
= ldb_dn_alloc_linearized(mem_ctx
, res
->msgs
[0]->dn
);
2277 if (memberdn
== NULL
)
2278 return NT_STATUS_NO_MEMORY
;
2280 mod
= ldb_msg_new(mem_ctx
);
2282 return NT_STATUS_NO_MEMORY
;
2285 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2287 ret
= samdb_msg_add_addval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2289 if (ret
!= LDB_SUCCESS
) {
2290 return NT_STATUS_UNSUCCESSFUL
;
2293 ret
= ldb_modify(a_state
->sam_ctx
, mod
);
2296 return NT_STATUS_OK
;
2297 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
:
2298 return NT_STATUS_MEMBER_IN_GROUP
;
2299 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
2300 return NT_STATUS_ACCESS_DENIED
;
2302 return NT_STATUS_UNSUCCESSFUL
;
2308 samr_DeleteDomainGroup
2310 static NTSTATUS
dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2311 struct samr_DeleteDomainGroup
*r
)
2313 struct dcesrv_handle
*h
;
2314 struct samr_account_state
*a_state
;
2317 *r
->out
.group_handle
= *r
->in
.group_handle
;
2319 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2323 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2324 if (ret
!= LDB_SUCCESS
) {
2325 return NT_STATUS_UNSUCCESSFUL
;
2329 ZERO_STRUCTP(r
->out
.group_handle
);
2331 return NT_STATUS_OK
;
2336 samr_DeleteGroupMember
2338 static NTSTATUS
dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2339 struct samr_DeleteGroupMember
*r
)
2341 struct dcesrv_handle
*h
;
2342 struct samr_account_state
*a_state
;
2343 struct samr_domain_state
*d_state
;
2344 struct ldb_message
*mod
;
2345 struct dom_sid
*membersid
;
2346 const char *memberdn
;
2347 struct ldb_result
*res
;
2348 const char * const attrs
[] = { NULL
};
2351 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2354 d_state
= a_state
->domain_state
;
2356 membersid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2357 if (membersid
== NULL
)
2358 return NT_STATUS_NO_MEMORY
;
2360 /* In native mode, AD can also nest domain groups. Not sure yet
2361 * whether this is also available via RPC. */
2362 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
,
2363 d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
,
2364 "(&(objectSid=%s)(objectclass=user))",
2365 ldap_encode_ndr_dom_sid(mem_ctx
, membersid
));
2367 if (ret
!= LDB_SUCCESS
) {
2368 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2371 if (res
->count
== 0) {
2372 return NT_STATUS_NO_SUCH_USER
;
2375 if (res
->count
> 1) {
2376 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2379 memberdn
= ldb_dn_alloc_linearized(mem_ctx
, res
->msgs
[0]->dn
);
2381 if (memberdn
== NULL
)
2382 return NT_STATUS_NO_MEMORY
;
2384 mod
= ldb_msg_new(mem_ctx
);
2386 return NT_STATUS_NO_MEMORY
;
2389 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2391 ret
= samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2393 if (ret
!= LDB_SUCCESS
) {
2394 return NT_STATUS_NO_MEMORY
;
2397 ret
= ldb_modify(a_state
->sam_ctx
, mod
);
2400 return NT_STATUS_OK
;
2401 case LDB_ERR_NO_SUCH_ATTRIBUTE
:
2402 return NT_STATUS_MEMBER_NOT_IN_GROUP
;
2403 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
2404 return NT_STATUS_ACCESS_DENIED
;
2406 return NT_STATUS_UNSUCCESSFUL
;
2412 samr_QueryGroupMember
2414 static NTSTATUS
dcesrv_samr_QueryGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2415 struct samr_QueryGroupMember
*r
)
2417 struct dcesrv_handle
*h
;
2418 struct samr_account_state
*a_state
;
2419 struct ldb_message
**res
;
2420 struct ldb_message_element
*el
;
2421 struct samr_RidTypeArray
*array
;
2422 const char * const attrs
[2] = { "member", NULL
};
2425 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2429 /* pull the member attribute */
2430 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2431 a_state
->account_dn
, &res
, attrs
);
2434 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2437 array
= talloc(mem_ctx
, struct samr_RidTypeArray
);
2440 return NT_STATUS_NO_MEMORY
;
2442 ZERO_STRUCTP(array
);
2444 el
= ldb_msg_find_element(res
[0], "member");
2449 array
->count
= el
->num_values
;
2451 array
->rids
= talloc_array(mem_ctx
, uint32_t,
2453 if (array
->rids
== NULL
)
2454 return NT_STATUS_NO_MEMORY
;
2456 array
->types
= talloc_array(mem_ctx
, uint32_t,
2458 if (array
->types
== NULL
)
2459 return NT_STATUS_NO_MEMORY
;
2461 for (i
=0; i
<el
->num_values
; i
++) {
2462 struct ldb_message
**res2
;
2463 const char * const attrs2
[2] = { "objectSid", NULL
};
2464 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2465 ldb_dn_from_ldb_val(mem_ctx
, a_state
->sam_ctx
, &el
->values
[i
]),
2468 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2471 samdb_result_rid_from_sid(mem_ctx
, res2
[0],
2474 if (array
->rids
[i
] == 0)
2475 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2477 array
->types
[i
] = 7; /* RID type of some kind, not sure what the value means. */
2481 *r
->out
.rids
= array
;
2483 return NT_STATUS_OK
;
2488 samr_SetMemberAttributesOfGroup
2490 static NTSTATUS
dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2491 struct samr_SetMemberAttributesOfGroup
*r
)
2493 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
2500 static NTSTATUS
dcesrv_samr_OpenAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2501 struct samr_OpenAlias
*r
)
2503 struct samr_domain_state
*d_state
;
2504 struct samr_account_state
*a_state
;
2505 struct dcesrv_handle
*h
;
2506 const char *alias_name
;
2507 struct dom_sid
*sid
;
2508 struct ldb_message
**msgs
;
2509 struct dcesrv_handle
*g_handle
;
2510 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2513 ZERO_STRUCTP(r
->out
.alias_handle
);
2515 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2519 /* form the alias SID */
2520 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2522 return NT_STATUS_NO_MEMORY
;
2524 /* search for the group record */
2525 ret
= gendb_search(d_state
->sam_ctx
,
2526 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2527 "(&(objectSid=%s)(objectclass=group)"
2528 "(|(grouptype=%d)(grouptype=%d)))",
2529 ldap_encode_ndr_dom_sid(mem_ctx
, sid
),
2530 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
2531 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
2533 return NT_STATUS_NO_SUCH_ALIAS
;
2536 DEBUG(0,("Found %d records matching sid %s\n",
2537 ret
, dom_sid_string(mem_ctx
, sid
)));
2538 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2541 alias_name
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2542 if (alias_name
== NULL
) {
2543 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2544 dom_sid_string(mem_ctx
, sid
)));
2545 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2548 a_state
= talloc(mem_ctx
, struct samr_account_state
);
2550 return NT_STATUS_NO_MEMORY
;
2552 a_state
->sam_ctx
= d_state
->sam_ctx
;
2553 a_state
->access_mask
= r
->in
.access_mask
;
2554 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2555 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2556 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2557 a_state
->account_name
= talloc_strdup(a_state
, alias_name
);
2558 if (!a_state
->account_name
) {
2559 return NT_STATUS_NO_MEMORY
;
2562 /* create the policy handle */
2563 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_ALIAS
);
2565 return NT_STATUS_NO_MEMORY
;
2568 g_handle
->data
= talloc_steal(g_handle
, a_state
);
2570 *r
->out
.alias_handle
= g_handle
->wire_handle
;
2572 return NT_STATUS_OK
;
2579 static NTSTATUS
dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2580 struct samr_QueryAliasInfo
*r
)
2582 struct dcesrv_handle
*h
;
2583 struct samr_account_state
*a_state
;
2584 struct ldb_message
*msg
, **res
;
2585 const char * const attrs
[4] = { "sAMAccountName", "description",
2586 "numMembers", NULL
};
2588 union samr_AliasInfo
*info
;
2590 *r
->out
.info
= NULL
;
2592 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2596 /* pull all the alias attributes */
2597 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2598 a_state
->account_dn
,&res
, attrs
);
2600 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2604 /* allocate the info structure */
2605 info
= talloc_zero(mem_ctx
, union samr_AliasInfo
);
2607 return NT_STATUS_NO_MEMORY
;
2610 switch(r
->in
.level
) {
2612 QUERY_STRING(msg
, all
.name
, "sAMAccountName");
2613 QUERY_UINT (msg
, all
.num_members
, "numMembers");
2614 QUERY_STRING(msg
, all
.description
, "description");
2617 QUERY_STRING(msg
, name
, "sAMAccountName");
2619 case ALIASINFODESCRIPTION
:
2620 QUERY_STRING(msg
, description
, "description");
2624 return NT_STATUS_INVALID_INFO_CLASS
;
2627 *r
->out
.info
= info
;
2629 return NT_STATUS_OK
;
2636 static NTSTATUS
dcesrv_samr_SetAliasInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2637 struct samr_SetAliasInfo
*r
)
2639 struct dcesrv_handle
*h
;
2640 struct samr_account_state
*a_state
;
2641 struct ldb_message
*msg
;
2642 struct ldb_context
*sam_ctx
;
2645 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2648 sam_ctx
= a_state
->sam_ctx
;
2650 msg
= ldb_msg_new(mem_ctx
);
2652 return NT_STATUS_NO_MEMORY
;
2655 msg
->dn
= ldb_dn_copy(mem_ctx
, a_state
->account_dn
);
2657 return NT_STATUS_NO_MEMORY
;
2660 switch (r
->in
.level
) {
2661 case ALIASINFODESCRIPTION
:
2662 SET_STRING(msg
, description
, "description");
2665 /* On W2k3 this does not change the name, it changes the
2666 * sAMAccountName attribute */
2667 SET_STRING(msg
, name
, "sAMAccountName");
2670 return NT_STATUS_INVALID_INFO_CLASS
;
2673 /* modify the samdb record */
2674 ret
= ldb_modify(a_state
->sam_ctx
, msg
);
2675 if (ret
!= LDB_SUCCESS
) {
2676 /* we really need samdb.c to return NTSTATUS */
2677 return NT_STATUS_UNSUCCESSFUL
;
2680 return NT_STATUS_OK
;
2687 static NTSTATUS
dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2688 struct samr_DeleteDomAlias
*r
)
2690 struct dcesrv_handle
*h
;
2691 struct samr_account_state
*a_state
;
2694 *r
->out
.alias_handle
= *r
->in
.alias_handle
;
2696 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2700 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2701 if (ret
!= LDB_SUCCESS
) {
2702 return NT_STATUS_UNSUCCESSFUL
;
2706 ZERO_STRUCTP(r
->out
.alias_handle
);
2708 return NT_STATUS_OK
;
2715 static NTSTATUS
dcesrv_samr_AddAliasMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2716 struct samr_AddAliasMember
*r
)
2718 struct dcesrv_handle
*h
;
2719 struct samr_account_state
*a_state
;
2720 struct samr_domain_state
*d_state
;
2721 struct ldb_message
*mod
;
2722 struct ldb_message
**msgs
;
2723 const char * const attrs
[] = { NULL
};
2724 struct ldb_dn
*memberdn
= NULL
;
2728 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2731 d_state
= a_state
->domain_state
;
2733 ret
= gendb_search(d_state
->sam_ctx
, mem_ctx
, NULL
,
2734 &msgs
, attrs
, "(objectsid=%s)",
2735 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
2738 memberdn
= msgs
[0]->dn
;
2739 } else if (ret
> 1) {
2740 DEBUG(0,("Found %d records matching sid %s\n",
2741 ret
, dom_sid_string(mem_ctx
, r
->in
.sid
)));
2742 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2743 } else if (ret
== 0) {
2744 status
= samdb_create_foreign_security_principal(
2745 d_state
->sam_ctx
, mem_ctx
, r
->in
.sid
, &memberdn
);
2746 if (!NT_STATUS_IS_OK(status
)) {
2750 DEBUG(0, ("samdb_search returned %d: %s\n", ret
,
2751 ldb_errstring(d_state
->sam_ctx
)));
2754 if (memberdn
== NULL
) {
2755 DEBUG(0, ("Could not find memberdn\n"));
2756 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2759 mod
= ldb_msg_new(mem_ctx
);
2761 return NT_STATUS_NO_MEMORY
;
2764 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2766 ret
= samdb_msg_add_addval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2767 ldb_dn_alloc_linearized(mem_ctx
, memberdn
));
2768 if (ret
!= LDB_SUCCESS
) {
2769 return NT_STATUS_UNSUCCESSFUL
;
2772 if (ldb_modify(a_state
->sam_ctx
, mod
) != LDB_SUCCESS
) {
2773 return NT_STATUS_UNSUCCESSFUL
;
2776 return NT_STATUS_OK
;
2781 samr_DeleteAliasMember
2783 static NTSTATUS
dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2784 struct samr_DeleteAliasMember
*r
)
2786 struct dcesrv_handle
*h
;
2787 struct samr_account_state
*a_state
;
2788 struct samr_domain_state
*d_state
;
2789 struct ldb_message
*mod
;
2790 const char *memberdn
;
2793 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2796 d_state
= a_state
->domain_state
;
2798 memberdn
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
2799 "distinguishedName", "(objectSid=%s)",
2800 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
2802 if (memberdn
== NULL
)
2803 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2805 mod
= ldb_msg_new(mem_ctx
);
2807 return NT_STATUS_NO_MEMORY
;
2810 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2812 ret
= samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2814 if (ret
!= LDB_SUCCESS
)
2815 return NT_STATUS_UNSUCCESSFUL
;
2817 if (ldb_modify(a_state
->sam_ctx
, mod
) != LDB_SUCCESS
)
2818 return NT_STATUS_UNSUCCESSFUL
;
2820 return NT_STATUS_OK
;
2825 samr_GetMembersInAlias
2827 static NTSTATUS
dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2828 struct samr_GetMembersInAlias
*r
)
2830 struct dcesrv_handle
*h
;
2831 struct samr_account_state
*a_state
;
2832 struct samr_domain_state
*d_state
;
2833 struct ldb_message
**msgs
;
2834 struct lsa_SidPtr
*sids
;
2835 struct ldb_message_element
*el
;
2836 const char * const attrs
[2] = { "member", NULL
};
2839 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2842 d_state
= a_state
->domain_state
;
2844 ret
= gendb_search_dn(d_state
->sam_ctx
, mem_ctx
,
2845 a_state
->account_dn
, &msgs
, attrs
);
2848 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2849 } else if (ret
== 0) {
2850 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2851 } else if (ret
!= 1) {
2852 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2855 r
->out
.sids
->num_sids
= 0;
2856 r
->out
.sids
->sids
= NULL
;
2858 el
= ldb_msg_find_element(msgs
[0], "member");
2863 sids
= talloc_array(mem_ctx
, struct lsa_SidPtr
,
2867 return NT_STATUS_NO_MEMORY
;
2869 for (i
=0; i
<el
->num_values
; i
++) {
2870 struct ldb_message
**msgs2
;
2871 const char * const attrs2
[2] = { "objectSid", NULL
};
2872 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2873 ldb_dn_from_ldb_val(mem_ctx
, a_state
->sam_ctx
, &el
->values
[i
]),
2876 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2878 sids
[i
].sid
= samdb_result_dom_sid(mem_ctx
, msgs2
[0],
2881 if (sids
[i
].sid
== NULL
)
2882 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2884 r
->out
.sids
->num_sids
= el
->num_values
;
2885 r
->out
.sids
->sids
= sids
;
2888 return NT_STATUS_OK
;
2894 static NTSTATUS
dcesrv_samr_OpenUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2895 struct samr_OpenUser
*r
)
2897 struct samr_domain_state
*d_state
;
2898 struct samr_account_state
*a_state
;
2899 struct dcesrv_handle
*h
;
2900 const char *account_name
;
2901 struct dom_sid
*sid
;
2902 struct ldb_message
**msgs
;
2903 struct dcesrv_handle
*u_handle
;
2904 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2907 ZERO_STRUCTP(r
->out
.user_handle
);
2909 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2913 /* form the users SID */
2914 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2916 return NT_STATUS_NO_MEMORY
;
2919 /* search for the user record */
2920 ret
= gendb_search(d_state
->sam_ctx
,
2921 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2922 "(&(objectSid=%s)(objectclass=user))",
2923 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
2925 return NT_STATUS_NO_SUCH_USER
;
2928 DEBUG(0,("Found %d records matching sid %s\n", ret
,
2929 dom_sid_string(mem_ctx
, sid
)));
2930 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2933 account_name
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2934 if (account_name
== NULL
) {
2935 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2936 dom_sid_string(mem_ctx
, sid
)));
2937 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2940 a_state
= talloc(mem_ctx
, struct samr_account_state
);
2942 return NT_STATUS_NO_MEMORY
;
2944 a_state
->sam_ctx
= d_state
->sam_ctx
;
2945 a_state
->access_mask
= r
->in
.access_mask
;
2946 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2947 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2948 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2949 a_state
->account_name
= talloc_strdup(a_state
, account_name
);
2950 if (!a_state
->account_name
) {
2951 return NT_STATUS_NO_MEMORY
;
2954 /* create the policy handle */
2955 u_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_USER
);
2957 return NT_STATUS_NO_MEMORY
;
2960 u_handle
->data
= talloc_steal(u_handle
, a_state
);
2962 *r
->out
.user_handle
= u_handle
->wire_handle
;
2964 return NT_STATUS_OK
;
2972 static NTSTATUS
dcesrv_samr_DeleteUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2973 struct samr_DeleteUser
*r
)
2975 struct dcesrv_handle
*h
;
2976 struct samr_account_state
*a_state
;
2979 *r
->out
.user_handle
= *r
->in
.user_handle
;
2981 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
2985 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2986 if (ret
!= LDB_SUCCESS
) {
2987 DEBUG(1, ("Failed to delete user: %s: %s\n",
2988 ldb_dn_get_linearized(a_state
->account_dn
),
2989 ldb_errstring(a_state
->sam_ctx
)));
2990 return NT_STATUS_UNSUCCESSFUL
;
2994 ZERO_STRUCTP(r
->out
.user_handle
);
2996 return NT_STATUS_OK
;
3003 static NTSTATUS
dcesrv_samr_QueryUserInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3004 struct samr_QueryUserInfo
*r
)
3006 struct dcesrv_handle
*h
;
3007 struct samr_account_state
*a_state
;
3008 struct ldb_message
*msg
, **res
;
3010 struct ldb_context
*sam_ctx
;
3012 const char * const *attrs
= NULL
;
3013 union samr_UserInfo
*info
;
3015 *r
->out
.info
= NULL
;
3017 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3020 sam_ctx
= a_state
->sam_ctx
;
3022 /* fill in the reply */
3023 switch (r
->in
.level
) {
3026 static const char * const attrs2
[] = {"sAMAccountName",
3037 static const char * const attrs2
[] = {"comment",
3046 static const char * const attrs2
[] = {"sAMAccountName",
3061 "userAccountControl",
3068 static const char * const attrs2
[] = {"logonHours",
3075 static const char * const attrs2
[] = {"sAMAccountName",
3092 "userAccountControl",
3099 static const char * const attrs2
[] = {"sAMAccountName",
3107 static const char * const attrs2
[] = {"sAMAccountName",
3114 static const char * const attrs2
[] = {"displayName",
3121 static const char * const attrs2
[] = {"primaryGroupID",
3128 static const char * const attrs2
[] = {"homeDirectory",
3136 static const char * const attrs2
[] = {"scriptPath",
3143 static const char * const attrs2
[] = {"profilePath",
3150 static const char * const attrs2
[] = {"description",
3157 static const char * const attrs2
[] = {"userWorkstations",
3164 static const char * const attrs2
[] = {"userAccountControl",
3172 static const char * const attrs2
[] = {"accountExpires",
3179 return NT_STATUS_NOT_SUPPORTED
;
3183 static const char * const attrs2
[] = {"userParameters",
3190 static const char * const attrs2
[] = {"lastLogon",
3206 "userAccountControl",
3221 return NT_STATUS_NOT_SUPPORTED
;
3225 return NT_STATUS_INVALID_INFO_CLASS
;
3229 /* pull all the user attributes */
3230 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
3231 a_state
->account_dn
,&res
, attrs
);
3233 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3237 /* allocate the info structure */
3238 info
= talloc_zero(mem_ctx
, union samr_UserInfo
);
3240 return NT_STATUS_NO_MEMORY
;
3243 /* fill in the reply */
3244 switch (r
->in
.level
) {
3246 QUERY_STRING(msg
, info1
.account_name
, "sAMAccountName");
3247 QUERY_STRING(msg
, info1
.full_name
, "displayName");
3248 QUERY_UINT (msg
, info1
.primary_gid
, "primaryGroupID");
3249 QUERY_STRING(msg
, info1
.description
, "description");
3250 QUERY_STRING(msg
, info1
.comment
, "comment");
3254 QUERY_STRING(msg
, info2
.comment
, "comment");
3255 QUERY_UINT (msg
, info2
.country_code
, "countryCode");
3256 QUERY_UINT (msg
, info2
.code_page
, "codePage");
3260 QUERY_STRING(msg
, info3
.account_name
, "sAMAccountName");
3261 QUERY_STRING(msg
, info3
.full_name
, "displayName");
3262 QUERY_RID (msg
, info3
.rid
, "objectSid");
3263 QUERY_UINT (msg
, info3
.primary_gid
, "primaryGroupID");
3264 QUERY_STRING(msg
, info3
.home_directory
, "homeDirectory");
3265 QUERY_STRING(msg
, info3
.home_drive
, "homeDrive");
3266 QUERY_STRING(msg
, info3
.logon_script
, "scriptPath");
3267 QUERY_STRING(msg
, info3
.profile_path
, "profilePath");
3268 QUERY_STRING(msg
, info3
.workstations
, "userWorkstations");
3269 QUERY_UINT64(msg
, info3
.last_logon
, "lastLogon");
3270 QUERY_UINT64(msg
, info3
.last_logoff
, "lastLogoff");
3271 QUERY_UINT64(msg
, info3
.last_password_change
, "pwdLastSet");
3272 QUERY_APASSC(msg
, info3
.allow_password_change
, "pwdLastSet");
3273 QUERY_FPASSC(msg
, info3
.force_password_change
, "pwdLastSet");
3274 QUERY_LHOURS(msg
, info3
.logon_hours
, "logonHours");
3275 QUERY_UINT (msg
, info3
.bad_password_count
, "badPwdCount");
3276 QUERY_UINT (msg
, info3
.logon_count
, "logonCount");
3277 QUERY_AFLAGS(msg
, info3
.acct_flags
, "userAccountControl");
3281 QUERY_LHOURS(msg
, info4
.logon_hours
, "logonHours");
3285 QUERY_STRING(msg
, info5
.account_name
, "sAMAccountName");
3286 QUERY_STRING(msg
, info5
.full_name
, "displayName");
3287 QUERY_RID (msg
, info5
.rid
, "objectSid");
3288 QUERY_UINT (msg
, info5
.primary_gid
, "primaryGroupID");
3289 QUERY_STRING(msg
, info5
.home_directory
, "homeDirectory");
3290 QUERY_STRING(msg
, info5
.home_drive
, "homeDrive");
3291 QUERY_STRING(msg
, info5
.logon_script
, "scriptPath");
3292 QUERY_STRING(msg
, info5
.profile_path
, "profilePath");
3293 QUERY_STRING(msg
, info5
.description
, "description");
3294 QUERY_STRING(msg
, info5
.workstations
, "userWorkstations");
3295 QUERY_UINT64(msg
, info5
.last_logon
, "lastLogon");
3296 QUERY_UINT64(msg
, info5
.last_logoff
, "lastLogoff");
3297 QUERY_LHOURS(msg
, info5
.logon_hours
, "logonHours");
3298 QUERY_UINT (msg
, info5
.bad_password_count
, "badPwdCount");
3299 QUERY_UINT (msg
, info5
.logon_count
, "logonCount");
3300 QUERY_UINT64(msg
, info5
.last_password_change
, "pwdLastSet");
3301 QUERY_UINT64(msg
, info5
.acct_expiry
, "accountExpires");
3302 QUERY_AFLAGS(msg
, info5
.acct_flags
, "userAccountControl");
3306 QUERY_STRING(msg
, info6
.account_name
, "sAMAccountName");
3307 QUERY_STRING(msg
, info6
.full_name
, "displayName");
3311 QUERY_STRING(msg
, info7
.account_name
, "sAMAccountName");
3315 QUERY_STRING(msg
, info8
.full_name
, "displayName");
3319 QUERY_UINT (msg
, info9
.primary_gid
, "primaryGroupID");
3323 QUERY_STRING(msg
, info10
.home_directory
,"homeDirectory");
3324 QUERY_STRING(msg
, info10
.home_drive
, "homeDrive");
3328 QUERY_STRING(msg
, info11
.logon_script
, "scriptPath");
3332 QUERY_STRING(msg
, info12
.profile_path
, "profilePath");
3336 QUERY_STRING(msg
, info13
.description
, "description");
3340 QUERY_STRING(msg
, info14
.workstations
, "userWorkstations");
3344 QUERY_AFLAGS(msg
, info16
.acct_flags
, "userAccountControl");
3348 QUERY_UINT64(msg
, info17
.acct_expiry
, "accountExpires");
3352 QUERY_PARAMETERS(msg
, info20
.parameters
, "userParameters");
3356 QUERY_UINT64(msg
, info21
.last_logon
, "lastLogon");
3357 QUERY_UINT64(msg
, info21
.last_logoff
, "lastLogoff");
3358 QUERY_UINT64(msg
, info21
.last_password_change
, "pwdLastSet");
3359 QUERY_UINT64(msg
, info21
.acct_expiry
, "accountExpires");
3360 QUERY_APASSC(msg
, info21
.allow_password_change
,"pwdLastSet");
3361 QUERY_FPASSC(msg
, info21
.force_password_change
,"pwdLastSet");
3362 QUERY_STRING(msg
, info21
.account_name
, "sAMAccountName");
3363 QUERY_STRING(msg
, info21
.full_name
, "displayName");
3364 QUERY_STRING(msg
, info21
.home_directory
, "homeDirectory");
3365 QUERY_STRING(msg
, info21
.home_drive
, "homeDrive");
3366 QUERY_STRING(msg
, info21
.logon_script
, "scriptPath");
3367 QUERY_STRING(msg
, info21
.profile_path
, "profilePath");
3368 QUERY_STRING(msg
, info21
.description
, "description");
3369 QUERY_STRING(msg
, info21
.workstations
, "userWorkstations");
3370 QUERY_STRING(msg
, info21
.comment
, "comment");
3371 QUERY_PARAMETERS(msg
, info21
.parameters
, "userParameters");
3372 QUERY_RID (msg
, info21
.rid
, "objectSid");
3373 QUERY_UINT (msg
, info21
.primary_gid
, "primaryGroupID");
3374 QUERY_AFLAGS(msg
, info21
.acct_flags
, "userAccountControl");
3375 info
->info21
.fields_present
= 0x00FFFFFF;
3376 QUERY_LHOURS(msg
, info21
.logon_hours
, "logonHours");
3377 QUERY_UINT (msg
, info21
.bad_password_count
, "badPwdCount");
3378 QUERY_UINT (msg
, info21
.logon_count
, "logonCount");
3379 QUERY_UINT (msg
, info21
.country_code
, "countryCode");
3380 QUERY_UINT (msg
, info21
.code_page
, "codePage");
3386 return NT_STATUS_INVALID_INFO_CLASS
;
3389 *r
->out
.info
= info
;
3391 return NT_STATUS_OK
;
3398 static NTSTATUS
dcesrv_samr_SetUserInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3399 struct samr_SetUserInfo
*r
)
3401 struct dcesrv_handle
*h
;
3402 struct samr_account_state
*a_state
;
3403 struct ldb_message
*msg
;
3405 NTSTATUS status
= NT_STATUS_OK
;
3406 struct ldb_context
*sam_ctx
;
3408 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3411 sam_ctx
= a_state
->sam_ctx
;
3413 msg
= ldb_msg_new(mem_ctx
);
3415 return NT_STATUS_NO_MEMORY
;
3418 msg
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
3420 return NT_STATUS_NO_MEMORY
;
3423 switch (r
->in
.level
) {
3425 SET_STRING(msg
, info2
.comment
, "comment");
3426 SET_UINT (msg
, info2
.country_code
, "countryCode");
3427 SET_UINT (msg
, info2
.code_page
, "codePage");
3431 SET_LHOURS(msg
, info4
.logon_hours
, "logonHours");
3435 SET_STRING(msg
, info6
.account_name
, "samAccountName");
3436 SET_STRING(msg
, info6
.full_name
, "displayName");
3440 SET_STRING(msg
, info7
.account_name
, "samAccountName");
3444 SET_STRING(msg
, info8
.full_name
, "displayName");
3448 SET_UINT(msg
, info9
.primary_gid
, "primaryGroupID");
3452 SET_STRING(msg
, info10
.home_directory
, "homeDirectory");
3453 SET_STRING(msg
, info10
.home_drive
, "homeDrive");
3457 SET_STRING(msg
, info11
.logon_script
, "scriptPath");
3461 SET_STRING(msg
, info12
.profile_path
, "profilePath");
3465 SET_STRING(msg
, info13
.description
, "description");
3469 SET_STRING(msg
, info14
.workstations
, "userWorkstations");
3473 SET_AFLAGS(msg
, info16
.acct_flags
, "userAccountControl");
3477 SET_UINT64(msg
, info17
.acct_expiry
, "accountExpires");
3481 SET_PARAMETERS(msg
, info20
.parameters
, "userParameters");
3485 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3486 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3487 SET_UINT64(msg
, info21
.acct_expiry
, "accountExpires");
3488 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3489 SET_STRING(msg
, info21
.account_name
, "samAccountName");
3490 IFSET(SAMR_FIELD_FULL_NAME
)
3491 SET_STRING(msg
, info21
.full_name
, "displayName");
3492 IFSET(SAMR_FIELD_HOME_DIRECTORY
)
3493 SET_STRING(msg
, info21
.home_directory
, "homeDirectory");
3494 IFSET(SAMR_FIELD_HOME_DRIVE
)
3495 SET_STRING(msg
, info21
.home_drive
, "homeDrive");
3496 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3497 SET_STRING(msg
, info21
.logon_script
, "scriptPath");
3498 IFSET(SAMR_FIELD_PROFILE_PATH
)
3499 SET_STRING(msg
, info21
.profile_path
, "profilePath");
3500 IFSET(SAMR_FIELD_DESCRIPTION
)
3501 SET_STRING(msg
, info21
.description
, "description");
3502 IFSET(SAMR_FIELD_WORKSTATIONS
)
3503 SET_STRING(msg
, info21
.workstations
, "userWorkstations");
3504 IFSET(SAMR_FIELD_COMMENT
)
3505 SET_STRING(msg
, info21
.comment
, "comment");
3506 IFSET(SAMR_FIELD_PARAMETERS
)
3507 SET_PARAMETERS(msg
, info21
.parameters
, "userParameters");
3508 IFSET(SAMR_FIELD_PRIMARY_GID
)
3509 SET_UINT(msg
, info21
.primary_gid
, "primaryGroupID");
3510 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3511 SET_AFLAGS(msg
, info21
.acct_flags
, "userAccountControl");
3512 IFSET(SAMR_FIELD_LOGON_HOURS
)
3513 SET_LHOURS(msg
, info21
.logon_hours
, "logonHours");
3514 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3515 SET_UINT (msg
, info21
.country_code
, "countryCode");
3516 IFSET(SAMR_FIELD_CODE_PAGE
)
3517 SET_UINT (msg
, info21
.code_page
, "codePage");
3522 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3523 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3524 SET_UINT64(msg
, info23
.info
.acct_expiry
, "accountExpires");
3525 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3526 SET_STRING(msg
, info23
.info
.account_name
, "samAccountName");
3527 IFSET(SAMR_FIELD_FULL_NAME
)
3528 SET_STRING(msg
, info23
.info
.full_name
, "displayName");
3529 IFSET(SAMR_FIELD_HOME_DIRECTORY
)
3530 SET_STRING(msg
, info23
.info
.home_directory
, "homeDirectory");
3531 IFSET(SAMR_FIELD_HOME_DRIVE
)
3532 SET_STRING(msg
, info23
.info
.home_drive
, "homeDrive");
3533 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3534 SET_STRING(msg
, info23
.info
.logon_script
, "scriptPath");
3535 IFSET(SAMR_FIELD_PROFILE_PATH
)
3536 SET_STRING(msg
, info23
.info
.profile_path
, "profilePath");
3537 IFSET(SAMR_FIELD_DESCRIPTION
)
3538 SET_STRING(msg
, info23
.info
.description
, "description");
3539 IFSET(SAMR_FIELD_WORKSTATIONS
)
3540 SET_STRING(msg
, info23
.info
.workstations
, "userWorkstations");
3541 IFSET(SAMR_FIELD_COMMENT
)
3542 SET_STRING(msg
, info23
.info
.comment
, "comment");
3543 IFSET(SAMR_FIELD_PARAMETERS
)
3544 SET_PARAMETERS(msg
, info23
.info
.parameters
, "userParameters");
3545 IFSET(SAMR_FIELD_PRIMARY_GID
)
3546 SET_UINT(msg
, info23
.info
.primary_gid
, "primaryGroupID");
3547 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3548 SET_AFLAGS(msg
, info23
.info
.acct_flags
, "userAccountControl");
3549 IFSET(SAMR_FIELD_LOGON_HOURS
)
3550 SET_LHOURS(msg
, info23
.info
.logon_hours
, "logonHours");
3551 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3552 SET_UINT (msg
, info23
.info
.country_code
, "countryCode");
3553 IFSET(SAMR_FIELD_CODE_PAGE
)
3554 SET_UINT (msg
, info23
.info
.code_page
, "codePage");
3556 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT
) {
3557 status
= samr_set_password(dce_call
,
3559 a_state
->account_dn
,
3560 a_state
->domain_state
->domain_dn
,
3562 &r
->in
.info
->info23
.password
);
3563 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT
) {
3564 status
= samr_set_password(dce_call
,
3566 a_state
->account_dn
,
3567 a_state
->domain_state
->domain_dn
,
3569 &r
->in
.info
->info23
.password
);
3574 /* the set password levels are handled separately */
3576 status
= samr_set_password(dce_call
,
3578 a_state
->account_dn
,
3579 a_state
->domain_state
->domain_dn
,
3581 &r
->in
.info
->info24
.password
);
3585 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3586 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3587 SET_UINT64(msg
, info25
.info
.acct_expiry
, "accountExpires");
3588 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3589 SET_STRING(msg
, info25
.info
.account_name
, "samAccountName");
3590 IFSET(SAMR_FIELD_FULL_NAME
)
3591 SET_STRING(msg
, info25
.info
.full_name
, "displayName");
3592 IFSET(SAMR_FIELD_HOME_DIRECTORY
)
3593 SET_STRING(msg
, info25
.info
.home_directory
, "homeDirectory");
3594 IFSET(SAMR_FIELD_HOME_DRIVE
)
3595 SET_STRING(msg
, info25
.info
.home_drive
, "homeDrive");
3596 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3597 SET_STRING(msg
, info25
.info
.logon_script
, "scriptPath");
3598 IFSET(SAMR_FIELD_PROFILE_PATH
)
3599 SET_STRING(msg
, info25
.info
.profile_path
, "profilePath");
3600 IFSET(SAMR_FIELD_DESCRIPTION
)
3601 SET_STRING(msg
, info25
.info
.description
, "description");
3602 IFSET(SAMR_FIELD_WORKSTATIONS
)
3603 SET_STRING(msg
, info25
.info
.workstations
, "userWorkstations");
3604 IFSET(SAMR_FIELD_COMMENT
)
3605 SET_STRING(msg
, info25
.info
.comment
, "comment");
3606 IFSET(SAMR_FIELD_PARAMETERS
)
3607 SET_PARAMETERS(msg
, info25
.info
.parameters
, "userParameters");
3608 IFSET(SAMR_FIELD_PRIMARY_GID
)
3609 SET_UINT(msg
, info25
.info
.primary_gid
, "primaryGroupID");
3610 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3611 SET_AFLAGS(msg
, info25
.info
.acct_flags
, "userAccountControl");
3612 IFSET(SAMR_FIELD_LOGON_HOURS
)
3613 SET_LHOURS(msg
, info25
.info
.logon_hours
, "logonHours");
3614 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3615 SET_UINT (msg
, info25
.info
.country_code
, "countryCode");
3616 IFSET(SAMR_FIELD_CODE_PAGE
)
3617 SET_UINT (msg
, info25
.info
.code_page
, "codePage");
3619 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT
) {
3620 status
= samr_set_password_ex(dce_call
,
3622 a_state
->account_dn
,
3623 a_state
->domain_state
->domain_dn
,
3625 &r
->in
.info
->info25
.password
);
3626 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT
) {
3627 status
= samr_set_password_ex(dce_call
,
3629 a_state
->account_dn
,
3630 a_state
->domain_state
->domain_dn
,
3632 &r
->in
.info
->info25
.password
);
3637 /* the set password levels are handled separately */
3639 status
= samr_set_password_ex(dce_call
,
3641 a_state
->account_dn
,
3642 a_state
->domain_state
->domain_dn
,
3644 &r
->in
.info
->info26
.password
);
3649 /* many info classes are not valid for SetUserInfo */
3650 return NT_STATUS_INVALID_INFO_CLASS
;
3653 if (!NT_STATUS_IS_OK(status
)) {
3657 /* modify the samdb record */
3658 if (msg
->num_elements
> 0) {
3659 ret
= ldb_modify(a_state
->sam_ctx
, msg
);
3660 if (ret
!= LDB_SUCCESS
) {
3661 DEBUG(1,("Failed to modify record %s: %s\n",
3662 ldb_dn_get_linearized(a_state
->account_dn
),
3663 ldb_errstring(a_state
->sam_ctx
)));
3665 /* we really need samdb.c to return NTSTATUS */
3666 return NT_STATUS_UNSUCCESSFUL
;
3670 return NT_STATUS_OK
;
3675 samr_GetGroupsForUser
3677 static NTSTATUS
dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3678 struct samr_GetGroupsForUser
*r
)
3680 struct dcesrv_handle
*h
;
3681 struct samr_account_state
*a_state
;
3682 struct samr_domain_state
*d_state
;
3683 struct ldb_message
**res
;
3684 const char * const attrs
[2] = { "objectSid", NULL
};
3685 struct samr_RidWithAttributeArray
*array
;
3688 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3691 d_state
= a_state
->domain_state
;
3693 count
= samdb_search_domain(a_state
->sam_ctx
, mem_ctx
,
3694 d_state
->domain_dn
, &res
,
3695 attrs
, d_state
->domain_sid
,
3696 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3697 ldb_dn_get_linearized(a_state
->account_dn
),
3698 GTYPE_SECURITY_GLOBAL_GROUP
);
3700 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3702 array
= talloc(mem_ctx
, struct samr_RidWithAttributeArray
);
3704 return NT_STATUS_NO_MEMORY
;
3709 array
->rids
= talloc_array(mem_ctx
, struct samr_RidWithAttribute
,
3711 if (array
->rids
== NULL
)
3712 return NT_STATUS_NO_MEMORY
;
3714 /* Adds the primary group */
3715 array
->rids
[0].rid
= samdb_search_uint(a_state
->sam_ctx
, mem_ctx
,
3716 ~0, a_state
->account_dn
,
3717 "primaryGroupID", NULL
);
3718 array
->rids
[0].attributes
= SE_GROUP_MANDATORY
3719 | SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3722 /* Adds the additional groups */
3723 for (i
= 0; i
< count
; i
++) {
3724 struct dom_sid
*group_sid
;
3726 group_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
], "objectSid");
3727 if (group_sid
== NULL
) {
3728 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3732 array
->rids
[i
+ 1].rid
=
3733 group_sid
->sub_auths
[group_sid
->num_auths
-1];
3734 array
->rids
[i
+ 1].attributes
= SE_GROUP_MANDATORY
3735 | SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3739 *r
->out
.rids
= array
;
3741 return NT_STATUS_OK
;
3746 samr_QueryDisplayInfo
3748 static NTSTATUS
dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3749 struct samr_QueryDisplayInfo
*r
)
3751 struct dcesrv_handle
*h
;
3752 struct samr_domain_state
*d_state
;
3753 struct ldb_message
**res
;
3754 int ldb_cnt
, count
, i
;
3755 const char * const attrs
[] = { "objectSid", "sAMAccountName",
3756 "displayName", "description", "userAccountControl",
3757 "pwdLastSet", NULL
};
3758 struct samr_DispEntryFull
*entriesFull
= NULL
;
3759 struct samr_DispEntryFullGroup
*entriesFullGroup
= NULL
;
3760 struct samr_DispEntryAscii
*entriesAscii
= NULL
;
3761 struct samr_DispEntryGeneral
*entriesGeneral
= NULL
;
3764 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
3768 switch (r
->in
.level
) {
3771 filter
= talloc_asprintf(mem_ctx
, "(&(objectclass=user)"
3772 "(sAMAccountType=%u))",
3773 ATYPE_NORMAL_ACCOUNT
);
3776 filter
= talloc_asprintf(mem_ctx
, "(&(objectclass=user)"
3777 "(sAMAccountType=%u))",
3778 ATYPE_WORKSTATION_TRUST
);
3782 filter
= talloc_asprintf(mem_ctx
,
3783 "(&(|(groupType=%d)(groupType=%d))"
3784 "(objectClass=group))",
3785 GTYPE_SECURITY_UNIVERSAL_GROUP
,
3786 GTYPE_SECURITY_GLOBAL_GROUP
);
3789 return NT_STATUS_INVALID_INFO_CLASS
;
3792 /* search for all requested objects in this domain. This could
3793 possibly be cached and resumed based on resume_key */
3794 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
3795 d_state
->domain_dn
, &res
, attrs
,
3796 d_state
->domain_sid
, "%s", filter
);
3797 if (ldb_cnt
== -1) {
3798 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3800 if (ldb_cnt
== 0 || r
->in
.max_entries
== 0) {
3801 return NT_STATUS_OK
;
3804 switch (r
->in
.level
) {
3806 entriesGeneral
= talloc_array(mem_ctx
,
3807 struct samr_DispEntryGeneral
,
3811 entriesFull
= talloc_array(mem_ctx
,
3812 struct samr_DispEntryFull
,
3816 entriesFullGroup
= talloc_array(mem_ctx
,
3817 struct samr_DispEntryFullGroup
,
3822 entriesAscii
= talloc_array(mem_ctx
,
3823 struct samr_DispEntryAscii
,
3828 if ((entriesGeneral
== NULL
) && (entriesFull
== NULL
) &&
3829 (entriesAscii
== NULL
) && (entriesFullGroup
== NULL
))
3830 return NT_STATUS_NO_MEMORY
;
3834 for (i
=0; i
<ldb_cnt
; i
++) {
3835 struct dom_sid
*objectsid
;
3837 objectsid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
3839 if (objectsid
== NULL
)
3842 switch(r
->in
.level
) {
3844 entriesGeneral
[count
].idx
= count
+ 1;
3845 entriesGeneral
[count
].rid
=
3846 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3847 entriesGeneral
[count
].acct_flags
=
3848 samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
,
3850 d_state
->domain_dn
);
3851 entriesGeneral
[count
].account_name
.string
=
3852 samdb_result_string(res
[i
],
3853 "sAMAccountName", "");
3854 entriesGeneral
[count
].full_name
.string
=
3855 samdb_result_string(res
[i
], "displayName", "");
3856 entriesGeneral
[count
].description
.string
=
3857 samdb_result_string(res
[i
], "description", "");
3860 entriesFull
[count
].idx
= count
+ 1;
3861 entriesFull
[count
].rid
=
3862 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3864 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3865 entriesFull
[count
].acct_flags
=
3866 samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
,
3868 d_state
->domain_dn
) | ACB_NORMAL
;
3869 entriesFull
[count
].account_name
.string
=
3870 samdb_result_string(res
[i
], "sAMAccountName",
3872 entriesFull
[count
].description
.string
=
3873 samdb_result_string(res
[i
], "description", "");
3876 entriesFullGroup
[count
].idx
= count
+ 1;
3877 entriesFullGroup
[count
].rid
=
3878 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3879 /* We get a "7" here for groups */
3880 entriesFullGroup
[count
].acct_flags
3881 = SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3882 entriesFullGroup
[count
].account_name
.string
=
3883 samdb_result_string(res
[i
], "sAMAccountName",
3885 entriesFullGroup
[count
].description
.string
=
3886 samdb_result_string(res
[i
], "description", "");
3890 entriesAscii
[count
].idx
= count
+ 1;
3891 entriesAscii
[count
].account_name
.string
=
3892 samdb_result_string(res
[i
], "sAMAccountName",
3900 *r
->out
.total_size
= count
;
3902 if (r
->in
.start_idx
>= count
) {
3903 *r
->out
.returned_size
= 0;
3904 switch(r
->in
.level
) {
3906 r
->out
.info
->info1
.count
= *r
->out
.returned_size
;
3907 r
->out
.info
->info1
.entries
= NULL
;
3910 r
->out
.info
->info2
.count
= *r
->out
.returned_size
;
3911 r
->out
.info
->info2
.entries
= NULL
;
3914 r
->out
.info
->info3
.count
= *r
->out
.returned_size
;
3915 r
->out
.info
->info3
.entries
= NULL
;
3918 r
->out
.info
->info4
.count
= *r
->out
.returned_size
;
3919 r
->out
.info
->info4
.entries
= NULL
;
3922 r
->out
.info
->info5
.count
= *r
->out
.returned_size
;
3923 r
->out
.info
->info5
.entries
= NULL
;
3927 *r
->out
.returned_size
= MIN(count
- r
->in
.start_idx
,
3929 switch(r
->in
.level
) {
3931 r
->out
.info
->info1
.count
= *r
->out
.returned_size
;
3932 r
->out
.info
->info1
.entries
=
3933 &(entriesGeneral
[r
->in
.start_idx
]);
3936 r
->out
.info
->info2
.count
= *r
->out
.returned_size
;
3937 r
->out
.info
->info2
.entries
=
3938 &(entriesFull
[r
->in
.start_idx
]);
3941 r
->out
.info
->info3
.count
= *r
->out
.returned_size
;
3942 r
->out
.info
->info3
.entries
=
3943 &(entriesFullGroup
[r
->in
.start_idx
]);
3946 r
->out
.info
->info4
.count
= *r
->out
.returned_size
;
3947 r
->out
.info
->info4
.entries
=
3948 &(entriesAscii
[r
->in
.start_idx
]);
3951 r
->out
.info
->info5
.count
= *r
->out
.returned_size
;
3952 r
->out
.info
->info5
.entries
=
3953 &(entriesAscii
[r
->in
.start_idx
]);
3958 return (*r
->out
.returned_size
< (count
- r
->in
.start_idx
)) ?
3959 STATUS_MORE_ENTRIES
: NT_STATUS_OK
;
3964 samr_GetDisplayEnumerationIndex
3966 static NTSTATUS
dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3967 struct samr_GetDisplayEnumerationIndex
*r
)
3969 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
3974 samr_TestPrivateFunctionsDomain
3976 static NTSTATUS
dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3977 struct samr_TestPrivateFunctionsDomain
*r
)
3979 return NT_STATUS_NOT_IMPLEMENTED
;
3984 samr_TestPrivateFunctionsUser
3986 static NTSTATUS
dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3987 struct samr_TestPrivateFunctionsUser
*r
)
3989 return NT_STATUS_NOT_IMPLEMENTED
;
3996 static NTSTATUS
dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3997 struct samr_GetUserPwInfo
*r
)
3999 struct dcesrv_handle
*h
;
4000 struct samr_account_state
*a_state
;
4002 ZERO_STRUCTP(r
->out
.info
);
4004 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
4008 r
->out
.info
->min_password_length
= samdb_search_uint(a_state
->sam_ctx
,
4009 mem_ctx
, 0, a_state
->domain_state
->domain_dn
, "minPwdLength",
4011 r
->out
.info
->password_properties
= samdb_search_uint(a_state
->sam_ctx
,
4012 mem_ctx
, 0, a_state
->account_dn
, "pwdProperties", NULL
);
4014 return NT_STATUS_OK
;
4019 samr_RemoveMemberFromForeignDomain
4021 static NTSTATUS
dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4022 struct samr_RemoveMemberFromForeignDomain
*r
)
4024 struct dcesrv_handle
*h
;
4025 struct samr_domain_state
*d_state
;
4026 const char *memberdn
;
4027 struct ldb_message
**res
;
4028 const char * const attrs
[3] = { "distinguishedName", "objectSid", NULL
};
4031 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
4035 memberdn
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
4036 "distinguishedName", "(objectSid=%s)",
4037 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
4039 if (memberdn
== NULL
) {
4040 return NT_STATUS_OK
;
4043 /* TODO: Does this call only remove alias members, or does it do this
4044 * for domain groups as well? */
4046 count
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
4047 d_state
->domain_dn
, &res
, attrs
,
4048 d_state
->domain_sid
,
4049 "(&(member=%s)(objectClass=group)"
4050 "(|(groupType=%d)(groupType=%d)))",
4052 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
4053 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
4056 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
4058 for (i
=0; i
<count
; i
++) {
4059 struct ldb_message
*mod
;
4061 mod
= ldb_msg_new(mem_ctx
);
4063 return NT_STATUS_NO_MEMORY
;
4066 mod
->dn
= samdb_result_dn(d_state
->sam_ctx
, mod
, res
[i
], "distinguishedName", NULL
);
4067 if (mod
->dn
== NULL
) {
4072 if (samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
,
4073 "member", memberdn
) != LDB_SUCCESS
)
4074 return NT_STATUS_NO_MEMORY
;
4076 if (ldb_modify(d_state
->sam_ctx
, mod
) != LDB_SUCCESS
)
4077 return NT_STATUS_UNSUCCESSFUL
;
4082 return NT_STATUS_OK
;
4087 samr_QueryDomainInfo2
4089 just an alias for samr_QueryDomainInfo
4091 static NTSTATUS
dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4092 struct samr_QueryDomainInfo2
*r
)
4094 struct samr_QueryDomainInfo r1
;
4097 ZERO_STRUCT(r1
.out
);
4098 r1
.in
.domain_handle
= r
->in
.domain_handle
;
4099 r1
.in
.level
= r
->in
.level
;
4100 r1
.out
.info
= r
->out
.info
;
4102 status
= dcesrv_samr_QueryDomainInfo(dce_call
, mem_ctx
, &r1
);
4111 just an alias for samr_QueryUserInfo
4113 static NTSTATUS
dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4114 struct samr_QueryUserInfo2
*r
)
4116 struct samr_QueryUserInfo r1
;
4119 r1
.in
.user_handle
= r
->in
.user_handle
;
4120 r1
.in
.level
= r
->in
.level
;
4121 r1
.out
.info
= r
->out
.info
;
4123 status
= dcesrv_samr_QueryUserInfo(dce_call
, mem_ctx
, &r1
);
4130 samr_QueryDisplayInfo2
4132 static NTSTATUS
dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4133 struct samr_QueryDisplayInfo2
*r
)
4135 struct samr_QueryDisplayInfo q
;
4138 q
.in
.domain_handle
= r
->in
.domain_handle
;
4139 q
.in
.level
= r
->in
.level
;
4140 q
.in
.start_idx
= r
->in
.start_idx
;
4141 q
.in
.max_entries
= r
->in
.max_entries
;
4142 q
.in
.buf_size
= r
->in
.buf_size
;
4143 q
.out
.total_size
= r
->out
.total_size
;
4144 q
.out
.returned_size
= r
->out
.returned_size
;
4145 q
.out
.info
= r
->out
.info
;
4147 result
= dcesrv_samr_QueryDisplayInfo(dce_call
, mem_ctx
, &q
);
4154 samr_GetDisplayEnumerationIndex2
4156 static NTSTATUS
dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4157 struct samr_GetDisplayEnumerationIndex2
*r
)
4159 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4164 samr_QueryDisplayInfo3
4166 static NTSTATUS
dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4167 struct samr_QueryDisplayInfo3
*r
)
4169 struct samr_QueryDisplayInfo q
;
4172 q
.in
.domain_handle
= r
->in
.domain_handle
;
4173 q
.in
.level
= r
->in
.level
;
4174 q
.in
.start_idx
= r
->in
.start_idx
;
4175 q
.in
.max_entries
= r
->in
.max_entries
;
4176 q
.in
.buf_size
= r
->in
.buf_size
;
4177 q
.out
.total_size
= r
->out
.total_size
;
4178 q
.out
.returned_size
= r
->out
.returned_size
;
4179 q
.out
.info
= r
->out
.info
;
4181 result
= dcesrv_samr_QueryDisplayInfo(dce_call
, mem_ctx
, &q
);
4188 samr_AddMultipleMembersToAlias
4190 static NTSTATUS
dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4191 struct samr_AddMultipleMembersToAlias
*r
)
4193 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4198 samr_RemoveMultipleMembersFromAlias
4200 static NTSTATUS
dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4201 struct samr_RemoveMultipleMembersFromAlias
*r
)
4203 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4210 this fetches the default password properties for a domain
4212 note that w2k3 completely ignores the domain name in this call, and
4213 always returns the information for the servers primary domain
4215 static NTSTATUS
dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4216 struct samr_GetDomPwInfo
*r
)
4218 struct ldb_message
**msgs
;
4220 const char * const attrs
[] = {"minPwdLength", "pwdProperties", NULL
};
4221 struct ldb_context
*sam_ctx
;
4223 ZERO_STRUCTP(r
->out
.info
);
4225 sam_ctx
= samdb_connect(mem_ctx
, dce_call
->event_ctx
,
4226 dce_call
->conn
->dce_ctx
->lp_ctx
,
4227 dce_call
->conn
->auth_state
.session_info
);
4228 if (sam_ctx
== NULL
) {
4229 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
4232 /* The domain name in this call is ignored */
4233 ret
= gendb_search_dn(sam_ctx
,
4234 mem_ctx
, NULL
, &msgs
, attrs
);
4236 talloc_free(sam_ctx
);
4238 return NT_STATUS_NO_SUCH_DOMAIN
;
4242 talloc_free(sam_ctx
);
4244 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
4247 r
->out
.info
->min_password_length
= samdb_result_uint(msgs
[0],
4249 r
->out
.info
->password_properties
= samdb_result_uint(msgs
[0],
4250 "pwdProperties", 1);
4253 talloc_unlink(mem_ctx
, sam_ctx
);
4255 return NT_STATUS_OK
;
4262 static NTSTATUS
dcesrv_samr_Connect2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4263 struct samr_Connect2
*r
)
4265 struct samr_Connect c
;
4267 c
.in
.system_name
= NULL
;
4268 c
.in
.access_mask
= r
->in
.access_mask
;
4269 c
.out
.connect_handle
= r
->out
.connect_handle
;
4271 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4278 just an alias for samr_SetUserInfo
4280 static NTSTATUS
dcesrv_samr_SetUserInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4281 struct samr_SetUserInfo2
*r
)
4283 struct samr_SetUserInfo r2
;
4285 r2
.in
.user_handle
= r
->in
.user_handle
;
4286 r2
.in
.level
= r
->in
.level
;
4287 r2
.in
.info
= r
->in
.info
;
4289 return dcesrv_samr_SetUserInfo(dce_call
, mem_ctx
, &r2
);
4294 samr_SetBootKeyInformation
4296 static NTSTATUS
dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4297 struct samr_SetBootKeyInformation
*r
)
4299 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4304 samr_GetBootKeyInformation
4306 static NTSTATUS
dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4307 struct samr_GetBootKeyInformation
*r
)
4309 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4316 static NTSTATUS
dcesrv_samr_Connect3(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4317 struct samr_Connect3
*r
)
4319 struct samr_Connect c
;
4321 c
.in
.system_name
= NULL
;
4322 c
.in
.access_mask
= r
->in
.access_mask
;
4323 c
.out
.connect_handle
= r
->out
.connect_handle
;
4325 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4332 static NTSTATUS
dcesrv_samr_Connect4(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4333 struct samr_Connect4
*r
)
4335 struct samr_Connect c
;
4337 c
.in
.system_name
= NULL
;
4338 c
.in
.access_mask
= r
->in
.access_mask
;
4339 c
.out
.connect_handle
= r
->out
.connect_handle
;
4341 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4348 static NTSTATUS
dcesrv_samr_Connect5(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4349 struct samr_Connect5
*r
)
4351 struct samr_Connect c
;
4354 c
.in
.system_name
= NULL
;
4355 c
.in
.access_mask
= r
->in
.access_mask
;
4356 c
.out
.connect_handle
= r
->out
.connect_handle
;
4358 status
= dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4360 r
->out
.info_out
->info1
.client_version
= SAMR_CONNECT_AFTER_W2K
;
4361 r
->out
.info_out
->info1
.unknown2
= 0;
4362 *r
->out
.level_out
= r
->in
.level_in
;
4371 static NTSTATUS
dcesrv_samr_RidToSid(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4372 struct samr_RidToSid
*r
)
4374 struct samr_domain_state
*d_state
;
4375 struct dcesrv_handle
*h
;
4377 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
4381 /* form the users SID */
4382 *r
->out
.sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
4384 return NT_STATUS_NO_MEMORY
;
4387 return NT_STATUS_OK
;
4392 samr_SetDsrmPassword
4394 static NTSTATUS
dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4395 struct samr_SetDsrmPassword
*r
)
4397 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4402 samr_ValidatePassword
4404 For now the call checks the password complexity (if active) and the minimum
4405 password length on level 2 and 3. Level 1 is ignored for now.
4407 static NTSTATUS
dcesrv_samr_ValidatePassword(struct dcesrv_call_state
*dce_call
,
4408 TALLOC_CTX
*mem_ctx
,
4409 struct samr_ValidatePassword
*r
)
4411 struct samr_GetDomPwInfo r2
;
4412 struct samr_PwInfo pwInfo
;
4414 enum samr_ValidationStatus res
;
4417 (*r
->out
.rep
) = talloc_zero(mem_ctx
, union samr_ValidatePasswordRep
);
4419 r2
.in
.domain_name
= NULL
;
4420 r2
.out
.info
= &pwInfo
;
4421 status
= dcesrv_samr_GetDomPwInfo(dce_call
, mem_ctx
, &r2
);
4422 if (!NT_STATUS_IS_OK(status
)) {
4426 switch (r
->in
.level
) {
4427 case NetValidateAuthentication
:
4428 /* we don't support this yet */
4429 return NT_STATUS_NOT_SUPPORTED
;
4431 case NetValidatePasswordChange
:
4432 password
= data_blob_const(r
->in
.req
->req2
.password
.string
,
4433 r
->in
.req
->req2
.password
.length
);
4434 res
= samdb_check_password(&password
,
4435 pwInfo
.password_properties
,
4436 pwInfo
.min_password_length
);
4437 (*r
->out
.rep
)->ctr2
.status
= res
;
4439 case NetValidatePasswordReset
:
4440 password
= data_blob_const(r
->in
.req
->req3
.password
.string
,
4441 r
->in
.req
->req3
.password
.length
);
4442 res
= samdb_check_password(&password
,
4443 pwInfo
.password_properties
,
4444 pwInfo
.min_password_length
);
4445 (*r
->out
.rep
)->ctr3
.status
= res
;
4448 return NT_STATUS_INVALID_INFO_CLASS
;
4452 return NT_STATUS_OK
;
4456 /* include the generated boilerplate */
4457 #include "librpc/gen_ndr/ndr_samr_s.c"