samr4: Remove talloc_asprintf leak onto mem_ctx
[Samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob25255d32be2fea1935c622103002a23a0f32a8c4
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 #define DCESRV_INTERFACE_SAMR_BIND(call, iface) \
45 dcesrv_interface_samr_bind(call, iface)
46 static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_call_state *dce_call,
47 const struct dcesrv_interface *iface)
49 return dcesrv_interface_bind_reject_connect(dce_call, iface);
52 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
54 #define QUERY_STRING(msg, field, attr) \
55 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
56 #define QUERY_UINT(msg, field, attr) \
57 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
58 #define QUERY_RID(msg, field, attr) \
59 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
60 #define QUERY_UINT64(msg, field, attr) \
61 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
62 #define QUERY_APASSC(msg, field, attr) \
63 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
64 a_state->domain_state->domain_dn, msg, attr);
65 #define QUERY_FPASSC(msg, field, attr) \
66 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
67 a_state->domain_state->domain_dn, msg);
68 #define QUERY_BPWDCT(msg, field, attr) \
69 info->field = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx, \
70 a_state->domain_state->domain_dn, msg);
71 #define QUERY_LHOURS(msg, field, attr) \
72 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
73 #define QUERY_AFLAGS(msg, field, attr) \
74 info->field = samdb_result_acct_flags(msg, attr);
77 /* these are used to make the Set[User|Group]Info code easier to follow */
79 #define SET_STRING(msg, field, attr) do { \
80 struct ldb_message_element *set_el; \
81 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
82 if (r->in.info->field.string[0] == '\0') { \
83 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
84 return NT_STATUS_NO_MEMORY; \
85 } \
86 } \
87 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 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_UINT(msg, field, attr) do { \
95 struct ldb_message_element *set_el; \
96 if (samdb_msg_add_uint(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_INT64(msg, field, attr) do { \
104 struct ldb_message_element *set_el; \
105 if (samdb_msg_add_int64(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 SET_UINT64(msg, field, attr) do { \
113 struct ldb_message_element *set_el; \
114 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
115 return NT_STATUS_NO_MEMORY; \
117 set_el = ldb_msg_find_element(msg, attr); \
118 set_el->flags = LDB_FLAG_MOD_REPLACE; \
119 } while (0)
121 /* Set account flags, discarding flags that cannot be set with SAMR */
122 #define SET_AFLAGS(msg, field, attr) do { \
123 struct ldb_message_element *set_el; \
124 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
125 return NT_STATUS_NO_MEMORY; \
127 set_el = ldb_msg_find_element(msg, attr); \
128 set_el->flags = LDB_FLAG_MOD_REPLACE; \
129 } while (0)
131 #define SET_LHOURS(msg, field, attr) do { \
132 struct ldb_message_element *set_el; \
133 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
134 return NT_STATUS_NO_MEMORY; \
136 set_el = ldb_msg_find_element(msg, attr); \
137 set_el->flags = LDB_FLAG_MOD_REPLACE; \
138 } while (0)
140 #define SET_PARAMETERS(msg, field, attr) do { \
141 struct ldb_message_element *set_el; \
142 if (r->in.info->field.length != 0) { \
143 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
144 return NT_STATUS_NO_MEMORY; \
146 set_el = ldb_msg_find_element(msg, attr); \
147 set_el->flags = LDB_FLAG_MOD_REPLACE; \
149 } while (0)
154 samr_Connect
156 create a connection to the SAM database
158 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
159 struct samr_Connect *r)
161 struct samr_connect_state *c_state;
162 struct dcesrv_handle *handle;
164 ZERO_STRUCTP(r->out.connect_handle);
166 c_state = talloc(mem_ctx, struct samr_connect_state);
167 if (!c_state) {
168 return NT_STATUS_NO_MEMORY;
171 /* make sure the sam database is accessible */
172 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);
173 if (c_state->sam_ctx == NULL) {
174 talloc_free(c_state);
175 return NT_STATUS_INVALID_SYSTEM_SERVICE;
179 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
180 if (!handle) {
181 talloc_free(c_state);
182 return NT_STATUS_NO_MEMORY;
185 handle->data = talloc_steal(handle, c_state);
187 c_state->access_mask = r->in.access_mask;
188 *r->out.connect_handle = handle->wire_handle;
190 return NT_STATUS_OK;
195 samr_Close
197 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
198 struct samr_Close *r)
200 struct dcesrv_handle *h;
202 *r->out.handle = *r->in.handle;
204 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
206 talloc_free(h);
208 ZERO_STRUCTP(r->out.handle);
210 return NT_STATUS_OK;
215 samr_SetSecurity
217 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
218 struct samr_SetSecurity *r)
220 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
225 samr_QuerySecurity
227 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
228 struct samr_QuerySecurity *r)
230 struct dcesrv_handle *h;
231 struct sec_desc_buf *sd;
233 *r->out.sdbuf = NULL;
235 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
237 sd = talloc(mem_ctx, struct sec_desc_buf);
238 if (sd == NULL) {
239 return NT_STATUS_NO_MEMORY;
242 sd->sd = samdb_default_security_descriptor(mem_ctx);
244 *r->out.sdbuf = sd;
246 return NT_STATUS_OK;
251 samr_Shutdown
253 we refuse this operation completely. If a admin wants to shutdown samr
254 in Samba then they should use the samba admin tools to disable the samr pipe
256 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
257 struct samr_Shutdown *r)
259 return NT_STATUS_ACCESS_DENIED;
264 samr_LookupDomain
266 this maps from a domain name to a SID
268 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
269 struct samr_LookupDomain *r)
271 struct samr_connect_state *c_state;
272 struct dcesrv_handle *h;
273 struct dom_sid *sid;
274 const char * const dom_attrs[] = { "objectSid", NULL};
275 struct ldb_message **dom_msgs;
276 int ret;
278 *r->out.sid = NULL;
280 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
282 c_state = h->data;
284 if (r->in.domain_name->string == NULL) {
285 return NT_STATUS_INVALID_PARAMETER;
288 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
289 ret = gendb_search(c_state->sam_ctx,
290 mem_ctx, NULL, &dom_msgs, dom_attrs,
291 "(objectClass=builtinDomain)");
292 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
293 ret = gendb_search_dn(c_state->sam_ctx,
294 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
295 &dom_msgs, dom_attrs);
296 } else {
297 return NT_STATUS_NO_SUCH_DOMAIN;
299 if (ret != 1) {
300 return NT_STATUS_NO_SUCH_DOMAIN;
303 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
304 "objectSid");
306 if (sid == NULL) {
307 return NT_STATUS_NO_SUCH_DOMAIN;
310 *r->out.sid = sid;
312 return NT_STATUS_OK;
317 samr_EnumDomains
319 list the domains in the SAM
321 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
322 struct samr_EnumDomains *r)
324 struct dcesrv_handle *h;
325 struct samr_SamArray *array;
326 uint32_t i, start_i;
328 *r->out.resume_handle = 0;
329 *r->out.sam = NULL;
330 *r->out.num_entries = 0;
332 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
334 *r->out.resume_handle = 2;
336 start_i = *r->in.resume_handle;
338 if (start_i >= 2) {
339 /* search past end of list is not an error for this call */
340 return NT_STATUS_OK;
343 array = talloc(mem_ctx, struct samr_SamArray);
344 if (array == NULL) {
345 return NT_STATUS_NO_MEMORY;
348 array->count = 0;
349 array->entries = NULL;
351 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
352 if (array->entries == NULL) {
353 return NT_STATUS_NO_MEMORY;
356 for (i=0;i<2-start_i;i++) {
357 array->entries[i].idx = start_i + i;
358 if (i == 0) {
359 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
360 } else {
361 array->entries[i].name.string = "BUILTIN";
365 *r->out.sam = array;
366 *r->out.num_entries = i;
367 array->count = *r->out.num_entries;
369 return NT_STATUS_OK;
374 samr_OpenDomain
376 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
377 struct samr_OpenDomain *r)
379 struct dcesrv_handle *h_conn, *h_domain;
380 struct samr_connect_state *c_state;
381 struct samr_domain_state *d_state;
382 const char * const dom_attrs[] = { "cn", NULL};
383 struct ldb_message **dom_msgs;
384 int ret;
386 ZERO_STRUCTP(r->out.domain_handle);
388 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
390 c_state = h_conn->data;
392 if (r->in.sid == NULL) {
393 return NT_STATUS_INVALID_PARAMETER;
396 d_state = talloc(mem_ctx, struct samr_domain_state);
397 if (!d_state) {
398 return NT_STATUS_NO_MEMORY;
401 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
403 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
404 d_state->builtin = true;
405 d_state->domain_name = "BUILTIN";
406 } else {
407 d_state->builtin = false;
408 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
411 ret = gendb_search(c_state->sam_ctx,
412 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
413 "(objectSid=%s)",
414 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
416 if (ret == 0) {
417 talloc_free(d_state);
418 return NT_STATUS_NO_SUCH_DOMAIN;
419 } else if (ret > 1) {
420 talloc_free(d_state);
421 return NT_STATUS_INTERNAL_DB_CORRUPTION;
422 } else if (ret == -1) {
423 talloc_free(d_state);
424 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
425 return NT_STATUS_INTERNAL_DB_CORRUPTION;
428 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
429 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
430 d_state->connect_state = talloc_reference(d_state, c_state);
431 d_state->sam_ctx = c_state->sam_ctx;
432 d_state->access_mask = r->in.access_mask;
434 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
436 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
437 if (!h_domain) {
438 talloc_free(d_state);
439 return NT_STATUS_NO_MEMORY;
442 h_domain->data = talloc_steal(h_domain, d_state);
444 *r->out.domain_handle = h_domain->wire_handle;
446 return NT_STATUS_OK;
450 return DomInfo1
452 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
453 TALLOC_CTX *mem_ctx,
454 struct ldb_message **dom_msgs,
455 struct samr_DomInfo1 *info)
457 info->min_password_length =
458 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
459 info->password_history_length =
460 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
461 info->password_properties =
462 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
463 info->max_password_age =
464 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
465 info->min_password_age =
466 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
468 return NT_STATUS_OK;
472 return DomInfo2
474 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
475 TALLOC_CTX *mem_ctx,
476 struct ldb_message **dom_msgs,
477 struct samr_DomGeneralInformation *info)
479 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
480 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
481 "domainReplica",
482 "");
484 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
485 0x8000000000000000LL);
487 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
488 "oEMInformation",
489 "");
490 info->domain_name.string = state->domain_name;
492 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
494 switch (state->role) {
495 case ROLE_ACTIVE_DIRECTORY_DC:
496 /* This pulls the NetBIOS name from the
497 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
498 string */
499 if (samdb_is_pdc(state->sam_ctx)) {
500 info->role = SAMR_ROLE_DOMAIN_PDC;
501 } else {
502 info->role = SAMR_ROLE_DOMAIN_BDC;
504 break;
505 case ROLE_DOMAIN_PDC:
506 case ROLE_DOMAIN_BDC:
507 case ROLE_AUTO:
508 return NT_STATUS_INTERNAL_ERROR;
509 case ROLE_DOMAIN_MEMBER:
510 info->role = SAMR_ROLE_DOMAIN_MEMBER;
511 break;
512 case ROLE_STANDALONE:
513 info->role = SAMR_ROLE_STANDALONE;
514 break;
517 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx,
518 state->domain_dn,
519 "(objectClass=user)");
520 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx,
521 state->domain_dn,
522 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
523 GTYPE_SECURITY_UNIVERSAL_GROUP,
524 GTYPE_SECURITY_GLOBAL_GROUP);
525 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx,
526 state->domain_dn,
527 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
528 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
529 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
531 return NT_STATUS_OK;
535 return DomInfo3
537 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
538 TALLOC_CTX *mem_ctx,
539 struct ldb_message **dom_msgs,
540 struct samr_DomInfo3 *info)
542 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
543 0x8000000000000000LL);
545 return NT_STATUS_OK;
549 return DomInfo4
551 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
552 TALLOC_CTX *mem_ctx,
553 struct ldb_message **dom_msgs,
554 struct samr_DomOEMInformation *info)
556 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
557 "oEMInformation",
558 "");
560 return NT_STATUS_OK;
564 return DomInfo5
566 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
567 TALLOC_CTX *mem_ctx,
568 struct ldb_message **dom_msgs,
569 struct samr_DomInfo5 *info)
571 info->domain_name.string = state->domain_name;
573 return NT_STATUS_OK;
577 return DomInfo6
579 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
580 TALLOC_CTX *mem_ctx,
581 struct ldb_message **dom_msgs,
582 struct samr_DomInfo6 *info)
584 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
585 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
586 "domainReplica",
587 "");
589 return NT_STATUS_OK;
593 return DomInfo7
595 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
596 TALLOC_CTX *mem_ctx,
597 struct ldb_message **dom_msgs,
598 struct samr_DomInfo7 *info)
601 switch (state->role) {
602 case ROLE_ACTIVE_DIRECTORY_DC:
603 /* This pulls the NetBIOS name from the
604 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
605 string */
606 if (samdb_is_pdc(state->sam_ctx)) {
607 info->role = SAMR_ROLE_DOMAIN_PDC;
608 } else {
609 info->role = SAMR_ROLE_DOMAIN_BDC;
611 break;
612 case ROLE_DOMAIN_PDC:
613 case ROLE_DOMAIN_BDC:
614 case ROLE_AUTO:
615 return NT_STATUS_INTERNAL_ERROR;
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)));
988 return dsdb_ldb_err_to_ntstatus(ret);
991 return NT_STATUS_OK;
995 samr_CreateDomainGroup
997 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
998 struct samr_CreateDomainGroup *r)
1000 NTSTATUS status;
1001 struct samr_domain_state *d_state;
1002 struct samr_account_state *a_state;
1003 struct dcesrv_handle *h;
1004 const char *groupname;
1005 struct dom_sid *group_sid;
1006 struct ldb_dn *group_dn;
1007 struct dcesrv_handle *g_handle;
1009 ZERO_STRUCTP(r->out.group_handle);
1010 *r->out.rid = 0;
1012 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1014 d_state = h->data;
1016 if (d_state->builtin) {
1017 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1018 return NT_STATUS_ACCESS_DENIED;
1021 groupname = r->in.name->string;
1023 if (groupname == NULL) {
1024 return NT_STATUS_INVALID_PARAMETER;
1027 status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 return status;
1032 a_state = talloc(mem_ctx, struct samr_account_state);
1033 if (!a_state) {
1034 return NT_STATUS_NO_MEMORY;
1036 a_state->sam_ctx = d_state->sam_ctx;
1037 a_state->access_mask = r->in.access_mask;
1038 a_state->domain_state = talloc_reference(a_state, d_state);
1039 a_state->account_dn = talloc_steal(a_state, group_dn);
1041 a_state->account_name = talloc_steal(a_state, groupname);
1043 /* create the policy handle */
1044 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1045 if (!g_handle) {
1046 return NT_STATUS_NO_MEMORY;
1049 g_handle->data = talloc_steal(g_handle, a_state);
1051 *r->out.group_handle = g_handle->wire_handle;
1052 *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1054 return NT_STATUS_OK;
1059 comparison function for sorting SamEntry array
1061 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1063 return e1->idx - e2->idx;
1067 samr_EnumDomainGroups
1069 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1070 struct samr_EnumDomainGroups *r)
1072 struct dcesrv_handle *h;
1073 struct samr_domain_state *d_state;
1074 struct ldb_message **res;
1075 int i, ldb_cnt;
1076 uint32_t first, count;
1077 struct samr_SamEntry *entries;
1078 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1079 struct samr_SamArray *sam;
1081 *r->out.resume_handle = 0;
1082 *r->out.sam = NULL;
1083 *r->out.num_entries = 0;
1085 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1087 d_state = h->data;
1089 /* search for all domain groups in this domain. This could possibly be
1090 cached and resumed based on resume_key */
1091 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1092 d_state->domain_dn, &res, attrs,
1093 d_state->domain_sid,
1094 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1095 GTYPE_SECURITY_UNIVERSAL_GROUP,
1096 GTYPE_SECURITY_GLOBAL_GROUP);
1097 if (ldb_cnt < 0) {
1098 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1101 /* convert to SamEntry format */
1102 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1103 if (!entries) {
1104 return NT_STATUS_NO_MEMORY;
1107 count = 0;
1109 for (i=0;i<ldb_cnt;i++) {
1110 struct dom_sid *group_sid;
1112 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1113 "objectSid");
1114 if (group_sid == NULL) {
1115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1118 entries[count].idx =
1119 group_sid->sub_auths[group_sid->num_auths-1];
1120 entries[count].name.string =
1121 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1122 count += 1;
1125 /* sort the results by rid */
1126 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1128 /* find the first entry to return */
1129 for (first=0;
1130 first<count && entries[first].idx <= *r->in.resume_handle;
1131 first++) ;
1133 /* return the rest, limit by max_size. Note that we
1134 use the w2k3 element size value of 54 */
1135 *r->out.num_entries = count - first;
1136 *r->out.num_entries = MIN(*r->out.num_entries,
1137 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1139 sam = talloc(mem_ctx, struct samr_SamArray);
1140 if (!sam) {
1141 return NT_STATUS_NO_MEMORY;
1144 sam->entries = entries+first;
1145 sam->count = *r->out.num_entries;
1147 *r->out.sam = sam;
1149 if (first == count) {
1150 return NT_STATUS_OK;
1153 if (*r->out.num_entries < count - first) {
1154 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1155 return STATUS_MORE_ENTRIES;
1158 return NT_STATUS_OK;
1163 samr_CreateUser2
1165 This call uses transactions to ensure we don't get a new conflicting
1166 user while we are processing this, and to ensure the user either
1167 completly exists, or does not.
1169 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1170 struct samr_CreateUser2 *r)
1172 NTSTATUS status;
1173 struct samr_domain_state *d_state;
1174 struct samr_account_state *a_state;
1175 struct dcesrv_handle *h;
1176 struct ldb_dn *dn;
1177 struct dom_sid *sid;
1178 struct dcesrv_handle *u_handle;
1179 const char *account_name;
1181 ZERO_STRUCTP(r->out.user_handle);
1182 *r->out.access_granted = 0;
1183 *r->out.rid = 0;
1185 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1187 d_state = h->data;
1189 if (d_state->builtin) {
1190 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1191 return NT_STATUS_ACCESS_DENIED;
1192 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1193 /* Domain trust accounts must be created by the LSA calls */
1194 return NT_STATUS_ACCESS_DENIED;
1196 account_name = r->in.account_name->string;
1198 if (account_name == NULL) {
1199 return NT_STATUS_INVALID_PARAMETER;
1202 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
1203 &sid, &dn);
1204 if (!NT_STATUS_IS_OK(status)) {
1205 return status;
1207 a_state = talloc(mem_ctx, struct samr_account_state);
1208 if (!a_state) {
1209 return NT_STATUS_NO_MEMORY;
1211 a_state->sam_ctx = d_state->sam_ctx;
1212 a_state->access_mask = r->in.access_mask;
1213 a_state->domain_state = talloc_reference(a_state, d_state);
1214 a_state->account_dn = talloc_steal(a_state, dn);
1216 a_state->account_name = talloc_steal(a_state, account_name);
1217 if (!a_state->account_name) {
1218 return NT_STATUS_NO_MEMORY;
1221 /* create the policy handle */
1222 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1223 if (!u_handle) {
1224 return NT_STATUS_NO_MEMORY;
1227 u_handle->data = talloc_steal(u_handle, a_state);
1229 *r->out.user_handle = u_handle->wire_handle;
1230 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1232 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1234 return NT_STATUS_OK;
1239 samr_CreateUser
1241 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1242 struct samr_CreateUser *r)
1244 struct samr_CreateUser2 r2;
1245 uint32_t access_granted = 0;
1248 /* a simple wrapper around samr_CreateUser2 works nicely */
1250 r2 = (struct samr_CreateUser2) {
1251 .in.domain_handle = r->in.domain_handle,
1252 .in.account_name = r->in.account_name,
1253 .in.acct_flags = ACB_NORMAL,
1254 .in.access_mask = r->in.access_mask,
1255 .out.user_handle = r->out.user_handle,
1256 .out.access_granted = &access_granted,
1257 .out.rid = r->out.rid
1260 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1264 samr_EnumDomainUsers
1266 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1267 struct samr_EnumDomainUsers *r)
1269 struct dcesrv_handle *h;
1270 struct samr_domain_state *d_state;
1271 struct ldb_message **res;
1272 int i, ldb_cnt;
1273 uint32_t first, count;
1274 struct samr_SamEntry *entries;
1275 const char * const attrs[] = { "objectSid", "sAMAccountName",
1276 "userAccountControl", NULL };
1277 struct samr_SamArray *sam;
1279 *r->out.resume_handle = 0;
1280 *r->out.sam = NULL;
1281 *r->out.num_entries = 0;
1283 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1285 d_state = h->data;
1287 /* search for all domain users in this domain. This could possibly be
1288 cached and resumed on resume_key */
1289 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1290 d_state->domain_dn,
1291 &res, attrs,
1292 d_state->domain_sid,
1293 "(objectClass=user)");
1294 if (ldb_cnt < 0) {
1295 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1298 /* convert to SamEntry format */
1299 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1300 if (!entries) {
1301 return NT_STATUS_NO_MEMORY;
1304 count = 0;
1306 for (i=0;i<ldb_cnt;i++) {
1307 /* Check if a mask has been requested */
1308 if (r->in.acct_flags
1309 && ((samdb_result_acct_flags(res[i], NULL) & 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 char *filter;
1529 const char * const attrs[] = { "objectSid", NULL };
1530 struct ldb_message **res;
1531 uint32_t i;
1532 int count = 0;
1533 char membersidstr[DOM_SID_STR_BUFLEN];
1535 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1537 d_state = h->data;
1539 filter = talloc_asprintf(mem_ctx,
1540 "(&(|(grouptype=%d)(grouptype=%d))"
1541 "(objectclass=group)(|",
1542 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1543 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1544 if (filter == NULL) {
1545 return NT_STATUS_NO_MEMORY;
1548 for (i=0; i<r->in.sids->num_sids; i++) {
1549 dom_sid_string_buf(r->in.sids->sids[i].sid,
1550 membersidstr, sizeof(membersidstr));
1552 filter = talloc_asprintf_append(filter, "(member=<SID=%s>)",
1553 membersidstr);
1554 if (filter == NULL) {
1555 return NT_STATUS_NO_MEMORY;
1559 /* Find out if we had at least one valid member SID passed - otherwise
1560 * just skip the search. */
1561 if (strstr(filter, "member") != NULL) {
1562 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1563 &res, attrs, d_state->domain_sid,
1564 "%s))", filter);
1565 if (count < 0) {
1566 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1570 r->out.rids->count = 0;
1571 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1572 if (r->out.rids->ids == NULL)
1573 return NT_STATUS_NO_MEMORY;
1575 for (i=0; i<count; i++) {
1576 struct dom_sid *alias_sid;
1578 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1579 if (alias_sid == NULL) {
1580 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1583 r->out.rids->ids[r->out.rids->count] =
1584 alias_sid->sub_auths[alias_sid->num_auths-1];
1585 r->out.rids->count += 1;
1588 return NT_STATUS_OK;
1593 samr_LookupNames
1595 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1596 struct samr_LookupNames *r)
1598 struct dcesrv_handle *h;
1599 struct samr_domain_state *d_state;
1600 uint32_t i, num_mapped;
1601 NTSTATUS status = NT_STATUS_OK;
1602 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1603 int count;
1605 ZERO_STRUCTP(r->out.rids);
1606 ZERO_STRUCTP(r->out.types);
1608 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1610 d_state = h->data;
1612 if (r->in.num_names == 0) {
1613 return NT_STATUS_OK;
1616 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1617 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1618 if (!r->out.rids->ids || !r->out.types->ids) {
1619 return NT_STATUS_NO_MEMORY;
1621 r->out.rids->count = r->in.num_names;
1622 r->out.types->count = r->in.num_names;
1624 num_mapped = 0;
1626 for (i=0;i<r->in.num_names;i++) {
1627 struct ldb_message **res;
1628 struct dom_sid *sid;
1629 uint32_t atype, rtype;
1631 r->out.rids->ids[i] = 0;
1632 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1634 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1635 "sAMAccountName=%s",
1636 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1637 if (count != 1) {
1638 status = STATUS_SOME_UNMAPPED;
1639 continue;
1642 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1643 if (sid == NULL) {
1644 status = STATUS_SOME_UNMAPPED;
1645 continue;
1648 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1649 if (atype == 0) {
1650 status = STATUS_SOME_UNMAPPED;
1651 continue;
1654 rtype = ds_atype_map(atype);
1656 if (rtype == SID_NAME_UNKNOWN) {
1657 status = STATUS_SOME_UNMAPPED;
1658 continue;
1661 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1662 r->out.types->ids[i] = rtype;
1663 num_mapped++;
1666 if (num_mapped == 0) {
1667 return NT_STATUS_NONE_MAPPED;
1669 return status;
1674 samr_LookupRids
1676 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1677 struct samr_LookupRids *r)
1679 NTSTATUS status;
1680 struct dcesrv_handle *h;
1681 struct samr_domain_state *d_state;
1682 const char **names;
1683 struct lsa_String *lsa_names;
1684 enum lsa_SidType *ids;
1686 ZERO_STRUCTP(r->out.names);
1687 ZERO_STRUCTP(r->out.types);
1689 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1691 d_state = h->data;
1693 if (r->in.num_rids == 0)
1694 return NT_STATUS_OK;
1696 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1697 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1698 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1700 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1701 return NT_STATUS_NO_MEMORY;
1703 r->out.names->names = lsa_names;
1704 r->out.names->count = r->in.num_rids;
1706 r->out.types->ids = (uint32_t *) ids;
1707 r->out.types->count = r->in.num_rids;
1709 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1710 r->in.num_rids, r->in.rids, names, ids);
1711 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1712 uint32_t i;
1713 for (i = 0; i < r->in.num_rids; i++) {
1714 lsa_names[i].string = names[i];
1717 return status;
1722 samr_OpenGroup
1724 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1725 struct samr_OpenGroup *r)
1727 struct samr_domain_state *d_state;
1728 struct samr_account_state *a_state;
1729 struct dcesrv_handle *h;
1730 const char *groupname;
1731 struct dom_sid *sid;
1732 struct ldb_message **msgs;
1733 struct dcesrv_handle *g_handle;
1734 const char * const attrs[2] = { "sAMAccountName", NULL };
1735 int ret;
1737 ZERO_STRUCTP(r->out.group_handle);
1739 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1741 d_state = h->data;
1743 /* form the group SID */
1744 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1745 if (!sid) {
1746 return NT_STATUS_NO_MEMORY;
1749 /* search for the group record */
1750 if (d_state->builtin) {
1751 ret = gendb_search(d_state->sam_ctx,
1752 mem_ctx, d_state->domain_dn, &msgs, attrs,
1753 "(&(objectSid=%s)(objectClass=group)"
1754 "(groupType=%d))",
1755 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1756 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
1757 } else {
1758 ret = gendb_search(d_state->sam_ctx,
1759 mem_ctx, d_state->domain_dn, &msgs, attrs,
1760 "(&(objectSid=%s)(objectClass=group)"
1761 "(|(groupType=%d)(groupType=%d)))",
1762 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1763 GTYPE_SECURITY_UNIVERSAL_GROUP,
1764 GTYPE_SECURITY_GLOBAL_GROUP);
1766 if (ret == 0) {
1767 return NT_STATUS_NO_SUCH_GROUP;
1769 if (ret != 1) {
1770 DEBUG(0,("Found %d records matching sid %s\n",
1771 ret, dom_sid_string(mem_ctx, sid)));
1772 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1775 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1776 if (groupname == NULL) {
1777 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1778 dom_sid_string(mem_ctx, sid)));
1779 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1782 a_state = talloc(mem_ctx, struct samr_account_state);
1783 if (!a_state) {
1784 return NT_STATUS_NO_MEMORY;
1786 a_state->sam_ctx = d_state->sam_ctx;
1787 a_state->access_mask = r->in.access_mask;
1788 a_state->domain_state = talloc_reference(a_state, d_state);
1789 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1790 a_state->account_sid = talloc_steal(a_state, sid);
1791 a_state->account_name = talloc_strdup(a_state, groupname);
1792 if (!a_state->account_name) {
1793 return NT_STATUS_NO_MEMORY;
1796 /* create the policy handle */
1797 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1798 if (!g_handle) {
1799 return NT_STATUS_NO_MEMORY;
1802 g_handle->data = talloc_steal(g_handle, a_state);
1804 *r->out.group_handle = g_handle->wire_handle;
1806 return NT_STATUS_OK;
1810 samr_QueryGroupInfo
1812 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1813 struct samr_QueryGroupInfo *r)
1815 struct dcesrv_handle *h;
1816 struct samr_account_state *a_state;
1817 struct ldb_message *msg, **res;
1818 const char * const attrs[4] = { "sAMAccountName", "description",
1819 "numMembers", NULL };
1820 int ret;
1821 union samr_GroupInfo *info;
1823 *r->out.info = NULL;
1825 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1827 a_state = h->data;
1829 /* pull all the group attributes */
1830 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1831 a_state->account_dn, &res, attrs);
1832 if (ret == 0) {
1833 return NT_STATUS_NO_SUCH_GROUP;
1835 if (ret != 1) {
1836 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1838 msg = res[0];
1840 /* allocate the info structure */
1841 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1842 if (info == NULL) {
1843 return NT_STATUS_NO_MEMORY;
1846 /* Fill in the level */
1847 switch (r->in.level) {
1848 case GROUPINFOALL:
1849 QUERY_STRING(msg, all.name, "sAMAccountName");
1850 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1851 QUERY_UINT (msg, all.num_members, "numMembers")
1852 QUERY_STRING(msg, all.description, "description");
1853 break;
1854 case GROUPINFONAME:
1855 QUERY_STRING(msg, name, "sAMAccountName");
1856 break;
1857 case GROUPINFOATTRIBUTES:
1858 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1859 break;
1860 case GROUPINFODESCRIPTION:
1861 QUERY_STRING(msg, description, "description");
1862 break;
1863 case GROUPINFOALL2:
1864 QUERY_STRING(msg, all2.name, "sAMAccountName");
1865 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1866 QUERY_UINT (msg, all2.num_members, "numMembers")
1867 QUERY_STRING(msg, all2.description, "description");
1868 break;
1869 default:
1870 talloc_free(info);
1871 return NT_STATUS_INVALID_INFO_CLASS;
1874 *r->out.info = info;
1876 return NT_STATUS_OK;
1881 samr_SetGroupInfo
1883 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1884 struct samr_SetGroupInfo *r)
1886 struct dcesrv_handle *h;
1887 struct samr_account_state *g_state;
1888 struct ldb_message *msg;
1889 int ret;
1891 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1893 g_state = h->data;
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 return dsdb_ldb_err_to_ntstatus(ret);
1927 return NT_STATUS_OK;
1932 samr_AddGroupMember
1934 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1935 struct samr_AddGroupMember *r)
1937 struct dcesrv_handle *h;
1938 struct samr_account_state *a_state;
1939 struct samr_domain_state *d_state;
1940 struct ldb_message *mod;
1941 struct dom_sid *membersid;
1942 const char *memberdn;
1943 struct ldb_result *res;
1944 const char * const attrs[] = { NULL };
1945 int ret;
1947 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1949 a_state = h->data;
1950 d_state = a_state->domain_state;
1952 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1953 if (membersid == NULL) {
1954 return NT_STATUS_NO_MEMORY;
1957 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1958 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1959 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1960 "(objectSid=%s)",
1961 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1963 if (ret != LDB_SUCCESS) {
1964 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1967 if (res->count == 0) {
1968 return NT_STATUS_NO_SUCH_USER;
1971 if (res->count > 1) {
1972 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1975 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1977 if (memberdn == NULL)
1978 return NT_STATUS_NO_MEMORY;
1980 mod = ldb_msg_new(mem_ctx);
1981 if (mod == NULL) {
1982 return NT_STATUS_NO_MEMORY;
1985 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1987 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1988 memberdn);
1989 if (ret != LDB_SUCCESS) {
1990 return dsdb_ldb_err_to_ntstatus(ret);
1993 ret = ldb_modify(a_state->sam_ctx, mod);
1994 switch (ret) {
1995 case LDB_SUCCESS:
1996 return NT_STATUS_OK;
1997 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1998 return NT_STATUS_MEMBER_IN_GROUP;
1999 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2000 return NT_STATUS_ACCESS_DENIED;
2001 default:
2002 return dsdb_ldb_err_to_ntstatus(ret);
2008 samr_DeleteDomainGroup
2010 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2011 struct samr_DeleteDomainGroup *r)
2013 struct dcesrv_handle *h;
2014 struct samr_account_state *a_state;
2015 int ret;
2017 *r->out.group_handle = *r->in.group_handle;
2019 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2021 a_state = h->data;
2023 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2024 if (ret != LDB_SUCCESS) {
2025 return dsdb_ldb_err_to_ntstatus(ret);
2028 talloc_free(h);
2029 ZERO_STRUCTP(r->out.group_handle);
2031 return NT_STATUS_OK;
2036 samr_DeleteGroupMember
2038 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2039 struct samr_DeleteGroupMember *r)
2041 struct dcesrv_handle *h;
2042 struct samr_account_state *a_state;
2043 struct samr_domain_state *d_state;
2044 struct ldb_message *mod;
2045 struct dom_sid *membersid;
2046 const char *memberdn;
2047 struct ldb_result *res;
2048 const char * const attrs[] = { NULL };
2049 int ret;
2051 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2053 a_state = h->data;
2054 d_state = a_state->domain_state;
2056 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2057 if (membersid == NULL) {
2058 return NT_STATUS_NO_MEMORY;
2061 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2062 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2063 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2064 "(objectSid=%s)",
2065 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2067 if (ret != LDB_SUCCESS) {
2068 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2071 if (res->count == 0) {
2072 return NT_STATUS_NO_SUCH_USER;
2075 if (res->count > 1) {
2076 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2079 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2081 if (memberdn == NULL)
2082 return NT_STATUS_NO_MEMORY;
2084 mod = ldb_msg_new(mem_ctx);
2085 if (mod == NULL) {
2086 return NT_STATUS_NO_MEMORY;
2089 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2091 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2092 memberdn);
2093 if (ret != LDB_SUCCESS) {
2094 return NT_STATUS_NO_MEMORY;
2097 ret = ldb_modify(a_state->sam_ctx, mod);
2098 switch (ret) {
2099 case LDB_SUCCESS:
2100 return NT_STATUS_OK;
2101 case LDB_ERR_UNWILLING_TO_PERFORM:
2102 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2103 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2104 return NT_STATUS_ACCESS_DENIED;
2105 default:
2106 return dsdb_ldb_err_to_ntstatus(ret);
2112 samr_QueryGroupMember
2114 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2115 struct samr_QueryGroupMember *r)
2117 struct dcesrv_handle *h;
2118 struct samr_account_state *a_state;
2119 struct samr_domain_state *d_state;
2120 struct samr_RidAttrArray *array;
2121 unsigned int i, num_members;
2122 struct dom_sid *members;
2123 NTSTATUS status;
2125 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2127 a_state = h->data;
2128 d_state = a_state->domain_state;
2130 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2131 a_state->account_dn, &members,
2132 &num_members);
2133 if (!NT_STATUS_IS_OK(status)) {
2134 return status;
2137 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2138 if (array == NULL) {
2139 return NT_STATUS_NO_MEMORY;
2142 if (num_members == 0) {
2143 *r->out.rids = array;
2145 return NT_STATUS_OK;
2148 array->rids = talloc_array(array, uint32_t, num_members);
2149 if (array->rids == NULL) {
2150 return NT_STATUS_NO_MEMORY;
2153 array->attributes = talloc_array(array, uint32_t, num_members);
2154 if (array->attributes == NULL) {
2155 return NT_STATUS_NO_MEMORY;
2158 array->count = 0;
2159 for (i=0; i<num_members; i++) {
2160 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2161 continue;
2164 status = dom_sid_split_rid(NULL, &members[i], NULL,
2165 &array->rids[array->count]);
2166 if (!NT_STATUS_IS_OK(status)) {
2167 return status;
2170 array->attributes[array->count] = SE_GROUP_MANDATORY |
2171 SE_GROUP_ENABLED_BY_DEFAULT |
2172 SE_GROUP_ENABLED;
2173 array->count++;
2176 *r->out.rids = array;
2178 return NT_STATUS_OK;
2183 samr_SetMemberAttributesOfGroup
2185 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2186 struct samr_SetMemberAttributesOfGroup *r)
2188 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2193 samr_OpenAlias
2195 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2196 struct samr_OpenAlias *r)
2198 struct samr_domain_state *d_state;
2199 struct samr_account_state *a_state;
2200 struct dcesrv_handle *h;
2201 const char *alias_name;
2202 struct dom_sid *sid;
2203 struct ldb_message **msgs;
2204 struct dcesrv_handle *g_handle;
2205 const char * const attrs[2] = { "sAMAccountName", NULL };
2206 int ret;
2208 ZERO_STRUCTP(r->out.alias_handle);
2210 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2212 d_state = h->data;
2214 /* form the alias SID */
2215 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2216 if (sid == NULL)
2217 return NT_STATUS_NO_MEMORY;
2219 /* search for the group record */
2220 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2221 "(&(objectSid=%s)(objectclass=group)"
2222 "(|(grouptype=%d)(grouptype=%d)))",
2223 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2224 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2225 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2226 if (ret == 0) {
2227 return NT_STATUS_NO_SUCH_ALIAS;
2229 if (ret != 1) {
2230 DEBUG(0,("Found %d records matching sid %s\n",
2231 ret, dom_sid_string(mem_ctx, sid)));
2232 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2235 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2236 if (alias_name == NULL) {
2237 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2238 dom_sid_string(mem_ctx, sid)));
2239 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2242 a_state = talloc(mem_ctx, struct samr_account_state);
2243 if (!a_state) {
2244 return NT_STATUS_NO_MEMORY;
2246 a_state->sam_ctx = d_state->sam_ctx;
2247 a_state->access_mask = r->in.access_mask;
2248 a_state->domain_state = talloc_reference(a_state, d_state);
2249 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2250 a_state->account_sid = talloc_steal(a_state, sid);
2251 a_state->account_name = talloc_strdup(a_state, alias_name);
2252 if (!a_state->account_name) {
2253 return NT_STATUS_NO_MEMORY;
2256 /* create the policy handle */
2257 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2258 if (!g_handle) {
2259 return NT_STATUS_NO_MEMORY;
2262 g_handle->data = talloc_steal(g_handle, a_state);
2264 *r->out.alias_handle = g_handle->wire_handle;
2266 return NT_STATUS_OK;
2271 samr_QueryAliasInfo
2273 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2274 struct samr_QueryAliasInfo *r)
2276 struct dcesrv_handle *h;
2277 struct samr_account_state *a_state;
2278 struct ldb_message *msg, **res;
2279 const char * const attrs[4] = { "sAMAccountName", "description",
2280 "numMembers", NULL };
2281 int ret;
2282 union samr_AliasInfo *info;
2284 *r->out.info = NULL;
2286 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2288 a_state = h->data;
2290 /* pull all the alias attributes */
2291 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2292 a_state->account_dn, &res, attrs);
2293 if (ret == 0) {
2294 return NT_STATUS_NO_SUCH_ALIAS;
2296 if (ret != 1) {
2297 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2299 msg = res[0];
2301 /* allocate the info structure */
2302 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2303 if (info == NULL) {
2304 return NT_STATUS_NO_MEMORY;
2307 switch(r->in.level) {
2308 case ALIASINFOALL:
2309 QUERY_STRING(msg, all.name, "sAMAccountName");
2310 QUERY_UINT (msg, all.num_members, "numMembers");
2311 QUERY_STRING(msg, all.description, "description");
2312 break;
2313 case ALIASINFONAME:
2314 QUERY_STRING(msg, name, "sAMAccountName");
2315 break;
2316 case ALIASINFODESCRIPTION:
2317 QUERY_STRING(msg, description, "description");
2318 break;
2319 default:
2320 talloc_free(info);
2321 return NT_STATUS_INVALID_INFO_CLASS;
2324 *r->out.info = info;
2326 return NT_STATUS_OK;
2331 samr_SetAliasInfo
2333 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2334 struct samr_SetAliasInfo *r)
2336 struct dcesrv_handle *h;
2337 struct samr_account_state *a_state;
2338 struct ldb_message *msg;
2339 int ret;
2341 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2343 a_state = h->data;
2345 msg = ldb_msg_new(mem_ctx);
2346 if (msg == NULL) {
2347 return NT_STATUS_NO_MEMORY;
2350 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2351 if (!msg->dn) {
2352 return NT_STATUS_NO_MEMORY;
2355 switch (r->in.level) {
2356 case ALIASINFODESCRIPTION:
2357 SET_STRING(msg, description, "description");
2358 break;
2359 case ALIASINFONAME:
2360 /* On W2k3 this does not change the name, it changes the
2361 * sAMAccountName attribute */
2362 SET_STRING(msg, name, "sAMAccountName");
2363 break;
2364 default:
2365 return NT_STATUS_INVALID_INFO_CLASS;
2368 /* modify the samdb record */
2369 ret = ldb_modify(a_state->sam_ctx, msg);
2370 if (ret != LDB_SUCCESS) {
2371 return dsdb_ldb_err_to_ntstatus(ret);
2374 return NT_STATUS_OK;
2379 samr_DeleteDomAlias
2381 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2382 struct samr_DeleteDomAlias *r)
2384 struct dcesrv_handle *h;
2385 struct samr_account_state *a_state;
2386 int ret;
2388 *r->out.alias_handle = *r->in.alias_handle;
2390 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2392 a_state = h->data;
2394 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2395 if (ret != LDB_SUCCESS) {
2396 return dsdb_ldb_err_to_ntstatus(ret);
2399 talloc_free(h);
2400 ZERO_STRUCTP(r->out.alias_handle);
2402 return NT_STATUS_OK;
2407 samr_AddAliasMember
2409 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2410 struct samr_AddAliasMember *r)
2412 struct dcesrv_handle *h;
2413 struct samr_account_state *a_state;
2414 struct samr_domain_state *d_state;
2415 struct ldb_message *mod;
2416 struct ldb_message **msgs;
2417 const char * const attrs[] = { NULL };
2418 struct ldb_dn *memberdn = NULL;
2419 int ret;
2420 NTSTATUS status;
2422 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2424 a_state = h->data;
2425 d_state = a_state->domain_state;
2427 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2428 &msgs, attrs, "(objectsid=%s)",
2429 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2431 if (ret == 1) {
2432 memberdn = msgs[0]->dn;
2433 } else if (ret == 0) {
2434 status = samdb_create_foreign_security_principal(
2435 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2436 if (!NT_STATUS_IS_OK(status)) {
2437 return status;
2439 } else {
2440 DEBUG(0,("Found %d records matching sid %s\n",
2441 ret, dom_sid_string(mem_ctx, r->in.sid)));
2442 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2445 if (memberdn == NULL) {
2446 DEBUG(0, ("Could not find memberdn\n"));
2447 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2450 mod = ldb_msg_new(mem_ctx);
2451 if (mod == NULL) {
2452 return NT_STATUS_NO_MEMORY;
2455 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2457 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2458 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2459 if (ret != LDB_SUCCESS) {
2460 return dsdb_ldb_err_to_ntstatus(ret);
2463 ret = ldb_modify(a_state->sam_ctx, mod);
2464 switch (ret) {
2465 case LDB_SUCCESS:
2466 return NT_STATUS_OK;
2467 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2468 return NT_STATUS_MEMBER_IN_GROUP;
2469 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2470 return NT_STATUS_ACCESS_DENIED;
2471 default:
2472 return dsdb_ldb_err_to_ntstatus(ret);
2478 samr_DeleteAliasMember
2480 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2481 struct samr_DeleteAliasMember *r)
2483 struct dcesrv_handle *h;
2484 struct samr_account_state *a_state;
2485 struct samr_domain_state *d_state;
2486 struct ldb_message *mod;
2487 const char *memberdn;
2488 int ret;
2490 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2492 a_state = h->data;
2493 d_state = a_state->domain_state;
2495 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2496 "distinguishedName", "(objectSid=%s)",
2497 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2498 if (memberdn == NULL) {
2499 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2502 mod = ldb_msg_new(mem_ctx);
2503 if (mod == NULL) {
2504 return NT_STATUS_NO_MEMORY;
2507 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2509 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2510 memberdn);
2511 if (ret != LDB_SUCCESS) {
2512 return dsdb_ldb_err_to_ntstatus(ret);
2515 ret = ldb_modify(a_state->sam_ctx, mod);
2516 switch (ret) {
2517 case LDB_SUCCESS:
2518 return NT_STATUS_OK;
2519 case LDB_ERR_UNWILLING_TO_PERFORM:
2520 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2521 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2522 return NT_STATUS_ACCESS_DENIED;
2523 default:
2524 return dsdb_ldb_err_to_ntstatus(ret);
2530 samr_GetMembersInAlias
2532 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2533 struct samr_GetMembersInAlias *r)
2535 struct dcesrv_handle *h;
2536 struct samr_account_state *a_state;
2537 struct samr_domain_state *d_state;
2538 struct lsa_SidPtr *array;
2539 unsigned int i, num_members;
2540 struct dom_sid *members;
2541 NTSTATUS status;
2543 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2545 a_state = h->data;
2546 d_state = a_state->domain_state;
2548 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2549 a_state->account_dn, &members,
2550 &num_members);
2551 if (!NT_STATUS_IS_OK(status)) {
2552 return status;
2555 if (num_members == 0) {
2556 r->out.sids->sids = NULL;
2558 return NT_STATUS_OK;
2561 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2562 if (array == NULL) {
2563 return NT_STATUS_NO_MEMORY;
2566 for (i=0; i<num_members; i++) {
2567 array[i].sid = &members[i];
2570 r->out.sids->num_sids = num_members;
2571 r->out.sids->sids = array;
2573 return NT_STATUS_OK;
2577 samr_OpenUser
2579 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2580 struct samr_OpenUser *r)
2582 struct samr_domain_state *d_state;
2583 struct samr_account_state *a_state;
2584 struct dcesrv_handle *h;
2585 const char *account_name;
2586 struct dom_sid *sid;
2587 struct ldb_message **msgs;
2588 struct dcesrv_handle *u_handle;
2589 const char * const attrs[2] = { "sAMAccountName", NULL };
2590 int ret;
2592 ZERO_STRUCTP(r->out.user_handle);
2594 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2596 d_state = h->data;
2598 /* form the users SID */
2599 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2600 if (!sid) {
2601 return NT_STATUS_NO_MEMORY;
2604 /* search for the user record */
2605 ret = gendb_search(d_state->sam_ctx,
2606 mem_ctx, d_state->domain_dn, &msgs, attrs,
2607 "(&(objectSid=%s)(objectclass=user))",
2608 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2609 if (ret == 0) {
2610 return NT_STATUS_NO_SUCH_USER;
2612 if (ret != 1) {
2613 DEBUG(0,("Found %d records matching sid %s\n", ret,
2614 dom_sid_string(mem_ctx, sid)));
2615 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2618 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2619 if (account_name == NULL) {
2620 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2621 dom_sid_string(mem_ctx, sid)));
2622 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2625 a_state = talloc(mem_ctx, struct samr_account_state);
2626 if (!a_state) {
2627 return NT_STATUS_NO_MEMORY;
2629 a_state->sam_ctx = d_state->sam_ctx;
2630 a_state->access_mask = r->in.access_mask;
2631 a_state->domain_state = talloc_reference(a_state, d_state);
2632 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2633 a_state->account_sid = talloc_steal(a_state, sid);
2634 a_state->account_name = talloc_strdup(a_state, account_name);
2635 if (!a_state->account_name) {
2636 return NT_STATUS_NO_MEMORY;
2639 /* create the policy handle */
2640 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2641 if (!u_handle) {
2642 return NT_STATUS_NO_MEMORY;
2645 u_handle->data = talloc_steal(u_handle, a_state);
2647 *r->out.user_handle = u_handle->wire_handle;
2649 return NT_STATUS_OK;
2655 samr_DeleteUser
2657 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2658 struct samr_DeleteUser *r)
2660 struct dcesrv_handle *h;
2661 struct samr_account_state *a_state;
2662 int ret;
2664 *r->out.user_handle = *r->in.user_handle;
2666 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2668 a_state = h->data;
2670 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2671 if (ret != LDB_SUCCESS) {
2672 DEBUG(1, ("Failed to delete user: %s: %s\n",
2673 ldb_dn_get_linearized(a_state->account_dn),
2674 ldb_errstring(a_state->sam_ctx)));
2675 return dsdb_ldb_err_to_ntstatus(ret);
2678 talloc_free(h);
2679 ZERO_STRUCTP(r->out.user_handle);
2681 return NT_STATUS_OK;
2686 samr_QueryUserInfo
2688 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2689 struct samr_QueryUserInfo *r)
2691 struct dcesrv_handle *h;
2692 struct samr_account_state *a_state;
2693 struct ldb_message *msg, **res;
2694 int ret;
2695 struct ldb_context *sam_ctx;
2697 const char * const *attrs = NULL;
2698 union samr_UserInfo *info;
2700 NTSTATUS status;
2702 *r->out.info = NULL;
2704 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2706 a_state = h->data;
2707 sam_ctx = a_state->sam_ctx;
2709 /* fill in the reply */
2710 switch (r->in.level) {
2711 case 1:
2713 static const char * const attrs2[] = {"sAMAccountName",
2714 "displayName",
2715 "primaryroupID",
2716 "description",
2717 "comment",
2718 NULL};
2719 attrs = attrs2;
2720 break;
2722 case 2:
2724 static const char * const attrs2[] = {"comment",
2725 "countryCode",
2726 "codePage",
2727 NULL};
2728 attrs = attrs2;
2729 break;
2731 case 3:
2733 static const char * const attrs2[] = {"sAMAccountName",
2734 "displayName",
2735 "objectSid",
2736 "primaryGroupID",
2737 "homeDirectory",
2738 "homeDrive",
2739 "scriptPath",
2740 "profilePath",
2741 "userWorkstations",
2742 "lastLogon",
2743 "lastLogoff",
2744 "pwdLastSet",
2745 "logonHours",
2746 "badPwdCount",
2747 "badPasswordTime",
2748 "logonCount",
2749 "userAccountControl",
2750 "msDS-User-Account-Control-Computed",
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 "badPasswordTime",
2779 "logonCount",
2780 "pwdLastSet",
2781 "accountExpires",
2782 "userAccountControl",
2783 "msDS-User-Account-Control-Computed",
2784 NULL};
2785 attrs = attrs2;
2786 break;
2788 case 6:
2790 static const char * const attrs2[] = {"sAMAccountName",
2791 "displayName",
2792 NULL};
2793 attrs = attrs2;
2794 break;
2796 case 7:
2798 static const char * const attrs2[] = {"sAMAccountName",
2799 NULL};
2800 attrs = attrs2;
2801 break;
2803 case 8:
2805 static const char * const attrs2[] = {"displayName",
2806 NULL};
2807 attrs = attrs2;
2808 break;
2810 case 9:
2812 static const char * const attrs2[] = {"primaryGroupID",
2813 NULL};
2814 attrs = attrs2;
2815 break;
2817 case 10:
2819 static const char * const attrs2[] = {"homeDirectory",
2820 "homeDrive",
2821 NULL};
2822 attrs = attrs2;
2823 break;
2825 case 11:
2827 static const char * const attrs2[] = {"scriptPath",
2828 NULL};
2829 attrs = attrs2;
2830 break;
2832 case 12:
2834 static const char * const attrs2[] = {"profilePath",
2835 NULL};
2836 attrs = attrs2;
2837 break;
2839 case 13:
2841 static const char * const attrs2[] = {"description",
2842 NULL};
2843 attrs = attrs2;
2844 break;
2846 case 14:
2848 static const char * const attrs2[] = {"userWorkstations",
2849 NULL};
2850 attrs = attrs2;
2851 break;
2853 case 16:
2855 static const char * const attrs2[] = {"userAccountControl",
2856 "msDS-User-Account-Control-Computed",
2857 "pwdLastSet",
2858 NULL};
2859 attrs = attrs2;
2860 break;
2862 case 17:
2864 static const char * const attrs2[] = {"accountExpires",
2865 NULL};
2866 attrs = attrs2;
2867 break;
2869 case 18:
2871 return NT_STATUS_NOT_SUPPORTED;
2873 case 20:
2875 static const char * const attrs2[] = {"userParameters",
2876 NULL};
2877 attrs = attrs2;
2878 break;
2880 case 21:
2882 static const char * const attrs2[] = {"lastLogon",
2883 "lastLogoff",
2884 "pwdLastSet",
2885 "accountExpires",
2886 "sAMAccountName",
2887 "displayName",
2888 "homeDirectory",
2889 "homeDrive",
2890 "scriptPath",
2891 "profilePath",
2892 "description",
2893 "userWorkstations",
2894 "comment",
2895 "userParameters",
2896 "objectSid",
2897 "primaryGroupID",
2898 "userAccountControl",
2899 "msDS-User-Account-Control-Computed",
2900 "logonHours",
2901 "badPwdCount",
2902 "badPasswordTime",
2903 "logonCount",
2904 "countryCode",
2905 "codePage",
2906 NULL};
2907 attrs = attrs2;
2908 break;
2910 case 23:
2911 case 24:
2912 case 25:
2913 case 26:
2915 return NT_STATUS_NOT_SUPPORTED;
2917 default:
2919 return NT_STATUS_INVALID_INFO_CLASS;
2923 /* pull all the user attributes */
2924 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2925 a_state->account_dn, &res, attrs);
2926 if (ret == 0) {
2927 return NT_STATUS_NO_SUCH_USER;
2929 if (ret != 1) {
2930 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2932 msg = res[0];
2934 /* allocate the info structure */
2935 info = talloc_zero(mem_ctx, union samr_UserInfo);
2936 if (info == NULL) {
2937 return NT_STATUS_NO_MEMORY;
2940 /* fill in the reply */
2941 switch (r->in.level) {
2942 case 1:
2943 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2944 QUERY_STRING(msg, info1.full_name, "displayName");
2945 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2946 QUERY_STRING(msg, info1.description, "description");
2947 QUERY_STRING(msg, info1.comment, "comment");
2948 break;
2950 case 2:
2951 QUERY_STRING(msg, info2.comment, "comment");
2952 QUERY_UINT (msg, info2.country_code, "countryCode");
2953 QUERY_UINT (msg, info2.code_page, "codePage");
2954 break;
2956 case 3:
2957 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2958 QUERY_STRING(msg, info3.full_name, "displayName");
2959 QUERY_RID (msg, info3.rid, "objectSid");
2960 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2961 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2962 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2963 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2964 QUERY_STRING(msg, info3.profile_path, "profilePath");
2965 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2966 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2967 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2968 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2969 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2970 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2971 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2972 /* level 3 gives the raw badPwdCount value */
2973 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2974 QUERY_UINT (msg, info3.logon_count, "logonCount");
2975 QUERY_AFLAGS(msg, info3.acct_flags, "msDS-User-Account-Control-Computed");
2976 break;
2978 case 4:
2979 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2980 break;
2982 case 5:
2983 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2984 QUERY_STRING(msg, info5.full_name, "displayName");
2985 QUERY_RID (msg, info5.rid, "objectSid");
2986 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2987 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2988 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2989 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2990 QUERY_STRING(msg, info5.profile_path, "profilePath");
2991 QUERY_STRING(msg, info5.description, "description");
2992 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2993 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2994 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2995 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2996 QUERY_BPWDCT(msg, info5.bad_password_count, "badPwdCount");
2997 QUERY_UINT (msg, info5.logon_count, "logonCount");
2998 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2999 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3000 QUERY_AFLAGS(msg, info5.acct_flags, "msDS-User-Account-Control-Computed");
3001 break;
3003 case 6:
3004 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3005 QUERY_STRING(msg, info6.full_name, "displayName");
3006 break;
3008 case 7:
3009 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3010 break;
3012 case 8:
3013 QUERY_STRING(msg, info8.full_name, "displayName");
3014 break;
3016 case 9:
3017 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3018 break;
3020 case 10:
3021 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3022 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3023 break;
3025 case 11:
3026 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3027 break;
3029 case 12:
3030 QUERY_STRING(msg, info12.profile_path, "profilePath");
3031 break;
3033 case 13:
3034 QUERY_STRING(msg, info13.description, "description");
3035 break;
3037 case 14:
3038 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3039 break;
3041 case 16:
3042 QUERY_AFLAGS(msg, info16.acct_flags, "msDS-User-Account-Control-Computed");
3043 break;
3045 case 17:
3046 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3047 break;
3049 case 20:
3050 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
3051 if (!NT_STATUS_IS_OK(status)) {
3052 talloc_free(info);
3053 return status;
3055 break;
3057 case 21:
3058 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3059 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3060 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3061 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3062 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3063 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3064 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3065 QUERY_STRING(msg, info21.full_name, "displayName");
3066 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3067 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3068 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3069 QUERY_STRING(msg, info21.profile_path, "profilePath");
3070 QUERY_STRING(msg, info21.description, "description");
3071 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3072 QUERY_STRING(msg, info21.comment, "comment");
3073 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
3074 if (!NT_STATUS_IS_OK(status)) {
3075 talloc_free(info);
3076 return status;
3079 QUERY_RID (msg, info21.rid, "objectSid");
3080 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3081 QUERY_AFLAGS(msg, info21.acct_flags, "msDS-User-Account-Control-Computed");
3082 info->info21.fields_present = 0x08FFFFFF;
3083 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3084 QUERY_BPWDCT(msg, info21.bad_password_count, "badPwdCount");
3085 QUERY_UINT (msg, info21.logon_count, "logonCount");
3086 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3087 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3088 } else {
3089 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3091 QUERY_UINT (msg, info21.country_code, "countryCode");
3092 QUERY_UINT (msg, info21.code_page, "codePage");
3093 break;
3096 default:
3097 talloc_free(info);
3098 return NT_STATUS_INVALID_INFO_CLASS;
3101 *r->out.info = info;
3103 return NT_STATUS_OK;
3108 samr_SetUserInfo
3110 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3111 struct samr_SetUserInfo *r)
3113 struct dcesrv_handle *h;
3114 struct samr_account_state *a_state;
3115 struct ldb_message *msg;
3116 int ret;
3117 NTSTATUS status = NT_STATUS_OK;
3118 struct ldb_context *sam_ctx;
3120 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3122 a_state = h->data;
3123 sam_ctx = a_state->sam_ctx;
3125 msg = ldb_msg_new(mem_ctx);
3126 if (msg == NULL) {
3127 return NT_STATUS_NO_MEMORY;
3130 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3131 if (!msg->dn) {
3132 return NT_STATUS_NO_MEMORY;
3135 switch (r->in.level) {
3136 case 2:
3137 SET_STRING(msg, info2.comment, "comment");
3138 SET_UINT (msg, info2.country_code, "countryCode");
3139 SET_UINT (msg, info2.code_page, "codePage");
3140 break;
3142 case 4:
3143 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3144 break;
3146 case 6:
3147 SET_STRING(msg, info6.account_name, "samAccountName");
3148 SET_STRING(msg, info6.full_name, "displayName");
3149 break;
3151 case 7:
3152 SET_STRING(msg, info7.account_name, "samAccountName");
3153 break;
3155 case 8:
3156 SET_STRING(msg, info8.full_name, "displayName");
3157 break;
3159 case 9:
3160 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3161 break;
3163 case 10:
3164 SET_STRING(msg, info10.home_directory, "homeDirectory");
3165 SET_STRING(msg, info10.home_drive, "homeDrive");
3166 break;
3168 case 11:
3169 SET_STRING(msg, info11.logon_script, "scriptPath");
3170 break;
3172 case 12:
3173 SET_STRING(msg, info12.profile_path, "profilePath");
3174 break;
3176 case 13:
3177 SET_STRING(msg, info13.description, "description");
3178 break;
3180 case 14:
3181 SET_STRING(msg, info14.workstations, "userWorkstations");
3182 break;
3184 case 16:
3185 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3186 break;
3188 case 17:
3189 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3190 break;
3192 case 18:
3193 status = samr_set_password_buffers(dce_call,
3194 a_state->sam_ctx,
3195 a_state->account_dn,
3196 a_state->domain_state->domain_dn,
3197 mem_ctx,
3198 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3199 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3200 if (!NT_STATUS_IS_OK(status)) {
3201 return status;
3204 if (r->in.info->info18.password_expired > 0) {
3205 struct ldb_message_element *set_el;
3206 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3207 return NT_STATUS_NO_MEMORY;
3209 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3210 set_el->flags = LDB_FLAG_MOD_REPLACE;
3212 break;
3214 case 20:
3215 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3216 break;
3218 case 21:
3219 if (r->in.info->info21.fields_present == 0)
3220 return NT_STATUS_INVALID_PARAMETER;
3222 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3223 IFSET(SAMR_FIELD_LAST_LOGON)
3224 SET_UINT64(msg, info21.last_logon, "lastLogon");
3225 IFSET(SAMR_FIELD_LAST_LOGOFF)
3226 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3227 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3228 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3229 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3230 SET_STRING(msg, info21.account_name, "samAccountName");
3231 IFSET(SAMR_FIELD_FULL_NAME)
3232 SET_STRING(msg, info21.full_name, "displayName");
3233 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3234 SET_STRING(msg, info21.home_directory, "homeDirectory");
3235 IFSET(SAMR_FIELD_HOME_DRIVE)
3236 SET_STRING(msg, info21.home_drive, "homeDrive");
3237 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3238 SET_STRING(msg, info21.logon_script, "scriptPath");
3239 IFSET(SAMR_FIELD_PROFILE_PATH)
3240 SET_STRING(msg, info21.profile_path, "profilePath");
3241 IFSET(SAMR_FIELD_DESCRIPTION)
3242 SET_STRING(msg, info21.description, "description");
3243 IFSET(SAMR_FIELD_WORKSTATIONS)
3244 SET_STRING(msg, info21.workstations, "userWorkstations");
3245 IFSET(SAMR_FIELD_COMMENT)
3246 SET_STRING(msg, info21.comment, "comment");
3247 IFSET(SAMR_FIELD_PARAMETERS)
3248 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3249 IFSET(SAMR_FIELD_PRIMARY_GID)
3250 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3251 IFSET(SAMR_FIELD_ACCT_FLAGS)
3252 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3253 IFSET(SAMR_FIELD_LOGON_HOURS)
3254 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3255 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3256 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3257 IFSET(SAMR_FIELD_NUM_LOGONS)
3258 SET_UINT (msg, info21.logon_count, "logonCount");
3259 IFSET(SAMR_FIELD_COUNTRY_CODE)
3260 SET_UINT (msg, info21.country_code, "countryCode");
3261 IFSET(SAMR_FIELD_CODE_PAGE)
3262 SET_UINT (msg, info21.code_page, "codePage");
3264 /* password change fields */
3265 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3266 return NT_STATUS_ACCESS_DENIED;
3268 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3269 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3270 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3272 if (r->in.info->info21.lm_password_set) {
3273 if ((r->in.info->info21.lm_owf_password.length != 16)
3274 || (r->in.info->info21.lm_owf_password.size != 16)) {
3275 return NT_STATUS_INVALID_PARAMETER;
3278 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3280 if (r->in.info->info21.nt_password_set) {
3281 if ((r->in.info->info21.nt_owf_password.length != 16)
3282 || (r->in.info->info21.nt_owf_password.size != 16)) {
3283 return NT_STATUS_INVALID_PARAMETER;
3286 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3288 status = samr_set_password_buffers(dce_call,
3289 a_state->sam_ctx,
3290 a_state->account_dn,
3291 a_state->domain_state->domain_dn,
3292 mem_ctx,
3293 lm_pwd_hash,
3294 nt_pwd_hash);
3295 if (!NT_STATUS_IS_OK(status)) {
3296 return status;
3301 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3302 NTTIME t = 0;
3303 struct ldb_message_element *set_el;
3304 if (r->in.info->info21.password_expired
3305 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3306 unix_to_nt_time(&t, time(NULL));
3308 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3309 "pwdLastSet", t) != LDB_SUCCESS) {
3310 return NT_STATUS_NO_MEMORY;
3312 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3313 set_el->flags = LDB_FLAG_MOD_REPLACE;
3315 #undef IFSET
3316 break;
3318 case 23:
3319 if (r->in.info->info23.info.fields_present == 0)
3320 return NT_STATUS_INVALID_PARAMETER;
3322 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3323 IFSET(SAMR_FIELD_LAST_LOGON)
3324 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3325 IFSET(SAMR_FIELD_LAST_LOGOFF)
3326 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3327 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3328 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3329 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3330 SET_STRING(msg, info23.info.account_name, "samAccountName");
3331 IFSET(SAMR_FIELD_FULL_NAME)
3332 SET_STRING(msg, info23.info.full_name, "displayName");
3333 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3334 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3335 IFSET(SAMR_FIELD_HOME_DRIVE)
3336 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3337 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3338 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3339 IFSET(SAMR_FIELD_PROFILE_PATH)
3340 SET_STRING(msg, info23.info.profile_path, "profilePath");
3341 IFSET(SAMR_FIELD_DESCRIPTION)
3342 SET_STRING(msg, info23.info.description, "description");
3343 IFSET(SAMR_FIELD_WORKSTATIONS)
3344 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3345 IFSET(SAMR_FIELD_COMMENT)
3346 SET_STRING(msg, info23.info.comment, "comment");
3347 IFSET(SAMR_FIELD_PARAMETERS)
3348 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3349 IFSET(SAMR_FIELD_PRIMARY_GID)
3350 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3351 IFSET(SAMR_FIELD_ACCT_FLAGS)
3352 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3353 IFSET(SAMR_FIELD_LOGON_HOURS)
3354 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3355 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3356 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3357 IFSET(SAMR_FIELD_NUM_LOGONS)
3358 SET_UINT (msg, info23.info.logon_count, "logonCount");
3360 IFSET(SAMR_FIELD_COUNTRY_CODE)
3361 SET_UINT (msg, info23.info.country_code, "countryCode");
3362 IFSET(SAMR_FIELD_CODE_PAGE)
3363 SET_UINT (msg, info23.info.code_page, "codePage");
3365 /* password change fields */
3366 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3367 return NT_STATUS_ACCESS_DENIED;
3369 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3370 status = samr_set_password(dce_call,
3371 a_state->sam_ctx,
3372 a_state->account_dn,
3373 a_state->domain_state->domain_dn,
3374 mem_ctx,
3375 &r->in.info->info23.password);
3376 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3377 status = samr_set_password(dce_call,
3378 a_state->sam_ctx,
3379 a_state->account_dn,
3380 a_state->domain_state->domain_dn,
3381 mem_ctx,
3382 &r->in.info->info23.password);
3384 if (!NT_STATUS_IS_OK(status)) {
3385 return status;
3388 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3389 NTTIME t = 0;
3390 struct ldb_message_element *set_el;
3391 if (r->in.info->info23.info.password_expired
3392 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3393 unix_to_nt_time(&t, time(NULL));
3395 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3396 "pwdLastSet", t) != LDB_SUCCESS) {
3397 return NT_STATUS_NO_MEMORY;
3399 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3400 set_el->flags = LDB_FLAG_MOD_REPLACE;
3402 #undef IFSET
3403 break;
3405 /* the set password levels are handled separately */
3406 case 24:
3407 status = samr_set_password(dce_call,
3408 a_state->sam_ctx,
3409 a_state->account_dn,
3410 a_state->domain_state->domain_dn,
3411 mem_ctx,
3412 &r->in.info->info24.password);
3413 if (!NT_STATUS_IS_OK(status)) {
3414 return status;
3417 if (r->in.info->info24.password_expired > 0) {
3418 struct ldb_message_element *set_el;
3419 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3420 return NT_STATUS_NO_MEMORY;
3422 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3423 set_el->flags = LDB_FLAG_MOD_REPLACE;
3425 break;
3427 case 25:
3428 if (r->in.info->info25.info.fields_present == 0)
3429 return NT_STATUS_INVALID_PARAMETER;
3431 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3432 IFSET(SAMR_FIELD_LAST_LOGON)
3433 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3434 IFSET(SAMR_FIELD_LAST_LOGOFF)
3435 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3436 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3437 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3438 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3439 SET_STRING(msg, info25.info.account_name, "samAccountName");
3440 IFSET(SAMR_FIELD_FULL_NAME)
3441 SET_STRING(msg, info25.info.full_name, "displayName");
3442 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3443 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3444 IFSET(SAMR_FIELD_HOME_DRIVE)
3445 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3446 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3447 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3448 IFSET(SAMR_FIELD_PROFILE_PATH)
3449 SET_STRING(msg, info25.info.profile_path, "profilePath");
3450 IFSET(SAMR_FIELD_DESCRIPTION)
3451 SET_STRING(msg, info25.info.description, "description");
3452 IFSET(SAMR_FIELD_WORKSTATIONS)
3453 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3454 IFSET(SAMR_FIELD_COMMENT)
3455 SET_STRING(msg, info25.info.comment, "comment");
3456 IFSET(SAMR_FIELD_PARAMETERS)
3457 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3458 IFSET(SAMR_FIELD_PRIMARY_GID)
3459 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3460 IFSET(SAMR_FIELD_ACCT_FLAGS)
3461 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3462 IFSET(SAMR_FIELD_LOGON_HOURS)
3463 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3464 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3465 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3466 IFSET(SAMR_FIELD_NUM_LOGONS)
3467 SET_UINT (msg, info25.info.logon_count, "logonCount");
3468 IFSET(SAMR_FIELD_COUNTRY_CODE)
3469 SET_UINT (msg, info25.info.country_code, "countryCode");
3470 IFSET(SAMR_FIELD_CODE_PAGE)
3471 SET_UINT (msg, info25.info.code_page, "codePage");
3473 /* password change fields */
3474 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3475 return NT_STATUS_ACCESS_DENIED;
3477 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3478 status = samr_set_password_ex(dce_call,
3479 a_state->sam_ctx,
3480 a_state->account_dn,
3481 a_state->domain_state->domain_dn,
3482 mem_ctx,
3483 &r->in.info->info25.password);
3484 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3485 status = samr_set_password_ex(dce_call,
3486 a_state->sam_ctx,
3487 a_state->account_dn,
3488 a_state->domain_state->domain_dn,
3489 mem_ctx,
3490 &r->in.info->info25.password);
3492 if (!NT_STATUS_IS_OK(status)) {
3493 return status;
3496 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3497 NTTIME t = 0;
3498 struct ldb_message_element *set_el;
3499 if (r->in.info->info25.info.password_expired
3500 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3501 unix_to_nt_time(&t, time(NULL));
3503 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3504 "pwdLastSet", t) != LDB_SUCCESS) {
3505 return NT_STATUS_NO_MEMORY;
3507 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3508 set_el->flags = LDB_FLAG_MOD_REPLACE;
3510 #undef IFSET
3511 break;
3513 /* the set password levels are handled separately */
3514 case 26:
3515 status = samr_set_password_ex(dce_call,
3516 a_state->sam_ctx,
3517 a_state->account_dn,
3518 a_state->domain_state->domain_dn,
3519 mem_ctx,
3520 &r->in.info->info26.password);
3521 if (!NT_STATUS_IS_OK(status)) {
3522 return status;
3525 if (r->in.info->info26.password_expired > 0) {
3526 NTTIME t = 0;
3527 struct ldb_message_element *set_el;
3528 if (r->in.info->info26.password_expired
3529 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3530 unix_to_nt_time(&t, time(NULL));
3532 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3533 "pwdLastSet", t) != LDB_SUCCESS) {
3534 return NT_STATUS_NO_MEMORY;
3536 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3537 set_el->flags = LDB_FLAG_MOD_REPLACE;
3539 break;
3541 default:
3542 /* many info classes are not valid for SetUserInfo */
3543 return NT_STATUS_INVALID_INFO_CLASS;
3546 if (!NT_STATUS_IS_OK(status)) {
3547 return status;
3550 /* modify the samdb record */
3551 if (msg->num_elements > 0) {
3552 ret = ldb_modify(a_state->sam_ctx, msg);
3553 if (ret != LDB_SUCCESS) {
3554 DEBUG(1,("Failed to modify record %s: %s\n",
3555 ldb_dn_get_linearized(a_state->account_dn),
3556 ldb_errstring(a_state->sam_ctx)));
3558 return dsdb_ldb_err_to_ntstatus(ret);
3562 return NT_STATUS_OK;
3567 samr_GetGroupsForUser
3569 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3570 struct samr_GetGroupsForUser *r)
3572 struct dcesrv_handle *h;
3573 struct samr_account_state *a_state;
3574 struct samr_domain_state *d_state;
3575 struct ldb_message **res;
3576 const char * const attrs[2] = { "objectSid", NULL };
3577 struct samr_RidWithAttributeArray *array;
3578 int i, count;
3579 char membersidstr[DOM_SID_STR_BUFLEN];
3581 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3583 a_state = h->data;
3584 d_state = a_state->domain_state;
3586 dom_sid_string_buf(a_state->account_sid,
3587 membersidstr, sizeof(membersidstr)),
3589 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3590 d_state->domain_dn, &res,
3591 attrs, d_state->domain_sid,
3592 "(&(member=<SID=%s>)"
3593 "(|(grouptype=%d)(grouptype=%d))"
3594 "(objectclass=group))",
3595 membersidstr,
3596 GTYPE_SECURITY_UNIVERSAL_GROUP,
3597 GTYPE_SECURITY_GLOBAL_GROUP);
3598 if (count < 0)
3599 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3601 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3602 if (array == NULL)
3603 return NT_STATUS_NO_MEMORY;
3605 array->count = 0;
3606 array->rids = NULL;
3608 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3609 count + 1);
3610 if (array->rids == NULL)
3611 return NT_STATUS_NO_MEMORY;
3613 /* Adds the primary group */
3614 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3615 ~0, a_state->account_dn,
3616 "primaryGroupID", NULL);
3617 array->rids[0].attributes = SE_GROUP_MANDATORY
3618 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3619 array->count += 1;
3621 /* Adds the additional groups */
3622 for (i = 0; i < count; i++) {
3623 struct dom_sid *group_sid;
3625 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3626 if (group_sid == NULL) {
3627 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3630 array->rids[i + 1].rid =
3631 group_sid->sub_auths[group_sid->num_auths-1];
3632 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3633 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3634 array->count += 1;
3637 *r->out.rids = array;
3639 return NT_STATUS_OK;
3644 samr_QueryDisplayInfo
3646 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3647 struct samr_QueryDisplayInfo *r)
3649 struct dcesrv_handle *h;
3650 struct samr_domain_state *d_state;
3651 struct ldb_result *res;
3652 unsigned int i;
3653 uint32_t count;
3654 const char * const attrs[] = { "objectSid", "sAMAccountName",
3655 "displayName", "description", "userAccountControl",
3656 "pwdLastSet", NULL };
3657 struct samr_DispEntryFull *entriesFull = NULL;
3658 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3659 struct samr_DispEntryAscii *entriesAscii = NULL;
3660 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3661 const char *filter;
3662 int ret;
3664 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3666 d_state = h->data;
3668 switch (r->in.level) {
3669 case 1:
3670 case 4:
3671 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3672 "(sAMAccountType=%d))",
3673 ATYPE_NORMAL_ACCOUNT);
3674 break;
3675 case 2:
3676 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3677 "(sAMAccountType=%d))",
3678 ATYPE_WORKSTATION_TRUST);
3679 break;
3680 case 3:
3681 case 5:
3682 filter = talloc_asprintf(mem_ctx,
3683 "(&(|(groupType=%d)(groupType=%d))"
3684 "(objectClass=group))",
3685 GTYPE_SECURITY_UNIVERSAL_GROUP,
3686 GTYPE_SECURITY_GLOBAL_GROUP);
3687 break;
3688 default:
3689 return NT_STATUS_INVALID_INFO_CLASS;
3692 /* search for all requested objects in all domains. This could
3693 possibly be cached and resumed based on resume_key */
3694 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, ldb_get_default_basedn(d_state->sam_ctx),
3695 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3696 if (ret != LDB_SUCCESS) {
3697 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3699 if ((res->count == 0) || (r->in.max_entries == 0)) {
3700 return NT_STATUS_OK;
3703 switch (r->in.level) {
3704 case 1:
3705 entriesGeneral = talloc_array(mem_ctx,
3706 struct samr_DispEntryGeneral,
3707 res->count);
3708 break;
3709 case 2:
3710 entriesFull = talloc_array(mem_ctx,
3711 struct samr_DispEntryFull,
3712 res->count);
3713 break;
3714 case 3:
3715 entriesFullGroup = talloc_array(mem_ctx,
3716 struct samr_DispEntryFullGroup,
3717 res->count);
3718 break;
3719 case 4:
3720 case 5:
3721 entriesAscii = talloc_array(mem_ctx,
3722 struct samr_DispEntryAscii,
3723 res->count);
3724 break;
3727 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3728 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3729 return NT_STATUS_NO_MEMORY;
3731 count = 0;
3733 for (i = 0; i < res->count; i++) {
3734 struct dom_sid *objectsid;
3736 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3737 "objectSid");
3738 if (objectsid == NULL)
3739 continue;
3741 switch(r->in.level) {
3742 case 1:
3743 entriesGeneral[count].idx = count + 1;
3744 entriesGeneral[count].rid =
3745 objectsid->sub_auths[objectsid->num_auths-1];
3746 entriesGeneral[count].acct_flags =
3747 samdb_result_acct_flags(res->msgs[i], NULL);
3748 entriesGeneral[count].account_name.string =
3749 ldb_msg_find_attr_as_string(res->msgs[i],
3750 "sAMAccountName", "");
3751 entriesGeneral[count].full_name.string =
3752 ldb_msg_find_attr_as_string(res->msgs[i],
3753 "displayName", "");
3754 entriesGeneral[count].description.string =
3755 ldb_msg_find_attr_as_string(res->msgs[i],
3756 "description", "");
3757 break;
3758 case 2:
3759 entriesFull[count].idx = count + 1;
3760 entriesFull[count].rid =
3761 objectsid->sub_auths[objectsid->num_auths-1];
3763 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3764 entriesFull[count].acct_flags =
3765 samdb_result_acct_flags(res->msgs[i],
3766 NULL) | ACB_NORMAL;
3767 entriesFull[count].account_name.string =
3768 ldb_msg_find_attr_as_string(res->msgs[i],
3769 "sAMAccountName", "");
3770 entriesFull[count].description.string =
3771 ldb_msg_find_attr_as_string(res->msgs[i],
3772 "description", "");
3773 break;
3774 case 3:
3775 entriesFullGroup[count].idx = count + 1;
3776 entriesFullGroup[count].rid =
3777 objectsid->sub_auths[objectsid->num_auths-1];
3778 /* We get a "7" here for groups */
3779 entriesFullGroup[count].acct_flags
3780 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3781 entriesFullGroup[count].account_name.string =
3782 ldb_msg_find_attr_as_string(res->msgs[i],
3783 "sAMAccountName", "");
3784 entriesFullGroup[count].description.string =
3785 ldb_msg_find_attr_as_string(res->msgs[i],
3786 "description", "");
3787 break;
3788 case 4:
3789 case 5:
3790 entriesAscii[count].idx = count + 1;
3791 entriesAscii[count].account_name.string =
3792 ldb_msg_find_attr_as_string(res->msgs[i],
3793 "sAMAccountName", "");
3794 break;
3797 count += 1;
3800 *r->out.total_size = count;
3802 if (r->in.start_idx >= count) {
3803 *r->out.returned_size = 0;
3804 switch(r->in.level) {
3805 case 1:
3806 r->out.info->info1.count = *r->out.returned_size;
3807 r->out.info->info1.entries = NULL;
3808 break;
3809 case 2:
3810 r->out.info->info2.count = *r->out.returned_size;
3811 r->out.info->info2.entries = NULL;
3812 break;
3813 case 3:
3814 r->out.info->info3.count = *r->out.returned_size;
3815 r->out.info->info3.entries = NULL;
3816 break;
3817 case 4:
3818 r->out.info->info4.count = *r->out.returned_size;
3819 r->out.info->info4.entries = NULL;
3820 break;
3821 case 5:
3822 r->out.info->info5.count = *r->out.returned_size;
3823 r->out.info->info5.entries = NULL;
3824 break;
3826 } else {
3827 *r->out.returned_size = MIN(count - r->in.start_idx,
3828 r->in.max_entries);
3829 switch(r->in.level) {
3830 case 1:
3831 r->out.info->info1.count = *r->out.returned_size;
3832 r->out.info->info1.entries =
3833 &(entriesGeneral[r->in.start_idx]);
3834 break;
3835 case 2:
3836 r->out.info->info2.count = *r->out.returned_size;
3837 r->out.info->info2.entries =
3838 &(entriesFull[r->in.start_idx]);
3839 break;
3840 case 3:
3841 r->out.info->info3.count = *r->out.returned_size;
3842 r->out.info->info3.entries =
3843 &(entriesFullGroup[r->in.start_idx]);
3844 break;
3845 case 4:
3846 r->out.info->info4.count = *r->out.returned_size;
3847 r->out.info->info4.entries =
3848 &(entriesAscii[r->in.start_idx]);
3849 break;
3850 case 5:
3851 r->out.info->info5.count = *r->out.returned_size;
3852 r->out.info->info5.entries =
3853 &(entriesAscii[r->in.start_idx]);
3854 break;
3858 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3859 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3864 samr_GetDisplayEnumerationIndex
3866 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3867 struct samr_GetDisplayEnumerationIndex *r)
3869 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3874 samr_TestPrivateFunctionsDomain
3876 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3877 struct samr_TestPrivateFunctionsDomain *r)
3879 return NT_STATUS_NOT_IMPLEMENTED;
3884 samr_TestPrivateFunctionsUser
3886 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3887 struct samr_TestPrivateFunctionsUser *r)
3889 return NT_STATUS_NOT_IMPLEMENTED;
3894 samr_GetUserPwInfo
3896 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3897 struct samr_GetUserPwInfo *r)
3899 struct dcesrv_handle *h;
3900 struct samr_account_state *a_state;
3902 ZERO_STRUCTP(r->out.info);
3904 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3906 a_state = h->data;
3908 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3909 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3910 NULL);
3911 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3912 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3914 return NT_STATUS_OK;
3919 samr_RemoveMemberFromForeignDomain
3921 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3922 TALLOC_CTX *mem_ctx,
3923 struct samr_RemoveMemberFromForeignDomain *r)
3925 struct dcesrv_handle *h;
3926 struct samr_domain_state *d_state;
3927 const char *memberdn;
3928 struct ldb_message **res;
3929 const char *no_attrs[] = { NULL };
3930 int i, count;
3932 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3934 d_state = h->data;
3936 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3937 "distinguishedName", "(objectSid=%s)",
3938 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3939 /* Nothing to do */
3940 if (memberdn == NULL) {
3941 return NT_STATUS_OK;
3944 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3945 d_state->domain_dn, &res, no_attrs,
3946 d_state->domain_sid,
3947 "(&(member=%s)(objectClass=group)"
3948 "(|(groupType=%d)(groupType=%d)))",
3949 memberdn,
3950 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3951 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3953 if (count < 0)
3954 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3956 for (i=0; i<count; i++) {
3957 struct ldb_message *mod;
3958 int ret;
3960 mod = ldb_msg_new(mem_ctx);
3961 if (mod == NULL) {
3962 return NT_STATUS_NO_MEMORY;
3965 mod->dn = res[i]->dn;
3967 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3968 "member", memberdn) != LDB_SUCCESS)
3969 return NT_STATUS_NO_MEMORY;
3971 ret = ldb_modify(d_state->sam_ctx, mod);
3972 talloc_free(mod);
3973 if (ret != LDB_SUCCESS) {
3974 return dsdb_ldb_err_to_ntstatus(ret);
3978 return NT_STATUS_OK;
3983 samr_QueryDomainInfo2
3985 just an alias for samr_QueryDomainInfo
3987 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3988 struct samr_QueryDomainInfo2 *r)
3990 struct samr_QueryDomainInfo r1;
3991 NTSTATUS status;
3993 ZERO_STRUCT(r1.out);
3994 r1.in.domain_handle = r->in.domain_handle;
3995 r1.in.level = r->in.level;
3996 r1.out.info = r->out.info;
3998 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4000 return status;
4005 samr_QueryUserInfo2
4007 just an alias for samr_QueryUserInfo
4009 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4010 struct samr_QueryUserInfo2 *r)
4012 struct samr_QueryUserInfo r1;
4013 NTSTATUS status;
4015 r1 = (struct samr_QueryUserInfo) {
4016 .in.user_handle = r->in.user_handle,
4017 .in.level = r->in.level,
4018 .out.info = r->out.info
4021 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4023 return status;
4028 samr_QueryDisplayInfo2
4030 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4031 struct samr_QueryDisplayInfo2 *r)
4033 struct samr_QueryDisplayInfo q;
4034 NTSTATUS result;
4036 q.in.domain_handle = r->in.domain_handle;
4037 q.in.level = r->in.level;
4038 q.in.start_idx = r->in.start_idx;
4039 q.in.max_entries = r->in.max_entries;
4040 q.in.buf_size = r->in.buf_size;
4041 q.out.total_size = r->out.total_size;
4042 q.out.returned_size = r->out.returned_size;
4043 q.out.info = r->out.info;
4045 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4047 return result;
4052 samr_GetDisplayEnumerationIndex2
4054 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4055 struct samr_GetDisplayEnumerationIndex2 *r)
4057 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4062 samr_QueryDisplayInfo3
4064 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4065 struct samr_QueryDisplayInfo3 *r)
4067 struct samr_QueryDisplayInfo q;
4068 NTSTATUS result;
4070 q.in.domain_handle = r->in.domain_handle;
4071 q.in.level = r->in.level;
4072 q.in.start_idx = r->in.start_idx;
4073 q.in.max_entries = r->in.max_entries;
4074 q.in.buf_size = r->in.buf_size;
4075 q.out.total_size = r->out.total_size;
4076 q.out.returned_size = r->out.returned_size;
4077 q.out.info = r->out.info;
4079 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4081 return result;
4086 samr_AddMultipleMembersToAlias
4088 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4089 struct samr_AddMultipleMembersToAlias *r)
4091 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4096 samr_RemoveMultipleMembersFromAlias
4098 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4099 struct samr_RemoveMultipleMembersFromAlias *r)
4101 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4106 samr_GetDomPwInfo
4108 this fetches the default password properties for a domain
4110 note that w2k3 completely ignores the domain name in this call, and
4111 always returns the information for the servers primary domain
4113 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4114 struct samr_GetDomPwInfo *r)
4116 struct ldb_message **msgs;
4117 int ret;
4118 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4119 struct ldb_context *sam_ctx;
4121 ZERO_STRUCTP(r->out.info);
4123 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4124 dce_call->conn->dce_ctx->lp_ctx,
4125 dce_call->conn->auth_state.session_info, 0);
4126 if (sam_ctx == NULL) {
4127 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4130 /* The domain name in this call is ignored */
4131 ret = gendb_search_dn(sam_ctx,
4132 mem_ctx, NULL, &msgs, attrs);
4133 if (ret <= 0) {
4134 talloc_free(sam_ctx);
4136 return NT_STATUS_NO_SUCH_DOMAIN;
4138 if (ret > 1) {
4139 talloc_free(msgs);
4140 talloc_free(sam_ctx);
4142 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4145 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4146 "minPwdLength", 0);
4147 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4148 "pwdProperties", 1);
4150 talloc_free(msgs);
4151 talloc_unlink(mem_ctx, sam_ctx);
4153 return NT_STATUS_OK;
4158 samr_Connect2
4160 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4161 struct samr_Connect2 *r)
4163 struct samr_Connect c;
4165 c.in.system_name = NULL;
4166 c.in.access_mask = r->in.access_mask;
4167 c.out.connect_handle = r->out.connect_handle;
4169 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4174 samr_SetUserInfo2
4176 just an alias for samr_SetUserInfo
4178 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4179 struct samr_SetUserInfo2 *r)
4181 struct samr_SetUserInfo r2;
4183 r2.in.user_handle = r->in.user_handle;
4184 r2.in.level = r->in.level;
4185 r2.in.info = r->in.info;
4187 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4192 samr_SetBootKeyInformation
4194 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4195 struct samr_SetBootKeyInformation *r)
4197 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4202 samr_GetBootKeyInformation
4204 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4205 struct samr_GetBootKeyInformation *r)
4207 /* Windows Server 2008 returns this */
4208 return NT_STATUS_NOT_SUPPORTED;
4213 samr_Connect3
4215 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4216 struct samr_Connect3 *r)
4218 struct samr_Connect c;
4220 c.in.system_name = NULL;
4221 c.in.access_mask = r->in.access_mask;
4222 c.out.connect_handle = r->out.connect_handle;
4224 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4229 samr_Connect4
4231 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4232 struct samr_Connect4 *r)
4234 struct samr_Connect c;
4236 c.in.system_name = NULL;
4237 c.in.access_mask = r->in.access_mask;
4238 c.out.connect_handle = r->out.connect_handle;
4240 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4245 samr_Connect5
4247 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4248 struct samr_Connect5 *r)
4250 struct samr_Connect c;
4251 NTSTATUS status;
4253 c.in.system_name = NULL;
4254 c.in.access_mask = r->in.access_mask;
4255 c.out.connect_handle = r->out.connect_handle;
4257 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4259 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4260 r->out.info_out->info1.unknown2 = 0;
4261 *r->out.level_out = r->in.level_in;
4263 return status;
4268 samr_RidToSid
4270 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4271 struct samr_RidToSid *r)
4273 struct samr_domain_state *d_state;
4274 struct dcesrv_handle *h;
4276 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4278 d_state = h->data;
4280 /* form the users SID */
4281 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4282 if (!*r->out.sid) {
4283 return NT_STATUS_NO_MEMORY;
4286 return NT_STATUS_OK;
4291 samr_SetDsrmPassword
4293 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4294 struct samr_SetDsrmPassword *r)
4296 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4301 samr_ValidatePassword
4303 For now the call checks the password complexity (if active) and the minimum
4304 password length on level 2 and 3. Level 1 is ignored for now.
4306 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4307 TALLOC_CTX *mem_ctx,
4308 struct samr_ValidatePassword *r)
4310 struct samr_GetDomPwInfo r2;
4311 struct samr_PwInfo pwInfo;
4312 DATA_BLOB password;
4313 enum samr_ValidationStatus res;
4314 NTSTATUS status;
4315 enum dcerpc_transport_t transport =
4316 dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
4318 if (transport != NCACN_IP_TCP && transport != NCALRPC) {
4319 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4322 if (dce_call->conn->auth_state.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
4323 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4326 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4328 r2.in.domain_name = NULL;
4329 r2.out.info = &pwInfo;
4330 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4331 if (!NT_STATUS_IS_OK(status)) {
4332 return status;
4335 switch (r->in.level) {
4336 case NetValidateAuthentication:
4337 /* we don't support this yet */
4338 return NT_STATUS_NOT_SUPPORTED;
4339 break;
4340 case NetValidatePasswordChange:
4341 password = data_blob_const(r->in.req->req2.password.string,
4342 r->in.req->req2.password.length);
4343 res = samdb_check_password(&password,
4344 pwInfo.password_properties,
4345 pwInfo.min_password_length);
4346 (*r->out.rep)->ctr2.status = res;
4347 break;
4348 case NetValidatePasswordReset:
4349 password = data_blob_const(r->in.req->req3.password.string,
4350 r->in.req->req3.password.length);
4351 res = samdb_check_password(&password,
4352 pwInfo.password_properties,
4353 pwInfo.min_password_length);
4354 (*r->out.rep)->ctr3.status = res;
4355 break;
4356 default:
4357 return NT_STATUS_INVALID_INFO_CLASS;
4358 break;
4361 return NT_STATUS_OK;
4365 /* include the generated boilerplate */
4366 #include "librpc/gen_ndr/ndr_samr_s.c"