s4:samr - Fix up the SAMR server to support the primary group of a user in the right way
[Samba/aatanasov.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob6dda06a6b88fd8b0d1fc434b976fa69342d7e411
1 /*
2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "libcli/security/security.h"
37 #include "rpc_server/samr/proto.h"
38 #include "../lib/util/util_ldb.h"
39 #include "param/param.h"
41 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
43 #define QUERY_STRING(msg, field, attr) \
44 info->field.string = samdb_result_string(msg, attr, "");
45 #define QUERY_UINT(msg, field, attr) \
46 info->field = samdb_result_uint(msg, attr, 0);
47 #define QUERY_RID(msg, field, attr) \
48 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
49 #define QUERY_UINT64(msg, field, attr) \
50 info->field = samdb_result_uint64(msg, attr, 0);
51 #define QUERY_APASSC(msg, field, attr) \
52 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
53 a_state->domain_state->domain_dn, msg, attr);
54 #define QUERY_FPASSC(msg, field, attr) \
55 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg);
57 #define QUERY_LHOURS(msg, field, attr) \
58 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
59 #define QUERY_AFLAGS(msg, field, attr) \
60 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
61 #define QUERY_PARAMETERS(msg, field, attr) \
62 info->field = samdb_result_parameters(mem_ctx, msg, attr);
65 /* these are used to make the Set[User|Group]Info code easier to follow */
67 #define SET_STRING(msg, field, attr) do { \
68 struct ldb_message_element *set_el; \
69 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
70 if (r->in.info->field.string[0] == '\0') { \
71 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
72 return NT_STATUS_NO_MEMORY; \
73 } \
74 } \
75 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
76 return NT_STATUS_NO_MEMORY; \
77 } \
78 set_el = ldb_msg_find_element(msg, attr); \
79 set_el->flags = LDB_FLAG_MOD_REPLACE; \
80 } while (0)
82 #define SET_UINT(msg, field, attr) do { \
83 struct ldb_message_element *set_el; \
84 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
85 return NT_STATUS_NO_MEMORY; \
86 } \
87 set_el = ldb_msg_find_element(msg, attr); \
88 set_el->flags = LDB_FLAG_MOD_REPLACE; \
89 } while (0)
91 #define SET_INT64(msg, field, attr) do { \
92 struct ldb_message_element *set_el; \
93 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
94 return NT_STATUS_NO_MEMORY; \
95 } \
96 set_el = ldb_msg_find_element(msg, attr); \
97 set_el->flags = LDB_FLAG_MOD_REPLACE; \
98 } while (0)
100 #define SET_UINT64(msg, field, attr) do { \
101 struct ldb_message_element *set_el; \
102 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
103 return NT_STATUS_NO_MEMORY; \
105 set_el = ldb_msg_find_element(msg, attr); \
106 set_el->flags = LDB_FLAG_MOD_REPLACE; \
107 } while (0)
109 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
110 do { \
111 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
112 return NT_STATUS_INVALID_PARAMETER; \
114 } while (0) \
116 /* Set account flags, discarding flags that cannot be set with SAMR */
117 #define SET_AFLAGS(msg, field, attr) do { \
118 struct ldb_message_element *set_el; \
119 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
120 return NT_STATUS_INVALID_PARAMETER; \
122 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
127 return NT_STATUS_NO_MEMORY; \
129 set_el = ldb_msg_find_element(msg, attr); \
130 set_el->flags = LDB_FLAG_MOD_REPLACE; \
131 } while (0)
133 #define SET_LHOURS(msg, field, attr) do { \
134 struct ldb_message_element *set_el; \
135 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
136 return NT_STATUS_NO_MEMORY; \
138 set_el = ldb_msg_find_element(msg, attr); \
139 set_el->flags = LDB_FLAG_MOD_REPLACE; \
140 } while (0)
142 #define SET_PARAMETERS(msg, field, attr) do { \
143 struct ldb_message_element *set_el; \
144 if (r->in.info->field.length != 0) { \
145 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
146 return NT_STATUS_NO_MEMORY; \
148 set_el = ldb_msg_find_element(msg, attr); \
149 set_el->flags = LDB_FLAG_MOD_REPLACE; \
151 } while (0)
156 samr_Connect
158 create a connection to the SAM database
160 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
161 struct samr_Connect *r)
163 struct samr_connect_state *c_state;
164 struct dcesrv_handle *handle;
166 ZERO_STRUCTP(r->out.connect_handle);
168 c_state = talloc(dce_call->conn, struct samr_connect_state);
169 if (!c_state) {
170 return NT_STATUS_NO_MEMORY;
173 /* make sure the sam database is accessible */
174 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
175 if (c_state->sam_ctx == NULL) {
176 talloc_free(c_state);
177 return NT_STATUS_INVALID_SYSTEM_SERVICE;
181 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
182 if (!handle) {
183 talloc_free(c_state);
184 return NT_STATUS_NO_MEMORY;
187 handle->data = talloc_steal(handle, c_state);
189 c_state->access_mask = r->in.access_mask;
190 *r->out.connect_handle = handle->wire_handle;
192 return NT_STATUS_OK;
197 samr_Close
199 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
200 struct samr_Close *r)
202 struct dcesrv_handle *h;
204 *r->out.handle = *r->in.handle;
206 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
208 talloc_free(h);
210 ZERO_STRUCTP(r->out.handle);
212 return NT_STATUS_OK;
217 samr_SetSecurity
219 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
220 struct samr_SetSecurity *r)
222 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
227 samr_QuerySecurity
229 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
230 struct samr_QuerySecurity *r)
232 struct dcesrv_handle *h;
233 struct sec_desc_buf *sd;
235 *r->out.sdbuf = NULL;
237 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
239 sd = talloc(mem_ctx, struct sec_desc_buf);
240 if (sd == NULL) {
241 return NT_STATUS_NO_MEMORY;
244 sd->sd = samdb_default_security_descriptor(mem_ctx);
246 *r->out.sdbuf = sd;
248 return NT_STATUS_OK;
253 samr_Shutdown
255 we refuse this operation completely. If a admin wants to shutdown samr
256 in Samba then they should use the samba admin tools to disable the samr pipe
258 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
259 struct samr_Shutdown *r)
261 return NT_STATUS_ACCESS_DENIED;
266 samr_LookupDomain
268 this maps from a domain name to a SID
270 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
271 struct samr_LookupDomain *r)
273 struct samr_connect_state *c_state;
274 struct dcesrv_handle *h;
275 struct dom_sid *sid;
276 const char * const dom_attrs[] = { "objectSid", NULL};
277 struct ldb_message **dom_msgs;
278 int ret;
280 *r->out.sid = NULL;
282 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
284 c_state = h->data;
286 if (r->in.domain_name->string == NULL) {
287 return NT_STATUS_INVALID_PARAMETER;
290 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
291 ret = gendb_search(c_state->sam_ctx,
292 mem_ctx, NULL, &dom_msgs, dom_attrs,
293 "(objectClass=builtinDomain)");
294 } else if (strcasecmp_m(r->in.domain_name->string, lp_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
295 ret = gendb_search_dn(c_state->sam_ctx,
296 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
297 &dom_msgs, dom_attrs);
298 } else {
299 return NT_STATUS_NO_SUCH_DOMAIN;
301 if (ret != 1) {
302 return NT_STATUS_NO_SUCH_DOMAIN;
305 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
306 "objectSid");
308 if (sid == NULL) {
309 return NT_STATUS_NO_SUCH_DOMAIN;
312 *r->out.sid = sid;
314 return NT_STATUS_OK;
319 samr_EnumDomains
321 list the domains in the SAM
323 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
324 struct samr_EnumDomains *r)
326 struct samr_connect_state *c_state;
327 struct dcesrv_handle *h;
328 struct samr_SamArray *array;
329 int i, start_i;
331 *r->out.resume_handle = 0;
332 *r->out.sam = NULL;
333 *r->out.num_entries = 0;
335 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
337 c_state = h->data;
339 *r->out.resume_handle = 2;
341 start_i = *r->in.resume_handle;
343 if (start_i >= 2) {
344 /* search past end of list is not an error for this call */
345 return NT_STATUS_OK;
348 array = talloc(mem_ctx, struct samr_SamArray);
349 if (array == NULL) {
350 return NT_STATUS_NO_MEMORY;
353 array->count = 0;
354 array->entries = NULL;
356 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
357 if (array->entries == NULL) {
358 return NT_STATUS_NO_MEMORY;
361 for (i=0;i<2-start_i;i++) {
362 array->entries[i].idx = start_i + i;
363 if (i == 0) {
364 array->entries[i].name.string = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
365 } else {
366 array->entries[i].name.string = "BUILTIN";
370 *r->out.sam = array;
371 *r->out.num_entries = i;
372 array->count = *r->out.num_entries;
374 return NT_STATUS_OK;
379 samr_OpenDomain
381 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
382 struct samr_OpenDomain *r)
384 struct dcesrv_handle *h_conn, *h_domain;
385 struct samr_connect_state *c_state;
386 struct samr_domain_state *d_state;
387 const char * const dom_attrs[] = { "cn", NULL};
388 struct ldb_message **dom_msgs;
389 int ret;
391 ZERO_STRUCTP(r->out.domain_handle);
393 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
395 c_state = h_conn->data;
397 if (r->in.sid == NULL) {
398 return NT_STATUS_INVALID_PARAMETER;
401 d_state = talloc(c_state, struct samr_domain_state);
402 if (!d_state) {
403 return NT_STATUS_NO_MEMORY;
406 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
408 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
409 d_state->builtin = true;
410 d_state->domain_name = "BUILTIN";
411 } else {
412 d_state->builtin = false;
413 d_state->domain_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
416 ret = gendb_search(c_state->sam_ctx,
417 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
418 "(objectSid=%s)",
419 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
421 if (ret == 0) {
422 talloc_free(d_state);
423 return NT_STATUS_NO_SUCH_DOMAIN;
424 } else if (ret > 1) {
425 talloc_free(d_state);
426 return NT_STATUS_INTERNAL_DB_CORRUPTION;
427 } else if (ret == -1) {
428 talloc_free(d_state);
429 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
430 return NT_STATUS_INTERNAL_DB_CORRUPTION;
433 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
434 d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
435 d_state->connect_state = talloc_reference(d_state, c_state);
436 d_state->sam_ctx = c_state->sam_ctx;
437 d_state->access_mask = r->in.access_mask;
439 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
441 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
442 if (!h_domain) {
443 talloc_free(d_state);
444 return NT_STATUS_NO_MEMORY;
447 h_domain->data = talloc_steal(h_domain, d_state);
449 *r->out.domain_handle = h_domain->wire_handle;
451 return NT_STATUS_OK;
455 return DomInfo1
457 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
458 TALLOC_CTX *mem_ctx,
459 struct ldb_message **dom_msgs,
460 struct samr_DomInfo1 *info)
462 info->min_password_length =
463 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
464 info->password_history_length =
465 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
466 info->password_properties =
467 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
468 info->max_password_age =
469 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
470 info->min_password_age =
471 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
473 return NT_STATUS_OK;
477 return DomInfo2
479 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
480 TALLOC_CTX *mem_ctx,
481 struct ldb_message **dom_msgs,
482 struct samr_DomGeneralInformation *info)
484 /* This pulls the NetBIOS name from the
485 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
486 string */
487 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
489 if (!info->primary.string) {
490 info->primary.string = lp_netbios_name(state->lp_ctx);
493 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
494 0x8000000000000000LL);
496 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
497 info->domain_name.string = state->domain_name;
499 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
501 switch (state->role) {
502 case ROLE_DOMAIN_CONTROLLER:
503 /* This pulls the NetBIOS name from the
504 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
505 string */
506 if (samdb_is_pdc(state->sam_ctx)) {
507 info->role = SAMR_ROLE_DOMAIN_PDC;
508 } else {
509 info->role = SAMR_ROLE_DOMAIN_BDC;
511 break;
512 case ROLE_DOMAIN_MEMBER:
513 info->role = SAMR_ROLE_DOMAIN_MEMBER;
514 break;
515 case ROLE_STANDALONE:
516 info->role = SAMR_ROLE_STANDALONE;
517 break;
520 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
521 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
522 "(objectClass=user)");
523 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
524 "(&(objectClass=group)(sAMAccountType=%u))",
525 ATYPE_GLOBAL_GROUP);
526 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
527 "(&(objectClass=group)(sAMAccountType=%u))",
528 ATYPE_LOCAL_GROUP);
530 return NT_STATUS_OK;
534 return DomInfo3
536 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
537 TALLOC_CTX *mem_ctx,
538 struct ldb_message **dom_msgs,
539 struct samr_DomInfo3 *info)
541 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
542 0x8000000000000000LL);
544 return NT_STATUS_OK;
548 return DomInfo4
550 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
551 TALLOC_CTX *mem_ctx,
552 struct ldb_message **dom_msgs,
553 struct samr_DomOEMInformation *info)
555 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
557 return NT_STATUS_OK;
561 return DomInfo5
563 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
564 TALLOC_CTX *mem_ctx,
565 struct ldb_message **dom_msgs,
566 struct samr_DomInfo5 *info)
568 info->domain_name.string = state->domain_name;
570 return NT_STATUS_OK;
574 return DomInfo6
576 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
577 TALLOC_CTX *mem_ctx,
578 struct ldb_message **dom_msgs,
579 struct samr_DomInfo6 *info)
581 /* This pulls the NetBIOS name from the
582 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
583 string */
584 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
585 dom_msgs[0], "fSMORoleOwner");
587 if (!info->primary.string) {
588 info->primary.string = lp_netbios_name(state->lp_ctx);
591 return NT_STATUS_OK;
595 return DomInfo7
597 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
598 TALLOC_CTX *mem_ctx,
599 struct ldb_message **dom_msgs,
600 struct samr_DomInfo7 *info)
603 switch (state->role) {
604 case ROLE_DOMAIN_CONTROLLER:
605 /* This pulls the NetBIOS name from the
606 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
607 string */
608 if (samdb_is_pdc(state->sam_ctx)) {
609 info->role = SAMR_ROLE_DOMAIN_PDC;
610 } else {
611 info->role = SAMR_ROLE_DOMAIN_BDC;
613 break;
614 case ROLE_DOMAIN_MEMBER:
615 info->role = SAMR_ROLE_DOMAIN_MEMBER;
616 break;
617 case ROLE_STANDALONE:
618 info->role = SAMR_ROLE_STANDALONE;
619 break;
622 return NT_STATUS_OK;
626 return DomInfo8
628 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
629 TALLOC_CTX *mem_ctx,
630 struct ldb_message **dom_msgs,
631 struct samr_DomInfo8 *info)
633 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
634 time(NULL));
636 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
637 0x0LL);
639 return NT_STATUS_OK;
643 return DomInfo9
645 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
646 TALLOC_CTX *mem_ctx,
647 struct ldb_message **dom_msgs,
648 struct samr_DomInfo9 *info)
650 info->domain_server_state = DOMAIN_SERVER_ENABLED;
652 return NT_STATUS_OK;
656 return DomInfo11
658 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
659 TALLOC_CTX *mem_ctx,
660 struct ldb_message **dom_msgs,
661 struct samr_DomGeneralInformation2 *info)
663 NTSTATUS status;
664 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
665 if (!NT_STATUS_IS_OK(status)) {
666 return status;
669 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
670 -18000000000LL);
671 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
672 -18000000000LL);
673 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
675 return NT_STATUS_OK;
679 return DomInfo12
681 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
682 TALLOC_CTX *mem_ctx,
683 struct ldb_message **dom_msgs,
684 struct samr_DomInfo12 *info)
686 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
687 -18000000000LL);
688 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
689 -18000000000LL);
690 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
692 return NT_STATUS_OK;
696 return DomInfo13
698 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
699 TALLOC_CTX *mem_ctx,
700 struct ldb_message **dom_msgs,
701 struct samr_DomInfo13 *info)
703 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
704 time(NULL));
706 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
707 0x0LL);
709 info->modified_count_at_last_promotion = 0;
711 return NT_STATUS_OK;
715 samr_QueryDomainInfo
717 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
718 struct samr_QueryDomainInfo *r)
720 struct dcesrv_handle *h;
721 struct samr_domain_state *d_state;
722 union samr_DomainInfo *info;
724 struct ldb_message **dom_msgs;
725 const char * const *attrs = NULL;
727 *r->out.info = NULL;
729 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
731 d_state = h->data;
733 info = talloc(mem_ctx, union samr_DomainInfo);
734 if (!info) {
735 return NT_STATUS_NO_MEMORY;
738 switch (r->in.level) {
739 case 1:
741 static const char * const attrs2[] = { "minPwdLength",
742 "pwdHistoryLength",
743 "pwdProperties",
744 "maxPwdAge",
745 "minPwdAge",
746 NULL };
747 attrs = attrs2;
748 break;
750 case 2:
752 static const char * const attrs2[] = {"forceLogoff",
753 "oEMInformation",
754 "modifiedCount",
755 "fSMORoleOwner",
756 NULL};
757 attrs = attrs2;
758 break;
760 case 3:
762 static const char * const attrs2[] = {"forceLogoff",
763 NULL};
764 attrs = attrs2;
765 break;
767 case 4:
769 static const char * const attrs2[] = {"oEMInformation",
770 NULL};
771 attrs = attrs2;
772 break;
774 case 5:
776 attrs = NULL;
777 break;
779 case 6:
781 static const char * const attrs2[] = {"fSMORoleOwner",
782 NULL};
783 attrs = attrs2;
784 break;
786 case 7:
788 attrs = NULL;
789 break;
791 case 8:
793 static const char * const attrs2[] = { "modifiedCount",
794 "creationTime",
795 NULL };
796 attrs = attrs2;
797 break;
799 case 9:
800 attrs = NULL;
801 break;
802 case 11:
804 static const char * const attrs2[] = { "oEMInformation",
805 "forceLogoff",
806 "modifiedCount",
807 "lockoutDuration",
808 "lockOutObservationWindow",
809 "lockoutThreshold",
810 NULL};
811 attrs = attrs2;
812 break;
814 case 12:
816 static const char * const attrs2[] = { "lockoutDuration",
817 "lockOutObservationWindow",
818 "lockoutThreshold",
819 NULL};
820 attrs = attrs2;
821 break;
823 case 13:
825 static const char * const attrs2[] = { "modifiedCount",
826 "creationTime",
827 NULL };
828 attrs = attrs2;
829 break;
833 /* some levels don't need a search */
834 if (attrs) {
835 int ret;
836 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
837 d_state->domain_dn, &dom_msgs, attrs);
838 if (ret != 1) {
839 return NT_STATUS_INTERNAL_DB_CORRUPTION;
843 *r->out.info = info;
845 ZERO_STRUCTP(info);
847 switch (r->in.level) {
848 case 1:
849 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
850 &info->info1);
851 case 2:
852 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
853 &info->general);
854 case 3:
855 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
856 &info->info3);
857 case 4:
858 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
859 &info->oem);
860 case 5:
861 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
862 &info->info5);
863 case 6:
864 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
865 &info->info6);
866 case 7:
867 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
868 &info->info7);
869 case 8:
870 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
871 &info->info8);
872 case 9:
873 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
874 &info->info9);
875 case 11:
876 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
877 &info->general2);
878 case 12:
879 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
880 &info->info12);
881 case 13:
882 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
883 &info->info13);
886 return NT_STATUS_INVALID_INFO_CLASS;
891 samr_SetDomainInfo
893 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
894 struct samr_SetDomainInfo *r)
896 struct dcesrv_handle *h;
897 struct samr_domain_state *d_state;
898 struct ldb_message *msg;
899 int ret;
900 struct ldb_context *sam_ctx;
902 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
904 d_state = h->data;
905 sam_ctx = d_state->sam_ctx;
907 msg = ldb_msg_new(mem_ctx);
908 if (msg == NULL) {
909 return NT_STATUS_NO_MEMORY;
912 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
913 if (!msg->dn) {
914 return NT_STATUS_NO_MEMORY;
917 switch (r->in.level) {
918 case 1:
919 SET_UINT (msg, info1.min_password_length, "minPwdLength");
920 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
921 SET_UINT (msg, info1.password_properties, "pwdProperties");
922 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
923 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
924 break;
925 case 3:
926 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
927 break;
928 case 4:
929 SET_STRING(msg, oem.oem_information, "oEMInformation");
930 break;
932 case 6:
933 case 7:
934 case 9:
935 /* No op, we don't know where to set these */
936 return NT_STATUS_OK;
938 case 12:
940 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
941 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
942 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
943 break;
945 default:
946 /* many info classes are not valid for SetDomainInfo */
947 return NT_STATUS_INVALID_INFO_CLASS;
950 /* modify the samdb record */
951 ret = ldb_modify(sam_ctx, msg);
952 if (ret != 0) {
953 DEBUG(1,("Failed to modify record %s: %s\n",
954 ldb_dn_get_linearized(d_state->domain_dn),
955 ldb_errstring(sam_ctx)));
957 /* we really need samdb.c to return NTSTATUS */
958 return NT_STATUS_UNSUCCESSFUL;
961 return NT_STATUS_OK;
965 samr_CreateDomainGroup
967 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
968 struct samr_CreateDomainGroup *r)
970 struct samr_domain_state *d_state;
971 struct samr_account_state *a_state;
972 struct dcesrv_handle *h;
973 const char *name;
974 struct ldb_message *msg;
975 struct dom_sid *sid;
976 const char *groupname;
977 struct dcesrv_handle *g_handle;
978 int ret;
980 ZERO_STRUCTP(r->out.group_handle);
981 *r->out.rid = 0;
983 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
985 d_state = h->data;
987 if (d_state->builtin) {
988 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
989 return NT_STATUS_ACCESS_DENIED;
992 groupname = r->in.name->string;
994 if (groupname == NULL) {
995 return NT_STATUS_INVALID_PARAMETER;
998 /* check if the group already exists */
999 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1000 "sAMAccountName",
1001 "(&(sAMAccountName=%s)(objectclass=group))",
1002 ldb_binary_encode_string(mem_ctx, groupname));
1003 if (name != NULL) {
1004 return NT_STATUS_GROUP_EXISTS;
1007 msg = ldb_msg_new(mem_ctx);
1008 if (msg == NULL) {
1009 return NT_STATUS_NO_MEMORY;
1012 /* add core elements to the ldb_message for the user */
1013 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1014 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1015 if (!msg->dn) {
1016 return NT_STATUS_NO_MEMORY;
1018 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1019 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1021 /* create the group */
1022 ret = ldb_add(d_state->sam_ctx, msg);
1023 switch (ret) {
1024 case LDB_SUCCESS:
1025 break;
1026 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1027 DEBUG(0,("Failed to create group record %s: %s\n",
1028 ldb_dn_get_linearized(msg->dn),
1029 ldb_errstring(d_state->sam_ctx)));
1030 return NT_STATUS_GROUP_EXISTS;
1031 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1032 DEBUG(0,("Failed to create group record %s: %s\n",
1033 ldb_dn_get_linearized(msg->dn),
1034 ldb_errstring(d_state->sam_ctx)));
1035 return NT_STATUS_ACCESS_DENIED;
1036 default:
1037 DEBUG(0,("Failed to create group record %s: %s\n",
1038 ldb_dn_get_linearized(msg->dn),
1039 ldb_errstring(d_state->sam_ctx)));
1040 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1043 a_state = talloc(d_state, struct samr_account_state);
1044 if (!a_state) {
1045 return NT_STATUS_NO_MEMORY;
1047 a_state->sam_ctx = d_state->sam_ctx;
1048 a_state->access_mask = r->in.access_mask;
1049 a_state->domain_state = talloc_reference(a_state, d_state);
1050 a_state->account_dn = talloc_steal(a_state, msg->dn);
1052 /* retrieve the sid for the group just created */
1053 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1054 msg->dn, "objectSid", NULL);
1055 if (sid == NULL) {
1056 return NT_STATUS_UNSUCCESSFUL;
1059 a_state->account_name = talloc_strdup(a_state, groupname);
1060 if (!a_state->account_name) {
1061 return NT_STATUS_NO_MEMORY;
1064 /* create the policy handle */
1065 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1066 if (!g_handle) {
1067 return NT_STATUS_NO_MEMORY;
1070 g_handle->data = talloc_steal(g_handle, a_state);
1072 *r->out.group_handle = g_handle->wire_handle;
1073 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1075 return NT_STATUS_OK;
1080 comparison function for sorting SamEntry array
1082 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1084 return e1->idx - e2->idx;
1088 samr_EnumDomainGroups
1090 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1091 struct samr_EnumDomainGroups *r)
1093 struct dcesrv_handle *h;
1094 struct samr_domain_state *d_state;
1095 struct ldb_message **res;
1096 int ldb_cnt, count, i, first;
1097 struct samr_SamEntry *entries;
1098 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1099 struct samr_SamArray *sam;
1101 *r->out.resume_handle = 0;
1102 *r->out.sam = NULL;
1103 *r->out.num_entries = 0;
1105 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1107 d_state = h->data;
1109 /* search for all domain groups in this domain. This could possibly be
1110 cached and resumed based on resume_key */
1111 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1112 d_state->domain_dn, &res, attrs,
1113 d_state->domain_sid,
1114 "(&(grouptype=%d)(objectclass=group))",
1115 GTYPE_SECURITY_GLOBAL_GROUP);
1116 if (ldb_cnt == -1) {
1117 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1120 /* convert to SamEntry format */
1121 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1122 if (!entries) {
1123 return NT_STATUS_NO_MEMORY;
1126 count = 0;
1128 for (i=0;i<ldb_cnt;i++) {
1129 struct dom_sid *group_sid;
1131 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1132 "objectSid");
1133 if (group_sid == NULL)
1134 continue;
1136 entries[count].idx =
1137 group_sid->sub_auths[group_sid->num_auths-1];
1138 entries[count].name.string =
1139 samdb_result_string(res[i], "sAMAccountName", "");
1140 count += 1;
1143 /* sort the results by rid */
1144 qsort(entries, count, sizeof(struct samr_SamEntry),
1145 (comparison_fn_t)compare_SamEntry);
1147 /* find the first entry to return */
1148 for (first=0;
1149 first<count && entries[first].idx <= *r->in.resume_handle;
1150 first++) ;
1152 /* return the rest, limit by max_size. Note that we
1153 use the w2k3 element size value of 54 */
1154 *r->out.num_entries = count - first;
1155 *r->out.num_entries = MIN(*r->out.num_entries,
1156 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1158 sam = talloc(mem_ctx, struct samr_SamArray);
1159 if (!sam) {
1160 return NT_STATUS_NO_MEMORY;
1163 sam->entries = entries+first;
1164 sam->count = *r->out.num_entries;
1166 *r->out.sam = sam;
1168 if (*r->out.num_entries < count - first) {
1169 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1170 return STATUS_MORE_ENTRIES;
1173 return NT_STATUS_OK;
1178 samr_CreateUser2
1180 This call uses transactions to ensure we don't get a new conflicting
1181 user while we are processing this, and to ensure the user either
1182 completly exists, or does not.
1184 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1185 struct samr_CreateUser2 *r)
1187 struct samr_domain_state *d_state;
1188 struct samr_account_state *a_state;
1189 struct dcesrv_handle *h;
1190 const char *name;
1191 struct ldb_message *msg;
1192 struct dom_sid *sid;
1193 const char *account_name;
1194 struct dcesrv_handle *u_handle;
1195 int ret;
1196 const char *container, *obj_class=NULL;
1197 char *cn_name;
1198 int cn_name_len;
1200 const char *attrs[] = {
1201 "objectSid",
1202 "userAccountControl",
1203 NULL
1206 uint32_t user_account_control;
1208 struct ldb_message **msgs;
1210 ZERO_STRUCTP(r->out.user_handle);
1211 *r->out.access_granted = 0;
1212 *r->out.rid = 0;
1214 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1216 d_state = h->data;
1218 if (d_state->builtin) {
1219 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1220 return NT_STATUS_ACCESS_DENIED;
1221 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1222 /* Domain trust accounts must be created by the LSA calls */
1223 return NT_STATUS_ACCESS_DENIED;
1225 account_name = r->in.account_name->string;
1227 if (account_name == NULL) {
1228 return NT_STATUS_INVALID_PARAMETER;
1232 * Start a transaction, so we can query and do a subsequent atomic
1233 * modify
1236 ret = ldb_transaction_start(d_state->sam_ctx);
1237 if (ret != 0) {
1238 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1239 ldb_errstring(d_state->sam_ctx)));
1240 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1243 /* check if the user already exists */
1244 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1245 "sAMAccountName",
1246 "(&(sAMAccountName=%s)(objectclass=user))",
1247 ldb_binary_encode_string(mem_ctx, account_name));
1248 if (name != NULL) {
1249 ldb_transaction_cancel(d_state->sam_ctx);
1250 return NT_STATUS_USER_EXISTS;
1253 msg = ldb_msg_new(mem_ctx);
1254 if (msg == NULL) {
1255 ldb_transaction_cancel(d_state->sam_ctx);
1256 return NT_STATUS_NO_MEMORY;
1259 cn_name = talloc_strdup(mem_ctx, account_name);
1260 if (!cn_name) {
1261 ldb_transaction_cancel(d_state->sam_ctx);
1262 return NT_STATUS_NO_MEMORY;
1265 cn_name_len = strlen(cn_name);
1267 /* This must be one of these values *only* */
1268 if (r->in.acct_flags == ACB_NORMAL) {
1269 container = "CN=Users";
1270 obj_class = "user";
1272 } else if (r->in.acct_flags == ACB_WSTRUST) {
1273 if (cn_name[cn_name_len - 1] != '$') {
1274 ldb_transaction_cancel(d_state->sam_ctx);
1275 return NT_STATUS_FOOBAR;
1277 cn_name[cn_name_len - 1] = '\0';
1278 container = "CN=Computers";
1279 obj_class = "computer";
1280 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1281 "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1283 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1284 if (cn_name[cn_name_len - 1] != '$') {
1285 ldb_transaction_cancel(d_state->sam_ctx);
1286 return NT_STATUS_FOOBAR;
1288 cn_name[cn_name_len - 1] = '\0';
1289 container = "OU=Domain Controllers";
1290 obj_class = "computer";
1291 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1292 "primaryGroupID", DOMAIN_RID_DCS);
1293 } else {
1294 ldb_transaction_cancel(d_state->sam_ctx);
1295 return NT_STATUS_INVALID_PARAMETER;
1298 /* add core elements to the ldb_message for the user */
1299 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1300 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1301 ldb_transaction_cancel(d_state->sam_ctx);
1302 return NT_STATUS_FOOBAR;
1305 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName",
1306 account_name);
1307 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass",
1308 obj_class);
1310 /* create the user */
1311 ret = ldb_add(d_state->sam_ctx, msg);
1312 switch (ret) {
1313 case LDB_SUCCESS:
1314 break;
1315 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1316 ldb_transaction_cancel(d_state->sam_ctx);
1317 DEBUG(0,("Failed to create user record %s: %s\n",
1318 ldb_dn_get_linearized(msg->dn),
1319 ldb_errstring(d_state->sam_ctx)));
1320 return NT_STATUS_USER_EXISTS;
1321 case LDB_ERR_UNWILLING_TO_PERFORM:
1322 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1323 ldb_transaction_cancel(d_state->sam_ctx);
1324 DEBUG(0,("Failed to create user record %s: %s\n",
1325 ldb_dn_get_linearized(msg->dn),
1326 ldb_errstring(d_state->sam_ctx)));
1327 return NT_STATUS_ACCESS_DENIED;
1328 default:
1329 ldb_transaction_cancel(d_state->sam_ctx);
1330 DEBUG(0,("Failed to create user record %s: %s\n",
1331 ldb_dn_get_linearized(msg->dn),
1332 ldb_errstring(d_state->sam_ctx)));
1333 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1336 a_state = talloc(d_state, struct samr_account_state);
1337 if (!a_state) {
1338 ldb_transaction_cancel(d_state->sam_ctx);
1339 return NT_STATUS_NO_MEMORY;
1341 a_state->sam_ctx = d_state->sam_ctx;
1342 a_state->access_mask = r->in.access_mask;
1343 a_state->domain_state = talloc_reference(a_state, d_state);
1344 a_state->account_dn = talloc_steal(a_state, msg->dn);
1346 /* retrieve the sid and account control bits for the user just created */
1347 ret = gendb_search_dn(d_state->sam_ctx, a_state,
1348 msg->dn, &msgs, attrs);
1350 if (ret != 1) {
1351 ldb_transaction_cancel(d_state->sam_ctx);
1352 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1353 ldb_dn_get_linearized(msg->dn)));
1354 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1356 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1357 if (sid == NULL) {
1358 ldb_transaction_cancel(d_state->sam_ctx);
1359 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1360 ldb_dn_get_linearized(msg->dn)));
1361 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1364 /* Change the account control to be the correct account type.
1365 * The default is for a workstation account */
1366 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1367 user_account_control = (user_account_control &
1368 ~(UF_NORMAL_ACCOUNT |
1369 UF_INTERDOMAIN_TRUST_ACCOUNT |
1370 UF_WORKSTATION_TRUST_ACCOUNT |
1371 UF_SERVER_TRUST_ACCOUNT));
1372 user_account_control |= ds_acb2uf(r->in.acct_flags);
1374 talloc_free(msg);
1375 msg = ldb_msg_new(mem_ctx);
1376 if (msg == NULL) {
1377 ldb_transaction_cancel(d_state->sam_ctx);
1378 return NT_STATUS_NO_MEMORY;
1381 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1383 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1384 "userAccountControl",
1385 user_account_control) != 0) {
1386 ldb_transaction_cancel(d_state->sam_ctx);
1387 return NT_STATUS_NO_MEMORY;
1390 /* modify the samdb record */
1391 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1392 if (ret != 0) {
1393 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1394 ldb_dn_get_linearized(msg->dn),
1395 ldb_errstring(d_state->sam_ctx)));
1396 ldb_transaction_cancel(d_state->sam_ctx);
1398 /* we really need samdb.c to return NTSTATUS */
1399 return NT_STATUS_UNSUCCESSFUL;
1402 ret = ldb_transaction_commit(d_state->sam_ctx);
1403 if (ret != 0) {
1404 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1405 ldb_dn_get_linearized(msg->dn),
1406 ldb_errstring(d_state->sam_ctx)));
1407 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1410 a_state->account_name = talloc_steal(a_state, account_name);
1411 if (!a_state->account_name) {
1412 return NT_STATUS_NO_MEMORY;
1415 /* create the policy handle */
1416 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1417 if (!u_handle) {
1418 return NT_STATUS_NO_MEMORY;
1421 u_handle->data = talloc_steal(u_handle, a_state);
1423 *r->out.user_handle = u_handle->wire_handle;
1424 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1426 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1428 return NT_STATUS_OK;
1433 samr_CreateUser
1435 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1436 struct samr_CreateUser *r)
1438 struct samr_CreateUser2 r2;
1439 uint32_t access_granted = 0;
1442 /* a simple wrapper around samr_CreateUser2 works nicely */
1443 r2.in.domain_handle = r->in.domain_handle;
1444 r2.in.account_name = r->in.account_name;
1445 r2.in.acct_flags = ACB_NORMAL;
1446 r2.in.access_mask = r->in.access_mask;
1447 r2.out.user_handle = r->out.user_handle;
1448 r2.out.access_granted = &access_granted;
1449 r2.out.rid = r->out.rid;
1451 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1455 samr_EnumDomainUsers
1457 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1458 struct samr_EnumDomainUsers *r)
1460 struct dcesrv_handle *h;
1461 struct samr_domain_state *d_state;
1462 struct ldb_result *res;
1463 int ret, num_filtered_entries, i, first;
1464 struct samr_SamEntry *entries;
1465 const char * const attrs[] = { "objectSid", "sAMAccountName",
1466 "userAccountControl", NULL };
1467 struct samr_SamArray *sam;
1469 *r->out.resume_handle = 0;
1470 *r->out.sam = NULL;
1471 *r->out.num_entries = 0;
1473 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1475 d_state = h->data;
1477 /* don't have to worry about users in the builtin domain, as there are none */
1478 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1480 if (ret != LDB_SUCCESS) {
1481 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1482 ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1483 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1486 /* convert to SamEntry format */
1487 entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1488 if (!entries) {
1489 return NT_STATUS_NO_MEMORY;
1491 num_filtered_entries = 0;
1492 for (i=0;i<res->count;i++) {
1493 /* Check if a mask has been requested */
1494 if (r->in.acct_flags
1495 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i],
1496 d_state->domain_dn) & r->in.acct_flags) == 0)) {
1497 continue;
1499 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1500 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1501 num_filtered_entries++;
1504 /* sort the results by rid */
1505 qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry),
1506 (comparison_fn_t)compare_SamEntry);
1508 /* find the first entry to return */
1509 for (first=0;
1510 first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1511 first++) ;
1513 /* return the rest, limit by max_size. Note that we
1514 use the w2k3 element size value of 54 */
1515 *r->out.num_entries = num_filtered_entries - first;
1516 *r->out.num_entries = MIN(*r->out.num_entries,
1517 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1519 sam = talloc(mem_ctx, struct samr_SamArray);
1520 if (!sam) {
1521 return NT_STATUS_NO_MEMORY;
1524 sam->entries = entries+first;
1525 sam->count = *r->out.num_entries;
1527 *r->out.sam = sam;
1529 if (first == num_filtered_entries) {
1530 return NT_STATUS_OK;
1533 if (*r->out.num_entries < num_filtered_entries - first) {
1534 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1535 return STATUS_MORE_ENTRIES;
1538 return NT_STATUS_OK;
1543 samr_CreateDomAlias
1545 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1546 struct samr_CreateDomAlias *r)
1548 struct samr_domain_state *d_state;
1549 struct samr_account_state *a_state;
1550 struct dcesrv_handle *h;
1551 const char *alias_name, *name;
1552 struct ldb_message *msg;
1553 struct dom_sid *sid;
1554 struct dcesrv_handle *a_handle;
1555 int ret;
1557 ZERO_STRUCTP(r->out.alias_handle);
1558 *r->out.rid = 0;
1560 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1562 d_state = h->data;
1564 if (d_state->builtin) {
1565 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1566 return NT_STATUS_ACCESS_DENIED;
1569 alias_name = r->in.alias_name->string;
1571 if (alias_name == NULL) {
1572 return NT_STATUS_INVALID_PARAMETER;
1575 /* Check if alias already exists */
1576 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1577 "sAMAccountName",
1578 "(sAMAccountName=%s)(objectclass=group))",
1579 ldb_binary_encode_string(mem_ctx, alias_name));
1581 if (name != NULL) {
1582 return NT_STATUS_ALIAS_EXISTS;
1585 msg = ldb_msg_new(mem_ctx);
1586 if (msg == NULL) {
1587 return NT_STATUS_NO_MEMORY;
1590 /* add core elements to the ldb_message for the alias */
1591 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1592 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1593 if (!msg->dn) {
1594 return NT_STATUS_NO_MEMORY;
1597 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1598 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1599 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1601 /* create the alias */
1602 ret = ldb_add(d_state->sam_ctx, msg);
1603 switch (ret) {
1604 case LDB_SUCCESS:
1605 break;
1606 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1607 return NT_STATUS_ALIAS_EXISTS;
1608 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1609 return NT_STATUS_ACCESS_DENIED;
1610 default:
1611 DEBUG(0,("Failed to create alias record %s: %s\n",
1612 ldb_dn_get_linearized(msg->dn),
1613 ldb_errstring(d_state->sam_ctx)));
1614 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1617 a_state = talloc(d_state, struct samr_account_state);
1618 if (!a_state) {
1619 return NT_STATUS_NO_MEMORY;
1622 a_state->sam_ctx = d_state->sam_ctx;
1623 a_state->access_mask = r->in.access_mask;
1624 a_state->domain_state = talloc_reference(a_state, d_state);
1625 a_state->account_dn = talloc_steal(a_state, msg->dn);
1627 /* retrieve the sid for the alias just created */
1628 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1629 msg->dn, "objectSid", NULL);
1631 a_state->account_name = talloc_strdup(a_state, alias_name);
1632 if (!a_state->account_name) {
1633 return NT_STATUS_NO_MEMORY;
1636 /* create the policy handle */
1637 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1638 if (a_handle == NULL)
1639 return NT_STATUS_NO_MEMORY;
1641 a_handle->data = talloc_steal(a_handle, a_state);
1643 *r->out.alias_handle = a_handle->wire_handle;
1645 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1647 return NT_STATUS_OK;
1652 samr_EnumDomainAliases
1654 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1655 struct samr_EnumDomainAliases *r)
1657 struct dcesrv_handle *h;
1658 struct samr_domain_state *d_state;
1659 struct ldb_message **res;
1660 int ldb_cnt, count, i, first;
1661 struct samr_SamEntry *entries;
1662 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1663 struct samr_SamArray *sam;
1665 *r->out.resume_handle = 0;
1666 *r->out.sam = NULL;
1667 *r->out.num_entries = 0;
1669 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1671 d_state = h->data;
1673 /* search for all domain groups in this domain. This could possibly be
1674 cached and resumed based on resume_key */
1675 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1676 d_state->domain_dn,
1677 &res, attrs,
1678 d_state->domain_sid,
1679 "(&(|(grouptype=%d)(grouptype=%d)))"
1680 "(objectclass=group))",
1681 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1682 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1683 if (ldb_cnt == -1) {
1684 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1686 if (ldb_cnt == 0) {
1687 return NT_STATUS_OK;
1690 /* convert to SamEntry format */
1691 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1692 if (!entries) {
1693 return NT_STATUS_NO_MEMORY;
1696 count = 0;
1698 for (i=0;i<ldb_cnt;i++) {
1699 struct dom_sid *alias_sid;
1701 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1702 "objectSid");
1704 if (alias_sid == NULL)
1705 continue;
1707 entries[count].idx =
1708 alias_sid->sub_auths[alias_sid->num_auths-1];
1709 entries[count].name.string =
1710 samdb_result_string(res[i], "sAMAccountName", "");
1711 count += 1;
1714 /* sort the results by rid */
1715 qsort(entries, count, sizeof(struct samr_SamEntry),
1716 (comparison_fn_t)compare_SamEntry);
1718 /* find the first entry to return */
1719 for (first=0;
1720 first<count && entries[first].idx <= *r->in.resume_handle;
1721 first++) ;
1723 if (first == count) {
1724 return NT_STATUS_OK;
1727 *r->out.num_entries = count - first;
1728 *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1730 sam = talloc(mem_ctx, struct samr_SamArray);
1731 if (!sam) {
1732 return NT_STATUS_NO_MEMORY;
1735 sam->entries = entries+first;
1736 sam->count = *r->out.num_entries;
1738 *r->out.sam = sam;
1740 if (*r->out.num_entries < count - first) {
1741 *r->out.resume_handle =
1742 entries[first+*r->out.num_entries-1].idx;
1743 return STATUS_MORE_ENTRIES;
1746 return NT_STATUS_OK;
1751 samr_GetAliasMembership
1753 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1754 struct samr_GetAliasMembership *r)
1756 struct dcesrv_handle *h;
1757 struct samr_domain_state *d_state;
1758 struct ldb_message **res;
1759 int i, count = 0;
1761 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1763 d_state = h->data;
1765 if (r->in.sids->num_sids > 0) {
1766 const char *filter;
1767 const char * const attrs[2] = { "objectSid", NULL };
1769 filter = talloc_asprintf(mem_ctx,
1770 "(&(|(grouptype=%d)(grouptype=%d))"
1771 "(objectclass=group)(|",
1772 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1773 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1774 if (filter == NULL)
1775 return NT_STATUS_NO_MEMORY;
1777 for (i=0; i<r->in.sids->num_sids; i++) {
1778 const char *memberdn;
1780 memberdn =
1781 samdb_search_string(d_state->sam_ctx,
1782 mem_ctx, NULL,
1783 "distinguishedName",
1784 "(objectSid=%s)",
1785 ldap_encode_ndr_dom_sid(mem_ctx,
1786 r->in.sids->sids[i].sid));
1788 if (memberdn == NULL)
1789 continue;
1791 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1792 filter, memberdn);
1793 if (filter == NULL)
1794 return NT_STATUS_NO_MEMORY;
1797 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1798 d_state->domain_dn, &res, attrs,
1799 d_state->domain_sid, "%s))", filter);
1800 if (count < 0)
1801 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1804 r->out.rids->count = 0;
1805 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1806 if (r->out.rids->ids == NULL)
1807 return NT_STATUS_NO_MEMORY;
1809 for (i=0; i<count; i++) {
1810 struct dom_sid *alias_sid;
1812 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1814 if (alias_sid == NULL) {
1815 DEBUG(0, ("Could not find objectSid\n"));
1816 continue;
1819 r->out.rids->ids[r->out.rids->count] =
1820 alias_sid->sub_auths[alias_sid->num_auths-1];
1821 r->out.rids->count += 1;
1824 return NT_STATUS_OK;
1829 samr_LookupNames
1831 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1832 struct samr_LookupNames *r)
1834 struct dcesrv_handle *h;
1835 struct samr_domain_state *d_state;
1836 int i, num_mapped;
1837 NTSTATUS status = NT_STATUS_OK;
1838 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1839 int count;
1841 ZERO_STRUCTP(r->out.rids);
1842 ZERO_STRUCTP(r->out.types);
1844 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1846 d_state = h->data;
1848 if (r->in.num_names == 0) {
1849 return NT_STATUS_OK;
1852 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1853 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1854 if (!r->out.rids->ids || !r->out.types->ids) {
1855 return NT_STATUS_NO_MEMORY;
1857 r->out.rids->count = r->in.num_names;
1858 r->out.types->count = r->in.num_names;
1860 num_mapped = 0;
1862 for (i=0;i<r->in.num_names;i++) {
1863 struct ldb_message **res;
1864 struct dom_sid *sid;
1865 uint32_t atype, rtype;
1867 r->out.rids->ids[i] = 0;
1868 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1870 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1871 "sAMAccountName=%s",
1872 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1873 if (count != 1) {
1874 status = STATUS_SOME_UNMAPPED;
1875 continue;
1878 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1879 if (sid == NULL) {
1880 status = STATUS_SOME_UNMAPPED;
1881 continue;
1884 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1885 if (atype == 0) {
1886 status = STATUS_SOME_UNMAPPED;
1887 continue;
1890 rtype = ds_atype_map(atype);
1892 if (rtype == SID_NAME_UNKNOWN) {
1893 status = STATUS_SOME_UNMAPPED;
1894 continue;
1897 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1898 r->out.types->ids[i] = rtype;
1899 num_mapped++;
1902 if (num_mapped == 0) {
1903 return NT_STATUS_NONE_MAPPED;
1905 return status;
1910 samr_LookupRids
1912 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1913 struct samr_LookupRids *r)
1915 struct dcesrv_handle *h;
1916 struct samr_domain_state *d_state;
1917 int i, total;
1918 NTSTATUS status = NT_STATUS_OK;
1919 struct lsa_String *names;
1920 uint32_t *ids;
1922 ZERO_STRUCTP(r->out.names);
1923 ZERO_STRUCTP(r->out.types);
1925 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1927 d_state = h->data;
1929 if (r->in.num_rids == 0)
1930 return NT_STATUS_OK;
1932 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1933 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1935 if ((names == NULL) || (ids == NULL))
1936 return NT_STATUS_NO_MEMORY;
1938 total = 0;
1940 for (i=0; i<r->in.num_rids; i++) {
1941 struct ldb_message **res;
1942 int count;
1943 const char * const attrs[] = { "sAMAccountType",
1944 "sAMAccountName", NULL };
1945 uint32_t atype;
1946 struct dom_sid *sid;
1948 ids[i] = SID_NAME_UNKNOWN;
1950 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid,
1951 r->in.rids[i]);
1952 if (sid == NULL) {
1953 names[i].string = NULL;
1954 status = STATUS_SOME_UNMAPPED;
1955 continue;
1958 count = gendb_search(d_state->sam_ctx, mem_ctx,
1959 d_state->domain_dn, &res, attrs,
1960 "(objectSid=%s)",
1961 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1962 if (count != 1) {
1963 names[i].string = NULL;
1964 status = STATUS_SOME_UNMAPPED;
1965 continue;
1968 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1969 NULL);
1971 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1972 if (atype == 0) {
1973 status = STATUS_SOME_UNMAPPED;
1974 continue;
1977 ids[i] = ds_atype_map(atype);
1979 if (ids[i] == SID_NAME_UNKNOWN) {
1980 status = STATUS_SOME_UNMAPPED;
1981 continue;
1985 r->out.names->names = names;
1986 r->out.names->count = r->in.num_rids;
1988 r->out.types->ids = ids;
1989 r->out.types->count = r->in.num_rids;
1991 return status;
1996 samr_OpenGroup
1998 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1999 struct samr_OpenGroup *r)
2001 struct samr_domain_state *d_state;
2002 struct samr_account_state *a_state;
2003 struct dcesrv_handle *h;
2004 const char *groupname;
2005 struct dom_sid *sid;
2006 struct ldb_message **msgs;
2007 struct dcesrv_handle *g_handle;
2008 const char * const attrs[2] = { "sAMAccountName", NULL };
2009 int ret;
2011 ZERO_STRUCTP(r->out.group_handle);
2013 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2015 d_state = h->data;
2017 /* form the group SID */
2018 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2019 if (!sid) {
2020 return NT_STATUS_NO_MEMORY;
2023 /* search for the group record */
2024 ret = gendb_search(d_state->sam_ctx,
2025 mem_ctx, d_state->domain_dn, &msgs, attrs,
2026 "(&(objectSid=%s)(objectclass=group)"
2027 "(grouptype=%d))",
2028 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2029 GTYPE_SECURITY_GLOBAL_GROUP);
2030 if (ret == 0) {
2031 return NT_STATUS_NO_SUCH_GROUP;
2033 if (ret != 1) {
2034 DEBUG(0,("Found %d records matching sid %s\n",
2035 ret, dom_sid_string(mem_ctx, sid)));
2036 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2039 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2040 if (groupname == NULL) {
2041 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2042 dom_sid_string(mem_ctx, sid)));
2043 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2046 a_state = talloc(d_state, struct samr_account_state);
2047 if (!a_state) {
2048 return NT_STATUS_NO_MEMORY;
2050 a_state->sam_ctx = d_state->sam_ctx;
2051 a_state->access_mask = r->in.access_mask;
2052 a_state->domain_state = talloc_reference(a_state, d_state);
2053 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2054 a_state->account_sid = talloc_steal(a_state, sid);
2055 a_state->account_name = talloc_strdup(a_state, groupname);
2056 if (!a_state->account_name) {
2057 return NT_STATUS_NO_MEMORY;
2060 /* create the policy handle */
2061 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2062 if (!g_handle) {
2063 return NT_STATUS_NO_MEMORY;
2066 g_handle->data = talloc_steal(g_handle, a_state);
2068 *r->out.group_handle = g_handle->wire_handle;
2070 return NT_STATUS_OK;
2074 samr_QueryGroupInfo
2076 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2077 struct samr_QueryGroupInfo *r)
2079 struct dcesrv_handle *h;
2080 struct samr_account_state *a_state;
2081 struct ldb_message *msg;
2082 struct ldb_result *res;
2083 const char * const attrs[4] = { "sAMAccountName", "description",
2084 "numMembers", NULL };
2085 int ret;
2086 union samr_GroupInfo *info;
2088 *r->out.info = NULL;
2090 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2092 a_state = h->data;
2094 ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn,
2095 LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2097 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2098 return NT_STATUS_NO_SUCH_GROUP;
2099 } else if (ret != LDB_SUCCESS) {
2100 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2101 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2104 if (res->count != 1) {
2105 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2107 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2109 msg = res->msgs[0];
2111 /* allocate the info structure */
2112 info = talloc_zero(mem_ctx, union samr_GroupInfo);
2113 if (info == NULL) {
2114 return NT_STATUS_NO_MEMORY;
2117 /* Fill in the level */
2118 switch (r->in.level) {
2119 case GROUPINFOALL:
2120 QUERY_STRING(msg, all.name, "sAMAccountName");
2121 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2122 QUERY_UINT (msg, all.num_members, "numMembers")
2123 QUERY_STRING(msg, all.description, "description");
2124 break;
2125 case GROUPINFONAME:
2126 QUERY_STRING(msg, name, "sAMAccountName");
2127 break;
2128 case GROUPINFOATTRIBUTES:
2129 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2130 break;
2131 case GROUPINFODESCRIPTION:
2132 QUERY_STRING(msg, description, "description");
2133 break;
2134 case GROUPINFOALL2:
2135 QUERY_STRING(msg, all2.name, "sAMAccountName");
2136 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2137 QUERY_UINT (msg, all2.num_members, "numMembers")
2138 QUERY_STRING(msg, all2.description, "description");
2139 break;
2140 default:
2141 talloc_free(info);
2142 return NT_STATUS_INVALID_INFO_CLASS;
2145 *r->out.info = info;
2147 return NT_STATUS_OK;
2152 samr_SetGroupInfo
2154 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2155 struct samr_SetGroupInfo *r)
2157 struct dcesrv_handle *h;
2158 struct samr_account_state *g_state;
2159 struct ldb_message *msg;
2160 struct ldb_context *sam_ctx;
2161 int ret;
2163 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2165 g_state = h->data;
2166 sam_ctx = g_state->sam_ctx;
2168 msg = ldb_msg_new(mem_ctx);
2169 if (msg == NULL) {
2170 return NT_STATUS_NO_MEMORY;
2173 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2174 if (!msg->dn) {
2175 return NT_STATUS_NO_MEMORY;
2178 switch (r->in.level) {
2179 case GROUPINFODESCRIPTION:
2180 SET_STRING(msg, description, "description");
2181 break;
2182 case GROUPINFONAME:
2183 /* On W2k3 this does not change the name, it changes the
2184 * sAMAccountName attribute */
2185 SET_STRING(msg, name, "sAMAccountName");
2186 break;
2187 case GROUPINFOATTRIBUTES:
2188 /* This does not do anything obviously visible in W2k3 LDAP */
2189 return NT_STATUS_OK;
2190 default:
2191 return NT_STATUS_INVALID_INFO_CLASS;
2194 /* modify the samdb record */
2195 ret = ldb_modify(g_state->sam_ctx, msg);
2196 if (ret != 0) {
2197 /* we really need samdb.c to return NTSTATUS */
2198 return NT_STATUS_UNSUCCESSFUL;
2201 return NT_STATUS_OK;
2206 samr_AddGroupMember
2208 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2209 struct samr_AddGroupMember *r)
2211 struct dcesrv_handle *h;
2212 struct samr_account_state *a_state;
2213 struct samr_domain_state *d_state;
2214 struct ldb_message *mod;
2215 struct dom_sid *membersid;
2216 const char *memberdn;
2217 struct ldb_result *res;
2218 const char * const attrs[] = { NULL };
2219 int ret;
2221 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2223 a_state = h->data;
2224 d_state = a_state->domain_state;
2226 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2227 if (membersid == NULL)
2228 return NT_STATUS_NO_MEMORY;
2230 /* In native mode, AD can also nest domain groups. Not sure yet
2231 * whether this is also available via RPC. */
2232 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2233 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2234 "(&(objectSid=%s)(objectclass=user))",
2235 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2237 if (ret != 0) {
2238 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2241 if (res->count == 0) {
2242 return NT_STATUS_NO_SUCH_USER;
2245 if (res->count > 1) {
2246 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2249 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2251 if (memberdn == NULL)
2252 return NT_STATUS_NO_MEMORY;
2254 mod = ldb_msg_new(mem_ctx);
2255 if (mod == NULL) {
2256 return NT_STATUS_NO_MEMORY;
2259 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2261 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2262 memberdn) != 0)
2263 return NT_STATUS_UNSUCCESSFUL;
2265 ret = ldb_modify(a_state->sam_ctx, mod);
2266 switch (ret) {
2267 case LDB_SUCCESS:
2268 return NT_STATUS_OK;
2269 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2270 return NT_STATUS_MEMBER_IN_GROUP;
2271 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2272 return NT_STATUS_ACCESS_DENIED;
2273 default:
2274 return NT_STATUS_UNSUCCESSFUL;
2281 samr_DeleteDomainGroup
2283 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2284 struct samr_DeleteDomainGroup *r)
2286 struct dcesrv_handle *h;
2287 struct samr_account_state *a_state;
2288 int ret;
2290 *r->out.group_handle = *r->in.group_handle;
2292 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2294 a_state = h->data;
2296 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2297 if (ret != 0) {
2298 return NT_STATUS_UNSUCCESSFUL;
2301 ZERO_STRUCTP(r->out.group_handle);
2303 return NT_STATUS_OK;
2308 samr_DeleteGroupMember
2310 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2311 struct samr_DeleteGroupMember *r)
2313 struct dcesrv_handle *h;
2314 struct samr_account_state *a_state;
2315 struct samr_domain_state *d_state;
2316 struct ldb_message *mod;
2317 struct dom_sid *membersid;
2318 const char *memberdn;
2319 struct ldb_result *res;
2320 const char * const attrs[] = { NULL };
2321 int ret;
2323 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2325 a_state = h->data;
2326 d_state = a_state->domain_state;
2328 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2329 if (membersid == NULL)
2330 return NT_STATUS_NO_MEMORY;
2332 /* In native mode, AD can also nest domain groups. Not sure yet
2333 * whether this is also available via RPC. */
2334 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2335 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2336 "(&(objectSid=%s)(objectclass=user))",
2337 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2339 if (ret != 0) {
2340 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2343 if (res->count == 0) {
2344 return NT_STATUS_NO_SUCH_USER;
2347 if (res->count > 1) {
2348 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2351 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2353 if (memberdn == NULL)
2354 return NT_STATUS_NO_MEMORY;
2356 mod = ldb_msg_new(mem_ctx);
2357 if (mod == NULL) {
2358 return NT_STATUS_NO_MEMORY;
2361 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2363 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2364 memberdn) != 0) {
2365 return NT_STATUS_NO_MEMORY;
2368 ret = ldb_modify(a_state->sam_ctx, mod);
2369 switch (ret) {
2370 case LDB_SUCCESS:
2371 return NT_STATUS_OK;
2372 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2373 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2374 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2375 return NT_STATUS_ACCESS_DENIED;
2376 default:
2377 return NT_STATUS_UNSUCCESSFUL;
2383 samr_QueryGroupMember
2385 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2386 struct samr_QueryGroupMember *r)
2388 struct dcesrv_handle *h;
2389 struct samr_account_state *a_state;
2390 struct ldb_message **res;
2391 struct ldb_message_element *el;
2392 struct samr_RidTypeArray *array;
2393 const char * const attrs[2] = { "member", NULL };
2394 int ret;
2396 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2398 a_state = h->data;
2400 /* pull the member attribute */
2401 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2402 a_state->account_dn, &res, attrs);
2404 if (ret != 1) {
2405 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2408 array = talloc(mem_ctx, struct samr_RidTypeArray);
2410 if (array == NULL)
2411 return NT_STATUS_NO_MEMORY;
2413 ZERO_STRUCTP(array);
2415 el = ldb_msg_find_element(res[0], "member");
2417 if (el != NULL) {
2418 int i;
2420 array->count = el->num_values;
2422 array->rids = talloc_array(mem_ctx, uint32_t,
2423 el->num_values);
2424 if (array->rids == NULL)
2425 return NT_STATUS_NO_MEMORY;
2427 array->types = talloc_array(mem_ctx, uint32_t,
2428 el->num_values);
2429 if (array->types == NULL)
2430 return NT_STATUS_NO_MEMORY;
2432 for (i=0; i<el->num_values; i++) {
2433 struct ldb_message **res2;
2434 const char * const attrs2[2] = { "objectSid", NULL };
2435 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2436 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2437 &res2, attrs2);
2438 if (ret != 1)
2439 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2441 array->rids[i] =
2442 samdb_result_rid_from_sid(mem_ctx, res2[0],
2443 "objectSid", 0);
2445 if (array->rids[i] == 0)
2446 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2448 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2452 *r->out.rids = array;
2454 return NT_STATUS_OK;
2459 samr_SetMemberAttributesOfGroup
2461 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2462 struct samr_SetMemberAttributesOfGroup *r)
2464 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2469 samr_OpenAlias
2471 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2472 struct samr_OpenAlias *r)
2474 struct samr_domain_state *d_state;
2475 struct samr_account_state *a_state;
2476 struct dcesrv_handle *h;
2477 const char *alias_name;
2478 struct dom_sid *sid;
2479 struct ldb_message **msgs;
2480 struct dcesrv_handle *g_handle;
2481 const char * const attrs[2] = { "sAMAccountName", NULL };
2482 int ret;
2484 ZERO_STRUCTP(r->out.alias_handle);
2486 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2488 d_state = h->data;
2490 /* form the alias SID */
2491 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2492 if (sid == NULL)
2493 return NT_STATUS_NO_MEMORY;
2495 /* search for the group record */
2496 ret = gendb_search(d_state->sam_ctx,
2497 mem_ctx, d_state->domain_dn, &msgs, attrs,
2498 "(&(objectSid=%s)(objectclass=group)"
2499 "(|(grouptype=%d)(grouptype=%d)))",
2500 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2501 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2502 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2503 if (ret == 0) {
2504 return NT_STATUS_NO_SUCH_ALIAS;
2506 if (ret != 1) {
2507 DEBUG(0,("Found %d records matching sid %s\n",
2508 ret, dom_sid_string(mem_ctx, sid)));
2509 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2512 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2513 if (alias_name == NULL) {
2514 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2515 dom_sid_string(mem_ctx, sid)));
2516 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2519 a_state = talloc(d_state, struct samr_account_state);
2520 if (!a_state) {
2521 return NT_STATUS_NO_MEMORY;
2523 a_state->sam_ctx = d_state->sam_ctx;
2524 a_state->access_mask = r->in.access_mask;
2525 a_state->domain_state = talloc_reference(a_state, d_state);
2526 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2527 a_state->account_sid = talloc_steal(a_state, sid);
2528 a_state->account_name = talloc_strdup(a_state, alias_name);
2529 if (!a_state->account_name) {
2530 return NT_STATUS_NO_MEMORY;
2533 /* create the policy handle */
2534 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2535 if (!g_handle) {
2536 return NT_STATUS_NO_MEMORY;
2539 g_handle->data = talloc_steal(g_handle, a_state);
2541 *r->out.alias_handle = g_handle->wire_handle;
2543 return NT_STATUS_OK;
2548 samr_QueryAliasInfo
2550 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2551 struct samr_QueryAliasInfo *r)
2553 struct dcesrv_handle *h;
2554 struct samr_account_state *a_state;
2555 struct ldb_message *msg, **res;
2556 const char * const attrs[4] = { "sAMAccountName", "description",
2557 "numMembers", NULL };
2558 int ret;
2559 union samr_AliasInfo *info;
2561 *r->out.info = NULL;
2563 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2565 a_state = h->data;
2567 /* pull all the alias attributes */
2568 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2569 a_state->account_dn ,&res, attrs);
2570 if (ret != 1) {
2571 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2573 msg = res[0];
2575 /* allocate the info structure */
2576 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2577 if (info == NULL) {
2578 return NT_STATUS_NO_MEMORY;
2581 switch(r->in.level) {
2582 case ALIASINFOALL:
2583 QUERY_STRING(msg, all.name, "sAMAccountName");
2584 QUERY_UINT (msg, all.num_members, "numMembers");
2585 QUERY_STRING(msg, all.description, "description");
2586 break;
2587 case ALIASINFONAME:
2588 QUERY_STRING(msg, name, "sAMAccountName");
2589 break;
2590 case ALIASINFODESCRIPTION:
2591 QUERY_STRING(msg, description, "description");
2592 break;
2593 default:
2594 talloc_free(info);
2595 return NT_STATUS_INVALID_INFO_CLASS;
2598 *r->out.info = info;
2600 return NT_STATUS_OK;
2605 samr_SetAliasInfo
2607 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2608 struct samr_SetAliasInfo *r)
2610 struct dcesrv_handle *h;
2611 struct samr_account_state *a_state;
2612 struct ldb_message *msg;
2613 struct ldb_context *sam_ctx;
2614 int ret;
2616 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2618 a_state = h->data;
2619 sam_ctx = a_state->sam_ctx;
2621 msg = ldb_msg_new(mem_ctx);
2622 if (msg == NULL) {
2623 return NT_STATUS_NO_MEMORY;
2626 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2627 if (!msg->dn) {
2628 return NT_STATUS_NO_MEMORY;
2631 switch (r->in.level) {
2632 case ALIASINFODESCRIPTION:
2633 SET_STRING(msg, description, "description");
2634 break;
2635 case ALIASINFONAME:
2636 /* On W2k3 this does not change the name, it changes the
2637 * sAMAccountName attribute */
2638 SET_STRING(msg, name, "sAMAccountName");
2639 break;
2640 default:
2641 return NT_STATUS_INVALID_INFO_CLASS;
2644 /* modify the samdb record */
2645 ret = ldb_modify(a_state->sam_ctx, msg);
2646 if (ret != 0) {
2647 /* we really need samdb.c to return NTSTATUS */
2648 return NT_STATUS_UNSUCCESSFUL;
2651 return NT_STATUS_OK;
2656 samr_DeleteDomAlias
2658 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2659 struct samr_DeleteDomAlias *r)
2661 struct dcesrv_handle *h;
2662 struct samr_account_state *a_state;
2663 int ret;
2665 *r->out.alias_handle = *r->in.alias_handle;
2667 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2669 a_state = h->data;
2671 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2672 if (ret != 0) {
2673 return NT_STATUS_UNSUCCESSFUL;
2676 ZERO_STRUCTP(r->out.alias_handle);
2678 return NT_STATUS_OK;
2683 samr_AddAliasMember
2685 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2686 struct samr_AddAliasMember *r)
2688 struct dcesrv_handle *h;
2689 struct samr_account_state *a_state;
2690 struct samr_domain_state *d_state;
2691 struct ldb_message *mod;
2692 struct ldb_message **msgs;
2693 const char * const attrs[] = { NULL };
2694 struct ldb_dn *memberdn = NULL;
2695 int ret;
2696 NTSTATUS status;
2698 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2700 a_state = h->data;
2701 d_state = a_state->domain_state;
2703 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2704 &msgs, attrs, "(objectsid=%s)",
2705 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2707 if (ret == 1) {
2708 memberdn = msgs[0]->dn;
2709 } else if (ret > 1) {
2710 DEBUG(0,("Found %d records matching sid %s\n",
2711 ret, dom_sid_string(mem_ctx, r->in.sid)));
2712 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2713 } else if (ret == 0) {
2714 status = samdb_create_foreign_security_principal(
2715 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2716 if (!NT_STATUS_IS_OK(status)) {
2717 return status;
2719 } else {
2720 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2723 if (memberdn == NULL) {
2724 DEBUG(0, ("Could not find memberdn\n"));
2725 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2728 mod = ldb_msg_new(mem_ctx);
2729 if (mod == NULL) {
2730 return NT_STATUS_NO_MEMORY;
2733 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2735 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2736 ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2737 return NT_STATUS_UNSUCCESSFUL;
2739 if (ldb_modify(a_state->sam_ctx, mod) != 0)
2740 return NT_STATUS_UNSUCCESSFUL;
2742 return NT_STATUS_OK;
2747 samr_DeleteAliasMember
2749 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2750 struct samr_DeleteAliasMember *r)
2752 struct dcesrv_handle *h;
2753 struct samr_account_state *a_state;
2754 struct samr_domain_state *d_state;
2755 struct ldb_message *mod;
2756 const char *memberdn;
2758 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2760 a_state = h->data;
2761 d_state = a_state->domain_state;
2763 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2764 "distinguishedName", "(objectSid=%s)",
2765 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2767 if (memberdn == NULL)
2768 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2770 mod = ldb_msg_new(mem_ctx);
2771 if (mod == NULL) {
2772 return NT_STATUS_NO_MEMORY;
2775 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2777 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2778 memberdn) != 0)
2779 return NT_STATUS_UNSUCCESSFUL;
2781 if (ldb_modify(a_state->sam_ctx, mod) != 0)
2782 return NT_STATUS_UNSUCCESSFUL;
2784 return NT_STATUS_OK;
2789 samr_GetMembersInAlias
2791 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2792 struct samr_GetMembersInAlias *r)
2794 struct dcesrv_handle *h;
2795 struct samr_account_state *a_state;
2796 struct samr_domain_state *d_state;
2797 struct ldb_message **msgs;
2798 struct lsa_SidPtr *sids;
2799 struct ldb_message_element *el;
2800 const char * const attrs[2] = { "member", NULL};
2801 int ret;
2803 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2805 a_state = h->data;
2806 d_state = a_state->domain_state;
2808 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2809 a_state->account_dn, &msgs, attrs);
2811 if (ret == -1) {
2812 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2813 } else if (ret == 0) {
2814 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2815 } else if (ret != 1) {
2816 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2819 r->out.sids->num_sids = 0;
2820 r->out.sids->sids = NULL;
2822 el = ldb_msg_find_element(msgs[0], "member");
2824 if (el != NULL) {
2825 int i;
2827 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2828 el->num_values);
2830 if (sids == NULL)
2831 return NT_STATUS_NO_MEMORY;
2833 for (i=0; i<el->num_values; i++) {
2834 struct ldb_message **msgs2;
2835 const char * const attrs2[2] = { "objectSid", NULL };
2836 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2837 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2838 &msgs2, attrs2);
2839 if (ret != 1)
2840 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2842 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2843 "objectSid");
2845 if (sids[i].sid == NULL)
2846 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2848 r->out.sids->num_sids = el->num_values;
2849 r->out.sids->sids = sids;
2852 return NT_STATUS_OK;
2856 samr_OpenUser
2858 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2859 struct samr_OpenUser *r)
2861 struct samr_domain_state *d_state;
2862 struct samr_account_state *a_state;
2863 struct dcesrv_handle *h;
2864 const char *account_name;
2865 struct dom_sid *sid;
2866 struct ldb_message **msgs;
2867 struct dcesrv_handle *u_handle;
2868 const char * const attrs[2] = { "sAMAccountName", NULL };
2869 int ret;
2871 ZERO_STRUCTP(r->out.user_handle);
2873 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2875 d_state = h->data;
2877 /* form the users SID */
2878 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2879 if (!sid) {
2880 return NT_STATUS_NO_MEMORY;
2883 /* search for the user record */
2884 ret = gendb_search(d_state->sam_ctx,
2885 mem_ctx, d_state->domain_dn, &msgs, attrs,
2886 "(&(objectSid=%s)(objectclass=user))",
2887 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2888 if (ret == 0) {
2889 return NT_STATUS_NO_SUCH_USER;
2891 if (ret != 1) {
2892 DEBUG(0,("Found %d records matching sid %s\n", ret,
2893 dom_sid_string(mem_ctx, sid)));
2894 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2897 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2898 if (account_name == NULL) {
2899 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2900 dom_sid_string(mem_ctx, sid)));
2901 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2904 a_state = talloc(mem_ctx, struct samr_account_state);
2905 if (!a_state) {
2906 return NT_STATUS_NO_MEMORY;
2908 a_state->sam_ctx = d_state->sam_ctx;
2909 a_state->access_mask = r->in.access_mask;
2910 a_state->domain_state = talloc_reference(a_state, d_state);
2911 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2912 a_state->account_sid = talloc_steal(a_state, sid);
2913 a_state->account_name = talloc_strdup(a_state, account_name);
2914 if (!a_state->account_name) {
2915 return NT_STATUS_NO_MEMORY;
2918 /* create the policy handle */
2919 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2920 if (!u_handle) {
2921 return NT_STATUS_NO_MEMORY;
2924 u_handle->data = talloc_steal(u_handle, a_state);
2926 *r->out.user_handle = u_handle->wire_handle;
2928 return NT_STATUS_OK;
2934 samr_DeleteUser
2936 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2937 struct samr_DeleteUser *r)
2939 struct dcesrv_handle *h;
2940 struct samr_account_state *a_state;
2941 int ret;
2943 *r->out.user_handle = *r->in.user_handle;
2945 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2947 a_state = h->data;
2949 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2950 if (ret != 0) {
2951 DEBUG(1, ("Failed to delete user: %s: %s\n",
2952 ldb_dn_get_linearized(a_state->account_dn),
2953 ldb_errstring(a_state->sam_ctx)));
2954 return NT_STATUS_UNSUCCESSFUL;
2957 ZERO_STRUCTP(r->out.user_handle);
2959 return NT_STATUS_OK;
2964 samr_QueryUserInfo
2966 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2967 struct samr_QueryUserInfo *r)
2969 struct dcesrv_handle *h;
2970 struct samr_account_state *a_state;
2971 struct ldb_message *msg, **res;
2972 int ret;
2973 struct ldb_context *sam_ctx;
2975 const char * const *attrs = NULL;
2976 union samr_UserInfo *info;
2978 *r->out.info = NULL;
2980 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2982 a_state = h->data;
2983 sam_ctx = a_state->sam_ctx;
2985 /* fill in the reply */
2986 switch (r->in.level) {
2987 case 1:
2989 static const char * const attrs2[] = {"sAMAccountName",
2990 "displayName",
2991 "primaryroupID",
2992 "description",
2993 "comment",
2994 NULL};
2995 attrs = attrs2;
2996 break;
2998 case 2:
3000 static const char * const attrs2[] = {"comment",
3001 "countryCode",
3002 "codePage",
3003 NULL};
3004 attrs = attrs2;
3005 break;
3007 case 3:
3009 static const char * const attrs2[] = {"sAMAccountName",
3010 "displayName",
3011 "objectSid",
3012 "primaryGroupID",
3013 "homeDirectory",
3014 "homeDrive",
3015 "scriptPath",
3016 "profilePath",
3017 "userWorkstations",
3018 "lastLogon",
3019 "lastLogoff",
3020 "pwdLastSet",
3021 "logonHours",
3022 "badPwdCount",
3023 "logonCount",
3024 "userAccountControl",
3025 NULL};
3026 attrs = attrs2;
3027 break;
3029 case 4:
3031 static const char * const attrs2[] = {"logonHours",
3032 NULL};
3033 attrs = attrs2;
3034 break;
3036 case 5:
3038 static const char * const attrs2[] = {"sAMAccountName",
3039 "displayName",
3040 "objectSid",
3041 "primaryGroupID",
3042 "homeDirectory",
3043 "homeDrive",
3044 "scriptPath",
3045 "profilePath",
3046 "description",
3047 "userWorkstations",
3048 "lastLogon",
3049 "lastLogoff",
3050 "logonHours",
3051 "badPwdCount",
3052 "logonCount",
3053 "pwdLastSet",
3054 "accountExpires",
3055 "userAccountControl",
3056 NULL};
3057 attrs = attrs2;
3058 break;
3060 case 6:
3062 static const char * const attrs2[] = {"sAMAccountName",
3063 "displayName",
3064 NULL};
3065 attrs = attrs2;
3066 break;
3068 case 7:
3070 static const char * const attrs2[] = {"sAMAccountName",
3071 NULL};
3072 attrs = attrs2;
3073 break;
3075 case 8:
3077 static const char * const attrs2[] = {"displayName",
3078 NULL};
3079 attrs = attrs2;
3080 break;
3082 case 9:
3084 static const char * const attrs2[] = {"primaryGroupID",
3085 NULL};
3086 attrs = attrs2;
3087 break;
3089 case 10:
3091 static const char * const attrs2[] = {"homeDirectory",
3092 "homeDrive",
3093 NULL};
3094 attrs = attrs2;
3095 break;
3097 case 11:
3099 static const char * const attrs2[] = {"scriptPath",
3100 NULL};
3101 attrs = attrs2;
3102 break;
3104 case 12:
3106 static const char * const attrs2[] = {"profilePath",
3107 NULL};
3108 attrs = attrs2;
3109 break;
3111 case 13:
3113 static const char * const attrs2[] = {"description",
3114 NULL};
3115 attrs = attrs2;
3116 break;
3118 case 14:
3120 static const char * const attrs2[] = {"userWorkstations",
3121 NULL};
3122 attrs = attrs2;
3123 break;
3125 case 16:
3127 static const char * const attrs2[] = {"userAccountControl",
3128 "pwdLastSet",
3129 NULL};
3130 attrs = attrs2;
3131 break;
3133 case 17:
3135 static const char * const attrs2[] = {"accountExpires",
3136 NULL};
3137 attrs = attrs2;
3138 break;
3140 case 20:
3142 static const char * const attrs2[] = {"userParameters",
3143 NULL};
3144 attrs = attrs2;
3145 break;
3147 case 21:
3149 static const char * const attrs2[] = {"lastLogon",
3150 "lastLogoff",
3151 "pwdLastSet",
3152 "accountExpires",
3153 "sAMAccountName",
3154 "displayName",
3155 "homeDirectory",
3156 "homeDrive",
3157 "scriptPath",
3158 "profilePath",
3159 "description",
3160 "userWorkstations",
3161 "comment",
3162 "userParameters",
3163 "objectSid",
3164 "primaryGroupID",
3165 "userAccountControl",
3166 "logonHours",
3167 "badPwdCount",
3168 "logonCount",
3169 "countryCode",
3170 "codePage",
3171 NULL};
3172 attrs = attrs2;
3173 break;
3177 /* pull all the user attributes */
3178 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3179 a_state->account_dn ,&res, attrs);
3180 if (ret != 1) {
3181 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3183 msg = res[0];
3185 /* allocate the info structure */
3186 info = talloc_zero(mem_ctx, union samr_UserInfo);
3187 if (info == NULL) {
3188 return NT_STATUS_NO_MEMORY;
3191 /* fill in the reply */
3192 switch (r->in.level) {
3193 case 1:
3194 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3195 QUERY_STRING(msg, info1.full_name, "displayName");
3196 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3197 QUERY_STRING(msg, info1.description, "description");
3198 QUERY_STRING(msg, info1.comment, "comment");
3199 break;
3201 case 2:
3202 QUERY_STRING(msg, info2.comment, "comment");
3203 QUERY_UINT (msg, info2.country_code, "countryCode");
3204 QUERY_UINT (msg, info2.code_page, "codePage");
3205 break;
3207 case 3:
3208 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3209 QUERY_STRING(msg, info3.full_name, "displayName");
3210 QUERY_RID (msg, info3.rid, "objectSid");
3211 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3212 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3213 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3214 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3215 QUERY_STRING(msg, info3.profile_path, "profilePath");
3216 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3217 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3218 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3219 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3220 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3221 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3222 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3223 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3224 QUERY_UINT (msg, info3.logon_count, "logonCount");
3225 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3226 break;
3228 case 4:
3229 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3230 break;
3232 case 5:
3233 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3234 QUERY_STRING(msg, info5.full_name, "displayName");
3235 QUERY_RID (msg, info5.rid, "objectSid");
3236 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3237 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3238 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3239 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3240 QUERY_STRING(msg, info5.profile_path, "profilePath");
3241 QUERY_STRING(msg, info5.description, "description");
3242 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3243 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3244 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3245 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3246 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3247 QUERY_UINT (msg, info5.logon_count, "logonCount");
3248 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3249 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3250 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3251 break;
3253 case 6:
3254 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3255 QUERY_STRING(msg, info6.full_name, "displayName");
3256 break;
3258 case 7:
3259 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3260 break;
3262 case 8:
3263 QUERY_STRING(msg, info8.full_name, "displayName");
3264 break;
3266 case 9:
3267 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3268 break;
3270 case 10:
3271 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3272 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3273 break;
3275 case 11:
3276 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3277 break;
3279 case 12:
3280 QUERY_STRING(msg, info12.profile_path, "profilePath");
3281 break;
3283 case 13:
3284 QUERY_STRING(msg, info13.description, "description");
3285 break;
3287 case 14:
3288 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3289 break;
3291 case 16:
3292 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3293 break;
3295 case 17:
3296 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3297 break;
3299 case 20:
3300 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3301 break;
3303 case 21:
3304 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3305 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3306 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3307 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3308 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3309 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3310 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3311 QUERY_STRING(msg, info21.full_name, "displayName");
3312 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3313 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3314 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3315 QUERY_STRING(msg, info21.profile_path, "profilePath");
3316 QUERY_STRING(msg, info21.description, "description");
3317 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3318 QUERY_STRING(msg, info21.comment, "comment");
3319 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3320 QUERY_RID (msg, info21.rid, "objectSid");
3321 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3322 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3323 info->info21.fields_present = 0x00FFFFFF;
3324 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3325 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3326 QUERY_UINT (msg, info21.logon_count, "logonCount");
3327 QUERY_UINT (msg, info21.country_code, "countryCode");
3328 QUERY_UINT (msg, info21.code_page, "codePage");
3329 break;
3332 default:
3333 talloc_free(info);
3334 return NT_STATUS_INVALID_INFO_CLASS;
3337 *r->out.info = info;
3339 return NT_STATUS_OK;
3344 samr_SetUserInfo
3346 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3347 struct samr_SetUserInfo *r)
3349 struct dcesrv_handle *h;
3350 struct samr_account_state *a_state;
3351 struct ldb_message *msg;
3352 int ret;
3353 NTSTATUS status = NT_STATUS_OK;
3354 struct ldb_context *sam_ctx;
3356 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3358 a_state = h->data;
3359 sam_ctx = a_state->sam_ctx;
3361 msg = ldb_msg_new(mem_ctx);
3362 if (msg == NULL) {
3363 return NT_STATUS_NO_MEMORY;
3366 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3367 if (!msg->dn) {
3368 return NT_STATUS_NO_MEMORY;
3371 switch (r->in.level) {
3372 case 2:
3373 SET_STRING(msg, info2.comment, "comment");
3374 SET_UINT (msg, info2.country_code, "countryCode");
3375 SET_UINT (msg, info2.code_page, "codePage");
3376 break;
3378 case 4:
3379 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3380 break;
3382 case 6:
3383 SET_STRING(msg, info6.account_name, "samAccountName");
3384 SET_STRING(msg, info6.full_name, "displayName");
3385 break;
3387 case 7:
3388 SET_STRING(msg, info7.account_name, "samAccountName");
3389 break;
3391 case 8:
3392 SET_STRING(msg, info8.full_name, "displayName");
3393 break;
3395 case 9:
3396 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3397 break;
3399 case 10:
3400 SET_STRING(msg, info10.home_directory, "homeDirectory");
3401 SET_STRING(msg, info10.home_drive, "homeDrive");
3402 break;
3404 case 11:
3405 SET_STRING(msg, info11.logon_script, "scriptPath");
3406 break;
3408 case 12:
3409 SET_STRING(msg, info12.profile_path, "profilePath");
3410 break;
3412 case 13:
3413 SET_STRING(msg, info13.description, "description");
3414 break;
3416 case 14:
3417 SET_STRING(msg, info14.workstations, "userWorkstations");
3418 break;
3420 case 16:
3421 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3422 break;
3424 case 17:
3425 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3426 break;
3428 case 20:
3429 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3430 break;
3432 case 21:
3433 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3434 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3435 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3436 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3437 SET_STRING(msg, info21.account_name, "samAccountName");
3438 IFSET(SAMR_FIELD_FULL_NAME)
3439 SET_STRING(msg, info21.full_name, "displayName");
3440 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3441 SET_STRING(msg, info21.home_directory, "homeDirectory");
3442 IFSET(SAMR_FIELD_HOME_DRIVE)
3443 SET_STRING(msg, info21.home_drive, "homeDrive");
3444 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3445 SET_STRING(msg, info21.logon_script, "scriptPath");
3446 IFSET(SAMR_FIELD_PROFILE_PATH)
3447 SET_STRING(msg, info21.profile_path, "profilePath");
3448 IFSET(SAMR_FIELD_DESCRIPTION)
3449 SET_STRING(msg, info21.description, "description");
3450 IFSET(SAMR_FIELD_WORKSTATIONS)
3451 SET_STRING(msg, info21.workstations, "userWorkstations");
3452 IFSET(SAMR_FIELD_COMMENT)
3453 SET_STRING(msg, info21.comment, "comment");
3454 IFSET(SAMR_FIELD_PARAMETERS)
3455 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3456 IFSET(SAMR_FIELD_PRIMARY_GID)
3457 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3458 IFSET(SAMR_FIELD_ACCT_FLAGS)
3459 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3460 IFSET(SAMR_FIELD_LOGON_HOURS)
3461 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3462 IFSET(SAMR_FIELD_COUNTRY_CODE)
3463 SET_UINT (msg, info21.country_code, "countryCode");
3464 IFSET(SAMR_FIELD_CODE_PAGE)
3465 SET_UINT (msg, info21.code_page, "codePage");
3466 #undef IFSET
3467 break;
3469 case 23:
3470 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3471 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3472 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3473 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3474 SET_STRING(msg, info23.info.account_name, "samAccountName");
3475 IFSET(SAMR_FIELD_FULL_NAME)
3476 SET_STRING(msg, info23.info.full_name, "displayName");
3477 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3478 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3479 IFSET(SAMR_FIELD_HOME_DRIVE)
3480 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3481 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3482 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3483 IFSET(SAMR_FIELD_PROFILE_PATH)
3484 SET_STRING(msg, info23.info.profile_path, "profilePath");
3485 IFSET(SAMR_FIELD_DESCRIPTION)
3486 SET_STRING(msg, info23.info.description, "description");
3487 IFSET(SAMR_FIELD_WORKSTATIONS)
3488 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3489 IFSET(SAMR_FIELD_COMMENT)
3490 SET_STRING(msg, info23.info.comment, "comment");
3491 IFSET(SAMR_FIELD_PARAMETERS)
3492 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3493 IFSET(SAMR_FIELD_PRIMARY_GID)
3494 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3495 IFSET(SAMR_FIELD_ACCT_FLAGS)
3496 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3497 IFSET(SAMR_FIELD_LOGON_HOURS)
3498 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3499 IFSET(SAMR_FIELD_COUNTRY_CODE)
3500 SET_UINT (msg, info23.info.country_code, "countryCode");
3501 IFSET(SAMR_FIELD_CODE_PAGE)
3502 SET_UINT (msg, info23.info.code_page, "codePage");
3504 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3505 status = samr_set_password(dce_call,
3506 a_state->sam_ctx,
3507 a_state->account_dn,
3508 a_state->domain_state->domain_dn,
3509 mem_ctx, msg,
3510 &r->in.info->info23.password);
3511 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3512 status = samr_set_password(dce_call,
3513 a_state->sam_ctx,
3514 a_state->account_dn,
3515 a_state->domain_state->domain_dn,
3516 mem_ctx, msg,
3517 &r->in.info->info23.password);
3519 #undef IFSET
3520 break;
3522 /* the set password levels are handled separately */
3523 case 24:
3524 status = samr_set_password(dce_call,
3525 a_state->sam_ctx,
3526 a_state->account_dn,
3527 a_state->domain_state->domain_dn,
3528 mem_ctx, msg,
3529 &r->in.info->info24.password);
3530 break;
3532 case 25:
3533 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3534 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3535 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3536 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3537 SET_STRING(msg, info25.info.account_name, "samAccountName");
3538 IFSET(SAMR_FIELD_FULL_NAME)
3539 SET_STRING(msg, info25.info.full_name, "displayName");
3540 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3541 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3542 IFSET(SAMR_FIELD_HOME_DRIVE)
3543 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3544 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3545 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3546 IFSET(SAMR_FIELD_PROFILE_PATH)
3547 SET_STRING(msg, info25.info.profile_path, "profilePath");
3548 IFSET(SAMR_FIELD_DESCRIPTION)
3549 SET_STRING(msg, info25.info.description, "description");
3550 IFSET(SAMR_FIELD_WORKSTATIONS)
3551 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3552 IFSET(SAMR_FIELD_COMMENT)
3553 SET_STRING(msg, info25.info.comment, "comment");
3554 IFSET(SAMR_FIELD_PARAMETERS)
3555 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3556 IFSET(SAMR_FIELD_PRIMARY_GID)
3557 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3558 IFSET(SAMR_FIELD_ACCT_FLAGS)
3559 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3560 IFSET(SAMR_FIELD_LOGON_HOURS)
3561 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3562 IFSET(SAMR_FIELD_COUNTRY_CODE)
3563 SET_UINT (msg, info25.info.country_code, "countryCode");
3564 IFSET(SAMR_FIELD_CODE_PAGE)
3565 SET_UINT (msg, info25.info.code_page, "codePage");
3567 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3568 status = samr_set_password_ex(dce_call,
3569 a_state->sam_ctx,
3570 a_state->account_dn,
3571 a_state->domain_state->domain_dn,
3572 mem_ctx, msg,
3573 &r->in.info->info25.password);
3574 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3575 status = samr_set_password_ex(dce_call,
3576 a_state->sam_ctx,
3577 a_state->account_dn,
3578 a_state->domain_state->domain_dn,
3579 mem_ctx, msg,
3580 &r->in.info->info25.password);
3582 #undef IFSET
3583 break;
3585 /* the set password levels are handled separately */
3586 case 26:
3587 status = samr_set_password_ex(dce_call,
3588 a_state->sam_ctx,
3589 a_state->account_dn,
3590 a_state->domain_state->domain_dn,
3591 mem_ctx, msg,
3592 &r->in.info->info26.password);
3593 break;
3596 default:
3597 /* many info classes are not valid for SetUserInfo */
3598 return NT_STATUS_INVALID_INFO_CLASS;
3601 if (!NT_STATUS_IS_OK(status)) {
3602 return status;
3605 /* modify the samdb record */
3606 ret = ldb_modify(a_state->sam_ctx, msg);
3607 if (ret != 0) {
3608 DEBUG(1,("Failed to modify record %s: %s\n",
3609 ldb_dn_get_linearized(a_state->account_dn),
3610 ldb_errstring(a_state->sam_ctx)));
3612 /* we really need samdb.c to return NTSTATUS */
3613 return NT_STATUS_UNSUCCESSFUL;
3616 return NT_STATUS_OK;
3621 samr_GetGroupsForUser
3623 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3624 struct samr_GetGroupsForUser *r)
3626 struct dcesrv_handle *h;
3627 struct samr_account_state *a_state;
3628 struct samr_domain_state *d_state;
3629 struct ldb_message **res;
3630 const char * const attrs[2] = { "objectSid", NULL };
3631 struct samr_RidWithAttributeArray *array;
3632 int i, count;
3634 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3636 a_state = h->data;
3637 d_state = a_state->domain_state;
3639 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3640 d_state->domain_dn, &res,
3641 attrs, d_state->domain_sid,
3642 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3643 ldb_dn_get_linearized(a_state->account_dn),
3644 GTYPE_SECURITY_GLOBAL_GROUP);
3645 if (count < 0)
3646 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3648 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3649 if (array == NULL)
3650 return NT_STATUS_NO_MEMORY;
3652 array->count = 0;
3653 array->rids = NULL;
3655 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3656 count + 1);
3657 if (array->rids == NULL)
3658 return NT_STATUS_NO_MEMORY;
3660 /* Adds the primary group */
3661 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3662 ~0, a_state->account_dn,
3663 "primaryGroupID", NULL);
3664 array->rids[0].attributes = SE_GROUP_MANDATORY
3665 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3666 array->count += 1;
3668 /* Adds the additional groups */
3669 for (i = 0; i < count; i++) {
3670 struct dom_sid *group_sid;
3672 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3673 if (group_sid == NULL) {
3674 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3675 continue;
3678 array->rids[i + 1].rid =
3679 group_sid->sub_auths[group_sid->num_auths-1];
3680 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3681 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3682 array->count += 1;
3685 *r->out.rids = array;
3687 return NT_STATUS_OK;
3692 samr_QueryDisplayInfo
3694 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3695 struct samr_QueryDisplayInfo *r)
3697 struct dcesrv_handle *h;
3698 struct samr_domain_state *d_state;
3699 struct ldb_message **res;
3700 int ldb_cnt, count, i;
3701 const char * const attrs[] = { "objectSid", "sAMAccountName",
3702 "displayName", "description", "userAccountControl",
3703 "pwdLastSet", NULL };
3704 struct samr_DispEntryFull *entriesFull = NULL;
3705 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3706 struct samr_DispEntryAscii *entriesAscii = NULL;
3707 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3708 const char *filter;
3710 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3712 d_state = h->data;
3714 switch (r->in.level) {
3715 case 1:
3716 case 4:
3717 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3718 "(sAMAccountType=%u))",
3719 ATYPE_NORMAL_ACCOUNT);
3720 break;
3721 case 2:
3722 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3723 "(sAMAccountType=%u))",
3724 ATYPE_WORKSTATION_TRUST);
3725 break;
3726 case 3:
3727 case 5:
3728 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3729 "(objectclass=group))",
3730 GTYPE_SECURITY_GLOBAL_GROUP);
3731 break;
3732 default:
3733 return NT_STATUS_INVALID_INFO_CLASS;
3736 /* search for all requested objects in this domain. This could
3737 possibly be cached and resumed based on resume_key */
3738 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3739 d_state->domain_dn, &res, attrs,
3740 d_state->domain_sid, "%s", filter);
3741 if (ldb_cnt == -1) {
3742 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3744 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3745 return NT_STATUS_OK;
3748 switch (r->in.level) {
3749 case 1:
3750 entriesGeneral = talloc_array(mem_ctx,
3751 struct samr_DispEntryGeneral,
3752 ldb_cnt);
3753 break;
3754 case 2:
3755 entriesFull = talloc_array(mem_ctx,
3756 struct samr_DispEntryFull,
3757 ldb_cnt);
3758 break;
3759 case 3:
3760 entriesFullGroup = talloc_array(mem_ctx,
3761 struct samr_DispEntryFullGroup,
3762 ldb_cnt);
3763 break;
3764 case 4:
3765 case 5:
3766 entriesAscii = talloc_array(mem_ctx,
3767 struct samr_DispEntryAscii,
3768 ldb_cnt);
3769 break;
3772 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3773 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3774 return NT_STATUS_NO_MEMORY;
3776 count = 0;
3778 for (i=0; i<ldb_cnt; i++) {
3779 struct dom_sid *objectsid;
3781 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3782 "objectSid");
3783 if (objectsid == NULL)
3784 continue;
3786 switch(r->in.level) {
3787 case 1:
3788 entriesGeneral[count].idx = count + 1;
3789 entriesGeneral[count].rid =
3790 objectsid->sub_auths[objectsid->num_auths-1];
3791 entriesGeneral[count].acct_flags =
3792 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3793 res[i],
3794 d_state->domain_dn);
3795 entriesGeneral[count].account_name.string =
3796 samdb_result_string(res[i],
3797 "sAMAccountName", "");
3798 entriesGeneral[count].full_name.string =
3799 samdb_result_string(res[i], "displayName", "");
3800 entriesGeneral[count].description.string =
3801 samdb_result_string(res[i], "description", "");
3802 break;
3803 case 2:
3804 entriesFull[count].idx = count + 1;
3805 entriesFull[count].rid =
3806 objectsid->sub_auths[objectsid->num_auths-1];
3808 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3809 entriesFull[count].acct_flags =
3810 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3811 res[i],
3812 d_state->domain_dn) | ACB_NORMAL;
3813 entriesFull[count].account_name.string =
3814 samdb_result_string(res[i], "sAMAccountName",
3815 "");
3816 entriesFull[count].description.string =
3817 samdb_result_string(res[i], "description", "");
3818 break;
3819 case 3:
3820 entriesFullGroup[count].idx = count + 1;
3821 entriesFullGroup[count].rid =
3822 objectsid->sub_auths[objectsid->num_auths-1];
3823 /* We get a "7" here for groups */
3824 entriesFullGroup[count].acct_flags
3825 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3826 entriesFullGroup[count].account_name.string =
3827 samdb_result_string(res[i], "sAMAccountName",
3828 "");
3829 entriesFullGroup[count].description.string =
3830 samdb_result_string(res[i], "description", "");
3831 break;
3832 case 4:
3833 case 5:
3834 entriesAscii[count].idx = count + 1;
3835 entriesAscii[count].account_name.string =
3836 samdb_result_string(res[i], "sAMAccountName",
3837 "");
3838 break;
3841 count += 1;
3844 *r->out.total_size = count;
3846 if (r->in.start_idx >= count) {
3847 *r->out.returned_size = 0;
3848 switch(r->in.level) {
3849 case 1:
3850 r->out.info->info1.count = *r->out.returned_size;
3851 r->out.info->info1.entries = NULL;
3852 break;
3853 case 2:
3854 r->out.info->info2.count = *r->out.returned_size;
3855 r->out.info->info2.entries = NULL;
3856 break;
3857 case 3:
3858 r->out.info->info3.count = *r->out.returned_size;
3859 r->out.info->info3.entries = NULL;
3860 break;
3861 case 4:
3862 r->out.info->info4.count = *r->out.returned_size;
3863 r->out.info->info4.entries = NULL;
3864 break;
3865 case 5:
3866 r->out.info->info5.count = *r->out.returned_size;
3867 r->out.info->info5.entries = NULL;
3868 break;
3870 } else {
3871 *r->out.returned_size = MIN(count - r->in.start_idx,
3872 r->in.max_entries);
3873 switch(r->in.level) {
3874 case 1:
3875 r->out.info->info1.count = *r->out.returned_size;
3876 r->out.info->info1.entries =
3877 &(entriesGeneral[r->in.start_idx]);
3878 break;
3879 case 2:
3880 r->out.info->info2.count = *r->out.returned_size;
3881 r->out.info->info2.entries =
3882 &(entriesFull[r->in.start_idx]);
3883 break;
3884 case 3:
3885 r->out.info->info3.count = *r->out.returned_size;
3886 r->out.info->info3.entries =
3887 &(entriesFullGroup[r->in.start_idx]);
3888 break;
3889 case 4:
3890 r->out.info->info4.count = *r->out.returned_size;
3891 r->out.info->info4.entries =
3892 &(entriesAscii[r->in.start_idx]);
3893 break;
3894 case 5:
3895 r->out.info->info5.count = *r->out.returned_size;
3896 r->out.info->info5.entries =
3897 &(entriesAscii[r->in.start_idx]);
3898 break;
3902 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3903 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3908 samr_GetDisplayEnumerationIndex
3910 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3911 struct samr_GetDisplayEnumerationIndex *r)
3913 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3918 samr_TestPrivateFunctionsDomain
3920 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3921 struct samr_TestPrivateFunctionsDomain *r)
3923 return NT_STATUS_NOT_IMPLEMENTED;
3928 samr_TestPrivateFunctionsUser
3930 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3931 struct samr_TestPrivateFunctionsUser *r)
3933 return NT_STATUS_NOT_IMPLEMENTED;
3938 samr_GetUserPwInfo
3940 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3941 struct samr_GetUserPwInfo *r)
3943 struct dcesrv_handle *h;
3944 struct samr_account_state *a_state;
3946 ZERO_STRUCTP(r->out.info);
3948 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3950 a_state = h->data;
3952 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3953 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3954 NULL);
3955 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3956 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3958 return NT_STATUS_OK;
3963 samr_RemoveMemberFromForeignDomain
3965 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3966 struct samr_RemoveMemberFromForeignDomain *r)
3968 struct dcesrv_handle *h;
3969 struct samr_domain_state *d_state;
3970 const char *memberdn;
3971 struct ldb_message **res;
3972 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3973 int i, count;
3975 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3977 d_state = h->data;
3979 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3980 "distinguishedName", "(objectSid=%s)",
3981 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3982 /* Nothing to do */
3983 if (memberdn == NULL) {
3984 return NT_STATUS_OK;
3987 /* TODO: Does this call only remove alias members, or does it do this
3988 * for domain groups as well? */
3990 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3991 d_state->domain_dn, &res, attrs,
3992 d_state->domain_sid,
3993 "(&(member=%s)(objectClass=group)"
3994 "(|(groupType=%d)(groupType=%d)))",
3995 memberdn,
3996 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3997 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3999 if (count < 0)
4000 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4002 for (i=0; i<count; i++) {
4003 struct ldb_message *mod;
4005 mod = ldb_msg_new(mem_ctx);
4006 if (mod == NULL) {
4007 return NT_STATUS_NO_MEMORY;
4010 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4011 if (mod->dn == NULL) {
4012 talloc_free(mod);
4013 continue;
4016 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4017 "member", memberdn) != 0)
4018 return NT_STATUS_NO_MEMORY;
4020 if (ldb_modify(d_state->sam_ctx, mod) != 0)
4021 return NT_STATUS_UNSUCCESSFUL;
4023 talloc_free(mod);
4026 return NT_STATUS_OK;
4031 samr_QueryDomainInfo2
4033 just an alias for samr_QueryDomainInfo
4035 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4036 struct samr_QueryDomainInfo2 *r)
4038 struct samr_QueryDomainInfo r1;
4039 NTSTATUS status;
4041 ZERO_STRUCT(r1.out);
4042 r1.in.domain_handle = r->in.domain_handle;
4043 r1.in.level = r->in.level;
4044 r1.out.info = r->out.info;
4046 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4048 return status;
4053 samr_QueryUserInfo2
4055 just an alias for samr_QueryUserInfo
4057 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4058 struct samr_QueryUserInfo2 *r)
4060 struct samr_QueryUserInfo r1;
4061 NTSTATUS status;
4063 r1.in.user_handle = r->in.user_handle;
4064 r1.in.level = r->in.level;
4065 r1.out.info = r->out.info;
4067 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4069 return status;
4074 samr_QueryDisplayInfo2
4076 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4077 struct samr_QueryDisplayInfo2 *r)
4079 struct samr_QueryDisplayInfo q;
4080 NTSTATUS result;
4082 q.in.domain_handle = r->in.domain_handle;
4083 q.in.level = r->in.level;
4084 q.in.start_idx = r->in.start_idx;
4085 q.in.max_entries = r->in.max_entries;
4086 q.in.buf_size = r->in.buf_size;
4087 q.out.total_size = r->out.total_size;
4088 q.out.returned_size = r->out.returned_size;
4089 q.out.info = r->out.info;
4091 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4093 return result;
4098 samr_GetDisplayEnumerationIndex2
4100 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4101 struct samr_GetDisplayEnumerationIndex2 *r)
4103 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4108 samr_QueryDisplayInfo3
4110 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4111 struct samr_QueryDisplayInfo3 *r)
4113 struct samr_QueryDisplayInfo q;
4114 NTSTATUS result;
4116 q.in.domain_handle = r->in.domain_handle;
4117 q.in.level = r->in.level;
4118 q.in.start_idx = r->in.start_idx;
4119 q.in.max_entries = r->in.max_entries;
4120 q.in.buf_size = r->in.buf_size;
4121 q.out.total_size = r->out.total_size;
4122 q.out.returned_size = r->out.returned_size;
4123 q.out.info = r->out.info;
4125 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4127 return result;
4132 samr_AddMultipleMembersToAlias
4134 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4135 struct samr_AddMultipleMembersToAlias *r)
4137 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4142 samr_RemoveMultipleMembersFromAlias
4144 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4145 struct samr_RemoveMultipleMembersFromAlias *r)
4147 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4152 samr_GetDomPwInfo
4154 this fetches the default password properties for a domain
4156 note that w2k3 completely ignores the domain name in this call, and
4157 always returns the information for the servers primary domain
4159 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4160 struct samr_GetDomPwInfo *r)
4162 struct ldb_message **msgs;
4163 int ret;
4164 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4165 struct ldb_context *sam_ctx;
4167 ZERO_STRUCTP(r->out.info);
4169 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
4170 if (sam_ctx == NULL) {
4171 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4174 /* The domain name in this call is ignored */
4175 ret = gendb_search_dn(sam_ctx,
4176 mem_ctx, NULL, &msgs, attrs);
4177 if (ret <= 0) {
4178 return NT_STATUS_NO_SUCH_DOMAIN;
4180 if (ret > 1) {
4181 talloc_free(msgs);
4182 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4185 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4186 "minPwdLength", 0);
4187 r->out.info->password_properties = samdb_result_uint(msgs[0],
4188 "pwdProperties", 1);
4190 talloc_free(msgs);
4192 talloc_free(sam_ctx);
4193 return NT_STATUS_OK;
4198 samr_Connect2
4200 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4201 struct samr_Connect2 *r)
4203 struct samr_Connect c;
4205 c.in.system_name = NULL;
4206 c.in.access_mask = r->in.access_mask;
4207 c.out.connect_handle = r->out.connect_handle;
4209 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4214 samr_SetUserInfo2
4216 just an alias for samr_SetUserInfo
4218 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4219 struct samr_SetUserInfo2 *r)
4221 struct samr_SetUserInfo r2;
4223 r2.in.user_handle = r->in.user_handle;
4224 r2.in.level = r->in.level;
4225 r2.in.info = r->in.info;
4227 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4232 samr_SetBootKeyInformation
4234 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4235 struct samr_SetBootKeyInformation *r)
4237 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4242 samr_GetBootKeyInformation
4244 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4245 struct samr_GetBootKeyInformation *r)
4247 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4252 samr_Connect3
4254 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4255 struct samr_Connect3 *r)
4257 struct samr_Connect c;
4259 c.in.system_name = NULL;
4260 c.in.access_mask = r->in.access_mask;
4261 c.out.connect_handle = r->out.connect_handle;
4263 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4268 samr_Connect4
4270 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4271 struct samr_Connect4 *r)
4273 struct samr_Connect c;
4275 c.in.system_name = NULL;
4276 c.in.access_mask = r->in.access_mask;
4277 c.out.connect_handle = r->out.connect_handle;
4279 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4284 samr_Connect5
4286 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4287 struct samr_Connect5 *r)
4289 struct samr_Connect c;
4290 NTSTATUS status;
4292 c.in.system_name = NULL;
4293 c.in.access_mask = r->in.access_mask;
4294 c.out.connect_handle = r->out.connect_handle;
4296 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4298 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4299 r->out.info_out->info1.unknown2 = 0;
4300 *r->out.level_out = r->in.level_in;
4302 return status;
4307 samr_RidToSid
4309 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4310 struct samr_RidToSid *r)
4312 struct samr_domain_state *d_state;
4313 struct dcesrv_handle *h;
4315 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4317 d_state = h->data;
4319 /* form the users SID */
4320 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4321 if (!*r->out.sid) {
4322 return NT_STATUS_NO_MEMORY;
4325 return NT_STATUS_OK;
4330 samr_SetDsrmPassword
4332 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4333 struct samr_SetDsrmPassword *r)
4335 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4340 samr_ValidatePassword
4342 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4343 struct samr_ValidatePassword *r)
4345 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4349 /* include the generated boilerplate */
4350 #include "librpc/gen_ndr/ndr_samr_s.c"