examples/VFS: fix shadow_copy_test.c in reference to shadow_copy changes
[Samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob25e57278d34e58602fad2b887303bf21b5895575
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 <ldb.h>
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
44 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
46 #define QUERY_STRING(msg, field, attr) \
47 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
48 #define QUERY_UINT(msg, field, attr) \
49 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
50 #define QUERY_RID(msg, field, attr) \
51 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
52 #define QUERY_UINT64(msg, field, attr) \
53 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
54 #define QUERY_APASSC(msg, field, attr) \
55 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg, attr);
57 #define QUERY_FPASSC(msg, field, attr) \
58 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
59 a_state->domain_state->domain_dn, msg);
60 #define QUERY_LHOURS(msg, field, attr) \
61 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
62 #define QUERY_AFLAGS(msg, field, attr) \
63 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
64 #define QUERY_PARAMETERS(msg, field, attr) \
65 info->field = samdb_result_parameters(mem_ctx, msg, attr);
68 /* these are used to make the Set[User|Group]Info code easier to follow */
70 #define SET_STRING(msg, field, attr) do { \
71 struct ldb_message_element *set_el; \
72 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
73 if (r->in.info->field.string[0] == '\0') { \
74 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
75 return NT_STATUS_NO_MEMORY; \
76 } \
77 } \
78 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
79 return NT_STATUS_NO_MEMORY; \
80 } \
81 set_el = ldb_msg_find_element(msg, attr); \
82 set_el->flags = LDB_FLAG_MOD_REPLACE; \
83 } while (0)
85 #define SET_UINT(msg, field, attr) do { \
86 struct ldb_message_element *set_el; \
87 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
88 return NT_STATUS_NO_MEMORY; \
89 } \
90 set_el = ldb_msg_find_element(msg, attr); \
91 set_el->flags = LDB_FLAG_MOD_REPLACE; \
92 } while (0)
94 #define SET_INT64(msg, field, attr) do { \
95 struct ldb_message_element *set_el; \
96 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
97 return NT_STATUS_NO_MEMORY; \
98 } \
99 set_el = ldb_msg_find_element(msg, attr); \
100 set_el->flags = LDB_FLAG_MOD_REPLACE; \
101 } while (0)
103 #define SET_UINT64(msg, field, attr) do { \
104 struct ldb_message_element *set_el; \
105 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
106 return NT_STATUS_NO_MEMORY; \
108 set_el = ldb_msg_find_element(msg, attr); \
109 set_el->flags = LDB_FLAG_MOD_REPLACE; \
110 } while (0)
112 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
113 do { \
114 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
115 return NT_STATUS_INVALID_PARAMETER; \
117 } while (0) \
119 /* Set account flags, discarding flags that cannot be set with SAMR */
120 #define SET_AFLAGS(msg, field, attr) do { \
121 struct ldb_message_element *set_el; \
122 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
123 return NT_STATUS_INVALID_PARAMETER; \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
128 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
129 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
130 return NT_STATUS_NO_MEMORY; \
132 set_el = ldb_msg_find_element(msg, attr); \
133 set_el->flags = LDB_FLAG_MOD_REPLACE; \
134 } while (0)
136 #define SET_LHOURS(msg, field, attr) do { \
137 struct ldb_message_element *set_el; \
138 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
139 return NT_STATUS_NO_MEMORY; \
141 set_el = ldb_msg_find_element(msg, attr); \
142 set_el->flags = LDB_FLAG_MOD_REPLACE; \
143 } while (0)
145 #define SET_PARAMETERS(msg, field, attr) do { \
146 struct ldb_message_element *set_el; \
147 if (r->in.info->field.length != 0) { \
148 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
149 return NT_STATUS_NO_MEMORY; \
151 set_el = ldb_msg_find_element(msg, attr); \
152 set_el->flags = LDB_FLAG_MOD_REPLACE; \
154 } while (0)
159 samr_Connect
161 create a connection to the SAM database
163 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
164 struct samr_Connect *r)
166 struct samr_connect_state *c_state;
167 struct dcesrv_handle *handle;
169 ZERO_STRUCTP(r->out.connect_handle);
171 c_state = talloc(mem_ctx, struct samr_connect_state);
172 if (!c_state) {
173 return NT_STATUS_NO_MEMORY;
176 /* make sure the sam database is accessible */
177 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, 0);
178 if (c_state->sam_ctx == NULL) {
179 talloc_free(c_state);
180 return NT_STATUS_INVALID_SYSTEM_SERVICE;
184 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
185 if (!handle) {
186 talloc_free(c_state);
187 return NT_STATUS_NO_MEMORY;
190 handle->data = talloc_steal(handle, c_state);
192 c_state->access_mask = r->in.access_mask;
193 *r->out.connect_handle = handle->wire_handle;
195 return NT_STATUS_OK;
200 samr_Close
202 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
203 struct samr_Close *r)
205 struct dcesrv_handle *h;
207 *r->out.handle = *r->in.handle;
209 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
211 talloc_free(h);
213 ZERO_STRUCTP(r->out.handle);
215 return NT_STATUS_OK;
220 samr_SetSecurity
222 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
223 struct samr_SetSecurity *r)
225 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
230 samr_QuerySecurity
232 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
233 struct samr_QuerySecurity *r)
235 struct dcesrv_handle *h;
236 struct sec_desc_buf *sd;
238 *r->out.sdbuf = NULL;
240 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
242 sd = talloc(mem_ctx, struct sec_desc_buf);
243 if (sd == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 sd->sd = samdb_default_security_descriptor(mem_ctx);
249 *r->out.sdbuf = sd;
251 return NT_STATUS_OK;
256 samr_Shutdown
258 we refuse this operation completely. If a admin wants to shutdown samr
259 in Samba then they should use the samba admin tools to disable the samr pipe
261 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
262 struct samr_Shutdown *r)
264 return NT_STATUS_ACCESS_DENIED;
269 samr_LookupDomain
271 this maps from a domain name to a SID
273 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
274 struct samr_LookupDomain *r)
276 struct samr_connect_state *c_state;
277 struct dcesrv_handle *h;
278 struct dom_sid *sid;
279 const char * const dom_attrs[] = { "objectSid", NULL};
280 struct ldb_message **dom_msgs;
281 int ret;
283 *r->out.sid = NULL;
285 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
287 c_state = h->data;
289 if (r->in.domain_name->string == NULL) {
290 return NT_STATUS_INVALID_PARAMETER;
293 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
294 ret = gendb_search(c_state->sam_ctx,
295 mem_ctx, NULL, &dom_msgs, dom_attrs,
296 "(objectClass=builtinDomain)");
297 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
298 ret = gendb_search_dn(c_state->sam_ctx,
299 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
300 &dom_msgs, dom_attrs);
301 } else {
302 return NT_STATUS_NO_SUCH_DOMAIN;
304 if (ret != 1) {
305 return NT_STATUS_NO_SUCH_DOMAIN;
308 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
309 "objectSid");
311 if (sid == NULL) {
312 return NT_STATUS_NO_SUCH_DOMAIN;
315 *r->out.sid = sid;
317 return NT_STATUS_OK;
322 samr_EnumDomains
324 list the domains in the SAM
326 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
327 struct samr_EnumDomains *r)
329 struct samr_connect_state *c_state;
330 struct dcesrv_handle *h;
331 struct samr_SamArray *array;
332 uint32_t i, start_i;
334 *r->out.resume_handle = 0;
335 *r->out.sam = NULL;
336 *r->out.num_entries = 0;
338 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
340 c_state = h->data;
342 *r->out.resume_handle = 2;
344 start_i = *r->in.resume_handle;
346 if (start_i >= 2) {
347 /* search past end of list is not an error for this call */
348 return NT_STATUS_OK;
351 array = talloc(mem_ctx, struct samr_SamArray);
352 if (array == NULL) {
353 return NT_STATUS_NO_MEMORY;
356 array->count = 0;
357 array->entries = NULL;
359 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
360 if (array->entries == NULL) {
361 return NT_STATUS_NO_MEMORY;
364 for (i=0;i<2-start_i;i++) {
365 array->entries[i].idx = start_i + i;
366 if (i == 0) {
367 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
368 } else {
369 array->entries[i].name.string = "BUILTIN";
373 *r->out.sam = array;
374 *r->out.num_entries = i;
375 array->count = *r->out.num_entries;
377 return NT_STATUS_OK;
382 samr_OpenDomain
384 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
385 struct samr_OpenDomain *r)
387 struct dcesrv_handle *h_conn, *h_domain;
388 struct samr_connect_state *c_state;
389 struct samr_domain_state *d_state;
390 const char * const dom_attrs[] = { "cn", NULL};
391 struct ldb_message **dom_msgs;
392 int ret;
394 ZERO_STRUCTP(r->out.domain_handle);
396 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
398 c_state = h_conn->data;
400 if (r->in.sid == NULL) {
401 return NT_STATUS_INVALID_PARAMETER;
404 d_state = talloc(mem_ctx, struct samr_domain_state);
405 if (!d_state) {
406 return NT_STATUS_NO_MEMORY;
409 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
411 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
412 d_state->builtin = true;
413 d_state->domain_name = "BUILTIN";
414 } else {
415 d_state->builtin = false;
416 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
419 ret = gendb_search(c_state->sam_ctx,
420 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
421 "(objectSid=%s)",
422 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
424 if (ret == 0) {
425 talloc_free(d_state);
426 return NT_STATUS_NO_SUCH_DOMAIN;
427 } else if (ret > 1) {
428 talloc_free(d_state);
429 return NT_STATUS_INTERNAL_DB_CORRUPTION;
430 } else if (ret == -1) {
431 talloc_free(d_state);
432 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
433 return NT_STATUS_INTERNAL_DB_CORRUPTION;
436 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
437 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
438 d_state->connect_state = talloc_reference(d_state, c_state);
439 d_state->sam_ctx = c_state->sam_ctx;
440 d_state->access_mask = r->in.access_mask;
442 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
444 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
445 if (!h_domain) {
446 talloc_free(d_state);
447 return NT_STATUS_NO_MEMORY;
450 h_domain->data = talloc_steal(h_domain, d_state);
452 *r->out.domain_handle = h_domain->wire_handle;
454 return NT_STATUS_OK;
458 return DomInfo1
460 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
461 TALLOC_CTX *mem_ctx,
462 struct ldb_message **dom_msgs,
463 struct samr_DomInfo1 *info)
465 info->min_password_length =
466 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
467 info->password_history_length =
468 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
469 info->password_properties =
470 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
471 info->max_password_age =
472 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
473 info->min_password_age =
474 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
476 return NT_STATUS_OK;
480 return DomInfo2
482 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
483 TALLOC_CTX *mem_ctx,
484 struct ldb_message **dom_msgs,
485 struct samr_DomGeneralInformation *info)
487 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
488 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
489 "domainReplica",
490 "");
492 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
493 0x8000000000000000LL);
495 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
496 "oEMInformation",
497 "");
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 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx,
522 state->domain_dn,
523 "(objectClass=user)");
524 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx,
525 state->domain_dn,
526 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
527 GTYPE_SECURITY_UNIVERSAL_GROUP,
528 GTYPE_SECURITY_GLOBAL_GROUP);
529 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx,
530 state->domain_dn,
531 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
532 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
533 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
535 return NT_STATUS_OK;
539 return DomInfo3
541 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
542 TALLOC_CTX *mem_ctx,
543 struct ldb_message **dom_msgs,
544 struct samr_DomInfo3 *info)
546 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
547 0x8000000000000000LL);
549 return NT_STATUS_OK;
553 return DomInfo4
555 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
556 TALLOC_CTX *mem_ctx,
557 struct ldb_message **dom_msgs,
558 struct samr_DomOEMInformation *info)
560 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
561 "oEMInformation",
562 "");
564 return NT_STATUS_OK;
568 return DomInfo5
570 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
571 TALLOC_CTX *mem_ctx,
572 struct ldb_message **dom_msgs,
573 struct samr_DomInfo5 *info)
575 info->domain_name.string = state->domain_name;
577 return NT_STATUS_OK;
581 return DomInfo6
583 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
584 TALLOC_CTX *mem_ctx,
585 struct ldb_message **dom_msgs,
586 struct samr_DomInfo6 *info)
588 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
589 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
590 "domainReplica",
591 "");
593 return NT_STATUS_OK;
597 return DomInfo7
599 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
600 TALLOC_CTX *mem_ctx,
601 struct ldb_message **dom_msgs,
602 struct samr_DomInfo7 *info)
605 switch (state->role) {
606 case ROLE_DOMAIN_CONTROLLER:
607 /* This pulls the NetBIOS name from the
608 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
609 string */
610 if (samdb_is_pdc(state->sam_ctx)) {
611 info->role = SAMR_ROLE_DOMAIN_PDC;
612 } else {
613 info->role = SAMR_ROLE_DOMAIN_BDC;
615 break;
616 case ROLE_DOMAIN_MEMBER:
617 info->role = SAMR_ROLE_DOMAIN_MEMBER;
618 break;
619 case ROLE_STANDALONE:
620 info->role = SAMR_ROLE_STANDALONE;
621 break;
624 return NT_STATUS_OK;
628 return DomInfo8
630 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
631 TALLOC_CTX *mem_ctx,
632 struct ldb_message **dom_msgs,
633 struct samr_DomInfo8 *info)
635 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
636 time(NULL));
638 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
639 0x0LL);
641 return NT_STATUS_OK;
645 return DomInfo9
647 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
648 TALLOC_CTX *mem_ctx,
649 struct ldb_message **dom_msgs,
650 struct samr_DomInfo9 *info)
652 info->domain_server_state = DOMAIN_SERVER_ENABLED;
654 return NT_STATUS_OK;
658 return DomInfo11
660 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
661 TALLOC_CTX *mem_ctx,
662 struct ldb_message **dom_msgs,
663 struct samr_DomGeneralInformation2 *info)
665 NTSTATUS status;
666 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
667 if (!NT_STATUS_IS_OK(status)) {
668 return status;
671 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
672 -18000000000LL);
673 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
674 -18000000000LL);
675 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
677 return NT_STATUS_OK;
681 return DomInfo12
683 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
684 TALLOC_CTX *mem_ctx,
685 struct ldb_message **dom_msgs,
686 struct samr_DomInfo12 *info)
688 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
689 -18000000000LL);
690 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
691 -18000000000LL);
692 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
694 return NT_STATUS_OK;
698 return DomInfo13
700 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
701 TALLOC_CTX *mem_ctx,
702 struct ldb_message **dom_msgs,
703 struct samr_DomInfo13 *info)
705 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
706 time(NULL));
708 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
709 0x0LL);
711 info->modified_count_at_last_promotion = 0;
713 return NT_STATUS_OK;
717 samr_QueryDomainInfo
719 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
720 TALLOC_CTX *mem_ctx,
721 struct samr_QueryDomainInfo *r)
723 struct dcesrv_handle *h;
724 struct samr_domain_state *d_state;
725 union samr_DomainInfo *info;
727 struct ldb_message **dom_msgs;
728 const char * const *attrs = NULL;
730 *r->out.info = NULL;
732 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
734 d_state = h->data;
736 switch (r->in.level) {
737 case 1:
739 static const char * const attrs2[] = { "minPwdLength",
740 "pwdHistoryLength",
741 "pwdProperties",
742 "maxPwdAge",
743 "minPwdAge",
744 NULL };
745 attrs = attrs2;
746 break;
748 case 2:
750 static const char * const attrs2[] = {"forceLogoff",
751 "oEMInformation",
752 "modifiedCount",
753 "domainReplica",
754 NULL};
755 attrs = attrs2;
756 break;
758 case 3:
760 static const char * const attrs2[] = {"forceLogoff",
761 NULL};
762 attrs = attrs2;
763 break;
765 case 4:
767 static const char * const attrs2[] = {"oEMInformation",
768 NULL};
769 attrs = attrs2;
770 break;
772 case 5:
774 attrs = NULL;
775 break;
777 case 6:
779 static const char * const attrs2[] = { "domainReplica",
780 NULL };
781 attrs = attrs2;
782 break;
784 case 7:
786 attrs = NULL;
787 break;
789 case 8:
791 static const char * const attrs2[] = { "modifiedCount",
792 "creationTime",
793 NULL };
794 attrs = attrs2;
795 break;
797 case 9:
799 attrs = NULL;
800 break;
802 case 11:
804 static const char * const attrs2[] = { "oEMInformation",
805 "forceLogoff",
806 "modifiedCount",
807 "lockoutDuration",
808 "lockOutObservationWindow",
809 "lockoutThreshold",
810 NULL};
811 attrs = attrs2;
812 break;
814 case 12:
816 static const char * const attrs2[] = { "lockoutDuration",
817 "lockOutObservationWindow",
818 "lockoutThreshold",
819 NULL};
820 attrs = attrs2;
821 break;
823 case 13:
825 static const char * const attrs2[] = { "modifiedCount",
826 "creationTime",
827 NULL };
828 attrs = attrs2;
829 break;
831 default:
833 return NT_STATUS_INVALID_INFO_CLASS;
837 /* some levels don't need a search */
838 if (attrs) {
839 int ret;
840 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
841 d_state->domain_dn, &dom_msgs, attrs);
842 if (ret == 0) {
843 return NT_STATUS_NO_SUCH_DOMAIN;
845 if (ret != 1) {
846 return NT_STATUS_INTERNAL_DB_CORRUPTION;
850 /* allocate the info structure */
851 info = talloc_zero(mem_ctx, union samr_DomainInfo);
852 if (info == NULL) {
853 return NT_STATUS_NO_MEMORY;
856 *r->out.info = info;
858 switch (r->in.level) {
859 case 1:
860 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
861 &info->info1);
862 case 2:
863 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
864 &info->general);
865 case 3:
866 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
867 &info->info3);
868 case 4:
869 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
870 &info->oem);
871 case 5:
872 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
873 &info->info5);
874 case 6:
875 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
876 &info->info6);
877 case 7:
878 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
879 &info->info7);
880 case 8:
881 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
882 &info->info8);
883 case 9:
884 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
885 &info->info9);
886 case 11:
887 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
888 &info->general2);
889 case 12:
890 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
891 &info->info12);
892 case 13:
893 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
894 &info->info13);
895 default:
896 return NT_STATUS_INVALID_INFO_CLASS;
902 samr_SetDomainInfo
904 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
905 struct samr_SetDomainInfo *r)
907 struct dcesrv_handle *h;
908 struct samr_domain_state *d_state;
909 struct ldb_message *msg;
910 int ret;
911 struct ldb_context *sam_ctx;
913 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
915 d_state = h->data;
916 sam_ctx = d_state->sam_ctx;
918 msg = ldb_msg_new(mem_ctx);
919 if (msg == NULL) {
920 return NT_STATUS_NO_MEMORY;
923 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
924 if (!msg->dn) {
925 return NT_STATUS_NO_MEMORY;
928 switch (r->in.level) {
929 case 1:
930 SET_UINT (msg, info1.min_password_length, "minPwdLength");
931 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
932 SET_UINT (msg, info1.password_properties, "pwdProperties");
933 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
934 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
935 break;
936 case 3:
937 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
938 break;
939 case 4:
940 SET_STRING(msg, oem.oem_information, "oEMInformation");
941 break;
943 case 6:
944 case 7:
945 case 9:
946 /* No op, we don't know where to set these */
947 return NT_STATUS_OK;
949 case 12:
951 * It is not possible to set lockout_duration < lockout_window.
952 * (The test is the other way around since the negative numbers
953 * are stored...)
955 * TODO:
956 * This check should be moved to the backend, i.e. to some
957 * ldb module under dsdb/samdb/ldb_modules/ .
959 * This constraint is documented here for the samr rpc service:
960 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
961 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
963 * And here for the ldap backend:
964 * MS-ADTS 3.1.1.5.3.2 Constraints
965 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
967 if (r->in.info->info12.lockout_duration >
968 r->in.info->info12.lockout_window)
970 return NT_STATUS_INVALID_PARAMETER;
972 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
973 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
974 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
975 break;
977 default:
978 /* many info classes are not valid for SetDomainInfo */
979 return NT_STATUS_INVALID_INFO_CLASS;
982 /* modify the samdb record */
983 ret = ldb_modify(sam_ctx, msg);
984 if (ret != LDB_SUCCESS) {
985 DEBUG(1,("Failed to modify record %s: %s\n",
986 ldb_dn_get_linearized(d_state->domain_dn),
987 ldb_errstring(sam_ctx)));
989 /* we really need samdb.c to return NTSTATUS */
990 return NT_STATUS_UNSUCCESSFUL;
993 return NT_STATUS_OK;
997 samr_CreateDomainGroup
999 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1000 struct samr_CreateDomainGroup *r)
1002 NTSTATUS status;
1003 struct samr_domain_state *d_state;
1004 struct samr_account_state *a_state;
1005 struct dcesrv_handle *h;
1006 const char *groupname;
1007 struct dom_sid *group_sid;
1008 struct ldb_dn *group_dn;
1009 struct dcesrv_handle *g_handle;
1011 ZERO_STRUCTP(r->out.group_handle);
1012 *r->out.rid = 0;
1014 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1016 d_state = h->data;
1018 if (d_state->builtin) {
1019 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1020 return NT_STATUS_ACCESS_DENIED;
1023 groupname = r->in.name->string;
1025 if (groupname == NULL) {
1026 return NT_STATUS_INVALID_PARAMETER;
1029 status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 return status;
1034 a_state = talloc(mem_ctx, struct samr_account_state);
1035 if (!a_state) {
1036 return NT_STATUS_NO_MEMORY;
1038 a_state->sam_ctx = d_state->sam_ctx;
1039 a_state->access_mask = r->in.access_mask;
1040 a_state->domain_state = talloc_reference(a_state, d_state);
1041 a_state->account_dn = talloc_steal(a_state, group_dn);
1043 a_state->account_name = talloc_steal(a_state, groupname);
1045 /* create the policy handle */
1046 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1047 if (!g_handle) {
1048 return NT_STATUS_NO_MEMORY;
1051 g_handle->data = talloc_steal(g_handle, a_state);
1053 *r->out.group_handle = g_handle->wire_handle;
1054 *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1056 return NT_STATUS_OK;
1061 comparison function for sorting SamEntry array
1063 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1065 return e1->idx - e2->idx;
1069 samr_EnumDomainGroups
1071 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1072 struct samr_EnumDomainGroups *r)
1074 struct dcesrv_handle *h;
1075 struct samr_domain_state *d_state;
1076 struct ldb_message **res;
1077 int i, ldb_cnt;
1078 uint32_t first, count;
1079 struct samr_SamEntry *entries;
1080 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1081 struct samr_SamArray *sam;
1083 *r->out.resume_handle = 0;
1084 *r->out.sam = NULL;
1085 *r->out.num_entries = 0;
1087 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1089 d_state = h->data;
1091 /* search for all domain groups in this domain. This could possibly be
1092 cached and resumed based on resume_key */
1093 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1094 d_state->domain_dn, &res, attrs,
1095 d_state->domain_sid,
1096 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1097 GTYPE_SECURITY_UNIVERSAL_GROUP,
1098 GTYPE_SECURITY_GLOBAL_GROUP);
1099 if (ldb_cnt < 0) {
1100 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1103 /* convert to SamEntry format */
1104 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1105 if (!entries) {
1106 return NT_STATUS_NO_MEMORY;
1109 count = 0;
1111 for (i=0;i<ldb_cnt;i++) {
1112 struct dom_sid *group_sid;
1114 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1115 "objectSid");
1116 if (group_sid == NULL) {
1117 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1120 entries[count].idx =
1121 group_sid->sub_auths[group_sid->num_auths-1];
1122 entries[count].name.string =
1123 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1124 count += 1;
1127 /* sort the results by rid */
1128 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1130 /* find the first entry to return */
1131 for (first=0;
1132 first<count && entries[first].idx <= *r->in.resume_handle;
1133 first++) ;
1135 /* return the rest, limit by max_size. Note that we
1136 use the w2k3 element size value of 54 */
1137 *r->out.num_entries = count - first;
1138 *r->out.num_entries = MIN(*r->out.num_entries,
1139 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1141 sam = talloc(mem_ctx, struct samr_SamArray);
1142 if (!sam) {
1143 return NT_STATUS_NO_MEMORY;
1146 sam->entries = entries+first;
1147 sam->count = *r->out.num_entries;
1149 *r->out.sam = sam;
1151 if (first == count) {
1152 return NT_STATUS_OK;
1155 if (*r->out.num_entries < count - first) {
1156 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1157 return STATUS_MORE_ENTRIES;
1160 return NT_STATUS_OK;
1165 samr_CreateUser2
1167 This call uses transactions to ensure we don't get a new conflicting
1168 user while we are processing this, and to ensure the user either
1169 completly exists, or does not.
1171 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1172 struct samr_CreateUser2 *r)
1174 NTSTATUS status;
1175 struct samr_domain_state *d_state;
1176 struct samr_account_state *a_state;
1177 struct dcesrv_handle *h;
1178 struct ldb_dn *dn;
1179 struct dom_sid *sid;
1180 struct dcesrv_handle *u_handle;
1181 const char *account_name;
1183 ZERO_STRUCTP(r->out.user_handle);
1184 *r->out.access_granted = 0;
1185 *r->out.rid = 0;
1187 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1189 d_state = h->data;
1191 if (d_state->builtin) {
1192 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1193 return NT_STATUS_ACCESS_DENIED;
1194 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1195 /* Domain trust accounts must be created by the LSA calls */
1196 return NT_STATUS_ACCESS_DENIED;
1198 account_name = r->in.account_name->string;
1200 if (account_name == NULL) {
1201 return NT_STATUS_INVALID_PARAMETER;
1204 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, &sid, &dn);
1205 if (!NT_STATUS_IS_OK(status)) {
1206 return status;
1208 a_state = talloc(mem_ctx, struct samr_account_state);
1209 if (!a_state) {
1210 ldb_transaction_cancel(d_state->sam_ctx);
1211 return NT_STATUS_NO_MEMORY;
1213 a_state->sam_ctx = d_state->sam_ctx;
1214 a_state->access_mask = r->in.access_mask;
1215 a_state->domain_state = talloc_reference(a_state, d_state);
1216 a_state->account_dn = talloc_steal(a_state, dn);
1218 a_state->account_name = talloc_steal(a_state, account_name);
1219 if (!a_state->account_name) {
1220 return NT_STATUS_NO_MEMORY;
1223 /* create the policy handle */
1224 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1225 if (!u_handle) {
1226 return NT_STATUS_NO_MEMORY;
1229 u_handle->data = talloc_steal(u_handle, a_state);
1231 *r->out.user_handle = u_handle->wire_handle;
1232 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1234 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1236 return NT_STATUS_OK;
1241 samr_CreateUser
1243 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1244 struct samr_CreateUser *r)
1246 struct samr_CreateUser2 r2;
1247 uint32_t access_granted = 0;
1250 /* a simple wrapper around samr_CreateUser2 works nicely */
1251 r2.in.domain_handle = r->in.domain_handle;
1252 r2.in.account_name = r->in.account_name;
1253 r2.in.acct_flags = ACB_NORMAL;
1254 r2.in.access_mask = r->in.access_mask;
1255 r2.out.user_handle = r->out.user_handle;
1256 r2.out.access_granted = &access_granted;
1257 r2.out.rid = r->out.rid;
1259 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1263 samr_EnumDomainUsers
1265 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1266 struct samr_EnumDomainUsers *r)
1268 struct dcesrv_handle *h;
1269 struct samr_domain_state *d_state;
1270 struct ldb_message **res;
1271 int i, ldb_cnt;
1272 uint32_t first, count;
1273 struct samr_SamEntry *entries;
1274 const char * const attrs[] = { "objectSid", "sAMAccountName",
1275 "userAccountControl", NULL };
1276 struct samr_SamArray *sam;
1278 *r->out.resume_handle = 0;
1279 *r->out.sam = NULL;
1280 *r->out.num_entries = 0;
1282 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1284 d_state = h->data;
1286 /* search for all domain users in this domain. This could possibly be
1287 cached and resumed on resume_key */
1288 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1289 d_state->domain_dn,
1290 &res, attrs,
1291 d_state->domain_sid,
1292 "(objectClass=user)");
1293 if (ldb_cnt < 0) {
1294 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1297 /* convert to SamEntry format */
1298 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1299 if (!entries) {
1300 return NT_STATUS_NO_MEMORY;
1303 count = 0;
1305 for (i=0;i<ldb_cnt;i++) {
1306 /* Check if a mask has been requested */
1307 if (r->in.acct_flags
1308 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
1309 res[i], d_state->domain_dn) & r->in.acct_flags) == 0)) {
1310 continue;
1312 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1313 "objectSid", 0);
1314 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1315 "sAMAccountName", "");
1316 count += 1;
1319 /* sort the results by rid */
1320 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1322 /* find the first entry to return */
1323 for (first=0;
1324 first<count && entries[first].idx <= *r->in.resume_handle;
1325 first++) ;
1327 /* return the rest, limit by max_size. Note that we
1328 use the w2k3 element size value of 54 */
1329 *r->out.num_entries = count - first;
1330 *r->out.num_entries = MIN(*r->out.num_entries,
1331 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1333 sam = talloc(mem_ctx, struct samr_SamArray);
1334 if (!sam) {
1335 return NT_STATUS_NO_MEMORY;
1338 sam->entries = entries+first;
1339 sam->count = *r->out.num_entries;
1341 *r->out.sam = sam;
1343 if (first == count) {
1344 return NT_STATUS_OK;
1347 if (*r->out.num_entries < count - first) {
1348 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1349 return STATUS_MORE_ENTRIES;
1352 return NT_STATUS_OK;
1357 samr_CreateDomAlias
1359 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1360 struct samr_CreateDomAlias *r)
1362 struct samr_domain_state *d_state;
1363 struct samr_account_state *a_state;
1364 struct dcesrv_handle *h;
1365 const char *alias_name;
1366 struct dom_sid *sid;
1367 struct dcesrv_handle *a_handle;
1368 struct ldb_dn *dn;
1369 NTSTATUS status;
1371 ZERO_STRUCTP(r->out.alias_handle);
1372 *r->out.rid = 0;
1374 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1376 d_state = h->data;
1378 if (d_state->builtin) {
1379 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1380 return NT_STATUS_ACCESS_DENIED;
1383 alias_name = r->in.alias_name->string;
1385 if (alias_name == NULL) {
1386 return NT_STATUS_INVALID_PARAMETER;
1389 status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1390 if (!NT_STATUS_IS_OK(status)) {
1391 return status;
1394 a_state = talloc(mem_ctx, struct samr_account_state);
1395 if (!a_state) {
1396 return NT_STATUS_NO_MEMORY;
1399 a_state->sam_ctx = d_state->sam_ctx;
1400 a_state->access_mask = r->in.access_mask;
1401 a_state->domain_state = talloc_reference(a_state, d_state);
1402 a_state->account_dn = talloc_steal(a_state, dn);
1404 a_state->account_name = talloc_steal(a_state, alias_name);
1406 /* create the policy handle */
1407 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1408 if (a_handle == NULL)
1409 return NT_STATUS_NO_MEMORY;
1411 a_handle->data = talloc_steal(a_handle, a_state);
1413 *r->out.alias_handle = a_handle->wire_handle;
1415 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1417 return NT_STATUS_OK;
1422 samr_EnumDomainAliases
1424 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1425 struct samr_EnumDomainAliases *r)
1427 struct dcesrv_handle *h;
1428 struct samr_domain_state *d_state;
1429 struct ldb_message **res;
1430 int i, ldb_cnt;
1431 uint32_t first, count;
1432 struct samr_SamEntry *entries;
1433 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1434 struct samr_SamArray *sam;
1436 *r->out.resume_handle = 0;
1437 *r->out.sam = NULL;
1438 *r->out.num_entries = 0;
1440 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1442 d_state = h->data;
1444 /* search for all domain aliases in this domain. This could possibly be
1445 cached and resumed based on resume_key */
1446 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1447 &res, attrs,
1448 d_state->domain_sid,
1449 "(&(|(grouptype=%d)(grouptype=%d)))"
1450 "(objectclass=group))",
1451 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1452 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1453 if (ldb_cnt < 0) {
1454 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1457 /* convert to SamEntry format */
1458 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1459 if (!entries) {
1460 return NT_STATUS_NO_MEMORY;
1463 count = 0;
1465 for (i=0;i<ldb_cnt;i++) {
1466 struct dom_sid *alias_sid;
1468 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1469 "objectSid");
1471 if (alias_sid == NULL) {
1472 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1475 entries[count].idx =
1476 alias_sid->sub_auths[alias_sid->num_auths-1];
1477 entries[count].name.string =
1478 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1479 count += 1;
1482 /* sort the results by rid */
1483 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1485 /* find the first entry to return */
1486 for (first=0;
1487 first<count && entries[first].idx <= *r->in.resume_handle;
1488 first++) ;
1490 /* return the rest, limit by max_size. Note that we
1491 use the w2k3 element size value of 54 */
1492 *r->out.num_entries = count - first;
1493 *r->out.num_entries = MIN(*r->out.num_entries,
1494 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1496 sam = talloc(mem_ctx, struct samr_SamArray);
1497 if (!sam) {
1498 return NT_STATUS_NO_MEMORY;
1501 sam->entries = entries+first;
1502 sam->count = *r->out.num_entries;
1504 *r->out.sam = sam;
1506 if (first == count) {
1507 return NT_STATUS_OK;
1510 if (*r->out.num_entries < count - first) {
1511 *r->out.resume_handle =
1512 entries[first+*r->out.num_entries-1].idx;
1513 return STATUS_MORE_ENTRIES;
1516 return NT_STATUS_OK;
1521 samr_GetAliasMembership
1523 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1524 struct samr_GetAliasMembership *r)
1526 struct dcesrv_handle *h;
1527 struct samr_domain_state *d_state;
1528 const char *filter;
1529 const char * const attrs[] = { "objectSid", NULL };
1530 struct ldb_message **res;
1531 uint32_t i;
1532 int count = 0;
1534 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1536 d_state = h->data;
1538 filter = talloc_asprintf(mem_ctx,
1539 "(&(|(grouptype=%d)(grouptype=%d))"
1540 "(objectclass=group)(|",
1541 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1542 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1543 if (filter == NULL) {
1544 return NT_STATUS_NO_MEMORY;
1547 for (i=0; i<r->in.sids->num_sids; i++) {
1548 const char *memberdn;
1550 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1551 "distinguishedName",
1552 "(objectSid=%s)",
1553 ldap_encode_ndr_dom_sid(mem_ctx,
1554 r->in.sids->sids[i].sid));
1555 if (memberdn == NULL) {
1556 continue;
1559 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1560 memberdn);
1561 if (filter == NULL) {
1562 return NT_STATUS_NO_MEMORY;
1566 /* Find out if we had at least one valid member SID passed - otherwise
1567 * just skip the search. */
1568 if (strstr(filter, "member") != NULL) {
1569 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1570 &res, attrs, d_state->domain_sid,
1571 "%s))", filter);
1572 if (count < 0) {
1573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1577 r->out.rids->count = 0;
1578 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1579 if (r->out.rids->ids == NULL)
1580 return NT_STATUS_NO_MEMORY;
1582 for (i=0; i<count; i++) {
1583 struct dom_sid *alias_sid;
1585 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1586 if (alias_sid == NULL) {
1587 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1590 r->out.rids->ids[r->out.rids->count] =
1591 alias_sid->sub_auths[alias_sid->num_auths-1];
1592 r->out.rids->count += 1;
1595 return NT_STATUS_OK;
1600 samr_LookupNames
1602 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1603 struct samr_LookupNames *r)
1605 struct dcesrv_handle *h;
1606 struct samr_domain_state *d_state;
1607 uint32_t i, num_mapped;
1608 NTSTATUS status = NT_STATUS_OK;
1609 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1610 int count;
1612 ZERO_STRUCTP(r->out.rids);
1613 ZERO_STRUCTP(r->out.types);
1615 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1617 d_state = h->data;
1619 if (r->in.num_names == 0) {
1620 return NT_STATUS_OK;
1623 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1624 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1625 if (!r->out.rids->ids || !r->out.types->ids) {
1626 return NT_STATUS_NO_MEMORY;
1628 r->out.rids->count = r->in.num_names;
1629 r->out.types->count = r->in.num_names;
1631 num_mapped = 0;
1633 for (i=0;i<r->in.num_names;i++) {
1634 struct ldb_message **res;
1635 struct dom_sid *sid;
1636 uint32_t atype, rtype;
1638 r->out.rids->ids[i] = 0;
1639 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1641 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1642 "sAMAccountName=%s",
1643 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1644 if (count != 1) {
1645 status = STATUS_SOME_UNMAPPED;
1646 continue;
1649 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1650 if (sid == NULL) {
1651 status = STATUS_SOME_UNMAPPED;
1652 continue;
1655 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1656 if (atype == 0) {
1657 status = STATUS_SOME_UNMAPPED;
1658 continue;
1661 rtype = ds_atype_map(atype);
1663 if (rtype == SID_NAME_UNKNOWN) {
1664 status = STATUS_SOME_UNMAPPED;
1665 continue;
1668 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1669 r->out.types->ids[i] = rtype;
1670 num_mapped++;
1673 if (num_mapped == 0) {
1674 return NT_STATUS_NONE_MAPPED;
1676 return status;
1681 samr_LookupRids
1683 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1684 struct samr_LookupRids *r)
1686 NTSTATUS status;
1687 struct dcesrv_handle *h;
1688 struct samr_domain_state *d_state;
1689 const char **names;
1690 struct lsa_String *lsa_names;
1691 enum lsa_SidType *ids;
1693 ZERO_STRUCTP(r->out.names);
1694 ZERO_STRUCTP(r->out.types);
1696 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1698 d_state = h->data;
1700 if (r->in.num_rids == 0)
1701 return NT_STATUS_OK;
1703 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1704 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1705 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1707 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1708 return NT_STATUS_NO_MEMORY;
1710 r->out.names->names = lsa_names;
1711 r->out.names->count = r->in.num_rids;
1713 r->out.types->ids = (uint32_t *) ids;
1714 r->out.types->count = r->in.num_rids;
1716 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1717 r->in.num_rids, r->in.rids, names, ids);
1718 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1719 uint32_t i;
1720 for (i = 0; i < r->in.num_rids; i++) {
1721 lsa_names[i].string = names[i];
1724 return status;
1729 samr_OpenGroup
1731 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1732 struct samr_OpenGroup *r)
1734 struct samr_domain_state *d_state;
1735 struct samr_account_state *a_state;
1736 struct dcesrv_handle *h;
1737 const char *groupname;
1738 struct dom_sid *sid;
1739 struct ldb_message **msgs;
1740 struct dcesrv_handle *g_handle;
1741 const char * const attrs[2] = { "sAMAccountName", NULL };
1742 int ret;
1744 ZERO_STRUCTP(r->out.group_handle);
1746 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1748 d_state = h->data;
1750 /* form the group SID */
1751 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1752 if (!sid) {
1753 return NT_STATUS_NO_MEMORY;
1756 /* search for the group record */
1757 ret = gendb_search(d_state->sam_ctx,
1758 mem_ctx, d_state->domain_dn, &msgs, attrs,
1759 "(&(objectSid=%s)(objectClass=group)"
1760 "(|(groupType=%d)(groupType=%d)))",
1761 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1762 GTYPE_SECURITY_UNIVERSAL_GROUP,
1763 GTYPE_SECURITY_GLOBAL_GROUP);
1764 if (ret == 0) {
1765 return NT_STATUS_NO_SUCH_GROUP;
1767 if (ret != 1) {
1768 DEBUG(0,("Found %d records matching sid %s\n",
1769 ret, dom_sid_string(mem_ctx, sid)));
1770 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1773 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1774 if (groupname == NULL) {
1775 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1776 dom_sid_string(mem_ctx, sid)));
1777 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1780 a_state = talloc(mem_ctx, struct samr_account_state);
1781 if (!a_state) {
1782 return NT_STATUS_NO_MEMORY;
1784 a_state->sam_ctx = d_state->sam_ctx;
1785 a_state->access_mask = r->in.access_mask;
1786 a_state->domain_state = talloc_reference(a_state, d_state);
1787 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1788 a_state->account_sid = talloc_steal(a_state, sid);
1789 a_state->account_name = talloc_strdup(a_state, groupname);
1790 if (!a_state->account_name) {
1791 return NT_STATUS_NO_MEMORY;
1794 /* create the policy handle */
1795 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1796 if (!g_handle) {
1797 return NT_STATUS_NO_MEMORY;
1800 g_handle->data = talloc_steal(g_handle, a_state);
1802 *r->out.group_handle = g_handle->wire_handle;
1804 return NT_STATUS_OK;
1808 samr_QueryGroupInfo
1810 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1811 struct samr_QueryGroupInfo *r)
1813 struct dcesrv_handle *h;
1814 struct samr_account_state *a_state;
1815 struct ldb_message *msg, **res;
1816 const char * const attrs[4] = { "sAMAccountName", "description",
1817 "numMembers", NULL };
1818 int ret;
1819 union samr_GroupInfo *info;
1821 *r->out.info = NULL;
1823 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1825 a_state = h->data;
1827 /* pull all the group attributes */
1828 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1829 a_state->account_dn, &res, attrs);
1830 if (ret == 0) {
1831 return NT_STATUS_NO_SUCH_GROUP;
1833 if (ret != 1) {
1834 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1836 msg = res[0];
1838 /* allocate the info structure */
1839 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1840 if (info == NULL) {
1841 return NT_STATUS_NO_MEMORY;
1844 /* Fill in the level */
1845 switch (r->in.level) {
1846 case GROUPINFOALL:
1847 QUERY_STRING(msg, all.name, "sAMAccountName");
1848 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1849 QUERY_UINT (msg, all.num_members, "numMembers")
1850 QUERY_STRING(msg, all.description, "description");
1851 break;
1852 case GROUPINFONAME:
1853 QUERY_STRING(msg, name, "sAMAccountName");
1854 break;
1855 case GROUPINFOATTRIBUTES:
1856 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1857 break;
1858 case GROUPINFODESCRIPTION:
1859 QUERY_STRING(msg, description, "description");
1860 break;
1861 case GROUPINFOALL2:
1862 QUERY_STRING(msg, all2.name, "sAMAccountName");
1863 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1864 QUERY_UINT (msg, all2.num_members, "numMembers")
1865 QUERY_STRING(msg, all2.description, "description");
1866 break;
1867 default:
1868 talloc_free(info);
1869 return NT_STATUS_INVALID_INFO_CLASS;
1872 *r->out.info = info;
1874 return NT_STATUS_OK;
1879 samr_SetGroupInfo
1881 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1882 struct samr_SetGroupInfo *r)
1884 struct dcesrv_handle *h;
1885 struct samr_account_state *g_state;
1886 struct ldb_message *msg;
1887 struct ldb_context *sam_ctx;
1888 int ret;
1890 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1892 g_state = h->data;
1893 sam_ctx = g_state->sam_ctx;
1895 msg = ldb_msg_new(mem_ctx);
1896 if (msg == NULL) {
1897 return NT_STATUS_NO_MEMORY;
1900 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1901 if (!msg->dn) {
1902 return NT_STATUS_NO_MEMORY;
1905 switch (r->in.level) {
1906 case GROUPINFODESCRIPTION:
1907 SET_STRING(msg, description, "description");
1908 break;
1909 case GROUPINFONAME:
1910 /* On W2k3 this does not change the name, it changes the
1911 * sAMAccountName attribute */
1912 SET_STRING(msg, name, "sAMAccountName");
1913 break;
1914 case GROUPINFOATTRIBUTES:
1915 /* This does not do anything obviously visible in W2k3 LDAP */
1916 return NT_STATUS_OK;
1917 default:
1918 return NT_STATUS_INVALID_INFO_CLASS;
1921 /* modify the samdb record */
1922 ret = ldb_modify(g_state->sam_ctx, msg);
1923 if (ret != LDB_SUCCESS) {
1924 /* we really need samdb.c to return NTSTATUS */
1925 return NT_STATUS_UNSUCCESSFUL;
1928 return NT_STATUS_OK;
1933 samr_AddGroupMember
1935 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1936 struct samr_AddGroupMember *r)
1938 struct dcesrv_handle *h;
1939 struct samr_account_state *a_state;
1940 struct samr_domain_state *d_state;
1941 struct ldb_message *mod;
1942 struct dom_sid *membersid;
1943 const char *memberdn;
1944 struct ldb_result *res;
1945 const char * const attrs[] = { NULL };
1946 int ret;
1948 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1950 a_state = h->data;
1951 d_state = a_state->domain_state;
1953 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1954 if (membersid == NULL) {
1955 return NT_STATUS_NO_MEMORY;
1958 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1959 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1960 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1961 "(objectSid=%s)",
1962 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1964 if (ret != LDB_SUCCESS) {
1965 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1968 if (res->count == 0) {
1969 return NT_STATUS_NO_SUCH_USER;
1972 if (res->count > 1) {
1973 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1976 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1978 if (memberdn == NULL)
1979 return NT_STATUS_NO_MEMORY;
1981 mod = ldb_msg_new(mem_ctx);
1982 if (mod == NULL) {
1983 return NT_STATUS_NO_MEMORY;
1986 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1988 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1989 memberdn);
1990 if (ret != LDB_SUCCESS) {
1991 return NT_STATUS_UNSUCCESSFUL;
1994 ret = ldb_modify(a_state->sam_ctx, mod);
1995 switch (ret) {
1996 case LDB_SUCCESS:
1997 return NT_STATUS_OK;
1998 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1999 return NT_STATUS_MEMBER_IN_GROUP;
2000 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2001 return NT_STATUS_ACCESS_DENIED;
2002 default:
2003 return NT_STATUS_UNSUCCESSFUL;
2009 samr_DeleteDomainGroup
2011 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2012 struct samr_DeleteDomainGroup *r)
2014 struct dcesrv_handle *h;
2015 struct samr_account_state *a_state;
2016 int ret;
2018 *r->out.group_handle = *r->in.group_handle;
2020 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2022 a_state = h->data;
2024 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2025 if (ret != LDB_SUCCESS) {
2026 return NT_STATUS_UNSUCCESSFUL;
2029 talloc_free(h);
2030 ZERO_STRUCTP(r->out.group_handle);
2032 return NT_STATUS_OK;
2037 samr_DeleteGroupMember
2039 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2040 struct samr_DeleteGroupMember *r)
2042 struct dcesrv_handle *h;
2043 struct samr_account_state *a_state;
2044 struct samr_domain_state *d_state;
2045 struct ldb_message *mod;
2046 struct dom_sid *membersid;
2047 const char *memberdn;
2048 struct ldb_result *res;
2049 const char * const attrs[] = { NULL };
2050 int ret;
2052 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2054 a_state = h->data;
2055 d_state = a_state->domain_state;
2057 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2058 if (membersid == NULL) {
2059 return NT_STATUS_NO_MEMORY;
2062 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2063 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2064 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2065 "(objectSid=%s)",
2066 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2068 if (ret != LDB_SUCCESS) {
2069 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2072 if (res->count == 0) {
2073 return NT_STATUS_NO_SUCH_USER;
2076 if (res->count > 1) {
2077 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2080 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2082 if (memberdn == NULL)
2083 return NT_STATUS_NO_MEMORY;
2085 mod = ldb_msg_new(mem_ctx);
2086 if (mod == NULL) {
2087 return NT_STATUS_NO_MEMORY;
2090 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2092 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2093 memberdn);
2094 if (ret != LDB_SUCCESS) {
2095 return NT_STATUS_NO_MEMORY;
2098 ret = ldb_modify(a_state->sam_ctx, mod);
2099 switch (ret) {
2100 case LDB_SUCCESS:
2101 return NT_STATUS_OK;
2102 case LDB_ERR_UNWILLING_TO_PERFORM:
2103 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2104 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2105 return NT_STATUS_ACCESS_DENIED;
2106 default:
2107 return NT_STATUS_UNSUCCESSFUL;
2113 samr_QueryGroupMember
2115 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2116 struct samr_QueryGroupMember *r)
2118 struct dcesrv_handle *h;
2119 struct samr_account_state *a_state;
2120 struct samr_domain_state *d_state;
2121 struct samr_RidAttrArray *array;
2122 unsigned int i, num_members;
2123 struct dom_sid *members;
2124 NTSTATUS status;
2126 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2128 a_state = h->data;
2129 d_state = a_state->domain_state;
2131 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2132 a_state->account_dn, &members,
2133 &num_members);
2134 if (!NT_STATUS_IS_OK(status)) {
2135 return status;
2138 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2139 if (array == NULL) {
2140 return NT_STATUS_NO_MEMORY;
2143 if (num_members == 0) {
2144 *r->out.rids = array;
2146 return NT_STATUS_OK;
2149 array->rids = talloc_array(array, uint32_t, num_members);
2150 if (array->rids == NULL) {
2151 return NT_STATUS_NO_MEMORY;
2154 array->attributes = talloc_array(array, uint32_t, num_members);
2155 if (array->attributes == NULL) {
2156 return NT_STATUS_NO_MEMORY;
2159 array->count = 0;
2160 for (i=0; i<num_members; i++) {
2161 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2162 continue;
2165 status = dom_sid_split_rid(NULL, &members[i], NULL,
2166 &array->rids[array->count]);
2167 if (!NT_STATUS_IS_OK(status)) {
2168 return status;
2171 array->attributes[array->count] = SE_GROUP_MANDATORY |
2172 SE_GROUP_ENABLED_BY_DEFAULT |
2173 SE_GROUP_ENABLED;
2174 array->count++;
2177 *r->out.rids = array;
2179 return NT_STATUS_OK;
2184 samr_SetMemberAttributesOfGroup
2186 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2187 struct samr_SetMemberAttributesOfGroup *r)
2189 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2194 samr_OpenAlias
2196 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2197 struct samr_OpenAlias *r)
2199 struct samr_domain_state *d_state;
2200 struct samr_account_state *a_state;
2201 struct dcesrv_handle *h;
2202 const char *alias_name;
2203 struct dom_sid *sid;
2204 struct ldb_message **msgs;
2205 struct dcesrv_handle *g_handle;
2206 const char * const attrs[2] = { "sAMAccountName", NULL };
2207 int ret;
2209 ZERO_STRUCTP(r->out.alias_handle);
2211 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2213 d_state = h->data;
2215 /* form the alias SID */
2216 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2217 if (sid == NULL)
2218 return NT_STATUS_NO_MEMORY;
2220 /* search for the group record */
2221 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2222 "(&(objectSid=%s)(objectclass=group)"
2223 "(|(grouptype=%d)(grouptype=%d)))",
2224 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2225 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2226 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2227 if (ret == 0) {
2228 return NT_STATUS_NO_SUCH_ALIAS;
2230 if (ret != 1) {
2231 DEBUG(0,("Found %d records matching sid %s\n",
2232 ret, dom_sid_string(mem_ctx, sid)));
2233 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2236 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2237 if (alias_name == NULL) {
2238 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2239 dom_sid_string(mem_ctx, sid)));
2240 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2243 a_state = talloc(mem_ctx, struct samr_account_state);
2244 if (!a_state) {
2245 return NT_STATUS_NO_MEMORY;
2247 a_state->sam_ctx = d_state->sam_ctx;
2248 a_state->access_mask = r->in.access_mask;
2249 a_state->domain_state = talloc_reference(a_state, d_state);
2250 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2251 a_state->account_sid = talloc_steal(a_state, sid);
2252 a_state->account_name = talloc_strdup(a_state, alias_name);
2253 if (!a_state->account_name) {
2254 return NT_STATUS_NO_MEMORY;
2257 /* create the policy handle */
2258 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2259 if (!g_handle) {
2260 return NT_STATUS_NO_MEMORY;
2263 g_handle->data = talloc_steal(g_handle, a_state);
2265 *r->out.alias_handle = g_handle->wire_handle;
2267 return NT_STATUS_OK;
2272 samr_QueryAliasInfo
2274 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2275 struct samr_QueryAliasInfo *r)
2277 struct dcesrv_handle *h;
2278 struct samr_account_state *a_state;
2279 struct ldb_message *msg, **res;
2280 const char * const attrs[4] = { "sAMAccountName", "description",
2281 "numMembers", NULL };
2282 int ret;
2283 union samr_AliasInfo *info;
2285 *r->out.info = NULL;
2287 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2289 a_state = h->data;
2291 /* pull all the alias attributes */
2292 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2293 a_state->account_dn, &res, attrs);
2294 if (ret == 0) {
2295 return NT_STATUS_NO_SUCH_ALIAS;
2297 if (ret != 1) {
2298 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2300 msg = res[0];
2302 /* allocate the info structure */
2303 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2304 if (info == NULL) {
2305 return NT_STATUS_NO_MEMORY;
2308 switch(r->in.level) {
2309 case ALIASINFOALL:
2310 QUERY_STRING(msg, all.name, "sAMAccountName");
2311 QUERY_UINT (msg, all.num_members, "numMembers");
2312 QUERY_STRING(msg, all.description, "description");
2313 break;
2314 case ALIASINFONAME:
2315 QUERY_STRING(msg, name, "sAMAccountName");
2316 break;
2317 case ALIASINFODESCRIPTION:
2318 QUERY_STRING(msg, description, "description");
2319 break;
2320 default:
2321 talloc_free(info);
2322 return NT_STATUS_INVALID_INFO_CLASS;
2325 *r->out.info = info;
2327 return NT_STATUS_OK;
2332 samr_SetAliasInfo
2334 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2335 struct samr_SetAliasInfo *r)
2337 struct dcesrv_handle *h;
2338 struct samr_account_state *a_state;
2339 struct ldb_message *msg;
2340 struct ldb_context *sam_ctx;
2341 int ret;
2343 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2345 a_state = h->data;
2346 sam_ctx = a_state->sam_ctx;
2348 msg = ldb_msg_new(mem_ctx);
2349 if (msg == NULL) {
2350 return NT_STATUS_NO_MEMORY;
2353 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2354 if (!msg->dn) {
2355 return NT_STATUS_NO_MEMORY;
2358 switch (r->in.level) {
2359 case ALIASINFODESCRIPTION:
2360 SET_STRING(msg, description, "description");
2361 break;
2362 case ALIASINFONAME:
2363 /* On W2k3 this does not change the name, it changes the
2364 * sAMAccountName attribute */
2365 SET_STRING(msg, name, "sAMAccountName");
2366 break;
2367 default:
2368 return NT_STATUS_INVALID_INFO_CLASS;
2371 /* modify the samdb record */
2372 ret = ldb_modify(a_state->sam_ctx, msg);
2373 if (ret != LDB_SUCCESS) {
2374 /* we really need samdb.c to return NTSTATUS */
2375 return NT_STATUS_UNSUCCESSFUL;
2378 return NT_STATUS_OK;
2383 samr_DeleteDomAlias
2385 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2386 struct samr_DeleteDomAlias *r)
2388 struct dcesrv_handle *h;
2389 struct samr_account_state *a_state;
2390 int ret;
2392 *r->out.alias_handle = *r->in.alias_handle;
2394 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2396 a_state = h->data;
2398 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2399 if (ret != LDB_SUCCESS) {
2400 return NT_STATUS_UNSUCCESSFUL;
2403 talloc_free(h);
2404 ZERO_STRUCTP(r->out.alias_handle);
2406 return NT_STATUS_OK;
2411 samr_AddAliasMember
2413 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2414 struct samr_AddAliasMember *r)
2416 struct dcesrv_handle *h;
2417 struct samr_account_state *a_state;
2418 struct samr_domain_state *d_state;
2419 struct ldb_message *mod;
2420 struct ldb_message **msgs;
2421 const char * const attrs[] = { NULL };
2422 struct ldb_dn *memberdn = NULL;
2423 int ret;
2424 NTSTATUS status;
2426 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2428 a_state = h->data;
2429 d_state = a_state->domain_state;
2431 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2432 &msgs, attrs, "(objectsid=%s)",
2433 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2435 if (ret == 1) {
2436 memberdn = msgs[0]->dn;
2437 } else if (ret == 0) {
2438 status = samdb_create_foreign_security_principal(
2439 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2440 if (!NT_STATUS_IS_OK(status)) {
2441 return status;
2443 } else {
2444 DEBUG(0,("Found %d records matching sid %s\n",
2445 ret, dom_sid_string(mem_ctx, r->in.sid)));
2446 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2449 if (memberdn == NULL) {
2450 DEBUG(0, ("Could not find memberdn\n"));
2451 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2454 mod = ldb_msg_new(mem_ctx);
2455 if (mod == NULL) {
2456 return NT_STATUS_NO_MEMORY;
2459 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2461 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2462 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2463 if (ret != LDB_SUCCESS) {
2464 return NT_STATUS_UNSUCCESSFUL;
2467 ret = ldb_modify(a_state->sam_ctx, mod);
2468 switch (ret) {
2469 case LDB_SUCCESS:
2470 return NT_STATUS_OK;
2471 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2472 return NT_STATUS_MEMBER_IN_GROUP;
2473 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2474 return NT_STATUS_ACCESS_DENIED;
2475 default:
2476 return NT_STATUS_UNSUCCESSFUL;
2482 samr_DeleteAliasMember
2484 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2485 struct samr_DeleteAliasMember *r)
2487 struct dcesrv_handle *h;
2488 struct samr_account_state *a_state;
2489 struct samr_domain_state *d_state;
2490 struct ldb_message *mod;
2491 const char *memberdn;
2492 int ret;
2494 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2496 a_state = h->data;
2497 d_state = a_state->domain_state;
2499 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2500 "distinguishedName", "(objectSid=%s)",
2501 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2502 if (memberdn == NULL) {
2503 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2506 mod = ldb_msg_new(mem_ctx);
2507 if (mod == NULL) {
2508 return NT_STATUS_NO_MEMORY;
2511 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2513 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2514 memberdn);
2515 if (ret != LDB_SUCCESS) {
2516 return NT_STATUS_UNSUCCESSFUL;
2519 ret = ldb_modify(a_state->sam_ctx, mod);
2520 switch (ret) {
2521 case LDB_SUCCESS:
2522 return NT_STATUS_OK;
2523 case LDB_ERR_UNWILLING_TO_PERFORM:
2524 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2525 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2526 return NT_STATUS_ACCESS_DENIED;
2527 default:
2528 return NT_STATUS_UNSUCCESSFUL;
2534 samr_GetMembersInAlias
2536 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2537 struct samr_GetMembersInAlias *r)
2539 struct dcesrv_handle *h;
2540 struct samr_account_state *a_state;
2541 struct samr_domain_state *d_state;
2542 struct lsa_SidPtr *array;
2543 unsigned int i, num_members;
2544 struct dom_sid *members;
2545 NTSTATUS status;
2547 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2549 a_state = h->data;
2550 d_state = a_state->domain_state;
2552 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2553 a_state->account_dn, &members,
2554 &num_members);
2555 if (!NT_STATUS_IS_OK(status)) {
2556 return status;
2559 if (num_members == 0) {
2560 r->out.sids->sids = NULL;
2562 return NT_STATUS_OK;
2565 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2566 if (array == NULL) {
2567 return NT_STATUS_NO_MEMORY;
2570 for (i=0; i<num_members; i++) {
2571 array[i].sid = &members[i];
2574 r->out.sids->num_sids = num_members;
2575 r->out.sids->sids = array;
2577 return NT_STATUS_OK;
2581 samr_OpenUser
2583 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2584 struct samr_OpenUser *r)
2586 struct samr_domain_state *d_state;
2587 struct samr_account_state *a_state;
2588 struct dcesrv_handle *h;
2589 const char *account_name;
2590 struct dom_sid *sid;
2591 struct ldb_message **msgs;
2592 struct dcesrv_handle *u_handle;
2593 const char * const attrs[2] = { "sAMAccountName", NULL };
2594 int ret;
2596 ZERO_STRUCTP(r->out.user_handle);
2598 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2600 d_state = h->data;
2602 /* form the users SID */
2603 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2604 if (!sid) {
2605 return NT_STATUS_NO_MEMORY;
2608 /* search for the user record */
2609 ret = gendb_search(d_state->sam_ctx,
2610 mem_ctx, d_state->domain_dn, &msgs, attrs,
2611 "(&(objectSid=%s)(objectclass=user))",
2612 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2613 if (ret == 0) {
2614 return NT_STATUS_NO_SUCH_USER;
2616 if (ret != 1) {
2617 DEBUG(0,("Found %d records matching sid %s\n", ret,
2618 dom_sid_string(mem_ctx, sid)));
2619 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2622 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2623 if (account_name == NULL) {
2624 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2625 dom_sid_string(mem_ctx, sid)));
2626 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2629 a_state = talloc(mem_ctx, struct samr_account_state);
2630 if (!a_state) {
2631 return NT_STATUS_NO_MEMORY;
2633 a_state->sam_ctx = d_state->sam_ctx;
2634 a_state->access_mask = r->in.access_mask;
2635 a_state->domain_state = talloc_reference(a_state, d_state);
2636 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2637 a_state->account_sid = talloc_steal(a_state, sid);
2638 a_state->account_name = talloc_strdup(a_state, account_name);
2639 if (!a_state->account_name) {
2640 return NT_STATUS_NO_MEMORY;
2643 /* create the policy handle */
2644 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2645 if (!u_handle) {
2646 return NT_STATUS_NO_MEMORY;
2649 u_handle->data = talloc_steal(u_handle, a_state);
2651 *r->out.user_handle = u_handle->wire_handle;
2653 return NT_STATUS_OK;
2659 samr_DeleteUser
2661 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2662 struct samr_DeleteUser *r)
2664 struct dcesrv_handle *h;
2665 struct samr_account_state *a_state;
2666 int ret;
2668 *r->out.user_handle = *r->in.user_handle;
2670 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2672 a_state = h->data;
2674 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2675 if (ret != LDB_SUCCESS) {
2676 DEBUG(1, ("Failed to delete user: %s: %s\n",
2677 ldb_dn_get_linearized(a_state->account_dn),
2678 ldb_errstring(a_state->sam_ctx)));
2679 return NT_STATUS_UNSUCCESSFUL;
2682 talloc_free(h);
2683 ZERO_STRUCTP(r->out.user_handle);
2685 return NT_STATUS_OK;
2690 samr_QueryUserInfo
2692 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2693 struct samr_QueryUserInfo *r)
2695 struct dcesrv_handle *h;
2696 struct samr_account_state *a_state;
2697 struct ldb_message *msg, **res;
2698 int ret;
2699 struct ldb_context *sam_ctx;
2701 const char * const *attrs = NULL;
2702 union samr_UserInfo *info;
2704 *r->out.info = NULL;
2706 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2708 a_state = h->data;
2709 sam_ctx = a_state->sam_ctx;
2711 /* fill in the reply */
2712 switch (r->in.level) {
2713 case 1:
2715 static const char * const attrs2[] = {"sAMAccountName",
2716 "displayName",
2717 "primaryroupID",
2718 "description",
2719 "comment",
2720 NULL};
2721 attrs = attrs2;
2722 break;
2724 case 2:
2726 static const char * const attrs2[] = {"comment",
2727 "countryCode",
2728 "codePage",
2729 NULL};
2730 attrs = attrs2;
2731 break;
2733 case 3:
2735 static const char * const attrs2[] = {"sAMAccountName",
2736 "displayName",
2737 "objectSid",
2738 "primaryGroupID",
2739 "homeDirectory",
2740 "homeDrive",
2741 "scriptPath",
2742 "profilePath",
2743 "userWorkstations",
2744 "lastLogon",
2745 "lastLogoff",
2746 "pwdLastSet",
2747 "logonHours",
2748 "badPwdCount",
2749 "logonCount",
2750 "userAccountControl",
2751 NULL};
2752 attrs = attrs2;
2753 break;
2755 case 4:
2757 static const char * const attrs2[] = {"logonHours",
2758 NULL};
2759 attrs = attrs2;
2760 break;
2762 case 5:
2764 static const char * const attrs2[] = {"sAMAccountName",
2765 "displayName",
2766 "objectSid",
2767 "primaryGroupID",
2768 "homeDirectory",
2769 "homeDrive",
2770 "scriptPath",
2771 "profilePath",
2772 "description",
2773 "userWorkstations",
2774 "lastLogon",
2775 "lastLogoff",
2776 "logonHours",
2777 "badPwdCount",
2778 "logonCount",
2779 "pwdLastSet",
2780 "accountExpires",
2781 "userAccountControl",
2782 NULL};
2783 attrs = attrs2;
2784 break;
2786 case 6:
2788 static const char * const attrs2[] = {"sAMAccountName",
2789 "displayName",
2790 NULL};
2791 attrs = attrs2;
2792 break;
2794 case 7:
2796 static const char * const attrs2[] = {"sAMAccountName",
2797 NULL};
2798 attrs = attrs2;
2799 break;
2801 case 8:
2803 static const char * const attrs2[] = {"displayName",
2804 NULL};
2805 attrs = attrs2;
2806 break;
2808 case 9:
2810 static const char * const attrs2[] = {"primaryGroupID",
2811 NULL};
2812 attrs = attrs2;
2813 break;
2815 case 10:
2817 static const char * const attrs2[] = {"homeDirectory",
2818 "homeDrive",
2819 NULL};
2820 attrs = attrs2;
2821 break;
2823 case 11:
2825 static const char * const attrs2[] = {"scriptPath",
2826 NULL};
2827 attrs = attrs2;
2828 break;
2830 case 12:
2832 static const char * const attrs2[] = {"profilePath",
2833 NULL};
2834 attrs = attrs2;
2835 break;
2837 case 13:
2839 static const char * const attrs2[] = {"description",
2840 NULL};
2841 attrs = attrs2;
2842 break;
2844 case 14:
2846 static const char * const attrs2[] = {"userWorkstations",
2847 NULL};
2848 attrs = attrs2;
2849 break;
2851 case 16:
2853 static const char * const attrs2[] = {"userAccountControl",
2854 "pwdLastSet",
2855 NULL};
2856 attrs = attrs2;
2857 break;
2859 case 17:
2861 static const char * const attrs2[] = {"accountExpires",
2862 NULL};
2863 attrs = attrs2;
2864 break;
2866 case 18:
2868 return NT_STATUS_NOT_SUPPORTED;
2870 case 20:
2872 static const char * const attrs2[] = {"userParameters",
2873 NULL};
2874 attrs = attrs2;
2875 break;
2877 case 21:
2879 static const char * const attrs2[] = {"lastLogon",
2880 "lastLogoff",
2881 "pwdLastSet",
2882 "accountExpires",
2883 "sAMAccountName",
2884 "displayName",
2885 "homeDirectory",
2886 "homeDrive",
2887 "scriptPath",
2888 "profilePath",
2889 "description",
2890 "userWorkstations",
2891 "comment",
2892 "userParameters",
2893 "objectSid",
2894 "primaryGroupID",
2895 "userAccountControl",
2896 "logonHours",
2897 "badPwdCount",
2898 "logonCount",
2899 "countryCode",
2900 "codePage",
2901 NULL};
2902 attrs = attrs2;
2903 break;
2905 case 23:
2906 case 24:
2907 case 25:
2908 case 26:
2910 return NT_STATUS_NOT_SUPPORTED;
2912 default:
2914 return NT_STATUS_INVALID_INFO_CLASS;
2918 /* pull all the user attributes */
2919 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2920 a_state->account_dn, &res, attrs);
2921 if (ret == 0) {
2922 return NT_STATUS_NO_SUCH_USER;
2924 if (ret != 1) {
2925 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2927 msg = res[0];
2929 /* allocate the info structure */
2930 info = talloc_zero(mem_ctx, union samr_UserInfo);
2931 if (info == NULL) {
2932 return NT_STATUS_NO_MEMORY;
2935 /* fill in the reply */
2936 switch (r->in.level) {
2937 case 1:
2938 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2939 QUERY_STRING(msg, info1.full_name, "displayName");
2940 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2941 QUERY_STRING(msg, info1.description, "description");
2942 QUERY_STRING(msg, info1.comment, "comment");
2943 break;
2945 case 2:
2946 QUERY_STRING(msg, info2.comment, "comment");
2947 QUERY_UINT (msg, info2.country_code, "countryCode");
2948 QUERY_UINT (msg, info2.code_page, "codePage");
2949 break;
2951 case 3:
2952 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2953 QUERY_STRING(msg, info3.full_name, "displayName");
2954 QUERY_RID (msg, info3.rid, "objectSid");
2955 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2956 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2957 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2958 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2959 QUERY_STRING(msg, info3.profile_path, "profilePath");
2960 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2961 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2962 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2963 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2964 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2965 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2966 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2967 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2968 QUERY_UINT (msg, info3.logon_count, "logonCount");
2969 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
2970 break;
2972 case 4:
2973 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2974 break;
2976 case 5:
2977 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2978 QUERY_STRING(msg, info5.full_name, "displayName");
2979 QUERY_RID (msg, info5.rid, "objectSid");
2980 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2981 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2982 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2983 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2984 QUERY_STRING(msg, info5.profile_path, "profilePath");
2985 QUERY_STRING(msg, info5.description, "description");
2986 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2987 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2988 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2989 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2990 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
2991 QUERY_UINT (msg, info5.logon_count, "logonCount");
2992 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2993 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
2994 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
2995 break;
2997 case 6:
2998 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
2999 QUERY_STRING(msg, info6.full_name, "displayName");
3000 break;
3002 case 7:
3003 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3004 break;
3006 case 8:
3007 QUERY_STRING(msg, info8.full_name, "displayName");
3008 break;
3010 case 9:
3011 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3012 break;
3014 case 10:
3015 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3016 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3017 break;
3019 case 11:
3020 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3021 break;
3023 case 12:
3024 QUERY_STRING(msg, info12.profile_path, "profilePath");
3025 break;
3027 case 13:
3028 QUERY_STRING(msg, info13.description, "description");
3029 break;
3031 case 14:
3032 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3033 break;
3035 case 16:
3036 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3037 break;
3039 case 17:
3040 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3041 break;
3043 case 20:
3044 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3045 break;
3047 case 21:
3048 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3049 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3050 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3051 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3052 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3053 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3054 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3055 QUERY_STRING(msg, info21.full_name, "displayName");
3056 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3057 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3058 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3059 QUERY_STRING(msg, info21.profile_path, "profilePath");
3060 QUERY_STRING(msg, info21.description, "description");
3061 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3062 QUERY_STRING(msg, info21.comment, "comment");
3063 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3064 QUERY_RID (msg, info21.rid, "objectSid");
3065 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3066 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3067 info->info21.fields_present = 0x08FFFFFF;
3068 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3069 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3070 QUERY_UINT (msg, info21.logon_count, "logonCount");
3071 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3072 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3073 } else {
3074 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3076 QUERY_UINT (msg, info21.country_code, "countryCode");
3077 QUERY_UINT (msg, info21.code_page, "codePage");
3078 break;
3081 default:
3082 talloc_free(info);
3083 return NT_STATUS_INVALID_INFO_CLASS;
3086 *r->out.info = info;
3088 return NT_STATUS_OK;
3093 samr_SetUserInfo
3095 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3096 struct samr_SetUserInfo *r)
3098 struct dcesrv_handle *h;
3099 struct samr_account_state *a_state;
3100 struct ldb_message *msg;
3101 int ret;
3102 NTSTATUS status = NT_STATUS_OK;
3103 struct ldb_context *sam_ctx;
3105 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3107 a_state = h->data;
3108 sam_ctx = a_state->sam_ctx;
3110 msg = ldb_msg_new(mem_ctx);
3111 if (msg == NULL) {
3112 return NT_STATUS_NO_MEMORY;
3115 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3116 if (!msg->dn) {
3117 return NT_STATUS_NO_MEMORY;
3120 switch (r->in.level) {
3121 case 2:
3122 SET_STRING(msg, info2.comment, "comment");
3123 SET_UINT (msg, info2.country_code, "countryCode");
3124 SET_UINT (msg, info2.code_page, "codePage");
3125 break;
3127 case 4:
3128 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3129 break;
3131 case 6:
3132 SET_STRING(msg, info6.account_name, "samAccountName");
3133 SET_STRING(msg, info6.full_name, "displayName");
3134 break;
3136 case 7:
3137 SET_STRING(msg, info7.account_name, "samAccountName");
3138 break;
3140 case 8:
3141 SET_STRING(msg, info8.full_name, "displayName");
3142 break;
3144 case 9:
3145 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3146 break;
3148 case 10:
3149 SET_STRING(msg, info10.home_directory, "homeDirectory");
3150 SET_STRING(msg, info10.home_drive, "homeDrive");
3151 break;
3153 case 11:
3154 SET_STRING(msg, info11.logon_script, "scriptPath");
3155 break;
3157 case 12:
3158 SET_STRING(msg, info12.profile_path, "profilePath");
3159 break;
3161 case 13:
3162 SET_STRING(msg, info13.description, "description");
3163 break;
3165 case 14:
3166 SET_STRING(msg, info14.workstations, "userWorkstations");
3167 break;
3169 case 16:
3170 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3171 break;
3173 case 17:
3174 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3175 break;
3177 case 18:
3178 status = samr_set_password_buffers(dce_call,
3179 a_state->sam_ctx,
3180 a_state->account_dn,
3181 a_state->domain_state->domain_dn,
3182 mem_ctx,
3183 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3184 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3185 if (!NT_STATUS_IS_OK(status)) {
3186 return status;
3189 if (r->in.info->info18.password_expired > 0) {
3190 struct ldb_message_element *set_el;
3191 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3192 return NT_STATUS_NO_MEMORY;
3194 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3195 set_el->flags = LDB_FLAG_MOD_REPLACE;
3197 break;
3199 case 20:
3200 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3201 break;
3203 case 21:
3204 if (r->in.info->info21.fields_present == 0)
3205 return NT_STATUS_INVALID_PARAMETER;
3207 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3208 IFSET(SAMR_FIELD_LAST_LOGON)
3209 SET_UINT64(msg, info21.last_logon, "lastLogon");
3210 IFSET(SAMR_FIELD_LAST_LOGOFF)
3211 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3212 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3213 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3214 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3215 SET_STRING(msg, info21.account_name, "samAccountName");
3216 IFSET(SAMR_FIELD_FULL_NAME)
3217 SET_STRING(msg, info21.full_name, "displayName");
3218 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3219 SET_STRING(msg, info21.home_directory, "homeDirectory");
3220 IFSET(SAMR_FIELD_HOME_DRIVE)
3221 SET_STRING(msg, info21.home_drive, "homeDrive");
3222 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3223 SET_STRING(msg, info21.logon_script, "scriptPath");
3224 IFSET(SAMR_FIELD_PROFILE_PATH)
3225 SET_STRING(msg, info21.profile_path, "profilePath");
3226 IFSET(SAMR_FIELD_DESCRIPTION)
3227 SET_STRING(msg, info21.description, "description");
3228 IFSET(SAMR_FIELD_WORKSTATIONS)
3229 SET_STRING(msg, info21.workstations, "userWorkstations");
3230 IFSET(SAMR_FIELD_COMMENT)
3231 SET_STRING(msg, info21.comment, "comment");
3232 IFSET(SAMR_FIELD_PARAMETERS)
3233 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3234 IFSET(SAMR_FIELD_PRIMARY_GID)
3235 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3236 IFSET(SAMR_FIELD_ACCT_FLAGS)
3237 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3238 IFSET(SAMR_FIELD_LOGON_HOURS)
3239 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3240 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3241 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3242 IFSET(SAMR_FIELD_NUM_LOGONS)
3243 SET_UINT (msg, info21.logon_count, "logonCount");
3244 IFSET(SAMR_FIELD_COUNTRY_CODE)
3245 SET_UINT (msg, info21.country_code, "countryCode");
3246 IFSET(SAMR_FIELD_CODE_PAGE)
3247 SET_UINT (msg, info21.code_page, "codePage");
3249 /* password change fields */
3250 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3251 return NT_STATUS_ACCESS_DENIED;
3253 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3254 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3255 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3257 if (r->in.info->info21.lm_password_set) {
3258 if ((r->in.info->info21.lm_owf_password.length != 16)
3259 || (r->in.info->info21.lm_owf_password.size != 16)) {
3260 return NT_STATUS_INVALID_PARAMETER;
3263 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3265 if (r->in.info->info21.nt_password_set) {
3266 if ((r->in.info->info21.nt_owf_password.length != 16)
3267 || (r->in.info->info21.nt_owf_password.size != 16)) {
3268 return NT_STATUS_INVALID_PARAMETER;
3271 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3273 status = samr_set_password_buffers(dce_call,
3274 a_state->sam_ctx,
3275 a_state->account_dn,
3276 a_state->domain_state->domain_dn,
3277 mem_ctx,
3278 lm_pwd_hash,
3279 nt_pwd_hash);
3280 if (!NT_STATUS_IS_OK(status)) {
3281 return status;
3286 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3287 NTTIME t = 0;
3288 struct ldb_message_element *set_el;
3289 if (r->in.info->info21.password_expired
3290 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3291 unix_to_nt_time(&t, time(NULL));
3293 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3294 "pwdLastSet", t) != LDB_SUCCESS) {
3295 return NT_STATUS_NO_MEMORY;
3297 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3298 set_el->flags = LDB_FLAG_MOD_REPLACE;
3300 #undef IFSET
3301 break;
3303 case 23:
3304 if (r->in.info->info23.info.fields_present == 0)
3305 return NT_STATUS_INVALID_PARAMETER;
3307 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3308 IFSET(SAMR_FIELD_LAST_LOGON)
3309 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3310 IFSET(SAMR_FIELD_LAST_LOGOFF)
3311 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3312 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3313 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3314 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3315 SET_STRING(msg, info23.info.account_name, "samAccountName");
3316 IFSET(SAMR_FIELD_FULL_NAME)
3317 SET_STRING(msg, info23.info.full_name, "displayName");
3318 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3319 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3320 IFSET(SAMR_FIELD_HOME_DRIVE)
3321 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3322 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3323 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3324 IFSET(SAMR_FIELD_PROFILE_PATH)
3325 SET_STRING(msg, info23.info.profile_path, "profilePath");
3326 IFSET(SAMR_FIELD_DESCRIPTION)
3327 SET_STRING(msg, info23.info.description, "description");
3328 IFSET(SAMR_FIELD_WORKSTATIONS)
3329 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3330 IFSET(SAMR_FIELD_COMMENT)
3331 SET_STRING(msg, info23.info.comment, "comment");
3332 IFSET(SAMR_FIELD_PARAMETERS)
3333 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3334 IFSET(SAMR_FIELD_PRIMARY_GID)
3335 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3336 IFSET(SAMR_FIELD_ACCT_FLAGS)
3337 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3338 IFSET(SAMR_FIELD_LOGON_HOURS)
3339 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3340 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3341 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3342 IFSET(SAMR_FIELD_NUM_LOGONS)
3343 SET_UINT (msg, info23.info.logon_count, "logonCount");
3345 IFSET(SAMR_FIELD_COUNTRY_CODE)
3346 SET_UINT (msg, info23.info.country_code, "countryCode");
3347 IFSET(SAMR_FIELD_CODE_PAGE)
3348 SET_UINT (msg, info23.info.code_page, "codePage");
3350 /* password change fields */
3351 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3352 return NT_STATUS_ACCESS_DENIED;
3354 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3355 status = samr_set_password(dce_call,
3356 a_state->sam_ctx,
3357 a_state->account_dn,
3358 a_state->domain_state->domain_dn,
3359 mem_ctx,
3360 &r->in.info->info23.password);
3361 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3362 status = samr_set_password(dce_call,
3363 a_state->sam_ctx,
3364 a_state->account_dn,
3365 a_state->domain_state->domain_dn,
3366 mem_ctx,
3367 &r->in.info->info23.password);
3369 if (!NT_STATUS_IS_OK(status)) {
3370 return status;
3373 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3374 NTTIME t = 0;
3375 struct ldb_message_element *set_el;
3376 if (r->in.info->info23.info.password_expired
3377 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3378 unix_to_nt_time(&t, time(NULL));
3380 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3381 "pwdLastSet", t) != LDB_SUCCESS) {
3382 return NT_STATUS_NO_MEMORY;
3384 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3385 set_el->flags = LDB_FLAG_MOD_REPLACE;
3387 #undef IFSET
3388 break;
3390 /* the set password levels are handled separately */
3391 case 24:
3392 status = samr_set_password(dce_call,
3393 a_state->sam_ctx,
3394 a_state->account_dn,
3395 a_state->domain_state->domain_dn,
3396 mem_ctx,
3397 &r->in.info->info24.password);
3398 if (!NT_STATUS_IS_OK(status)) {
3399 return status;
3402 if (r->in.info->info24.password_expired > 0) {
3403 struct ldb_message_element *set_el;
3404 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3405 return NT_STATUS_NO_MEMORY;
3407 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3408 set_el->flags = LDB_FLAG_MOD_REPLACE;
3410 break;
3412 case 25:
3413 if (r->in.info->info25.info.fields_present == 0)
3414 return NT_STATUS_INVALID_PARAMETER;
3416 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3417 IFSET(SAMR_FIELD_LAST_LOGON)
3418 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3419 IFSET(SAMR_FIELD_LAST_LOGOFF)
3420 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3421 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3422 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3423 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3424 SET_STRING(msg, info25.info.account_name, "samAccountName");
3425 IFSET(SAMR_FIELD_FULL_NAME)
3426 SET_STRING(msg, info25.info.full_name, "displayName");
3427 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3428 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3429 IFSET(SAMR_FIELD_HOME_DRIVE)
3430 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3431 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3432 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3433 IFSET(SAMR_FIELD_PROFILE_PATH)
3434 SET_STRING(msg, info25.info.profile_path, "profilePath");
3435 IFSET(SAMR_FIELD_DESCRIPTION)
3436 SET_STRING(msg, info25.info.description, "description");
3437 IFSET(SAMR_FIELD_WORKSTATIONS)
3438 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3439 IFSET(SAMR_FIELD_COMMENT)
3440 SET_STRING(msg, info25.info.comment, "comment");
3441 IFSET(SAMR_FIELD_PARAMETERS)
3442 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3443 IFSET(SAMR_FIELD_PRIMARY_GID)
3444 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3445 IFSET(SAMR_FIELD_ACCT_FLAGS)
3446 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3447 IFSET(SAMR_FIELD_LOGON_HOURS)
3448 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3449 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3450 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3451 IFSET(SAMR_FIELD_NUM_LOGONS)
3452 SET_UINT (msg, info25.info.logon_count, "logonCount");
3453 IFSET(SAMR_FIELD_COUNTRY_CODE)
3454 SET_UINT (msg, info25.info.country_code, "countryCode");
3455 IFSET(SAMR_FIELD_CODE_PAGE)
3456 SET_UINT (msg, info25.info.code_page, "codePage");
3458 /* password change fields */
3459 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3460 return NT_STATUS_ACCESS_DENIED;
3462 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3463 status = samr_set_password_ex(dce_call,
3464 a_state->sam_ctx,
3465 a_state->account_dn,
3466 a_state->domain_state->domain_dn,
3467 mem_ctx,
3468 &r->in.info->info25.password);
3469 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3470 status = samr_set_password_ex(dce_call,
3471 a_state->sam_ctx,
3472 a_state->account_dn,
3473 a_state->domain_state->domain_dn,
3474 mem_ctx,
3475 &r->in.info->info25.password);
3477 if (!NT_STATUS_IS_OK(status)) {
3478 return status;
3481 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3482 NTTIME t = 0;
3483 struct ldb_message_element *set_el;
3484 if (r->in.info->info25.info.password_expired
3485 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3486 unix_to_nt_time(&t, time(NULL));
3488 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3489 "pwdLastSet", t) != LDB_SUCCESS) {
3490 return NT_STATUS_NO_MEMORY;
3492 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3493 set_el->flags = LDB_FLAG_MOD_REPLACE;
3495 #undef IFSET
3496 break;
3498 /* the set password levels are handled separately */
3499 case 26:
3500 status = samr_set_password_ex(dce_call,
3501 a_state->sam_ctx,
3502 a_state->account_dn,
3503 a_state->domain_state->domain_dn,
3504 mem_ctx,
3505 &r->in.info->info26.password);
3506 if (!NT_STATUS_IS_OK(status)) {
3507 return status;
3510 if (r->in.info->info26.password_expired > 0) {
3511 struct ldb_message_element *set_el;
3512 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3513 return NT_STATUS_NO_MEMORY;
3515 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3516 set_el->flags = LDB_FLAG_MOD_REPLACE;
3518 break;
3520 default:
3521 /* many info classes are not valid for SetUserInfo */
3522 return NT_STATUS_INVALID_INFO_CLASS;
3525 if (!NT_STATUS_IS_OK(status)) {
3526 return status;
3529 /* modify the samdb record */
3530 if (msg->num_elements > 0) {
3531 ret = ldb_modify(a_state->sam_ctx, msg);
3532 if (ret != LDB_SUCCESS) {
3533 DEBUG(1,("Failed to modify record %s: %s\n",
3534 ldb_dn_get_linearized(a_state->account_dn),
3535 ldb_errstring(a_state->sam_ctx)));
3537 /* we really need samdb.c to return NTSTATUS */
3538 return NT_STATUS_UNSUCCESSFUL;
3542 return NT_STATUS_OK;
3547 samr_GetGroupsForUser
3549 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3550 struct samr_GetGroupsForUser *r)
3552 struct dcesrv_handle *h;
3553 struct samr_account_state *a_state;
3554 struct samr_domain_state *d_state;
3555 struct ldb_message **res;
3556 const char * const attrs[2] = { "objectSid", NULL };
3557 struct samr_RidWithAttributeArray *array;
3558 int i, count;
3560 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3562 a_state = h->data;
3563 d_state = a_state->domain_state;
3565 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3566 d_state->domain_dn, &res,
3567 attrs, d_state->domain_sid,
3568 "(&(member=%s)(|(grouptype=%d)(grouptype=%d))(objectclass=group))",
3569 ldb_dn_get_linearized(a_state->account_dn),
3570 GTYPE_SECURITY_UNIVERSAL_GROUP,
3571 GTYPE_SECURITY_GLOBAL_GROUP);
3572 if (count < 0)
3573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3575 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3576 if (array == NULL)
3577 return NT_STATUS_NO_MEMORY;
3579 array->count = 0;
3580 array->rids = NULL;
3582 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3583 count + 1);
3584 if (array->rids == NULL)
3585 return NT_STATUS_NO_MEMORY;
3587 /* Adds the primary group */
3588 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3589 ~0, a_state->account_dn,
3590 "primaryGroupID", NULL);
3591 array->rids[0].attributes = SE_GROUP_MANDATORY
3592 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3593 array->count += 1;
3595 /* Adds the additional groups */
3596 for (i = 0; i < count; i++) {
3597 struct dom_sid *group_sid;
3599 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3600 if (group_sid == NULL) {
3601 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3604 array->rids[i + 1].rid =
3605 group_sid->sub_auths[group_sid->num_auths-1];
3606 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3607 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3608 array->count += 1;
3611 *r->out.rids = array;
3613 return NT_STATUS_OK;
3618 samr_QueryDisplayInfo
3620 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3621 struct samr_QueryDisplayInfo *r)
3623 struct dcesrv_handle *h;
3624 struct samr_domain_state *d_state;
3625 struct ldb_result *res;
3626 unsigned int i;
3627 uint32_t count;
3628 const char * const attrs[] = { "objectSid", "sAMAccountName",
3629 "displayName", "description", "userAccountControl",
3630 "pwdLastSet", NULL };
3631 struct samr_DispEntryFull *entriesFull = NULL;
3632 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3633 struct samr_DispEntryAscii *entriesAscii = NULL;
3634 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3635 const char *filter;
3636 int ret;
3638 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3640 d_state = h->data;
3642 switch (r->in.level) {
3643 case 1:
3644 case 4:
3645 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3646 "(sAMAccountType=%d))",
3647 ATYPE_NORMAL_ACCOUNT);
3648 break;
3649 case 2:
3650 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3651 "(sAMAccountType=%d))",
3652 ATYPE_WORKSTATION_TRUST);
3653 break;
3654 case 3:
3655 case 5:
3656 filter = talloc_asprintf(mem_ctx,
3657 "(&(|(groupType=%d)(groupType=%d))"
3658 "(objectClass=group))",
3659 GTYPE_SECURITY_UNIVERSAL_GROUP,
3660 GTYPE_SECURITY_GLOBAL_GROUP);
3661 break;
3662 default:
3663 return NT_STATUS_INVALID_INFO_CLASS;
3666 /* search for all requested objects in all domains. This could
3667 possibly be cached and resumed based on resume_key */
3668 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, NULL,
3669 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3670 if (ret != LDB_SUCCESS) {
3671 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3673 if ((res->count == 0) || (r->in.max_entries == 0)) {
3674 return NT_STATUS_OK;
3677 switch (r->in.level) {
3678 case 1:
3679 entriesGeneral = talloc_array(mem_ctx,
3680 struct samr_DispEntryGeneral,
3681 res->count);
3682 break;
3683 case 2:
3684 entriesFull = talloc_array(mem_ctx,
3685 struct samr_DispEntryFull,
3686 res->count);
3687 break;
3688 case 3:
3689 entriesFullGroup = talloc_array(mem_ctx,
3690 struct samr_DispEntryFullGroup,
3691 res->count);
3692 break;
3693 case 4:
3694 case 5:
3695 entriesAscii = talloc_array(mem_ctx,
3696 struct samr_DispEntryAscii,
3697 res->count);
3698 break;
3701 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3702 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3703 return NT_STATUS_NO_MEMORY;
3705 count = 0;
3707 for (i = 0; i < res->count; i++) {
3708 struct dom_sid *objectsid;
3710 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3711 "objectSid");
3712 if (objectsid == NULL)
3713 continue;
3715 switch(r->in.level) {
3716 case 1:
3717 entriesGeneral[count].idx = count + 1;
3718 entriesGeneral[count].rid =
3719 objectsid->sub_auths[objectsid->num_auths-1];
3720 entriesGeneral[count].acct_flags =
3721 samdb_result_acct_flags(d_state->sam_ctx,
3722 mem_ctx,
3723 res->msgs[i],
3724 d_state->domain_dn);
3725 entriesGeneral[count].account_name.string =
3726 ldb_msg_find_attr_as_string(res->msgs[i],
3727 "sAMAccountName", "");
3728 entriesGeneral[count].full_name.string =
3729 ldb_msg_find_attr_as_string(res->msgs[i],
3730 "displayName", "");
3731 entriesGeneral[count].description.string =
3732 ldb_msg_find_attr_as_string(res->msgs[i],
3733 "description", "");
3734 break;
3735 case 2:
3736 entriesFull[count].idx = count + 1;
3737 entriesFull[count].rid =
3738 objectsid->sub_auths[objectsid->num_auths-1];
3740 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3741 entriesFull[count].acct_flags =
3742 samdb_result_acct_flags(d_state->sam_ctx,
3743 mem_ctx,
3744 res->msgs[i],
3745 d_state->domain_dn) | ACB_NORMAL;
3746 entriesFull[count].account_name.string =
3747 ldb_msg_find_attr_as_string(res->msgs[i],
3748 "sAMAccountName", "");
3749 entriesFull[count].description.string =
3750 ldb_msg_find_attr_as_string(res->msgs[i],
3751 "description", "");
3752 break;
3753 case 3:
3754 entriesFullGroup[count].idx = count + 1;
3755 entriesFullGroup[count].rid =
3756 objectsid->sub_auths[objectsid->num_auths-1];
3757 /* We get a "7" here for groups */
3758 entriesFullGroup[count].acct_flags
3759 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3760 entriesFullGroup[count].account_name.string =
3761 ldb_msg_find_attr_as_string(res->msgs[i],
3762 "sAMAccountName", "");
3763 entriesFullGroup[count].description.string =
3764 ldb_msg_find_attr_as_string(res->msgs[i],
3765 "description", "");
3766 break;
3767 case 4:
3768 case 5:
3769 entriesAscii[count].idx = count + 1;
3770 entriesAscii[count].account_name.string =
3771 ldb_msg_find_attr_as_string(res->msgs[i],
3772 "sAMAccountName", "");
3773 break;
3776 count += 1;
3779 *r->out.total_size = count;
3781 if (r->in.start_idx >= count) {
3782 *r->out.returned_size = 0;
3783 switch(r->in.level) {
3784 case 1:
3785 r->out.info->info1.count = *r->out.returned_size;
3786 r->out.info->info1.entries = NULL;
3787 break;
3788 case 2:
3789 r->out.info->info2.count = *r->out.returned_size;
3790 r->out.info->info2.entries = NULL;
3791 break;
3792 case 3:
3793 r->out.info->info3.count = *r->out.returned_size;
3794 r->out.info->info3.entries = NULL;
3795 break;
3796 case 4:
3797 r->out.info->info4.count = *r->out.returned_size;
3798 r->out.info->info4.entries = NULL;
3799 break;
3800 case 5:
3801 r->out.info->info5.count = *r->out.returned_size;
3802 r->out.info->info5.entries = NULL;
3803 break;
3805 } else {
3806 *r->out.returned_size = MIN(count - r->in.start_idx,
3807 r->in.max_entries);
3808 switch(r->in.level) {
3809 case 1:
3810 r->out.info->info1.count = *r->out.returned_size;
3811 r->out.info->info1.entries =
3812 &(entriesGeneral[r->in.start_idx]);
3813 break;
3814 case 2:
3815 r->out.info->info2.count = *r->out.returned_size;
3816 r->out.info->info2.entries =
3817 &(entriesFull[r->in.start_idx]);
3818 break;
3819 case 3:
3820 r->out.info->info3.count = *r->out.returned_size;
3821 r->out.info->info3.entries =
3822 &(entriesFullGroup[r->in.start_idx]);
3823 break;
3824 case 4:
3825 r->out.info->info4.count = *r->out.returned_size;
3826 r->out.info->info4.entries =
3827 &(entriesAscii[r->in.start_idx]);
3828 break;
3829 case 5:
3830 r->out.info->info5.count = *r->out.returned_size;
3831 r->out.info->info5.entries =
3832 &(entriesAscii[r->in.start_idx]);
3833 break;
3837 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3838 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3843 samr_GetDisplayEnumerationIndex
3845 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3846 struct samr_GetDisplayEnumerationIndex *r)
3848 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3853 samr_TestPrivateFunctionsDomain
3855 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3856 struct samr_TestPrivateFunctionsDomain *r)
3858 return NT_STATUS_NOT_IMPLEMENTED;
3863 samr_TestPrivateFunctionsUser
3865 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3866 struct samr_TestPrivateFunctionsUser *r)
3868 return NT_STATUS_NOT_IMPLEMENTED;
3873 samr_GetUserPwInfo
3875 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3876 struct samr_GetUserPwInfo *r)
3878 struct dcesrv_handle *h;
3879 struct samr_account_state *a_state;
3881 ZERO_STRUCTP(r->out.info);
3883 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3885 a_state = h->data;
3887 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3888 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3889 NULL);
3890 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3891 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3893 return NT_STATUS_OK;
3898 samr_RemoveMemberFromForeignDomain
3900 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3901 TALLOC_CTX *mem_ctx,
3902 struct samr_RemoveMemberFromForeignDomain *r)
3904 struct dcesrv_handle *h;
3905 struct samr_domain_state *d_state;
3906 const char *memberdn;
3907 struct ldb_message **res;
3908 const char *no_attrs[] = { NULL };
3909 int i, count;
3911 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3913 d_state = h->data;
3915 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3916 "distinguishedName", "(objectSid=%s)",
3917 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3918 /* Nothing to do */
3919 if (memberdn == NULL) {
3920 return NT_STATUS_OK;
3923 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3924 d_state->domain_dn, &res, no_attrs,
3925 d_state->domain_sid,
3926 "(&(member=%s)(objectClass=group)"
3927 "(|(groupType=%d)(groupType=%d)))",
3928 memberdn,
3929 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3930 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3932 if (count < 0)
3933 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3935 for (i=0; i<count; i++) {
3936 struct ldb_message *mod;
3938 mod = ldb_msg_new(mem_ctx);
3939 if (mod == NULL) {
3940 return NT_STATUS_NO_MEMORY;
3943 mod->dn = res[i]->dn;
3945 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3946 "member", memberdn) != LDB_SUCCESS)
3947 return NT_STATUS_NO_MEMORY;
3949 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
3950 return NT_STATUS_UNSUCCESSFUL;
3952 talloc_free(mod);
3955 return NT_STATUS_OK;
3960 samr_QueryDomainInfo2
3962 just an alias for samr_QueryDomainInfo
3964 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3965 struct samr_QueryDomainInfo2 *r)
3967 struct samr_QueryDomainInfo r1;
3968 NTSTATUS status;
3970 ZERO_STRUCT(r1.out);
3971 r1.in.domain_handle = r->in.domain_handle;
3972 r1.in.level = r->in.level;
3973 r1.out.info = r->out.info;
3975 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3977 return status;
3982 samr_QueryUserInfo2
3984 just an alias for samr_QueryUserInfo
3986 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3987 struct samr_QueryUserInfo2 *r)
3989 struct samr_QueryUserInfo r1;
3990 NTSTATUS status;
3992 r1.in.user_handle = r->in.user_handle;
3993 r1.in.level = r->in.level;
3994 r1.out.info = r->out.info;
3996 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3998 return status;
4003 samr_QueryDisplayInfo2
4005 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4006 struct samr_QueryDisplayInfo2 *r)
4008 struct samr_QueryDisplayInfo q;
4009 NTSTATUS result;
4011 q.in.domain_handle = r->in.domain_handle;
4012 q.in.level = r->in.level;
4013 q.in.start_idx = r->in.start_idx;
4014 q.in.max_entries = r->in.max_entries;
4015 q.in.buf_size = r->in.buf_size;
4016 q.out.total_size = r->out.total_size;
4017 q.out.returned_size = r->out.returned_size;
4018 q.out.info = r->out.info;
4020 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4022 return result;
4027 samr_GetDisplayEnumerationIndex2
4029 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4030 struct samr_GetDisplayEnumerationIndex2 *r)
4032 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4037 samr_QueryDisplayInfo3
4039 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4040 struct samr_QueryDisplayInfo3 *r)
4042 struct samr_QueryDisplayInfo q;
4043 NTSTATUS result;
4045 q.in.domain_handle = r->in.domain_handle;
4046 q.in.level = r->in.level;
4047 q.in.start_idx = r->in.start_idx;
4048 q.in.max_entries = r->in.max_entries;
4049 q.in.buf_size = r->in.buf_size;
4050 q.out.total_size = r->out.total_size;
4051 q.out.returned_size = r->out.returned_size;
4052 q.out.info = r->out.info;
4054 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4056 return result;
4061 samr_AddMultipleMembersToAlias
4063 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4064 struct samr_AddMultipleMembersToAlias *r)
4066 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4071 samr_RemoveMultipleMembersFromAlias
4073 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4074 struct samr_RemoveMultipleMembersFromAlias *r)
4076 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4081 samr_GetDomPwInfo
4083 this fetches the default password properties for a domain
4085 note that w2k3 completely ignores the domain name in this call, and
4086 always returns the information for the servers primary domain
4088 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4089 struct samr_GetDomPwInfo *r)
4091 struct ldb_message **msgs;
4092 int ret;
4093 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4094 struct ldb_context *sam_ctx;
4096 ZERO_STRUCTP(r->out.info);
4098 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4099 dce_call->conn->dce_ctx->lp_ctx,
4100 dce_call->conn->auth_state.session_info, 0);
4101 if (sam_ctx == NULL) {
4102 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4105 /* The domain name in this call is ignored */
4106 ret = gendb_search_dn(sam_ctx,
4107 mem_ctx, NULL, &msgs, attrs);
4108 if (ret <= 0) {
4109 talloc_free(sam_ctx);
4111 return NT_STATUS_NO_SUCH_DOMAIN;
4113 if (ret > 1) {
4114 talloc_free(msgs);
4115 talloc_free(sam_ctx);
4117 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4120 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4121 "minPwdLength", 0);
4122 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4123 "pwdProperties", 1);
4125 talloc_free(msgs);
4126 talloc_unlink(mem_ctx, sam_ctx);
4128 return NT_STATUS_OK;
4133 samr_Connect2
4135 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4136 struct samr_Connect2 *r)
4138 struct samr_Connect c;
4140 c.in.system_name = NULL;
4141 c.in.access_mask = r->in.access_mask;
4142 c.out.connect_handle = r->out.connect_handle;
4144 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4149 samr_SetUserInfo2
4151 just an alias for samr_SetUserInfo
4153 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4154 struct samr_SetUserInfo2 *r)
4156 struct samr_SetUserInfo r2;
4158 r2.in.user_handle = r->in.user_handle;
4159 r2.in.level = r->in.level;
4160 r2.in.info = r->in.info;
4162 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4167 samr_SetBootKeyInformation
4169 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4170 struct samr_SetBootKeyInformation *r)
4172 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4177 samr_GetBootKeyInformation
4179 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4180 struct samr_GetBootKeyInformation *r)
4182 /* Windows Server 2008 returns this */
4183 return NT_STATUS_NOT_SUPPORTED;
4188 samr_Connect3
4190 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4191 struct samr_Connect3 *r)
4193 struct samr_Connect c;
4195 c.in.system_name = NULL;
4196 c.in.access_mask = r->in.access_mask;
4197 c.out.connect_handle = r->out.connect_handle;
4199 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4204 samr_Connect4
4206 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4207 struct samr_Connect4 *r)
4209 struct samr_Connect c;
4211 c.in.system_name = NULL;
4212 c.in.access_mask = r->in.access_mask;
4213 c.out.connect_handle = r->out.connect_handle;
4215 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4220 samr_Connect5
4222 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4223 struct samr_Connect5 *r)
4225 struct samr_Connect c;
4226 NTSTATUS status;
4228 c.in.system_name = NULL;
4229 c.in.access_mask = r->in.access_mask;
4230 c.out.connect_handle = r->out.connect_handle;
4232 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4234 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4235 r->out.info_out->info1.unknown2 = 0;
4236 *r->out.level_out = r->in.level_in;
4238 return status;
4243 samr_RidToSid
4245 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4246 struct samr_RidToSid *r)
4248 struct samr_domain_state *d_state;
4249 struct dcesrv_handle *h;
4251 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4253 d_state = h->data;
4255 /* form the users SID */
4256 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4257 if (!*r->out.sid) {
4258 return NT_STATUS_NO_MEMORY;
4261 return NT_STATUS_OK;
4266 samr_SetDsrmPassword
4268 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4269 struct samr_SetDsrmPassword *r)
4271 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4276 samr_ValidatePassword
4278 For now the call checks the password complexity (if active) and the minimum
4279 password length on level 2 and 3. Level 1 is ignored for now.
4281 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4282 TALLOC_CTX *mem_ctx,
4283 struct samr_ValidatePassword *r)
4285 struct samr_GetDomPwInfo r2;
4286 struct samr_PwInfo pwInfo;
4287 DATA_BLOB password;
4288 enum samr_ValidationStatus res;
4289 NTSTATUS status;
4291 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4293 r2.in.domain_name = NULL;
4294 r2.out.info = &pwInfo;
4295 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4296 if (!NT_STATUS_IS_OK(status)) {
4297 return status;
4300 switch (r->in.level) {
4301 case NetValidateAuthentication:
4302 /* we don't support this yet */
4303 return NT_STATUS_NOT_SUPPORTED;
4304 break;
4305 case NetValidatePasswordChange:
4306 password = data_blob_const(r->in.req->req2.password.string,
4307 r->in.req->req2.password.length);
4308 res = samdb_check_password(&password,
4309 pwInfo.password_properties,
4310 pwInfo.min_password_length);
4311 (*r->out.rep)->ctr2.status = res;
4312 break;
4313 case NetValidatePasswordReset:
4314 password = data_blob_const(r->in.req->req3.password.string,
4315 r->in.req->req3.password.length);
4316 res = samdb_check_password(&password,
4317 pwInfo.password_properties,
4318 pwInfo.min_password_length);
4319 (*r->out.rep)->ctr3.status = res;
4320 break;
4321 default:
4322 return NT_STATUS_INVALID_INFO_CLASS;
4323 break;
4326 return NT_STATUS_OK;
4330 /* include the generated boilerplate */
4331 #include "librpc/gen_ndr/ndr_samr_s.c"