s4:dcesrv_samr - prevent "ldb_modify" on a possibly empty message
[Samba/ekacnet.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob00820a3ab26b1728fecde300bc8bce67a4a95d64
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 != LDB_SUCCESS) {
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 != LDB_SUCCESS) {
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 != LDB_SUCCESS) {
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 != LDB_SUCCESS) {
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 != LDB_SUCCESS) {
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;
2231 /* In native mode, AD can also nest domain groups. Not sure yet
2232 * whether this is also available via RPC. */
2233 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2234 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2235 "(&(objectSid=%s)(objectclass=user))",
2236 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2238 if (ret != LDB_SUCCESS) {
2239 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2242 if (res->count == 0) {
2243 return NT_STATUS_NO_SUCH_USER;
2246 if (res->count > 1) {
2247 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2250 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2252 if (memberdn == NULL)
2253 return NT_STATUS_NO_MEMORY;
2255 mod = ldb_msg_new(mem_ctx);
2256 if (mod == NULL) {
2257 return NT_STATUS_NO_MEMORY;
2260 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2262 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2263 memberdn);
2264 if (ret != LDB_SUCCESS) {
2265 return NT_STATUS_UNSUCCESSFUL;
2268 ret = ldb_modify(a_state->sam_ctx, mod);
2269 switch (ret) {
2270 case LDB_SUCCESS:
2271 return NT_STATUS_OK;
2272 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2273 return NT_STATUS_MEMBER_IN_GROUP;
2274 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2275 return NT_STATUS_ACCESS_DENIED;
2276 default:
2277 return NT_STATUS_UNSUCCESSFUL;
2283 samr_DeleteDomainGroup
2285 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2286 struct samr_DeleteDomainGroup *r)
2288 struct dcesrv_handle *h;
2289 struct samr_account_state *a_state;
2290 int ret;
2292 *r->out.group_handle = *r->in.group_handle;
2294 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2296 a_state = h->data;
2298 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2299 if (ret != LDB_SUCCESS) {
2300 return NT_STATUS_UNSUCCESSFUL;
2303 ZERO_STRUCTP(r->out.group_handle);
2305 return NT_STATUS_OK;
2310 samr_DeleteGroupMember
2312 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2313 struct samr_DeleteGroupMember *r)
2315 struct dcesrv_handle *h;
2316 struct samr_account_state *a_state;
2317 struct samr_domain_state *d_state;
2318 struct ldb_message *mod;
2319 struct dom_sid *membersid;
2320 const char *memberdn;
2321 struct ldb_result *res;
2322 const char * const attrs[] = { NULL };
2323 int ret;
2325 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2327 a_state = h->data;
2328 d_state = a_state->domain_state;
2330 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2331 if (membersid == NULL)
2332 return NT_STATUS_NO_MEMORY;
2334 /* In native mode, AD can also nest domain groups. Not sure yet
2335 * whether this is also available via RPC. */
2336 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2337 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2338 "(&(objectSid=%s)(objectclass=user))",
2339 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2341 if (ret != LDB_SUCCESS) {
2342 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2345 if (res->count == 0) {
2346 return NT_STATUS_NO_SUCH_USER;
2349 if (res->count > 1) {
2350 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2353 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2355 if (memberdn == NULL)
2356 return NT_STATUS_NO_MEMORY;
2358 mod = ldb_msg_new(mem_ctx);
2359 if (mod == NULL) {
2360 return NT_STATUS_NO_MEMORY;
2363 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2365 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2366 memberdn);
2367 if (ret != LDB_SUCCESS) {
2368 return NT_STATUS_NO_MEMORY;
2371 ret = ldb_modify(a_state->sam_ctx, mod);
2372 switch (ret) {
2373 case LDB_SUCCESS:
2374 return NT_STATUS_OK;
2375 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2376 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2377 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2378 return NT_STATUS_ACCESS_DENIED;
2379 default:
2380 return NT_STATUS_UNSUCCESSFUL;
2386 samr_QueryGroupMember
2388 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2389 struct samr_QueryGroupMember *r)
2391 struct dcesrv_handle *h;
2392 struct samr_account_state *a_state;
2393 struct ldb_message **res;
2394 struct ldb_message_element *el;
2395 struct samr_RidTypeArray *array;
2396 const char * const attrs[2] = { "member", NULL };
2397 int ret;
2399 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2401 a_state = h->data;
2403 /* pull the member attribute */
2404 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2405 a_state->account_dn, &res, attrs);
2407 if (ret != 1) {
2408 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2411 array = talloc(mem_ctx, struct samr_RidTypeArray);
2413 if (array == NULL)
2414 return NT_STATUS_NO_MEMORY;
2416 ZERO_STRUCTP(array);
2418 el = ldb_msg_find_element(res[0], "member");
2420 if (el != NULL) {
2421 int i;
2423 array->count = el->num_values;
2425 array->rids = talloc_array(mem_ctx, uint32_t,
2426 el->num_values);
2427 if (array->rids == NULL)
2428 return NT_STATUS_NO_MEMORY;
2430 array->types = talloc_array(mem_ctx, uint32_t,
2431 el->num_values);
2432 if (array->types == NULL)
2433 return NT_STATUS_NO_MEMORY;
2435 for (i=0; i<el->num_values; i++) {
2436 struct ldb_message **res2;
2437 const char * const attrs2[2] = { "objectSid", NULL };
2438 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2439 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2440 &res2, attrs2);
2441 if (ret != 1)
2442 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2444 array->rids[i] =
2445 samdb_result_rid_from_sid(mem_ctx, res2[0],
2446 "objectSid", 0);
2448 if (array->rids[i] == 0)
2449 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2451 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2455 *r->out.rids = array;
2457 return NT_STATUS_OK;
2462 samr_SetMemberAttributesOfGroup
2464 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2465 struct samr_SetMemberAttributesOfGroup *r)
2467 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2472 samr_OpenAlias
2474 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2475 struct samr_OpenAlias *r)
2477 struct samr_domain_state *d_state;
2478 struct samr_account_state *a_state;
2479 struct dcesrv_handle *h;
2480 const char *alias_name;
2481 struct dom_sid *sid;
2482 struct ldb_message **msgs;
2483 struct dcesrv_handle *g_handle;
2484 const char * const attrs[2] = { "sAMAccountName", NULL };
2485 int ret;
2487 ZERO_STRUCTP(r->out.alias_handle);
2489 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2491 d_state = h->data;
2493 /* form the alias SID */
2494 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2495 if (sid == NULL)
2496 return NT_STATUS_NO_MEMORY;
2498 /* search for the group record */
2499 ret = gendb_search(d_state->sam_ctx,
2500 mem_ctx, d_state->domain_dn, &msgs, attrs,
2501 "(&(objectSid=%s)(objectclass=group)"
2502 "(|(grouptype=%d)(grouptype=%d)))",
2503 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2504 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2505 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2506 if (ret == 0) {
2507 return NT_STATUS_NO_SUCH_ALIAS;
2509 if (ret != 1) {
2510 DEBUG(0,("Found %d records matching sid %s\n",
2511 ret, dom_sid_string(mem_ctx, sid)));
2512 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2515 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2516 if (alias_name == NULL) {
2517 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2518 dom_sid_string(mem_ctx, sid)));
2519 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2522 a_state = talloc(d_state, struct samr_account_state);
2523 if (!a_state) {
2524 return NT_STATUS_NO_MEMORY;
2526 a_state->sam_ctx = d_state->sam_ctx;
2527 a_state->access_mask = r->in.access_mask;
2528 a_state->domain_state = talloc_reference(a_state, d_state);
2529 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2530 a_state->account_sid = talloc_steal(a_state, sid);
2531 a_state->account_name = talloc_strdup(a_state, alias_name);
2532 if (!a_state->account_name) {
2533 return NT_STATUS_NO_MEMORY;
2536 /* create the policy handle */
2537 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2538 if (!g_handle) {
2539 return NT_STATUS_NO_MEMORY;
2542 g_handle->data = talloc_steal(g_handle, a_state);
2544 *r->out.alias_handle = g_handle->wire_handle;
2546 return NT_STATUS_OK;
2551 samr_QueryAliasInfo
2553 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2554 struct samr_QueryAliasInfo *r)
2556 struct dcesrv_handle *h;
2557 struct samr_account_state *a_state;
2558 struct ldb_message *msg, **res;
2559 const char * const attrs[4] = { "sAMAccountName", "description",
2560 "numMembers", NULL };
2561 int ret;
2562 union samr_AliasInfo *info;
2564 *r->out.info = NULL;
2566 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2568 a_state = h->data;
2570 /* pull all the alias attributes */
2571 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2572 a_state->account_dn ,&res, attrs);
2573 if (ret != 1) {
2574 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2576 msg = res[0];
2578 /* allocate the info structure */
2579 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2580 if (info == NULL) {
2581 return NT_STATUS_NO_MEMORY;
2584 switch(r->in.level) {
2585 case ALIASINFOALL:
2586 QUERY_STRING(msg, all.name, "sAMAccountName");
2587 QUERY_UINT (msg, all.num_members, "numMembers");
2588 QUERY_STRING(msg, all.description, "description");
2589 break;
2590 case ALIASINFONAME:
2591 QUERY_STRING(msg, name, "sAMAccountName");
2592 break;
2593 case ALIASINFODESCRIPTION:
2594 QUERY_STRING(msg, description, "description");
2595 break;
2596 default:
2597 talloc_free(info);
2598 return NT_STATUS_INVALID_INFO_CLASS;
2601 *r->out.info = info;
2603 return NT_STATUS_OK;
2608 samr_SetAliasInfo
2610 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2611 struct samr_SetAliasInfo *r)
2613 struct dcesrv_handle *h;
2614 struct samr_account_state *a_state;
2615 struct ldb_message *msg;
2616 struct ldb_context *sam_ctx;
2617 int ret;
2619 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2621 a_state = h->data;
2622 sam_ctx = a_state->sam_ctx;
2624 msg = ldb_msg_new(mem_ctx);
2625 if (msg == NULL) {
2626 return NT_STATUS_NO_MEMORY;
2629 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2630 if (!msg->dn) {
2631 return NT_STATUS_NO_MEMORY;
2634 switch (r->in.level) {
2635 case ALIASINFODESCRIPTION:
2636 SET_STRING(msg, description, "description");
2637 break;
2638 case ALIASINFONAME:
2639 /* On W2k3 this does not change the name, it changes the
2640 * sAMAccountName attribute */
2641 SET_STRING(msg, name, "sAMAccountName");
2642 break;
2643 default:
2644 return NT_STATUS_INVALID_INFO_CLASS;
2647 /* modify the samdb record */
2648 ret = ldb_modify(a_state->sam_ctx, msg);
2649 if (ret != 0) {
2650 /* we really need samdb.c to return NTSTATUS */
2651 return NT_STATUS_UNSUCCESSFUL;
2654 return NT_STATUS_OK;
2659 samr_DeleteDomAlias
2661 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2662 struct samr_DeleteDomAlias *r)
2664 struct dcesrv_handle *h;
2665 struct samr_account_state *a_state;
2666 int ret;
2668 *r->out.alias_handle = *r->in.alias_handle;
2670 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2672 a_state = h->data;
2674 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2675 if (ret != 0) {
2676 return NT_STATUS_UNSUCCESSFUL;
2679 ZERO_STRUCTP(r->out.alias_handle);
2681 return NT_STATUS_OK;
2686 samr_AddAliasMember
2688 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2689 struct samr_AddAliasMember *r)
2691 struct dcesrv_handle *h;
2692 struct samr_account_state *a_state;
2693 struct samr_domain_state *d_state;
2694 struct ldb_message *mod;
2695 struct ldb_message **msgs;
2696 const char * const attrs[] = { NULL };
2697 struct ldb_dn *memberdn = NULL;
2698 int ret;
2699 NTSTATUS status;
2701 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2703 a_state = h->data;
2704 d_state = a_state->domain_state;
2706 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2707 &msgs, attrs, "(objectsid=%s)",
2708 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2710 if (ret == 1) {
2711 memberdn = msgs[0]->dn;
2712 } else if (ret > 1) {
2713 DEBUG(0,("Found %d records matching sid %s\n",
2714 ret, dom_sid_string(mem_ctx, r->in.sid)));
2715 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2716 } else if (ret == 0) {
2717 status = samdb_create_foreign_security_principal(
2718 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2719 if (!NT_STATUS_IS_OK(status)) {
2720 return status;
2722 } else {
2723 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2726 if (memberdn == NULL) {
2727 DEBUG(0, ("Could not find memberdn\n"));
2728 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2731 mod = ldb_msg_new(mem_ctx);
2732 if (mod == NULL) {
2733 return NT_STATUS_NO_MEMORY;
2736 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2738 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2739 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2740 if (ret != LDB_SUCCESS) {
2741 return NT_STATUS_UNSUCCESSFUL;
2744 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2745 return NT_STATUS_UNSUCCESSFUL;
2748 return NT_STATUS_OK;
2753 samr_DeleteAliasMember
2755 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2756 struct samr_DeleteAliasMember *r)
2758 struct dcesrv_handle *h;
2759 struct samr_account_state *a_state;
2760 struct samr_domain_state *d_state;
2761 struct ldb_message *mod;
2762 const char *memberdn;
2763 int ret;
2765 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2767 a_state = h->data;
2768 d_state = a_state->domain_state;
2770 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2771 "distinguishedName", "(objectSid=%s)",
2772 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2774 if (memberdn == NULL)
2775 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2777 mod = ldb_msg_new(mem_ctx);
2778 if (mod == NULL) {
2779 return NT_STATUS_NO_MEMORY;
2782 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2784 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2785 memberdn);
2786 if (ret != LDB_SUCCESS)
2787 return NT_STATUS_UNSUCCESSFUL;
2789 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2790 return NT_STATUS_UNSUCCESSFUL;
2792 return NT_STATUS_OK;
2797 samr_GetMembersInAlias
2799 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2800 struct samr_GetMembersInAlias *r)
2802 struct dcesrv_handle *h;
2803 struct samr_account_state *a_state;
2804 struct samr_domain_state *d_state;
2805 struct ldb_message **msgs;
2806 struct lsa_SidPtr *sids;
2807 struct ldb_message_element *el;
2808 const char * const attrs[2] = { "member", NULL};
2809 int ret;
2811 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2813 a_state = h->data;
2814 d_state = a_state->domain_state;
2816 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2817 a_state->account_dn, &msgs, attrs);
2819 if (ret == -1) {
2820 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2821 } else if (ret == 0) {
2822 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2823 } else if (ret != 1) {
2824 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2827 r->out.sids->num_sids = 0;
2828 r->out.sids->sids = NULL;
2830 el = ldb_msg_find_element(msgs[0], "member");
2832 if (el != NULL) {
2833 int i;
2835 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2836 el->num_values);
2838 if (sids == NULL)
2839 return NT_STATUS_NO_MEMORY;
2841 for (i=0; i<el->num_values; i++) {
2842 struct ldb_message **msgs2;
2843 const char * const attrs2[2] = { "objectSid", NULL };
2844 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2845 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2846 &msgs2, attrs2);
2847 if (ret != 1)
2848 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2850 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2851 "objectSid");
2853 if (sids[i].sid == NULL)
2854 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2856 r->out.sids->num_sids = el->num_values;
2857 r->out.sids->sids = sids;
2860 return NT_STATUS_OK;
2864 samr_OpenUser
2866 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2867 struct samr_OpenUser *r)
2869 struct samr_domain_state *d_state;
2870 struct samr_account_state *a_state;
2871 struct dcesrv_handle *h;
2872 const char *account_name;
2873 struct dom_sid *sid;
2874 struct ldb_message **msgs;
2875 struct dcesrv_handle *u_handle;
2876 const char * const attrs[2] = { "sAMAccountName", NULL };
2877 int ret;
2879 ZERO_STRUCTP(r->out.user_handle);
2881 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2883 d_state = h->data;
2885 /* form the users SID */
2886 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2887 if (!sid) {
2888 return NT_STATUS_NO_MEMORY;
2891 /* search for the user record */
2892 ret = gendb_search(d_state->sam_ctx,
2893 mem_ctx, d_state->domain_dn, &msgs, attrs,
2894 "(&(objectSid=%s)(objectclass=user))",
2895 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2896 if (ret == 0) {
2897 return NT_STATUS_NO_SUCH_USER;
2899 if (ret != 1) {
2900 DEBUG(0,("Found %d records matching sid %s\n", ret,
2901 dom_sid_string(mem_ctx, sid)));
2902 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2905 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2906 if (account_name == NULL) {
2907 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2908 dom_sid_string(mem_ctx, sid)));
2909 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2912 a_state = talloc(mem_ctx, struct samr_account_state);
2913 if (!a_state) {
2914 return NT_STATUS_NO_MEMORY;
2916 a_state->sam_ctx = d_state->sam_ctx;
2917 a_state->access_mask = r->in.access_mask;
2918 a_state->domain_state = talloc_reference(a_state, d_state);
2919 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2920 a_state->account_sid = talloc_steal(a_state, sid);
2921 a_state->account_name = talloc_strdup(a_state, account_name);
2922 if (!a_state->account_name) {
2923 return NT_STATUS_NO_MEMORY;
2926 /* create the policy handle */
2927 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2928 if (!u_handle) {
2929 return NT_STATUS_NO_MEMORY;
2932 u_handle->data = talloc_steal(u_handle, a_state);
2934 *r->out.user_handle = u_handle->wire_handle;
2936 return NT_STATUS_OK;
2942 samr_DeleteUser
2944 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2945 struct samr_DeleteUser *r)
2947 struct dcesrv_handle *h;
2948 struct samr_account_state *a_state;
2949 int ret;
2951 *r->out.user_handle = *r->in.user_handle;
2953 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2955 a_state = h->data;
2957 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2958 if (ret != LDB_SUCCESS) {
2959 DEBUG(1, ("Failed to delete user: %s: %s\n",
2960 ldb_dn_get_linearized(a_state->account_dn),
2961 ldb_errstring(a_state->sam_ctx)));
2962 return NT_STATUS_UNSUCCESSFUL;
2965 ZERO_STRUCTP(r->out.user_handle);
2967 return NT_STATUS_OK;
2972 samr_QueryUserInfo
2974 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2975 struct samr_QueryUserInfo *r)
2977 struct dcesrv_handle *h;
2978 struct samr_account_state *a_state;
2979 struct ldb_message *msg, **res;
2980 int ret;
2981 struct ldb_context *sam_ctx;
2983 const char * const *attrs = NULL;
2984 union samr_UserInfo *info;
2986 *r->out.info = NULL;
2988 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2990 a_state = h->data;
2991 sam_ctx = a_state->sam_ctx;
2993 /* fill in the reply */
2994 switch (r->in.level) {
2995 case 1:
2997 static const char * const attrs2[] = {"sAMAccountName",
2998 "displayName",
2999 "primaryroupID",
3000 "description",
3001 "comment",
3002 NULL};
3003 attrs = attrs2;
3004 break;
3006 case 2:
3008 static const char * const attrs2[] = {"comment",
3009 "countryCode",
3010 "codePage",
3011 NULL};
3012 attrs = attrs2;
3013 break;
3015 case 3:
3017 static const char * const attrs2[] = {"sAMAccountName",
3018 "displayName",
3019 "objectSid",
3020 "primaryGroupID",
3021 "homeDirectory",
3022 "homeDrive",
3023 "scriptPath",
3024 "profilePath",
3025 "userWorkstations",
3026 "lastLogon",
3027 "lastLogoff",
3028 "pwdLastSet",
3029 "logonHours",
3030 "badPwdCount",
3031 "logonCount",
3032 "userAccountControl",
3033 NULL};
3034 attrs = attrs2;
3035 break;
3037 case 4:
3039 static const char * const attrs2[] = {"logonHours",
3040 NULL};
3041 attrs = attrs2;
3042 break;
3044 case 5:
3046 static const char * const attrs2[] = {"sAMAccountName",
3047 "displayName",
3048 "objectSid",
3049 "primaryGroupID",
3050 "homeDirectory",
3051 "homeDrive",
3052 "scriptPath",
3053 "profilePath",
3054 "description",
3055 "userWorkstations",
3056 "lastLogon",
3057 "lastLogoff",
3058 "logonHours",
3059 "badPwdCount",
3060 "logonCount",
3061 "pwdLastSet",
3062 "accountExpires",
3063 "userAccountControl",
3064 NULL};
3065 attrs = attrs2;
3066 break;
3068 case 6:
3070 static const char * const attrs2[] = {"sAMAccountName",
3071 "displayName",
3072 NULL};
3073 attrs = attrs2;
3074 break;
3076 case 7:
3078 static const char * const attrs2[] = {"sAMAccountName",
3079 NULL};
3080 attrs = attrs2;
3081 break;
3083 case 8:
3085 static const char * const attrs2[] = {"displayName",
3086 NULL};
3087 attrs = attrs2;
3088 break;
3090 case 9:
3092 static const char * const attrs2[] = {"primaryGroupID",
3093 NULL};
3094 attrs = attrs2;
3095 break;
3097 case 10:
3099 static const char * const attrs2[] = {"homeDirectory",
3100 "homeDrive",
3101 NULL};
3102 attrs = attrs2;
3103 break;
3105 case 11:
3107 static const char * const attrs2[] = {"scriptPath",
3108 NULL};
3109 attrs = attrs2;
3110 break;
3112 case 12:
3114 static const char * const attrs2[] = {"profilePath",
3115 NULL};
3116 attrs = attrs2;
3117 break;
3119 case 13:
3121 static const char * const attrs2[] = {"description",
3122 NULL};
3123 attrs = attrs2;
3124 break;
3126 case 14:
3128 static const char * const attrs2[] = {"userWorkstations",
3129 NULL};
3130 attrs = attrs2;
3131 break;
3133 case 16:
3135 static const char * const attrs2[] = {"userAccountControl",
3136 "pwdLastSet",
3137 NULL};
3138 attrs = attrs2;
3139 break;
3141 case 17:
3143 static const char * const attrs2[] = {"accountExpires",
3144 NULL};
3145 attrs = attrs2;
3146 break;
3148 case 20:
3150 static const char * const attrs2[] = {"userParameters",
3151 NULL};
3152 attrs = attrs2;
3153 break;
3155 case 21:
3157 static const char * const attrs2[] = {"lastLogon",
3158 "lastLogoff",
3159 "pwdLastSet",
3160 "accountExpires",
3161 "sAMAccountName",
3162 "displayName",
3163 "homeDirectory",
3164 "homeDrive",
3165 "scriptPath",
3166 "profilePath",
3167 "description",
3168 "userWorkstations",
3169 "comment",
3170 "userParameters",
3171 "objectSid",
3172 "primaryGroupID",
3173 "userAccountControl",
3174 "logonHours",
3175 "badPwdCount",
3176 "logonCount",
3177 "countryCode",
3178 "codePage",
3179 NULL};
3180 attrs = attrs2;
3181 break;
3185 /* pull all the user attributes */
3186 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3187 a_state->account_dn ,&res, attrs);
3188 if (ret != 1) {
3189 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3191 msg = res[0];
3193 /* allocate the info structure */
3194 info = talloc_zero(mem_ctx, union samr_UserInfo);
3195 if (info == NULL) {
3196 return NT_STATUS_NO_MEMORY;
3199 /* fill in the reply */
3200 switch (r->in.level) {
3201 case 1:
3202 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3203 QUERY_STRING(msg, info1.full_name, "displayName");
3204 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3205 QUERY_STRING(msg, info1.description, "description");
3206 QUERY_STRING(msg, info1.comment, "comment");
3207 break;
3209 case 2:
3210 QUERY_STRING(msg, info2.comment, "comment");
3211 QUERY_UINT (msg, info2.country_code, "countryCode");
3212 QUERY_UINT (msg, info2.code_page, "codePage");
3213 break;
3215 case 3:
3216 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3217 QUERY_STRING(msg, info3.full_name, "displayName");
3218 QUERY_RID (msg, info3.rid, "objectSid");
3219 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3220 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3221 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3222 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3223 QUERY_STRING(msg, info3.profile_path, "profilePath");
3224 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3225 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3226 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3227 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3228 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3229 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3230 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3231 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3232 QUERY_UINT (msg, info3.logon_count, "logonCount");
3233 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3234 break;
3236 case 4:
3237 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3238 break;
3240 case 5:
3241 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3242 QUERY_STRING(msg, info5.full_name, "displayName");
3243 QUERY_RID (msg, info5.rid, "objectSid");
3244 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3245 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3246 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3247 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3248 QUERY_STRING(msg, info5.profile_path, "profilePath");
3249 QUERY_STRING(msg, info5.description, "description");
3250 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3251 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3252 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3253 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3254 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3255 QUERY_UINT (msg, info5.logon_count, "logonCount");
3256 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3257 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3258 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3259 break;
3261 case 6:
3262 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3263 QUERY_STRING(msg, info6.full_name, "displayName");
3264 break;
3266 case 7:
3267 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3268 break;
3270 case 8:
3271 QUERY_STRING(msg, info8.full_name, "displayName");
3272 break;
3274 case 9:
3275 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3276 break;
3278 case 10:
3279 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3280 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3281 break;
3283 case 11:
3284 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3285 break;
3287 case 12:
3288 QUERY_STRING(msg, info12.profile_path, "profilePath");
3289 break;
3291 case 13:
3292 QUERY_STRING(msg, info13.description, "description");
3293 break;
3295 case 14:
3296 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3297 break;
3299 case 16:
3300 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3301 break;
3303 case 17:
3304 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3305 break;
3307 case 20:
3308 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3309 break;
3311 case 21:
3312 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3313 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3314 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3315 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3316 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3317 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3318 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3319 QUERY_STRING(msg, info21.full_name, "displayName");
3320 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3321 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3322 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3323 QUERY_STRING(msg, info21.profile_path, "profilePath");
3324 QUERY_STRING(msg, info21.description, "description");
3325 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3326 QUERY_STRING(msg, info21.comment, "comment");
3327 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3328 QUERY_RID (msg, info21.rid, "objectSid");
3329 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3330 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3331 info->info21.fields_present = 0x00FFFFFF;
3332 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3333 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3334 QUERY_UINT (msg, info21.logon_count, "logonCount");
3335 QUERY_UINT (msg, info21.country_code, "countryCode");
3336 QUERY_UINT (msg, info21.code_page, "codePage");
3337 break;
3340 default:
3341 talloc_free(info);
3342 return NT_STATUS_INVALID_INFO_CLASS;
3345 *r->out.info = info;
3347 return NT_STATUS_OK;
3352 samr_SetUserInfo
3354 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3355 struct samr_SetUserInfo *r)
3357 struct dcesrv_handle *h;
3358 struct samr_account_state *a_state;
3359 struct ldb_message *msg;
3360 int ret;
3361 NTSTATUS status = NT_STATUS_OK;
3362 struct ldb_context *sam_ctx;
3364 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3366 a_state = h->data;
3367 sam_ctx = a_state->sam_ctx;
3369 msg = ldb_msg_new(mem_ctx);
3370 if (msg == NULL) {
3371 return NT_STATUS_NO_MEMORY;
3374 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3375 if (!msg->dn) {
3376 return NT_STATUS_NO_MEMORY;
3379 switch (r->in.level) {
3380 case 2:
3381 SET_STRING(msg, info2.comment, "comment");
3382 SET_UINT (msg, info2.country_code, "countryCode");
3383 SET_UINT (msg, info2.code_page, "codePage");
3384 break;
3386 case 4:
3387 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3388 break;
3390 case 6:
3391 SET_STRING(msg, info6.account_name, "samAccountName");
3392 SET_STRING(msg, info6.full_name, "displayName");
3393 break;
3395 case 7:
3396 SET_STRING(msg, info7.account_name, "samAccountName");
3397 break;
3399 case 8:
3400 SET_STRING(msg, info8.full_name, "displayName");
3401 break;
3403 case 9:
3404 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3405 break;
3407 case 10:
3408 SET_STRING(msg, info10.home_directory, "homeDirectory");
3409 SET_STRING(msg, info10.home_drive, "homeDrive");
3410 break;
3412 case 11:
3413 SET_STRING(msg, info11.logon_script, "scriptPath");
3414 break;
3416 case 12:
3417 SET_STRING(msg, info12.profile_path, "profilePath");
3418 break;
3420 case 13:
3421 SET_STRING(msg, info13.description, "description");
3422 break;
3424 case 14:
3425 SET_STRING(msg, info14.workstations, "userWorkstations");
3426 break;
3428 case 16:
3429 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3430 break;
3432 case 17:
3433 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3434 break;
3436 case 20:
3437 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3438 break;
3440 case 21:
3441 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3442 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3443 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3444 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3445 SET_STRING(msg, info21.account_name, "samAccountName");
3446 IFSET(SAMR_FIELD_FULL_NAME)
3447 SET_STRING(msg, info21.full_name, "displayName");
3448 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3449 SET_STRING(msg, info21.home_directory, "homeDirectory");
3450 IFSET(SAMR_FIELD_HOME_DRIVE)
3451 SET_STRING(msg, info21.home_drive, "homeDrive");
3452 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3453 SET_STRING(msg, info21.logon_script, "scriptPath");
3454 IFSET(SAMR_FIELD_PROFILE_PATH)
3455 SET_STRING(msg, info21.profile_path, "profilePath");
3456 IFSET(SAMR_FIELD_DESCRIPTION)
3457 SET_STRING(msg, info21.description, "description");
3458 IFSET(SAMR_FIELD_WORKSTATIONS)
3459 SET_STRING(msg, info21.workstations, "userWorkstations");
3460 IFSET(SAMR_FIELD_COMMENT)
3461 SET_STRING(msg, info21.comment, "comment");
3462 IFSET(SAMR_FIELD_PARAMETERS)
3463 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3464 IFSET(SAMR_FIELD_PRIMARY_GID)
3465 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3466 IFSET(SAMR_FIELD_ACCT_FLAGS)
3467 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3468 IFSET(SAMR_FIELD_LOGON_HOURS)
3469 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3470 IFSET(SAMR_FIELD_COUNTRY_CODE)
3471 SET_UINT (msg, info21.country_code, "countryCode");
3472 IFSET(SAMR_FIELD_CODE_PAGE)
3473 SET_UINT (msg, info21.code_page, "codePage");
3474 #undef IFSET
3475 break;
3477 case 23:
3478 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3479 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3480 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3481 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3482 SET_STRING(msg, info23.info.account_name, "samAccountName");
3483 IFSET(SAMR_FIELD_FULL_NAME)
3484 SET_STRING(msg, info23.info.full_name, "displayName");
3485 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3486 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3487 IFSET(SAMR_FIELD_HOME_DRIVE)
3488 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3489 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3490 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3491 IFSET(SAMR_FIELD_PROFILE_PATH)
3492 SET_STRING(msg, info23.info.profile_path, "profilePath");
3493 IFSET(SAMR_FIELD_DESCRIPTION)
3494 SET_STRING(msg, info23.info.description, "description");
3495 IFSET(SAMR_FIELD_WORKSTATIONS)
3496 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3497 IFSET(SAMR_FIELD_COMMENT)
3498 SET_STRING(msg, info23.info.comment, "comment");
3499 IFSET(SAMR_FIELD_PARAMETERS)
3500 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3501 IFSET(SAMR_FIELD_PRIMARY_GID)
3502 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3503 IFSET(SAMR_FIELD_ACCT_FLAGS)
3504 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3505 IFSET(SAMR_FIELD_LOGON_HOURS)
3506 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3507 IFSET(SAMR_FIELD_COUNTRY_CODE)
3508 SET_UINT (msg, info23.info.country_code, "countryCode");
3509 IFSET(SAMR_FIELD_CODE_PAGE)
3510 SET_UINT (msg, info23.info.code_page, "codePage");
3512 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3513 status = samr_set_password(dce_call,
3514 a_state->sam_ctx,
3515 a_state->account_dn,
3516 a_state->domain_state->domain_dn,
3517 mem_ctx, msg,
3518 &r->in.info->info23.password);
3519 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3520 status = samr_set_password(dce_call,
3521 a_state->sam_ctx,
3522 a_state->account_dn,
3523 a_state->domain_state->domain_dn,
3524 mem_ctx, msg,
3525 &r->in.info->info23.password);
3527 #undef IFSET
3528 break;
3530 /* the set password levels are handled separately */
3531 case 24:
3532 status = samr_set_password(dce_call,
3533 a_state->sam_ctx,
3534 a_state->account_dn,
3535 a_state->domain_state->domain_dn,
3536 mem_ctx, msg,
3537 &r->in.info->info24.password);
3538 break;
3540 case 25:
3541 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3542 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3543 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3544 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3545 SET_STRING(msg, info25.info.account_name, "samAccountName");
3546 IFSET(SAMR_FIELD_FULL_NAME)
3547 SET_STRING(msg, info25.info.full_name, "displayName");
3548 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3549 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3550 IFSET(SAMR_FIELD_HOME_DRIVE)
3551 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3552 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3553 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3554 IFSET(SAMR_FIELD_PROFILE_PATH)
3555 SET_STRING(msg, info25.info.profile_path, "profilePath");
3556 IFSET(SAMR_FIELD_DESCRIPTION)
3557 SET_STRING(msg, info25.info.description, "description");
3558 IFSET(SAMR_FIELD_WORKSTATIONS)
3559 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3560 IFSET(SAMR_FIELD_COMMENT)
3561 SET_STRING(msg, info25.info.comment, "comment");
3562 IFSET(SAMR_FIELD_PARAMETERS)
3563 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3564 IFSET(SAMR_FIELD_PRIMARY_GID)
3565 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3566 IFSET(SAMR_FIELD_ACCT_FLAGS)
3567 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3568 IFSET(SAMR_FIELD_LOGON_HOURS)
3569 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3570 IFSET(SAMR_FIELD_COUNTRY_CODE)
3571 SET_UINT (msg, info25.info.country_code, "countryCode");
3572 IFSET(SAMR_FIELD_CODE_PAGE)
3573 SET_UINT (msg, info25.info.code_page, "codePage");
3575 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3576 status = samr_set_password_ex(dce_call,
3577 a_state->sam_ctx,
3578 a_state->account_dn,
3579 a_state->domain_state->domain_dn,
3580 mem_ctx, msg,
3581 &r->in.info->info25.password);
3582 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3583 status = samr_set_password_ex(dce_call,
3584 a_state->sam_ctx,
3585 a_state->account_dn,
3586 a_state->domain_state->domain_dn,
3587 mem_ctx, msg,
3588 &r->in.info->info25.password);
3590 #undef IFSET
3591 break;
3593 /* the set password levels are handled separately */
3594 case 26:
3595 status = samr_set_password_ex(dce_call,
3596 a_state->sam_ctx,
3597 a_state->account_dn,
3598 a_state->domain_state->domain_dn,
3599 mem_ctx, msg,
3600 &r->in.info->info26.password);
3601 break;
3604 default:
3605 /* many info classes are not valid for SetUserInfo */
3606 return NT_STATUS_INVALID_INFO_CLASS;
3609 if (!NT_STATUS_IS_OK(status)) {
3610 return status;
3613 /* modify the samdb record */
3614 if (msg->num_elements > 0) {
3615 ret = ldb_modify(a_state->sam_ctx, msg);
3616 if (ret != LDB_SUCCESS) {
3617 DEBUG(1,("Failed to modify record %s: %s\n",
3618 ldb_dn_get_linearized(a_state->account_dn),
3619 ldb_errstring(a_state->sam_ctx)));
3621 /* we really need samdb.c to return NTSTATUS */
3622 return NT_STATUS_UNSUCCESSFUL;
3626 return NT_STATUS_OK;
3631 samr_GetGroupsForUser
3633 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3634 struct samr_GetGroupsForUser *r)
3636 struct dcesrv_handle *h;
3637 struct samr_account_state *a_state;
3638 struct samr_domain_state *d_state;
3639 struct ldb_message **res;
3640 const char * const attrs[2] = { "objectSid", NULL };
3641 struct samr_RidWithAttributeArray *array;
3642 int i, count;
3644 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3646 a_state = h->data;
3647 d_state = a_state->domain_state;
3649 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3650 d_state->domain_dn, &res,
3651 attrs, d_state->domain_sid,
3652 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3653 ldb_dn_get_linearized(a_state->account_dn),
3654 GTYPE_SECURITY_GLOBAL_GROUP);
3655 if (count < 0)
3656 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3658 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3659 if (array == NULL)
3660 return NT_STATUS_NO_MEMORY;
3662 array->count = 0;
3663 array->rids = NULL;
3665 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3666 count + 1);
3667 if (array->rids == NULL)
3668 return NT_STATUS_NO_MEMORY;
3670 /* Adds the primary group */
3671 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3672 ~0, a_state->account_dn,
3673 "primaryGroupID", NULL);
3674 array->rids[0].attributes = SE_GROUP_MANDATORY
3675 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3676 array->count += 1;
3678 /* Adds the additional groups */
3679 for (i = 0; i < count; i++) {
3680 struct dom_sid *group_sid;
3682 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3683 if (group_sid == NULL) {
3684 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3685 continue;
3688 array->rids[i + 1].rid =
3689 group_sid->sub_auths[group_sid->num_auths-1];
3690 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3691 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3692 array->count += 1;
3695 *r->out.rids = array;
3697 return NT_STATUS_OK;
3702 samr_QueryDisplayInfo
3704 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3705 struct samr_QueryDisplayInfo *r)
3707 struct dcesrv_handle *h;
3708 struct samr_domain_state *d_state;
3709 struct ldb_message **res;
3710 int ldb_cnt, count, i;
3711 const char * const attrs[] = { "objectSid", "sAMAccountName",
3712 "displayName", "description", "userAccountControl",
3713 "pwdLastSet", NULL };
3714 struct samr_DispEntryFull *entriesFull = NULL;
3715 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3716 struct samr_DispEntryAscii *entriesAscii = NULL;
3717 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3718 const char *filter;
3720 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3722 d_state = h->data;
3724 switch (r->in.level) {
3725 case 1:
3726 case 4:
3727 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3728 "(sAMAccountType=%u))",
3729 ATYPE_NORMAL_ACCOUNT);
3730 break;
3731 case 2:
3732 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3733 "(sAMAccountType=%u))",
3734 ATYPE_WORKSTATION_TRUST);
3735 break;
3736 case 3:
3737 case 5:
3738 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3739 "(objectclass=group))",
3740 GTYPE_SECURITY_GLOBAL_GROUP);
3741 break;
3742 default:
3743 return NT_STATUS_INVALID_INFO_CLASS;
3746 /* search for all requested objects in this domain. This could
3747 possibly be cached and resumed based on resume_key */
3748 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3749 d_state->domain_dn, &res, attrs,
3750 d_state->domain_sid, "%s", filter);
3751 if (ldb_cnt == -1) {
3752 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3754 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3755 return NT_STATUS_OK;
3758 switch (r->in.level) {
3759 case 1:
3760 entriesGeneral = talloc_array(mem_ctx,
3761 struct samr_DispEntryGeneral,
3762 ldb_cnt);
3763 break;
3764 case 2:
3765 entriesFull = talloc_array(mem_ctx,
3766 struct samr_DispEntryFull,
3767 ldb_cnt);
3768 break;
3769 case 3:
3770 entriesFullGroup = talloc_array(mem_ctx,
3771 struct samr_DispEntryFullGroup,
3772 ldb_cnt);
3773 break;
3774 case 4:
3775 case 5:
3776 entriesAscii = talloc_array(mem_ctx,
3777 struct samr_DispEntryAscii,
3778 ldb_cnt);
3779 break;
3782 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3783 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3784 return NT_STATUS_NO_MEMORY;
3786 count = 0;
3788 for (i=0; i<ldb_cnt; i++) {
3789 struct dom_sid *objectsid;
3791 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3792 "objectSid");
3793 if (objectsid == NULL)
3794 continue;
3796 switch(r->in.level) {
3797 case 1:
3798 entriesGeneral[count].idx = count + 1;
3799 entriesGeneral[count].rid =
3800 objectsid->sub_auths[objectsid->num_auths-1];
3801 entriesGeneral[count].acct_flags =
3802 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3803 res[i],
3804 d_state->domain_dn);
3805 entriesGeneral[count].account_name.string =
3806 samdb_result_string(res[i],
3807 "sAMAccountName", "");
3808 entriesGeneral[count].full_name.string =
3809 samdb_result_string(res[i], "displayName", "");
3810 entriesGeneral[count].description.string =
3811 samdb_result_string(res[i], "description", "");
3812 break;
3813 case 2:
3814 entriesFull[count].idx = count + 1;
3815 entriesFull[count].rid =
3816 objectsid->sub_auths[objectsid->num_auths-1];
3818 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3819 entriesFull[count].acct_flags =
3820 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3821 res[i],
3822 d_state->domain_dn) | ACB_NORMAL;
3823 entriesFull[count].account_name.string =
3824 samdb_result_string(res[i], "sAMAccountName",
3825 "");
3826 entriesFull[count].description.string =
3827 samdb_result_string(res[i], "description", "");
3828 break;
3829 case 3:
3830 entriesFullGroup[count].idx = count + 1;
3831 entriesFullGroup[count].rid =
3832 objectsid->sub_auths[objectsid->num_auths-1];
3833 /* We get a "7" here for groups */
3834 entriesFullGroup[count].acct_flags
3835 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3836 entriesFullGroup[count].account_name.string =
3837 samdb_result_string(res[i], "sAMAccountName",
3838 "");
3839 entriesFullGroup[count].description.string =
3840 samdb_result_string(res[i], "description", "");
3841 break;
3842 case 4:
3843 case 5:
3844 entriesAscii[count].idx = count + 1;
3845 entriesAscii[count].account_name.string =
3846 samdb_result_string(res[i], "sAMAccountName",
3847 "");
3848 break;
3851 count += 1;
3854 *r->out.total_size = count;
3856 if (r->in.start_idx >= count) {
3857 *r->out.returned_size = 0;
3858 switch(r->in.level) {
3859 case 1:
3860 r->out.info->info1.count = *r->out.returned_size;
3861 r->out.info->info1.entries = NULL;
3862 break;
3863 case 2:
3864 r->out.info->info2.count = *r->out.returned_size;
3865 r->out.info->info2.entries = NULL;
3866 break;
3867 case 3:
3868 r->out.info->info3.count = *r->out.returned_size;
3869 r->out.info->info3.entries = NULL;
3870 break;
3871 case 4:
3872 r->out.info->info4.count = *r->out.returned_size;
3873 r->out.info->info4.entries = NULL;
3874 break;
3875 case 5:
3876 r->out.info->info5.count = *r->out.returned_size;
3877 r->out.info->info5.entries = NULL;
3878 break;
3880 } else {
3881 *r->out.returned_size = MIN(count - r->in.start_idx,
3882 r->in.max_entries);
3883 switch(r->in.level) {
3884 case 1:
3885 r->out.info->info1.count = *r->out.returned_size;
3886 r->out.info->info1.entries =
3887 &(entriesGeneral[r->in.start_idx]);
3888 break;
3889 case 2:
3890 r->out.info->info2.count = *r->out.returned_size;
3891 r->out.info->info2.entries =
3892 &(entriesFull[r->in.start_idx]);
3893 break;
3894 case 3:
3895 r->out.info->info3.count = *r->out.returned_size;
3896 r->out.info->info3.entries =
3897 &(entriesFullGroup[r->in.start_idx]);
3898 break;
3899 case 4:
3900 r->out.info->info4.count = *r->out.returned_size;
3901 r->out.info->info4.entries =
3902 &(entriesAscii[r->in.start_idx]);
3903 break;
3904 case 5:
3905 r->out.info->info5.count = *r->out.returned_size;
3906 r->out.info->info5.entries =
3907 &(entriesAscii[r->in.start_idx]);
3908 break;
3912 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3913 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3918 samr_GetDisplayEnumerationIndex
3920 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3921 struct samr_GetDisplayEnumerationIndex *r)
3923 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3928 samr_TestPrivateFunctionsDomain
3930 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3931 struct samr_TestPrivateFunctionsDomain *r)
3933 return NT_STATUS_NOT_IMPLEMENTED;
3938 samr_TestPrivateFunctionsUser
3940 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3941 struct samr_TestPrivateFunctionsUser *r)
3943 return NT_STATUS_NOT_IMPLEMENTED;
3948 samr_GetUserPwInfo
3950 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3951 struct samr_GetUserPwInfo *r)
3953 struct dcesrv_handle *h;
3954 struct samr_account_state *a_state;
3956 ZERO_STRUCTP(r->out.info);
3958 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3960 a_state = h->data;
3962 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3963 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3964 NULL);
3965 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3966 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3968 return NT_STATUS_OK;
3973 samr_RemoveMemberFromForeignDomain
3975 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3976 struct samr_RemoveMemberFromForeignDomain *r)
3978 struct dcesrv_handle *h;
3979 struct samr_domain_state *d_state;
3980 const char *memberdn;
3981 struct ldb_message **res;
3982 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3983 int i, count;
3985 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3987 d_state = h->data;
3989 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3990 "distinguishedName", "(objectSid=%s)",
3991 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3992 /* Nothing to do */
3993 if (memberdn == NULL) {
3994 return NT_STATUS_OK;
3997 /* TODO: Does this call only remove alias members, or does it do this
3998 * for domain groups as well? */
4000 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4001 d_state->domain_dn, &res, attrs,
4002 d_state->domain_sid,
4003 "(&(member=%s)(objectClass=group)"
4004 "(|(groupType=%d)(groupType=%d)))",
4005 memberdn,
4006 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4007 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4009 if (count < 0)
4010 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4012 for (i=0; i<count; i++) {
4013 struct ldb_message *mod;
4015 mod = ldb_msg_new(mem_ctx);
4016 if (mod == NULL) {
4017 return NT_STATUS_NO_MEMORY;
4020 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4021 if (mod->dn == NULL) {
4022 talloc_free(mod);
4023 continue;
4026 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4027 "member", memberdn) != 0)
4028 return NT_STATUS_NO_MEMORY;
4030 if (ldb_modify(d_state->sam_ctx, mod) != 0)
4031 return NT_STATUS_UNSUCCESSFUL;
4033 talloc_free(mod);
4036 return NT_STATUS_OK;
4041 samr_QueryDomainInfo2
4043 just an alias for samr_QueryDomainInfo
4045 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4046 struct samr_QueryDomainInfo2 *r)
4048 struct samr_QueryDomainInfo r1;
4049 NTSTATUS status;
4051 ZERO_STRUCT(r1.out);
4052 r1.in.domain_handle = r->in.domain_handle;
4053 r1.in.level = r->in.level;
4054 r1.out.info = r->out.info;
4056 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4058 return status;
4063 samr_QueryUserInfo2
4065 just an alias for samr_QueryUserInfo
4067 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4068 struct samr_QueryUserInfo2 *r)
4070 struct samr_QueryUserInfo r1;
4071 NTSTATUS status;
4073 r1.in.user_handle = r->in.user_handle;
4074 r1.in.level = r->in.level;
4075 r1.out.info = r->out.info;
4077 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4079 return status;
4084 samr_QueryDisplayInfo2
4086 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4087 struct samr_QueryDisplayInfo2 *r)
4089 struct samr_QueryDisplayInfo q;
4090 NTSTATUS result;
4092 q.in.domain_handle = r->in.domain_handle;
4093 q.in.level = r->in.level;
4094 q.in.start_idx = r->in.start_idx;
4095 q.in.max_entries = r->in.max_entries;
4096 q.in.buf_size = r->in.buf_size;
4097 q.out.total_size = r->out.total_size;
4098 q.out.returned_size = r->out.returned_size;
4099 q.out.info = r->out.info;
4101 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4103 return result;
4108 samr_GetDisplayEnumerationIndex2
4110 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4111 struct samr_GetDisplayEnumerationIndex2 *r)
4113 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4118 samr_QueryDisplayInfo3
4120 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4121 struct samr_QueryDisplayInfo3 *r)
4123 struct samr_QueryDisplayInfo q;
4124 NTSTATUS result;
4126 q.in.domain_handle = r->in.domain_handle;
4127 q.in.level = r->in.level;
4128 q.in.start_idx = r->in.start_idx;
4129 q.in.max_entries = r->in.max_entries;
4130 q.in.buf_size = r->in.buf_size;
4131 q.out.total_size = r->out.total_size;
4132 q.out.returned_size = r->out.returned_size;
4133 q.out.info = r->out.info;
4135 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4137 return result;
4142 samr_AddMultipleMembersToAlias
4144 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4145 struct samr_AddMultipleMembersToAlias *r)
4147 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4152 samr_RemoveMultipleMembersFromAlias
4154 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4155 struct samr_RemoveMultipleMembersFromAlias *r)
4157 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4162 samr_GetDomPwInfo
4164 this fetches the default password properties for a domain
4166 note that w2k3 completely ignores the domain name in this call, and
4167 always returns the information for the servers primary domain
4169 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4170 struct samr_GetDomPwInfo *r)
4172 struct ldb_message **msgs;
4173 int ret;
4174 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4175 struct ldb_context *sam_ctx;
4177 ZERO_STRUCTP(r->out.info);
4179 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
4180 if (sam_ctx == NULL) {
4181 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4184 /* The domain name in this call is ignored */
4185 ret = gendb_search_dn(sam_ctx,
4186 mem_ctx, NULL, &msgs, attrs);
4187 if (ret <= 0) {
4188 talloc_free(sam_ctx);
4190 return NT_STATUS_NO_SUCH_DOMAIN;
4192 if (ret > 1) {
4193 talloc_free(msgs);
4194 talloc_free(sam_ctx);
4196 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4199 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4200 "minPwdLength", 0);
4201 r->out.info->password_properties = samdb_result_uint(msgs[0],
4202 "pwdProperties", 1);
4204 talloc_free(msgs);
4205 talloc_free(sam_ctx);
4207 return NT_STATUS_OK;
4212 samr_Connect2
4214 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4215 struct samr_Connect2 *r)
4217 struct samr_Connect c;
4219 c.in.system_name = NULL;
4220 c.in.access_mask = r->in.access_mask;
4221 c.out.connect_handle = r->out.connect_handle;
4223 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4228 samr_SetUserInfo2
4230 just an alias for samr_SetUserInfo
4232 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4233 struct samr_SetUserInfo2 *r)
4235 struct samr_SetUserInfo r2;
4237 r2.in.user_handle = r->in.user_handle;
4238 r2.in.level = r->in.level;
4239 r2.in.info = r->in.info;
4241 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4246 samr_SetBootKeyInformation
4248 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4249 struct samr_SetBootKeyInformation *r)
4251 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4256 samr_GetBootKeyInformation
4258 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4259 struct samr_GetBootKeyInformation *r)
4261 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4266 samr_Connect3
4268 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4269 struct samr_Connect3 *r)
4271 struct samr_Connect c;
4273 c.in.system_name = NULL;
4274 c.in.access_mask = r->in.access_mask;
4275 c.out.connect_handle = r->out.connect_handle;
4277 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4282 samr_Connect4
4284 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4285 struct samr_Connect4 *r)
4287 struct samr_Connect c;
4289 c.in.system_name = NULL;
4290 c.in.access_mask = r->in.access_mask;
4291 c.out.connect_handle = r->out.connect_handle;
4293 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4298 samr_Connect5
4300 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4301 struct samr_Connect5 *r)
4303 struct samr_Connect c;
4304 NTSTATUS status;
4306 c.in.system_name = NULL;
4307 c.in.access_mask = r->in.access_mask;
4308 c.out.connect_handle = r->out.connect_handle;
4310 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4312 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4313 r->out.info_out->info1.unknown2 = 0;
4314 *r->out.level_out = r->in.level_in;
4316 return status;
4321 samr_RidToSid
4323 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4324 struct samr_RidToSid *r)
4326 struct samr_domain_state *d_state;
4327 struct dcesrv_handle *h;
4329 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4331 d_state = h->data;
4333 /* form the users SID */
4334 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4335 if (!*r->out.sid) {
4336 return NT_STATUS_NO_MEMORY;
4339 return NT_STATUS_OK;
4344 samr_SetDsrmPassword
4346 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4347 struct samr_SetDsrmPassword *r)
4349 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4354 samr_ValidatePassword
4356 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4357 struct samr_ValidatePassword *r)
4359 /* just say it's OK for now - we need to hook this into our
4360 password strength code later */
4361 DEBUG(0,(__location__ ": Faking samr_ValidatePassword reply\n"));
4362 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4363 return NT_STATUS_OK;
4367 /* include the generated boilerplate */
4368 #include "librpc/gen_ndr/ndr_samr_s.c"