s4:dcesrv_samr - Implement "dcesrv_samr_ValidatePassword" using my new check password...
[Samba/fernandojvsilva.git] / source4 / rpc_server / samr / dcesrv_samr.c
blobeecc00d4628e53cffc0c8d1cb4da74b749d84db7
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(mem_ctx, 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(mem_ctx, 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(mem_ctx, 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(msg, 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(mem_ctx, 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, mem_ctx,
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(mem_ctx, 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(mem_ctx, 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 talloc_free(h);
2304 ZERO_STRUCTP(r->out.group_handle);
2306 return NT_STATUS_OK;
2311 samr_DeleteGroupMember
2313 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2314 struct samr_DeleteGroupMember *r)
2316 struct dcesrv_handle *h;
2317 struct samr_account_state *a_state;
2318 struct samr_domain_state *d_state;
2319 struct ldb_message *mod;
2320 struct dom_sid *membersid;
2321 const char *memberdn;
2322 struct ldb_result *res;
2323 const char * const attrs[] = { NULL };
2324 int ret;
2326 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2328 a_state = h->data;
2329 d_state = a_state->domain_state;
2331 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2332 if (membersid == NULL)
2333 return NT_STATUS_NO_MEMORY;
2335 /* In native mode, AD can also nest domain groups. Not sure yet
2336 * whether this is also available via RPC. */
2337 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2338 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2339 "(&(objectSid=%s)(objectclass=user))",
2340 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2342 if (ret != LDB_SUCCESS) {
2343 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2346 if (res->count == 0) {
2347 return NT_STATUS_NO_SUCH_USER;
2350 if (res->count > 1) {
2351 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2354 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2356 if (memberdn == NULL)
2357 return NT_STATUS_NO_MEMORY;
2359 mod = ldb_msg_new(mem_ctx);
2360 if (mod == NULL) {
2361 return NT_STATUS_NO_MEMORY;
2364 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2366 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2367 memberdn);
2368 if (ret != LDB_SUCCESS) {
2369 return NT_STATUS_NO_MEMORY;
2372 ret = ldb_modify(a_state->sam_ctx, mod);
2373 switch (ret) {
2374 case LDB_SUCCESS:
2375 return NT_STATUS_OK;
2376 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2377 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2378 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2379 return NT_STATUS_ACCESS_DENIED;
2380 default:
2381 return NT_STATUS_UNSUCCESSFUL;
2387 samr_QueryGroupMember
2389 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2390 struct samr_QueryGroupMember *r)
2392 struct dcesrv_handle *h;
2393 struct samr_account_state *a_state;
2394 struct ldb_message **res;
2395 struct ldb_message_element *el;
2396 struct samr_RidTypeArray *array;
2397 const char * const attrs[2] = { "member", NULL };
2398 int ret;
2400 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2402 a_state = h->data;
2404 /* pull the member attribute */
2405 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2406 a_state->account_dn, &res, attrs);
2408 if (ret != 1) {
2409 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2412 array = talloc(mem_ctx, struct samr_RidTypeArray);
2414 if (array == NULL)
2415 return NT_STATUS_NO_MEMORY;
2417 ZERO_STRUCTP(array);
2419 el = ldb_msg_find_element(res[0], "member");
2421 if (el != NULL) {
2422 int i;
2424 array->count = el->num_values;
2426 array->rids = talloc_array(mem_ctx, uint32_t,
2427 el->num_values);
2428 if (array->rids == NULL)
2429 return NT_STATUS_NO_MEMORY;
2431 array->types = talloc_array(mem_ctx, uint32_t,
2432 el->num_values);
2433 if (array->types == NULL)
2434 return NT_STATUS_NO_MEMORY;
2436 for (i=0; i<el->num_values; i++) {
2437 struct ldb_message **res2;
2438 const char * const attrs2[2] = { "objectSid", NULL };
2439 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2440 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2441 &res2, attrs2);
2442 if (ret != 1)
2443 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2445 array->rids[i] =
2446 samdb_result_rid_from_sid(mem_ctx, res2[0],
2447 "objectSid", 0);
2449 if (array->rids[i] == 0)
2450 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2452 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2456 *r->out.rids = array;
2458 return NT_STATUS_OK;
2463 samr_SetMemberAttributesOfGroup
2465 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2466 struct samr_SetMemberAttributesOfGroup *r)
2468 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2473 samr_OpenAlias
2475 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2476 struct samr_OpenAlias *r)
2478 struct samr_domain_state *d_state;
2479 struct samr_account_state *a_state;
2480 struct dcesrv_handle *h;
2481 const char *alias_name;
2482 struct dom_sid *sid;
2483 struct ldb_message **msgs;
2484 struct dcesrv_handle *g_handle;
2485 const char * const attrs[2] = { "sAMAccountName", NULL };
2486 int ret;
2488 ZERO_STRUCTP(r->out.alias_handle);
2490 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2492 d_state = h->data;
2494 /* form the alias SID */
2495 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2496 if (sid == NULL)
2497 return NT_STATUS_NO_MEMORY;
2499 /* search for the group record */
2500 ret = gendb_search(d_state->sam_ctx,
2501 mem_ctx, d_state->domain_dn, &msgs, attrs,
2502 "(&(objectSid=%s)(objectclass=group)"
2503 "(|(grouptype=%d)(grouptype=%d)))",
2504 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2505 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2506 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2507 if (ret == 0) {
2508 return NT_STATUS_NO_SUCH_ALIAS;
2510 if (ret != 1) {
2511 DEBUG(0,("Found %d records matching sid %s\n",
2512 ret, dom_sid_string(mem_ctx, sid)));
2513 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2516 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2517 if (alias_name == NULL) {
2518 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2519 dom_sid_string(mem_ctx, sid)));
2520 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2523 a_state = talloc(mem_ctx, struct samr_account_state);
2524 if (!a_state) {
2525 return NT_STATUS_NO_MEMORY;
2527 a_state->sam_ctx = d_state->sam_ctx;
2528 a_state->access_mask = r->in.access_mask;
2529 a_state->domain_state = talloc_reference(a_state, d_state);
2530 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2531 a_state->account_sid = talloc_steal(a_state, sid);
2532 a_state->account_name = talloc_strdup(a_state, alias_name);
2533 if (!a_state->account_name) {
2534 return NT_STATUS_NO_MEMORY;
2537 /* create the policy handle */
2538 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2539 if (!g_handle) {
2540 return NT_STATUS_NO_MEMORY;
2543 g_handle->data = talloc_steal(g_handle, a_state);
2545 *r->out.alias_handle = g_handle->wire_handle;
2547 return NT_STATUS_OK;
2552 samr_QueryAliasInfo
2554 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2555 struct samr_QueryAliasInfo *r)
2557 struct dcesrv_handle *h;
2558 struct samr_account_state *a_state;
2559 struct ldb_message *msg, **res;
2560 const char * const attrs[4] = { "sAMAccountName", "description",
2561 "numMembers", NULL };
2562 int ret;
2563 union samr_AliasInfo *info;
2565 *r->out.info = NULL;
2567 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2569 a_state = h->data;
2571 /* pull all the alias attributes */
2572 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2573 a_state->account_dn ,&res, attrs);
2574 if (ret != 1) {
2575 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2577 msg = res[0];
2579 /* allocate the info structure */
2580 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2581 if (info == NULL) {
2582 return NT_STATUS_NO_MEMORY;
2585 switch(r->in.level) {
2586 case ALIASINFOALL:
2587 QUERY_STRING(msg, all.name, "sAMAccountName");
2588 QUERY_UINT (msg, all.num_members, "numMembers");
2589 QUERY_STRING(msg, all.description, "description");
2590 break;
2591 case ALIASINFONAME:
2592 QUERY_STRING(msg, name, "sAMAccountName");
2593 break;
2594 case ALIASINFODESCRIPTION:
2595 QUERY_STRING(msg, description, "description");
2596 break;
2597 default:
2598 talloc_free(info);
2599 return NT_STATUS_INVALID_INFO_CLASS;
2602 *r->out.info = info;
2604 return NT_STATUS_OK;
2609 samr_SetAliasInfo
2611 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2612 struct samr_SetAliasInfo *r)
2614 struct dcesrv_handle *h;
2615 struct samr_account_state *a_state;
2616 struct ldb_message *msg;
2617 struct ldb_context *sam_ctx;
2618 int ret;
2620 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2622 a_state = h->data;
2623 sam_ctx = a_state->sam_ctx;
2625 msg = ldb_msg_new(mem_ctx);
2626 if (msg == NULL) {
2627 return NT_STATUS_NO_MEMORY;
2630 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2631 if (!msg->dn) {
2632 return NT_STATUS_NO_MEMORY;
2635 switch (r->in.level) {
2636 case ALIASINFODESCRIPTION:
2637 SET_STRING(msg, description, "description");
2638 break;
2639 case ALIASINFONAME:
2640 /* On W2k3 this does not change the name, it changes the
2641 * sAMAccountName attribute */
2642 SET_STRING(msg, name, "sAMAccountName");
2643 break;
2644 default:
2645 return NT_STATUS_INVALID_INFO_CLASS;
2648 /* modify the samdb record */
2649 ret = ldb_modify(a_state->sam_ctx, msg);
2650 if (ret != LDB_SUCCESS) {
2651 /* we really need samdb.c to return NTSTATUS */
2652 return NT_STATUS_UNSUCCESSFUL;
2655 return NT_STATUS_OK;
2660 samr_DeleteDomAlias
2662 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2663 struct samr_DeleteDomAlias *r)
2665 struct dcesrv_handle *h;
2666 struct samr_account_state *a_state;
2667 int ret;
2669 *r->out.alias_handle = *r->in.alias_handle;
2671 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2673 a_state = h->data;
2675 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2676 if (ret != 0) {
2677 return NT_STATUS_UNSUCCESSFUL;
2680 talloc_free(h);
2681 ZERO_STRUCTP(r->out.alias_handle);
2683 return NT_STATUS_OK;
2688 samr_AddAliasMember
2690 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2691 struct samr_AddAliasMember *r)
2693 struct dcesrv_handle *h;
2694 struct samr_account_state *a_state;
2695 struct samr_domain_state *d_state;
2696 struct ldb_message *mod;
2697 struct ldb_message **msgs;
2698 const char * const attrs[] = { NULL };
2699 struct ldb_dn *memberdn = NULL;
2700 int ret;
2701 NTSTATUS status;
2703 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2705 a_state = h->data;
2706 d_state = a_state->domain_state;
2708 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2709 &msgs, attrs, "(objectsid=%s)",
2710 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2712 if (ret == 1) {
2713 memberdn = msgs[0]->dn;
2714 } else if (ret > 1) {
2715 DEBUG(0,("Found %d records matching sid %s\n",
2716 ret, dom_sid_string(mem_ctx, r->in.sid)));
2717 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2718 } else if (ret == 0) {
2719 status = samdb_create_foreign_security_principal(
2720 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2721 if (!NT_STATUS_IS_OK(status)) {
2722 return status;
2724 } else {
2725 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2728 if (memberdn == NULL) {
2729 DEBUG(0, ("Could not find memberdn\n"));
2730 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2733 mod = ldb_msg_new(mem_ctx);
2734 if (mod == NULL) {
2735 return NT_STATUS_NO_MEMORY;
2738 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2740 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2741 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2742 if (ret != LDB_SUCCESS) {
2743 return NT_STATUS_UNSUCCESSFUL;
2746 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2747 return NT_STATUS_UNSUCCESSFUL;
2750 return NT_STATUS_OK;
2755 samr_DeleteAliasMember
2757 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2758 struct samr_DeleteAliasMember *r)
2760 struct dcesrv_handle *h;
2761 struct samr_account_state *a_state;
2762 struct samr_domain_state *d_state;
2763 struct ldb_message *mod;
2764 const char *memberdn;
2765 int ret;
2767 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2769 a_state = h->data;
2770 d_state = a_state->domain_state;
2772 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2773 "distinguishedName", "(objectSid=%s)",
2774 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2776 if (memberdn == NULL)
2777 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2779 mod = ldb_msg_new(mem_ctx);
2780 if (mod == NULL) {
2781 return NT_STATUS_NO_MEMORY;
2784 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2786 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2787 memberdn);
2788 if (ret != LDB_SUCCESS)
2789 return NT_STATUS_UNSUCCESSFUL;
2791 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2792 return NT_STATUS_UNSUCCESSFUL;
2794 return NT_STATUS_OK;
2799 samr_GetMembersInAlias
2801 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2802 struct samr_GetMembersInAlias *r)
2804 struct dcesrv_handle *h;
2805 struct samr_account_state *a_state;
2806 struct samr_domain_state *d_state;
2807 struct ldb_message **msgs;
2808 struct lsa_SidPtr *sids;
2809 struct ldb_message_element *el;
2810 const char * const attrs[2] = { "member", NULL};
2811 int ret;
2813 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2815 a_state = h->data;
2816 d_state = a_state->domain_state;
2818 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2819 a_state->account_dn, &msgs, attrs);
2821 if (ret == -1) {
2822 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2823 } else if (ret == 0) {
2824 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2825 } else if (ret != 1) {
2826 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2829 r->out.sids->num_sids = 0;
2830 r->out.sids->sids = NULL;
2832 el = ldb_msg_find_element(msgs[0], "member");
2834 if (el != NULL) {
2835 int i;
2837 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2838 el->num_values);
2840 if (sids == NULL)
2841 return NT_STATUS_NO_MEMORY;
2843 for (i=0; i<el->num_values; i++) {
2844 struct ldb_message **msgs2;
2845 const char * const attrs2[2] = { "objectSid", NULL };
2846 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2847 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2848 &msgs2, attrs2);
2849 if (ret != 1)
2850 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2852 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2853 "objectSid");
2855 if (sids[i].sid == NULL)
2856 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2858 r->out.sids->num_sids = el->num_values;
2859 r->out.sids->sids = sids;
2862 return NT_STATUS_OK;
2866 samr_OpenUser
2868 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2869 struct samr_OpenUser *r)
2871 struct samr_domain_state *d_state;
2872 struct samr_account_state *a_state;
2873 struct dcesrv_handle *h;
2874 const char *account_name;
2875 struct dom_sid *sid;
2876 struct ldb_message **msgs;
2877 struct dcesrv_handle *u_handle;
2878 const char * const attrs[2] = { "sAMAccountName", NULL };
2879 int ret;
2881 ZERO_STRUCTP(r->out.user_handle);
2883 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2885 d_state = h->data;
2887 /* form the users SID */
2888 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2889 if (!sid) {
2890 return NT_STATUS_NO_MEMORY;
2893 /* search for the user record */
2894 ret = gendb_search(d_state->sam_ctx,
2895 mem_ctx, d_state->domain_dn, &msgs, attrs,
2896 "(&(objectSid=%s)(objectclass=user))",
2897 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2898 if (ret == 0) {
2899 return NT_STATUS_NO_SUCH_USER;
2901 if (ret != 1) {
2902 DEBUG(0,("Found %d records matching sid %s\n", ret,
2903 dom_sid_string(mem_ctx, sid)));
2904 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2907 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2908 if (account_name == NULL) {
2909 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2910 dom_sid_string(mem_ctx, sid)));
2911 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2914 a_state = talloc(mem_ctx, struct samr_account_state);
2915 if (!a_state) {
2916 return NT_STATUS_NO_MEMORY;
2918 a_state->sam_ctx = d_state->sam_ctx;
2919 a_state->access_mask = r->in.access_mask;
2920 a_state->domain_state = talloc_reference(a_state, d_state);
2921 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2922 a_state->account_sid = talloc_steal(a_state, sid);
2923 a_state->account_name = talloc_strdup(a_state, account_name);
2924 if (!a_state->account_name) {
2925 return NT_STATUS_NO_MEMORY;
2928 /* create the policy handle */
2929 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2930 if (!u_handle) {
2931 return NT_STATUS_NO_MEMORY;
2934 u_handle->data = talloc_steal(u_handle, a_state);
2936 *r->out.user_handle = u_handle->wire_handle;
2938 return NT_STATUS_OK;
2944 samr_DeleteUser
2946 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2947 struct samr_DeleteUser *r)
2949 struct dcesrv_handle *h;
2950 struct samr_account_state *a_state;
2951 int ret;
2953 *r->out.user_handle = *r->in.user_handle;
2955 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2957 a_state = h->data;
2959 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2960 if (ret != LDB_SUCCESS) {
2961 DEBUG(1, ("Failed to delete user: %s: %s\n",
2962 ldb_dn_get_linearized(a_state->account_dn),
2963 ldb_errstring(a_state->sam_ctx)));
2964 return NT_STATUS_UNSUCCESSFUL;
2967 talloc_free(h);
2968 ZERO_STRUCTP(r->out.user_handle);
2970 return NT_STATUS_OK;
2975 samr_QueryUserInfo
2977 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2978 struct samr_QueryUserInfo *r)
2980 struct dcesrv_handle *h;
2981 struct samr_account_state *a_state;
2982 struct ldb_message *msg, **res;
2983 int ret;
2984 struct ldb_context *sam_ctx;
2986 const char * const *attrs = NULL;
2987 union samr_UserInfo *info;
2989 *r->out.info = NULL;
2991 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2993 a_state = h->data;
2994 sam_ctx = a_state->sam_ctx;
2996 /* fill in the reply */
2997 switch (r->in.level) {
2998 case 1:
3000 static const char * const attrs2[] = {"sAMAccountName",
3001 "displayName",
3002 "primaryroupID",
3003 "description",
3004 "comment",
3005 NULL};
3006 attrs = attrs2;
3007 break;
3009 case 2:
3011 static const char * const attrs2[] = {"comment",
3012 "countryCode",
3013 "codePage",
3014 NULL};
3015 attrs = attrs2;
3016 break;
3018 case 3:
3020 static const char * const attrs2[] = {"sAMAccountName",
3021 "displayName",
3022 "objectSid",
3023 "primaryGroupID",
3024 "homeDirectory",
3025 "homeDrive",
3026 "scriptPath",
3027 "profilePath",
3028 "userWorkstations",
3029 "lastLogon",
3030 "lastLogoff",
3031 "pwdLastSet",
3032 "logonHours",
3033 "badPwdCount",
3034 "logonCount",
3035 "userAccountControl",
3036 NULL};
3037 attrs = attrs2;
3038 break;
3040 case 4:
3042 static const char * const attrs2[] = {"logonHours",
3043 NULL};
3044 attrs = attrs2;
3045 break;
3047 case 5:
3049 static const char * const attrs2[] = {"sAMAccountName",
3050 "displayName",
3051 "objectSid",
3052 "primaryGroupID",
3053 "homeDirectory",
3054 "homeDrive",
3055 "scriptPath",
3056 "profilePath",
3057 "description",
3058 "userWorkstations",
3059 "lastLogon",
3060 "lastLogoff",
3061 "logonHours",
3062 "badPwdCount",
3063 "logonCount",
3064 "pwdLastSet",
3065 "accountExpires",
3066 "userAccountControl",
3067 NULL};
3068 attrs = attrs2;
3069 break;
3071 case 6:
3073 static const char * const attrs2[] = {"sAMAccountName",
3074 "displayName",
3075 NULL};
3076 attrs = attrs2;
3077 break;
3079 case 7:
3081 static const char * const attrs2[] = {"sAMAccountName",
3082 NULL};
3083 attrs = attrs2;
3084 break;
3086 case 8:
3088 static const char * const attrs2[] = {"displayName",
3089 NULL};
3090 attrs = attrs2;
3091 break;
3093 case 9:
3095 static const char * const attrs2[] = {"primaryGroupID",
3096 NULL};
3097 attrs = attrs2;
3098 break;
3100 case 10:
3102 static const char * const attrs2[] = {"homeDirectory",
3103 "homeDrive",
3104 NULL};
3105 attrs = attrs2;
3106 break;
3108 case 11:
3110 static const char * const attrs2[] = {"scriptPath",
3111 NULL};
3112 attrs = attrs2;
3113 break;
3115 case 12:
3117 static const char * const attrs2[] = {"profilePath",
3118 NULL};
3119 attrs = attrs2;
3120 break;
3122 case 13:
3124 static const char * const attrs2[] = {"description",
3125 NULL};
3126 attrs = attrs2;
3127 break;
3129 case 14:
3131 static const char * const attrs2[] = {"userWorkstations",
3132 NULL};
3133 attrs = attrs2;
3134 break;
3136 case 16:
3138 static const char * const attrs2[] = {"userAccountControl",
3139 "pwdLastSet",
3140 NULL};
3141 attrs = attrs2;
3142 break;
3144 case 17:
3146 static const char * const attrs2[] = {"accountExpires",
3147 NULL};
3148 attrs = attrs2;
3149 break;
3151 case 20:
3153 static const char * const attrs2[] = {"userParameters",
3154 NULL};
3155 attrs = attrs2;
3156 break;
3158 case 21:
3160 static const char * const attrs2[] = {"lastLogon",
3161 "lastLogoff",
3162 "pwdLastSet",
3163 "accountExpires",
3164 "sAMAccountName",
3165 "displayName",
3166 "homeDirectory",
3167 "homeDrive",
3168 "scriptPath",
3169 "profilePath",
3170 "description",
3171 "userWorkstations",
3172 "comment",
3173 "userParameters",
3174 "objectSid",
3175 "primaryGroupID",
3176 "userAccountControl",
3177 "logonHours",
3178 "badPwdCount",
3179 "logonCount",
3180 "countryCode",
3181 "codePage",
3182 NULL};
3183 attrs = attrs2;
3184 break;
3188 /* pull all the user attributes */
3189 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3190 a_state->account_dn ,&res, attrs);
3191 if (ret != 1) {
3192 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3194 msg = res[0];
3196 /* allocate the info structure */
3197 info = talloc_zero(mem_ctx, union samr_UserInfo);
3198 if (info == NULL) {
3199 return NT_STATUS_NO_MEMORY;
3202 /* fill in the reply */
3203 switch (r->in.level) {
3204 case 1:
3205 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3206 QUERY_STRING(msg, info1.full_name, "displayName");
3207 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3208 QUERY_STRING(msg, info1.description, "description");
3209 QUERY_STRING(msg, info1.comment, "comment");
3210 break;
3212 case 2:
3213 QUERY_STRING(msg, info2.comment, "comment");
3214 QUERY_UINT (msg, info2.country_code, "countryCode");
3215 QUERY_UINT (msg, info2.code_page, "codePage");
3216 break;
3218 case 3:
3219 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3220 QUERY_STRING(msg, info3.full_name, "displayName");
3221 QUERY_RID (msg, info3.rid, "objectSid");
3222 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3223 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3224 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3225 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3226 QUERY_STRING(msg, info3.profile_path, "profilePath");
3227 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3228 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3229 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3230 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3231 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3232 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3233 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3234 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3235 QUERY_UINT (msg, info3.logon_count, "logonCount");
3236 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3237 break;
3239 case 4:
3240 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3241 break;
3243 case 5:
3244 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3245 QUERY_STRING(msg, info5.full_name, "displayName");
3246 QUERY_RID (msg, info5.rid, "objectSid");
3247 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3248 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3249 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3250 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3251 QUERY_STRING(msg, info5.profile_path, "profilePath");
3252 QUERY_STRING(msg, info5.description, "description");
3253 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3254 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3255 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3256 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3257 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3258 QUERY_UINT (msg, info5.logon_count, "logonCount");
3259 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3260 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3261 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3262 break;
3264 case 6:
3265 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3266 QUERY_STRING(msg, info6.full_name, "displayName");
3267 break;
3269 case 7:
3270 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3271 break;
3273 case 8:
3274 QUERY_STRING(msg, info8.full_name, "displayName");
3275 break;
3277 case 9:
3278 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3279 break;
3281 case 10:
3282 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3283 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3284 break;
3286 case 11:
3287 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3288 break;
3290 case 12:
3291 QUERY_STRING(msg, info12.profile_path, "profilePath");
3292 break;
3294 case 13:
3295 QUERY_STRING(msg, info13.description, "description");
3296 break;
3298 case 14:
3299 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3300 break;
3302 case 16:
3303 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3304 break;
3306 case 17:
3307 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3308 break;
3310 case 20:
3311 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3312 break;
3314 case 21:
3315 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3316 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3317 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3318 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3319 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3320 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3321 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3322 QUERY_STRING(msg, info21.full_name, "displayName");
3323 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3324 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3325 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3326 QUERY_STRING(msg, info21.profile_path, "profilePath");
3327 QUERY_STRING(msg, info21.description, "description");
3328 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3329 QUERY_STRING(msg, info21.comment, "comment");
3330 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3331 QUERY_RID (msg, info21.rid, "objectSid");
3332 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3333 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3334 info->info21.fields_present = 0x00FFFFFF;
3335 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3336 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3337 QUERY_UINT (msg, info21.logon_count, "logonCount");
3338 QUERY_UINT (msg, info21.country_code, "countryCode");
3339 QUERY_UINT (msg, info21.code_page, "codePage");
3340 break;
3343 default:
3344 talloc_free(info);
3345 return NT_STATUS_INVALID_INFO_CLASS;
3348 *r->out.info = info;
3350 return NT_STATUS_OK;
3355 samr_SetUserInfo
3357 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3358 struct samr_SetUserInfo *r)
3360 struct dcesrv_handle *h;
3361 struct samr_account_state *a_state;
3362 struct ldb_message *msg;
3363 int ret;
3364 NTSTATUS status = NT_STATUS_OK;
3365 struct ldb_context *sam_ctx;
3367 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3369 a_state = h->data;
3370 sam_ctx = a_state->sam_ctx;
3372 msg = ldb_msg_new(mem_ctx);
3373 if (msg == NULL) {
3374 return NT_STATUS_NO_MEMORY;
3377 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3378 if (!msg->dn) {
3379 return NT_STATUS_NO_MEMORY;
3382 switch (r->in.level) {
3383 case 2:
3384 SET_STRING(msg, info2.comment, "comment");
3385 SET_UINT (msg, info2.country_code, "countryCode");
3386 SET_UINT (msg, info2.code_page, "codePage");
3387 break;
3389 case 4:
3390 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3391 break;
3393 case 6:
3394 SET_STRING(msg, info6.account_name, "samAccountName");
3395 SET_STRING(msg, info6.full_name, "displayName");
3396 break;
3398 case 7:
3399 SET_STRING(msg, info7.account_name, "samAccountName");
3400 break;
3402 case 8:
3403 SET_STRING(msg, info8.full_name, "displayName");
3404 break;
3406 case 9:
3407 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3408 break;
3410 case 10:
3411 SET_STRING(msg, info10.home_directory, "homeDirectory");
3412 SET_STRING(msg, info10.home_drive, "homeDrive");
3413 break;
3415 case 11:
3416 SET_STRING(msg, info11.logon_script, "scriptPath");
3417 break;
3419 case 12:
3420 SET_STRING(msg, info12.profile_path, "profilePath");
3421 break;
3423 case 13:
3424 SET_STRING(msg, info13.description, "description");
3425 break;
3427 case 14:
3428 SET_STRING(msg, info14.workstations, "userWorkstations");
3429 break;
3431 case 16:
3432 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3433 break;
3435 case 17:
3436 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3437 break;
3439 case 20:
3440 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3441 break;
3443 case 21:
3444 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3445 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3446 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3447 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3448 SET_STRING(msg, info21.account_name, "samAccountName");
3449 IFSET(SAMR_FIELD_FULL_NAME)
3450 SET_STRING(msg, info21.full_name, "displayName");
3451 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3452 SET_STRING(msg, info21.home_directory, "homeDirectory");
3453 IFSET(SAMR_FIELD_HOME_DRIVE)
3454 SET_STRING(msg, info21.home_drive, "homeDrive");
3455 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3456 SET_STRING(msg, info21.logon_script, "scriptPath");
3457 IFSET(SAMR_FIELD_PROFILE_PATH)
3458 SET_STRING(msg, info21.profile_path, "profilePath");
3459 IFSET(SAMR_FIELD_DESCRIPTION)
3460 SET_STRING(msg, info21.description, "description");
3461 IFSET(SAMR_FIELD_WORKSTATIONS)
3462 SET_STRING(msg, info21.workstations, "userWorkstations");
3463 IFSET(SAMR_FIELD_COMMENT)
3464 SET_STRING(msg, info21.comment, "comment");
3465 IFSET(SAMR_FIELD_PARAMETERS)
3466 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3467 IFSET(SAMR_FIELD_PRIMARY_GID)
3468 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3469 IFSET(SAMR_FIELD_ACCT_FLAGS)
3470 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3471 IFSET(SAMR_FIELD_LOGON_HOURS)
3472 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3473 IFSET(SAMR_FIELD_COUNTRY_CODE)
3474 SET_UINT (msg, info21.country_code, "countryCode");
3475 IFSET(SAMR_FIELD_CODE_PAGE)
3476 SET_UINT (msg, info21.code_page, "codePage");
3477 #undef IFSET
3478 break;
3480 case 23:
3481 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3482 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3483 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3484 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3485 SET_STRING(msg, info23.info.account_name, "samAccountName");
3486 IFSET(SAMR_FIELD_FULL_NAME)
3487 SET_STRING(msg, info23.info.full_name, "displayName");
3488 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3489 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3490 IFSET(SAMR_FIELD_HOME_DRIVE)
3491 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3492 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3493 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3494 IFSET(SAMR_FIELD_PROFILE_PATH)
3495 SET_STRING(msg, info23.info.profile_path, "profilePath");
3496 IFSET(SAMR_FIELD_DESCRIPTION)
3497 SET_STRING(msg, info23.info.description, "description");
3498 IFSET(SAMR_FIELD_WORKSTATIONS)
3499 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3500 IFSET(SAMR_FIELD_COMMENT)
3501 SET_STRING(msg, info23.info.comment, "comment");
3502 IFSET(SAMR_FIELD_PARAMETERS)
3503 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3504 IFSET(SAMR_FIELD_PRIMARY_GID)
3505 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3506 IFSET(SAMR_FIELD_ACCT_FLAGS)
3507 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3508 IFSET(SAMR_FIELD_LOGON_HOURS)
3509 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3510 IFSET(SAMR_FIELD_COUNTRY_CODE)
3511 SET_UINT (msg, info23.info.country_code, "countryCode");
3512 IFSET(SAMR_FIELD_CODE_PAGE)
3513 SET_UINT (msg, info23.info.code_page, "codePage");
3515 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3516 status = samr_set_password(dce_call,
3517 a_state->sam_ctx,
3518 a_state->account_dn,
3519 a_state->domain_state->domain_dn,
3520 mem_ctx, msg,
3521 &r->in.info->info23.password);
3522 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3523 status = samr_set_password(dce_call,
3524 a_state->sam_ctx,
3525 a_state->account_dn,
3526 a_state->domain_state->domain_dn,
3527 mem_ctx, msg,
3528 &r->in.info->info23.password);
3530 #undef IFSET
3531 break;
3533 /* the set password levels are handled separately */
3534 case 24:
3535 status = samr_set_password(dce_call,
3536 a_state->sam_ctx,
3537 a_state->account_dn,
3538 a_state->domain_state->domain_dn,
3539 mem_ctx, msg,
3540 &r->in.info->info24.password);
3541 break;
3543 case 25:
3544 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3545 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3546 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3547 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3548 SET_STRING(msg, info25.info.account_name, "samAccountName");
3549 IFSET(SAMR_FIELD_FULL_NAME)
3550 SET_STRING(msg, info25.info.full_name, "displayName");
3551 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3552 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3553 IFSET(SAMR_FIELD_HOME_DRIVE)
3554 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3555 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3556 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3557 IFSET(SAMR_FIELD_PROFILE_PATH)
3558 SET_STRING(msg, info25.info.profile_path, "profilePath");
3559 IFSET(SAMR_FIELD_DESCRIPTION)
3560 SET_STRING(msg, info25.info.description, "description");
3561 IFSET(SAMR_FIELD_WORKSTATIONS)
3562 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3563 IFSET(SAMR_FIELD_COMMENT)
3564 SET_STRING(msg, info25.info.comment, "comment");
3565 IFSET(SAMR_FIELD_PARAMETERS)
3566 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3567 IFSET(SAMR_FIELD_PRIMARY_GID)
3568 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3569 IFSET(SAMR_FIELD_ACCT_FLAGS)
3570 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3571 IFSET(SAMR_FIELD_LOGON_HOURS)
3572 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3573 IFSET(SAMR_FIELD_COUNTRY_CODE)
3574 SET_UINT (msg, info25.info.country_code, "countryCode");
3575 IFSET(SAMR_FIELD_CODE_PAGE)
3576 SET_UINT (msg, info25.info.code_page, "codePage");
3578 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3579 status = samr_set_password_ex(dce_call,
3580 a_state->sam_ctx,
3581 a_state->account_dn,
3582 a_state->domain_state->domain_dn,
3583 mem_ctx, msg,
3584 &r->in.info->info25.password);
3585 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3586 status = samr_set_password_ex(dce_call,
3587 a_state->sam_ctx,
3588 a_state->account_dn,
3589 a_state->domain_state->domain_dn,
3590 mem_ctx, msg,
3591 &r->in.info->info25.password);
3593 #undef IFSET
3594 break;
3596 /* the set password levels are handled separately */
3597 case 26:
3598 status = samr_set_password_ex(dce_call,
3599 a_state->sam_ctx,
3600 a_state->account_dn,
3601 a_state->domain_state->domain_dn,
3602 mem_ctx, msg,
3603 &r->in.info->info26.password);
3604 break;
3607 default:
3608 /* many info classes are not valid for SetUserInfo */
3609 return NT_STATUS_INVALID_INFO_CLASS;
3612 if (!NT_STATUS_IS_OK(status)) {
3613 return status;
3616 /* modify the samdb record */
3617 if (msg->num_elements > 0) {
3618 ret = ldb_modify(a_state->sam_ctx, msg);
3619 if (ret != LDB_SUCCESS) {
3620 DEBUG(1,("Failed to modify record %s: %s\n",
3621 ldb_dn_get_linearized(a_state->account_dn),
3622 ldb_errstring(a_state->sam_ctx)));
3624 /* we really need samdb.c to return NTSTATUS */
3625 return NT_STATUS_UNSUCCESSFUL;
3629 return NT_STATUS_OK;
3634 samr_GetGroupsForUser
3636 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3637 struct samr_GetGroupsForUser *r)
3639 struct dcesrv_handle *h;
3640 struct samr_account_state *a_state;
3641 struct samr_domain_state *d_state;
3642 struct ldb_message **res;
3643 const char * const attrs[2] = { "objectSid", NULL };
3644 struct samr_RidWithAttributeArray *array;
3645 int i, count;
3647 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3649 a_state = h->data;
3650 d_state = a_state->domain_state;
3652 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3653 d_state->domain_dn, &res,
3654 attrs, d_state->domain_sid,
3655 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3656 ldb_dn_get_linearized(a_state->account_dn),
3657 GTYPE_SECURITY_GLOBAL_GROUP);
3658 if (count < 0)
3659 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3661 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3662 if (array == NULL)
3663 return NT_STATUS_NO_MEMORY;
3665 array->count = 0;
3666 array->rids = NULL;
3668 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3669 count + 1);
3670 if (array->rids == NULL)
3671 return NT_STATUS_NO_MEMORY;
3673 /* Adds the primary group */
3674 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3675 ~0, a_state->account_dn,
3676 "primaryGroupID", NULL);
3677 array->rids[0].attributes = SE_GROUP_MANDATORY
3678 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3679 array->count += 1;
3681 /* Adds the additional groups */
3682 for (i = 0; i < count; i++) {
3683 struct dom_sid *group_sid;
3685 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3686 if (group_sid == NULL) {
3687 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3688 continue;
3691 array->rids[i + 1].rid =
3692 group_sid->sub_auths[group_sid->num_auths-1];
3693 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3694 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3695 array->count += 1;
3698 *r->out.rids = array;
3700 return NT_STATUS_OK;
3705 samr_QueryDisplayInfo
3707 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3708 struct samr_QueryDisplayInfo *r)
3710 struct dcesrv_handle *h;
3711 struct samr_domain_state *d_state;
3712 struct ldb_message **res;
3713 int ldb_cnt, count, i;
3714 const char * const attrs[] = { "objectSid", "sAMAccountName",
3715 "displayName", "description", "userAccountControl",
3716 "pwdLastSet", NULL };
3717 struct samr_DispEntryFull *entriesFull = NULL;
3718 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3719 struct samr_DispEntryAscii *entriesAscii = NULL;
3720 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3721 const char *filter;
3723 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3725 d_state = h->data;
3727 switch (r->in.level) {
3728 case 1:
3729 case 4:
3730 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3731 "(sAMAccountType=%u))",
3732 ATYPE_NORMAL_ACCOUNT);
3733 break;
3734 case 2:
3735 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3736 "(sAMAccountType=%u))",
3737 ATYPE_WORKSTATION_TRUST);
3738 break;
3739 case 3:
3740 case 5:
3741 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3742 "(objectclass=group))",
3743 GTYPE_SECURITY_GLOBAL_GROUP);
3744 break;
3745 default:
3746 return NT_STATUS_INVALID_INFO_CLASS;
3749 /* search for all requested objects in this domain. This could
3750 possibly be cached and resumed based on resume_key */
3751 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3752 d_state->domain_dn, &res, attrs,
3753 d_state->domain_sid, "%s", filter);
3754 if (ldb_cnt == -1) {
3755 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3757 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3758 return NT_STATUS_OK;
3761 switch (r->in.level) {
3762 case 1:
3763 entriesGeneral = talloc_array(mem_ctx,
3764 struct samr_DispEntryGeneral,
3765 ldb_cnt);
3766 break;
3767 case 2:
3768 entriesFull = talloc_array(mem_ctx,
3769 struct samr_DispEntryFull,
3770 ldb_cnt);
3771 break;
3772 case 3:
3773 entriesFullGroup = talloc_array(mem_ctx,
3774 struct samr_DispEntryFullGroup,
3775 ldb_cnt);
3776 break;
3777 case 4:
3778 case 5:
3779 entriesAscii = talloc_array(mem_ctx,
3780 struct samr_DispEntryAscii,
3781 ldb_cnt);
3782 break;
3785 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3786 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3787 return NT_STATUS_NO_MEMORY;
3789 count = 0;
3791 for (i=0; i<ldb_cnt; i++) {
3792 struct dom_sid *objectsid;
3794 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3795 "objectSid");
3796 if (objectsid == NULL)
3797 continue;
3799 switch(r->in.level) {
3800 case 1:
3801 entriesGeneral[count].idx = count + 1;
3802 entriesGeneral[count].rid =
3803 objectsid->sub_auths[objectsid->num_auths-1];
3804 entriesGeneral[count].acct_flags =
3805 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3806 res[i],
3807 d_state->domain_dn);
3808 entriesGeneral[count].account_name.string =
3809 samdb_result_string(res[i],
3810 "sAMAccountName", "");
3811 entriesGeneral[count].full_name.string =
3812 samdb_result_string(res[i], "displayName", "");
3813 entriesGeneral[count].description.string =
3814 samdb_result_string(res[i], "description", "");
3815 break;
3816 case 2:
3817 entriesFull[count].idx = count + 1;
3818 entriesFull[count].rid =
3819 objectsid->sub_auths[objectsid->num_auths-1];
3821 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3822 entriesFull[count].acct_flags =
3823 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3824 res[i],
3825 d_state->domain_dn) | ACB_NORMAL;
3826 entriesFull[count].account_name.string =
3827 samdb_result_string(res[i], "sAMAccountName",
3828 "");
3829 entriesFull[count].description.string =
3830 samdb_result_string(res[i], "description", "");
3831 break;
3832 case 3:
3833 entriesFullGroup[count].idx = count + 1;
3834 entriesFullGroup[count].rid =
3835 objectsid->sub_auths[objectsid->num_auths-1];
3836 /* We get a "7" here for groups */
3837 entriesFullGroup[count].acct_flags
3838 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3839 entriesFullGroup[count].account_name.string =
3840 samdb_result_string(res[i], "sAMAccountName",
3841 "");
3842 entriesFullGroup[count].description.string =
3843 samdb_result_string(res[i], "description", "");
3844 break;
3845 case 4:
3846 case 5:
3847 entriesAscii[count].idx = count + 1;
3848 entriesAscii[count].account_name.string =
3849 samdb_result_string(res[i], "sAMAccountName",
3850 "");
3851 break;
3854 count += 1;
3857 *r->out.total_size = count;
3859 if (r->in.start_idx >= count) {
3860 *r->out.returned_size = 0;
3861 switch(r->in.level) {
3862 case 1:
3863 r->out.info->info1.count = *r->out.returned_size;
3864 r->out.info->info1.entries = NULL;
3865 break;
3866 case 2:
3867 r->out.info->info2.count = *r->out.returned_size;
3868 r->out.info->info2.entries = NULL;
3869 break;
3870 case 3:
3871 r->out.info->info3.count = *r->out.returned_size;
3872 r->out.info->info3.entries = NULL;
3873 break;
3874 case 4:
3875 r->out.info->info4.count = *r->out.returned_size;
3876 r->out.info->info4.entries = NULL;
3877 break;
3878 case 5:
3879 r->out.info->info5.count = *r->out.returned_size;
3880 r->out.info->info5.entries = NULL;
3881 break;
3883 } else {
3884 *r->out.returned_size = MIN(count - r->in.start_idx,
3885 r->in.max_entries);
3886 switch(r->in.level) {
3887 case 1:
3888 r->out.info->info1.count = *r->out.returned_size;
3889 r->out.info->info1.entries =
3890 &(entriesGeneral[r->in.start_idx]);
3891 break;
3892 case 2:
3893 r->out.info->info2.count = *r->out.returned_size;
3894 r->out.info->info2.entries =
3895 &(entriesFull[r->in.start_idx]);
3896 break;
3897 case 3:
3898 r->out.info->info3.count = *r->out.returned_size;
3899 r->out.info->info3.entries =
3900 &(entriesFullGroup[r->in.start_idx]);
3901 break;
3902 case 4:
3903 r->out.info->info4.count = *r->out.returned_size;
3904 r->out.info->info4.entries =
3905 &(entriesAscii[r->in.start_idx]);
3906 break;
3907 case 5:
3908 r->out.info->info5.count = *r->out.returned_size;
3909 r->out.info->info5.entries =
3910 &(entriesAscii[r->in.start_idx]);
3911 break;
3915 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3916 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3921 samr_GetDisplayEnumerationIndex
3923 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3924 struct samr_GetDisplayEnumerationIndex *r)
3926 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3931 samr_TestPrivateFunctionsDomain
3933 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3934 struct samr_TestPrivateFunctionsDomain *r)
3936 return NT_STATUS_NOT_IMPLEMENTED;
3941 samr_TestPrivateFunctionsUser
3943 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3944 struct samr_TestPrivateFunctionsUser *r)
3946 return NT_STATUS_NOT_IMPLEMENTED;
3951 samr_GetUserPwInfo
3953 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3954 struct samr_GetUserPwInfo *r)
3956 struct dcesrv_handle *h;
3957 struct samr_account_state *a_state;
3959 ZERO_STRUCTP(r->out.info);
3961 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3963 a_state = h->data;
3965 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3966 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3967 NULL);
3968 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3969 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3971 return NT_STATUS_OK;
3976 samr_RemoveMemberFromForeignDomain
3978 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3979 struct samr_RemoveMemberFromForeignDomain *r)
3981 struct dcesrv_handle *h;
3982 struct samr_domain_state *d_state;
3983 const char *memberdn;
3984 struct ldb_message **res;
3985 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3986 int i, count;
3988 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3990 d_state = h->data;
3992 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3993 "distinguishedName", "(objectSid=%s)",
3994 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3995 /* Nothing to do */
3996 if (memberdn == NULL) {
3997 return NT_STATUS_OK;
4000 /* TODO: Does this call only remove alias members, or does it do this
4001 * for domain groups as well? */
4003 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4004 d_state->domain_dn, &res, attrs,
4005 d_state->domain_sid,
4006 "(&(member=%s)(objectClass=group)"
4007 "(|(groupType=%d)(groupType=%d)))",
4008 memberdn,
4009 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4010 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4012 if (count < 0)
4013 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4015 for (i=0; i<count; i++) {
4016 struct ldb_message *mod;
4018 mod = ldb_msg_new(mem_ctx);
4019 if (mod == NULL) {
4020 return NT_STATUS_NO_MEMORY;
4023 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4024 if (mod->dn == NULL) {
4025 talloc_free(mod);
4026 continue;
4029 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4030 "member", memberdn) != 0)
4031 return NT_STATUS_NO_MEMORY;
4033 if (ldb_modify(d_state->sam_ctx, mod) != 0)
4034 return NT_STATUS_UNSUCCESSFUL;
4036 talloc_free(mod);
4039 return NT_STATUS_OK;
4044 samr_QueryDomainInfo2
4046 just an alias for samr_QueryDomainInfo
4048 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4049 struct samr_QueryDomainInfo2 *r)
4051 struct samr_QueryDomainInfo r1;
4052 NTSTATUS status;
4054 ZERO_STRUCT(r1.out);
4055 r1.in.domain_handle = r->in.domain_handle;
4056 r1.in.level = r->in.level;
4057 r1.out.info = r->out.info;
4059 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4061 return status;
4066 samr_QueryUserInfo2
4068 just an alias for samr_QueryUserInfo
4070 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4071 struct samr_QueryUserInfo2 *r)
4073 struct samr_QueryUserInfo r1;
4074 NTSTATUS status;
4076 r1.in.user_handle = r->in.user_handle;
4077 r1.in.level = r->in.level;
4078 r1.out.info = r->out.info;
4080 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4082 return status;
4087 samr_QueryDisplayInfo2
4089 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4090 struct samr_QueryDisplayInfo2 *r)
4092 struct samr_QueryDisplayInfo q;
4093 NTSTATUS result;
4095 q.in.domain_handle = r->in.domain_handle;
4096 q.in.level = r->in.level;
4097 q.in.start_idx = r->in.start_idx;
4098 q.in.max_entries = r->in.max_entries;
4099 q.in.buf_size = r->in.buf_size;
4100 q.out.total_size = r->out.total_size;
4101 q.out.returned_size = r->out.returned_size;
4102 q.out.info = r->out.info;
4104 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4106 return result;
4111 samr_GetDisplayEnumerationIndex2
4113 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4114 struct samr_GetDisplayEnumerationIndex2 *r)
4116 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4121 samr_QueryDisplayInfo3
4123 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4124 struct samr_QueryDisplayInfo3 *r)
4126 struct samr_QueryDisplayInfo q;
4127 NTSTATUS result;
4129 q.in.domain_handle = r->in.domain_handle;
4130 q.in.level = r->in.level;
4131 q.in.start_idx = r->in.start_idx;
4132 q.in.max_entries = r->in.max_entries;
4133 q.in.buf_size = r->in.buf_size;
4134 q.out.total_size = r->out.total_size;
4135 q.out.returned_size = r->out.returned_size;
4136 q.out.info = r->out.info;
4138 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4140 return result;
4145 samr_AddMultipleMembersToAlias
4147 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4148 struct samr_AddMultipleMembersToAlias *r)
4150 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4155 samr_RemoveMultipleMembersFromAlias
4157 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4158 struct samr_RemoveMultipleMembersFromAlias *r)
4160 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4165 samr_GetDomPwInfo
4167 this fetches the default password properties for a domain
4169 note that w2k3 completely ignores the domain name in this call, and
4170 always returns the information for the servers primary domain
4172 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4173 struct samr_GetDomPwInfo *r)
4175 struct ldb_message **msgs;
4176 int ret;
4177 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4178 struct ldb_context *sam_ctx;
4180 ZERO_STRUCTP(r->out.info);
4182 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4183 dce_call->conn->dce_ctx->lp_ctx,
4184 dce_call->conn->auth_state.session_info);
4185 if (sam_ctx == NULL) {
4186 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4189 /* The domain name in this call is ignored */
4190 ret = gendb_search_dn(sam_ctx,
4191 mem_ctx, NULL, &msgs, attrs);
4192 if (ret <= 0) {
4193 talloc_free(sam_ctx);
4195 return NT_STATUS_NO_SUCH_DOMAIN;
4197 if (ret > 1) {
4198 talloc_free(msgs);
4199 talloc_free(sam_ctx);
4201 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4204 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4205 "minPwdLength", 0);
4206 r->out.info->password_properties = samdb_result_uint(msgs[0],
4207 "pwdProperties", 1);
4209 talloc_free(msgs);
4210 talloc_unlink(mem_ctx, sam_ctx);
4212 return NT_STATUS_OK;
4217 samr_Connect2
4219 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4220 struct samr_Connect2 *r)
4222 struct samr_Connect c;
4224 c.in.system_name = NULL;
4225 c.in.access_mask = r->in.access_mask;
4226 c.out.connect_handle = r->out.connect_handle;
4228 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4233 samr_SetUserInfo2
4235 just an alias for samr_SetUserInfo
4237 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4238 struct samr_SetUserInfo2 *r)
4240 struct samr_SetUserInfo r2;
4242 r2.in.user_handle = r->in.user_handle;
4243 r2.in.level = r->in.level;
4244 r2.in.info = r->in.info;
4246 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4251 samr_SetBootKeyInformation
4253 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4254 struct samr_SetBootKeyInformation *r)
4256 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4261 samr_GetBootKeyInformation
4263 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4264 struct samr_GetBootKeyInformation *r)
4266 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4271 samr_Connect3
4273 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4274 struct samr_Connect3 *r)
4276 struct samr_Connect c;
4278 c.in.system_name = NULL;
4279 c.in.access_mask = r->in.access_mask;
4280 c.out.connect_handle = r->out.connect_handle;
4282 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4287 samr_Connect4
4289 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4290 struct samr_Connect4 *r)
4292 struct samr_Connect c;
4294 c.in.system_name = NULL;
4295 c.in.access_mask = r->in.access_mask;
4296 c.out.connect_handle = r->out.connect_handle;
4298 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4303 samr_Connect5
4305 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4306 struct samr_Connect5 *r)
4308 struct samr_Connect c;
4309 NTSTATUS status;
4311 c.in.system_name = NULL;
4312 c.in.access_mask = r->in.access_mask;
4313 c.out.connect_handle = r->out.connect_handle;
4315 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4317 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4318 r->out.info_out->info1.unknown2 = 0;
4319 *r->out.level_out = r->in.level_in;
4321 return status;
4326 samr_RidToSid
4328 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4329 struct samr_RidToSid *r)
4331 struct samr_domain_state *d_state;
4332 struct dcesrv_handle *h;
4334 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4336 d_state = h->data;
4338 /* form the users SID */
4339 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4340 if (!*r->out.sid) {
4341 return NT_STATUS_NO_MEMORY;
4344 return NT_STATUS_OK;
4349 samr_SetDsrmPassword
4351 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4352 struct samr_SetDsrmPassword *r)
4354 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4359 samr_ValidatePassword
4361 For now the call checks the password complexity (if active) and the minimum
4362 password length on level 2 and 3. Level 1 is ignored for now.
4364 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4365 TALLOC_CTX *mem_ctx,
4366 struct samr_ValidatePassword *r)
4368 struct samr_GetDomPwInfo r2;
4369 DATA_BLOB password;
4370 enum samr_ValidationStatus res;
4371 NTSTATUS status;
4373 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4375 r2.in.domain_name = NULL;
4376 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4377 if (!NT_STATUS_IS_OK(status)) {
4378 return status;
4381 switch (r->in.level) {
4382 case NetValidateAuthentication:
4383 /* we don't support this yet */
4384 return NT_STATUS_NOT_SUPPORTED;
4385 break;
4386 case NetValidatePasswordChange:
4387 password = data_blob_const(r->in.req->req2.password.string,
4388 r->in.req->req2.password.length);
4389 res = samdb_check_password(mem_ctx,
4390 dce_call->conn->dce_ctx->lp_ctx,
4391 &password,
4392 r2.out.info->password_properties,
4393 r2.out.info->min_password_length);
4394 (*r->out.rep)->ctr2.status = res;
4395 break;
4396 case NetValidatePasswordReset:
4397 password = data_blob_const(r->in.req->req3.password.string,
4398 r->in.req->req3.password.length);
4399 res = samdb_check_password(mem_ctx,
4400 dce_call->conn->dce_ctx->lp_ctx,
4401 &password,
4402 r2.out.info->password_properties,
4403 r2.out.info->min_password_length);
4404 (*r->out.rep)->ctr3.status = res;
4405 break;
4408 return NT_STATUS_OK;
4412 /* include the generated boilerplate */
4413 #include "librpc/gen_ndr/ndr_samr_s.c"