s4:dcesrv_samr_AddAliasMember - wrap a long "DEBUG" statement
[Samba/nascimento.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob1199e1d23ef34a96edce2f26ad1b17aeb01cfc29
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 int 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 ldb_cnt, count, i, first;
1125 struct samr_SamEntry *entries;
1126 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1127 struct samr_SamArray *sam;
1129 *r->out.resume_handle = 0;
1130 *r->out.sam = NULL;
1131 *r->out.num_entries = 0;
1133 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1135 d_state = h->data;
1137 /* search for all domain groups in this domain. This could possibly be
1138 cached and resumed based on resume_key */
1139 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1140 d_state->domain_dn, &res, attrs,
1141 d_state->domain_sid,
1142 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1143 GTYPE_SECURITY_UNIVERSAL_GROUP,
1144 GTYPE_SECURITY_GLOBAL_GROUP);
1145 if (ldb_cnt == -1) {
1146 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1149 /* convert to SamEntry format */
1150 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1151 if (!entries) {
1152 return NT_STATUS_NO_MEMORY;
1155 count = 0;
1157 for (i=0;i<ldb_cnt;i++) {
1158 struct dom_sid *group_sid;
1160 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1161 "objectSid");
1162 if (group_sid == NULL)
1163 continue;
1165 entries[count].idx =
1166 group_sid->sub_auths[group_sid->num_auths-1];
1167 entries[count].name.string =
1168 samdb_result_string(res[i], "sAMAccountName", "");
1169 count += 1;
1172 /* sort the results by rid */
1173 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1175 /* find the first entry to return */
1176 for (first=0;
1177 first<count && entries[first].idx <= *r->in.resume_handle;
1178 first++) ;
1180 /* return the rest, limit by max_size. Note that we
1181 use the w2k3 element size value of 54 */
1182 *r->out.num_entries = count - first;
1183 *r->out.num_entries = MIN(*r->out.num_entries,
1184 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1186 sam = talloc(mem_ctx, struct samr_SamArray);
1187 if (!sam) {
1188 return NT_STATUS_NO_MEMORY;
1191 sam->entries = entries+first;
1192 sam->count = *r->out.num_entries;
1194 *r->out.sam = sam;
1196 if (*r->out.num_entries < count - first) {
1197 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1198 return STATUS_MORE_ENTRIES;
1201 return NT_STATUS_OK;
1206 samr_CreateUser2
1208 This call uses transactions to ensure we don't get a new conflicting
1209 user while we are processing this, and to ensure the user either
1210 completly exists, or does not.
1212 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1213 struct samr_CreateUser2 *r)
1215 struct samr_domain_state *d_state;
1216 struct samr_account_state *a_state;
1217 struct dcesrv_handle *h;
1218 const char *name;
1219 struct ldb_message *msg;
1220 struct dom_sid *sid;
1221 const char *account_name;
1222 struct dcesrv_handle *u_handle;
1223 int ret;
1224 const char *container, *obj_class=NULL;
1225 char *cn_name;
1226 int cn_name_len;
1228 const char *attrs[] = {
1229 "objectSid",
1230 "userAccountControl",
1231 NULL
1234 uint32_t user_account_control;
1236 struct ldb_message **msgs;
1238 ZERO_STRUCTP(r->out.user_handle);
1239 *r->out.access_granted = 0;
1240 *r->out.rid = 0;
1242 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1244 d_state = h->data;
1246 if (d_state->builtin) {
1247 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1248 return NT_STATUS_ACCESS_DENIED;
1249 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1250 /* Domain trust accounts must be created by the LSA calls */
1251 return NT_STATUS_ACCESS_DENIED;
1253 account_name = r->in.account_name->string;
1255 if (account_name == NULL) {
1256 return NT_STATUS_INVALID_PARAMETER;
1260 * Start a transaction, so we can query and do a subsequent atomic
1261 * modify
1264 ret = ldb_transaction_start(d_state->sam_ctx);
1265 if (ret != LDB_SUCCESS) {
1266 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1267 ldb_errstring(d_state->sam_ctx)));
1268 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1271 /* check if the user already exists */
1272 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1273 "sAMAccountName",
1274 "(&(sAMAccountName=%s)(objectclass=user))",
1275 ldb_binary_encode_string(mem_ctx, account_name));
1276 if (name != NULL) {
1277 ldb_transaction_cancel(d_state->sam_ctx);
1278 return NT_STATUS_USER_EXISTS;
1281 msg = ldb_msg_new(mem_ctx);
1282 if (msg == NULL) {
1283 ldb_transaction_cancel(d_state->sam_ctx);
1284 return NT_STATUS_NO_MEMORY;
1287 cn_name = talloc_strdup(mem_ctx, account_name);
1288 if (!cn_name) {
1289 ldb_transaction_cancel(d_state->sam_ctx);
1290 return NT_STATUS_NO_MEMORY;
1293 cn_name_len = strlen(cn_name);
1295 /* This must be one of these values *only* */
1296 if (r->in.acct_flags == ACB_NORMAL) {
1297 container = "CN=Users";
1298 obj_class = "user";
1300 } else if (r->in.acct_flags == ACB_WSTRUST) {
1301 if (cn_name[cn_name_len - 1] != '$') {
1302 ldb_transaction_cancel(d_state->sam_ctx);
1303 return NT_STATUS_FOOBAR;
1305 cn_name[cn_name_len - 1] = '\0';
1306 container = "CN=Computers";
1307 obj_class = "computer";
1308 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1309 "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1311 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1312 if (cn_name[cn_name_len - 1] != '$') {
1313 ldb_transaction_cancel(d_state->sam_ctx);
1314 return NT_STATUS_FOOBAR;
1316 cn_name[cn_name_len - 1] = '\0';
1317 container = "OU=Domain Controllers";
1318 obj_class = "computer";
1319 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1320 "primaryGroupID", DOMAIN_RID_DCS);
1321 } else {
1322 ldb_transaction_cancel(d_state->sam_ctx);
1323 return NT_STATUS_INVALID_PARAMETER;
1326 /* add core elements to the ldb_message for the user */
1327 msg->dn = ldb_dn_copy(msg, d_state->domain_dn);
1328 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1329 ldb_transaction_cancel(d_state->sam_ctx);
1330 return NT_STATUS_FOOBAR;
1333 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName",
1334 account_name);
1335 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass",
1336 obj_class);
1338 /* create the user */
1339 ret = ldb_add(d_state->sam_ctx, msg);
1340 switch (ret) {
1341 case LDB_SUCCESS:
1342 break;
1343 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1344 ldb_transaction_cancel(d_state->sam_ctx);
1345 DEBUG(0,("Failed to create user record %s: %s\n",
1346 ldb_dn_get_linearized(msg->dn),
1347 ldb_errstring(d_state->sam_ctx)));
1348 return NT_STATUS_USER_EXISTS;
1349 case LDB_ERR_UNWILLING_TO_PERFORM:
1350 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1351 ldb_transaction_cancel(d_state->sam_ctx);
1352 DEBUG(0,("Failed to create user record %s: %s\n",
1353 ldb_dn_get_linearized(msg->dn),
1354 ldb_errstring(d_state->sam_ctx)));
1355 return NT_STATUS_ACCESS_DENIED;
1356 default:
1357 ldb_transaction_cancel(d_state->sam_ctx);
1358 DEBUG(0,("Failed to create user record %s: %s\n",
1359 ldb_dn_get_linearized(msg->dn),
1360 ldb_errstring(d_state->sam_ctx)));
1361 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1364 a_state = talloc(mem_ctx, struct samr_account_state);
1365 if (!a_state) {
1366 ldb_transaction_cancel(d_state->sam_ctx);
1367 return NT_STATUS_NO_MEMORY;
1369 a_state->sam_ctx = d_state->sam_ctx;
1370 a_state->access_mask = r->in.access_mask;
1371 a_state->domain_state = talloc_reference(a_state, d_state);
1372 a_state->account_dn = talloc_steal(a_state, msg->dn);
1374 /* retrieve the sid and account control bits for the user just created */
1375 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
1376 msg->dn, &msgs, attrs);
1378 if (ret != 1) {
1379 ldb_transaction_cancel(d_state->sam_ctx);
1380 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1381 ldb_dn_get_linearized(msg->dn)));
1382 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1384 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1385 if (sid == NULL) {
1386 ldb_transaction_cancel(d_state->sam_ctx);
1387 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1388 ldb_dn_get_linearized(msg->dn)));
1389 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1392 /* Change the account control to be the correct account type.
1393 * The default is for a workstation account */
1394 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1395 user_account_control = (user_account_control &
1396 ~(UF_NORMAL_ACCOUNT |
1397 UF_INTERDOMAIN_TRUST_ACCOUNT |
1398 UF_WORKSTATION_TRUST_ACCOUNT |
1399 UF_SERVER_TRUST_ACCOUNT));
1400 user_account_control |= ds_acb2uf(r->in.acct_flags);
1402 talloc_free(msg);
1403 msg = ldb_msg_new(mem_ctx);
1404 if (msg == NULL) {
1405 ldb_transaction_cancel(d_state->sam_ctx);
1406 return NT_STATUS_NO_MEMORY;
1409 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1411 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1412 "userAccountControl",
1413 user_account_control) != 0) {
1414 ldb_transaction_cancel(d_state->sam_ctx);
1415 return NT_STATUS_NO_MEMORY;
1418 /* modify the samdb record */
1419 ret = dsdb_replace(a_state->sam_ctx, msg, 0);
1420 if (ret != LDB_SUCCESS) {
1421 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1422 ldb_dn_get_linearized(msg->dn),
1423 ldb_errstring(d_state->sam_ctx)));
1424 ldb_transaction_cancel(d_state->sam_ctx);
1426 /* we really need samdb.c to return NTSTATUS */
1427 return NT_STATUS_UNSUCCESSFUL;
1430 ret = ldb_transaction_commit(d_state->sam_ctx);
1431 if (ret != LDB_SUCCESS) {
1432 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1433 ldb_dn_get_linearized(msg->dn),
1434 ldb_errstring(d_state->sam_ctx)));
1435 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1438 a_state->account_name = talloc_steal(a_state, account_name);
1439 if (!a_state->account_name) {
1440 return NT_STATUS_NO_MEMORY;
1443 /* create the policy handle */
1444 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1445 if (!u_handle) {
1446 return NT_STATUS_NO_MEMORY;
1449 u_handle->data = talloc_steal(u_handle, a_state);
1451 *r->out.user_handle = u_handle->wire_handle;
1452 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1454 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1456 return NT_STATUS_OK;
1461 samr_CreateUser
1463 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1464 struct samr_CreateUser *r)
1466 struct samr_CreateUser2 r2;
1467 uint32_t access_granted = 0;
1470 /* a simple wrapper around samr_CreateUser2 works nicely */
1471 r2.in.domain_handle = r->in.domain_handle;
1472 r2.in.account_name = r->in.account_name;
1473 r2.in.acct_flags = ACB_NORMAL;
1474 r2.in.access_mask = r->in.access_mask;
1475 r2.out.user_handle = r->out.user_handle;
1476 r2.out.access_granted = &access_granted;
1477 r2.out.rid = r->out.rid;
1479 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1483 samr_EnumDomainUsers
1485 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1486 struct samr_EnumDomainUsers *r)
1488 struct dcesrv_handle *h;
1489 struct samr_domain_state *d_state;
1490 struct ldb_result *res;
1491 int ret, num_filtered_entries, i, first;
1492 struct samr_SamEntry *entries;
1493 const char * const attrs[] = { "objectSid", "sAMAccountName",
1494 "userAccountControl", NULL };
1495 struct samr_SamArray *sam;
1497 *r->out.resume_handle = 0;
1498 *r->out.sam = NULL;
1499 *r->out.num_entries = 0;
1501 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1503 d_state = h->data;
1505 /* don't have to worry about users in the builtin domain, as there are none */
1506 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1508 if (ret != LDB_SUCCESS) {
1509 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1510 ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1511 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1514 /* convert to SamEntry format */
1515 entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1516 if (!entries) {
1517 return NT_STATUS_NO_MEMORY;
1519 num_filtered_entries = 0;
1520 for (i=0;i<res->count;i++) {
1521 /* Check if a mask has been requested */
1522 if (r->in.acct_flags
1523 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i],
1524 d_state->domain_dn) & r->in.acct_flags) == 0)) {
1525 continue;
1527 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1528 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1529 num_filtered_entries++;
1532 /* sort the results by rid */
1533 TYPESAFE_QSORT(entries, num_filtered_entries, compare_SamEntry);
1535 /* find the first entry to return */
1536 for (first=0;
1537 first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1538 first++) ;
1540 /* return the rest, limit by max_size. Note that we
1541 use the w2k3 element size value of 54 */
1542 *r->out.num_entries = num_filtered_entries - first;
1543 *r->out.num_entries = MIN(*r->out.num_entries,
1544 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1546 sam = talloc(mem_ctx, struct samr_SamArray);
1547 if (!sam) {
1548 return NT_STATUS_NO_MEMORY;
1551 sam->entries = entries+first;
1552 sam->count = *r->out.num_entries;
1554 *r->out.sam = sam;
1556 if (first == num_filtered_entries) {
1557 return NT_STATUS_OK;
1560 if (*r->out.num_entries < num_filtered_entries - first) {
1561 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1562 return STATUS_MORE_ENTRIES;
1565 return NT_STATUS_OK;
1570 samr_CreateDomAlias
1572 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1573 struct samr_CreateDomAlias *r)
1575 struct samr_domain_state *d_state;
1576 struct samr_account_state *a_state;
1577 struct dcesrv_handle *h;
1578 const char *alias_name, *name;
1579 struct ldb_message *msg;
1580 struct dom_sid *sid;
1581 struct dcesrv_handle *a_handle;
1582 int ret;
1584 ZERO_STRUCTP(r->out.alias_handle);
1585 *r->out.rid = 0;
1587 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1589 d_state = h->data;
1591 if (d_state->builtin) {
1592 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1593 return NT_STATUS_ACCESS_DENIED;
1596 alias_name = r->in.alias_name->string;
1598 if (alias_name == NULL) {
1599 return NT_STATUS_INVALID_PARAMETER;
1602 /* Check if alias already exists */
1603 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1604 "sAMAccountName",
1605 "(sAMAccountName=%s)(objectclass=group))",
1606 ldb_binary_encode_string(mem_ctx, alias_name));
1608 if (name != NULL) {
1609 return NT_STATUS_ALIAS_EXISTS;
1612 msg = ldb_msg_new(mem_ctx);
1613 if (msg == NULL) {
1614 return NT_STATUS_NO_MEMORY;
1617 /* add core elements to the ldb_message for the alias */
1618 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1619 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1620 if (!msg->dn) {
1621 return NT_STATUS_NO_MEMORY;
1624 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1625 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1626 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1628 /* create the alias */
1629 ret = ldb_add(d_state->sam_ctx, msg);
1630 switch (ret) {
1631 case LDB_SUCCESS:
1632 break;
1633 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1634 return NT_STATUS_ALIAS_EXISTS;
1635 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1636 return NT_STATUS_ACCESS_DENIED;
1637 default:
1638 DEBUG(0,("Failed to create alias record %s: %s\n",
1639 ldb_dn_get_linearized(msg->dn),
1640 ldb_errstring(d_state->sam_ctx)));
1641 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1644 a_state = talloc(mem_ctx, struct samr_account_state);
1645 if (!a_state) {
1646 return NT_STATUS_NO_MEMORY;
1649 a_state->sam_ctx = d_state->sam_ctx;
1650 a_state->access_mask = r->in.access_mask;
1651 a_state->domain_state = talloc_reference(a_state, d_state);
1652 a_state->account_dn = talloc_steal(a_state, msg->dn);
1654 /* retrieve the sid for the alias just created */
1655 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1656 msg->dn, "objectSid", NULL);
1658 a_state->account_name = talloc_strdup(a_state, alias_name);
1659 if (!a_state->account_name) {
1660 return NT_STATUS_NO_MEMORY;
1663 /* create the policy handle */
1664 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1665 if (a_handle == NULL)
1666 return NT_STATUS_NO_MEMORY;
1668 a_handle->data = talloc_steal(a_handle, a_state);
1670 *r->out.alias_handle = a_handle->wire_handle;
1672 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1674 return NT_STATUS_OK;
1679 samr_EnumDomainAliases
1681 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1682 struct samr_EnumDomainAliases *r)
1684 struct dcesrv_handle *h;
1685 struct samr_domain_state *d_state;
1686 struct ldb_message **res;
1687 int ldb_cnt, count, i, first;
1688 struct samr_SamEntry *entries;
1689 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1690 struct samr_SamArray *sam;
1692 *r->out.resume_handle = 0;
1693 *r->out.sam = NULL;
1694 *r->out.num_entries = 0;
1696 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1698 d_state = h->data;
1700 /* search for all domain groups in this domain. This could possibly be
1701 cached and resumed based on resume_key */
1702 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1703 d_state->domain_dn,
1704 &res, attrs,
1705 d_state->domain_sid,
1706 "(&(|(grouptype=%d)(grouptype=%d)))"
1707 "(objectclass=group))",
1708 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1709 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1710 if (ldb_cnt == -1) {
1711 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1713 if (ldb_cnt == 0) {
1714 return NT_STATUS_OK;
1717 /* convert to SamEntry format */
1718 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1719 if (!entries) {
1720 return NT_STATUS_NO_MEMORY;
1723 count = 0;
1725 for (i=0;i<ldb_cnt;i++) {
1726 struct dom_sid *alias_sid;
1728 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1729 "objectSid");
1731 if (alias_sid == NULL)
1732 continue;
1734 entries[count].idx =
1735 alias_sid->sub_auths[alias_sid->num_auths-1];
1736 entries[count].name.string =
1737 samdb_result_string(res[i], "sAMAccountName", "");
1738 count += 1;
1741 /* sort the results by rid */
1742 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1744 /* find the first entry to return */
1745 for (first=0;
1746 first<count && entries[first].idx <= *r->in.resume_handle;
1747 first++) ;
1749 if (first == count) {
1750 return NT_STATUS_OK;
1753 *r->out.num_entries = count - first;
1754 *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1756 sam = talloc(mem_ctx, struct samr_SamArray);
1757 if (!sam) {
1758 return NT_STATUS_NO_MEMORY;
1761 sam->entries = entries+first;
1762 sam->count = *r->out.num_entries;
1764 *r->out.sam = sam;
1766 if (*r->out.num_entries < count - first) {
1767 *r->out.resume_handle =
1768 entries[first+*r->out.num_entries-1].idx;
1769 return STATUS_MORE_ENTRIES;
1772 return NT_STATUS_OK;
1777 samr_GetAliasMembership
1779 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1780 struct samr_GetAliasMembership *r)
1782 struct dcesrv_handle *h;
1783 struct samr_domain_state *d_state;
1784 struct ldb_message **res;
1785 int i, count = 0;
1787 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1789 d_state = h->data;
1791 if (r->in.sids->num_sids > 0) {
1792 const char *filter;
1793 const char * const attrs[2] = { "objectSid", NULL };
1795 filter = talloc_asprintf(mem_ctx,
1796 "(&(|(grouptype=%d)(grouptype=%d))"
1797 "(objectclass=group)(|",
1798 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1799 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1800 if (filter == NULL)
1801 return NT_STATUS_NO_MEMORY;
1803 for (i=0; i<r->in.sids->num_sids; i++) {
1804 const char *memberdn;
1806 memberdn =
1807 samdb_search_string(d_state->sam_ctx,
1808 mem_ctx, NULL,
1809 "distinguishedName",
1810 "(objectSid=%s)",
1811 ldap_encode_ndr_dom_sid(mem_ctx,
1812 r->in.sids->sids[i].sid));
1814 if (memberdn == NULL)
1815 continue;
1817 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1818 filter, memberdn);
1819 if (filter == NULL)
1820 return NT_STATUS_NO_MEMORY;
1823 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1824 d_state->domain_dn, &res, attrs,
1825 d_state->domain_sid, "%s))", filter);
1826 if (count < 0)
1827 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1830 r->out.rids->count = 0;
1831 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1832 if (r->out.rids->ids == NULL)
1833 return NT_STATUS_NO_MEMORY;
1835 for (i=0; i<count; i++) {
1836 struct dom_sid *alias_sid;
1838 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1840 if (alias_sid == NULL) {
1841 DEBUG(0, ("Could not find objectSid\n"));
1842 continue;
1845 r->out.rids->ids[r->out.rids->count] =
1846 alias_sid->sub_auths[alias_sid->num_auths-1];
1847 r->out.rids->count += 1;
1850 return NT_STATUS_OK;
1855 samr_LookupNames
1857 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1858 struct samr_LookupNames *r)
1860 struct dcesrv_handle *h;
1861 struct samr_domain_state *d_state;
1862 int i, num_mapped;
1863 NTSTATUS status = NT_STATUS_OK;
1864 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1865 int count;
1867 ZERO_STRUCTP(r->out.rids);
1868 ZERO_STRUCTP(r->out.types);
1870 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1872 d_state = h->data;
1874 if (r->in.num_names == 0) {
1875 return NT_STATUS_OK;
1878 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1879 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1880 if (!r->out.rids->ids || !r->out.types->ids) {
1881 return NT_STATUS_NO_MEMORY;
1883 r->out.rids->count = r->in.num_names;
1884 r->out.types->count = r->in.num_names;
1886 num_mapped = 0;
1888 for (i=0;i<r->in.num_names;i++) {
1889 struct ldb_message **res;
1890 struct dom_sid *sid;
1891 uint32_t atype, rtype;
1893 r->out.rids->ids[i] = 0;
1894 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1896 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1897 "sAMAccountName=%s",
1898 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1899 if (count != 1) {
1900 status = STATUS_SOME_UNMAPPED;
1901 continue;
1904 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1905 if (sid == NULL) {
1906 status = STATUS_SOME_UNMAPPED;
1907 continue;
1910 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1911 if (atype == 0) {
1912 status = STATUS_SOME_UNMAPPED;
1913 continue;
1916 rtype = ds_atype_map(atype);
1918 if (rtype == SID_NAME_UNKNOWN) {
1919 status = STATUS_SOME_UNMAPPED;
1920 continue;
1923 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1924 r->out.types->ids[i] = rtype;
1925 num_mapped++;
1928 if (num_mapped == 0) {
1929 return NT_STATUS_NONE_MAPPED;
1931 return status;
1936 samr_LookupRids
1938 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1939 struct samr_LookupRids *r)
1941 struct dcesrv_handle *h;
1942 struct samr_domain_state *d_state;
1943 int i;
1944 NTSTATUS status = NT_STATUS_OK;
1945 struct lsa_String *names;
1946 uint32_t *ids;
1948 ZERO_STRUCTP(r->out.names);
1949 ZERO_STRUCTP(r->out.types);
1951 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1953 d_state = h->data;
1955 if (r->in.num_rids == 0)
1956 return NT_STATUS_OK;
1958 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1959 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1961 if ((names == NULL) || (ids == NULL))
1962 return NT_STATUS_NO_MEMORY;
1964 for (i=0; i<r->in.num_rids; i++) {
1965 struct ldb_message **res;
1966 int count;
1967 const char * const attrs[] = { "sAMAccountType",
1968 "sAMAccountName", NULL };
1969 uint32_t atype;
1970 struct dom_sid *sid;
1972 ids[i] = SID_NAME_UNKNOWN;
1974 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid,
1975 r->in.rids[i]);
1976 if (sid == NULL) {
1977 names[i].string = NULL;
1978 status = STATUS_SOME_UNMAPPED;
1979 continue;
1982 count = gendb_search(d_state->sam_ctx, mem_ctx,
1983 d_state->domain_dn, &res, attrs,
1984 "(objectSid=%s)",
1985 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1986 if (count != 1) {
1987 names[i].string = NULL;
1988 status = STATUS_SOME_UNMAPPED;
1989 continue;
1992 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1993 NULL);
1995 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1996 if (atype == 0) {
1997 status = STATUS_SOME_UNMAPPED;
1998 continue;
2001 ids[i] = ds_atype_map(atype);
2003 if (ids[i] == SID_NAME_UNKNOWN) {
2004 status = STATUS_SOME_UNMAPPED;
2005 continue;
2009 r->out.names->names = names;
2010 r->out.names->count = r->in.num_rids;
2012 r->out.types->ids = ids;
2013 r->out.types->count = r->in.num_rids;
2015 return status;
2020 samr_OpenGroup
2022 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2023 struct samr_OpenGroup *r)
2025 struct samr_domain_state *d_state;
2026 struct samr_account_state *a_state;
2027 struct dcesrv_handle *h;
2028 const char *groupname;
2029 struct dom_sid *sid;
2030 struct ldb_message **msgs;
2031 struct dcesrv_handle *g_handle;
2032 const char * const attrs[2] = { "sAMAccountName", NULL };
2033 int ret;
2035 ZERO_STRUCTP(r->out.group_handle);
2037 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2039 d_state = h->data;
2041 /* form the group SID */
2042 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2043 if (!sid) {
2044 return NT_STATUS_NO_MEMORY;
2047 /* search for the group record */
2048 ret = gendb_search(d_state->sam_ctx,
2049 mem_ctx, d_state->domain_dn, &msgs, attrs,
2050 "(&(objectSid=%s)(objectClass=group)"
2051 "(|(groupType=%d)(groupType=%d)))",
2052 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2053 GTYPE_SECURITY_UNIVERSAL_GROUP,
2054 GTYPE_SECURITY_GLOBAL_GROUP);
2055 if (ret == 0) {
2056 return NT_STATUS_NO_SUCH_GROUP;
2058 if (ret != 1) {
2059 DEBUG(0,("Found %d records matching sid %s\n",
2060 ret, dom_sid_string(mem_ctx, sid)));
2061 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2064 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2065 if (groupname == NULL) {
2066 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2067 dom_sid_string(mem_ctx, sid)));
2068 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2071 a_state = talloc(mem_ctx, struct samr_account_state);
2072 if (!a_state) {
2073 return NT_STATUS_NO_MEMORY;
2075 a_state->sam_ctx = d_state->sam_ctx;
2076 a_state->access_mask = r->in.access_mask;
2077 a_state->domain_state = talloc_reference(a_state, d_state);
2078 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2079 a_state->account_sid = talloc_steal(a_state, sid);
2080 a_state->account_name = talloc_strdup(a_state, groupname);
2081 if (!a_state->account_name) {
2082 return NT_STATUS_NO_MEMORY;
2085 /* create the policy handle */
2086 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2087 if (!g_handle) {
2088 return NT_STATUS_NO_MEMORY;
2091 g_handle->data = talloc_steal(g_handle, a_state);
2093 *r->out.group_handle = g_handle->wire_handle;
2095 return NT_STATUS_OK;
2099 samr_QueryGroupInfo
2101 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2102 struct samr_QueryGroupInfo *r)
2104 struct dcesrv_handle *h;
2105 struct samr_account_state *a_state;
2106 struct ldb_message *msg;
2107 struct ldb_result *res;
2108 const char * const attrs[4] = { "sAMAccountName", "description",
2109 "numMembers", NULL };
2110 int ret;
2111 union samr_GroupInfo *info;
2113 *r->out.info = NULL;
2115 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2117 a_state = h->data;
2119 ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn,
2120 LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2122 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2123 return NT_STATUS_NO_SUCH_GROUP;
2124 } else if (ret != LDB_SUCCESS) {
2125 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2126 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2129 if (res->count != 1) {
2130 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2132 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2134 msg = res->msgs[0];
2136 /* allocate the info structure */
2137 info = talloc_zero(mem_ctx, union samr_GroupInfo);
2138 if (info == NULL) {
2139 return NT_STATUS_NO_MEMORY;
2142 /* Fill in the level */
2143 switch (r->in.level) {
2144 case GROUPINFOALL:
2145 QUERY_STRING(msg, all.name, "sAMAccountName");
2146 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2147 QUERY_UINT (msg, all.num_members, "numMembers")
2148 QUERY_STRING(msg, all.description, "description");
2149 break;
2150 case GROUPINFONAME:
2151 QUERY_STRING(msg, name, "sAMAccountName");
2152 break;
2153 case GROUPINFOATTRIBUTES:
2154 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2155 break;
2156 case GROUPINFODESCRIPTION:
2157 QUERY_STRING(msg, description, "description");
2158 break;
2159 case GROUPINFOALL2:
2160 QUERY_STRING(msg, all2.name, "sAMAccountName");
2161 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2162 QUERY_UINT (msg, all2.num_members, "numMembers")
2163 QUERY_STRING(msg, all2.description, "description");
2164 break;
2165 default:
2166 talloc_free(info);
2167 return NT_STATUS_INVALID_INFO_CLASS;
2170 *r->out.info = info;
2172 return NT_STATUS_OK;
2177 samr_SetGroupInfo
2179 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2180 struct samr_SetGroupInfo *r)
2182 struct dcesrv_handle *h;
2183 struct samr_account_state *g_state;
2184 struct ldb_message *msg;
2185 struct ldb_context *sam_ctx;
2186 int ret;
2188 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2190 g_state = h->data;
2191 sam_ctx = g_state->sam_ctx;
2193 msg = ldb_msg_new(mem_ctx);
2194 if (msg == NULL) {
2195 return NT_STATUS_NO_MEMORY;
2198 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2199 if (!msg->dn) {
2200 return NT_STATUS_NO_MEMORY;
2203 switch (r->in.level) {
2204 case GROUPINFODESCRIPTION:
2205 SET_STRING(msg, description, "description");
2206 break;
2207 case GROUPINFONAME:
2208 /* On W2k3 this does not change the name, it changes the
2209 * sAMAccountName attribute */
2210 SET_STRING(msg, name, "sAMAccountName");
2211 break;
2212 case GROUPINFOATTRIBUTES:
2213 /* This does not do anything obviously visible in W2k3 LDAP */
2214 return NT_STATUS_OK;
2215 default:
2216 return NT_STATUS_INVALID_INFO_CLASS;
2219 /* modify the samdb record */
2220 ret = ldb_modify(g_state->sam_ctx, msg);
2221 if (ret != LDB_SUCCESS) {
2222 /* we really need samdb.c to return NTSTATUS */
2223 return NT_STATUS_UNSUCCESSFUL;
2226 return NT_STATUS_OK;
2231 samr_AddGroupMember
2233 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2234 struct samr_AddGroupMember *r)
2236 struct dcesrv_handle *h;
2237 struct samr_account_state *a_state;
2238 struct samr_domain_state *d_state;
2239 struct ldb_message *mod;
2240 struct dom_sid *membersid;
2241 const char *memberdn;
2242 struct ldb_result *res;
2243 const char * const attrs[] = { NULL };
2244 int ret;
2246 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2248 a_state = h->data;
2249 d_state = a_state->domain_state;
2251 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2252 if (membersid == NULL) {
2253 return NT_STATUS_NO_MEMORY;
2256 /* In native mode, AD can also nest domain groups. Not sure yet
2257 * whether this is also available via RPC. */
2258 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2259 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2260 "(&(objectSid=%s)(objectclass=user))",
2261 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2263 if (ret != LDB_SUCCESS) {
2264 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2267 if (res->count == 0) {
2268 return NT_STATUS_NO_SUCH_USER;
2271 if (res->count > 1) {
2272 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2275 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2277 if (memberdn == NULL)
2278 return NT_STATUS_NO_MEMORY;
2280 mod = ldb_msg_new(mem_ctx);
2281 if (mod == NULL) {
2282 return NT_STATUS_NO_MEMORY;
2285 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2287 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2288 memberdn);
2289 if (ret != LDB_SUCCESS) {
2290 return NT_STATUS_UNSUCCESSFUL;
2293 ret = ldb_modify(a_state->sam_ctx, mod);
2294 switch (ret) {
2295 case LDB_SUCCESS:
2296 return NT_STATUS_OK;
2297 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2298 return NT_STATUS_MEMBER_IN_GROUP;
2299 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2300 return NT_STATUS_ACCESS_DENIED;
2301 default:
2302 return NT_STATUS_UNSUCCESSFUL;
2308 samr_DeleteDomainGroup
2310 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2311 struct samr_DeleteDomainGroup *r)
2313 struct dcesrv_handle *h;
2314 struct samr_account_state *a_state;
2315 int ret;
2317 *r->out.group_handle = *r->in.group_handle;
2319 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2321 a_state = h->data;
2323 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2324 if (ret != LDB_SUCCESS) {
2325 return NT_STATUS_UNSUCCESSFUL;
2328 talloc_free(h);
2329 ZERO_STRUCTP(r->out.group_handle);
2331 return NT_STATUS_OK;
2336 samr_DeleteGroupMember
2338 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2339 struct samr_DeleteGroupMember *r)
2341 struct dcesrv_handle *h;
2342 struct samr_account_state *a_state;
2343 struct samr_domain_state *d_state;
2344 struct ldb_message *mod;
2345 struct dom_sid *membersid;
2346 const char *memberdn;
2347 struct ldb_result *res;
2348 const char * const attrs[] = { NULL };
2349 int ret;
2351 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2353 a_state = h->data;
2354 d_state = a_state->domain_state;
2356 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2357 if (membersid == NULL)
2358 return NT_STATUS_NO_MEMORY;
2360 /* In native mode, AD can also nest domain groups. Not sure yet
2361 * whether this is also available via RPC. */
2362 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2363 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2364 "(&(objectSid=%s)(objectclass=user))",
2365 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2367 if (ret != LDB_SUCCESS) {
2368 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2371 if (res->count == 0) {
2372 return NT_STATUS_NO_SUCH_USER;
2375 if (res->count > 1) {
2376 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2379 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2381 if (memberdn == NULL)
2382 return NT_STATUS_NO_MEMORY;
2384 mod = ldb_msg_new(mem_ctx);
2385 if (mod == NULL) {
2386 return NT_STATUS_NO_MEMORY;
2389 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2391 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2392 memberdn);
2393 if (ret != LDB_SUCCESS) {
2394 return NT_STATUS_NO_MEMORY;
2397 ret = ldb_modify(a_state->sam_ctx, mod);
2398 switch (ret) {
2399 case LDB_SUCCESS:
2400 return NT_STATUS_OK;
2401 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2402 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2403 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2404 return NT_STATUS_ACCESS_DENIED;
2405 default:
2406 return NT_STATUS_UNSUCCESSFUL;
2412 samr_QueryGroupMember
2414 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2415 struct samr_QueryGroupMember *r)
2417 struct dcesrv_handle *h;
2418 struct samr_account_state *a_state;
2419 struct ldb_message **res;
2420 struct ldb_message_element *el;
2421 struct samr_RidTypeArray *array;
2422 const char * const attrs[2] = { "member", NULL };
2423 int ret;
2425 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2427 a_state = h->data;
2429 /* pull the member attribute */
2430 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2431 a_state->account_dn, &res, attrs);
2433 if (ret != 1) {
2434 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2437 array = talloc(mem_ctx, struct samr_RidTypeArray);
2439 if (array == NULL)
2440 return NT_STATUS_NO_MEMORY;
2442 ZERO_STRUCTP(array);
2444 el = ldb_msg_find_element(res[0], "member");
2446 if (el != NULL) {
2447 int i;
2449 array->count = el->num_values;
2451 array->rids = talloc_array(mem_ctx, uint32_t,
2452 el->num_values);
2453 if (array->rids == NULL)
2454 return NT_STATUS_NO_MEMORY;
2456 array->types = talloc_array(mem_ctx, uint32_t,
2457 el->num_values);
2458 if (array->types == NULL)
2459 return NT_STATUS_NO_MEMORY;
2461 for (i=0; i<el->num_values; i++) {
2462 struct ldb_message **res2;
2463 const char * const attrs2[2] = { "objectSid", NULL };
2464 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2465 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2466 &res2, attrs2);
2467 if (ret != 1)
2468 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2470 array->rids[i] =
2471 samdb_result_rid_from_sid(mem_ctx, res2[0],
2472 "objectSid", 0);
2474 if (array->rids[i] == 0)
2475 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2477 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2481 *r->out.rids = array;
2483 return NT_STATUS_OK;
2488 samr_SetMemberAttributesOfGroup
2490 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2491 struct samr_SetMemberAttributesOfGroup *r)
2493 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2498 samr_OpenAlias
2500 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2501 struct samr_OpenAlias *r)
2503 struct samr_domain_state *d_state;
2504 struct samr_account_state *a_state;
2505 struct dcesrv_handle *h;
2506 const char *alias_name;
2507 struct dom_sid *sid;
2508 struct ldb_message **msgs;
2509 struct dcesrv_handle *g_handle;
2510 const char * const attrs[2] = { "sAMAccountName", NULL };
2511 int ret;
2513 ZERO_STRUCTP(r->out.alias_handle);
2515 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2517 d_state = h->data;
2519 /* form the alias SID */
2520 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2521 if (sid == NULL)
2522 return NT_STATUS_NO_MEMORY;
2524 /* search for the group record */
2525 ret = gendb_search(d_state->sam_ctx,
2526 mem_ctx, d_state->domain_dn, &msgs, attrs,
2527 "(&(objectSid=%s)(objectclass=group)"
2528 "(|(grouptype=%d)(grouptype=%d)))",
2529 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2530 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2531 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2532 if (ret == 0) {
2533 return NT_STATUS_NO_SUCH_ALIAS;
2535 if (ret != 1) {
2536 DEBUG(0,("Found %d records matching sid %s\n",
2537 ret, dom_sid_string(mem_ctx, sid)));
2538 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2541 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2542 if (alias_name == NULL) {
2543 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2544 dom_sid_string(mem_ctx, sid)));
2545 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2548 a_state = talloc(mem_ctx, struct samr_account_state);
2549 if (!a_state) {
2550 return NT_STATUS_NO_MEMORY;
2552 a_state->sam_ctx = d_state->sam_ctx;
2553 a_state->access_mask = r->in.access_mask;
2554 a_state->domain_state = talloc_reference(a_state, d_state);
2555 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2556 a_state->account_sid = talloc_steal(a_state, sid);
2557 a_state->account_name = talloc_strdup(a_state, alias_name);
2558 if (!a_state->account_name) {
2559 return NT_STATUS_NO_MEMORY;
2562 /* create the policy handle */
2563 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2564 if (!g_handle) {
2565 return NT_STATUS_NO_MEMORY;
2568 g_handle->data = talloc_steal(g_handle, a_state);
2570 *r->out.alias_handle = g_handle->wire_handle;
2572 return NT_STATUS_OK;
2577 samr_QueryAliasInfo
2579 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2580 struct samr_QueryAliasInfo *r)
2582 struct dcesrv_handle *h;
2583 struct samr_account_state *a_state;
2584 struct ldb_message *msg, **res;
2585 const char * const attrs[4] = { "sAMAccountName", "description",
2586 "numMembers", NULL };
2587 int ret;
2588 union samr_AliasInfo *info;
2590 *r->out.info = NULL;
2592 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2594 a_state = h->data;
2596 /* pull all the alias attributes */
2597 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2598 a_state->account_dn ,&res, attrs);
2599 if (ret != 1) {
2600 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2602 msg = res[0];
2604 /* allocate the info structure */
2605 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2606 if (info == NULL) {
2607 return NT_STATUS_NO_MEMORY;
2610 switch(r->in.level) {
2611 case ALIASINFOALL:
2612 QUERY_STRING(msg, all.name, "sAMAccountName");
2613 QUERY_UINT (msg, all.num_members, "numMembers");
2614 QUERY_STRING(msg, all.description, "description");
2615 break;
2616 case ALIASINFONAME:
2617 QUERY_STRING(msg, name, "sAMAccountName");
2618 break;
2619 case ALIASINFODESCRIPTION:
2620 QUERY_STRING(msg, description, "description");
2621 break;
2622 default:
2623 talloc_free(info);
2624 return NT_STATUS_INVALID_INFO_CLASS;
2627 *r->out.info = info;
2629 return NT_STATUS_OK;
2634 samr_SetAliasInfo
2636 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2637 struct samr_SetAliasInfo *r)
2639 struct dcesrv_handle *h;
2640 struct samr_account_state *a_state;
2641 struct ldb_message *msg;
2642 struct ldb_context *sam_ctx;
2643 int ret;
2645 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2647 a_state = h->data;
2648 sam_ctx = a_state->sam_ctx;
2650 msg = ldb_msg_new(mem_ctx);
2651 if (msg == NULL) {
2652 return NT_STATUS_NO_MEMORY;
2655 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2656 if (!msg->dn) {
2657 return NT_STATUS_NO_MEMORY;
2660 switch (r->in.level) {
2661 case ALIASINFODESCRIPTION:
2662 SET_STRING(msg, description, "description");
2663 break;
2664 case ALIASINFONAME:
2665 /* On W2k3 this does not change the name, it changes the
2666 * sAMAccountName attribute */
2667 SET_STRING(msg, name, "sAMAccountName");
2668 break;
2669 default:
2670 return NT_STATUS_INVALID_INFO_CLASS;
2673 /* modify the samdb record */
2674 ret = ldb_modify(a_state->sam_ctx, msg);
2675 if (ret != LDB_SUCCESS) {
2676 /* we really need samdb.c to return NTSTATUS */
2677 return NT_STATUS_UNSUCCESSFUL;
2680 return NT_STATUS_OK;
2685 samr_DeleteDomAlias
2687 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2688 struct samr_DeleteDomAlias *r)
2690 struct dcesrv_handle *h;
2691 struct samr_account_state *a_state;
2692 int ret;
2694 *r->out.alias_handle = *r->in.alias_handle;
2696 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2698 a_state = h->data;
2700 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2701 if (ret != LDB_SUCCESS) {
2702 return NT_STATUS_UNSUCCESSFUL;
2705 talloc_free(h);
2706 ZERO_STRUCTP(r->out.alias_handle);
2708 return NT_STATUS_OK;
2713 samr_AddAliasMember
2715 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2716 struct samr_AddAliasMember *r)
2718 struct dcesrv_handle *h;
2719 struct samr_account_state *a_state;
2720 struct samr_domain_state *d_state;
2721 struct ldb_message *mod;
2722 struct ldb_message **msgs;
2723 const char * const attrs[] = { NULL };
2724 struct ldb_dn *memberdn = NULL;
2725 int ret;
2726 NTSTATUS status;
2728 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2730 a_state = h->data;
2731 d_state = a_state->domain_state;
2733 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2734 &msgs, attrs, "(objectsid=%s)",
2735 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2737 if (ret == 1) {
2738 memberdn = msgs[0]->dn;
2739 } else if (ret > 1) {
2740 DEBUG(0,("Found %d records matching sid %s\n",
2741 ret, dom_sid_string(mem_ctx, r->in.sid)));
2742 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2743 } else if (ret == 0) {
2744 status = samdb_create_foreign_security_principal(
2745 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2746 if (!NT_STATUS_IS_OK(status)) {
2747 return status;
2749 } else {
2750 DEBUG(0, ("samdb_search returned %d: %s\n", ret,
2751 ldb_errstring(d_state->sam_ctx)));
2754 if (memberdn == NULL) {
2755 DEBUG(0, ("Could not find memberdn\n"));
2756 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2759 mod = ldb_msg_new(mem_ctx);
2760 if (mod == NULL) {
2761 return NT_STATUS_NO_MEMORY;
2764 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2766 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2767 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2768 if (ret != LDB_SUCCESS) {
2769 return NT_STATUS_UNSUCCESSFUL;
2772 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2773 return NT_STATUS_UNSUCCESSFUL;
2776 return NT_STATUS_OK;
2781 samr_DeleteAliasMember
2783 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2784 struct samr_DeleteAliasMember *r)
2786 struct dcesrv_handle *h;
2787 struct samr_account_state *a_state;
2788 struct samr_domain_state *d_state;
2789 struct ldb_message *mod;
2790 const char *memberdn;
2791 int ret;
2793 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2795 a_state = h->data;
2796 d_state = a_state->domain_state;
2798 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2799 "distinguishedName", "(objectSid=%s)",
2800 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2802 if (memberdn == NULL)
2803 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2805 mod = ldb_msg_new(mem_ctx);
2806 if (mod == NULL) {
2807 return NT_STATUS_NO_MEMORY;
2810 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2812 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2813 memberdn);
2814 if (ret != LDB_SUCCESS)
2815 return NT_STATUS_UNSUCCESSFUL;
2817 if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2818 return NT_STATUS_UNSUCCESSFUL;
2820 return NT_STATUS_OK;
2825 samr_GetMembersInAlias
2827 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2828 struct samr_GetMembersInAlias *r)
2830 struct dcesrv_handle *h;
2831 struct samr_account_state *a_state;
2832 struct samr_domain_state *d_state;
2833 struct ldb_message **msgs;
2834 struct lsa_SidPtr *sids;
2835 struct ldb_message_element *el;
2836 const char * const attrs[2] = { "member", NULL};
2837 int ret;
2839 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2841 a_state = h->data;
2842 d_state = a_state->domain_state;
2844 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2845 a_state->account_dn, &msgs, attrs);
2847 if (ret == -1) {
2848 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2849 } else if (ret == 0) {
2850 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2851 } else if (ret != 1) {
2852 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2855 r->out.sids->num_sids = 0;
2856 r->out.sids->sids = NULL;
2858 el = ldb_msg_find_element(msgs[0], "member");
2860 if (el != NULL) {
2861 int i;
2863 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2864 el->num_values);
2866 if (sids == NULL)
2867 return NT_STATUS_NO_MEMORY;
2869 for (i=0; i<el->num_values; i++) {
2870 struct ldb_message **msgs2;
2871 const char * const attrs2[2] = { "objectSid", NULL };
2872 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2873 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2874 &msgs2, attrs2);
2875 if (ret != 1)
2876 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2878 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2879 "objectSid");
2881 if (sids[i].sid == NULL)
2882 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2884 r->out.sids->num_sids = el->num_values;
2885 r->out.sids->sids = sids;
2888 return NT_STATUS_OK;
2892 samr_OpenUser
2894 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2895 struct samr_OpenUser *r)
2897 struct samr_domain_state *d_state;
2898 struct samr_account_state *a_state;
2899 struct dcesrv_handle *h;
2900 const char *account_name;
2901 struct dom_sid *sid;
2902 struct ldb_message **msgs;
2903 struct dcesrv_handle *u_handle;
2904 const char * const attrs[2] = { "sAMAccountName", NULL };
2905 int ret;
2907 ZERO_STRUCTP(r->out.user_handle);
2909 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2911 d_state = h->data;
2913 /* form the users SID */
2914 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2915 if (!sid) {
2916 return NT_STATUS_NO_MEMORY;
2919 /* search for the user record */
2920 ret = gendb_search(d_state->sam_ctx,
2921 mem_ctx, d_state->domain_dn, &msgs, attrs,
2922 "(&(objectSid=%s)(objectclass=user))",
2923 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2924 if (ret == 0) {
2925 return NT_STATUS_NO_SUCH_USER;
2927 if (ret != 1) {
2928 DEBUG(0,("Found %d records matching sid %s\n", ret,
2929 dom_sid_string(mem_ctx, sid)));
2930 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2933 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2934 if (account_name == NULL) {
2935 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2936 dom_sid_string(mem_ctx, sid)));
2937 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2940 a_state = talloc(mem_ctx, struct samr_account_state);
2941 if (!a_state) {
2942 return NT_STATUS_NO_MEMORY;
2944 a_state->sam_ctx = d_state->sam_ctx;
2945 a_state->access_mask = r->in.access_mask;
2946 a_state->domain_state = talloc_reference(a_state, d_state);
2947 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2948 a_state->account_sid = talloc_steal(a_state, sid);
2949 a_state->account_name = talloc_strdup(a_state, account_name);
2950 if (!a_state->account_name) {
2951 return NT_STATUS_NO_MEMORY;
2954 /* create the policy handle */
2955 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2956 if (!u_handle) {
2957 return NT_STATUS_NO_MEMORY;
2960 u_handle->data = talloc_steal(u_handle, a_state);
2962 *r->out.user_handle = u_handle->wire_handle;
2964 return NT_STATUS_OK;
2970 samr_DeleteUser
2972 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2973 struct samr_DeleteUser *r)
2975 struct dcesrv_handle *h;
2976 struct samr_account_state *a_state;
2977 int ret;
2979 *r->out.user_handle = *r->in.user_handle;
2981 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2983 a_state = h->data;
2985 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2986 if (ret != LDB_SUCCESS) {
2987 DEBUG(1, ("Failed to delete user: %s: %s\n",
2988 ldb_dn_get_linearized(a_state->account_dn),
2989 ldb_errstring(a_state->sam_ctx)));
2990 return NT_STATUS_UNSUCCESSFUL;
2993 talloc_free(h);
2994 ZERO_STRUCTP(r->out.user_handle);
2996 return NT_STATUS_OK;
3001 samr_QueryUserInfo
3003 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3004 struct samr_QueryUserInfo *r)
3006 struct dcesrv_handle *h;
3007 struct samr_account_state *a_state;
3008 struct ldb_message *msg, **res;
3009 int ret;
3010 struct ldb_context *sam_ctx;
3012 const char * const *attrs = NULL;
3013 union samr_UserInfo *info;
3015 *r->out.info = NULL;
3017 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3019 a_state = h->data;
3020 sam_ctx = a_state->sam_ctx;
3022 /* fill in the reply */
3023 switch (r->in.level) {
3024 case 1:
3026 static const char * const attrs2[] = {"sAMAccountName",
3027 "displayName",
3028 "primaryroupID",
3029 "description",
3030 "comment",
3031 NULL};
3032 attrs = attrs2;
3033 break;
3035 case 2:
3037 static const char * const attrs2[] = {"comment",
3038 "countryCode",
3039 "codePage",
3040 NULL};
3041 attrs = attrs2;
3042 break;
3044 case 3:
3046 static const char * const attrs2[] = {"sAMAccountName",
3047 "displayName",
3048 "objectSid",
3049 "primaryGroupID",
3050 "homeDirectory",
3051 "homeDrive",
3052 "scriptPath",
3053 "profilePath",
3054 "userWorkstations",
3055 "lastLogon",
3056 "lastLogoff",
3057 "pwdLastSet",
3058 "logonHours",
3059 "badPwdCount",
3060 "logonCount",
3061 "userAccountControl",
3062 NULL};
3063 attrs = attrs2;
3064 break;
3066 case 4:
3068 static const char * const attrs2[] = {"logonHours",
3069 NULL};
3070 attrs = attrs2;
3071 break;
3073 case 5:
3075 static const char * const attrs2[] = {"sAMAccountName",
3076 "displayName",
3077 "objectSid",
3078 "primaryGroupID",
3079 "homeDirectory",
3080 "homeDrive",
3081 "scriptPath",
3082 "profilePath",
3083 "description",
3084 "userWorkstations",
3085 "lastLogon",
3086 "lastLogoff",
3087 "logonHours",
3088 "badPwdCount",
3089 "logonCount",
3090 "pwdLastSet",
3091 "accountExpires",
3092 "userAccountControl",
3093 NULL};
3094 attrs = attrs2;
3095 break;
3097 case 6:
3099 static const char * const attrs2[] = {"sAMAccountName",
3100 "displayName",
3101 NULL};
3102 attrs = attrs2;
3103 break;
3105 case 7:
3107 static const char * const attrs2[] = {"sAMAccountName",
3108 NULL};
3109 attrs = attrs2;
3110 break;
3112 case 8:
3114 static const char * const attrs2[] = {"displayName",
3115 NULL};
3116 attrs = attrs2;
3117 break;
3119 case 9:
3121 static const char * const attrs2[] = {"primaryGroupID",
3122 NULL};
3123 attrs = attrs2;
3124 break;
3126 case 10:
3128 static const char * const attrs2[] = {"homeDirectory",
3129 "homeDrive",
3130 NULL};
3131 attrs = attrs2;
3132 break;
3134 case 11:
3136 static const char * const attrs2[] = {"scriptPath",
3137 NULL};
3138 attrs = attrs2;
3139 break;
3141 case 12:
3143 static const char * const attrs2[] = {"profilePath",
3144 NULL};
3145 attrs = attrs2;
3146 break;
3148 case 13:
3150 static const char * const attrs2[] = {"description",
3151 NULL};
3152 attrs = attrs2;
3153 break;
3155 case 14:
3157 static const char * const attrs2[] = {"userWorkstations",
3158 NULL};
3159 attrs = attrs2;
3160 break;
3162 case 16:
3164 static const char * const attrs2[] = {"userAccountControl",
3165 "pwdLastSet",
3166 NULL};
3167 attrs = attrs2;
3168 break;
3170 case 17:
3172 static const char * const attrs2[] = {"accountExpires",
3173 NULL};
3174 attrs = attrs2;
3175 break;
3177 case 18:
3179 return NT_STATUS_NOT_SUPPORTED;
3181 case 20:
3183 static const char * const attrs2[] = {"userParameters",
3184 NULL};
3185 attrs = attrs2;
3186 break;
3188 case 21:
3190 static const char * const attrs2[] = {"lastLogon",
3191 "lastLogoff",
3192 "pwdLastSet",
3193 "accountExpires",
3194 "sAMAccountName",
3195 "displayName",
3196 "homeDirectory",
3197 "homeDrive",
3198 "scriptPath",
3199 "profilePath",
3200 "description",
3201 "userWorkstations",
3202 "comment",
3203 "userParameters",
3204 "objectSid",
3205 "primaryGroupID",
3206 "userAccountControl",
3207 "logonHours",
3208 "badPwdCount",
3209 "logonCount",
3210 "countryCode",
3211 "codePage",
3212 NULL};
3213 attrs = attrs2;
3214 break;
3216 case 23:
3217 case 24:
3218 case 25:
3219 case 26:
3221 return NT_STATUS_NOT_SUPPORTED;
3223 default:
3225 return NT_STATUS_INVALID_INFO_CLASS;
3229 /* pull all the user attributes */
3230 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3231 a_state->account_dn ,&res, attrs);
3232 if (ret != 1) {
3233 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3235 msg = res[0];
3237 /* allocate the info structure */
3238 info = talloc_zero(mem_ctx, union samr_UserInfo);
3239 if (info == NULL) {
3240 return NT_STATUS_NO_MEMORY;
3243 /* fill in the reply */
3244 switch (r->in.level) {
3245 case 1:
3246 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3247 QUERY_STRING(msg, info1.full_name, "displayName");
3248 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3249 QUERY_STRING(msg, info1.description, "description");
3250 QUERY_STRING(msg, info1.comment, "comment");
3251 break;
3253 case 2:
3254 QUERY_STRING(msg, info2.comment, "comment");
3255 QUERY_UINT (msg, info2.country_code, "countryCode");
3256 QUERY_UINT (msg, info2.code_page, "codePage");
3257 break;
3259 case 3:
3260 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3261 QUERY_STRING(msg, info3.full_name, "displayName");
3262 QUERY_RID (msg, info3.rid, "objectSid");
3263 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3264 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3265 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3266 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3267 QUERY_STRING(msg, info3.profile_path, "profilePath");
3268 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3269 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3270 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3271 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3272 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3273 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3274 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3275 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3276 QUERY_UINT (msg, info3.logon_count, "logonCount");
3277 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3278 break;
3280 case 4:
3281 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3282 break;
3284 case 5:
3285 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3286 QUERY_STRING(msg, info5.full_name, "displayName");
3287 QUERY_RID (msg, info5.rid, "objectSid");
3288 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3289 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3290 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3291 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3292 QUERY_STRING(msg, info5.profile_path, "profilePath");
3293 QUERY_STRING(msg, info5.description, "description");
3294 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3295 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3296 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3297 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3298 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3299 QUERY_UINT (msg, info5.logon_count, "logonCount");
3300 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3301 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3302 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3303 break;
3305 case 6:
3306 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3307 QUERY_STRING(msg, info6.full_name, "displayName");
3308 break;
3310 case 7:
3311 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3312 break;
3314 case 8:
3315 QUERY_STRING(msg, info8.full_name, "displayName");
3316 break;
3318 case 9:
3319 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3320 break;
3322 case 10:
3323 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3324 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3325 break;
3327 case 11:
3328 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3329 break;
3331 case 12:
3332 QUERY_STRING(msg, info12.profile_path, "profilePath");
3333 break;
3335 case 13:
3336 QUERY_STRING(msg, info13.description, "description");
3337 break;
3339 case 14:
3340 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3341 break;
3343 case 16:
3344 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3345 break;
3347 case 17:
3348 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3349 break;
3351 case 20:
3352 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3353 break;
3355 case 21:
3356 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3357 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3358 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3359 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3360 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3361 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3362 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3363 QUERY_STRING(msg, info21.full_name, "displayName");
3364 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3365 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3366 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3367 QUERY_STRING(msg, info21.profile_path, "profilePath");
3368 QUERY_STRING(msg, info21.description, "description");
3369 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3370 QUERY_STRING(msg, info21.comment, "comment");
3371 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3372 QUERY_RID (msg, info21.rid, "objectSid");
3373 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3374 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3375 info->info21.fields_present = 0x00FFFFFF;
3376 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3377 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3378 QUERY_UINT (msg, info21.logon_count, "logonCount");
3379 QUERY_UINT (msg, info21.country_code, "countryCode");
3380 QUERY_UINT (msg, info21.code_page, "codePage");
3381 break;
3384 default:
3385 talloc_free(info);
3386 return NT_STATUS_INVALID_INFO_CLASS;
3389 *r->out.info = info;
3391 return NT_STATUS_OK;
3396 samr_SetUserInfo
3398 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3399 struct samr_SetUserInfo *r)
3401 struct dcesrv_handle *h;
3402 struct samr_account_state *a_state;
3403 struct ldb_message *msg;
3404 int ret;
3405 NTSTATUS status = NT_STATUS_OK;
3406 struct ldb_context *sam_ctx;
3408 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3410 a_state = h->data;
3411 sam_ctx = a_state->sam_ctx;
3413 msg = ldb_msg_new(mem_ctx);
3414 if (msg == NULL) {
3415 return NT_STATUS_NO_MEMORY;
3418 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3419 if (!msg->dn) {
3420 return NT_STATUS_NO_MEMORY;
3423 switch (r->in.level) {
3424 case 2:
3425 SET_STRING(msg, info2.comment, "comment");
3426 SET_UINT (msg, info2.country_code, "countryCode");
3427 SET_UINT (msg, info2.code_page, "codePage");
3428 break;
3430 case 4:
3431 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3432 break;
3434 case 6:
3435 SET_STRING(msg, info6.account_name, "samAccountName");
3436 SET_STRING(msg, info6.full_name, "displayName");
3437 break;
3439 case 7:
3440 SET_STRING(msg, info7.account_name, "samAccountName");
3441 break;
3443 case 8:
3444 SET_STRING(msg, info8.full_name, "displayName");
3445 break;
3447 case 9:
3448 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3449 break;
3451 case 10:
3452 SET_STRING(msg, info10.home_directory, "homeDirectory");
3453 SET_STRING(msg, info10.home_drive, "homeDrive");
3454 break;
3456 case 11:
3457 SET_STRING(msg, info11.logon_script, "scriptPath");
3458 break;
3460 case 12:
3461 SET_STRING(msg, info12.profile_path, "profilePath");
3462 break;
3464 case 13:
3465 SET_STRING(msg, info13.description, "description");
3466 break;
3468 case 14:
3469 SET_STRING(msg, info14.workstations, "userWorkstations");
3470 break;
3472 case 16:
3473 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3474 break;
3476 case 17:
3477 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3478 break;
3480 case 20:
3481 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3482 break;
3484 case 21:
3485 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3486 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3487 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3488 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3489 SET_STRING(msg, info21.account_name, "samAccountName");
3490 IFSET(SAMR_FIELD_FULL_NAME)
3491 SET_STRING(msg, info21.full_name, "displayName");
3492 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3493 SET_STRING(msg, info21.home_directory, "homeDirectory");
3494 IFSET(SAMR_FIELD_HOME_DRIVE)
3495 SET_STRING(msg, info21.home_drive, "homeDrive");
3496 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3497 SET_STRING(msg, info21.logon_script, "scriptPath");
3498 IFSET(SAMR_FIELD_PROFILE_PATH)
3499 SET_STRING(msg, info21.profile_path, "profilePath");
3500 IFSET(SAMR_FIELD_DESCRIPTION)
3501 SET_STRING(msg, info21.description, "description");
3502 IFSET(SAMR_FIELD_WORKSTATIONS)
3503 SET_STRING(msg, info21.workstations, "userWorkstations");
3504 IFSET(SAMR_FIELD_COMMENT)
3505 SET_STRING(msg, info21.comment, "comment");
3506 IFSET(SAMR_FIELD_PARAMETERS)
3507 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3508 IFSET(SAMR_FIELD_PRIMARY_GID)
3509 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3510 IFSET(SAMR_FIELD_ACCT_FLAGS)
3511 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3512 IFSET(SAMR_FIELD_LOGON_HOURS)
3513 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3514 IFSET(SAMR_FIELD_COUNTRY_CODE)
3515 SET_UINT (msg, info21.country_code, "countryCode");
3516 IFSET(SAMR_FIELD_CODE_PAGE)
3517 SET_UINT (msg, info21.code_page, "codePage");
3518 #undef IFSET
3519 break;
3521 case 23:
3522 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3523 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3524 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3525 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3526 SET_STRING(msg, info23.info.account_name, "samAccountName");
3527 IFSET(SAMR_FIELD_FULL_NAME)
3528 SET_STRING(msg, info23.info.full_name, "displayName");
3529 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3530 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3531 IFSET(SAMR_FIELD_HOME_DRIVE)
3532 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3533 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3534 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3535 IFSET(SAMR_FIELD_PROFILE_PATH)
3536 SET_STRING(msg, info23.info.profile_path, "profilePath");
3537 IFSET(SAMR_FIELD_DESCRIPTION)
3538 SET_STRING(msg, info23.info.description, "description");
3539 IFSET(SAMR_FIELD_WORKSTATIONS)
3540 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3541 IFSET(SAMR_FIELD_COMMENT)
3542 SET_STRING(msg, info23.info.comment, "comment");
3543 IFSET(SAMR_FIELD_PARAMETERS)
3544 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3545 IFSET(SAMR_FIELD_PRIMARY_GID)
3546 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3547 IFSET(SAMR_FIELD_ACCT_FLAGS)
3548 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3549 IFSET(SAMR_FIELD_LOGON_HOURS)
3550 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3551 IFSET(SAMR_FIELD_COUNTRY_CODE)
3552 SET_UINT (msg, info23.info.country_code, "countryCode");
3553 IFSET(SAMR_FIELD_CODE_PAGE)
3554 SET_UINT (msg, info23.info.code_page, "codePage");
3556 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3557 status = samr_set_password(dce_call,
3558 a_state->sam_ctx,
3559 a_state->account_dn,
3560 a_state->domain_state->domain_dn,
3561 mem_ctx, msg,
3562 &r->in.info->info23.password);
3563 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3564 status = samr_set_password(dce_call,
3565 a_state->sam_ctx,
3566 a_state->account_dn,
3567 a_state->domain_state->domain_dn,
3568 mem_ctx, msg,
3569 &r->in.info->info23.password);
3571 #undef IFSET
3572 break;
3574 /* the set password levels are handled separately */
3575 case 24:
3576 status = samr_set_password(dce_call,
3577 a_state->sam_ctx,
3578 a_state->account_dn,
3579 a_state->domain_state->domain_dn,
3580 mem_ctx, msg,
3581 &r->in.info->info24.password);
3582 break;
3584 case 25:
3585 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3586 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3587 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3588 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3589 SET_STRING(msg, info25.info.account_name, "samAccountName");
3590 IFSET(SAMR_FIELD_FULL_NAME)
3591 SET_STRING(msg, info25.info.full_name, "displayName");
3592 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3593 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3594 IFSET(SAMR_FIELD_HOME_DRIVE)
3595 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3596 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3597 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3598 IFSET(SAMR_FIELD_PROFILE_PATH)
3599 SET_STRING(msg, info25.info.profile_path, "profilePath");
3600 IFSET(SAMR_FIELD_DESCRIPTION)
3601 SET_STRING(msg, info25.info.description, "description");
3602 IFSET(SAMR_FIELD_WORKSTATIONS)
3603 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3604 IFSET(SAMR_FIELD_COMMENT)
3605 SET_STRING(msg, info25.info.comment, "comment");
3606 IFSET(SAMR_FIELD_PARAMETERS)
3607 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3608 IFSET(SAMR_FIELD_PRIMARY_GID)
3609 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3610 IFSET(SAMR_FIELD_ACCT_FLAGS)
3611 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3612 IFSET(SAMR_FIELD_LOGON_HOURS)
3613 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3614 IFSET(SAMR_FIELD_COUNTRY_CODE)
3615 SET_UINT (msg, info25.info.country_code, "countryCode");
3616 IFSET(SAMR_FIELD_CODE_PAGE)
3617 SET_UINT (msg, info25.info.code_page, "codePage");
3619 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3620 status = samr_set_password_ex(dce_call,
3621 a_state->sam_ctx,
3622 a_state->account_dn,
3623 a_state->domain_state->domain_dn,
3624 mem_ctx, msg,
3625 &r->in.info->info25.password);
3626 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3627 status = samr_set_password_ex(dce_call,
3628 a_state->sam_ctx,
3629 a_state->account_dn,
3630 a_state->domain_state->domain_dn,
3631 mem_ctx, msg,
3632 &r->in.info->info25.password);
3634 #undef IFSET
3635 break;
3637 /* the set password levels are handled separately */
3638 case 26:
3639 status = samr_set_password_ex(dce_call,
3640 a_state->sam_ctx,
3641 a_state->account_dn,
3642 a_state->domain_state->domain_dn,
3643 mem_ctx, msg,
3644 &r->in.info->info26.password);
3645 break;
3648 default:
3649 /* many info classes are not valid for SetUserInfo */
3650 return NT_STATUS_INVALID_INFO_CLASS;
3653 if (!NT_STATUS_IS_OK(status)) {
3654 return status;
3657 /* modify the samdb record */
3658 if (msg->num_elements > 0) {
3659 ret = ldb_modify(a_state->sam_ctx, msg);
3660 if (ret != LDB_SUCCESS) {
3661 DEBUG(1,("Failed to modify record %s: %s\n",
3662 ldb_dn_get_linearized(a_state->account_dn),
3663 ldb_errstring(a_state->sam_ctx)));
3665 /* we really need samdb.c to return NTSTATUS */
3666 return NT_STATUS_UNSUCCESSFUL;
3670 return NT_STATUS_OK;
3675 samr_GetGroupsForUser
3677 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3678 struct samr_GetGroupsForUser *r)
3680 struct dcesrv_handle *h;
3681 struct samr_account_state *a_state;
3682 struct samr_domain_state *d_state;
3683 struct ldb_message **res;
3684 const char * const attrs[2] = { "objectSid", NULL };
3685 struct samr_RidWithAttributeArray *array;
3686 int i, count;
3688 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3690 a_state = h->data;
3691 d_state = a_state->domain_state;
3693 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3694 d_state->domain_dn, &res,
3695 attrs, d_state->domain_sid,
3696 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3697 ldb_dn_get_linearized(a_state->account_dn),
3698 GTYPE_SECURITY_GLOBAL_GROUP);
3699 if (count < 0)
3700 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3702 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3703 if (array == NULL)
3704 return NT_STATUS_NO_MEMORY;
3706 array->count = 0;
3707 array->rids = NULL;
3709 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3710 count + 1);
3711 if (array->rids == NULL)
3712 return NT_STATUS_NO_MEMORY;
3714 /* Adds the primary group */
3715 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3716 ~0, a_state->account_dn,
3717 "primaryGroupID", NULL);
3718 array->rids[0].attributes = SE_GROUP_MANDATORY
3719 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3720 array->count += 1;
3722 /* Adds the additional groups */
3723 for (i = 0; i < count; i++) {
3724 struct dom_sid *group_sid;
3726 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3727 if (group_sid == NULL) {
3728 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3729 continue;
3732 array->rids[i + 1].rid =
3733 group_sid->sub_auths[group_sid->num_auths-1];
3734 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3735 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3736 array->count += 1;
3739 *r->out.rids = array;
3741 return NT_STATUS_OK;
3746 samr_QueryDisplayInfo
3748 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3749 struct samr_QueryDisplayInfo *r)
3751 struct dcesrv_handle *h;
3752 struct samr_domain_state *d_state;
3753 struct ldb_message **res;
3754 int ldb_cnt, count, i;
3755 const char * const attrs[] = { "objectSid", "sAMAccountName",
3756 "displayName", "description", "userAccountControl",
3757 "pwdLastSet", NULL };
3758 struct samr_DispEntryFull *entriesFull = NULL;
3759 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3760 struct samr_DispEntryAscii *entriesAscii = NULL;
3761 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3762 const char *filter;
3764 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3766 d_state = h->data;
3768 switch (r->in.level) {
3769 case 1:
3770 case 4:
3771 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3772 "(sAMAccountType=%u))",
3773 ATYPE_NORMAL_ACCOUNT);
3774 break;
3775 case 2:
3776 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3777 "(sAMAccountType=%u))",
3778 ATYPE_WORKSTATION_TRUST);
3779 break;
3780 case 3:
3781 case 5:
3782 filter = talloc_asprintf(mem_ctx,
3783 "(&(|(groupType=%d)(groupType=%d))"
3784 "(objectClass=group))",
3785 GTYPE_SECURITY_UNIVERSAL_GROUP,
3786 GTYPE_SECURITY_GLOBAL_GROUP);
3787 break;
3788 default:
3789 return NT_STATUS_INVALID_INFO_CLASS;
3792 /* search for all requested objects in this domain. This could
3793 possibly be cached and resumed based on resume_key */
3794 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3795 d_state->domain_dn, &res, attrs,
3796 d_state->domain_sid, "%s", filter);
3797 if (ldb_cnt == -1) {
3798 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3800 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3801 return NT_STATUS_OK;
3804 switch (r->in.level) {
3805 case 1:
3806 entriesGeneral = talloc_array(mem_ctx,
3807 struct samr_DispEntryGeneral,
3808 ldb_cnt);
3809 break;
3810 case 2:
3811 entriesFull = talloc_array(mem_ctx,
3812 struct samr_DispEntryFull,
3813 ldb_cnt);
3814 break;
3815 case 3:
3816 entriesFullGroup = talloc_array(mem_ctx,
3817 struct samr_DispEntryFullGroup,
3818 ldb_cnt);
3819 break;
3820 case 4:
3821 case 5:
3822 entriesAscii = talloc_array(mem_ctx,
3823 struct samr_DispEntryAscii,
3824 ldb_cnt);
3825 break;
3828 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3829 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3830 return NT_STATUS_NO_MEMORY;
3832 count = 0;
3834 for (i=0; i<ldb_cnt; i++) {
3835 struct dom_sid *objectsid;
3837 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3838 "objectSid");
3839 if (objectsid == NULL)
3840 continue;
3842 switch(r->in.level) {
3843 case 1:
3844 entriesGeneral[count].idx = count + 1;
3845 entriesGeneral[count].rid =
3846 objectsid->sub_auths[objectsid->num_auths-1];
3847 entriesGeneral[count].acct_flags =
3848 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3849 res[i],
3850 d_state->domain_dn);
3851 entriesGeneral[count].account_name.string =
3852 samdb_result_string(res[i],
3853 "sAMAccountName", "");
3854 entriesGeneral[count].full_name.string =
3855 samdb_result_string(res[i], "displayName", "");
3856 entriesGeneral[count].description.string =
3857 samdb_result_string(res[i], "description", "");
3858 break;
3859 case 2:
3860 entriesFull[count].idx = count + 1;
3861 entriesFull[count].rid =
3862 objectsid->sub_auths[objectsid->num_auths-1];
3864 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3865 entriesFull[count].acct_flags =
3866 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3867 res[i],
3868 d_state->domain_dn) | ACB_NORMAL;
3869 entriesFull[count].account_name.string =
3870 samdb_result_string(res[i], "sAMAccountName",
3871 "");
3872 entriesFull[count].description.string =
3873 samdb_result_string(res[i], "description", "");
3874 break;
3875 case 3:
3876 entriesFullGroup[count].idx = count + 1;
3877 entriesFullGroup[count].rid =
3878 objectsid->sub_auths[objectsid->num_auths-1];
3879 /* We get a "7" here for groups */
3880 entriesFullGroup[count].acct_flags
3881 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3882 entriesFullGroup[count].account_name.string =
3883 samdb_result_string(res[i], "sAMAccountName",
3884 "");
3885 entriesFullGroup[count].description.string =
3886 samdb_result_string(res[i], "description", "");
3887 break;
3888 case 4:
3889 case 5:
3890 entriesAscii[count].idx = count + 1;
3891 entriesAscii[count].account_name.string =
3892 samdb_result_string(res[i], "sAMAccountName",
3893 "");
3894 break;
3897 count += 1;
3900 *r->out.total_size = count;
3902 if (r->in.start_idx >= count) {
3903 *r->out.returned_size = 0;
3904 switch(r->in.level) {
3905 case 1:
3906 r->out.info->info1.count = *r->out.returned_size;
3907 r->out.info->info1.entries = NULL;
3908 break;
3909 case 2:
3910 r->out.info->info2.count = *r->out.returned_size;
3911 r->out.info->info2.entries = NULL;
3912 break;
3913 case 3:
3914 r->out.info->info3.count = *r->out.returned_size;
3915 r->out.info->info3.entries = NULL;
3916 break;
3917 case 4:
3918 r->out.info->info4.count = *r->out.returned_size;
3919 r->out.info->info4.entries = NULL;
3920 break;
3921 case 5:
3922 r->out.info->info5.count = *r->out.returned_size;
3923 r->out.info->info5.entries = NULL;
3924 break;
3926 } else {
3927 *r->out.returned_size = MIN(count - r->in.start_idx,
3928 r->in.max_entries);
3929 switch(r->in.level) {
3930 case 1:
3931 r->out.info->info1.count = *r->out.returned_size;
3932 r->out.info->info1.entries =
3933 &(entriesGeneral[r->in.start_idx]);
3934 break;
3935 case 2:
3936 r->out.info->info2.count = *r->out.returned_size;
3937 r->out.info->info2.entries =
3938 &(entriesFull[r->in.start_idx]);
3939 break;
3940 case 3:
3941 r->out.info->info3.count = *r->out.returned_size;
3942 r->out.info->info3.entries =
3943 &(entriesFullGroup[r->in.start_idx]);
3944 break;
3945 case 4:
3946 r->out.info->info4.count = *r->out.returned_size;
3947 r->out.info->info4.entries =
3948 &(entriesAscii[r->in.start_idx]);
3949 break;
3950 case 5:
3951 r->out.info->info5.count = *r->out.returned_size;
3952 r->out.info->info5.entries =
3953 &(entriesAscii[r->in.start_idx]);
3954 break;
3958 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3959 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3964 samr_GetDisplayEnumerationIndex
3966 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3967 struct samr_GetDisplayEnumerationIndex *r)
3969 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3974 samr_TestPrivateFunctionsDomain
3976 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3977 struct samr_TestPrivateFunctionsDomain *r)
3979 return NT_STATUS_NOT_IMPLEMENTED;
3984 samr_TestPrivateFunctionsUser
3986 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3987 struct samr_TestPrivateFunctionsUser *r)
3989 return NT_STATUS_NOT_IMPLEMENTED;
3994 samr_GetUserPwInfo
3996 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3997 struct samr_GetUserPwInfo *r)
3999 struct dcesrv_handle *h;
4000 struct samr_account_state *a_state;
4002 ZERO_STRUCTP(r->out.info);
4004 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4006 a_state = h->data;
4008 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4009 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4010 NULL);
4011 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4012 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4014 return NT_STATUS_OK;
4019 samr_RemoveMemberFromForeignDomain
4021 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4022 struct samr_RemoveMemberFromForeignDomain *r)
4024 struct dcesrv_handle *h;
4025 struct samr_domain_state *d_state;
4026 const char *memberdn;
4027 struct ldb_message **res;
4028 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
4029 int i, count;
4031 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4033 d_state = h->data;
4035 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4036 "distinguishedName", "(objectSid=%s)",
4037 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4038 /* Nothing to do */
4039 if (memberdn == NULL) {
4040 return NT_STATUS_OK;
4043 /* TODO: Does this call only remove alias members, or does it do this
4044 * for domain groups as well? */
4046 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4047 d_state->domain_dn, &res, attrs,
4048 d_state->domain_sid,
4049 "(&(member=%s)(objectClass=group)"
4050 "(|(groupType=%d)(groupType=%d)))",
4051 memberdn,
4052 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4053 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4055 if (count < 0)
4056 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4058 for (i=0; i<count; i++) {
4059 struct ldb_message *mod;
4061 mod = ldb_msg_new(mem_ctx);
4062 if (mod == NULL) {
4063 return NT_STATUS_NO_MEMORY;
4066 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4067 if (mod->dn == NULL) {
4068 talloc_free(mod);
4069 continue;
4072 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4073 "member", memberdn) != LDB_SUCCESS)
4074 return NT_STATUS_NO_MEMORY;
4076 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
4077 return NT_STATUS_UNSUCCESSFUL;
4079 talloc_free(mod);
4082 return NT_STATUS_OK;
4087 samr_QueryDomainInfo2
4089 just an alias for samr_QueryDomainInfo
4091 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4092 struct samr_QueryDomainInfo2 *r)
4094 struct samr_QueryDomainInfo r1;
4095 NTSTATUS status;
4097 ZERO_STRUCT(r1.out);
4098 r1.in.domain_handle = r->in.domain_handle;
4099 r1.in.level = r->in.level;
4100 r1.out.info = r->out.info;
4102 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4104 return status;
4109 samr_QueryUserInfo2
4111 just an alias for samr_QueryUserInfo
4113 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4114 struct samr_QueryUserInfo2 *r)
4116 struct samr_QueryUserInfo r1;
4117 NTSTATUS status;
4119 r1.in.user_handle = r->in.user_handle;
4120 r1.in.level = r->in.level;
4121 r1.out.info = r->out.info;
4123 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4125 return status;
4130 samr_QueryDisplayInfo2
4132 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4133 struct samr_QueryDisplayInfo2 *r)
4135 struct samr_QueryDisplayInfo q;
4136 NTSTATUS result;
4138 q.in.domain_handle = r->in.domain_handle;
4139 q.in.level = r->in.level;
4140 q.in.start_idx = r->in.start_idx;
4141 q.in.max_entries = r->in.max_entries;
4142 q.in.buf_size = r->in.buf_size;
4143 q.out.total_size = r->out.total_size;
4144 q.out.returned_size = r->out.returned_size;
4145 q.out.info = r->out.info;
4147 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4149 return result;
4154 samr_GetDisplayEnumerationIndex2
4156 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4157 struct samr_GetDisplayEnumerationIndex2 *r)
4159 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4164 samr_QueryDisplayInfo3
4166 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4167 struct samr_QueryDisplayInfo3 *r)
4169 struct samr_QueryDisplayInfo q;
4170 NTSTATUS result;
4172 q.in.domain_handle = r->in.domain_handle;
4173 q.in.level = r->in.level;
4174 q.in.start_idx = r->in.start_idx;
4175 q.in.max_entries = r->in.max_entries;
4176 q.in.buf_size = r->in.buf_size;
4177 q.out.total_size = r->out.total_size;
4178 q.out.returned_size = r->out.returned_size;
4179 q.out.info = r->out.info;
4181 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4183 return result;
4188 samr_AddMultipleMembersToAlias
4190 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4191 struct samr_AddMultipleMembersToAlias *r)
4193 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4198 samr_RemoveMultipleMembersFromAlias
4200 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4201 struct samr_RemoveMultipleMembersFromAlias *r)
4203 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4208 samr_GetDomPwInfo
4210 this fetches the default password properties for a domain
4212 note that w2k3 completely ignores the domain name in this call, and
4213 always returns the information for the servers primary domain
4215 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4216 struct samr_GetDomPwInfo *r)
4218 struct ldb_message **msgs;
4219 int ret;
4220 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4221 struct ldb_context *sam_ctx;
4223 ZERO_STRUCTP(r->out.info);
4225 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4226 dce_call->conn->dce_ctx->lp_ctx,
4227 dce_call->conn->auth_state.session_info);
4228 if (sam_ctx == NULL) {
4229 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4232 /* The domain name in this call is ignored */
4233 ret = gendb_search_dn(sam_ctx,
4234 mem_ctx, NULL, &msgs, attrs);
4235 if (ret <= 0) {
4236 talloc_free(sam_ctx);
4238 return NT_STATUS_NO_SUCH_DOMAIN;
4240 if (ret > 1) {
4241 talloc_free(msgs);
4242 talloc_free(sam_ctx);
4244 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4247 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4248 "minPwdLength", 0);
4249 r->out.info->password_properties = samdb_result_uint(msgs[0],
4250 "pwdProperties", 1);
4252 talloc_free(msgs);
4253 talloc_unlink(mem_ctx, sam_ctx);
4255 return NT_STATUS_OK;
4260 samr_Connect2
4262 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4263 struct samr_Connect2 *r)
4265 struct samr_Connect c;
4267 c.in.system_name = NULL;
4268 c.in.access_mask = r->in.access_mask;
4269 c.out.connect_handle = r->out.connect_handle;
4271 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4276 samr_SetUserInfo2
4278 just an alias for samr_SetUserInfo
4280 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4281 struct samr_SetUserInfo2 *r)
4283 struct samr_SetUserInfo r2;
4285 r2.in.user_handle = r->in.user_handle;
4286 r2.in.level = r->in.level;
4287 r2.in.info = r->in.info;
4289 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4294 samr_SetBootKeyInformation
4296 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4297 struct samr_SetBootKeyInformation *r)
4299 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4304 samr_GetBootKeyInformation
4306 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4307 struct samr_GetBootKeyInformation *r)
4309 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4314 samr_Connect3
4316 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4317 struct samr_Connect3 *r)
4319 struct samr_Connect c;
4321 c.in.system_name = NULL;
4322 c.in.access_mask = r->in.access_mask;
4323 c.out.connect_handle = r->out.connect_handle;
4325 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4330 samr_Connect4
4332 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4333 struct samr_Connect4 *r)
4335 struct samr_Connect c;
4337 c.in.system_name = NULL;
4338 c.in.access_mask = r->in.access_mask;
4339 c.out.connect_handle = r->out.connect_handle;
4341 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4346 samr_Connect5
4348 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4349 struct samr_Connect5 *r)
4351 struct samr_Connect c;
4352 NTSTATUS status;
4354 c.in.system_name = NULL;
4355 c.in.access_mask = r->in.access_mask;
4356 c.out.connect_handle = r->out.connect_handle;
4358 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4360 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4361 r->out.info_out->info1.unknown2 = 0;
4362 *r->out.level_out = r->in.level_in;
4364 return status;
4369 samr_RidToSid
4371 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4372 struct samr_RidToSid *r)
4374 struct samr_domain_state *d_state;
4375 struct dcesrv_handle *h;
4377 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4379 d_state = h->data;
4381 /* form the users SID */
4382 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4383 if (!*r->out.sid) {
4384 return NT_STATUS_NO_MEMORY;
4387 return NT_STATUS_OK;
4392 samr_SetDsrmPassword
4394 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4395 struct samr_SetDsrmPassword *r)
4397 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4402 samr_ValidatePassword
4404 For now the call checks the password complexity (if active) and the minimum
4405 password length on level 2 and 3. Level 1 is ignored for now.
4407 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4408 TALLOC_CTX *mem_ctx,
4409 struct samr_ValidatePassword *r)
4411 struct samr_GetDomPwInfo r2;
4412 struct samr_PwInfo pwInfo;
4413 DATA_BLOB password;
4414 enum samr_ValidationStatus res;
4415 NTSTATUS status;
4417 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4419 r2.in.domain_name = NULL;
4420 r2.out.info = &pwInfo;
4421 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4422 if (!NT_STATUS_IS_OK(status)) {
4423 return status;
4426 switch (r->in.level) {
4427 case NetValidateAuthentication:
4428 /* we don't support this yet */
4429 return NT_STATUS_NOT_SUPPORTED;
4430 break;
4431 case NetValidatePasswordChange:
4432 password = data_blob_const(r->in.req->req2.password.string,
4433 r->in.req->req2.password.length);
4434 res = samdb_check_password(&password,
4435 pwInfo.password_properties,
4436 pwInfo.min_password_length);
4437 (*r->out.rep)->ctr2.status = res;
4438 break;
4439 case NetValidatePasswordReset:
4440 password = data_blob_const(r->in.req->req3.password.string,
4441 r->in.req->req3.password.length);
4442 res = samdb_check_password(&password,
4443 pwInfo.password_properties,
4444 pwInfo.min_password_length);
4445 (*r->out.rep)->ctr3.status = res;
4446 break;
4447 default:
4448 return NT_STATUS_INVALID_INFO_CLASS;
4449 break;
4452 return NT_STATUS_OK;
4456 /* include the generated boilerplate */
4457 #include "librpc/gen_ndr/ndr_samr_s.c"