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
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "librpc/gen_ndr/ndr_samr.h"
26 #include "rpc_server/dcerpc_server.h"
27 #include "rpc_server/common/common.h"
28 #include "rpc_server/samr/dcesrv_samr.h"
29 #include "system/time.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/ldb/include/ldb_errors.h"
32 #include "dsdb/common/flags.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "libcli/ldap/ldap_ndr.h"
35 #include "libcli/security/security.h"
36 #include "rpc_server/samr/proto.h"
37 #include "util/util_ldb.h"
38 #include "param/param.h"
40 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
42 #define QUERY_STRING(msg, field, attr) \
43 r->out.info->field.string = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45 r->out.info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_UINT64(msg, field, attr) \
49 r->out.info->field = samdb_result_uint64(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51 r->out.info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
52 a_state->domain_state->domain_dn, msg, attr);
53 #define QUERY_FPASSC(msg, field, attr) \
54 r->out.info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
55 a_state->domain_state->domain_dn, msg);
56 #define QUERY_LHOURS(msg, field, attr) \
57 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59 r->out.info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
62 /* these are used to make the Set[User|Group]Info code easier to follow */
64 #define SET_STRING(msg, field, attr) do { \
65 struct ldb_message_element *set_el; \
66 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
67 if (r->in.info->field.string[0] == '\0') { \
68 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
69 return NT_STATUS_NO_MEMORY; \
72 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
73 return NT_STATUS_NO_MEMORY; \
75 set_el = ldb_msg_find_element(msg, attr); \
76 set_el->flags = LDB_FLAG_MOD_REPLACE; \
79 #define SET_UINT(msg, field, attr) do { \
80 struct ldb_message_element *set_el; \
81 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
82 return NT_STATUS_NO_MEMORY; \
84 set_el = ldb_msg_find_element(msg, attr); \
85 set_el->flags = LDB_FLAG_MOD_REPLACE; \
88 #define SET_INT64(msg, field, attr) do { \
89 struct ldb_message_element *set_el; \
90 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
91 return NT_STATUS_NO_MEMORY; \
93 set_el = ldb_msg_find_element(msg, attr); \
94 set_el->flags = LDB_FLAG_MOD_REPLACE; \
97 #define SET_UINT64(msg, field, attr) do { \
98 struct ldb_message_element *set_el; \
99 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
100 return NT_STATUS_NO_MEMORY; \
102 set_el = ldb_msg_find_element(msg, attr); \
103 set_el->flags = LDB_FLAG_MOD_REPLACE; \
106 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
108 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
109 return NT_STATUS_INVALID_PARAMETER; \
113 /* Set account flags, discarding flags that cannot be set with SAMR */
114 #define SET_AFLAGS(msg, field, attr) do { \
115 struct ldb_message_element *set_el; \
116 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
117 return NT_STATUS_INVALID_PARAMETER; \
119 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
120 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
121 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
122 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
124 return NT_STATUS_NO_MEMORY; \
126 set_el = ldb_msg_find_element(msg, attr); \
127 set_el->flags = LDB_FLAG_MOD_REPLACE; \
130 #define SET_LHOURS(msg, field, attr) do { \
131 struct ldb_message_element *set_el; \
132 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
133 return NT_STATUS_NO_MEMORY; \
135 set_el = ldb_msg_find_element(msg, attr); \
136 set_el->flags = LDB_FLAG_MOD_REPLACE; \
143 create a connection to the SAM database
145 static NTSTATUS
dcesrv_samr_Connect(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
146 struct samr_Connect
*r
)
148 struct samr_connect_state
*c_state
;
149 struct dcesrv_handle
*handle
;
151 ZERO_STRUCTP(r
->out
.connect_handle
);
153 c_state
= talloc(dce_call
->conn
, struct samr_connect_state
);
155 return NT_STATUS_NO_MEMORY
;
158 /* make sure the sam database is accessible */
159 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
);
160 if (c_state
->sam_ctx
== NULL
) {
161 talloc_free(c_state
);
162 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
166 handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_CONNECT
);
168 talloc_free(c_state
);
169 return NT_STATUS_NO_MEMORY
;
172 handle
->data
= talloc_steal(handle
, c_state
);
174 c_state
->access_mask
= r
->in
.access_mask
;
175 *r
->out
.connect_handle
= handle
->wire_handle
;
184 static NTSTATUS
dcesrv_samr_Close(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
185 struct samr_Close
*r
)
187 struct dcesrv_handle
*h
;
189 *r
->out
.handle
= *r
->in
.handle
;
191 DCESRV_PULL_HANDLE(h
, r
->in
.handle
, DCESRV_HANDLE_ANY
);
195 ZERO_STRUCTP(r
->out
.handle
);
204 static NTSTATUS
dcesrv_samr_SetSecurity(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
205 struct samr_SetSecurity
*r
)
207 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
214 static NTSTATUS
dcesrv_samr_QuerySecurity(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
215 struct samr_QuerySecurity
*r
)
217 struct dcesrv_handle
*h
;
218 struct sec_desc_buf
*sd
;
222 DCESRV_PULL_HANDLE(h
, r
->in
.handle
, DCESRV_HANDLE_ANY
);
224 sd
= talloc(mem_ctx
, struct sec_desc_buf
);
226 return NT_STATUS_NO_MEMORY
;
229 sd
->sd
= samdb_default_security_descriptor(mem_ctx
);
240 we refuse this operation completely. If a admin wants to shutdown samr
241 in Samba then they should use the samba admin tools to disable the samr pipe
243 static NTSTATUS
dcesrv_samr_Shutdown(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
244 struct samr_Shutdown
*r
)
246 return NT_STATUS_ACCESS_DENIED
;
253 this maps from a domain name to a SID
255 static NTSTATUS
dcesrv_samr_LookupDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
256 struct samr_LookupDomain
*r
)
258 struct samr_connect_state
*c_state
;
259 struct dcesrv_handle
*h
;
261 const char * const dom_attrs
[] = { "objectSid", NULL
};
262 const char * const ref_attrs
[] = { "ncName", NULL
};
263 struct ldb_message
**dom_msgs
;
264 struct ldb_message
**ref_msgs
;
266 struct ldb_dn
*partitions_basedn
;
270 DCESRV_PULL_HANDLE(h
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
274 if (r
->in
.domain_name
->string
== NULL
) {
275 return NT_STATUS_INVALID_PARAMETER
;
278 partitions_basedn
= samdb_partitions_dn(c_state
->sam_ctx
, mem_ctx
);
280 if (strcasecmp(r
->in
.domain_name
->string
, "BUILTIN") == 0) {
281 ret
= gendb_search(c_state
->sam_ctx
,
282 mem_ctx
, NULL
, &dom_msgs
, dom_attrs
,
283 "(objectClass=builtinDomain)");
285 ret
= gendb_search(c_state
->sam_ctx
,
286 mem_ctx
, partitions_basedn
, &ref_msgs
, ref_attrs
,
287 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
288 ldb_binary_encode_string(mem_ctx
, r
->in
.domain_name
->string
));
290 return NT_STATUS_NO_SUCH_DOMAIN
;
293 ret
= gendb_search_dn(c_state
->sam_ctx
, mem_ctx
,
294 samdb_result_dn(c_state
->sam_ctx
, mem_ctx
,
295 ref_msgs
[0], "ncName", NULL
),
296 &dom_msgs
, dom_attrs
);
300 return NT_STATUS_NO_SUCH_DOMAIN
;
303 sid
= samdb_result_dom_sid(mem_ctx
, dom_msgs
[0],
307 return NT_STATUS_NO_SUCH_DOMAIN
;
319 list the domains in the SAM
321 static NTSTATUS
dcesrv_samr_EnumDomains(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
322 struct samr_EnumDomains
*r
)
324 struct samr_connect_state
*c_state
;
325 struct dcesrv_handle
*h
;
326 struct samr_SamArray
*array
;
328 const char * const dom_attrs
[] = { "cn", NULL
};
329 const char * const ref_attrs
[] = { "nETBIOSName", NULL
};
330 struct ldb_result
*dom_res
;
331 struct ldb_result
*ref_res
;
332 struct ldb_dn
*partitions_basedn
;
334 *r
->out
.resume_handle
= 0;
336 r
->out
.num_entries
= 0;
338 DCESRV_PULL_HANDLE(h
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
342 partitions_basedn
= samdb_partitions_dn(c_state
->sam_ctx
, mem_ctx
);
344 ret
= ldb_search(c_state
->sam_ctx
, mem_ctx
, &dom_res
, ldb_get_default_basedn(c_state
->sam_ctx
),
345 LDB_SCOPE_SUBTREE
, dom_attrs
, "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
346 if (ret
!= LDB_SUCCESS
) {
347 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state
->sam_ctx
)));
348 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
351 *r
->out
.resume_handle
= dom_res
->count
;
353 start_i
= *r
->in
.resume_handle
;
355 if (start_i
>= dom_res
->count
) {
356 /* search past end of list is not an error for this call */
360 array
= talloc(mem_ctx
, struct samr_SamArray
);
362 return NT_STATUS_NO_MEMORY
;
366 array
->entries
= NULL
;
368 array
->entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, dom_res
->count
- start_i
);
369 if (array
->entries
== NULL
) {
370 return NT_STATUS_NO_MEMORY
;
373 for (i
=0;i
<dom_res
->count
-start_i
;i
++) {
374 array
->entries
[i
].idx
= start_i
+ i
;
375 /* try and find the domain */
376 ret
= ldb_search(c_state
->sam_ctx
, mem_ctx
, &ref_res
, partitions_basedn
,
377 LDB_SCOPE_SUBTREE
, ref_attrs
, "(&(objectClass=crossRef)(ncName=%s))",
378 ldb_dn_get_linearized(dom_res
->msgs
[i
]->dn
));
380 if (ret
!= LDB_SUCCESS
) {
381 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state
->sam_ctx
)));
382 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
385 if (ref_res
->count
== 1) {
386 array
->entries
[i
].name
.string
= samdb_result_string(ref_res
->msgs
[0], "nETBIOSName", NULL
);
388 array
->entries
[i
].name
.string
= samdb_result_string(dom_res
->msgs
[i
], "cn", NULL
);
393 r
->out
.num_entries
= i
;
394 array
->count
= r
->out
.num_entries
;
403 static NTSTATUS
dcesrv_samr_OpenDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
404 struct samr_OpenDomain
*r
)
406 struct dcesrv_handle
*h_conn
, *h_domain
;
407 const char *domain_name
;
408 struct samr_connect_state
*c_state
;
409 struct samr_domain_state
*d_state
;
410 const char * const dom_attrs
[] = { "cn", NULL
};
411 const char * const ref_attrs
[] = { "nETBIOSName", NULL
};
412 struct ldb_message
**dom_msgs
;
413 struct ldb_message
**ref_msgs
;
415 struct ldb_dn
*partitions_basedn
;
417 ZERO_STRUCTP(r
->out
.domain_handle
);
419 DCESRV_PULL_HANDLE(h_conn
, r
->in
.connect_handle
, SAMR_HANDLE_CONNECT
);
421 c_state
= h_conn
->data
;
423 if (r
->in
.sid
== NULL
) {
424 return NT_STATUS_INVALID_PARAMETER
;
427 partitions_basedn
= samdb_partitions_dn(c_state
->sam_ctx
, mem_ctx
);
429 ret
= gendb_search(c_state
->sam_ctx
,
430 mem_ctx
, NULL
, &dom_msgs
, dom_attrs
,
431 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
432 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
434 return NT_STATUS_NO_SUCH_DOMAIN
;
435 } else if (ret
> 1) {
436 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
437 } else if (ret
== -1) {
438 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx
, r
->in
.sid
), ldb_errstring(c_state
->sam_ctx
)));
439 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
441 ret
= gendb_search(c_state
->sam_ctx
,
442 mem_ctx
, partitions_basedn
, &ref_msgs
, ref_attrs
,
443 "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))",
444 ldb_dn_get_linearized(dom_msgs
[0]->dn
));
446 domain_name
= ldb_msg_find_attr_as_string(dom_msgs
[0], "cn", NULL
);
447 if (domain_name
== NULL
) {
448 return NT_STATUS_NO_SUCH_DOMAIN
;
450 } else if (ret
== 1) {
452 domain_name
= ldb_msg_find_attr_as_string(ref_msgs
[0], "nETBIOSName", NULL
);
453 if (domain_name
== NULL
) {
454 return NT_STATUS_NO_SUCH_DOMAIN
;
457 return NT_STATUS_NO_SUCH_DOMAIN
;
461 d_state
= talloc(c_state
, struct samr_domain_state
);
463 return NT_STATUS_NO_MEMORY
;
466 d_state
->role
= lp_server_role(dce_call
->conn
->dce_ctx
->lp_ctx
);
467 d_state
->connect_state
= talloc_reference(d_state
, c_state
);
468 d_state
->sam_ctx
= c_state
->sam_ctx
;
469 d_state
->domain_sid
= dom_sid_dup(d_state
, r
->in
.sid
);
470 d_state
->domain_name
= talloc_strdup(d_state
, domain_name
);
471 d_state
->domain_dn
= ldb_dn_copy(d_state
, dom_msgs
[0]->dn
);
472 if (!d_state
->domain_sid
|| !d_state
->domain_name
|| !d_state
->domain_dn
) {
473 talloc_free(d_state
);
474 return NT_STATUS_NO_MEMORY
;
476 d_state
->access_mask
= r
->in
.access_mask
;
478 if (dom_sid_equal(d_state
->domain_sid
, dom_sid_parse_talloc(mem_ctx
, SID_BUILTIN
))) {
479 d_state
->builtin
= true;
481 d_state
->builtin
= false;
484 d_state
->lp_ctx
= dce_call
->conn
->dce_ctx
->lp_ctx
;
486 h_domain
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_DOMAIN
);
488 talloc_free(d_state
);
489 return NT_STATUS_NO_MEMORY
;
492 h_domain
->data
= talloc_steal(h_domain
, d_state
);
494 *r
->out
.domain_handle
= h_domain
->wire_handle
;
502 static NTSTATUS
dcesrv_samr_info_DomInfo1(struct samr_domain_state
*state
,
504 struct ldb_message
**dom_msgs
,
505 struct samr_DomInfo1
*info
)
507 info
->min_password_length
=
508 samdb_result_uint(dom_msgs
[0], "minPwdLength", 0);
509 info
->password_history_length
=
510 samdb_result_uint(dom_msgs
[0], "pwdHistoryLength", 0);
511 info
->password_properties
=
512 samdb_result_uint(dom_msgs
[0], "pwdProperties", 0);
513 info
->max_password_age
=
514 samdb_result_int64(dom_msgs
[0], "maxPwdAge", 0);
515 info
->min_password_age
=
516 samdb_result_int64(dom_msgs
[0], "minPwdAge", 0);
524 static NTSTATUS
dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state
*state
,
526 struct ldb_message
**dom_msgs
,
527 struct samr_DomGeneralInformation
*info
)
529 /* This pulls the NetBIOS name from the
530 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
532 info
->primary
.string
= samdb_result_fsmo_name(state
->sam_ctx
, mem_ctx
, dom_msgs
[0], "fSMORoleOwner");
534 if (!info
->primary
.string
) {
535 info
->primary
.string
= lp_netbios_name(state
->lp_ctx
);
538 info
->force_logoff_time
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "forceLogoff",
539 0x8000000000000000LL
);
541 info
->oem_information
.string
= samdb_result_string(dom_msgs
[0], "oEMInformation", NULL
);
542 info
->domain_name
.string
= state
->domain_name
;
544 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
546 switch (state
->role
) {
547 case ROLE_DOMAIN_CONTROLLER
:
548 /* This pulls the NetBIOS name from the
549 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
551 if (samdb_is_pdc(state
->sam_ctx
)) {
552 info
->role
= SAMR_ROLE_DOMAIN_PDC
;
554 info
->role
= SAMR_ROLE_DOMAIN_BDC
;
557 case ROLE_DOMAIN_MEMBER
:
558 info
->role
= SAMR_ROLE_DOMAIN_MEMBER
;
560 case ROLE_STANDALONE
:
561 info
->role
= SAMR_ROLE_STANDALONE
;
565 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
566 info
->num_users
= samdb_search_count(state
->sam_ctx
, mem_ctx
, state
->domain_dn
,
567 "(objectClass=user)");
568 info
->num_groups
= samdb_search_count(state
->sam_ctx
, mem_ctx
, state
->domain_dn
,
569 "(&(objectClass=group)(sAMAccountType=%u))",
571 info
->num_aliases
= samdb_search_count(state
->sam_ctx
, mem_ctx
, state
->domain_dn
,
572 "(&(objectClass=group)(sAMAccountType=%u))",
581 static NTSTATUS
dcesrv_samr_info_DomInfo3(struct samr_domain_state
*state
,
583 struct ldb_message
**dom_msgs
,
584 struct samr_DomInfo3
*info
)
586 info
->force_logoff_time
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "forceLogoff",
587 0x8000000000000000LL
);
595 static NTSTATUS
dcesrv_samr_info_DomOEMInformation(struct samr_domain_state
*state
,
597 struct ldb_message
**dom_msgs
,
598 struct samr_DomOEMInformation
*info
)
600 info
->oem_information
.string
= samdb_result_string(dom_msgs
[0], "oEMInformation", NULL
);
608 static NTSTATUS
dcesrv_samr_info_DomInfo5(struct samr_domain_state
*state
,
610 struct ldb_message
**dom_msgs
,
611 struct samr_DomInfo5
*info
)
613 info
->domain_name
.string
= state
->domain_name
;
621 static NTSTATUS
dcesrv_samr_info_DomInfo6(struct samr_domain_state
*state
,
623 struct ldb_message
**dom_msgs
,
624 struct samr_DomInfo6
*info
)
626 /* This pulls the NetBIOS name from the
627 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
629 info
->primary
.string
= samdb_result_fsmo_name(state
->sam_ctx
, mem_ctx
,
630 dom_msgs
[0], "fSMORoleOwner");
632 if (!info
->primary
.string
) {
633 info
->primary
.string
= lp_netbios_name(state
->lp_ctx
);
642 static NTSTATUS
dcesrv_samr_info_DomInfo7(struct samr_domain_state
*state
,
644 struct ldb_message
**dom_msgs
,
645 struct samr_DomInfo7
*info
)
648 switch (state
->role
) {
649 case ROLE_DOMAIN_CONTROLLER
:
650 /* This pulls the NetBIOS name from the
651 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
653 if (samdb_is_pdc(state
->sam_ctx
)) {
654 info
->role
= SAMR_ROLE_DOMAIN_PDC
;
656 info
->role
= SAMR_ROLE_DOMAIN_BDC
;
659 case ROLE_DOMAIN_MEMBER
:
660 info
->role
= SAMR_ROLE_DOMAIN_MEMBER
;
662 case ROLE_STANDALONE
:
663 info
->role
= SAMR_ROLE_STANDALONE
;
673 static NTSTATUS
dcesrv_samr_info_DomInfo8(struct samr_domain_state
*state
,
675 struct ldb_message
**dom_msgs
,
676 struct samr_DomInfo8
*info
)
678 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
681 info
->domain_create_time
= ldb_msg_find_attr_as_uint(dom_msgs
[0], "creationTime",
690 static NTSTATUS
dcesrv_samr_info_DomInfo9(struct samr_domain_state
*state
,
692 struct ldb_message
**dom_msgs
,
693 struct samr_DomInfo9
*info
)
703 static NTSTATUS
dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state
*state
,
705 struct ldb_message
**dom_msgs
,
706 struct samr_DomGeneralInformation2
*info
)
709 status
= dcesrv_samr_info_DomGeneralInformation(state
, mem_ctx
, dom_msgs
, &info
->general
);
710 if (!NT_STATUS_IS_OK(status
)) {
714 info
->lockout_duration
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutDuration",
716 info
->lockout_window
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockOutObservationWindow",
718 info
->lockout_threshold
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutThreshold", 0);
726 static NTSTATUS
dcesrv_samr_info_DomInfo12(struct samr_domain_state
*state
,
728 struct ldb_message
**dom_msgs
,
729 struct samr_DomInfo12
*info
)
731 info
->lockout_duration
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutDuration",
733 info
->lockout_window
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockOutObservationWindow",
735 info
->lockout_threshold
= ldb_msg_find_attr_as_int64(dom_msgs
[0], "lockoutThreshold", 0);
743 static NTSTATUS
dcesrv_samr_info_DomInfo13(struct samr_domain_state
*state
,
745 struct ldb_message
**dom_msgs
,
746 struct samr_DomInfo13
*info
)
748 info
->sequence_num
= ldb_msg_find_attr_as_uint64(dom_msgs
[0], "modifiedCount",
751 info
->domain_create_time
= ldb_msg_find_attr_as_uint(dom_msgs
[0], "creationTime",
763 static NTSTATUS
dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
764 struct samr_QueryDomainInfo
*r
)
766 struct dcesrv_handle
*h
;
767 struct samr_domain_state
*d_state
;
769 struct ldb_message
**dom_msgs
;
770 const char * const *attrs
= NULL
;
774 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
778 r
->out
.info
= talloc(mem_ctx
, union samr_DomainInfo
);
780 return NT_STATUS_NO_MEMORY
;
783 switch (r
->in
.level
) {
786 static const char * const attrs2
[] = { "minPwdLength", "pwdHistoryLength",
787 "pwdProperties", "maxPwdAge",
794 static const char * const attrs2
[] = {"forceLogoff",
804 static const char * const attrs2
[] = {"forceLogoff",
811 static const char * const attrs2
[] = {"oEMInformation",
823 static const char * const attrs2
[] = {"fSMORoleOwner",
835 static const char * const attrs2
[] = { "modifiedCount",
846 static const char * const attrs2
[] = { "oEMInformation", "forceLogoff",
849 "lockOutObservationWindow",
857 static const char * const attrs2
[] = { "lockoutDuration",
858 "lockOutObservationWindow",
866 static const char * const attrs2
[] = { "modifiedCount",
874 /* some levels don't need a search */
877 ret
= gendb_search_dn(d_state
->sam_ctx
, mem_ctx
,
878 d_state
->domain_dn
, &dom_msgs
, attrs
);
880 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
884 ZERO_STRUCTP(r
->out
.info
);
886 switch (r
->in
.level
) {
888 return dcesrv_samr_info_DomInfo1(d_state
, mem_ctx
, dom_msgs
,
889 &r
->out
.info
->info1
);
891 return dcesrv_samr_info_DomGeneralInformation(d_state
, mem_ctx
, dom_msgs
,
892 &r
->out
.info
->general
);
894 return dcesrv_samr_info_DomInfo3(d_state
, mem_ctx
, dom_msgs
,
895 &r
->out
.info
->info3
);
897 return dcesrv_samr_info_DomOEMInformation(d_state
, mem_ctx
, dom_msgs
,
900 return dcesrv_samr_info_DomInfo5(d_state
, mem_ctx
, dom_msgs
,
901 &r
->out
.info
->info5
);
903 return dcesrv_samr_info_DomInfo6(d_state
, mem_ctx
, dom_msgs
,
904 &r
->out
.info
->info6
);
906 return dcesrv_samr_info_DomInfo7(d_state
, mem_ctx
, dom_msgs
,
907 &r
->out
.info
->info7
);
909 return dcesrv_samr_info_DomInfo8(d_state
, mem_ctx
, dom_msgs
,
910 &r
->out
.info
->info8
);
912 return dcesrv_samr_info_DomInfo9(d_state
, mem_ctx
, dom_msgs
,
913 &r
->out
.info
->info9
);
915 return dcesrv_samr_info_DomGeneralInformation2(d_state
, mem_ctx
, dom_msgs
,
916 &r
->out
.info
->general2
);
918 return dcesrv_samr_info_DomInfo12(d_state
, mem_ctx
, dom_msgs
,
919 &r
->out
.info
->info12
);
921 return dcesrv_samr_info_DomInfo13(d_state
, mem_ctx
, dom_msgs
,
922 &r
->out
.info
->info13
);
925 return NT_STATUS_INVALID_INFO_CLASS
;
932 static NTSTATUS
dcesrv_samr_SetDomainInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
933 struct samr_SetDomainInfo
*r
)
935 struct dcesrv_handle
*h
;
936 struct samr_domain_state
*d_state
;
937 struct ldb_message
*msg
;
939 struct ldb_context
*sam_ctx
;
941 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
944 sam_ctx
= d_state
->sam_ctx
;
946 msg
= ldb_msg_new(mem_ctx
);
948 return NT_STATUS_NO_MEMORY
;
951 msg
->dn
= talloc_reference(mem_ctx
, d_state
->domain_dn
);
953 return NT_STATUS_NO_MEMORY
;
956 switch (r
->in
.level
) {
958 SET_UINT (msg
, info1
.min_password_length
, "minPwdLength");
959 SET_UINT (msg
, info1
.password_history_length
, "pwdHistoryLength");
960 SET_UINT (msg
, info1
.password_properties
, "pwdProperties");
961 SET_INT64 (msg
, info1
.max_password_age
, "maxPwdAge");
962 SET_INT64 (msg
, info1
.min_password_age
, "minPwdAge");
965 SET_UINT64 (msg
, info3
.force_logoff_time
, "forceLogoff");
968 SET_STRING(msg
, oem
.oem_information
, "oEMInformation");
974 /* No op, we don't know where to set these */
979 SET_INT64 (msg
, info12
.lockout_duration
, "lockoutDuration");
980 SET_INT64 (msg
, info12
.lockout_window
, "lockOutObservationWindow");
981 SET_INT64 (msg
, info12
.lockout_threshold
, "lockoutThreshold");
985 /* many info classes are not valid for SetDomainInfo */
986 return NT_STATUS_INVALID_INFO_CLASS
;
989 /* modify the samdb record */
990 ret
= ldb_modify(sam_ctx
, msg
);
992 DEBUG(1,("Failed to modify record %s: %s\n",
993 ldb_dn_get_linearized(d_state
->domain_dn
),
994 ldb_errstring(sam_ctx
)));
996 /* we really need samdb.c to return NTSTATUS */
997 return NT_STATUS_UNSUCCESSFUL
;
1000 return NT_STATUS_OK
;
1004 samr_CreateDomainGroup
1006 static NTSTATUS
dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1007 struct samr_CreateDomainGroup
*r
)
1009 struct samr_domain_state
*d_state
;
1010 struct samr_account_state
*a_state
;
1011 struct dcesrv_handle
*h
;
1013 struct ldb_message
*msg
;
1014 struct dom_sid
*sid
;
1015 const char *groupname
;
1016 struct dcesrv_handle
*g_handle
;
1019 ZERO_STRUCTP(r
->out
.group_handle
);
1022 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1026 if (d_state
->builtin
) {
1027 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1028 return NT_STATUS_ACCESS_DENIED
;
1031 groupname
= r
->in
.name
->string
;
1033 if (groupname
== NULL
) {
1034 return NT_STATUS_INVALID_PARAMETER
;
1037 /* check if the group already exists */
1038 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1040 "(&(sAMAccountName=%s)(objectclass=group))",
1041 ldb_binary_encode_string(mem_ctx
, groupname
));
1043 return NT_STATUS_GROUP_EXISTS
;
1046 msg
= ldb_msg_new(mem_ctx
);
1048 return NT_STATUS_NO_MEMORY
;
1051 /* add core elements to the ldb_message for the user */
1052 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1053 ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,CN=Users", groupname
);
1055 return NT_STATUS_NO_MEMORY
;
1057 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName", groupname
);
1058 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass", "group");
1060 /* create the group */
1061 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1065 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1066 DEBUG(0,("Failed to create group record %s: %s\n",
1067 ldb_dn_get_linearized(msg
->dn
),
1068 ldb_errstring(d_state
->sam_ctx
)));
1069 return NT_STATUS_GROUP_EXISTS
;
1070 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1071 DEBUG(0,("Failed to create group record %s: %s\n",
1072 ldb_dn_get_linearized(msg
->dn
),
1073 ldb_errstring(d_state
->sam_ctx
)));
1074 return NT_STATUS_ACCESS_DENIED
;
1076 DEBUG(0,("Failed to create group record %s: %s\n",
1077 ldb_dn_get_linearized(msg
->dn
),
1078 ldb_errstring(d_state
->sam_ctx
)));
1079 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1082 a_state
= talloc(d_state
, struct samr_account_state
);
1084 return NT_STATUS_NO_MEMORY
;
1086 a_state
->sam_ctx
= d_state
->sam_ctx
;
1087 a_state
->access_mask
= r
->in
.access_mask
;
1088 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1089 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1091 /* retrieve the sid for the group just created */
1092 sid
= samdb_search_dom_sid(d_state
->sam_ctx
, a_state
,
1093 msg
->dn
, "objectSid", NULL
);
1095 return NT_STATUS_UNSUCCESSFUL
;
1098 a_state
->account_name
= talloc_strdup(a_state
, groupname
);
1099 if (!a_state
->account_name
) {
1100 return NT_STATUS_NO_MEMORY
;
1103 /* create the policy handle */
1104 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_GROUP
);
1106 return NT_STATUS_NO_MEMORY
;
1109 g_handle
->data
= talloc_steal(g_handle
, a_state
);
1111 *r
->out
.group_handle
= g_handle
->wire_handle
;
1112 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1114 return NT_STATUS_OK
;
1119 comparison function for sorting SamEntry array
1121 static int compare_SamEntry(struct samr_SamEntry
*e1
, struct samr_SamEntry
*e2
)
1123 return e1
->idx
- e2
->idx
;
1127 samr_EnumDomainGroups
1129 static NTSTATUS
dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1130 struct samr_EnumDomainGroups
*r
)
1132 struct dcesrv_handle
*h
;
1133 struct samr_domain_state
*d_state
;
1134 struct ldb_message
**res
;
1135 int ldb_cnt
, count
, i
, first
;
1136 struct samr_SamEntry
*entries
;
1137 const char * const attrs
[3] = { "objectSid", "sAMAccountName", NULL
};
1139 *r
->out
.resume_handle
= 0;
1141 r
->out
.num_entries
= 0;
1143 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1147 /* search for all domain groups in this domain. This could possibly be
1148 cached and resumed based on resume_key */
1149 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1150 d_state
->domain_dn
, &res
, attrs
,
1151 d_state
->domain_sid
,
1152 "(&(grouptype=%d)(objectclass=group))",
1153 GTYPE_SECURITY_GLOBAL_GROUP
);
1154 if (ldb_cnt
== -1) {
1155 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1158 /* convert to SamEntry format */
1159 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, ldb_cnt
);
1161 return NT_STATUS_NO_MEMORY
;
1166 for (i
=0;i
<ldb_cnt
;i
++) {
1167 struct dom_sid
*group_sid
;
1169 group_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
1171 if (group_sid
== NULL
)
1174 entries
[count
].idx
=
1175 group_sid
->sub_auths
[group_sid
->num_auths
-1];
1176 entries
[count
].name
.string
=
1177 samdb_result_string(res
[i
], "sAMAccountName", "");
1181 /* sort the results by rid */
1182 qsort(entries
, count
, sizeof(struct samr_SamEntry
),
1183 (comparison_fn_t
)compare_SamEntry
);
1185 /* find the first entry to return */
1187 first
<count
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1190 /* return the rest, limit by max_size. Note that we
1191 use the w2k3 element size value of 54 */
1192 r
->out
.num_entries
= count
- first
;
1193 r
->out
.num_entries
= MIN(r
->out
.num_entries
,
1194 1+(r
->in
.max_size
/SAMR_ENUM_USERS_MULTIPLIER
));
1196 r
->out
.sam
= talloc(mem_ctx
, struct samr_SamArray
);
1198 return NT_STATUS_NO_MEMORY
;
1201 r
->out
.sam
->entries
= entries
+first
;
1202 r
->out
.sam
->count
= r
->out
.num_entries
;
1204 if (r
->out
.num_entries
< count
- first
) {
1205 *r
->out
.resume_handle
= entries
[first
+r
->out
.num_entries
-1].idx
;
1206 return STATUS_MORE_ENTRIES
;
1209 return NT_STATUS_OK
;
1216 This call uses transactions to ensure we don't get a new conflicting
1217 user while we are processing this, and to ensure the user either
1218 completly exists, or does not.
1220 static NTSTATUS
dcesrv_samr_CreateUser2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1221 struct samr_CreateUser2
*r
)
1223 struct samr_domain_state
*d_state
;
1224 struct samr_account_state
*a_state
;
1225 struct dcesrv_handle
*h
;
1227 struct ldb_message
*msg
;
1228 struct dom_sid
*sid
;
1229 const char *account_name
;
1230 struct dcesrv_handle
*u_handle
;
1232 const char *container
, *obj_class
=NULL
;
1236 const char *attrs
[] = {
1238 "userAccountControl",
1242 uint32_t user_account_control
;
1244 struct ldb_message
**msgs
;
1246 ZERO_STRUCTP(r
->out
.user_handle
);
1247 *r
->out
.access_granted
= 0;
1250 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1254 if (d_state
->builtin
) {
1255 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1256 return NT_STATUS_ACCESS_DENIED
;
1258 account_name
= r
->in
.account_name
->string
;
1260 if (account_name
== NULL
) {
1261 return NT_STATUS_INVALID_PARAMETER
;
1264 ret
= ldb_transaction_start(d_state
->sam_ctx
);
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 return NT_STATUS_FOOBAR
;
1304 cn_name
[cn_name_len
- 1] = '\0';
1305 container
= "CN=Computers";
1306 obj_class
= "computer";
1307 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS
);
1309 } else if (r
->in
.acct_flags
== ACB_SVRTRUST
) {
1310 if (cn_name
[cn_name_len
- 1] != '$') {
1311 return NT_STATUS_FOOBAR
;
1313 cn_name
[cn_name_len
- 1] = '\0';
1314 container
= "OU=Domain Controllers";
1315 obj_class
= "computer";
1316 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
, "primaryGroupID", DOMAIN_RID_DCS
);
1318 } else if (r
->in
.acct_flags
== ACB_DOMTRUST
) {
1319 container
= "CN=Users";
1323 ldb_transaction_cancel(d_state
->sam_ctx
);
1324 return NT_STATUS_INVALID_PARAMETER
;
1327 /* add core elements to the ldb_message for the user */
1328 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1329 if ( ! ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,%s", cn_name
, container
)) {
1330 ldb_transaction_cancel(d_state
->sam_ctx
);
1331 return NT_STATUS_FOOBAR
;
1334 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName", account_name
);
1335 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass", obj_class
);
1337 /* Start a transaction, so we can query and do a subsequent atomic modify */
1339 /* create the user */
1340 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1344 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1345 ldb_transaction_cancel(d_state
->sam_ctx
);
1346 DEBUG(0,("Failed to create user record %s: %s\n",
1347 ldb_dn_get_linearized(msg
->dn
),
1348 ldb_errstring(d_state
->sam_ctx
)));
1349 return NT_STATUS_USER_EXISTS
;
1350 case LDB_ERR_UNWILLING_TO_PERFORM
:
1351 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1352 ldb_transaction_cancel(d_state
->sam_ctx
);
1353 DEBUG(0,("Failed to create user record %s: %s\n",
1354 ldb_dn_get_linearized(msg
->dn
),
1355 ldb_errstring(d_state
->sam_ctx
)));
1356 return NT_STATUS_ACCESS_DENIED
;
1358 ldb_transaction_cancel(d_state
->sam_ctx
);
1359 DEBUG(0,("Failed to create user record %s: %s\n",
1360 ldb_dn_get_linearized(msg
->dn
),
1361 ldb_errstring(d_state
->sam_ctx
)));
1362 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1365 a_state
= talloc(d_state
, struct samr_account_state
);
1367 ldb_transaction_cancel(d_state
->sam_ctx
);
1368 return NT_STATUS_NO_MEMORY
;
1370 a_state
->sam_ctx
= d_state
->sam_ctx
;
1371 a_state
->access_mask
= r
->in
.access_mask
;
1372 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1373 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1375 /* retrieve the sid and account control bits for the user just created */
1376 ret
= gendb_search_dn(d_state
->sam_ctx
, a_state
,
1377 msg
->dn
, &msgs
, attrs
);
1380 ldb_transaction_cancel(d_state
->sam_ctx
);
1381 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1382 ldb_dn_get_linearized(msg
->dn
)));
1383 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1385 sid
= samdb_result_dom_sid(mem_ctx
, msgs
[0], "objectSid");
1387 ldb_transaction_cancel(d_state
->sam_ctx
);
1388 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1389 ldb_dn_get_linearized(msg
->dn
)));
1390 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1393 /* Change the account control to be the correct account type.
1394 * The default is for a workstation account */
1395 user_account_control
= samdb_result_uint(msgs
[0], "userAccountControl", 0);
1396 user_account_control
= (user_account_control
&
1397 ~(UF_NORMAL_ACCOUNT
|
1398 UF_INTERDOMAIN_TRUST_ACCOUNT
|
1399 UF_WORKSTATION_TRUST_ACCOUNT
|
1400 UF_SERVER_TRUST_ACCOUNT
));
1401 user_account_control
|= samdb_acb2uf(r
->in
.acct_flags
);
1404 msg
= ldb_msg_new(mem_ctx
);
1406 ldb_transaction_cancel(d_state
->sam_ctx
);
1407 return NT_STATUS_NO_MEMORY
;
1410 msg
->dn
= ldb_dn_copy(msg
, a_state
->account_dn
);
1412 if (samdb_msg_add_uint(a_state
->sam_ctx
, mem_ctx
, msg
,
1413 "userAccountControl",
1414 user_account_control
) != 0) {
1415 ldb_transaction_cancel(d_state
->sam_ctx
);
1416 return NT_STATUS_NO_MEMORY
;
1419 /* modify the samdb record */
1420 ret
= samdb_replace(a_state
->sam_ctx
, mem_ctx
, msg
);
1422 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1423 ldb_dn_get_linearized(msg
->dn
),
1424 ldb_errstring(d_state
->sam_ctx
)));
1425 ldb_transaction_cancel(d_state
->sam_ctx
);
1427 /* we really need samdb.c to return NTSTATUS */
1428 return NT_STATUS_UNSUCCESSFUL
;
1431 ret
= ldb_transaction_commit(d_state
->sam_ctx
);
1433 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1434 ldb_dn_get_linearized(msg
->dn
),
1435 ldb_errstring(d_state
->sam_ctx
)));
1436 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1439 a_state
->account_name
= talloc_steal(a_state
, account_name
);
1440 if (!a_state
->account_name
) {
1441 return NT_STATUS_NO_MEMORY
;
1444 /* create the policy handle */
1445 u_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_USER
);
1447 return NT_STATUS_NO_MEMORY
;
1450 u_handle
->data
= talloc_steal(u_handle
, a_state
);
1452 *r
->out
.user_handle
= u_handle
->wire_handle
;
1453 *r
->out
.access_granted
= 0xf07ff; /* TODO: fix access mask calculations */
1455 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1457 return NT_STATUS_OK
;
1464 static NTSTATUS
dcesrv_samr_CreateUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1465 struct samr_CreateUser
*r
)
1467 struct samr_CreateUser2 r2
;
1468 uint32_t access_granted
= 0;
1471 /* a simple wrapper around samr_CreateUser2 works nicely */
1472 r2
.in
.domain_handle
= r
->in
.domain_handle
;
1473 r2
.in
.account_name
= r
->in
.account_name
;
1474 r2
.in
.acct_flags
= ACB_NORMAL
;
1475 r2
.in
.access_mask
= r
->in
.access_mask
;
1476 r2
.out
.user_handle
= r
->out
.user_handle
;
1477 r2
.out
.access_granted
= &access_granted
;
1478 r2
.out
.rid
= r
->out
.rid
;
1480 return dcesrv_samr_CreateUser2(dce_call
, mem_ctx
, &r2
);
1484 samr_EnumDomainUsers
1486 static NTSTATUS
dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1487 struct samr_EnumDomainUsers
*r
)
1489 struct dcesrv_handle
*h
;
1490 struct samr_domain_state
*d_state
;
1491 struct ldb_result
*res
;
1492 int ret
, num_filtered_entries
, i
, first
;
1493 struct samr_SamEntry
*entries
;
1494 const char * const attrs
[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL
};
1496 *r
->out
.resume_handle
= 0;
1498 r
->out
.num_entries
= 0;
1500 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1504 /* don't have to worry about users in the builtin domain, as there are none */
1505 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
, d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
, "objectClass=user");
1507 if (ret
!= LDB_SUCCESS
) {
1508 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1509 ldb_dn_get_linearized(d_state
->domain_dn
), ldb_errstring(d_state
->sam_ctx
)));
1510 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1513 /* convert to SamEntry format */
1514 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, res
->count
);
1516 return NT_STATUS_NO_MEMORY
;
1518 num_filtered_entries
= 0;
1519 for (i
=0;i
<res
->count
;i
++) {
1520 /* Check if a mask has been requested */
1521 if (r
->in
.acct_flags
1522 && ((samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
, res
->msgs
[i
],
1523 d_state
->domain_dn
) & r
->in
.acct_flags
) == 0)) {
1526 entries
[num_filtered_entries
].idx
= samdb_result_rid_from_sid(mem_ctx
, res
->msgs
[i
], "objectSid", 0);
1527 entries
[num_filtered_entries
].name
.string
= samdb_result_string(res
->msgs
[i
], "sAMAccountName", "");
1528 num_filtered_entries
++;
1531 /* sort the results by rid */
1532 qsort(entries
, num_filtered_entries
, sizeof(struct samr_SamEntry
),
1533 (comparison_fn_t
)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 r
->out
.sam
= talloc(mem_ctx
, struct samr_SamArray
);
1548 return NT_STATUS_NO_MEMORY
;
1551 r
->out
.sam
->entries
= entries
+first
;
1552 r
->out
.sam
->count
= r
->out
.num_entries
;
1554 if (first
== num_filtered_entries
) {
1555 return NT_STATUS_OK
;
1558 if (r
->out
.num_entries
< num_filtered_entries
- first
) {
1559 *r
->out
.resume_handle
= entries
[first
+r
->out
.num_entries
-1].idx
;
1560 return STATUS_MORE_ENTRIES
;
1563 return NT_STATUS_OK
;
1570 static NTSTATUS
dcesrv_samr_CreateDomAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1571 struct samr_CreateDomAlias
*r
)
1573 struct samr_domain_state
*d_state
;
1574 struct samr_account_state
*a_state
;
1575 struct dcesrv_handle
*h
;
1576 const char *alias_name
, *name
;
1577 struct ldb_message
*msg
;
1578 struct dom_sid
*sid
;
1579 struct dcesrv_handle
*a_handle
;
1582 ZERO_STRUCTP(r
->out
.alias_handle
);
1585 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1589 if (d_state
->builtin
) {
1590 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1591 return NT_STATUS_ACCESS_DENIED
;
1594 alias_name
= r
->in
.alias_name
->string
;
1596 if (alias_name
== NULL
) {
1597 return NT_STATUS_INVALID_PARAMETER
;
1600 /* Check if alias already exists */
1601 name
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
1603 "(sAMAccountName=%s)(objectclass=group))",
1604 ldb_binary_encode_string(mem_ctx
, alias_name
));
1607 return NT_STATUS_ALIAS_EXISTS
;
1610 msg
= ldb_msg_new(mem_ctx
);
1612 return NT_STATUS_NO_MEMORY
;
1615 /* add core elements to the ldb_message for the alias */
1616 msg
->dn
= ldb_dn_copy(mem_ctx
, d_state
->domain_dn
);
1617 ldb_dn_add_child_fmt(msg
->dn
, "CN=%s,CN=Users", alias_name
);
1619 return NT_STATUS_NO_MEMORY
;
1622 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "sAMAccountName", alias_name
);
1623 samdb_msg_add_string(d_state
->sam_ctx
, mem_ctx
, msg
, "objectClass", "group");
1624 samdb_msg_add_int(d_state
->sam_ctx
, mem_ctx
, msg
, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1626 /* create the alias */
1627 ret
= ldb_add(d_state
->sam_ctx
, msg
);
1631 case LDB_ERR_ENTRY_ALREADY_EXISTS
:
1632 return NT_STATUS_ALIAS_EXISTS
;
1633 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
1634 return NT_STATUS_ACCESS_DENIED
;
1636 DEBUG(0,("Failed to create alias record %s: %s\n",
1637 ldb_dn_get_linearized(msg
->dn
),
1638 ldb_errstring(d_state
->sam_ctx
)));
1639 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1642 a_state
= talloc(d_state
, struct samr_account_state
);
1644 return NT_STATUS_NO_MEMORY
;
1647 a_state
->sam_ctx
= d_state
->sam_ctx
;
1648 a_state
->access_mask
= r
->in
.access_mask
;
1649 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
1650 a_state
->account_dn
= talloc_steal(a_state
, msg
->dn
);
1652 /* retrieve the sid for the alias just created */
1653 sid
= samdb_search_dom_sid(d_state
->sam_ctx
, a_state
,
1654 msg
->dn
, "objectSid", NULL
);
1656 a_state
->account_name
= talloc_strdup(a_state
, alias_name
);
1657 if (!a_state
->account_name
) {
1658 return NT_STATUS_NO_MEMORY
;
1661 /* create the policy handle */
1662 a_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_ALIAS
);
1663 if (a_handle
== NULL
)
1664 return NT_STATUS_NO_MEMORY
;
1666 a_handle
->data
= talloc_steal(a_handle
, a_state
);
1668 *r
->out
.alias_handle
= a_handle
->wire_handle
;
1670 *r
->out
.rid
= sid
->sub_auths
[sid
->num_auths
-1];
1672 return NT_STATUS_OK
;
1677 samr_EnumDomainAliases
1679 static NTSTATUS
dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1680 struct samr_EnumDomainAliases
*r
)
1682 struct dcesrv_handle
*h
;
1683 struct samr_domain_state
*d_state
;
1684 struct ldb_message
**res
;
1685 int ldb_cnt
, count
, i
, first
;
1686 struct samr_SamEntry
*entries
;
1687 const char * const attrs
[3] = { "objectSid", "sAMAccountName", NULL
};
1689 *r
->out
.resume_handle
= 0;
1691 r
->out
.num_entries
= 0;
1693 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1697 /* search for all domain groups in this domain. This could possibly be
1698 cached and resumed based on resume_key */
1699 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1702 d_state
->domain_sid
,
1703 "(&(|(grouptype=%d)(grouptype=%d)))"
1704 "(objectclass=group))",
1705 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
1706 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1707 if (ldb_cnt
== -1) {
1708 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1711 return NT_STATUS_OK
;
1714 /* convert to SamEntry format */
1715 entries
= talloc_array(mem_ctx
, struct samr_SamEntry
, ldb_cnt
);
1717 return NT_STATUS_NO_MEMORY
;
1722 for (i
=0;i
<ldb_cnt
;i
++) {
1723 struct dom_sid
*alias_sid
;
1725 alias_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
1728 if (alias_sid
== NULL
)
1731 entries
[count
].idx
=
1732 alias_sid
->sub_auths
[alias_sid
->num_auths
-1];
1733 entries
[count
].name
.string
=
1734 samdb_result_string(res
[i
], "sAMAccountName", "");
1738 /* sort the results by rid */
1739 qsort(entries
, count
, sizeof(struct samr_SamEntry
),
1740 (comparison_fn_t
)compare_SamEntry
);
1742 /* find the first entry to return */
1744 first
<count
&& entries
[first
].idx
<= *r
->in
.resume_handle
;
1747 if (first
== count
) {
1748 return NT_STATUS_OK
;
1751 r
->out
.num_entries
= count
- first
;
1752 r
->out
.num_entries
= MIN(r
->out
.num_entries
, 1000);
1754 r
->out
.sam
= talloc(mem_ctx
, struct samr_SamArray
);
1756 return NT_STATUS_NO_MEMORY
;
1759 r
->out
.sam
->entries
= entries
+first
;
1760 r
->out
.sam
->count
= r
->out
.num_entries
;
1762 if (r
->out
.num_entries
< count
- first
) {
1763 *r
->out
.resume_handle
=
1764 entries
[first
+r
->out
.num_entries
-1].idx
;
1765 return STATUS_MORE_ENTRIES
;
1768 return NT_STATUS_OK
;
1773 samr_GetAliasMembership
1775 static NTSTATUS
dcesrv_samr_GetAliasMembership(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1776 struct samr_GetAliasMembership
*r
)
1778 struct dcesrv_handle
*h
;
1779 struct samr_domain_state
*d_state
;
1780 struct ldb_message
**res
;
1783 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1787 if (r
->in
.sids
->num_sids
> 0) {
1789 const char * const attrs
[2] = { "objectSid", NULL
};
1791 filter
= talloc_asprintf(mem_ctx
,
1792 "(&(|(grouptype=%d)(grouptype=%d))"
1793 "(objectclass=group)(|",
1794 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
1795 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
1797 return NT_STATUS_NO_MEMORY
;
1799 for (i
=0; i
<r
->in
.sids
->num_sids
; i
++) {
1800 const char *memberdn
;
1803 samdb_search_string(d_state
->sam_ctx
,
1804 mem_ctx
, NULL
, "distinguishedName",
1806 ldap_encode_ndr_dom_sid(mem_ctx
,
1807 r
->in
.sids
->sids
[i
].sid
));
1809 if (memberdn
== NULL
)
1812 filter
= talloc_asprintf(mem_ctx
, "%s(member=%s)",
1815 return NT_STATUS_NO_MEMORY
;
1818 count
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
1819 d_state
->domain_dn
, &res
, attrs
,
1820 d_state
->domain_sid
, "%s))", filter
);
1822 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1825 r
->out
.rids
->count
= 0;
1826 r
->out
.rids
->ids
= talloc_array(mem_ctx
, uint32_t, count
);
1827 if (r
->out
.rids
->ids
== NULL
)
1828 return NT_STATUS_NO_MEMORY
;
1830 for (i
=0; i
<count
; i
++) {
1831 struct dom_sid
*alias_sid
;
1833 alias_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
], "objectSid");
1835 if (alias_sid
== NULL
) {
1836 DEBUG(0, ("Could not find objectSid\n"));
1840 r
->out
.rids
->ids
[r
->out
.rids
->count
] =
1841 alias_sid
->sub_auths
[alias_sid
->num_auths
-1];
1842 r
->out
.rids
->count
+= 1;
1845 return NT_STATUS_OK
;
1852 static NTSTATUS
dcesrv_samr_LookupNames(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1853 struct samr_LookupNames
*r
)
1855 struct dcesrv_handle
*h
;
1856 struct samr_domain_state
*d_state
;
1858 NTSTATUS status
= NT_STATUS_OK
;
1859 const char * const attrs
[] = { "sAMAccountType", "objectSid", NULL
};
1862 ZERO_STRUCT(r
->out
.rids
);
1863 ZERO_STRUCT(r
->out
.types
);
1865 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1869 if (r
->in
.num_names
== 0) {
1870 return NT_STATUS_OK
;
1873 r
->out
.rids
.ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_names
);
1874 r
->out
.types
.ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_names
);
1875 if (!r
->out
.rids
.ids
|| !r
->out
.types
.ids
) {
1876 return NT_STATUS_NO_MEMORY
;
1878 r
->out
.rids
.count
= r
->in
.num_names
;
1879 r
->out
.types
.count
= r
->in
.num_names
;
1883 for (i
=0;i
<r
->in
.num_names
;i
++) {
1884 struct ldb_message
**res
;
1885 struct dom_sid
*sid
;
1886 uint32_t atype
, rtype
;
1888 r
->out
.rids
.ids
[i
] = 0;
1889 r
->out
.types
.ids
[i
] = SID_NAME_UNKNOWN
;
1891 count
= gendb_search(d_state
->sam_ctx
, mem_ctx
, d_state
->domain_dn
, &res
, attrs
,
1892 "sAMAccountName=%s",
1893 ldb_binary_encode_string(mem_ctx
, r
->in
.names
[i
].string
));
1895 status
= STATUS_SOME_UNMAPPED
;
1899 sid
= samdb_result_dom_sid(mem_ctx
, res
[0], "objectSid");
1901 status
= STATUS_SOME_UNMAPPED
;
1905 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
1907 status
= STATUS_SOME_UNMAPPED
;
1911 rtype
= samdb_atype_map(atype
);
1913 if (rtype
== SID_NAME_UNKNOWN
) {
1914 status
= STATUS_SOME_UNMAPPED
;
1918 r
->out
.rids
.ids
[i
] = sid
->sub_auths
[sid
->num_auths
-1];
1919 r
->out
.types
.ids
[i
] = rtype
;
1923 if (num_mapped
== 0) {
1924 return NT_STATUS_NONE_MAPPED
;
1933 static NTSTATUS
dcesrv_samr_LookupRids(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
1934 struct samr_LookupRids
*r
)
1936 struct dcesrv_handle
*h
;
1937 struct samr_domain_state
*d_state
;
1939 NTSTATUS status
= NT_STATUS_OK
;
1940 struct lsa_String
*names
;
1943 ZERO_STRUCT(r
->out
.names
);
1944 ZERO_STRUCT(r
->out
.types
);
1946 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
1950 if (r
->in
.num_rids
== 0)
1951 return NT_STATUS_OK
;
1953 names
= talloc_array(mem_ctx
, struct lsa_String
, r
->in
.num_rids
);
1954 ids
= talloc_array(mem_ctx
, uint32_t, r
->in
.num_rids
);
1956 if ((names
== NULL
) || (ids
== NULL
))
1957 return NT_STATUS_NO_MEMORY
;
1961 for (i
=0; i
<r
->in
.num_rids
; i
++) {
1962 struct ldb_message
**res
;
1964 const char * const attrs
[] = { "sAMAccountType",
1965 "sAMAccountName", NULL
};
1967 struct dom_sid
*sid
;
1969 ids
[i
] = SID_NAME_UNKNOWN
;
1971 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rids
[i
]);
1973 names
[i
].string
= NULL
;
1974 status
= STATUS_SOME_UNMAPPED
;
1978 count
= gendb_search(d_state
->sam_ctx
, mem_ctx
,
1979 d_state
->domain_dn
, &res
, attrs
,
1981 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
1983 names
[i
].string
= NULL
;
1984 status
= STATUS_SOME_UNMAPPED
;
1988 names
[i
].string
= samdb_result_string(res
[0], "sAMAccountName",
1991 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
1993 status
= STATUS_SOME_UNMAPPED
;
1997 ids
[i
] = samdb_atype_map(atype
);
1999 if (ids
[i
] == SID_NAME_UNKNOWN
) {
2000 status
= STATUS_SOME_UNMAPPED
;
2005 r
->out
.names
.names
= names
;
2006 r
->out
.names
.count
= r
->in
.num_rids
;
2008 r
->out
.types
.ids
= ids
;
2009 r
->out
.types
.count
= r
->in
.num_rids
;
2018 static NTSTATUS
dcesrv_samr_OpenGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2019 struct samr_OpenGroup
*r
)
2021 struct samr_domain_state
*d_state
;
2022 struct samr_account_state
*a_state
;
2023 struct dcesrv_handle
*h
;
2024 const char *groupname
;
2025 struct dom_sid
*sid
;
2026 struct ldb_message
**msgs
;
2027 struct dcesrv_handle
*g_handle
;
2028 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2031 ZERO_STRUCTP(r
->out
.group_handle
);
2033 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2037 /* form the group SID */
2038 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2040 return NT_STATUS_NO_MEMORY
;
2043 /* search for the group record */
2044 ret
= gendb_search(d_state
->sam_ctx
,
2045 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2046 "(&(objectSid=%s)(objectclass=group)"
2048 ldap_encode_ndr_dom_sid(mem_ctx
, sid
),
2049 GTYPE_SECURITY_GLOBAL_GROUP
);
2051 return NT_STATUS_NO_SUCH_GROUP
;
2054 DEBUG(0,("Found %d records matching sid %s\n",
2055 ret
, dom_sid_string(mem_ctx
, sid
)));
2056 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2059 groupname
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2060 if (groupname
== NULL
) {
2061 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2062 dom_sid_string(mem_ctx
, sid
)));
2063 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2066 a_state
= talloc(d_state
, struct samr_account_state
);
2068 return NT_STATUS_NO_MEMORY
;
2070 a_state
->sam_ctx
= d_state
->sam_ctx
;
2071 a_state
->access_mask
= r
->in
.access_mask
;
2072 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2073 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2074 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2075 a_state
->account_name
= talloc_strdup(a_state
, groupname
);
2076 if (!a_state
->account_name
) {
2077 return NT_STATUS_NO_MEMORY
;
2080 /* create the policy handle */
2081 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_GROUP
);
2083 return NT_STATUS_NO_MEMORY
;
2086 g_handle
->data
= talloc_steal(g_handle
, a_state
);
2088 *r
->out
.group_handle
= g_handle
->wire_handle
;
2090 return NT_STATUS_OK
;
2096 static NTSTATUS
dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2097 struct samr_QueryGroupInfo
*r
)
2099 struct dcesrv_handle
*h
;
2100 struct samr_account_state
*a_state
;
2101 struct ldb_message
*msg
;
2102 struct ldb_result
*res
;
2103 const char * const attrs
[4] = { "sAMAccountName", "description",
2104 "numMembers", NULL
};
2109 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2113 ret
= ldb_search(a_state
->sam_ctx
, mem_ctx
, &res
, a_state
->account_dn
, LDB_SCOPE_SUBTREE
, attrs
, "objectClass=*");
2115 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
2116 return NT_STATUS_NO_SUCH_GROUP
;
2117 } else if (ret
!= LDB_SUCCESS
) {
2118 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state
->sam_ctx
)));
2119 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2122 if (res
->count
!= 1) {
2123 DEBUG(2, ("Error finding group info, got %d entries\n", res
->count
));
2125 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2129 /* allocate the info structure */
2130 r
->out
.info
= talloc(mem_ctx
, union samr_GroupInfo
);
2131 if (r
->out
.info
== NULL
) {
2132 return NT_STATUS_NO_MEMORY
;
2134 ZERO_STRUCTP(r
->out
.info
);
2136 /* Fill in the level */
2137 switch (r
->in
.level
) {
2139 QUERY_STRING(msg
, all
.name
, "sAMAccountName");
2140 r
->out
.info
->all
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2141 QUERY_UINT (msg
, all
.num_members
, "numMembers")
2142 QUERY_STRING(msg
, all
.description
, "description");
2145 QUERY_STRING(msg
, name
, "sAMAccountName");
2147 case GROUPINFOATTRIBUTES
:
2148 r
->out
.info
->attributes
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2150 case GROUPINFODESCRIPTION
:
2151 QUERY_STRING(msg
, description
, "description");
2154 QUERY_STRING(msg
, all2
.name
, "sAMAccountName");
2155 r
->out
.info
->all
.attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
; /* Do like w2k3 */
2156 QUERY_UINT (msg
, all2
.num_members
, "numMembers")
2157 QUERY_STRING(msg
, all2
.description
, "description");
2161 return NT_STATUS_INVALID_INFO_CLASS
;
2164 return NT_STATUS_OK
;
2171 static NTSTATUS
dcesrv_samr_SetGroupInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2172 struct samr_SetGroupInfo
*r
)
2174 struct dcesrv_handle
*h
;
2175 struct samr_account_state
*g_state
;
2176 struct ldb_message
*msg
;
2177 struct ldb_context
*sam_ctx
;
2180 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2183 sam_ctx
= g_state
->sam_ctx
;
2185 msg
= ldb_msg_new(mem_ctx
);
2187 return NT_STATUS_NO_MEMORY
;
2190 msg
->dn
= ldb_dn_copy(mem_ctx
, g_state
->account_dn
);
2192 return NT_STATUS_NO_MEMORY
;
2195 switch (r
->in
.level
) {
2196 case GROUPINFODESCRIPTION
:
2197 SET_STRING(msg
, description
, "description");
2200 /* On W2k3 this does not change the name, it changes the
2201 * sAMAccountName attribute */
2202 SET_STRING(msg
, name
, "sAMAccountName");
2204 case GROUPINFOATTRIBUTES
:
2205 /* This does not do anything obviously visible in W2k3 LDAP */
2206 return NT_STATUS_OK
;
2208 return NT_STATUS_INVALID_INFO_CLASS
;
2211 /* modify the samdb record */
2212 ret
= ldb_modify(g_state
->sam_ctx
, msg
);
2214 /* we really need samdb.c to return NTSTATUS */
2215 return NT_STATUS_UNSUCCESSFUL
;
2218 return NT_STATUS_OK
;
2225 static NTSTATUS
dcesrv_samr_AddGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2226 struct samr_AddGroupMember
*r
)
2228 struct dcesrv_handle
*h
;
2229 struct samr_account_state
*a_state
;
2230 struct samr_domain_state
*d_state
;
2231 struct ldb_message
*mod
;
2232 struct dom_sid
*membersid
;
2233 const char *memberdn
;
2234 struct ldb_result
*res
;
2235 const char * const attrs
[] = { NULL
};
2238 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2241 d_state
= a_state
->domain_state
;
2243 membersid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2244 if (membersid
== NULL
)
2245 return NT_STATUS_NO_MEMORY
;
2247 /* In native mode, AD can also nest domain groups. Not sure yet
2248 * whether this is also available via RPC. */
2249 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
,
2250 d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
,
2251 "(&(objectSid=%s)(objectclass=user))",
2252 ldap_encode_ndr_dom_sid(mem_ctx
, membersid
));
2255 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2258 if (res
->count
== 0) {
2259 return NT_STATUS_NO_SUCH_USER
;
2262 if (res
->count
> 1) {
2263 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2266 memberdn
= ldb_dn_alloc_linearized(mem_ctx
, res
->msgs
[0]->dn
);
2268 if (memberdn
== NULL
)
2269 return NT_STATUS_NO_MEMORY
;
2271 mod
= ldb_msg_new(mem_ctx
);
2273 return NT_STATUS_NO_MEMORY
;
2276 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2278 if (samdb_msg_add_addval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2280 return NT_STATUS_UNSUCCESSFUL
;
2282 ret
= ldb_modify(a_state
->sam_ctx
, mod
);
2285 return NT_STATUS_OK
;
2286 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
:
2287 return NT_STATUS_MEMBER_IN_GROUP
;
2288 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
2289 return NT_STATUS_ACCESS_DENIED
;
2291 return NT_STATUS_UNSUCCESSFUL
;
2298 samr_DeleteDomainGroup
2300 static NTSTATUS
dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2301 struct samr_DeleteDomainGroup
*r
)
2303 struct dcesrv_handle
*h
;
2304 struct samr_account_state
*a_state
;
2307 *r
->out
.group_handle
= *r
->in
.group_handle
;
2309 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2313 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2315 return NT_STATUS_UNSUCCESSFUL
;
2318 ZERO_STRUCTP(r
->out
.group_handle
);
2320 return NT_STATUS_OK
;
2325 samr_DeleteGroupMember
2327 static NTSTATUS
dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2328 struct samr_DeleteGroupMember
*r
)
2330 struct dcesrv_handle
*h
;
2331 struct samr_account_state
*a_state
;
2332 struct samr_domain_state
*d_state
;
2333 struct ldb_message
*mod
;
2334 struct dom_sid
*membersid
;
2335 const char *memberdn
;
2336 struct ldb_result
*res
;
2337 const char * const attrs
[] = { NULL
};
2340 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2343 d_state
= a_state
->domain_state
;
2345 membersid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2346 if (membersid
== NULL
)
2347 return NT_STATUS_NO_MEMORY
;
2349 /* In native mode, AD can also nest domain groups. Not sure yet
2350 * whether this is also available via RPC. */
2351 ret
= ldb_search(d_state
->sam_ctx
, mem_ctx
, &res
,
2352 d_state
->domain_dn
, LDB_SCOPE_SUBTREE
, attrs
,
2353 "(&(objectSid=%s)(objectclass=user))",
2354 ldap_encode_ndr_dom_sid(mem_ctx
, membersid
));
2357 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2360 if (res
->count
== 0) {
2361 return NT_STATUS_NO_SUCH_USER
;
2364 if (res
->count
> 1) {
2365 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2368 memberdn
= ldb_dn_alloc_linearized(mem_ctx
, res
->msgs
[0]->dn
);
2370 if (memberdn
== NULL
)
2371 return NT_STATUS_NO_MEMORY
;
2373 mod
= ldb_msg_new(mem_ctx
);
2375 return NT_STATUS_NO_MEMORY
;
2378 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2380 if (samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2382 return NT_STATUS_NO_MEMORY
;
2385 ret
= ldb_modify(a_state
->sam_ctx
, mod
);
2388 return NT_STATUS_OK
;
2389 case LDB_ERR_NO_SUCH_ATTRIBUTE
:
2390 return NT_STATUS_MEMBER_NOT_IN_GROUP
;
2391 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
:
2392 return NT_STATUS_ACCESS_DENIED
;
2394 return NT_STATUS_UNSUCCESSFUL
;
2401 samr_QueryGroupMember
2403 static NTSTATUS
dcesrv_samr_QueryGroupMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2404 struct samr_QueryGroupMember
*r
)
2406 struct dcesrv_handle
*h
;
2407 struct samr_account_state
*a_state
;
2408 struct ldb_message
**res
;
2409 struct ldb_message_element
*el
;
2410 struct samr_RidTypeArray
*array
;
2411 const char * const attrs
[2] = { "member", NULL
};
2414 DCESRV_PULL_HANDLE(h
, r
->in
.group_handle
, SAMR_HANDLE_GROUP
);
2418 /* pull the member attribute */
2419 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2420 a_state
->account_dn
, &res
, attrs
);
2423 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2426 array
= talloc(mem_ctx
, struct samr_RidTypeArray
);
2429 return NT_STATUS_NO_MEMORY
;
2431 ZERO_STRUCTP(array
);
2433 el
= ldb_msg_find_element(res
[0], "member");
2438 array
->count
= el
->num_values
;
2440 array
->rids
= talloc_array(mem_ctx
, uint32_t,
2442 if (array
->rids
== NULL
)
2443 return NT_STATUS_NO_MEMORY
;
2445 array
->types
= talloc_array(mem_ctx
, uint32_t,
2447 if (array
->types
== NULL
)
2448 return NT_STATUS_NO_MEMORY
;
2450 for (i
=0; i
<el
->num_values
; i
++) {
2451 struct ldb_message
**res2
;
2452 const char * const attrs2
[2] = { "objectSid", NULL
};
2453 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2454 ldb_dn_new(mem_ctx
, a_state
->sam_ctx
, (const char *)el
->values
[i
].data
),
2457 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2460 samdb_result_rid_from_sid(mem_ctx
, res2
[0],
2463 if (array
->rids
[i
] == 0)
2464 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2466 array
->types
[i
] = 7; /* RID type of some kind, not sure what the value means. */
2470 r
->out
.rids
= array
;
2472 return NT_STATUS_OK
;
2477 samr_SetMemberAttributesOfGroup
2479 static NTSTATUS
dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2480 struct samr_SetMemberAttributesOfGroup
*r
)
2482 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
2489 static NTSTATUS
dcesrv_samr_OpenAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2490 struct samr_OpenAlias
*r
)
2492 struct samr_domain_state
*d_state
;
2493 struct samr_account_state
*a_state
;
2494 struct dcesrv_handle
*h
;
2495 const char *alias_name
;
2496 struct dom_sid
*sid
;
2497 struct ldb_message
**msgs
;
2498 struct dcesrv_handle
*g_handle
;
2499 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2502 ZERO_STRUCTP(r
->out
.alias_handle
);
2504 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2508 /* form the alias SID */
2509 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2511 return NT_STATUS_NO_MEMORY
;
2513 /* search for the group record */
2514 ret
= gendb_search(d_state
->sam_ctx
,
2515 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2516 "(&(objectSid=%s)(objectclass=group)"
2517 "(|(grouptype=%d)(grouptype=%d)))",
2518 ldap_encode_ndr_dom_sid(mem_ctx
, sid
),
2519 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
2520 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
2522 return NT_STATUS_NO_SUCH_ALIAS
;
2525 DEBUG(0,("Found %d records matching sid %s\n",
2526 ret
, dom_sid_string(mem_ctx
, sid
)));
2527 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2530 alias_name
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2531 if (alias_name
== NULL
) {
2532 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2533 dom_sid_string(mem_ctx
, sid
)));
2534 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2537 a_state
= talloc(d_state
, struct samr_account_state
);
2539 return NT_STATUS_NO_MEMORY
;
2541 a_state
->sam_ctx
= d_state
->sam_ctx
;
2542 a_state
->access_mask
= r
->in
.access_mask
;
2543 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2544 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2545 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2546 a_state
->account_name
= talloc_strdup(a_state
, alias_name
);
2547 if (!a_state
->account_name
) {
2548 return NT_STATUS_NO_MEMORY
;
2551 /* create the policy handle */
2552 g_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_ALIAS
);
2554 return NT_STATUS_NO_MEMORY
;
2557 g_handle
->data
= talloc_steal(g_handle
, a_state
);
2559 *r
->out
.alias_handle
= g_handle
->wire_handle
;
2561 return NT_STATUS_OK
;
2568 static NTSTATUS
dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2569 struct samr_QueryAliasInfo
*r
)
2571 struct dcesrv_handle
*h
;
2572 struct samr_account_state
*a_state
;
2573 struct ldb_message
*msg
, **res
;
2574 const char * const attrs
[4] = { "sAMAccountName", "description",
2575 "numMembers", NULL
};
2580 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2584 /* pull all the alias attributes */
2585 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2586 a_state
->account_dn
,&res
, attrs
);
2588 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2592 /* allocate the info structure */
2593 r
->out
.info
= talloc(mem_ctx
, union samr_AliasInfo
);
2594 if (r
->out
.info
== NULL
) {
2595 return NT_STATUS_NO_MEMORY
;
2597 ZERO_STRUCTP(r
->out
.info
);
2599 switch(r
->in
.level
) {
2601 QUERY_STRING(msg
, all
.name
, "sAMAccountName");
2602 QUERY_UINT (msg
, all
.num_members
, "numMembers");
2603 QUERY_STRING(msg
, all
.description
, "description");
2606 QUERY_STRING(msg
, name
, "sAMAccountName");
2608 case ALIASINFODESCRIPTION
:
2609 QUERY_STRING(msg
, description
, "description");
2613 return NT_STATUS_INVALID_INFO_CLASS
;
2616 return NT_STATUS_OK
;
2623 static NTSTATUS
dcesrv_samr_SetAliasInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2624 struct samr_SetAliasInfo
*r
)
2626 struct dcesrv_handle
*h
;
2627 struct samr_account_state
*a_state
;
2628 struct ldb_message
*msg
;
2629 struct ldb_context
*sam_ctx
;
2632 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2635 sam_ctx
= a_state
->sam_ctx
;
2637 msg
= ldb_msg_new(mem_ctx
);
2639 return NT_STATUS_NO_MEMORY
;
2642 msg
->dn
= ldb_dn_copy(mem_ctx
, a_state
->account_dn
);
2644 return NT_STATUS_NO_MEMORY
;
2647 switch (r
->in
.level
) {
2648 case ALIASINFODESCRIPTION
:
2649 SET_STRING(msg
, description
, "description");
2652 /* On W2k3 this does not change the name, it changes the
2653 * sAMAccountName attribute */
2654 SET_STRING(msg
, name
, "sAMAccountName");
2657 return NT_STATUS_INVALID_INFO_CLASS
;
2660 /* modify the samdb record */
2661 ret
= ldb_modify(a_state
->sam_ctx
, msg
);
2663 /* we really need samdb.c to return NTSTATUS */
2664 return NT_STATUS_UNSUCCESSFUL
;
2667 return NT_STATUS_OK
;
2674 static NTSTATUS
dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2675 struct samr_DeleteDomAlias
*r
)
2677 struct dcesrv_handle
*h
;
2678 struct samr_account_state
*a_state
;
2681 *r
->out
.alias_handle
= *r
->in
.alias_handle
;
2683 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2687 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2689 return NT_STATUS_UNSUCCESSFUL
;
2692 ZERO_STRUCTP(r
->out
.alias_handle
);
2694 return NT_STATUS_OK
;
2701 static NTSTATUS
dcesrv_samr_AddAliasMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2702 struct samr_AddAliasMember
*r
)
2704 struct dcesrv_handle
*h
;
2705 struct samr_account_state
*a_state
;
2706 struct samr_domain_state
*d_state
;
2707 struct ldb_message
*mod
;
2708 struct ldb_message
**msgs
;
2709 const char * const attrs
[] = { NULL
};
2710 struct ldb_dn
*memberdn
= NULL
;
2714 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2717 d_state
= a_state
->domain_state
;
2719 ret
= gendb_search(d_state
->sam_ctx
, mem_ctx
, NULL
,
2720 &msgs
, attrs
, "(objectsid=%s)",
2721 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
2724 memberdn
= msgs
[0]->dn
;
2725 } else if (ret
> 1) {
2726 DEBUG(0,("Found %d records matching sid %s\n",
2727 ret
, dom_sid_string(mem_ctx
, r
->in
.sid
)));
2728 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2729 } else if (ret
== 0) {
2730 status
= samdb_create_foreign_security_principal(d_state
->sam_ctx
, mem_ctx
,
2731 r
->in
.sid
, &memberdn
);
2732 if (!NT_STATUS_IS_OK(status
)) {
2736 DEBUG(0, ("samdb_search returned %d: %s\n", ret
, ldb_errstring(d_state
->sam_ctx
)));
2739 if (memberdn
== NULL
) {
2740 DEBUG(0, ("Could not find memberdn\n"));
2741 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2744 mod
= ldb_msg_new(mem_ctx
);
2746 return NT_STATUS_NO_MEMORY
;
2749 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2751 if (samdb_msg_add_addval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2752 ldb_dn_alloc_linearized(mem_ctx
, memberdn
)) != 0)
2753 return NT_STATUS_UNSUCCESSFUL
;
2755 if (ldb_modify(a_state
->sam_ctx
, mod
) != 0)
2756 return NT_STATUS_UNSUCCESSFUL
;
2758 return NT_STATUS_OK
;
2763 samr_DeleteAliasMember
2765 static NTSTATUS
dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2766 struct samr_DeleteAliasMember
*r
)
2768 struct dcesrv_handle
*h
;
2769 struct samr_account_state
*a_state
;
2770 struct samr_domain_state
*d_state
;
2771 struct ldb_message
*mod
;
2772 const char *memberdn
;
2774 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2777 d_state
= a_state
->domain_state
;
2779 memberdn
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
2780 "distinguishedName", "(objectSid=%s)",
2781 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
2783 if (memberdn
== NULL
)
2784 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2786 mod
= ldb_msg_new(mem_ctx
);
2788 return NT_STATUS_NO_MEMORY
;
2791 mod
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
2793 if (samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
, "member",
2795 return NT_STATUS_UNSUCCESSFUL
;
2797 if (ldb_modify(a_state
->sam_ctx
, mod
) != 0)
2798 return NT_STATUS_UNSUCCESSFUL
;
2800 return NT_STATUS_OK
;
2805 samr_GetMembersInAlias
2807 static NTSTATUS
dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2808 struct samr_GetMembersInAlias
*r
)
2810 struct dcesrv_handle
*h
;
2811 struct samr_account_state
*a_state
;
2812 struct samr_domain_state
*d_state
;
2813 struct ldb_message
**msgs
;
2814 struct lsa_SidPtr
*sids
;
2815 struct ldb_message_element
*el
;
2816 const char * const attrs
[2] = { "member", NULL
};
2819 DCESRV_PULL_HANDLE(h
, r
->in
.alias_handle
, SAMR_HANDLE_ALIAS
);
2822 d_state
= a_state
->domain_state
;
2824 ret
= gendb_search_dn(d_state
->sam_ctx
, mem_ctx
,
2825 a_state
->account_dn
, &msgs
, attrs
);
2828 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2830 r
->out
.sids
->num_sids
= 0;
2831 r
->out
.sids
->sids
= NULL
;
2833 el
= ldb_msg_find_element(msgs
[0], "member");
2838 sids
= talloc_array(mem_ctx
, struct lsa_SidPtr
,
2842 return NT_STATUS_NO_MEMORY
;
2844 for (i
=0; i
<el
->num_values
; i
++) {
2845 struct ldb_message
**msgs2
;
2846 const char * const attrs2
[2] = { "objectSid", NULL
};
2847 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
2848 ldb_dn_new(mem_ctx
, a_state
->sam_ctx
, (const char *)el
->values
[i
].data
),
2851 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2853 sids
[i
].sid
= samdb_result_dom_sid(mem_ctx
, msgs2
[0],
2856 if (sids
[i
].sid
== NULL
)
2857 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2859 r
->out
.sids
->num_sids
= el
->num_values
;
2860 r
->out
.sids
->sids
= sids
;
2863 return NT_STATUS_OK
;
2869 static NTSTATUS
dcesrv_samr_OpenUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2870 struct samr_OpenUser
*r
)
2872 struct samr_domain_state
*d_state
;
2873 struct samr_account_state
*a_state
;
2874 struct dcesrv_handle
*h
;
2875 const char *account_name
;
2876 struct dom_sid
*sid
;
2877 struct ldb_message
**msgs
;
2878 struct dcesrv_handle
*u_handle
;
2879 const char * const attrs
[2] = { "sAMAccountName", NULL
};
2882 ZERO_STRUCTP(r
->out
.user_handle
);
2884 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
2888 /* form the users SID */
2889 sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
2891 return NT_STATUS_NO_MEMORY
;
2894 /* search for the user record */
2895 ret
= gendb_search(d_state
->sam_ctx
,
2896 mem_ctx
, d_state
->domain_dn
, &msgs
, attrs
,
2897 "(&(objectSid=%s)(objectclass=user))",
2898 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
2900 return NT_STATUS_NO_SUCH_USER
;
2903 DEBUG(0,("Found %d records matching sid %s\n", ret
,
2904 dom_sid_string(mem_ctx
, sid
)));
2905 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2908 account_name
= samdb_result_string(msgs
[0], "sAMAccountName", NULL
);
2909 if (account_name
== NULL
) {
2910 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2911 dom_sid_string(mem_ctx
, sid
)));
2912 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2915 a_state
= talloc(mem_ctx
, struct samr_account_state
);
2917 return NT_STATUS_NO_MEMORY
;
2919 a_state
->sam_ctx
= d_state
->sam_ctx
;
2920 a_state
->access_mask
= r
->in
.access_mask
;
2921 a_state
->domain_state
= talloc_reference(a_state
, d_state
);
2922 a_state
->account_dn
= talloc_steal(a_state
, msgs
[0]->dn
);
2923 a_state
->account_sid
= talloc_steal(a_state
, sid
);
2924 a_state
->account_name
= talloc_strdup(a_state
, account_name
);
2925 if (!a_state
->account_name
) {
2926 return NT_STATUS_NO_MEMORY
;
2929 /* create the policy handle */
2930 u_handle
= dcesrv_handle_new(dce_call
->context
, SAMR_HANDLE_USER
);
2932 return NT_STATUS_NO_MEMORY
;
2935 u_handle
->data
= talloc_steal(u_handle
, a_state
);
2937 *r
->out
.user_handle
= u_handle
->wire_handle
;
2939 return NT_STATUS_OK
;
2947 static NTSTATUS
dcesrv_samr_DeleteUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2948 struct samr_DeleteUser
*r
)
2950 struct dcesrv_handle
*h
;
2951 struct samr_account_state
*a_state
;
2954 *r
->out
.user_handle
= *r
->in
.user_handle
;
2956 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
2960 ret
= ldb_delete(a_state
->sam_ctx
, a_state
->account_dn
);
2962 DEBUG(1, ("Failed to delete user: %s: %s\n",
2963 ldb_dn_get_linearized(a_state
->account_dn
),
2964 ldb_errstring(a_state
->sam_ctx
)));
2965 return NT_STATUS_UNSUCCESSFUL
;
2968 ZERO_STRUCTP(r
->out
.user_handle
);
2970 return NT_STATUS_OK
;
2977 static NTSTATUS
dcesrv_samr_QueryUserInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
2978 struct samr_QueryUserInfo
*r
)
2980 struct dcesrv_handle
*h
;
2981 struct samr_account_state
*a_state
;
2982 struct ldb_message
*msg
, **res
;
2984 struct ldb_context
*sam_ctx
;
2986 const char * const *attrs
= NULL
;
2990 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
2993 sam_ctx
= a_state
->sam_ctx
;
2995 /* fill in the reply */
2996 switch (r
->in
.level
) {
2999 static const char * const attrs2
[] = {"sAMAccountName", "displayName",
3000 "primaryroupID", "description",
3007 static const char * const attrs2
[] = {"comment", "countryCode", "codePage", NULL
};
3013 static const char * const attrs2
[] = {"sAMAccountName",
3028 "userAccountControl", NULL
};
3034 static const char * const attrs2
[] = {"logonHours", NULL
};
3040 static const char * const attrs2
[] = {"sAMAccountName",
3057 "userAccountControl",
3064 static const char * const attrs2
[] = {"sAMAccountName", "displayName", NULL
};
3070 static const char * const attrs2
[] = {"sAMAccountName", NULL
};
3076 static const char * const attrs2
[] = {"displayName", NULL
};
3082 static const char * const attrs2
[] = {"primaryGroupID", NULL
};
3088 static const char * const attrs2
[] = {"homeDirectory", "homeDrive", NULL
};
3094 static const char * const attrs2
[] = {"scriptPath", NULL
};
3100 static const char * const attrs2
[] = {"profilePath", NULL
};
3106 static const char * const attrs2
[] = {"description", NULL
};
3112 static const char * const attrs2
[] = {"userWorkstations", NULL
};
3118 static const char * const attrs2
[] = {"userAccountControl", "pwdLastSet", NULL
};
3124 static const char * const attrs2
[] = {"accountExpires", NULL
};
3130 static const char * const attrs2
[] = {"userParameters", NULL
};
3136 static const char * const attrs2
[] = {"lastLogon",
3152 "userAccountControl",
3164 /* pull all the user attributes */
3165 ret
= gendb_search_dn(a_state
->sam_ctx
, mem_ctx
,
3166 a_state
->account_dn
,&res
, attrs
);
3168 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3172 /* allocate the info structure */
3173 r
->out
.info
= talloc(mem_ctx
, union samr_UserInfo
);
3174 if (r
->out
.info
== NULL
) {
3175 return NT_STATUS_NO_MEMORY
;
3177 ZERO_STRUCTP(r
->out
.info
);
3179 /* fill in the reply */
3180 switch (r
->in
.level
) {
3182 QUERY_STRING(msg
, info1
.account_name
, "sAMAccountName");
3183 QUERY_STRING(msg
, info1
.full_name
, "displayName");
3184 QUERY_UINT (msg
, info1
.primary_gid
, "primaryGroupID");
3185 QUERY_STRING(msg
, info1
.description
, "description");
3186 QUERY_STRING(msg
, info1
.comment
, "comment");
3190 QUERY_STRING(msg
, info2
.comment
, "comment");
3191 QUERY_UINT (msg
, info2
.country_code
, "countryCode");
3192 QUERY_UINT (msg
, info2
.code_page
, "codePage");
3196 QUERY_STRING(msg
, info3
.account_name
, "sAMAccountName");
3197 QUERY_STRING(msg
, info3
.full_name
, "displayName");
3198 QUERY_RID (msg
, info3
.rid
, "objectSid");
3199 QUERY_UINT (msg
, info3
.primary_gid
, "primaryGroupID");
3200 QUERY_STRING(msg
, info3
.home_directory
, "homeDirectory");
3201 QUERY_STRING(msg
, info3
.home_drive
, "homeDrive");
3202 QUERY_STRING(msg
, info3
.logon_script
, "scriptPath");
3203 QUERY_STRING(msg
, info3
.profile_path
, "profilePath");
3204 QUERY_STRING(msg
, info3
.workstations
, "userWorkstations");
3205 QUERY_UINT64(msg
, info3
.last_logon
, "lastLogon");
3206 QUERY_UINT64(msg
, info3
.last_logoff
, "lastLogoff");
3207 QUERY_UINT64(msg
, info3
.last_password_change
, "pwdLastSet");
3208 QUERY_APASSC(msg
, info3
.allow_password_change
, "pwdLastSet");
3209 QUERY_FPASSC(msg
, info3
.force_password_change
, "pwdLastSet");
3210 QUERY_LHOURS(msg
, info3
.logon_hours
, "logonHours");
3211 QUERY_UINT (msg
, info3
.bad_password_count
, "badPwdCount");
3212 QUERY_UINT (msg
, info3
.logon_count
, "logonCount");
3213 QUERY_AFLAGS(msg
, info3
.acct_flags
, "userAccountControl");
3217 QUERY_LHOURS(msg
, info4
.logon_hours
, "logonHours");
3221 QUERY_STRING(msg
, info5
.account_name
, "sAMAccountName");
3222 QUERY_STRING(msg
, info5
.full_name
, "displayName");
3223 QUERY_RID (msg
, info5
.rid
, "objectSid");
3224 QUERY_UINT (msg
, info5
.primary_gid
, "primaryGroupID");
3225 QUERY_STRING(msg
, info5
.home_directory
, "homeDirectory");
3226 QUERY_STRING(msg
, info5
.home_drive
, "homeDrive");
3227 QUERY_STRING(msg
, info5
.logon_script
, "scriptPath");
3228 QUERY_STRING(msg
, info5
.profile_path
, "profilePath");
3229 QUERY_STRING(msg
, info5
.description
, "description");
3230 QUERY_STRING(msg
, info5
.workstations
, "userWorkstations");
3231 QUERY_UINT64(msg
, info5
.last_logon
, "lastLogon");
3232 QUERY_UINT64(msg
, info5
.last_logoff
, "lastLogoff");
3233 QUERY_LHOURS(msg
, info5
.logon_hours
, "logonHours");
3234 QUERY_UINT (msg
, info5
.bad_password_count
, "badPwdCount");
3235 QUERY_UINT (msg
, info5
.logon_count
, "logonCount");
3236 QUERY_UINT64(msg
, info5
.last_password_change
, "pwdLastSet");
3237 QUERY_UINT64(msg
, info5
.acct_expiry
, "accountExpires");
3238 QUERY_AFLAGS(msg
, info5
.acct_flags
, "userAccountControl");
3242 QUERY_STRING(msg
, info6
.account_name
, "sAMAccountName");
3243 QUERY_STRING(msg
, info6
.full_name
, "displayName");
3247 QUERY_STRING(msg
, info7
.account_name
, "sAMAccountName");
3251 QUERY_STRING(msg
, info8
.full_name
, "displayName");
3255 QUERY_UINT (msg
, info9
.primary_gid
, "primaryGroupID");
3259 QUERY_STRING(msg
, info10
.home_directory
,"homeDirectory");
3260 QUERY_STRING(msg
, info10
.home_drive
, "homeDrive");
3264 QUERY_STRING(msg
, info11
.logon_script
, "scriptPath");
3268 QUERY_STRING(msg
, info12
.profile_path
, "profilePath");
3272 QUERY_STRING(msg
, info13
.description
, "description");
3276 QUERY_STRING(msg
, info14
.workstations
, "userWorkstations");
3280 QUERY_AFLAGS(msg
, info16
.acct_flags
, "userAccountControl");
3284 QUERY_UINT64(msg
, info17
.acct_expiry
, "accountExpires");
3288 QUERY_STRING(msg
, info20
.parameters
, "userParameters");
3292 QUERY_UINT64(msg
, info21
.last_logon
, "lastLogon");
3293 QUERY_UINT64(msg
, info21
.last_logoff
, "lastLogoff");
3294 QUERY_UINT64(msg
, info21
.last_password_change
, "pwdLastSet");
3295 QUERY_UINT64(msg
, info21
.acct_expiry
, "accountExpires");
3296 QUERY_APASSC(msg
, info21
.allow_password_change
,"pwdLastSet");
3297 QUERY_FPASSC(msg
, info21
.force_password_change
,"pwdLastSet");
3298 QUERY_STRING(msg
, info21
.account_name
, "sAMAccountName");
3299 QUERY_STRING(msg
, info21
.full_name
, "displayName");
3300 QUERY_STRING(msg
, info21
.home_directory
, "homeDirectory");
3301 QUERY_STRING(msg
, info21
.home_drive
, "homeDrive");
3302 QUERY_STRING(msg
, info21
.logon_script
, "scriptPath");
3303 QUERY_STRING(msg
, info21
.profile_path
, "profilePath");
3304 QUERY_STRING(msg
, info21
.description
, "description");
3305 QUERY_STRING(msg
, info21
.workstations
, "userWorkstations");
3306 QUERY_STRING(msg
, info21
.comment
, "comment");
3307 QUERY_STRING(msg
, info21
.parameters
, "userParameters");
3308 QUERY_RID (msg
, info21
.rid
, "objectSid");
3309 QUERY_UINT (msg
, info21
.primary_gid
, "primaryGroupID");
3310 QUERY_AFLAGS(msg
, info21
.acct_flags
, "userAccountControl");
3311 r
->out
.info
->info21
.fields_present
= 0x00FFFFFF;
3312 QUERY_LHOURS(msg
, info21
.logon_hours
, "logonHours");
3313 QUERY_UINT (msg
, info21
.bad_password_count
, "badPwdCount");
3314 QUERY_UINT (msg
, info21
.logon_count
, "logonCount");
3315 QUERY_UINT (msg
, info21
.country_code
, "countryCode");
3316 QUERY_UINT (msg
, info21
.code_page
, "codePage");
3322 return NT_STATUS_INVALID_INFO_CLASS
;
3325 return NT_STATUS_OK
;
3332 static NTSTATUS
dcesrv_samr_SetUserInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3333 struct samr_SetUserInfo
*r
)
3335 struct dcesrv_handle
*h
;
3336 struct samr_account_state
*a_state
;
3337 struct ldb_message
*msg
;
3339 NTSTATUS status
= NT_STATUS_OK
;
3340 struct ldb_context
*sam_ctx
;
3342 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3345 sam_ctx
= a_state
->sam_ctx
;
3347 msg
= ldb_msg_new(mem_ctx
);
3349 return NT_STATUS_NO_MEMORY
;
3352 msg
->dn
= talloc_reference(mem_ctx
, a_state
->account_dn
);
3354 return NT_STATUS_NO_MEMORY
;
3357 switch (r
->in
.level
) {
3359 SET_STRING(msg
, info2
.comment
, "comment");
3360 SET_UINT (msg
, info2
.country_code
, "countryCode");
3361 SET_UINT (msg
, info2
.code_page
, "codePage");
3365 SET_LHOURS(msg
, info4
.logon_hours
, "logonHours");
3369 SET_STRING(msg
, info6
.full_name
, "displayName");
3373 SET_STRING(msg
, info7
.account_name
, "samAccountName");
3377 SET_STRING(msg
, info8
.full_name
, "displayName");
3381 SET_UINT(msg
, info9
.primary_gid
, "primaryGroupID");
3385 SET_STRING(msg
, info10
.home_directory
, "homeDirectory");
3386 SET_STRING(msg
, info10
.home_drive
, "homeDrive");
3390 SET_STRING(msg
, info11
.logon_script
, "scriptPath");
3394 SET_STRING(msg
, info12
.profile_path
, "profilePath");
3398 SET_STRING(msg
, info13
.description
, "description");
3402 SET_STRING(msg
, info14
.workstations
, "userWorkstations");
3406 SET_AFLAGS(msg
, info16
.acct_flags
, "userAccountControl");
3410 SET_UINT64(msg
, info17
.acct_expiry
, "accountExpires");
3414 SET_STRING(msg
, info20
.parameters
, "userParameters");
3418 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3419 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3420 SET_UINT64(msg
, info21
.acct_expiry
, "accountExpires");
3421 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3422 SET_STRING(msg
, info21
.account_name
, "samAccountName");
3423 IFSET(SAMR_FIELD_FULL_NAME
)
3424 SET_STRING(msg
, info21
.full_name
, "displayName");
3425 IFSET(SAMR_FIELD_DESCRIPTION
)
3426 SET_STRING(msg
, info21
.description
, "description");
3427 IFSET(SAMR_FIELD_COMMENT
)
3428 SET_STRING(msg
, info21
.comment
, "comment");
3429 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3430 SET_STRING(msg
, info21
.logon_script
, "scriptPath");
3431 IFSET(SAMR_FIELD_PROFILE_PATH
)
3432 SET_STRING(msg
, info21
.profile_path
, "profilePath");
3433 IFSET(SAMR_FIELD_HOME_DIRECTORY
)
3434 SET_STRING(msg
, info21
.home_directory
, "homeDirectory");
3435 IFSET(SAMR_FIELD_HOME_DRIVE
)
3436 SET_STRING(msg
, info21
.home_drive
, "homeDrive");
3437 IFSET(SAMR_FIELD_WORKSTATIONS
)
3438 SET_STRING(msg
, info21
.workstations
, "userWorkstations");
3439 IFSET(SAMR_FIELD_LOGON_HOURS
)
3440 SET_LHOURS(msg
, info21
.logon_hours
, "logonHours");
3441 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3442 SET_AFLAGS(msg
, info21
.acct_flags
, "userAccountControl");
3443 IFSET(SAMR_FIELD_PARAMETERS
)
3444 SET_STRING(msg
, info21
.parameters
, "userParameters");
3445 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3446 SET_UINT (msg
, info21
.country_code
, "countryCode");
3447 IFSET(SAMR_FIELD_CODE_PAGE
)
3448 SET_UINT (msg
, info21
.code_page
, "codePage");
3453 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3454 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3455 SET_UINT64(msg
, info23
.info
.acct_expiry
, "accountExpires");
3456 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3457 SET_STRING(msg
, info23
.info
.account_name
, "samAccountName");
3458 IFSET(SAMR_FIELD_FULL_NAME
)
3459 SET_STRING(msg
, info23
.info
.full_name
, "displayName");
3460 IFSET(SAMR_FIELD_DESCRIPTION
)
3461 SET_STRING(msg
, info23
.info
.description
, "description");
3462 IFSET(SAMR_FIELD_COMMENT
)
3463 SET_STRING(msg
, info23
.info
.comment
, "comment");
3464 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3465 SET_STRING(msg
, info23
.info
.logon_script
, "scriptPath");
3466 IFSET(SAMR_FIELD_PROFILE_PATH
)
3467 SET_STRING(msg
, info23
.info
.profile_path
, "profilePath");
3468 IFSET(SAMR_FIELD_WORKSTATIONS
)
3469 SET_STRING(msg
, info23
.info
.workstations
, "userWorkstations");
3470 IFSET(SAMR_FIELD_LOGON_HOURS
)
3471 SET_LHOURS(msg
, info23
.info
.logon_hours
, "logonHours");
3472 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3473 SET_AFLAGS(msg
, info23
.info
.acct_flags
, "userAccountControl");
3474 IFSET(SAMR_FIELD_PARAMETERS
)
3475 SET_STRING(msg
, info23
.info
.parameters
, "userParameters");
3476 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3477 SET_UINT (msg
, info23
.info
.country_code
, "countryCode");
3478 IFSET(SAMR_FIELD_CODE_PAGE
)
3479 SET_UINT (msg
, info23
.info
.code_page
, "codePage");
3480 IFSET(SAMR_FIELD_PASSWORD
) {
3481 status
= samr_set_password(dce_call
,
3483 a_state
->account_dn
,
3484 a_state
->domain_state
->domain_dn
,
3486 &r
->in
.info
->info23
.password
);
3487 } else IFSET(SAMR_FIELD_PASSWORD2
) {
3488 status
= samr_set_password(dce_call
,
3490 a_state
->account_dn
,
3491 a_state
->domain_state
->domain_dn
,
3493 &r
->in
.info
->info23
.password
);
3498 /* the set password levels are handled separately */
3500 status
= samr_set_password(dce_call
,
3502 a_state
->account_dn
,
3503 a_state
->domain_state
->domain_dn
,
3505 &r
->in
.info
->info24
.password
);
3509 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3510 IFSET(SAMR_FIELD_ACCT_EXPIRY
)
3511 SET_UINT64(msg
, info25
.info
.acct_expiry
, "accountExpires");
3512 IFSET(SAMR_FIELD_ACCOUNT_NAME
)
3513 SET_STRING(msg
, info25
.info
.account_name
, "samAccountName");
3514 IFSET(SAMR_FIELD_FULL_NAME
)
3515 SET_STRING(msg
, info25
.info
.full_name
, "displayName");
3516 IFSET(SAMR_FIELD_DESCRIPTION
)
3517 SET_STRING(msg
, info25
.info
.description
, "description");
3518 IFSET(SAMR_FIELD_COMMENT
)
3519 SET_STRING(msg
, info25
.info
.comment
, "comment");
3520 IFSET(SAMR_FIELD_LOGON_SCRIPT
)
3521 SET_STRING(msg
, info25
.info
.logon_script
, "scriptPath");
3522 IFSET(SAMR_FIELD_PROFILE_PATH
)
3523 SET_STRING(msg
, info25
.info
.profile_path
, "profilePath");
3524 IFSET(SAMR_FIELD_WORKSTATIONS
)
3525 SET_STRING(msg
, info25
.info
.workstations
, "userWorkstations");
3526 IFSET(SAMR_FIELD_LOGON_HOURS
)
3527 SET_LHOURS(msg
, info25
.info
.logon_hours
, "logonHours");
3528 IFSET(SAMR_FIELD_ACCT_FLAGS
)
3529 SET_AFLAGS(msg
, info25
.info
.acct_flags
, "userAccountControl");
3530 IFSET(SAMR_FIELD_PARAMETERS
)
3531 SET_STRING(msg
, info25
.info
.parameters
, "userParameters");
3532 IFSET(SAMR_FIELD_COUNTRY_CODE
)
3533 SET_UINT (msg
, info25
.info
.country_code
, "countryCode");
3534 IFSET(SAMR_FIELD_CODE_PAGE
)
3535 SET_UINT (msg
, info25
.info
.code_page
, "codePage");
3536 IFSET(SAMR_FIELD_PASSWORD
) {
3537 status
= samr_set_password_ex(dce_call
,
3539 a_state
->account_dn
,
3540 a_state
->domain_state
->domain_dn
,
3542 &r
->in
.info
->info25
.password
);
3543 } else IFSET(SAMR_FIELD_PASSWORD2
) {
3544 status
= samr_set_password_ex(dce_call
,
3546 a_state
->account_dn
,
3547 a_state
->domain_state
->domain_dn
,
3549 &r
->in
.info
->info25
.password
);
3554 /* the set password levels are handled separately */
3556 status
= samr_set_password_ex(dce_call
,
3558 a_state
->account_dn
,
3559 a_state
->domain_state
->domain_dn
,
3561 &r
->in
.info
->info26
.password
);
3566 /* many info classes are not valid for SetUserInfo */
3567 return NT_STATUS_INVALID_INFO_CLASS
;
3570 if (!NT_STATUS_IS_OK(status
)) {
3574 /* modify the samdb record */
3575 ret
= ldb_modify(a_state
->sam_ctx
, msg
);
3577 DEBUG(1,("Failed to modify record %s: %s\n",
3578 ldb_dn_get_linearized(a_state
->account_dn
),
3579 ldb_errstring(a_state
->sam_ctx
)));
3581 /* we really need samdb.c to return NTSTATUS */
3582 return NT_STATUS_UNSUCCESSFUL
;
3585 return NT_STATUS_OK
;
3590 samr_GetGroupsForUser
3592 static NTSTATUS
dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3593 struct samr_GetGroupsForUser
*r
)
3595 struct dcesrv_handle
*h
;
3596 struct samr_account_state
*a_state
;
3597 struct samr_domain_state
*d_state
;
3598 struct ldb_message
**res
;
3599 const char * const attrs
[2] = { "objectSid", NULL
};
3600 struct samr_RidWithAttributeArray
*array
;
3603 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3606 d_state
= a_state
->domain_state
;
3608 count
= samdb_search_domain(a_state
->sam_ctx
, mem_ctx
, d_state
->domain_dn
, &res
,
3609 attrs
, d_state
->domain_sid
,
3610 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3611 ldb_dn_get_linearized(a_state
->account_dn
),
3612 GTYPE_SECURITY_GLOBAL_GROUP
);
3614 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3616 array
= talloc(mem_ctx
, struct samr_RidWithAttributeArray
);
3618 return NT_STATUS_NO_MEMORY
;
3625 array
->rids
= talloc_array(mem_ctx
, struct samr_RidWithAttribute
,
3628 if (array
->rids
== NULL
)
3629 return NT_STATUS_NO_MEMORY
;
3631 for (i
=0; i
<count
; i
++) {
3632 struct dom_sid
*group_sid
;
3634 group_sid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
3636 if (group_sid
== NULL
) {
3637 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3641 array
->rids
[array
->count
].rid
=
3642 group_sid
->sub_auths
[group_sid
->num_auths
-1];
3643 array
->rids
[array
->count
].attributes
= SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3648 r
->out
.rids
= array
;
3650 return NT_STATUS_OK
;
3655 samr_QueryDisplayInfo
3657 static NTSTATUS
dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3658 struct samr_QueryDisplayInfo
*r
)
3660 struct dcesrv_handle
*h
;
3661 struct samr_domain_state
*d_state
;
3662 struct ldb_message
**res
;
3663 int ldb_cnt
, count
, i
;
3664 const char * const attrs
[] = { "objectSid", "sAMAccountName", "displayName",
3665 "description", "userAccountControl", "pwdLastSet", NULL
};
3666 struct samr_DispEntryFull
*entriesFull
= NULL
;
3667 struct samr_DispEntryFullGroup
*entriesFullGroup
= NULL
;
3668 struct samr_DispEntryAscii
*entriesAscii
= NULL
;
3669 struct samr_DispEntryGeneral
* entriesGeneral
= NULL
;
3672 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
3676 switch (r
->in
.level
) {
3679 filter
= talloc_asprintf(mem_ctx
, "(&(objectclass=user)"
3680 "(sAMAccountType=%u))",
3681 ATYPE_NORMAL_ACCOUNT
);
3684 filter
= talloc_asprintf(mem_ctx
, "(&(objectclass=user)"
3685 "(sAMAccountType=%u))",
3686 ATYPE_WORKSTATION_TRUST
);
3690 filter
= talloc_asprintf(mem_ctx
, "(&(grouptype=%d)"
3691 "(objectclass=group))",
3692 GTYPE_SECURITY_GLOBAL_GROUP
);
3695 return NT_STATUS_INVALID_INFO_CLASS
;
3698 /* search for all requested objects in this domain. This could
3699 possibly be cached and resumed based on resume_key */
3700 ldb_cnt
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
3701 d_state
->domain_dn
, &res
, attrs
,
3702 d_state
->domain_sid
, "%s", filter
);
3703 if (ldb_cnt
== -1) {
3704 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3706 if (ldb_cnt
== 0 || r
->in
.max_entries
== 0) {
3707 return NT_STATUS_OK
;
3710 switch (r
->in
.level
) {
3712 entriesGeneral
= talloc_array(mem_ctx
,
3713 struct samr_DispEntryGeneral
,
3717 entriesFull
= talloc_array(mem_ctx
,
3718 struct samr_DispEntryFull
,
3722 entriesFullGroup
= talloc_array(mem_ctx
,
3723 struct samr_DispEntryFullGroup
,
3728 entriesAscii
= talloc_array(mem_ctx
,
3729 struct samr_DispEntryAscii
,
3734 if ((entriesGeneral
== NULL
) && (entriesFull
== NULL
) &&
3735 (entriesAscii
== NULL
) && (entriesFullGroup
== NULL
))
3736 return NT_STATUS_NO_MEMORY
;
3740 for (i
=0; i
<ldb_cnt
; i
++) {
3741 struct dom_sid
*objectsid
;
3743 objectsid
= samdb_result_dom_sid(mem_ctx
, res
[i
],
3745 if (objectsid
== NULL
)
3748 switch(r
->in
.level
) {
3750 entriesGeneral
[count
].idx
= count
+ 1;
3751 entriesGeneral
[count
].rid
=
3752 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3753 entriesGeneral
[count
].acct_flags
=
3754 samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
,
3756 d_state
->domain_dn
);
3757 entriesGeneral
[count
].account_name
.string
=
3758 samdb_result_string(res
[i
],
3759 "sAMAccountName", "");
3760 entriesGeneral
[count
].full_name
.string
=
3761 samdb_result_string(res
[i
], "displayName", "");
3762 entriesGeneral
[count
].description
.string
=
3763 samdb_result_string(res
[i
], "description", "");
3766 entriesFull
[count
].idx
= count
+ 1;
3767 entriesFull
[count
].rid
=
3768 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3770 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3771 entriesFull
[count
].acct_flags
=
3772 samdb_result_acct_flags(d_state
->sam_ctx
, mem_ctx
,
3774 d_state
->domain_dn
) | ACB_NORMAL
;
3775 entriesFull
[count
].account_name
.string
=
3776 samdb_result_string(res
[i
], "sAMAccountName",
3778 entriesFull
[count
].description
.string
=
3779 samdb_result_string(res
[i
], "description", "");
3782 entriesFullGroup
[count
].idx
= count
+ 1;
3783 entriesFullGroup
[count
].rid
=
3784 objectsid
->sub_auths
[objectsid
->num_auths
-1];
3785 /* We get a "7" here for groups */
3786 entriesFullGroup
[count
].acct_flags
3787 = SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
3788 entriesFullGroup
[count
].account_name
.string
=
3789 samdb_result_string(res
[i
], "sAMAccountName",
3791 entriesFullGroup
[count
].description
.string
=
3792 samdb_result_string(res
[i
], "description", "");
3796 entriesAscii
[count
].idx
= count
+ 1;
3797 entriesAscii
[count
].account_name
.string
=
3798 samdb_result_string(res
[i
], "sAMAccountName",
3806 r
->out
.total_size
= count
;
3808 if (r
->in
.start_idx
>= count
) {
3809 r
->out
.returned_size
= 0;
3810 switch(r
->in
.level
) {
3812 r
->out
.info
.info1
.count
= r
->out
.returned_size
;
3813 r
->out
.info
.info1
.entries
= NULL
;
3816 r
->out
.info
.info2
.count
= r
->out
.returned_size
;
3817 r
->out
.info
.info2
.entries
= NULL
;
3820 r
->out
.info
.info3
.count
= r
->out
.returned_size
;
3821 r
->out
.info
.info3
.entries
= NULL
;
3824 r
->out
.info
.info4
.count
= r
->out
.returned_size
;
3825 r
->out
.info
.info4
.entries
= NULL
;
3828 r
->out
.info
.info5
.count
= r
->out
.returned_size
;
3829 r
->out
.info
.info5
.entries
= NULL
;
3833 r
->out
.returned_size
= MIN(count
- r
->in
.start_idx
,
3835 switch(r
->in
.level
) {
3837 r
->out
.info
.info1
.count
= r
->out
.returned_size
;
3838 r
->out
.info
.info1
.entries
=
3839 &(entriesGeneral
[r
->in
.start_idx
]);
3842 r
->out
.info
.info2
.count
= r
->out
.returned_size
;
3843 r
->out
.info
.info2
.entries
=
3844 &(entriesFull
[r
->in
.start_idx
]);
3847 r
->out
.info
.info3
.count
= r
->out
.returned_size
;
3848 r
->out
.info
.info3
.entries
=
3849 &(entriesFullGroup
[r
->in
.start_idx
]);
3852 r
->out
.info
.info4
.count
= r
->out
.returned_size
;
3853 r
->out
.info
.info4
.entries
=
3854 &(entriesAscii
[r
->in
.start_idx
]);
3857 r
->out
.info
.info5
.count
= r
->out
.returned_size
;
3858 r
->out
.info
.info5
.entries
=
3859 &(entriesAscii
[r
->in
.start_idx
]);
3864 return (r
->out
.returned_size
< (count
- r
->in
.start_idx
)) ?
3865 STATUS_MORE_ENTRIES
: NT_STATUS_OK
;
3870 samr_GetDisplayEnumerationIndex
3872 static NTSTATUS
dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3873 struct samr_GetDisplayEnumerationIndex
*r
)
3875 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
3880 samr_TestPrivateFunctionsDomain
3882 static NTSTATUS
dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3883 struct samr_TestPrivateFunctionsDomain
*r
)
3885 return NT_STATUS_NOT_IMPLEMENTED
;
3890 samr_TestPrivateFunctionsUser
3892 static NTSTATUS
dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3893 struct samr_TestPrivateFunctionsUser
*r
)
3895 return NT_STATUS_NOT_IMPLEMENTED
;
3902 static NTSTATUS
dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3903 struct samr_GetUserPwInfo
*r
)
3905 struct dcesrv_handle
*h
;
3906 struct samr_account_state
*a_state
;
3908 ZERO_STRUCT(r
->out
.info
);
3910 DCESRV_PULL_HANDLE(h
, r
->in
.user_handle
, SAMR_HANDLE_USER
);
3914 r
->out
.info
.min_password_length
= samdb_search_uint(a_state
->sam_ctx
, mem_ctx
, 0,
3915 a_state
->domain_state
->domain_dn
, "minPwdLength",
3917 r
->out
.info
.password_properties
= samdb_search_uint(a_state
->sam_ctx
, mem_ctx
, 0,
3918 a_state
->account_dn
,
3919 "pwdProperties", NULL
);
3920 return NT_STATUS_OK
;
3925 samr_RemoveMemberFromForeignDomain
3927 static NTSTATUS
dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3928 struct samr_RemoveMemberFromForeignDomain
*r
)
3930 struct dcesrv_handle
*h
;
3931 struct samr_domain_state
*d_state
;
3932 const char *memberdn
;
3933 struct ldb_message
**res
;
3934 const char * const attrs
[3] = { "distinguishedName", "objectSid", NULL
};
3937 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
3941 memberdn
= samdb_search_string(d_state
->sam_ctx
, mem_ctx
, NULL
,
3942 "distinguishedName", "(objectSid=%s)",
3943 ldap_encode_ndr_dom_sid(mem_ctx
, r
->in
.sid
));
3945 if (memberdn
== NULL
) {
3946 return NT_STATUS_OK
;
3949 /* TODO: Does this call only remove alias members, or does it do this
3950 * for domain groups as well? */
3952 count
= samdb_search_domain(d_state
->sam_ctx
, mem_ctx
,
3953 d_state
->domain_dn
, &res
, attrs
,
3954 d_state
->domain_sid
,
3955 "(&(member=%s)(objectClass=group)"
3956 "(|(groupType=%d)(groupType=%d)))",
3958 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
,
3959 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
);
3962 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
3964 for (i
=0; i
<count
; i
++) {
3965 struct ldb_message
*mod
;
3967 mod
= ldb_msg_new(mem_ctx
);
3969 return NT_STATUS_NO_MEMORY
;
3972 mod
->dn
= samdb_result_dn(d_state
->sam_ctx
, mod
, res
[i
], "distinguishedName", NULL
);
3973 if (mod
->dn
== NULL
) {
3978 if (samdb_msg_add_delval(d_state
->sam_ctx
, mem_ctx
, mod
,
3979 "member", memberdn
) != 0)
3980 return NT_STATUS_NO_MEMORY
;
3982 if (ldb_modify(d_state
->sam_ctx
, mod
) != 0)
3983 return NT_STATUS_UNSUCCESSFUL
;
3988 return NT_STATUS_OK
;
3993 samr_QueryDomainInfo2
3995 just an alias for samr_QueryDomainInfo
3997 static NTSTATUS
dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
3998 struct samr_QueryDomainInfo2
*r
)
4000 struct samr_QueryDomainInfo r1
;
4003 ZERO_STRUCT(r1
.out
);
4004 r1
.in
.domain_handle
= r
->in
.domain_handle
;
4005 r1
.in
.level
= r
->in
.level
;
4007 status
= dcesrv_samr_QueryDomainInfo(dce_call
, mem_ctx
, &r1
);
4009 r
->out
.info
= r1
.out
.info
;
4018 just an alias for samr_QueryUserInfo
4020 static NTSTATUS
dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4021 struct samr_QueryUserInfo2
*r
)
4023 struct samr_QueryUserInfo r1
;
4026 ZERO_STRUCT(r1
.out
);
4027 r1
.in
.user_handle
= r
->in
.user_handle
;
4028 r1
.in
.level
= r
->in
.level
;
4030 status
= dcesrv_samr_QueryUserInfo(dce_call
, mem_ctx
, &r1
);
4032 r
->out
.info
= r1
.out
.info
;
4039 samr_QueryDisplayInfo2
4041 static NTSTATUS
dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4042 struct samr_QueryDisplayInfo2
*r
)
4044 struct samr_QueryDisplayInfo q
;
4047 q
.in
.domain_handle
= r
->in
.domain_handle
;
4048 q
.in
.level
= r
->in
.level
;
4049 q
.in
.start_idx
= r
->in
.start_idx
;
4050 q
.in
.max_entries
= r
->in
.max_entries
;
4051 q
.in
.buf_size
= r
->in
.buf_size
;
4054 result
= dcesrv_samr_QueryDisplayInfo(dce_call
, mem_ctx
, &q
);
4056 r
->out
.total_size
= q
.out
.total_size
;
4057 r
->out
.returned_size
= q
.out
.returned_size
;
4058 r
->out
.info
= q
.out
.info
;
4065 samr_GetDisplayEnumerationIndex2
4067 static NTSTATUS
dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4068 struct samr_GetDisplayEnumerationIndex2
*r
)
4070 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4075 samr_QueryDisplayInfo3
4077 static NTSTATUS
dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4078 struct samr_QueryDisplayInfo3
*r
)
4080 struct samr_QueryDisplayInfo q
;
4083 q
.in
.domain_handle
= r
->in
.domain_handle
;
4084 q
.in
.level
= r
->in
.level
;
4085 q
.in
.start_idx
= r
->in
.start_idx
;
4086 q
.in
.max_entries
= r
->in
.max_entries
;
4087 q
.in
.buf_size
= r
->in
.buf_size
;
4090 result
= dcesrv_samr_QueryDisplayInfo(dce_call
, mem_ctx
, &q
);
4092 r
->out
.total_size
= q
.out
.total_size
;
4093 r
->out
.returned_size
= q
.out
.returned_size
;
4094 r
->out
.info
= q
.out
.info
;
4101 samr_AddMultipleMembersToAlias
4103 static NTSTATUS
dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4104 struct samr_AddMultipleMembersToAlias
*r
)
4106 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4111 samr_RemoveMultipleMembersFromAlias
4113 static NTSTATUS
dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4114 struct samr_RemoveMultipleMembersFromAlias
*r
)
4116 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4123 this fetches the default password properties for a domain
4125 note that w2k3 completely ignores the domain name in this call, and
4126 always returns the information for the servers primary domain
4128 static NTSTATUS
dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4129 struct samr_GetDomPwInfo
*r
)
4131 struct ldb_message
**msgs
;
4133 const char * const attrs
[] = {"minPwdLength", "pwdProperties", NULL
};
4134 struct ldb_context
*sam_ctx
;
4136 ZERO_STRUCT(r
->out
.info
);
4138 sam_ctx
= samdb_connect(mem_ctx
, dce_call
->event_ctx
, dce_call
->conn
->dce_ctx
->lp_ctx
, dce_call
->conn
->auth_state
.session_info
);
4139 if (sam_ctx
== NULL
) {
4140 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
4143 /* The domain name in this call is ignored */
4144 ret
= gendb_search_dn(sam_ctx
,
4145 mem_ctx
, NULL
, &msgs
, attrs
);
4147 return NT_STATUS_NO_SUCH_DOMAIN
;
4151 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
4154 r
->out
.info
.min_password_length
= samdb_result_uint(msgs
[0], "minPwdLength", 0);
4155 r
->out
.info
.password_properties
= samdb_result_uint(msgs
[0], "pwdProperties", 1);
4159 talloc_free(sam_ctx
);
4160 return NT_STATUS_OK
;
4167 static NTSTATUS
dcesrv_samr_Connect2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4168 struct samr_Connect2
*r
)
4170 struct samr_Connect c
;
4172 c
.in
.system_name
= NULL
;
4173 c
.in
.access_mask
= r
->in
.access_mask
;
4174 c
.out
.connect_handle
= r
->out
.connect_handle
;
4176 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4183 just an alias for samr_SetUserInfo
4185 static NTSTATUS
dcesrv_samr_SetUserInfo2(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4186 struct samr_SetUserInfo2
*r
)
4188 struct samr_SetUserInfo r2
;
4190 r2
.in
.user_handle
= r
->in
.user_handle
;
4191 r2
.in
.level
= r
->in
.level
;
4192 r2
.in
.info
= r
->in
.info
;
4194 return dcesrv_samr_SetUserInfo(dce_call
, mem_ctx
, &r2
);
4199 samr_SetBootKeyInformation
4201 static NTSTATUS
dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4202 struct samr_SetBootKeyInformation
*r
)
4204 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4209 samr_GetBootKeyInformation
4211 static NTSTATUS
dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4212 struct samr_GetBootKeyInformation
*r
)
4214 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4221 static NTSTATUS
dcesrv_samr_Connect3(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4222 struct samr_Connect3
*r
)
4224 struct samr_Connect c
;
4226 c
.in
.system_name
= NULL
;
4227 c
.in
.access_mask
= r
->in
.access_mask
;
4228 c
.out
.connect_handle
= r
->out
.connect_handle
;
4230 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4237 static NTSTATUS
dcesrv_samr_Connect4(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4238 struct samr_Connect4
*r
)
4240 struct samr_Connect c
;
4242 c
.in
.system_name
= NULL
;
4243 c
.in
.access_mask
= r
->in
.access_mask
;
4244 c
.out
.connect_handle
= r
->out
.connect_handle
;
4246 return dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4253 static NTSTATUS
dcesrv_samr_Connect5(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4254 struct samr_Connect5
*r
)
4256 struct samr_Connect c
;
4259 c
.in
.system_name
= NULL
;
4260 c
.in
.access_mask
= r
->in
.access_mask
;
4261 c
.out
.connect_handle
= r
->out
.connect_handle
;
4263 status
= dcesrv_samr_Connect(dce_call
, mem_ctx
, &c
);
4265 r
->out
.info
->info1
.unknown1
= 3;
4266 r
->out
.info
->info1
.unknown2
= 0;
4267 r
->out
.level
= r
->in
.level
;
4276 static NTSTATUS
dcesrv_samr_RidToSid(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4277 struct samr_RidToSid
*r
)
4279 struct samr_domain_state
*d_state
;
4280 struct dcesrv_handle
*h
;
4282 DCESRV_PULL_HANDLE(h
, r
->in
.domain_handle
, SAMR_HANDLE_DOMAIN
);
4286 /* form the users SID */
4287 r
->out
.sid
= dom_sid_add_rid(mem_ctx
, d_state
->domain_sid
, r
->in
.rid
);
4289 return NT_STATUS_NO_MEMORY
;
4292 return NT_STATUS_OK
;
4297 samr_SetDsrmPassword
4299 static NTSTATUS
dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4300 struct samr_SetDsrmPassword
*r
)
4302 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4307 samr_ValidatePassword
4309 static NTSTATUS
dcesrv_samr_ValidatePassword(struct dcesrv_call_state
*dce_call
, TALLOC_CTX
*mem_ctx
,
4310 struct samr_ValidatePassword
*r
)
4312 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR
);
4316 /* include the generated boilerplate */
4317 #include "librpc/gen_ndr/ndr_samr_s.c"