s4:samdb_set_password/samdb_set_password_sid - Rework
[Samba/ekacnet.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob5775b1410ff7461f4ddf72614683824c3100bb15
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"
40 #include "lib/util/tsort.h"
42 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
44 #define QUERY_STRING(msg, field, attr) \
45 info->field.string = samdb_result_string(msg, attr, "");
46 #define QUERY_UINT(msg, field, attr) \
47 info->field = samdb_result_uint(msg, attr, 0);
48 #define QUERY_RID(msg, field, attr) \
49 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
50 #define QUERY_UINT64(msg, field, attr) \
51 info->field = samdb_result_uint64(msg, attr, 0);
52 #define QUERY_APASSC(msg, field, attr) \
53 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
54 a_state->domain_state->domain_dn, msg, attr);
55 #define QUERY_FPASSC(msg, field, attr) \
56 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
57 a_state->domain_state->domain_dn, msg);
58 #define QUERY_LHOURS(msg, field, attr) \
59 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
60 #define QUERY_AFLAGS(msg, field, attr) \
61 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
62 #define QUERY_PARAMETERS(msg, field, attr) \
63 info->field = samdb_result_parameters(mem_ctx, msg, attr);
66 /* these are used to make the Set[User|Group]Info code easier to follow */
68 #define SET_STRING(msg, field, attr) do { \
69 struct ldb_message_element *set_el; \
70 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
71 if (r->in.info->field.string[0] == '\0') { \
72 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
73 return NT_STATUS_NO_MEMORY; \
74 } \
75 } \
76 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
77 return NT_STATUS_NO_MEMORY; \
78 } \
79 set_el = ldb_msg_find_element(msg, attr); \
80 set_el->flags = LDB_FLAG_MOD_REPLACE; \
81 } while (0)
83 #define SET_UINT(msg, field, attr) do { \
84 struct ldb_message_element *set_el; \
85 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
86 return NT_STATUS_NO_MEMORY; \
87 } \
88 set_el = ldb_msg_find_element(msg, attr); \
89 set_el->flags = LDB_FLAG_MOD_REPLACE; \
90 } while (0)
92 #define SET_INT64(msg, field, attr) do { \
93 struct ldb_message_element *set_el; \
94 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
95 return NT_STATUS_NO_MEMORY; \
96 } \
97 set_el = ldb_msg_find_element(msg, attr); \
98 set_el->flags = LDB_FLAG_MOD_REPLACE; \
99 } while (0)
101 #define SET_UINT64(msg, field, attr) do { \
102 struct ldb_message_element *set_el; \
103 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
104 return NT_STATUS_NO_MEMORY; \
106 set_el = ldb_msg_find_element(msg, attr); \
107 set_el->flags = LDB_FLAG_MOD_REPLACE; \
108 } while (0)
110 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
111 do { \
112 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
113 return NT_STATUS_INVALID_PARAMETER; \
115 } while (0) \
117 /* Set account flags, discarding flags that cannot be set with SAMR */
118 #define SET_AFLAGS(msg, field, attr) do { \
119 struct ldb_message_element *set_el; \
120 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
121 return NT_STATUS_INVALID_PARAMETER; \
123 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
128 return NT_STATUS_NO_MEMORY; \
130 set_el = ldb_msg_find_element(msg, attr); \
131 set_el->flags = LDB_FLAG_MOD_REPLACE; \
132 } while (0)
134 #define SET_LHOURS(msg, field, attr) do { \
135 struct ldb_message_element *set_el; \
136 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
137 return NT_STATUS_NO_MEMORY; \
139 set_el = ldb_msg_find_element(msg, attr); \
140 set_el->flags = LDB_FLAG_MOD_REPLACE; \
141 } while (0)
143 #define SET_PARAMETERS(msg, field, attr) do { \
144 struct ldb_message_element *set_el; \
145 if (r->in.info->field.length != 0) { \
146 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
147 return NT_STATUS_NO_MEMORY; \
149 set_el = ldb_msg_find_element(msg, attr); \
150 set_el->flags = LDB_FLAG_MOD_REPLACE; \
152 } while (0)
157 samr_Connect
159 create a connection to the SAM database
161 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
162 struct samr_Connect *r)
164 struct samr_connect_state *c_state;
165 struct dcesrv_handle *handle;
167 ZERO_STRUCTP(r->out.connect_handle);
169 c_state = talloc(mem_ctx, struct samr_connect_state);
170 if (!c_state) {
171 return NT_STATUS_NO_MEMORY;
174 /* make sure the sam database is accessible */
175 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
176 if (c_state->sam_ctx == NULL) {
177 talloc_free(c_state);
178 return NT_STATUS_INVALID_SYSTEM_SERVICE;
182 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
183 if (!handle) {
184 talloc_free(c_state);
185 return NT_STATUS_NO_MEMORY;
188 handle->data = talloc_steal(handle, c_state);
190 c_state->access_mask = r->in.access_mask;
191 *r->out.connect_handle = handle->wire_handle;
193 return NT_STATUS_OK;
198 samr_Close
200 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
201 struct samr_Close *r)
203 struct dcesrv_handle *h;
205 *r->out.handle = *r->in.handle;
207 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
209 talloc_free(h);
211 ZERO_STRUCTP(r->out.handle);
213 return NT_STATUS_OK;
218 samr_SetSecurity
220 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
221 struct samr_SetSecurity *r)
223 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
228 samr_QuerySecurity
230 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
231 struct samr_QuerySecurity *r)
233 struct dcesrv_handle *h;
234 struct sec_desc_buf *sd;
236 *r->out.sdbuf = NULL;
238 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
240 sd = talloc(mem_ctx, struct sec_desc_buf);
241 if (sd == NULL) {
242 return NT_STATUS_NO_MEMORY;
245 sd->sd = samdb_default_security_descriptor(mem_ctx);
247 *r->out.sdbuf = sd;
249 return NT_STATUS_OK;
254 samr_Shutdown
256 we refuse this operation completely. If a admin wants to shutdown samr
257 in Samba then they should use the samba admin tools to disable the samr pipe
259 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
260 struct samr_Shutdown *r)
262 return NT_STATUS_ACCESS_DENIED;
267 samr_LookupDomain
269 this maps from a domain name to a SID
271 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
272 struct samr_LookupDomain *r)
274 struct samr_connect_state *c_state;
275 struct dcesrv_handle *h;
276 struct dom_sid *sid;
277 const char * const dom_attrs[] = { "objectSid", NULL};
278 struct ldb_message **dom_msgs;
279 int ret;
281 *r->out.sid = NULL;
283 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
285 c_state = h->data;
287 if (r->in.domain_name->string == NULL) {
288 return NT_STATUS_INVALID_PARAMETER;
291 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
292 ret = gendb_search(c_state->sam_ctx,
293 mem_ctx, NULL, &dom_msgs, dom_attrs,
294 "(objectClass=builtinDomain)");
295 } else if (strcasecmp_m(r->in.domain_name->string, lp_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
296 ret = gendb_search_dn(c_state->sam_ctx,
297 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
298 &dom_msgs, dom_attrs);
299 } else {
300 return NT_STATUS_NO_SUCH_DOMAIN;
302 if (ret != 1) {
303 return NT_STATUS_NO_SUCH_DOMAIN;
306 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
307 "objectSid");
309 if (sid == NULL) {
310 return NT_STATUS_NO_SUCH_DOMAIN;
313 *r->out.sid = sid;
315 return NT_STATUS_OK;
320 samr_EnumDomains
322 list the domains in the SAM
324 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
325 struct samr_EnumDomains *r)
327 struct samr_connect_state *c_state;
328 struct dcesrv_handle *h;
329 struct samr_SamArray *array;
330 uint32_t i, start_i;
332 *r->out.resume_handle = 0;
333 *r->out.sam = NULL;
334 *r->out.num_entries = 0;
336 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
338 c_state = h->data;
340 *r->out.resume_handle = 2;
342 start_i = *r->in.resume_handle;
344 if (start_i >= 2) {
345 /* search past end of list is not an error for this call */
346 return NT_STATUS_OK;
349 array = talloc(mem_ctx, struct samr_SamArray);
350 if (array == NULL) {
351 return NT_STATUS_NO_MEMORY;
354 array->count = 0;
355 array->entries = NULL;
357 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
358 if (array->entries == NULL) {
359 return NT_STATUS_NO_MEMORY;
362 for (i=0;i<2-start_i;i++) {
363 array->entries[i].idx = start_i + i;
364 if (i == 0) {
365 array->entries[i].name.string = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
366 } else {
367 array->entries[i].name.string = "BUILTIN";
371 *r->out.sam = array;
372 *r->out.num_entries = i;
373 array->count = *r->out.num_entries;
375 return NT_STATUS_OK;
380 samr_OpenDomain
382 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
383 struct samr_OpenDomain *r)
385 struct dcesrv_handle *h_conn, *h_domain;
386 struct samr_connect_state *c_state;
387 struct samr_domain_state *d_state;
388 const char * const dom_attrs[] = { "cn", NULL};
389 struct ldb_message **dom_msgs;
390 int ret;
392 ZERO_STRUCTP(r->out.domain_handle);
394 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
396 c_state = h_conn->data;
398 if (r->in.sid == NULL) {
399 return NT_STATUS_INVALID_PARAMETER;
402 d_state = talloc(mem_ctx, struct samr_domain_state);
403 if (!d_state) {
404 return NT_STATUS_NO_MEMORY;
407 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
409 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
410 d_state->builtin = true;
411 d_state->domain_name = "BUILTIN";
412 } else {
413 d_state->builtin = false;
414 d_state->domain_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
417 ret = gendb_search(c_state->sam_ctx,
418 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
419 "(objectSid=%s)",
420 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
422 if (ret == 0) {
423 talloc_free(d_state);
424 return NT_STATUS_NO_SUCH_DOMAIN;
425 } else if (ret > 1) {
426 talloc_free(d_state);
427 return NT_STATUS_INTERNAL_DB_CORRUPTION;
428 } else if (ret == -1) {
429 talloc_free(d_state);
430 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
431 return NT_STATUS_INTERNAL_DB_CORRUPTION;
434 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
435 d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
436 d_state->connect_state = talloc_reference(d_state, c_state);
437 d_state->sam_ctx = c_state->sam_ctx;
438 d_state->access_mask = r->in.access_mask;
440 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
442 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
443 if (!h_domain) {
444 talloc_free(d_state);
445 return NT_STATUS_NO_MEMORY;
448 h_domain->data = talloc_steal(h_domain, d_state);
450 *r->out.domain_handle = h_domain->wire_handle;
452 return NT_STATUS_OK;
456 return DomInfo1
458 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
459 TALLOC_CTX *mem_ctx,
460 struct ldb_message **dom_msgs,
461 struct samr_DomInfo1 *info)
463 info->min_password_length =
464 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
465 info->password_history_length =
466 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
467 info->password_properties =
468 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
469 info->max_password_age =
470 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
471 info->min_password_age =
472 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
474 return NT_STATUS_OK;
478 return DomInfo2
480 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
481 TALLOC_CTX *mem_ctx,
482 struct ldb_message **dom_msgs,
483 struct samr_DomGeneralInformation *info)
485 /* This pulls the NetBIOS name from the
486 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
487 string */
488 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
490 if (!info->primary.string) {
491 info->primary.string = lp_netbios_name(state->lp_ctx);
494 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
495 0x8000000000000000LL);
497 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
498 info->domain_name.string = state->domain_name;
500 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
502 switch (state->role) {
503 case ROLE_DOMAIN_CONTROLLER:
504 /* This pulls the NetBIOS name from the
505 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
506 string */
507 if (samdb_is_pdc(state->sam_ctx)) {
508 info->role = SAMR_ROLE_DOMAIN_PDC;
509 } else {
510 info->role = SAMR_ROLE_DOMAIN_BDC;
512 break;
513 case ROLE_DOMAIN_MEMBER:
514 info->role = SAMR_ROLE_DOMAIN_MEMBER;
515 break;
516 case ROLE_STANDALONE:
517 info->role = SAMR_ROLE_STANDALONE;
518 break;
521 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
522 info->num_users = samdb_search_count(state->sam_ctx, state->domain_dn,
523 "(objectClass=user)");
524 info->num_groups = samdb_search_count(state->sam_ctx, state->domain_dn,
525 "(&(objectClass=group)(groupType=%u))",
526 GTYPE_SECURITY_GLOBAL_GROUP);
527 info->num_aliases = samdb_search_count(state->sam_ctx, state->domain_dn,
528 "(&(objectClass=group)(groupType=%u))",
529 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
531 return NT_STATUS_OK;
535 return DomInfo3
537 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
538 TALLOC_CTX *mem_ctx,
539 struct ldb_message **dom_msgs,
540 struct samr_DomInfo3 *info)
542 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
543 0x8000000000000000LL);
545 return NT_STATUS_OK;
549 return DomInfo4
551 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
552 TALLOC_CTX *mem_ctx,
553 struct ldb_message **dom_msgs,
554 struct samr_DomOEMInformation *info)
556 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
558 return NT_STATUS_OK;
562 return DomInfo5
564 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
565 TALLOC_CTX *mem_ctx,
566 struct ldb_message **dom_msgs,
567 struct samr_DomInfo5 *info)
569 info->domain_name.string = state->domain_name;
571 return NT_STATUS_OK;
575 return DomInfo6
577 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
578 TALLOC_CTX *mem_ctx,
579 struct ldb_message **dom_msgs,
580 struct samr_DomInfo6 *info)
582 /* This pulls the NetBIOS name from the
583 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
584 string */
585 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
586 dom_msgs[0], "fSMORoleOwner");
588 if (!info->primary.string) {
589 info->primary.string = lp_netbios_name(state->lp_ctx);
592 return NT_STATUS_OK;
596 return DomInfo7
598 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
599 TALLOC_CTX *mem_ctx,
600 struct ldb_message **dom_msgs,
601 struct samr_DomInfo7 *info)
604 switch (state->role) {
605 case ROLE_DOMAIN_CONTROLLER:
606 /* This pulls the NetBIOS name from the
607 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
608 string */
609 if (samdb_is_pdc(state->sam_ctx)) {
610 info->role = SAMR_ROLE_DOMAIN_PDC;
611 } else {
612 info->role = SAMR_ROLE_DOMAIN_BDC;
614 break;
615 case ROLE_DOMAIN_MEMBER:
616 info->role = SAMR_ROLE_DOMAIN_MEMBER;
617 break;
618 case ROLE_STANDALONE:
619 info->role = SAMR_ROLE_STANDALONE;
620 break;
623 return NT_STATUS_OK;
627 return DomInfo8
629 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
630 TALLOC_CTX *mem_ctx,
631 struct ldb_message **dom_msgs,
632 struct samr_DomInfo8 *info)
634 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
635 time(NULL));
637 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
638 0x0LL);
640 return NT_STATUS_OK;
644 return DomInfo9
646 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
647 TALLOC_CTX *mem_ctx,
648 struct ldb_message **dom_msgs,
649 struct samr_DomInfo9 *info)
651 info->domain_server_state = DOMAIN_SERVER_ENABLED;
653 return NT_STATUS_OK;
657 return DomInfo11
659 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
660 TALLOC_CTX *mem_ctx,
661 struct ldb_message **dom_msgs,
662 struct samr_DomGeneralInformation2 *info)
664 NTSTATUS status;
665 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
666 if (!NT_STATUS_IS_OK(status)) {
667 return status;
670 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
671 -18000000000LL);
672 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
673 -18000000000LL);
674 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
676 return NT_STATUS_OK;
680 return DomInfo12
682 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
683 TALLOC_CTX *mem_ctx,
684 struct ldb_message **dom_msgs,
685 struct samr_DomInfo12 *info)
687 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
688 -18000000000LL);
689 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
690 -18000000000LL);
691 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
693 return NT_STATUS_OK;
697 return DomInfo13
699 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
700 TALLOC_CTX *mem_ctx,
701 struct ldb_message **dom_msgs,
702 struct samr_DomInfo13 *info)
704 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
705 time(NULL));
707 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
708 0x0LL);
710 info->modified_count_at_last_promotion = 0;
712 return NT_STATUS_OK;
716 samr_QueryDomainInfo
718 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
719 struct samr_QueryDomainInfo *r)
721 struct dcesrv_handle *h;
722 struct samr_domain_state *d_state;
723 union samr_DomainInfo *info;
725 struct ldb_message **dom_msgs;
726 const char * const *attrs = NULL;
728 *r->out.info = NULL;
730 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
732 d_state = h->data;
734 info = talloc(mem_ctx, union samr_DomainInfo);
735 if (!info) {
736 return NT_STATUS_NO_MEMORY;
739 switch (r->in.level) {
740 case 1:
742 static const char * const attrs2[] = { "minPwdLength",
743 "pwdHistoryLength",
744 "pwdProperties",
745 "maxPwdAge",
746 "minPwdAge",
747 NULL };
748 attrs = attrs2;
749 break;
751 case 2:
753 static const char * const attrs2[] = {"forceLogoff",
754 "oEMInformation",
755 "modifiedCount",
756 "fSMORoleOwner",
757 NULL};
758 attrs = attrs2;
759 break;
761 case 3:
763 static const char * const attrs2[] = {"forceLogoff",
764 NULL};
765 attrs = attrs2;
766 break;
768 case 4:
770 static const char * const attrs2[] = {"oEMInformation",
771 NULL};
772 attrs = attrs2;
773 break;
775 case 5:
777 attrs = NULL;
778 break;
780 case 6:
782 static const char * const attrs2[] = {"fSMORoleOwner",
783 NULL};
784 attrs = attrs2;
785 break;
787 case 7:
789 attrs = NULL;
790 break;
792 case 8:
794 static const char * const attrs2[] = { "modifiedCount",
795 "creationTime",
796 NULL };
797 attrs = attrs2;
798 break;
800 case 9:
802 attrs = NULL;
803 break;
805 case 11:
807 static const char * const attrs2[] = { "oEMInformation",
808 "forceLogoff",
809 "modifiedCount",
810 "lockoutDuration",
811 "lockOutObservationWindow",
812 "lockoutThreshold",
813 NULL};
814 attrs = attrs2;
815 break;
817 case 12:
819 static const char * const attrs2[] = { "lockoutDuration",
820 "lockOutObservationWindow",
821 "lockoutThreshold",
822 NULL};
823 attrs = attrs2;
824 break;
826 case 13:
828 static const char * const attrs2[] = { "modifiedCount",
829 "creationTime",
830 NULL };
831 attrs = attrs2;
832 break;
834 default:
836 return NT_STATUS_INVALID_INFO_CLASS;
840 /* some levels don't need a search */
841 if (attrs) {
842 int ret;
843 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
844 d_state->domain_dn, &dom_msgs, attrs);
845 if (ret != 1) {
846 return NT_STATUS_INTERNAL_DB_CORRUPTION;
850 *r->out.info = info;
852 ZERO_STRUCTP(info);
854 switch (r->in.level) {
855 case 1:
856 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
857 &info->info1);
858 case 2:
859 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
860 &info->general);
861 case 3:
862 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
863 &info->info3);
864 case 4:
865 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
866 &info->oem);
867 case 5:
868 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
869 &info->info5);
870 case 6:
871 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
872 &info->info6);
873 case 7:
874 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
875 &info->info7);
876 case 8:
877 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
878 &info->info8);
879 case 9:
880 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
881 &info->info9);
882 case 11:
883 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
884 &info->general2);
885 case 12:
886 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
887 &info->info12);
888 case 13:
889 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
890 &info->info13);
891 default:
892 return NT_STATUS_INVALID_INFO_CLASS;
898 samr_SetDomainInfo
900 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
901 struct samr_SetDomainInfo *r)
903 struct dcesrv_handle *h;
904 struct samr_domain_state *d_state;
905 struct ldb_message *msg;
906 int ret;
907 struct ldb_context *sam_ctx;
909 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
911 d_state = h->data;
912 sam_ctx = d_state->sam_ctx;
914 msg = ldb_msg_new(mem_ctx);
915 if (msg == NULL) {
916 return NT_STATUS_NO_MEMORY;
919 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
920 if (!msg->dn) {
921 return NT_STATUS_NO_MEMORY;
924 switch (r->in.level) {
925 case 1:
926 SET_UINT (msg, info1.min_password_length, "minPwdLength");
927 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
928 SET_UINT (msg, info1.password_properties, "pwdProperties");
929 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
930 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
931 break;
932 case 3:
933 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
934 break;
935 case 4:
936 SET_STRING(msg, oem.oem_information, "oEMInformation");
937 break;
939 case 6:
940 case 7:
941 case 9:
942 /* No op, we don't know where to set these */
943 return NT_STATUS_OK;
945 case 12:
947 * It is not possible to set lockout_duration < lockout_window.
948 * (The test is the other way around since the negative numbers
949 * are stored...)
951 * TODO:
952 * This check should be moved to the backend, i.e. to some
953 * ldb module under dsdb/samdb/ldb_modules/ .
955 * This constraint is documented here for the samr rpc service:
956 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
957 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
959 * And here for the ldap backend:
960 * MS-ADTS 3.1.1.5.3.2 Constraints
961 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
963 if (r->in.info->info12.lockout_duration >
964 r->in.info->info12.lockout_window)
966 return NT_STATUS_INVALID_PARAMETER;
968 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
969 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
970 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
971 break;
973 default:
974 /* many info classes are not valid for SetDomainInfo */
975 return NT_STATUS_INVALID_INFO_CLASS;
978 /* modify the samdb record */
979 ret = ldb_modify(sam_ctx, msg);
980 if (ret != LDB_SUCCESS) {
981 DEBUG(1,("Failed to modify record %s: %s\n",
982 ldb_dn_get_linearized(d_state->domain_dn),
983 ldb_errstring(sam_ctx)));
985 /* we really need samdb.c to return NTSTATUS */
986 return NT_STATUS_UNSUCCESSFUL;
989 return NT_STATUS_OK;
993 samr_CreateDomainGroup
995 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
996 struct samr_CreateDomainGroup *r)
998 struct samr_domain_state *d_state;
999 struct samr_account_state *a_state;
1000 struct dcesrv_handle *h;
1001 const char *name;
1002 struct ldb_message *msg;
1003 struct dom_sid *sid;
1004 const char *groupname;
1005 struct dcesrv_handle *g_handle;
1006 int ret;
1008 ZERO_STRUCTP(r->out.group_handle);
1009 *r->out.rid = 0;
1011 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1013 d_state = h->data;
1015 if (d_state->builtin) {
1016 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1017 return NT_STATUS_ACCESS_DENIED;
1020 groupname = r->in.name->string;
1022 if (groupname == NULL) {
1023 return NT_STATUS_INVALID_PARAMETER;
1026 /* check if the group already exists */
1027 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1028 "sAMAccountName",
1029 "(&(sAMAccountName=%s)(objectclass=group))",
1030 ldb_binary_encode_string(mem_ctx, groupname));
1031 if (name != NULL) {
1032 return NT_STATUS_GROUP_EXISTS;
1035 msg = ldb_msg_new(mem_ctx);
1036 if (msg == NULL) {
1037 return NT_STATUS_NO_MEMORY;
1040 /* add core elements to the ldb_message for the user */
1041 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1042 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1043 if (!msg->dn) {
1044 return NT_STATUS_NO_MEMORY;
1046 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1047 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1049 /* create the group */
1050 ret = ldb_add(d_state->sam_ctx, msg);
1051 switch (ret) {
1052 case LDB_SUCCESS:
1053 break;
1054 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1055 DEBUG(0,("Failed to create group record %s: %s\n",
1056 ldb_dn_get_linearized(msg->dn),
1057 ldb_errstring(d_state->sam_ctx)));
1058 return NT_STATUS_GROUP_EXISTS;
1059 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1060 DEBUG(0,("Failed to create group record %s: %s\n",
1061 ldb_dn_get_linearized(msg->dn),
1062 ldb_errstring(d_state->sam_ctx)));
1063 return NT_STATUS_ACCESS_DENIED;
1064 default:
1065 DEBUG(0,("Failed to create group record %s: %s\n",
1066 ldb_dn_get_linearized(msg->dn),
1067 ldb_errstring(d_state->sam_ctx)));
1068 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1071 a_state = talloc(mem_ctx, struct samr_account_state);
1072 if (!a_state) {
1073 return NT_STATUS_NO_MEMORY;
1075 a_state->sam_ctx = d_state->sam_ctx;
1076 a_state->access_mask = r->in.access_mask;
1077 a_state->domain_state = talloc_reference(a_state, d_state);
1078 a_state->account_dn = talloc_steal(a_state, msg->dn);
1080 /* retrieve the sid for the group just created */
1081 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1082 msg->dn, "objectSid", NULL);
1083 if (sid == NULL) {
1084 return NT_STATUS_UNSUCCESSFUL;
1087 a_state->account_name = talloc_strdup(a_state, groupname);
1088 if (!a_state->account_name) {
1089 return NT_STATUS_NO_MEMORY;
1092 /* create the policy handle */
1093 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1094 if (!g_handle) {
1095 return NT_STATUS_NO_MEMORY;
1098 g_handle->data = talloc_steal(g_handle, a_state);
1100 *r->out.group_handle = g_handle->wire_handle;
1101 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1103 return NT_STATUS_OK;
1108 comparison function for sorting SamEntry array
1110 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1112 return e1->idx - e2->idx;
1116 samr_EnumDomainGroups
1118 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1119 struct samr_EnumDomainGroups *r)
1121 struct dcesrv_handle *h;
1122 struct samr_domain_state *d_state;
1123 struct ldb_message **res;
1124 int i, ldb_cnt;
1125 uint32_t first, count;
1126 struct samr_SamEntry *entries;
1127 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1128 struct samr_SamArray *sam;
1130 *r->out.resume_handle = 0;
1131 *r->out.sam = NULL;
1132 *r->out.num_entries = 0;
1134 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1136 d_state = h->data;
1138 /* search for all domain groups in this domain. This could possibly be
1139 cached and resumed based on resume_key */
1140 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1141 d_state->domain_dn, &res, attrs,
1142 d_state->domain_sid,
1143 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1144 GTYPE_SECURITY_UNIVERSAL_GROUP,
1145 GTYPE_SECURITY_GLOBAL_GROUP);
1146 if (ldb_cnt == -1) {
1147 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1150 /* convert to SamEntry format */
1151 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1152 if (!entries) {
1153 return NT_STATUS_NO_MEMORY;
1156 count = 0;
1158 for (i=0;i<ldb_cnt;i++) {
1159 struct dom_sid *group_sid;
1161 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1162 "objectSid");
1163 if (group_sid == NULL)
1164 continue;
1166 entries[count].idx =
1167 group_sid->sub_auths[group_sid->num_auths-1];
1168 entries[count].name.string =
1169 samdb_result_string(res[i], "sAMAccountName", "");
1170 count += 1;
1173 /* sort the results by rid */
1174 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1176 /* find the first entry to return */
1177 for (first=0;
1178 first<count && entries[first].idx <= *r->in.resume_handle;
1179 first++) ;
1181 /* return the rest, limit by max_size. Note that we
1182 use the w2k3 element size value of 54 */
1183 *r->out.num_entries = count - first;
1184 *r->out.num_entries = MIN(*r->out.num_entries,
1185 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1187 sam = talloc(mem_ctx, struct samr_SamArray);
1188 if (!sam) {
1189 return NT_STATUS_NO_MEMORY;
1192 sam->entries = entries+first;
1193 sam->count = *r->out.num_entries;
1195 *r->out.sam = sam;
1197 if (*r->out.num_entries < count - first) {
1198 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1199 return STATUS_MORE_ENTRIES;
1202 return NT_STATUS_OK;
1207 samr_CreateUser2
1209 This call uses transactions to ensure we don't get a new conflicting
1210 user while we are processing this, and to ensure the user either
1211 completly exists, or does not.
1213 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1214 struct samr_CreateUser2 *r)
1216 struct samr_domain_state *d_state;
1217 struct samr_account_state *a_state;
1218 struct dcesrv_handle *h;
1219 const char *name;
1220 struct ldb_message *msg;
1221 struct dom_sid *sid;
1222 const char *account_name;
1223 struct dcesrv_handle *u_handle;
1224 int ret;
1225 const char *container, *obj_class=NULL;
1226 char *cn_name;
1227 int cn_name_len;
1229 const char *attrs[] = {
1230 "objectSid",
1231 "userAccountControl",
1232 NULL
1235 uint32_t user_account_control;
1237 struct ldb_message **msgs;
1239 ZERO_STRUCTP(r->out.user_handle);
1240 *r->out.access_granted = 0;
1241 *r->out.rid = 0;
1243 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1245 d_state = h->data;
1247 if (d_state->builtin) {
1248 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1249 return NT_STATUS_ACCESS_DENIED;
1250 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1251 /* Domain trust accounts must be created by the LSA calls */
1252 return NT_STATUS_ACCESS_DENIED;
1254 account_name = r->in.account_name->string;
1256 if (account_name == NULL) {
1257 return NT_STATUS_INVALID_PARAMETER;
1261 * Start a transaction, so we can query and do a subsequent atomic
1262 * modify
1265 ret = ldb_transaction_start(d_state->sam_ctx);
1266 if (ret != LDB_SUCCESS) {
1267 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1268 ldb_errstring(d_state->sam_ctx)));
1269 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1272 /* check if the user already exists */
1273 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1274 "sAMAccountName",
1275 "(&(sAMAccountName=%s)(objectclass=user))",
1276 ldb_binary_encode_string(mem_ctx, account_name));
1277 if (name != NULL) {
1278 ldb_transaction_cancel(d_state->sam_ctx);
1279 return NT_STATUS_USER_EXISTS;
1282 msg = ldb_msg_new(mem_ctx);
1283 if (msg == NULL) {
1284 ldb_transaction_cancel(d_state->sam_ctx);
1285 return NT_STATUS_NO_MEMORY;
1288 cn_name = talloc_strdup(mem_ctx, account_name);
1289 if (!cn_name) {
1290 ldb_transaction_cancel(d_state->sam_ctx);
1291 return NT_STATUS_NO_MEMORY;
1294 cn_name_len = strlen(cn_name);
1296 /* This must be one of these values *only* */
1297 if (r->in.acct_flags == ACB_NORMAL) {
1298 container = "CN=Users";
1299 obj_class = "user";
1301 } else if (r->in.acct_flags == ACB_WSTRUST) {
1302 if (cn_name[cn_name_len - 1] != '$') {
1303 ldb_transaction_cancel(d_state->sam_ctx);
1304 return NT_STATUS_FOOBAR;
1306 cn_name[cn_name_len - 1] = '\0';
1307 container = "CN=Computers";
1308 obj_class = "computer";
1309 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1310 "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1312 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1313 if (cn_name[cn_name_len - 1] != '$') {
1314 ldb_transaction_cancel(d_state->sam_ctx);
1315 return NT_STATUS_FOOBAR;
1317 cn_name[cn_name_len - 1] = '\0';
1318 container = "OU=Domain Controllers";
1319 obj_class = "computer";
1320 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1321 "primaryGroupID", DOMAIN_RID_DCS);
1322 } else {
1323 ldb_transaction_cancel(d_state->sam_ctx);
1324 return NT_STATUS_INVALID_PARAMETER;
1327 /* add core elements to the ldb_message for the user */
1328 msg->dn = ldb_dn_copy(msg, d_state->domain_dn);
1329 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1330 ldb_transaction_cancel(d_state->sam_ctx);
1331 return NT_STATUS_FOOBAR;
1334 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName",
1335 account_name);
1336 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass",
1337 obj_class);
1339 /* create the user */
1340 ret = ldb_add(d_state->sam_ctx, msg);
1341 switch (ret) {
1342 case LDB_SUCCESS:
1343 break;
1344 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1345 ldb_transaction_cancel(d_state->sam_ctx);
1346 DEBUG(0,("Failed to create user record %s: %s\n",
1347 ldb_dn_get_linearized(msg->dn),
1348 ldb_errstring(d_state->sam_ctx)));
1349 return NT_STATUS_USER_EXISTS;
1350 case LDB_ERR_UNWILLING_TO_PERFORM:
1351 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1352 ldb_transaction_cancel(d_state->sam_ctx);
1353 DEBUG(0,("Failed to create user record %s: %s\n",
1354 ldb_dn_get_linearized(msg->dn),
1355 ldb_errstring(d_state->sam_ctx)));
1356 return NT_STATUS_ACCESS_DENIED;
1357 default:
1358 ldb_transaction_cancel(d_state->sam_ctx);
1359 DEBUG(0,("Failed to create user record %s: %s\n",
1360 ldb_dn_get_linearized(msg->dn),
1361 ldb_errstring(d_state->sam_ctx)));
1362 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1365 a_state = talloc(mem_ctx, struct samr_account_state);
1366 if (!a_state) {
1367 ldb_transaction_cancel(d_state->sam_ctx);
1368 return NT_STATUS_NO_MEMORY;
1370 a_state->sam_ctx = d_state->sam_ctx;
1371 a_state->access_mask = r->in.access_mask;
1372 a_state->domain_state = talloc_reference(a_state, d_state);
1373 a_state->account_dn = talloc_steal(a_state, msg->dn);
1375 /* retrieve the sid and account control bits for the user just created */
1376 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
1377 msg->dn, &msgs, attrs);
1379 if (ret != 1) {
1380 ldb_transaction_cancel(d_state->sam_ctx);
1381 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1382 ldb_dn_get_linearized(msg->dn)));
1383 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1385 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1386 if (sid == NULL) {
1387 ldb_transaction_cancel(d_state->sam_ctx);
1388 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1389 ldb_dn_get_linearized(msg->dn)));
1390 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1393 /* Change the account control to be the correct account type.
1394 * The default is for a workstation account */
1395 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1396 user_account_control = (user_account_control &
1397 ~(UF_NORMAL_ACCOUNT |
1398 UF_INTERDOMAIN_TRUST_ACCOUNT |
1399 UF_WORKSTATION_TRUST_ACCOUNT |
1400 UF_SERVER_TRUST_ACCOUNT));
1401 user_account_control |= ds_acb2uf(r->in.acct_flags);
1403 talloc_free(msg);
1404 msg = ldb_msg_new(mem_ctx);
1405 if (msg == NULL) {
1406 ldb_transaction_cancel(d_state->sam_ctx);
1407 return NT_STATUS_NO_MEMORY;
1410 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1412 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1413 "userAccountControl",
1414 user_account_control) != 0) {
1415 ldb_transaction_cancel(d_state->sam_ctx);
1416 return NT_STATUS_NO_MEMORY;
1419 /* modify the samdb record */
1420 ret = dsdb_replace(a_state->sam_ctx, msg, 0);
1421 if (ret != LDB_SUCCESS) {
1422 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1423 ldb_dn_get_linearized(msg->dn),
1424 ldb_errstring(d_state->sam_ctx)));
1425 ldb_transaction_cancel(d_state->sam_ctx);
1427 /* we really need samdb.c to return NTSTATUS */
1428 return NT_STATUS_UNSUCCESSFUL;
1431 ret = ldb_transaction_commit(d_state->sam_ctx);
1432 if (ret != LDB_SUCCESS) {
1433 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1434 ldb_dn_get_linearized(msg->dn),
1435 ldb_errstring(d_state->sam_ctx)));
1436 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1439 a_state->account_name = talloc_steal(a_state, account_name);
1440 if (!a_state->account_name) {
1441 return NT_STATUS_NO_MEMORY;
1444 /* create the policy handle */
1445 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1446 if (!u_handle) {
1447 return NT_STATUS_NO_MEMORY;
1450 u_handle->data = talloc_steal(u_handle, a_state);
1452 *r->out.user_handle = u_handle->wire_handle;
1453 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1455 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1457 return NT_STATUS_OK;
1462 samr_CreateUser
1464 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1465 struct samr_CreateUser *r)
1467 struct samr_CreateUser2 r2;
1468 uint32_t access_granted = 0;
1471 /* a simple wrapper around samr_CreateUser2 works nicely */
1472 r2.in.domain_handle = r->in.domain_handle;
1473 r2.in.account_name = r->in.account_name;
1474 r2.in.acct_flags = ACB_NORMAL;
1475 r2.in.access_mask = r->in.access_mask;
1476 r2.out.user_handle = r->out.user_handle;
1477 r2.out.access_granted = &access_granted;
1478 r2.out.rid = r->out.rid;
1480 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1484 samr_EnumDomainUsers
1486 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1487 struct samr_EnumDomainUsers *r)
1489 struct dcesrv_handle *h;
1490 struct samr_domain_state *d_state;
1491 struct ldb_result *res;
1492 int ret;
1493 unsigned int i;
1494 uint32_t num_filtered_entries, first;
1495 struct samr_SamEntry *entries;
1496 const char * const attrs[] = { "objectSid", "sAMAccountName",
1497 "userAccountControl", NULL };
1498 struct samr_SamArray *sam;
1500 *r->out.resume_handle = 0;
1501 *r->out.sam = NULL;
1502 *r->out.num_entries = 0;
1504 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1506 d_state = h->data;
1508 /* don't have to worry about users in the builtin domain, as there are none */
1509 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1511 if (ret != LDB_SUCCESS) {
1512 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1513 ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1514 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1517 /* convert to SamEntry format */
1518 entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1519 if (!entries) {
1520 return NT_STATUS_NO_MEMORY;
1522 num_filtered_entries = 0;
1523 for (i=0;i<res->count;i++) {
1524 /* Check if a mask has been requested */
1525 if (r->in.acct_flags
1526 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i],
1527 d_state->domain_dn) & r->in.acct_flags) == 0)) {
1528 continue;
1530 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1531 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1532 num_filtered_entries++;
1535 /* sort the results by rid */
1536 TYPESAFE_QSORT(entries, num_filtered_entries, compare_SamEntry);
1538 /* find the first entry to return */
1539 for (first=0;
1540 first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1541 first++) ;
1543 /* return the rest, limit by max_size. Note that we
1544 use the w2k3 element size value of 54 */
1545 *r->out.num_entries = num_filtered_entries - first;
1546 *r->out.num_entries = MIN(*r->out.num_entries,
1547 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1549 sam = talloc(mem_ctx, struct samr_SamArray);
1550 if (!sam) {
1551 return NT_STATUS_NO_MEMORY;
1554 sam->entries = entries+first;
1555 sam->count = *r->out.num_entries;
1557 *r->out.sam = sam;
1559 if (first == num_filtered_entries) {
1560 return NT_STATUS_OK;
1563 if (*r->out.num_entries < num_filtered_entries - first) {
1564 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1565 return STATUS_MORE_ENTRIES;
1568 return NT_STATUS_OK;
1573 samr_CreateDomAlias
1575 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1576 struct samr_CreateDomAlias *r)
1578 struct samr_domain_state *d_state;
1579 struct samr_account_state *a_state;
1580 struct dcesrv_handle *h;
1581 const char *alias_name, *name;
1582 struct ldb_message *msg;
1583 struct dom_sid *sid;
1584 struct dcesrv_handle *a_handle;
1585 int ret;
1587 ZERO_STRUCTP(r->out.alias_handle);
1588 *r->out.rid = 0;
1590 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1592 d_state = h->data;
1594 if (d_state->builtin) {
1595 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1596 return NT_STATUS_ACCESS_DENIED;
1599 alias_name = r->in.alias_name->string;
1601 if (alias_name == NULL) {
1602 return NT_STATUS_INVALID_PARAMETER;
1605 /* Check if alias already exists */
1606 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1607 "sAMAccountName",
1608 "(sAMAccountName=%s)(objectclass=group))",
1609 ldb_binary_encode_string(mem_ctx, alias_name));
1611 if (name != NULL) {
1612 return NT_STATUS_ALIAS_EXISTS;
1615 msg = ldb_msg_new(mem_ctx);
1616 if (msg == NULL) {
1617 return NT_STATUS_NO_MEMORY;
1620 /* add core elements to the ldb_message for the alias */
1621 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1622 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1623 if (!msg->dn) {
1624 return NT_STATUS_NO_MEMORY;
1627 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1628 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1629 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1631 /* create the alias */
1632 ret = ldb_add(d_state->sam_ctx, msg);
1633 switch (ret) {
1634 case LDB_SUCCESS:
1635 break;
1636 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1637 return NT_STATUS_ALIAS_EXISTS;
1638 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1639 return NT_STATUS_ACCESS_DENIED;
1640 default:
1641 DEBUG(0,("Failed to create alias record %s: %s\n",
1642 ldb_dn_get_linearized(msg->dn),
1643 ldb_errstring(d_state->sam_ctx)));
1644 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1647 a_state = talloc(mem_ctx, struct samr_account_state);
1648 if (!a_state) {
1649 return NT_STATUS_NO_MEMORY;
1652 a_state->sam_ctx = d_state->sam_ctx;
1653 a_state->access_mask = r->in.access_mask;
1654 a_state->domain_state = talloc_reference(a_state, d_state);
1655 a_state->account_dn = talloc_steal(a_state, msg->dn);
1657 /* retrieve the sid for the alias just created */
1658 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1659 msg->dn, "objectSid", NULL);
1661 a_state->account_name = talloc_strdup(a_state, alias_name);
1662 if (!a_state->account_name) {
1663 return NT_STATUS_NO_MEMORY;
1666 /* create the policy handle */
1667 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1668 if (a_handle == NULL)
1669 return NT_STATUS_NO_MEMORY;
1671 a_handle->data = talloc_steal(a_handle, a_state);
1673 *r->out.alias_handle = a_handle->wire_handle;
1675 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1677 return NT_STATUS_OK;
1682 samr_EnumDomainAliases
1684 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1685 struct samr_EnumDomainAliases *r)
1687 struct dcesrv_handle *h;
1688 struct samr_domain_state *d_state;
1689 struct ldb_message **res;
1690 int i, ldb_cnt;
1691 uint32_t first, count;
1692 struct samr_SamEntry *entries;
1693 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1694 struct samr_SamArray *sam;
1696 *r->out.resume_handle = 0;
1697 *r->out.sam = NULL;
1698 *r->out.num_entries = 0;
1700 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1702 d_state = h->data;
1704 /* search for all domain groups in this domain. This could possibly be
1705 cached and resumed based on resume_key */
1706 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1707 d_state->domain_dn,
1708 &res, attrs,
1709 d_state->domain_sid,
1710 "(&(|(grouptype=%d)(grouptype=%d)))"
1711 "(objectclass=group))",
1712 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1713 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1714 if (ldb_cnt == -1) {
1715 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1717 if (ldb_cnt == 0) {
1718 return NT_STATUS_OK;
1721 /* convert to SamEntry format */
1722 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1723 if (!entries) {
1724 return NT_STATUS_NO_MEMORY;
1727 count = 0;
1729 for (i=0;i<ldb_cnt;i++) {
1730 struct dom_sid *alias_sid;
1732 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1733 "objectSid");
1735 if (alias_sid == NULL)
1736 continue;
1738 entries[count].idx =
1739 alias_sid->sub_auths[alias_sid->num_auths-1];
1740 entries[count].name.string =
1741 samdb_result_string(res[i], "sAMAccountName", "");
1742 count += 1;
1745 /* sort the results by rid */
1746 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1748 /* find the first entry to return */
1749 for (first=0;
1750 first<count && entries[first].idx <= *r->in.resume_handle;
1751 first++) ;
1753 if (first == count) {
1754 return NT_STATUS_OK;
1757 *r->out.num_entries = count - first;
1758 *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1760 sam = talloc(mem_ctx, struct samr_SamArray);
1761 if (!sam) {
1762 return NT_STATUS_NO_MEMORY;
1765 sam->entries = entries+first;
1766 sam->count = *r->out.num_entries;
1768 *r->out.sam = sam;
1770 if (*r->out.num_entries < count - first) {
1771 *r->out.resume_handle =
1772 entries[first+*r->out.num_entries-1].idx;
1773 return STATUS_MORE_ENTRIES;
1776 return NT_STATUS_OK;
1781 samr_GetAliasMembership
1783 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1784 struct samr_GetAliasMembership *r)
1786 struct dcesrv_handle *h;
1787 struct samr_domain_state *d_state;
1788 struct ldb_message **res;
1789 int i, count = 0;
1791 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1793 d_state = h->data;
1795 if (r->in.sids->num_sids > 0) {
1796 const char *filter;
1797 const char * const attrs[2] = { "objectSid", NULL };
1799 filter = talloc_asprintf(mem_ctx,
1800 "(&(|(grouptype=%d)(grouptype=%d))"
1801 "(objectclass=group)(|",
1802 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1803 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1804 if (filter == NULL)
1805 return NT_STATUS_NO_MEMORY;
1807 for (i=0; i<r->in.sids->num_sids; i++) {
1808 const char *memberdn;
1810 memberdn =
1811 samdb_search_string(d_state->sam_ctx,
1812 mem_ctx, NULL,
1813 "distinguishedName",
1814 "(objectSid=%s)",
1815 ldap_encode_ndr_dom_sid(mem_ctx,
1816 r->in.sids->sids[i].sid));
1818 if (memberdn == NULL)
1819 continue;
1821 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1822 filter, memberdn);
1823 if (filter == NULL)
1824 return NT_STATUS_NO_MEMORY;
1827 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1828 d_state->domain_dn, &res, attrs,
1829 d_state->domain_sid, "%s))", filter);
1830 if (count < 0)
1831 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1834 r->out.rids->count = 0;
1835 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1836 if (r->out.rids->ids == NULL)
1837 return NT_STATUS_NO_MEMORY;
1839 for (i=0; i<count; i++) {
1840 struct dom_sid *alias_sid;
1842 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1844 if (alias_sid == NULL) {
1845 DEBUG(0, ("Could not find objectSid\n"));
1846 continue;
1849 r->out.rids->ids[r->out.rids->count] =
1850 alias_sid->sub_auths[alias_sid->num_auths-1];
1851 r->out.rids->count += 1;
1854 return NT_STATUS_OK;
1859 samr_LookupNames
1861 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1862 struct samr_LookupNames *r)
1864 struct dcesrv_handle *h;
1865 struct samr_domain_state *d_state;
1866 uint32_t i, num_mapped;
1867 NTSTATUS status = NT_STATUS_OK;
1868 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1869 int count;
1871 ZERO_STRUCTP(r->out.rids);
1872 ZERO_STRUCTP(r->out.types);
1874 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1876 d_state = h->data;
1878 if (r->in.num_names == 0) {
1879 return NT_STATUS_OK;
1882 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1883 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1884 if (!r->out.rids->ids || !r->out.types->ids) {
1885 return NT_STATUS_NO_MEMORY;
1887 r->out.rids->count = r->in.num_names;
1888 r->out.types->count = r->in.num_names;
1890 num_mapped = 0;
1892 for (i=0;i<r->in.num_names;i++) {
1893 struct ldb_message **res;
1894 struct dom_sid *sid;
1895 uint32_t atype, rtype;
1897 r->out.rids->ids[i] = 0;
1898 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1900 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1901 "sAMAccountName=%s",
1902 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1903 if (count != 1) {
1904 status = STATUS_SOME_UNMAPPED;
1905 continue;
1908 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1909 if (sid == NULL) {
1910 status = STATUS_SOME_UNMAPPED;
1911 continue;
1914 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1915 if (atype == 0) {
1916 status = STATUS_SOME_UNMAPPED;
1917 continue;
1920 rtype = ds_atype_map(atype);
1922 if (rtype == SID_NAME_UNKNOWN) {
1923 status = STATUS_SOME_UNMAPPED;
1924 continue;
1927 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1928 r->out.types->ids[i] = rtype;
1929 num_mapped++;
1932 if (num_mapped == 0) {
1933 return NT_STATUS_NONE_MAPPED;
1935 return status;
1940 samr_LookupRids
1942 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1943 struct samr_LookupRids *r)
1945 struct dcesrv_handle *h;
1946 struct samr_domain_state *d_state;
1947 uint32_t i;
1948 NTSTATUS status = NT_STATUS_OK;
1949 struct lsa_String *names;
1950 uint32_t *ids;
1952 ZERO_STRUCTP(r->out.names);
1953 ZERO_STRUCTP(r->out.types);
1955 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1957 d_state = h->data;
1959 if (r->in.num_rids == 0)
1960 return NT_STATUS_OK;
1962 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1963 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1965 if ((names == NULL) || (ids == NULL))
1966 return NT_STATUS_NO_MEMORY;
1968 for (i=0; i<r->in.num_rids; i++) {
1969 struct ldb_message **res;
1970 int count;
1971 const char * const attrs[] = { "sAMAccountType",
1972 "sAMAccountName", NULL };
1973 uint32_t atype;
1974 struct dom_sid *sid;
1976 ids[i] = SID_NAME_UNKNOWN;
1978 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid,
1979 r->in.rids[i]);
1980 if (sid == NULL) {
1981 names[i].string = NULL;
1982 status = STATUS_SOME_UNMAPPED;
1983 continue;
1986 count = gendb_search(d_state->sam_ctx, mem_ctx,
1987 d_state->domain_dn, &res, attrs,
1988 "(objectSid=%s)",
1989 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1990 if (count != 1) {
1991 names[i].string = NULL;
1992 status = STATUS_SOME_UNMAPPED;
1993 continue;
1996 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1997 NULL);
1999 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
2000 if (atype == 0) {
2001 status = STATUS_SOME_UNMAPPED;
2002 continue;
2005 ids[i] = ds_atype_map(atype);
2007 if (ids[i] == SID_NAME_UNKNOWN) {
2008 status = STATUS_SOME_UNMAPPED;
2009 continue;
2013 r->out.names->names = names;
2014 r->out.names->count = r->in.num_rids;
2016 r->out.types->ids = ids;
2017 r->out.types->count = r->in.num_rids;
2019 return status;
2024 samr_OpenGroup
2026 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2027 struct samr_OpenGroup *r)
2029 struct samr_domain_state *d_state;
2030 struct samr_account_state *a_state;
2031 struct dcesrv_handle *h;
2032 const char *groupname;
2033 struct dom_sid *sid;
2034 struct ldb_message **msgs;
2035 struct dcesrv_handle *g_handle;
2036 const char * const attrs[2] = { "sAMAccountName", NULL };
2037 int ret;
2039 ZERO_STRUCTP(r->out.group_handle);
2041 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2043 d_state = h->data;
2045 /* form the group SID */
2046 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2047 if (!sid) {
2048 return NT_STATUS_NO_MEMORY;
2051 /* search for the group record */
2052 ret = gendb_search(d_state->sam_ctx,
2053 mem_ctx, d_state->domain_dn, &msgs, attrs,
2054 "(&(objectSid=%s)(objectClass=group)"
2055 "(|(groupType=%d)(groupType=%d)))",
2056 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2057 GTYPE_SECURITY_UNIVERSAL_GROUP,
2058 GTYPE_SECURITY_GLOBAL_GROUP);
2059 if (ret == 0) {
2060 return NT_STATUS_NO_SUCH_GROUP;
2062 if (ret != 1) {
2063 DEBUG(0,("Found %d records matching sid %s\n",
2064 ret, dom_sid_string(mem_ctx, sid)));
2065 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2068 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2069 if (groupname == NULL) {
2070 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2071 dom_sid_string(mem_ctx, sid)));
2072 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2075 a_state = talloc(mem_ctx, struct samr_account_state);
2076 if (!a_state) {
2077 return NT_STATUS_NO_MEMORY;
2079 a_state->sam_ctx = d_state->sam_ctx;
2080 a_state->access_mask = r->in.access_mask;
2081 a_state->domain_state = talloc_reference(a_state, d_state);
2082 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2083 a_state->account_sid = talloc_steal(a_state, sid);
2084 a_state->account_name = talloc_strdup(a_state, groupname);
2085 if (!a_state->account_name) {
2086 return NT_STATUS_NO_MEMORY;
2089 /* create the policy handle */
2090 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2091 if (!g_handle) {
2092 return NT_STATUS_NO_MEMORY;
2095 g_handle->data = talloc_steal(g_handle, a_state);
2097 *r->out.group_handle = g_handle->wire_handle;
2099 return NT_STATUS_OK;
2103 samr_QueryGroupInfo
2105 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2106 struct samr_QueryGroupInfo *r)
2108 struct dcesrv_handle *h;
2109 struct samr_account_state *a_state;
2110 struct ldb_message *msg;
2111 struct ldb_result *res;
2112 const char * const attrs[4] = { "sAMAccountName", "description",
2113 "numMembers", NULL };
2114 int ret;
2115 union samr_GroupInfo *info;
2117 *r->out.info = NULL;
2119 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2121 a_state = h->data;
2123 ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn,
2124 LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2126 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2127 return NT_STATUS_NO_SUCH_GROUP;
2128 } else if (ret != LDB_SUCCESS) {
2129 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2130 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2133 if (res->count != 1) {
2134 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2136 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2138 msg = res->msgs[0];
2140 /* allocate the info structure */
2141 info = talloc_zero(mem_ctx, union samr_GroupInfo);
2142 if (info == NULL) {
2143 return NT_STATUS_NO_MEMORY;
2146 /* Fill in the level */
2147 switch (r->in.level) {
2148 case GROUPINFOALL:
2149 QUERY_STRING(msg, all.name, "sAMAccountName");
2150 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2151 QUERY_UINT (msg, all.num_members, "numMembers")
2152 QUERY_STRING(msg, all.description, "description");
2153 break;
2154 case GROUPINFONAME:
2155 QUERY_STRING(msg, name, "sAMAccountName");
2156 break;
2157 case GROUPINFOATTRIBUTES:
2158 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2159 break;
2160 case GROUPINFODESCRIPTION:
2161 QUERY_STRING(msg, description, "description");
2162 break;
2163 case GROUPINFOALL2:
2164 QUERY_STRING(msg, all2.name, "sAMAccountName");
2165 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2166 QUERY_UINT (msg, all2.num_members, "numMembers")
2167 QUERY_STRING(msg, all2.description, "description");
2168 break;
2169 default:
2170 talloc_free(info);
2171 return NT_STATUS_INVALID_INFO_CLASS;
2174 *r->out.info = info;
2176 return NT_STATUS_OK;
2181 samr_SetGroupInfo
2183 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2184 struct samr_SetGroupInfo *r)
2186 struct dcesrv_handle *h;
2187 struct samr_account_state *g_state;
2188 struct ldb_message *msg;
2189 struct ldb_context *sam_ctx;
2190 int ret;
2192 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2194 g_state = h->data;
2195 sam_ctx = g_state->sam_ctx;
2197 msg = ldb_msg_new(mem_ctx);
2198 if (msg == NULL) {
2199 return NT_STATUS_NO_MEMORY;
2202 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2203 if (!msg->dn) {
2204 return NT_STATUS_NO_MEMORY;
2207 switch (r->in.level) {
2208 case GROUPINFODESCRIPTION:
2209 SET_STRING(msg, description, "description");
2210 break;
2211 case GROUPINFONAME:
2212 /* On W2k3 this does not change the name, it changes the
2213 * sAMAccountName attribute */
2214 SET_STRING(msg, name, "sAMAccountName");
2215 break;
2216 case GROUPINFOATTRIBUTES:
2217 /* This does not do anything obviously visible in W2k3 LDAP */
2218 return NT_STATUS_OK;
2219 default:
2220 return NT_STATUS_INVALID_INFO_CLASS;
2223 /* modify the samdb record */
2224 ret = ldb_modify(g_state->sam_ctx, msg);
2225 if (ret != LDB_SUCCESS) {
2226 /* we really need samdb.c to return NTSTATUS */
2227 return NT_STATUS_UNSUCCESSFUL;
2230 return NT_STATUS_OK;
2235 samr_AddGroupMember
2237 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2238 struct samr_AddGroupMember *r)
2240 struct dcesrv_handle *h;
2241 struct samr_account_state *a_state;
2242 struct samr_domain_state *d_state;
2243 struct ldb_message *mod;
2244 struct dom_sid *membersid;
2245 const char *memberdn;
2246 struct ldb_result *res;
2247 const char * const attrs[] = { NULL };
2248 int ret;
2250 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2252 a_state = h->data;
2253 d_state = a_state->domain_state;
2255 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2256 if (membersid == NULL) {
2257 return NT_STATUS_NO_MEMORY;
2260 /* In native mode, AD can also nest domain groups. Not sure yet
2261 * whether this is also available via RPC. */
2262 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2263 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2264 "(&(objectSid=%s)(objectclass=user))",
2265 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2267 if (ret != LDB_SUCCESS) {
2268 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2271 if (res->count == 0) {
2272 return NT_STATUS_NO_SUCH_USER;
2275 if (res->count > 1) {
2276 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2279 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2281 if (memberdn == NULL)
2282 return NT_STATUS_NO_MEMORY;
2284 mod = ldb_msg_new(mem_ctx);
2285 if (mod == NULL) {
2286 return NT_STATUS_NO_MEMORY;
2289 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2291 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2292 memberdn);
2293 if (ret != LDB_SUCCESS) {
2294 return NT_STATUS_UNSUCCESSFUL;
2297 ret = ldb_modify(a_state->sam_ctx, mod);
2298 switch (ret) {
2299 case LDB_SUCCESS:
2300 return NT_STATUS_OK;
2301 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2302 return NT_STATUS_MEMBER_IN_GROUP;
2303 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2304 return NT_STATUS_ACCESS_DENIED;
2305 default:
2306 return NT_STATUS_UNSUCCESSFUL;
2312 samr_DeleteDomainGroup
2314 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2315 struct samr_DeleteDomainGroup *r)
2317 struct dcesrv_handle *h;
2318 struct samr_account_state *a_state;
2319 int ret;
2321 *r->out.group_handle = *r->in.group_handle;
2323 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2325 a_state = h->data;
2327 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2328 if (ret != LDB_SUCCESS) {
2329 return NT_STATUS_UNSUCCESSFUL;
2332 talloc_free(h);
2333 ZERO_STRUCTP(r->out.group_handle);
2335 return NT_STATUS_OK;
2340 samr_DeleteGroupMember
2342 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2343 struct samr_DeleteGroupMember *r)
2345 struct dcesrv_handle *h;
2346 struct samr_account_state *a_state;
2347 struct samr_domain_state *d_state;
2348 struct ldb_message *mod;
2349 struct dom_sid *membersid;
2350 const char *memberdn;
2351 struct ldb_result *res;
2352 const char * const attrs[] = { NULL };
2353 int ret;
2355 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2357 a_state = h->data;
2358 d_state = a_state->domain_state;
2360 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2361 if (membersid == NULL)
2362 return NT_STATUS_NO_MEMORY;
2364 /* In native mode, AD can also nest domain groups. Not sure yet
2365 * whether this is also available via RPC. */
2366 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2367 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2368 "(&(objectSid=%s)(objectclass=user))",
2369 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2371 if (ret != LDB_SUCCESS) {
2372 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2375 if (res->count == 0) {
2376 return NT_STATUS_NO_SUCH_USER;
2379 if (res->count > 1) {
2380 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2383 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2385 if (memberdn == NULL)
2386 return NT_STATUS_NO_MEMORY;
2388 mod = ldb_msg_new(mem_ctx);
2389 if (mod == NULL) {
2390 return NT_STATUS_NO_MEMORY;
2393 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2395 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2396 memberdn);
2397 if (ret != LDB_SUCCESS) {
2398 return NT_STATUS_NO_MEMORY;
2401 ret = ldb_modify(a_state->sam_ctx, mod);
2402 switch (ret) {
2403 case LDB_SUCCESS:
2404 return NT_STATUS_OK;
2405 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2406 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2407 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2408 return NT_STATUS_ACCESS_DENIED;
2409 default:
2410 return NT_STATUS_UNSUCCESSFUL;
2416 samr_QueryGroupMember
2418 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2419 struct samr_QueryGroupMember *r)
2421 struct dcesrv_handle *h;
2422 struct samr_account_state *a_state;
2423 struct ldb_message **res;
2424 struct ldb_message_element *el;
2425 struct samr_RidTypeArray *array;
2426 const char * const attrs[2] = { "member", NULL };
2427 int ret;
2429 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2431 a_state = h->data;
2433 /* pull the member attribute */
2434 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2435 a_state->account_dn, &res, attrs);
2437 if (ret != 1) {
2438 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2441 array = talloc(mem_ctx, struct samr_RidTypeArray);
2443 if (array == NULL)
2444 return NT_STATUS_NO_MEMORY;
2446 ZERO_STRUCTP(array);
2448 el = ldb_msg_find_element(res[0], "member");
2450 if (el != NULL) {
2451 unsigned int i;
2453 array->count = el->num_values;
2455 array->rids = talloc_array(mem_ctx, uint32_t,
2456 el->num_values);
2457 if (array->rids == NULL)
2458 return NT_STATUS_NO_MEMORY;
2460 array->types = talloc_array(mem_ctx, uint32_t,
2461 el->num_values);
2462 if (array->types == NULL)
2463 return NT_STATUS_NO_MEMORY;
2465 for (i=0; i<el->num_values; i++) {
2466 struct ldb_message **res2;
2467 const char * const attrs2[2] = { "objectSid", NULL };
2468 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2469 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2470 &res2, attrs2);
2471 if (ret != 1)
2472 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2474 array->rids[i] =
2475 samdb_result_rid_from_sid(mem_ctx, res2[0],
2476 "objectSid", 0);
2478 if (array->rids[i] == 0)
2479 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2481 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2485 *r->out.rids = array;
2487 return NT_STATUS_OK;
2492 samr_SetMemberAttributesOfGroup
2494 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2495 struct samr_SetMemberAttributesOfGroup *r)
2497 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2502 samr_OpenAlias
2504 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2505 struct samr_OpenAlias *r)
2507 struct samr_domain_state *d_state;
2508 struct samr_account_state *a_state;
2509 struct dcesrv_handle *h;
2510 const char *alias_name;
2511 struct dom_sid *sid;
2512 struct ldb_message **msgs;
2513 struct dcesrv_handle *g_handle;
2514 const char * const attrs[2] = { "sAMAccountName", NULL };
2515 int ret;
2517 ZERO_STRUCTP(r->out.alias_handle);
2519 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2521 d_state = h->data;
2523 /* form the alias SID */
2524 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2525 if (sid == NULL)
2526 return NT_STATUS_NO_MEMORY;
2528 /* search for the group record */
2529 ret = gendb_search(d_state->sam_ctx,
2530 mem_ctx, d_state->domain_dn, &msgs, attrs,
2531 "(&(objectSid=%s)(objectclass=group)"
2532 "(|(grouptype=%d)(grouptype=%d)))",
2533 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2534 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2535 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2536 if (ret == 0) {
2537 return NT_STATUS_NO_SUCH_ALIAS;
2539 if (ret != 1) {
2540 DEBUG(0,("Found %d records matching sid %s\n",
2541 ret, dom_sid_string(mem_ctx, sid)));
2542 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2545 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2546 if (alias_name == NULL) {
2547 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2548 dom_sid_string(mem_ctx, sid)));
2549 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2552 a_state = talloc(mem_ctx, struct samr_account_state);
2553 if (!a_state) {
2554 return NT_STATUS_NO_MEMORY;
2556 a_state->sam_ctx = d_state->sam_ctx;
2557 a_state->access_mask = r->in.access_mask;
2558 a_state->domain_state = talloc_reference(a_state, d_state);
2559 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2560 a_state->account_sid = talloc_steal(a_state, sid);
2561 a_state->account_name = talloc_strdup(a_state, alias_name);
2562 if (!a_state->account_name) {
2563 return NT_STATUS_NO_MEMORY;
2566 /* create the policy handle */
2567 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2568 if (!g_handle) {
2569 return NT_STATUS_NO_MEMORY;
2572 g_handle->data = talloc_steal(g_handle, a_state);
2574 *r->out.alias_handle = g_handle->wire_handle;
2576 return NT_STATUS_OK;
2581 samr_QueryAliasInfo
2583 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2584 struct samr_QueryAliasInfo *r)
2586 struct dcesrv_handle *h;
2587 struct samr_account_state *a_state;
2588 struct ldb_message *msg, **res;
2589 const char * const attrs[4] = { "sAMAccountName", "description",
2590 "numMembers", NULL };
2591 int ret;
2592 union samr_AliasInfo *info;
2594 *r->out.info = NULL;
2596 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2598 a_state = h->data;
2600 /* pull all the alias attributes */
2601 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2602 a_state->account_dn ,&res, attrs);
2603 if (ret != 1) {
2604 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2606 msg = res[0];
2608 /* allocate the info structure */
2609 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2610 if (info == NULL) {
2611 return NT_STATUS_NO_MEMORY;
2614 switch(r->in.level) {
2615 case ALIASINFOALL:
2616 QUERY_STRING(msg, all.name, "sAMAccountName");
2617 QUERY_UINT (msg, all.num_members, "numMembers");
2618 QUERY_STRING(msg, all.description, "description");
2619 break;
2620 case ALIASINFONAME:
2621 QUERY_STRING(msg, name, "sAMAccountName");
2622 break;
2623 case ALIASINFODESCRIPTION:
2624 QUERY_STRING(msg, description, "description");
2625 break;
2626 default:
2627 talloc_free(info);
2628 return NT_STATUS_INVALID_INFO_CLASS;
2631 *r->out.info = info;
2633 return NT_STATUS_OK;
2638 samr_SetAliasInfo
2640 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2641 struct samr_SetAliasInfo *r)
2643 struct dcesrv_handle *h;
2644 struct samr_account_state *a_state;
2645 struct ldb_message *msg;
2646 struct ldb_context *sam_ctx;
2647 int ret;
2649 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2651 a_state = h->data;
2652 sam_ctx = a_state->sam_ctx;
2654 msg = ldb_msg_new(mem_ctx);
2655 if (msg == NULL) {
2656 return NT_STATUS_NO_MEMORY;
2659 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2660 if (!msg->dn) {
2661 return NT_STATUS_NO_MEMORY;
2664 switch (r->in.level) {
2665 case ALIASINFODESCRIPTION:
2666 SET_STRING(msg, description, "description");
2667 break;
2668 case ALIASINFONAME:
2669 /* On W2k3 this does not change the name, it changes the
2670 * sAMAccountName attribute */
2671 SET_STRING(msg, name, "sAMAccountName");
2672 break;
2673 default:
2674 return NT_STATUS_INVALID_INFO_CLASS;
2677 /* modify the samdb record */
2678 ret = ldb_modify(a_state->sam_ctx, msg);
2679 if (ret != LDB_SUCCESS) {
2680 /* we really need samdb.c to return NTSTATUS */
2681 return NT_STATUS_UNSUCCESSFUL;
2684 return NT_STATUS_OK;
2689 samr_DeleteDomAlias
2691 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2692 struct samr_DeleteDomAlias *r)
2694 struct dcesrv_handle *h;
2695 struct samr_account_state *a_state;
2696 int ret;
2698 *r->out.alias_handle = *r->in.alias_handle;
2700 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2702 a_state = h->data;
2704 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2705 if (ret != LDB_SUCCESS) {
2706 return NT_STATUS_UNSUCCESSFUL;
2709 talloc_free(h);
2710 ZERO_STRUCTP(r->out.alias_handle);
2712 return NT_STATUS_OK;
2717 samr_AddAliasMember
2719 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2720 struct samr_AddAliasMember *r)
2722 struct dcesrv_handle *h;
2723 struct samr_account_state *a_state;
2724 struct samr_domain_state *d_state;
2725 struct ldb_message *mod;
2726 struct ldb_message **msgs;
2727 const char * const attrs[] = { NULL };
2728 struct ldb_dn *memberdn = NULL;
2729 int ret;
2730 NTSTATUS status;
2732 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2734 a_state = h->data;
2735 d_state = a_state->domain_state;
2737 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2738 &msgs, attrs, "(objectsid=%s)",
2739 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2741 if (ret == 1) {
2742 memberdn = msgs[0]->dn;
2743 } else if (ret > 1) {
2744 DEBUG(0,("Found %d records matching sid %s\n",
2745 ret, dom_sid_string(mem_ctx, r->in.sid)));
2746 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2747 } else if (ret == 0) {
2748 status = samdb_create_foreign_security_principal(
2749 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2750 if (!NT_STATUS_IS_OK(status)) {
2751 return status;
2753 } else {
2754 DEBUG(0, ("samdb_search returned %d: %s\n", ret,
2755 ldb_errstring(d_state->sam_ctx)));
2758 if (memberdn == NULL) {
2759 DEBUG(0, ("Could not find memberdn\n"));
2760 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2763 mod = ldb_msg_new(mem_ctx);
2764 if (mod == NULL) {
2765 return NT_STATUS_NO_MEMORY;
2768 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2770 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2771 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2772 if (ret != LDB_SUCCESS) {
2773 return NT_STATUS_UNSUCCESSFUL;
2776 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2777 return NT_STATUS_UNSUCCESSFUL;
2780 return NT_STATUS_OK;
2785 samr_DeleteAliasMember
2787 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2788 struct samr_DeleteAliasMember *r)
2790 struct dcesrv_handle *h;
2791 struct samr_account_state *a_state;
2792 struct samr_domain_state *d_state;
2793 struct ldb_message *mod;
2794 const char *memberdn;
2795 int ret;
2797 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2799 a_state = h->data;
2800 d_state = a_state->domain_state;
2802 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2803 "distinguishedName", "(objectSid=%s)",
2804 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2806 if (memberdn == NULL)
2807 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2809 mod = ldb_msg_new(mem_ctx);
2810 if (mod == NULL) {
2811 return NT_STATUS_NO_MEMORY;
2814 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2816 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2817 memberdn);
2818 if (ret != LDB_SUCCESS)
2819 return NT_STATUS_UNSUCCESSFUL;
2821 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2822 return NT_STATUS_UNSUCCESSFUL;
2824 return NT_STATUS_OK;
2829 samr_GetMembersInAlias
2831 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2832 struct samr_GetMembersInAlias *r)
2834 struct dcesrv_handle *h;
2835 struct samr_account_state *a_state;
2836 struct samr_domain_state *d_state;
2837 struct ldb_message **msgs;
2838 struct lsa_SidPtr *sids;
2839 struct ldb_message_element *el;
2840 const char * const attrs[2] = { "member", NULL};
2841 int ret;
2843 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2845 a_state = h->data;
2846 d_state = a_state->domain_state;
2848 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2849 a_state->account_dn, &msgs, attrs);
2851 if (ret == -1) {
2852 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2853 } else if (ret == 0) {
2854 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2855 } else if (ret != 1) {
2856 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2859 r->out.sids->num_sids = 0;
2860 r->out.sids->sids = NULL;
2862 el = ldb_msg_find_element(msgs[0], "member");
2864 if (el != NULL) {
2865 unsigned int i;
2867 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2868 el->num_values);
2870 if (sids == NULL)
2871 return NT_STATUS_NO_MEMORY;
2873 for (i=0; i<el->num_values; i++) {
2874 struct ldb_message **msgs2;
2875 const char * const attrs2[2] = { "objectSid", NULL };
2876 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2877 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2878 &msgs2, attrs2);
2879 if (ret != 1)
2880 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2882 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2883 "objectSid");
2885 if (sids[i].sid == NULL)
2886 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2888 r->out.sids->num_sids = el->num_values;
2889 r->out.sids->sids = sids;
2892 return NT_STATUS_OK;
2896 samr_OpenUser
2898 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2899 struct samr_OpenUser *r)
2901 struct samr_domain_state *d_state;
2902 struct samr_account_state *a_state;
2903 struct dcesrv_handle *h;
2904 const char *account_name;
2905 struct dom_sid *sid;
2906 struct ldb_message **msgs;
2907 struct dcesrv_handle *u_handle;
2908 const char * const attrs[2] = { "sAMAccountName", NULL };
2909 int ret;
2911 ZERO_STRUCTP(r->out.user_handle);
2913 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2915 d_state = h->data;
2917 /* form the users SID */
2918 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2919 if (!sid) {
2920 return NT_STATUS_NO_MEMORY;
2923 /* search for the user record */
2924 ret = gendb_search(d_state->sam_ctx,
2925 mem_ctx, d_state->domain_dn, &msgs, attrs,
2926 "(&(objectSid=%s)(objectclass=user))",
2927 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2928 if (ret == 0) {
2929 return NT_STATUS_NO_SUCH_USER;
2931 if (ret != 1) {
2932 DEBUG(0,("Found %d records matching sid %s\n", ret,
2933 dom_sid_string(mem_ctx, sid)));
2934 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2937 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2938 if (account_name == NULL) {
2939 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2940 dom_sid_string(mem_ctx, sid)));
2941 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2944 a_state = talloc(mem_ctx, struct samr_account_state);
2945 if (!a_state) {
2946 return NT_STATUS_NO_MEMORY;
2948 a_state->sam_ctx = d_state->sam_ctx;
2949 a_state->access_mask = r->in.access_mask;
2950 a_state->domain_state = talloc_reference(a_state, d_state);
2951 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2952 a_state->account_sid = talloc_steal(a_state, sid);
2953 a_state->account_name = talloc_strdup(a_state, account_name);
2954 if (!a_state->account_name) {
2955 return NT_STATUS_NO_MEMORY;
2958 /* create the policy handle */
2959 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2960 if (!u_handle) {
2961 return NT_STATUS_NO_MEMORY;
2964 u_handle->data = talloc_steal(u_handle, a_state);
2966 *r->out.user_handle = u_handle->wire_handle;
2968 return NT_STATUS_OK;
2974 samr_DeleteUser
2976 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2977 struct samr_DeleteUser *r)
2979 struct dcesrv_handle *h;
2980 struct samr_account_state *a_state;
2981 int ret;
2983 *r->out.user_handle = *r->in.user_handle;
2985 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2987 a_state = h->data;
2989 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2990 if (ret != LDB_SUCCESS) {
2991 DEBUG(1, ("Failed to delete user: %s: %s\n",
2992 ldb_dn_get_linearized(a_state->account_dn),
2993 ldb_errstring(a_state->sam_ctx)));
2994 return NT_STATUS_UNSUCCESSFUL;
2997 talloc_free(h);
2998 ZERO_STRUCTP(r->out.user_handle);
3000 return NT_STATUS_OK;
3005 samr_QueryUserInfo
3007 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3008 struct samr_QueryUserInfo *r)
3010 struct dcesrv_handle *h;
3011 struct samr_account_state *a_state;
3012 struct ldb_message *msg, **res;
3013 int ret;
3014 struct ldb_context *sam_ctx;
3016 const char * const *attrs = NULL;
3017 union samr_UserInfo *info;
3019 *r->out.info = NULL;
3021 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3023 a_state = h->data;
3024 sam_ctx = a_state->sam_ctx;
3026 /* fill in the reply */
3027 switch (r->in.level) {
3028 case 1:
3030 static const char * const attrs2[] = {"sAMAccountName",
3031 "displayName",
3032 "primaryroupID",
3033 "description",
3034 "comment",
3035 NULL};
3036 attrs = attrs2;
3037 break;
3039 case 2:
3041 static const char * const attrs2[] = {"comment",
3042 "countryCode",
3043 "codePage",
3044 NULL};
3045 attrs = attrs2;
3046 break;
3048 case 3:
3050 static const char * const attrs2[] = {"sAMAccountName",
3051 "displayName",
3052 "objectSid",
3053 "primaryGroupID",
3054 "homeDirectory",
3055 "homeDrive",
3056 "scriptPath",
3057 "profilePath",
3058 "userWorkstations",
3059 "lastLogon",
3060 "lastLogoff",
3061 "pwdLastSet",
3062 "logonHours",
3063 "badPwdCount",
3064 "logonCount",
3065 "userAccountControl",
3066 NULL};
3067 attrs = attrs2;
3068 break;
3070 case 4:
3072 static const char * const attrs2[] = {"logonHours",
3073 NULL};
3074 attrs = attrs2;
3075 break;
3077 case 5:
3079 static const char * const attrs2[] = {"sAMAccountName",
3080 "displayName",
3081 "objectSid",
3082 "primaryGroupID",
3083 "homeDirectory",
3084 "homeDrive",
3085 "scriptPath",
3086 "profilePath",
3087 "description",
3088 "userWorkstations",
3089 "lastLogon",
3090 "lastLogoff",
3091 "logonHours",
3092 "badPwdCount",
3093 "logonCount",
3094 "pwdLastSet",
3095 "accountExpires",
3096 "userAccountControl",
3097 NULL};
3098 attrs = attrs2;
3099 break;
3101 case 6:
3103 static const char * const attrs2[] = {"sAMAccountName",
3104 "displayName",
3105 NULL};
3106 attrs = attrs2;
3107 break;
3109 case 7:
3111 static const char * const attrs2[] = {"sAMAccountName",
3112 NULL};
3113 attrs = attrs2;
3114 break;
3116 case 8:
3118 static const char * const attrs2[] = {"displayName",
3119 NULL};
3120 attrs = attrs2;
3121 break;
3123 case 9:
3125 static const char * const attrs2[] = {"primaryGroupID",
3126 NULL};
3127 attrs = attrs2;
3128 break;
3130 case 10:
3132 static const char * const attrs2[] = {"homeDirectory",
3133 "homeDrive",
3134 NULL};
3135 attrs = attrs2;
3136 break;
3138 case 11:
3140 static const char * const attrs2[] = {"scriptPath",
3141 NULL};
3142 attrs = attrs2;
3143 break;
3145 case 12:
3147 static const char * const attrs2[] = {"profilePath",
3148 NULL};
3149 attrs = attrs2;
3150 break;
3152 case 13:
3154 static const char * const attrs2[] = {"description",
3155 NULL};
3156 attrs = attrs2;
3157 break;
3159 case 14:
3161 static const char * const attrs2[] = {"userWorkstations",
3162 NULL};
3163 attrs = attrs2;
3164 break;
3166 case 16:
3168 static const char * const attrs2[] = {"userAccountControl",
3169 "pwdLastSet",
3170 NULL};
3171 attrs = attrs2;
3172 break;
3174 case 17:
3176 static const char * const attrs2[] = {"accountExpires",
3177 NULL};
3178 attrs = attrs2;
3179 break;
3181 case 18:
3183 return NT_STATUS_NOT_SUPPORTED;
3185 case 20:
3187 static const char * const attrs2[] = {"userParameters",
3188 NULL};
3189 attrs = attrs2;
3190 break;
3192 case 21:
3194 static const char * const attrs2[] = {"lastLogon",
3195 "lastLogoff",
3196 "pwdLastSet",
3197 "accountExpires",
3198 "sAMAccountName",
3199 "displayName",
3200 "homeDirectory",
3201 "homeDrive",
3202 "scriptPath",
3203 "profilePath",
3204 "description",
3205 "userWorkstations",
3206 "comment",
3207 "userParameters",
3208 "objectSid",
3209 "primaryGroupID",
3210 "userAccountControl",
3211 "logonHours",
3212 "badPwdCount",
3213 "logonCount",
3214 "countryCode",
3215 "codePage",
3216 NULL};
3217 attrs = attrs2;
3218 break;
3220 case 23:
3221 case 24:
3222 case 25:
3223 case 26:
3225 return NT_STATUS_NOT_SUPPORTED;
3227 default:
3229 return NT_STATUS_INVALID_INFO_CLASS;
3233 /* pull all the user attributes */
3234 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3235 a_state->account_dn ,&res, attrs);
3236 if (ret != 1) {
3237 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3239 msg = res[0];
3241 /* allocate the info structure */
3242 info = talloc_zero(mem_ctx, union samr_UserInfo);
3243 if (info == NULL) {
3244 return NT_STATUS_NO_MEMORY;
3247 /* fill in the reply */
3248 switch (r->in.level) {
3249 case 1:
3250 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3251 QUERY_STRING(msg, info1.full_name, "displayName");
3252 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3253 QUERY_STRING(msg, info1.description, "description");
3254 QUERY_STRING(msg, info1.comment, "comment");
3255 break;
3257 case 2:
3258 QUERY_STRING(msg, info2.comment, "comment");
3259 QUERY_UINT (msg, info2.country_code, "countryCode");
3260 QUERY_UINT (msg, info2.code_page, "codePage");
3261 break;
3263 case 3:
3264 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3265 QUERY_STRING(msg, info3.full_name, "displayName");
3266 QUERY_RID (msg, info3.rid, "objectSid");
3267 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3268 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3269 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3270 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3271 QUERY_STRING(msg, info3.profile_path, "profilePath");
3272 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3273 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3274 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3275 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3276 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3277 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3278 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3279 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3280 QUERY_UINT (msg, info3.logon_count, "logonCount");
3281 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3282 break;
3284 case 4:
3285 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3286 break;
3288 case 5:
3289 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3290 QUERY_STRING(msg, info5.full_name, "displayName");
3291 QUERY_RID (msg, info5.rid, "objectSid");
3292 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3293 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3294 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3295 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3296 QUERY_STRING(msg, info5.profile_path, "profilePath");
3297 QUERY_STRING(msg, info5.description, "description");
3298 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3299 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3300 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3301 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3302 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3303 QUERY_UINT (msg, info5.logon_count, "logonCount");
3304 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3305 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3306 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3307 break;
3309 case 6:
3310 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3311 QUERY_STRING(msg, info6.full_name, "displayName");
3312 break;
3314 case 7:
3315 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3316 break;
3318 case 8:
3319 QUERY_STRING(msg, info8.full_name, "displayName");
3320 break;
3322 case 9:
3323 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3324 break;
3326 case 10:
3327 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3328 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3329 break;
3331 case 11:
3332 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3333 break;
3335 case 12:
3336 QUERY_STRING(msg, info12.profile_path, "profilePath");
3337 break;
3339 case 13:
3340 QUERY_STRING(msg, info13.description, "description");
3341 break;
3343 case 14:
3344 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3345 break;
3347 case 16:
3348 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3349 break;
3351 case 17:
3352 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3353 break;
3355 case 20:
3356 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3357 break;
3359 case 21:
3360 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3361 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3362 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3363 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3364 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3365 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3366 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3367 QUERY_STRING(msg, info21.full_name, "displayName");
3368 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3369 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3370 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3371 QUERY_STRING(msg, info21.profile_path, "profilePath");
3372 QUERY_STRING(msg, info21.description, "description");
3373 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3374 QUERY_STRING(msg, info21.comment, "comment");
3375 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3376 QUERY_RID (msg, info21.rid, "objectSid");
3377 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3378 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3379 info->info21.fields_present = 0x00FFFFFF;
3380 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3381 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3382 QUERY_UINT (msg, info21.logon_count, "logonCount");
3383 QUERY_UINT (msg, info21.country_code, "countryCode");
3384 QUERY_UINT (msg, info21.code_page, "codePage");
3385 break;
3388 default:
3389 talloc_free(info);
3390 return NT_STATUS_INVALID_INFO_CLASS;
3393 *r->out.info = info;
3395 return NT_STATUS_OK;
3400 samr_SetUserInfo
3402 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3403 struct samr_SetUserInfo *r)
3405 struct dcesrv_handle *h;
3406 struct samr_account_state *a_state;
3407 struct ldb_message *msg;
3408 int ret;
3409 NTSTATUS status = NT_STATUS_OK;
3410 struct ldb_context *sam_ctx;
3412 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3414 a_state = h->data;
3415 sam_ctx = a_state->sam_ctx;
3417 msg = ldb_msg_new(mem_ctx);
3418 if (msg == NULL) {
3419 return NT_STATUS_NO_MEMORY;
3422 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3423 if (!msg->dn) {
3424 return NT_STATUS_NO_MEMORY;
3427 switch (r->in.level) {
3428 case 2:
3429 SET_STRING(msg, info2.comment, "comment");
3430 SET_UINT (msg, info2.country_code, "countryCode");
3431 SET_UINT (msg, info2.code_page, "codePage");
3432 break;
3434 case 4:
3435 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3436 break;
3438 case 6:
3439 SET_STRING(msg, info6.account_name, "samAccountName");
3440 SET_STRING(msg, info6.full_name, "displayName");
3441 break;
3443 case 7:
3444 SET_STRING(msg, info7.account_name, "samAccountName");
3445 break;
3447 case 8:
3448 SET_STRING(msg, info8.full_name, "displayName");
3449 break;
3451 case 9:
3452 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3453 break;
3455 case 10:
3456 SET_STRING(msg, info10.home_directory, "homeDirectory");
3457 SET_STRING(msg, info10.home_drive, "homeDrive");
3458 break;
3460 case 11:
3461 SET_STRING(msg, info11.logon_script, "scriptPath");
3462 break;
3464 case 12:
3465 SET_STRING(msg, info12.profile_path, "profilePath");
3466 break;
3468 case 13:
3469 SET_STRING(msg, info13.description, "description");
3470 break;
3472 case 14:
3473 SET_STRING(msg, info14.workstations, "userWorkstations");
3474 break;
3476 case 16:
3477 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3478 break;
3480 case 17:
3481 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3482 break;
3484 case 20:
3485 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3486 break;
3488 case 21:
3489 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3490 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3491 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3492 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3493 SET_STRING(msg, info21.account_name, "samAccountName");
3494 IFSET(SAMR_FIELD_FULL_NAME)
3495 SET_STRING(msg, info21.full_name, "displayName");
3496 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3497 SET_STRING(msg, info21.home_directory, "homeDirectory");
3498 IFSET(SAMR_FIELD_HOME_DRIVE)
3499 SET_STRING(msg, info21.home_drive, "homeDrive");
3500 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3501 SET_STRING(msg, info21.logon_script, "scriptPath");
3502 IFSET(SAMR_FIELD_PROFILE_PATH)
3503 SET_STRING(msg, info21.profile_path, "profilePath");
3504 IFSET(SAMR_FIELD_DESCRIPTION)
3505 SET_STRING(msg, info21.description, "description");
3506 IFSET(SAMR_FIELD_WORKSTATIONS)
3507 SET_STRING(msg, info21.workstations, "userWorkstations");
3508 IFSET(SAMR_FIELD_COMMENT)
3509 SET_STRING(msg, info21.comment, "comment");
3510 IFSET(SAMR_FIELD_PARAMETERS)
3511 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3512 IFSET(SAMR_FIELD_PRIMARY_GID)
3513 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3514 IFSET(SAMR_FIELD_ACCT_FLAGS)
3515 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3516 IFSET(SAMR_FIELD_LOGON_HOURS)
3517 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3518 IFSET(SAMR_FIELD_COUNTRY_CODE)
3519 SET_UINT (msg, info21.country_code, "countryCode");
3520 IFSET(SAMR_FIELD_CODE_PAGE)
3521 SET_UINT (msg, info21.code_page, "codePage");
3522 #undef IFSET
3523 break;
3525 case 23:
3526 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3527 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3528 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3529 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3530 SET_STRING(msg, info23.info.account_name, "samAccountName");
3531 IFSET(SAMR_FIELD_FULL_NAME)
3532 SET_STRING(msg, info23.info.full_name, "displayName");
3533 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3534 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3535 IFSET(SAMR_FIELD_HOME_DRIVE)
3536 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3537 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3538 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3539 IFSET(SAMR_FIELD_PROFILE_PATH)
3540 SET_STRING(msg, info23.info.profile_path, "profilePath");
3541 IFSET(SAMR_FIELD_DESCRIPTION)
3542 SET_STRING(msg, info23.info.description, "description");
3543 IFSET(SAMR_FIELD_WORKSTATIONS)
3544 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3545 IFSET(SAMR_FIELD_COMMENT)
3546 SET_STRING(msg, info23.info.comment, "comment");
3547 IFSET(SAMR_FIELD_PARAMETERS)
3548 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3549 IFSET(SAMR_FIELD_PRIMARY_GID)
3550 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3551 IFSET(SAMR_FIELD_ACCT_FLAGS)
3552 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3553 IFSET(SAMR_FIELD_LOGON_HOURS)
3554 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3555 IFSET(SAMR_FIELD_COUNTRY_CODE)
3556 SET_UINT (msg, info23.info.country_code, "countryCode");
3557 IFSET(SAMR_FIELD_CODE_PAGE)
3558 SET_UINT (msg, info23.info.code_page, "codePage");
3560 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3561 status = samr_set_password(dce_call,
3562 a_state->sam_ctx,
3563 a_state->account_dn,
3564 a_state->domain_state->domain_dn,
3565 mem_ctx,
3566 &r->in.info->info23.password);
3567 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3568 status = samr_set_password(dce_call,
3569 a_state->sam_ctx,
3570 a_state->account_dn,
3571 a_state->domain_state->domain_dn,
3572 mem_ctx,
3573 &r->in.info->info23.password);
3575 #undef IFSET
3576 break;
3578 /* the set password levels are handled separately */
3579 case 24:
3580 status = samr_set_password(dce_call,
3581 a_state->sam_ctx,
3582 a_state->account_dn,
3583 a_state->domain_state->domain_dn,
3584 mem_ctx,
3585 &r->in.info->info24.password);
3586 break;
3588 case 25:
3589 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3590 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3591 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3592 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3593 SET_STRING(msg, info25.info.account_name, "samAccountName");
3594 IFSET(SAMR_FIELD_FULL_NAME)
3595 SET_STRING(msg, info25.info.full_name, "displayName");
3596 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3597 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3598 IFSET(SAMR_FIELD_HOME_DRIVE)
3599 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3600 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3601 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3602 IFSET(SAMR_FIELD_PROFILE_PATH)
3603 SET_STRING(msg, info25.info.profile_path, "profilePath");
3604 IFSET(SAMR_FIELD_DESCRIPTION)
3605 SET_STRING(msg, info25.info.description, "description");
3606 IFSET(SAMR_FIELD_WORKSTATIONS)
3607 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3608 IFSET(SAMR_FIELD_COMMENT)
3609 SET_STRING(msg, info25.info.comment, "comment");
3610 IFSET(SAMR_FIELD_PARAMETERS)
3611 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3612 IFSET(SAMR_FIELD_PRIMARY_GID)
3613 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3614 IFSET(SAMR_FIELD_ACCT_FLAGS)
3615 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3616 IFSET(SAMR_FIELD_LOGON_HOURS)
3617 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3618 IFSET(SAMR_FIELD_COUNTRY_CODE)
3619 SET_UINT (msg, info25.info.country_code, "countryCode");
3620 IFSET(SAMR_FIELD_CODE_PAGE)
3621 SET_UINT (msg, info25.info.code_page, "codePage");
3623 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3624 status = samr_set_password_ex(dce_call,
3625 a_state->sam_ctx,
3626 a_state->account_dn,
3627 a_state->domain_state->domain_dn,
3628 mem_ctx,
3629 &r->in.info->info25.password);
3630 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3631 status = samr_set_password_ex(dce_call,
3632 a_state->sam_ctx,
3633 a_state->account_dn,
3634 a_state->domain_state->domain_dn,
3635 mem_ctx,
3636 &r->in.info->info25.password);
3638 #undef IFSET
3639 break;
3641 /* the set password levels are handled separately */
3642 case 26:
3643 status = samr_set_password_ex(dce_call,
3644 a_state->sam_ctx,
3645 a_state->account_dn,
3646 a_state->domain_state->domain_dn,
3647 mem_ctx,
3648 &r->in.info->info26.password);
3649 break;
3652 default:
3653 /* many info classes are not valid for SetUserInfo */
3654 return NT_STATUS_INVALID_INFO_CLASS;
3657 if (!NT_STATUS_IS_OK(status)) {
3658 return status;
3661 /* modify the samdb record */
3662 if (msg->num_elements > 0) {
3663 ret = ldb_modify(a_state->sam_ctx, msg);
3664 if (ret != LDB_SUCCESS) {
3665 DEBUG(1,("Failed to modify record %s: %s\n",
3666 ldb_dn_get_linearized(a_state->account_dn),
3667 ldb_errstring(a_state->sam_ctx)));
3669 /* we really need samdb.c to return NTSTATUS */
3670 return NT_STATUS_UNSUCCESSFUL;
3674 return NT_STATUS_OK;
3679 samr_GetGroupsForUser
3681 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3682 struct samr_GetGroupsForUser *r)
3684 struct dcesrv_handle *h;
3685 struct samr_account_state *a_state;
3686 struct samr_domain_state *d_state;
3687 struct ldb_message **res;
3688 const char * const attrs[2] = { "objectSid", NULL };
3689 struct samr_RidWithAttributeArray *array;
3690 int i, count;
3692 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3694 a_state = h->data;
3695 d_state = a_state->domain_state;
3697 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3698 d_state->domain_dn, &res,
3699 attrs, d_state->domain_sid,
3700 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3701 ldb_dn_get_linearized(a_state->account_dn),
3702 GTYPE_SECURITY_GLOBAL_GROUP);
3703 if (count < 0)
3704 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3706 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3707 if (array == NULL)
3708 return NT_STATUS_NO_MEMORY;
3710 array->count = 0;
3711 array->rids = NULL;
3713 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3714 count + 1);
3715 if (array->rids == NULL)
3716 return NT_STATUS_NO_MEMORY;
3718 /* Adds the primary group */
3719 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3720 ~0, a_state->account_dn,
3721 "primaryGroupID", NULL);
3722 array->rids[0].attributes = SE_GROUP_MANDATORY
3723 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3724 array->count += 1;
3726 /* Adds the additional groups */
3727 for (i = 0; i < count; i++) {
3728 struct dom_sid *group_sid;
3730 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3731 if (group_sid == NULL) {
3732 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3733 continue;
3736 array->rids[i + 1].rid =
3737 group_sid->sub_auths[group_sid->num_auths-1];
3738 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3739 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3740 array->count += 1;
3743 *r->out.rids = array;
3745 return NT_STATUS_OK;
3750 samr_QueryDisplayInfo
3752 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3753 struct samr_QueryDisplayInfo *r)
3755 struct dcesrv_handle *h;
3756 struct samr_domain_state *d_state;
3757 struct ldb_message **res;
3758 int i, ldb_cnt;
3759 uint32_t count;
3760 const char * const attrs[] = { "objectSid", "sAMAccountName",
3761 "displayName", "description", "userAccountControl",
3762 "pwdLastSet", NULL };
3763 struct samr_DispEntryFull *entriesFull = NULL;
3764 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3765 struct samr_DispEntryAscii *entriesAscii = NULL;
3766 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3767 const char *filter;
3769 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3771 d_state = h->data;
3773 switch (r->in.level) {
3774 case 1:
3775 case 4:
3776 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3777 "(sAMAccountType=%u))",
3778 ATYPE_NORMAL_ACCOUNT);
3779 break;
3780 case 2:
3781 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3782 "(sAMAccountType=%u))",
3783 ATYPE_WORKSTATION_TRUST);
3784 break;
3785 case 3:
3786 case 5:
3787 filter = talloc_asprintf(mem_ctx,
3788 "(&(|(groupType=%d)(groupType=%d))"
3789 "(objectClass=group))",
3790 GTYPE_SECURITY_UNIVERSAL_GROUP,
3791 GTYPE_SECURITY_GLOBAL_GROUP);
3792 break;
3793 default:
3794 return NT_STATUS_INVALID_INFO_CLASS;
3797 /* search for all requested objects in this domain. This could
3798 possibly be cached and resumed based on resume_key */
3799 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3800 d_state->domain_dn, &res, attrs,
3801 d_state->domain_sid, "%s", filter);
3802 if (ldb_cnt == -1) {
3803 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3805 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3806 return NT_STATUS_OK;
3809 switch (r->in.level) {
3810 case 1:
3811 entriesGeneral = talloc_array(mem_ctx,
3812 struct samr_DispEntryGeneral,
3813 ldb_cnt);
3814 break;
3815 case 2:
3816 entriesFull = talloc_array(mem_ctx,
3817 struct samr_DispEntryFull,
3818 ldb_cnt);
3819 break;
3820 case 3:
3821 entriesFullGroup = talloc_array(mem_ctx,
3822 struct samr_DispEntryFullGroup,
3823 ldb_cnt);
3824 break;
3825 case 4:
3826 case 5:
3827 entriesAscii = talloc_array(mem_ctx,
3828 struct samr_DispEntryAscii,
3829 ldb_cnt);
3830 break;
3833 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3834 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3835 return NT_STATUS_NO_MEMORY;
3837 count = 0;
3839 for (i=0; i<ldb_cnt; i++) {
3840 struct dom_sid *objectsid;
3842 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3843 "objectSid");
3844 if (objectsid == NULL)
3845 continue;
3847 switch(r->in.level) {
3848 case 1:
3849 entriesGeneral[count].idx = count + 1;
3850 entriesGeneral[count].rid =
3851 objectsid->sub_auths[objectsid->num_auths-1];
3852 entriesGeneral[count].acct_flags =
3853 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3854 res[i],
3855 d_state->domain_dn);
3856 entriesGeneral[count].account_name.string =
3857 samdb_result_string(res[i],
3858 "sAMAccountName", "");
3859 entriesGeneral[count].full_name.string =
3860 samdb_result_string(res[i], "displayName", "");
3861 entriesGeneral[count].description.string =
3862 samdb_result_string(res[i], "description", "");
3863 break;
3864 case 2:
3865 entriesFull[count].idx = count + 1;
3866 entriesFull[count].rid =
3867 objectsid->sub_auths[objectsid->num_auths-1];
3869 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3870 entriesFull[count].acct_flags =
3871 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3872 res[i],
3873 d_state->domain_dn) | ACB_NORMAL;
3874 entriesFull[count].account_name.string =
3875 samdb_result_string(res[i], "sAMAccountName",
3876 "");
3877 entriesFull[count].description.string =
3878 samdb_result_string(res[i], "description", "");
3879 break;
3880 case 3:
3881 entriesFullGroup[count].idx = count + 1;
3882 entriesFullGroup[count].rid =
3883 objectsid->sub_auths[objectsid->num_auths-1];
3884 /* We get a "7" here for groups */
3885 entriesFullGroup[count].acct_flags
3886 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3887 entriesFullGroup[count].account_name.string =
3888 samdb_result_string(res[i], "sAMAccountName",
3889 "");
3890 entriesFullGroup[count].description.string =
3891 samdb_result_string(res[i], "description", "");
3892 break;
3893 case 4:
3894 case 5:
3895 entriesAscii[count].idx = count + 1;
3896 entriesAscii[count].account_name.string =
3897 samdb_result_string(res[i], "sAMAccountName",
3898 "");
3899 break;
3902 count += 1;
3905 *r->out.total_size = count;
3907 if (r->in.start_idx >= count) {
3908 *r->out.returned_size = 0;
3909 switch(r->in.level) {
3910 case 1:
3911 r->out.info->info1.count = *r->out.returned_size;
3912 r->out.info->info1.entries = NULL;
3913 break;
3914 case 2:
3915 r->out.info->info2.count = *r->out.returned_size;
3916 r->out.info->info2.entries = NULL;
3917 break;
3918 case 3:
3919 r->out.info->info3.count = *r->out.returned_size;
3920 r->out.info->info3.entries = NULL;
3921 break;
3922 case 4:
3923 r->out.info->info4.count = *r->out.returned_size;
3924 r->out.info->info4.entries = NULL;
3925 break;
3926 case 5:
3927 r->out.info->info5.count = *r->out.returned_size;
3928 r->out.info->info5.entries = NULL;
3929 break;
3931 } else {
3932 *r->out.returned_size = MIN(count - r->in.start_idx,
3933 r->in.max_entries);
3934 switch(r->in.level) {
3935 case 1:
3936 r->out.info->info1.count = *r->out.returned_size;
3937 r->out.info->info1.entries =
3938 &(entriesGeneral[r->in.start_idx]);
3939 break;
3940 case 2:
3941 r->out.info->info2.count = *r->out.returned_size;
3942 r->out.info->info2.entries =
3943 &(entriesFull[r->in.start_idx]);
3944 break;
3945 case 3:
3946 r->out.info->info3.count = *r->out.returned_size;
3947 r->out.info->info3.entries =
3948 &(entriesFullGroup[r->in.start_idx]);
3949 break;
3950 case 4:
3951 r->out.info->info4.count = *r->out.returned_size;
3952 r->out.info->info4.entries =
3953 &(entriesAscii[r->in.start_idx]);
3954 break;
3955 case 5:
3956 r->out.info->info5.count = *r->out.returned_size;
3957 r->out.info->info5.entries =
3958 &(entriesAscii[r->in.start_idx]);
3959 break;
3963 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3964 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3969 samr_GetDisplayEnumerationIndex
3971 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3972 struct samr_GetDisplayEnumerationIndex *r)
3974 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3979 samr_TestPrivateFunctionsDomain
3981 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3982 struct samr_TestPrivateFunctionsDomain *r)
3984 return NT_STATUS_NOT_IMPLEMENTED;
3989 samr_TestPrivateFunctionsUser
3991 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3992 struct samr_TestPrivateFunctionsUser *r)
3994 return NT_STATUS_NOT_IMPLEMENTED;
3999 samr_GetUserPwInfo
4001 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4002 struct samr_GetUserPwInfo *r)
4004 struct dcesrv_handle *h;
4005 struct samr_account_state *a_state;
4007 ZERO_STRUCTP(r->out.info);
4009 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4011 a_state = h->data;
4013 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4014 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4015 NULL);
4016 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4017 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4019 return NT_STATUS_OK;
4024 samr_RemoveMemberFromForeignDomain
4026 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4027 struct samr_RemoveMemberFromForeignDomain *r)
4029 struct dcesrv_handle *h;
4030 struct samr_domain_state *d_state;
4031 const char *memberdn;
4032 struct ldb_message **res;
4033 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
4034 int i, count;
4036 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4038 d_state = h->data;
4040 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4041 "distinguishedName", "(objectSid=%s)",
4042 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4043 /* Nothing to do */
4044 if (memberdn == NULL) {
4045 return NT_STATUS_OK;
4048 /* TODO: Does this call only remove alias members, or does it do this
4049 * for domain groups as well? */
4051 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4052 d_state->domain_dn, &res, attrs,
4053 d_state->domain_sid,
4054 "(&(member=%s)(objectClass=group)"
4055 "(|(groupType=%d)(groupType=%d)))",
4056 memberdn,
4057 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4058 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4060 if (count < 0)
4061 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4063 for (i=0; i<count; i++) {
4064 struct ldb_message *mod;
4066 mod = ldb_msg_new(mem_ctx);
4067 if (mod == NULL) {
4068 return NT_STATUS_NO_MEMORY;
4071 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4072 if (mod->dn == NULL) {
4073 talloc_free(mod);
4074 continue;
4077 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4078 "member", memberdn) != LDB_SUCCESS)
4079 return NT_STATUS_NO_MEMORY;
4081 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
4082 return NT_STATUS_UNSUCCESSFUL;
4084 talloc_free(mod);
4087 return NT_STATUS_OK;
4092 samr_QueryDomainInfo2
4094 just an alias for samr_QueryDomainInfo
4096 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4097 struct samr_QueryDomainInfo2 *r)
4099 struct samr_QueryDomainInfo r1;
4100 NTSTATUS status;
4102 ZERO_STRUCT(r1.out);
4103 r1.in.domain_handle = r->in.domain_handle;
4104 r1.in.level = r->in.level;
4105 r1.out.info = r->out.info;
4107 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4109 return status;
4114 samr_QueryUserInfo2
4116 just an alias for samr_QueryUserInfo
4118 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4119 struct samr_QueryUserInfo2 *r)
4121 struct samr_QueryUserInfo r1;
4122 NTSTATUS status;
4124 r1.in.user_handle = r->in.user_handle;
4125 r1.in.level = r->in.level;
4126 r1.out.info = r->out.info;
4128 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4130 return status;
4135 samr_QueryDisplayInfo2
4137 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4138 struct samr_QueryDisplayInfo2 *r)
4140 struct samr_QueryDisplayInfo q;
4141 NTSTATUS result;
4143 q.in.domain_handle = r->in.domain_handle;
4144 q.in.level = r->in.level;
4145 q.in.start_idx = r->in.start_idx;
4146 q.in.max_entries = r->in.max_entries;
4147 q.in.buf_size = r->in.buf_size;
4148 q.out.total_size = r->out.total_size;
4149 q.out.returned_size = r->out.returned_size;
4150 q.out.info = r->out.info;
4152 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4154 return result;
4159 samr_GetDisplayEnumerationIndex2
4161 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4162 struct samr_GetDisplayEnumerationIndex2 *r)
4164 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4169 samr_QueryDisplayInfo3
4171 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4172 struct samr_QueryDisplayInfo3 *r)
4174 struct samr_QueryDisplayInfo q;
4175 NTSTATUS result;
4177 q.in.domain_handle = r->in.domain_handle;
4178 q.in.level = r->in.level;
4179 q.in.start_idx = r->in.start_idx;
4180 q.in.max_entries = r->in.max_entries;
4181 q.in.buf_size = r->in.buf_size;
4182 q.out.total_size = r->out.total_size;
4183 q.out.returned_size = r->out.returned_size;
4184 q.out.info = r->out.info;
4186 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4188 return result;
4193 samr_AddMultipleMembersToAlias
4195 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4196 struct samr_AddMultipleMembersToAlias *r)
4198 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4203 samr_RemoveMultipleMembersFromAlias
4205 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4206 struct samr_RemoveMultipleMembersFromAlias *r)
4208 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4213 samr_GetDomPwInfo
4215 this fetches the default password properties for a domain
4217 note that w2k3 completely ignores the domain name in this call, and
4218 always returns the information for the servers primary domain
4220 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4221 struct samr_GetDomPwInfo *r)
4223 struct ldb_message **msgs;
4224 int ret;
4225 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4226 struct ldb_context *sam_ctx;
4228 ZERO_STRUCTP(r->out.info);
4230 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4231 dce_call->conn->dce_ctx->lp_ctx,
4232 dce_call->conn->auth_state.session_info);
4233 if (sam_ctx == NULL) {
4234 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4237 /* The domain name in this call is ignored */
4238 ret = gendb_search_dn(sam_ctx,
4239 mem_ctx, NULL, &msgs, attrs);
4240 if (ret <= 0) {
4241 talloc_free(sam_ctx);
4243 return NT_STATUS_NO_SUCH_DOMAIN;
4245 if (ret > 1) {
4246 talloc_free(msgs);
4247 talloc_free(sam_ctx);
4249 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4252 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4253 "minPwdLength", 0);
4254 r->out.info->password_properties = samdb_result_uint(msgs[0],
4255 "pwdProperties", 1);
4257 talloc_free(msgs);
4258 talloc_unlink(mem_ctx, sam_ctx);
4260 return NT_STATUS_OK;
4265 samr_Connect2
4267 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4268 struct samr_Connect2 *r)
4270 struct samr_Connect c;
4272 c.in.system_name = NULL;
4273 c.in.access_mask = r->in.access_mask;
4274 c.out.connect_handle = r->out.connect_handle;
4276 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4281 samr_SetUserInfo2
4283 just an alias for samr_SetUserInfo
4285 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4286 struct samr_SetUserInfo2 *r)
4288 struct samr_SetUserInfo r2;
4290 r2.in.user_handle = r->in.user_handle;
4291 r2.in.level = r->in.level;
4292 r2.in.info = r->in.info;
4294 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4299 samr_SetBootKeyInformation
4301 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4302 struct samr_SetBootKeyInformation *r)
4304 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4309 samr_GetBootKeyInformation
4311 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4312 struct samr_GetBootKeyInformation *r)
4314 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4319 samr_Connect3
4321 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4322 struct samr_Connect3 *r)
4324 struct samr_Connect c;
4326 c.in.system_name = NULL;
4327 c.in.access_mask = r->in.access_mask;
4328 c.out.connect_handle = r->out.connect_handle;
4330 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4335 samr_Connect4
4337 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4338 struct samr_Connect4 *r)
4340 struct samr_Connect c;
4342 c.in.system_name = NULL;
4343 c.in.access_mask = r->in.access_mask;
4344 c.out.connect_handle = r->out.connect_handle;
4346 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4351 samr_Connect5
4353 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4354 struct samr_Connect5 *r)
4356 struct samr_Connect c;
4357 NTSTATUS status;
4359 c.in.system_name = NULL;
4360 c.in.access_mask = r->in.access_mask;
4361 c.out.connect_handle = r->out.connect_handle;
4363 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4365 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4366 r->out.info_out->info1.unknown2 = 0;
4367 *r->out.level_out = r->in.level_in;
4369 return status;
4374 samr_RidToSid
4376 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4377 struct samr_RidToSid *r)
4379 struct samr_domain_state *d_state;
4380 struct dcesrv_handle *h;
4382 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4384 d_state = h->data;
4386 /* form the users SID */
4387 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4388 if (!*r->out.sid) {
4389 return NT_STATUS_NO_MEMORY;
4392 return NT_STATUS_OK;
4397 samr_SetDsrmPassword
4399 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4400 struct samr_SetDsrmPassword *r)
4402 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4407 samr_ValidatePassword
4409 For now the call checks the password complexity (if active) and the minimum
4410 password length on level 2 and 3. Level 1 is ignored for now.
4412 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4413 TALLOC_CTX *mem_ctx,
4414 struct samr_ValidatePassword *r)
4416 struct samr_GetDomPwInfo r2;
4417 struct samr_PwInfo pwInfo;
4418 DATA_BLOB password;
4419 enum samr_ValidationStatus res;
4420 NTSTATUS status;
4422 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4424 r2.in.domain_name = NULL;
4425 r2.out.info = &pwInfo;
4426 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4427 if (!NT_STATUS_IS_OK(status)) {
4428 return status;
4431 switch (r->in.level) {
4432 case NetValidateAuthentication:
4433 /* we don't support this yet */
4434 return NT_STATUS_NOT_SUPPORTED;
4435 break;
4436 case NetValidatePasswordChange:
4437 password = data_blob_const(r->in.req->req2.password.string,
4438 r->in.req->req2.password.length);
4439 res = samdb_check_password(&password,
4440 pwInfo.password_properties,
4441 pwInfo.min_password_length);
4442 (*r->out.rep)->ctr2.status = res;
4443 break;
4444 case NetValidatePasswordReset:
4445 password = data_blob_const(r->in.req->req3.password.string,
4446 r->in.req->req3.password.length);
4447 res = samdb_check_password(&password,
4448 pwInfo.password_properties,
4449 pwInfo.min_password_length);
4450 (*r->out.rep)->ctr3.status = res;
4451 break;
4452 default:
4453 return NT_STATUS_INVALID_INFO_CLASS;
4454 break;
4457 return NT_STATUS_OK;
4461 /* include the generated boilerplate */
4462 #include "librpc/gen_ndr/ndr_samr_s.c"