s4:samr: allow builtin groups for samr_OpenGroup.
[Samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
blobeacbe7da7b46797a03ae013268a99c03e5e8aed9
1 /*
2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include <ldb.h>
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
44 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
46 #define QUERY_STRING(msg, field, attr) \
47 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
48 #define QUERY_UINT(msg, field, attr) \
49 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
50 #define QUERY_RID(msg, field, attr) \
51 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
52 #define QUERY_UINT64(msg, field, attr) \
53 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
54 #define QUERY_APASSC(msg, field, attr) \
55 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg, attr);
57 #define QUERY_FPASSC(msg, field, attr) \
58 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
59 a_state->domain_state->domain_dn, msg);
60 #define QUERY_BPWDCT(msg, field, attr) \
61 info->field = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx, \
62 a_state->domain_state->domain_dn, msg);
63 #define QUERY_LHOURS(msg, field, attr) \
64 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
65 #define QUERY_AFLAGS(msg, field, attr) \
66 info->field = samdb_result_acct_flags(msg, attr);
67 #define QUERY_PARAMETERS(msg, field, attr) \
68 info->field = samdb_result_parameters(mem_ctx, msg, attr);
71 /* these are used to make the Set[User|Group]Info code easier to follow */
73 #define SET_STRING(msg, field, attr) do { \
74 struct ldb_message_element *set_el; \
75 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
76 if (r->in.info->field.string[0] == '\0') { \
77 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
78 return NT_STATUS_NO_MEMORY; \
79 } \
80 } \
81 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
82 return NT_STATUS_NO_MEMORY; \
83 } \
84 set_el = ldb_msg_find_element(msg, attr); \
85 set_el->flags = LDB_FLAG_MOD_REPLACE; \
86 } while (0)
88 #define SET_UINT(msg, field, attr) do { \
89 struct ldb_message_element *set_el; \
90 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
91 return NT_STATUS_NO_MEMORY; \
92 } \
93 set_el = ldb_msg_find_element(msg, attr); \
94 set_el->flags = LDB_FLAG_MOD_REPLACE; \
95 } while (0)
97 #define SET_INT64(msg, field, attr) do { \
98 struct ldb_message_element *set_el; \
99 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
100 return NT_STATUS_NO_MEMORY; \
102 set_el = ldb_msg_find_element(msg, attr); \
103 set_el->flags = LDB_FLAG_MOD_REPLACE; \
104 } while (0)
106 #define SET_UINT64(msg, field, attr) do { \
107 struct ldb_message_element *set_el; \
108 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
109 return NT_STATUS_NO_MEMORY; \
111 set_el = ldb_msg_find_element(msg, attr); \
112 set_el->flags = LDB_FLAG_MOD_REPLACE; \
113 } while (0)
115 /* Set account flags, discarding flags that cannot be set with SAMR */
116 #define SET_AFLAGS(msg, field, attr) do { \
117 struct ldb_message_element *set_el; \
118 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
119 return NT_STATUS_NO_MEMORY; \
121 set_el = ldb_msg_find_element(msg, attr); \
122 set_el->flags = LDB_FLAG_MOD_REPLACE; \
123 } while (0)
125 #define SET_LHOURS(msg, field, attr) do { \
126 struct ldb_message_element *set_el; \
127 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
128 return NT_STATUS_NO_MEMORY; \
130 set_el = ldb_msg_find_element(msg, attr); \
131 set_el->flags = LDB_FLAG_MOD_REPLACE; \
132 } while (0)
134 #define SET_PARAMETERS(msg, field, attr) do { \
135 struct ldb_message_element *set_el; \
136 if (r->in.info->field.length != 0) { \
137 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
138 return NT_STATUS_NO_MEMORY; \
140 set_el = ldb_msg_find_element(msg, attr); \
141 set_el->flags = LDB_FLAG_MOD_REPLACE; \
143 } while (0)
148 samr_Connect
150 create a connection to the SAM database
152 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
153 struct samr_Connect *r)
155 struct samr_connect_state *c_state;
156 struct dcesrv_handle *handle;
158 ZERO_STRUCTP(r->out.connect_handle);
160 c_state = talloc(mem_ctx, struct samr_connect_state);
161 if (!c_state) {
162 return NT_STATUS_NO_MEMORY;
165 /* make sure the sam database is accessible */
166 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);
167 if (c_state->sam_ctx == NULL) {
168 talloc_free(c_state);
169 return NT_STATUS_INVALID_SYSTEM_SERVICE;
173 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
174 if (!handle) {
175 talloc_free(c_state);
176 return NT_STATUS_NO_MEMORY;
179 handle->data = talloc_steal(handle, c_state);
181 c_state->access_mask = r->in.access_mask;
182 *r->out.connect_handle = handle->wire_handle;
184 return NT_STATUS_OK;
189 samr_Close
191 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
192 struct samr_Close *r)
194 struct dcesrv_handle *h;
196 *r->out.handle = *r->in.handle;
198 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
200 talloc_free(h);
202 ZERO_STRUCTP(r->out.handle);
204 return NT_STATUS_OK;
209 samr_SetSecurity
211 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
212 struct samr_SetSecurity *r)
214 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
219 samr_QuerySecurity
221 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
222 struct samr_QuerySecurity *r)
224 struct dcesrv_handle *h;
225 struct sec_desc_buf *sd;
227 *r->out.sdbuf = NULL;
229 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
231 sd = talloc(mem_ctx, struct sec_desc_buf);
232 if (sd == NULL) {
233 return NT_STATUS_NO_MEMORY;
236 sd->sd = samdb_default_security_descriptor(mem_ctx);
238 *r->out.sdbuf = sd;
240 return NT_STATUS_OK;
245 samr_Shutdown
247 we refuse this operation completely. If a admin wants to shutdown samr
248 in Samba then they should use the samba admin tools to disable the samr pipe
250 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
251 struct samr_Shutdown *r)
253 return NT_STATUS_ACCESS_DENIED;
258 samr_LookupDomain
260 this maps from a domain name to a SID
262 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
263 struct samr_LookupDomain *r)
265 struct samr_connect_state *c_state;
266 struct dcesrv_handle *h;
267 struct dom_sid *sid;
268 const char * const dom_attrs[] = { "objectSid", NULL};
269 struct ldb_message **dom_msgs;
270 int ret;
272 *r->out.sid = NULL;
274 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
276 c_state = h->data;
278 if (r->in.domain_name->string == NULL) {
279 return NT_STATUS_INVALID_PARAMETER;
282 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
283 ret = gendb_search(c_state->sam_ctx,
284 mem_ctx, NULL, &dom_msgs, dom_attrs,
285 "(objectClass=builtinDomain)");
286 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
287 ret = gendb_search_dn(c_state->sam_ctx,
288 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
289 &dom_msgs, dom_attrs);
290 } else {
291 return NT_STATUS_NO_SUCH_DOMAIN;
293 if (ret != 1) {
294 return NT_STATUS_NO_SUCH_DOMAIN;
297 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
298 "objectSid");
300 if (sid == NULL) {
301 return NT_STATUS_NO_SUCH_DOMAIN;
304 *r->out.sid = sid;
306 return NT_STATUS_OK;
311 samr_EnumDomains
313 list the domains in the SAM
315 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
316 struct samr_EnumDomains *r)
318 struct samr_connect_state *c_state;
319 struct dcesrv_handle *h;
320 struct samr_SamArray *array;
321 uint32_t i, start_i;
323 *r->out.resume_handle = 0;
324 *r->out.sam = NULL;
325 *r->out.num_entries = 0;
327 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
329 c_state = h->data;
331 *r->out.resume_handle = 2;
333 start_i = *r->in.resume_handle;
335 if (start_i >= 2) {
336 /* search past end of list is not an error for this call */
337 return NT_STATUS_OK;
340 array = talloc(mem_ctx, struct samr_SamArray);
341 if (array == NULL) {
342 return NT_STATUS_NO_MEMORY;
345 array->count = 0;
346 array->entries = NULL;
348 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
349 if (array->entries == NULL) {
350 return NT_STATUS_NO_MEMORY;
353 for (i=0;i<2-start_i;i++) {
354 array->entries[i].idx = start_i + i;
355 if (i == 0) {
356 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
357 } else {
358 array->entries[i].name.string = "BUILTIN";
362 *r->out.sam = array;
363 *r->out.num_entries = i;
364 array->count = *r->out.num_entries;
366 return NT_STATUS_OK;
371 samr_OpenDomain
373 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
374 struct samr_OpenDomain *r)
376 struct dcesrv_handle *h_conn, *h_domain;
377 struct samr_connect_state *c_state;
378 struct samr_domain_state *d_state;
379 const char * const dom_attrs[] = { "cn", NULL};
380 struct ldb_message **dom_msgs;
381 int ret;
383 ZERO_STRUCTP(r->out.domain_handle);
385 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
387 c_state = h_conn->data;
389 if (r->in.sid == NULL) {
390 return NT_STATUS_INVALID_PARAMETER;
393 d_state = talloc(mem_ctx, struct samr_domain_state);
394 if (!d_state) {
395 return NT_STATUS_NO_MEMORY;
398 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
400 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
401 d_state->builtin = true;
402 d_state->domain_name = "BUILTIN";
403 } else {
404 d_state->builtin = false;
405 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
408 ret = gendb_search(c_state->sam_ctx,
409 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
410 "(objectSid=%s)",
411 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
413 if (ret == 0) {
414 talloc_free(d_state);
415 return NT_STATUS_NO_SUCH_DOMAIN;
416 } else if (ret > 1) {
417 talloc_free(d_state);
418 return NT_STATUS_INTERNAL_DB_CORRUPTION;
419 } else if (ret == -1) {
420 talloc_free(d_state);
421 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
422 return NT_STATUS_INTERNAL_DB_CORRUPTION;
425 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
426 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
427 d_state->connect_state = talloc_reference(d_state, c_state);
428 d_state->sam_ctx = c_state->sam_ctx;
429 d_state->access_mask = r->in.access_mask;
431 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
433 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
434 if (!h_domain) {
435 talloc_free(d_state);
436 return NT_STATUS_NO_MEMORY;
439 h_domain->data = talloc_steal(h_domain, d_state);
441 *r->out.domain_handle = h_domain->wire_handle;
443 return NT_STATUS_OK;
447 return DomInfo1
449 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
450 TALLOC_CTX *mem_ctx,
451 struct ldb_message **dom_msgs,
452 struct samr_DomInfo1 *info)
454 info->min_password_length =
455 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
456 info->password_history_length =
457 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
458 info->password_properties =
459 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
460 info->max_password_age =
461 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
462 info->min_password_age =
463 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
465 return NT_STATUS_OK;
469 return DomInfo2
471 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
472 TALLOC_CTX *mem_ctx,
473 struct ldb_message **dom_msgs,
474 struct samr_DomGeneralInformation *info)
476 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
477 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
478 "domainReplica",
479 "");
481 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
482 0x8000000000000000LL);
484 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
485 "oEMInformation",
486 "");
487 info->domain_name.string = state->domain_name;
489 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
491 switch (state->role) {
492 case ROLE_ACTIVE_DIRECTORY_DC:
493 /* This pulls the NetBIOS name from the
494 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
495 string */
496 if (samdb_is_pdc(state->sam_ctx)) {
497 info->role = SAMR_ROLE_DOMAIN_PDC;
498 } else {
499 info->role = SAMR_ROLE_DOMAIN_BDC;
501 break;
502 case ROLE_DOMAIN_PDC:
503 case ROLE_DOMAIN_BDC:
504 return NT_STATUS_INTERNAL_ERROR;
505 case ROLE_DOMAIN_MEMBER:
506 info->role = SAMR_ROLE_DOMAIN_MEMBER;
507 break;
508 case ROLE_STANDALONE:
509 info->role = SAMR_ROLE_STANDALONE;
510 break;
513 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx,
514 state->domain_dn,
515 "(objectClass=user)");
516 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx,
517 state->domain_dn,
518 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
519 GTYPE_SECURITY_UNIVERSAL_GROUP,
520 GTYPE_SECURITY_GLOBAL_GROUP);
521 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx,
522 state->domain_dn,
523 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
524 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
525 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
527 return NT_STATUS_OK;
531 return DomInfo3
533 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
534 TALLOC_CTX *mem_ctx,
535 struct ldb_message **dom_msgs,
536 struct samr_DomInfo3 *info)
538 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
539 0x8000000000000000LL);
541 return NT_STATUS_OK;
545 return DomInfo4
547 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
548 TALLOC_CTX *mem_ctx,
549 struct ldb_message **dom_msgs,
550 struct samr_DomOEMInformation *info)
552 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
553 "oEMInformation",
554 "");
556 return NT_STATUS_OK;
560 return DomInfo5
562 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
563 TALLOC_CTX *mem_ctx,
564 struct ldb_message **dom_msgs,
565 struct samr_DomInfo5 *info)
567 info->domain_name.string = state->domain_name;
569 return NT_STATUS_OK;
573 return DomInfo6
575 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
576 TALLOC_CTX *mem_ctx,
577 struct ldb_message **dom_msgs,
578 struct samr_DomInfo6 *info)
580 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
581 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
582 "domainReplica",
583 "");
585 return NT_STATUS_OK;
589 return DomInfo7
591 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
592 TALLOC_CTX *mem_ctx,
593 struct ldb_message **dom_msgs,
594 struct samr_DomInfo7 *info)
597 switch (state->role) {
598 case ROLE_ACTIVE_DIRECTORY_DC:
599 /* This pulls the NetBIOS name from the
600 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
601 string */
602 if (samdb_is_pdc(state->sam_ctx)) {
603 info->role = SAMR_ROLE_DOMAIN_PDC;
604 } else {
605 info->role = SAMR_ROLE_DOMAIN_BDC;
607 break;
608 case ROLE_DOMAIN_PDC:
609 info->role = SAMR_ROLE_DOMAIN_PDC;
610 break;
611 case ROLE_DOMAIN_MEMBER:
612 info->role = SAMR_ROLE_DOMAIN_MEMBER;
613 break;
614 case ROLE_STANDALONE:
615 info->role = SAMR_ROLE_STANDALONE;
616 break;
619 return NT_STATUS_OK;
623 return DomInfo8
625 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
626 TALLOC_CTX *mem_ctx,
627 struct ldb_message **dom_msgs,
628 struct samr_DomInfo8 *info)
630 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
631 time(NULL));
633 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
634 0x0LL);
636 return NT_STATUS_OK;
640 return DomInfo9
642 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
643 TALLOC_CTX *mem_ctx,
644 struct ldb_message **dom_msgs,
645 struct samr_DomInfo9 *info)
647 info->domain_server_state = DOMAIN_SERVER_ENABLED;
649 return NT_STATUS_OK;
653 return DomInfo11
655 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
656 TALLOC_CTX *mem_ctx,
657 struct ldb_message **dom_msgs,
658 struct samr_DomGeneralInformation2 *info)
660 NTSTATUS status;
661 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
662 if (!NT_STATUS_IS_OK(status)) {
663 return status;
666 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
667 -18000000000LL);
668 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
669 -18000000000LL);
670 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
672 return NT_STATUS_OK;
676 return DomInfo12
678 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
679 TALLOC_CTX *mem_ctx,
680 struct ldb_message **dom_msgs,
681 struct samr_DomInfo12 *info)
683 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
684 -18000000000LL);
685 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
686 -18000000000LL);
687 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
689 return NT_STATUS_OK;
693 return DomInfo13
695 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
696 TALLOC_CTX *mem_ctx,
697 struct ldb_message **dom_msgs,
698 struct samr_DomInfo13 *info)
700 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
701 time(NULL));
703 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
704 0x0LL);
706 info->modified_count_at_last_promotion = 0;
708 return NT_STATUS_OK;
712 samr_QueryDomainInfo
714 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
715 TALLOC_CTX *mem_ctx,
716 struct samr_QueryDomainInfo *r)
718 struct dcesrv_handle *h;
719 struct samr_domain_state *d_state;
720 union samr_DomainInfo *info;
722 struct ldb_message **dom_msgs;
723 const char * const *attrs = NULL;
725 *r->out.info = NULL;
727 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
729 d_state = h->data;
731 switch (r->in.level) {
732 case 1:
734 static const char * const attrs2[] = { "minPwdLength",
735 "pwdHistoryLength",
736 "pwdProperties",
737 "maxPwdAge",
738 "minPwdAge",
739 NULL };
740 attrs = attrs2;
741 break;
743 case 2:
745 static const char * const attrs2[] = {"forceLogoff",
746 "oEMInformation",
747 "modifiedCount",
748 "domainReplica",
749 NULL};
750 attrs = attrs2;
751 break;
753 case 3:
755 static const char * const attrs2[] = {"forceLogoff",
756 NULL};
757 attrs = attrs2;
758 break;
760 case 4:
762 static const char * const attrs2[] = {"oEMInformation",
763 NULL};
764 attrs = attrs2;
765 break;
767 case 5:
769 attrs = NULL;
770 break;
772 case 6:
774 static const char * const attrs2[] = { "domainReplica",
775 NULL };
776 attrs = attrs2;
777 break;
779 case 7:
781 attrs = NULL;
782 break;
784 case 8:
786 static const char * const attrs2[] = { "modifiedCount",
787 "creationTime",
788 NULL };
789 attrs = attrs2;
790 break;
792 case 9:
794 attrs = NULL;
795 break;
797 case 11:
799 static const char * const attrs2[] = { "oEMInformation",
800 "forceLogoff",
801 "modifiedCount",
802 "lockoutDuration",
803 "lockOutObservationWindow",
804 "lockoutThreshold",
805 NULL};
806 attrs = attrs2;
807 break;
809 case 12:
811 static const char * const attrs2[] = { "lockoutDuration",
812 "lockOutObservationWindow",
813 "lockoutThreshold",
814 NULL};
815 attrs = attrs2;
816 break;
818 case 13:
820 static const char * const attrs2[] = { "modifiedCount",
821 "creationTime",
822 NULL };
823 attrs = attrs2;
824 break;
826 default:
828 return NT_STATUS_INVALID_INFO_CLASS;
832 /* some levels don't need a search */
833 if (attrs) {
834 int ret;
835 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
836 d_state->domain_dn, &dom_msgs, attrs);
837 if (ret == 0) {
838 return NT_STATUS_NO_SUCH_DOMAIN;
840 if (ret != 1) {
841 return NT_STATUS_INTERNAL_DB_CORRUPTION;
845 /* allocate the info structure */
846 info = talloc_zero(mem_ctx, union samr_DomainInfo);
847 if (info == NULL) {
848 return NT_STATUS_NO_MEMORY;
851 *r->out.info = info;
853 switch (r->in.level) {
854 case 1:
855 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
856 &info->info1);
857 case 2:
858 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
859 &info->general);
860 case 3:
861 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
862 &info->info3);
863 case 4:
864 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
865 &info->oem);
866 case 5:
867 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
868 &info->info5);
869 case 6:
870 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
871 &info->info6);
872 case 7:
873 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
874 &info->info7);
875 case 8:
876 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
877 &info->info8);
878 case 9:
879 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
880 &info->info9);
881 case 11:
882 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
883 &info->general2);
884 case 12:
885 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
886 &info->info12);
887 case 13:
888 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
889 &info->info13);
890 default:
891 return NT_STATUS_INVALID_INFO_CLASS;
897 samr_SetDomainInfo
899 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
900 struct samr_SetDomainInfo *r)
902 struct dcesrv_handle *h;
903 struct samr_domain_state *d_state;
904 struct ldb_message *msg;
905 int ret;
906 struct ldb_context *sam_ctx;
908 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
910 d_state = h->data;
911 sam_ctx = d_state->sam_ctx;
913 msg = ldb_msg_new(mem_ctx);
914 if (msg == NULL) {
915 return NT_STATUS_NO_MEMORY;
918 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
919 if (!msg->dn) {
920 return NT_STATUS_NO_MEMORY;
923 switch (r->in.level) {
924 case 1:
925 SET_UINT (msg, info1.min_password_length, "minPwdLength");
926 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
927 SET_UINT (msg, info1.password_properties, "pwdProperties");
928 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
929 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
930 break;
931 case 3:
932 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
933 break;
934 case 4:
935 SET_STRING(msg, oem.oem_information, "oEMInformation");
936 break;
938 case 6:
939 case 7:
940 case 9:
941 /* No op, we don't know where to set these */
942 return NT_STATUS_OK;
944 case 12:
946 * It is not possible to set lockout_duration < lockout_window.
947 * (The test is the other way around since the negative numbers
948 * are stored...)
950 * TODO:
951 * This check should be moved to the backend, i.e. to some
952 * ldb module under dsdb/samdb/ldb_modules/ .
954 * This constraint is documented here for the samr rpc service:
955 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
956 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
958 * And here for the ldap backend:
959 * MS-ADTS 3.1.1.5.3.2 Constraints
960 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
962 if (r->in.info->info12.lockout_duration >
963 r->in.info->info12.lockout_window)
965 return NT_STATUS_INVALID_PARAMETER;
967 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
968 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
969 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
970 break;
972 default:
973 /* many info classes are not valid for SetDomainInfo */
974 return NT_STATUS_INVALID_INFO_CLASS;
977 /* modify the samdb record */
978 ret = ldb_modify(sam_ctx, msg);
979 if (ret != LDB_SUCCESS) {
980 DEBUG(1,("Failed to modify record %s: %s\n",
981 ldb_dn_get_linearized(d_state->domain_dn),
982 ldb_errstring(sam_ctx)));
983 return dsdb_ldb_err_to_ntstatus(ret);
986 return NT_STATUS_OK;
990 samr_CreateDomainGroup
992 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
993 struct samr_CreateDomainGroup *r)
995 NTSTATUS status;
996 struct samr_domain_state *d_state;
997 struct samr_account_state *a_state;
998 struct dcesrv_handle *h;
999 const char *groupname;
1000 struct dom_sid *group_sid;
1001 struct ldb_dn *group_dn;
1002 struct dcesrv_handle *g_handle;
1004 ZERO_STRUCTP(r->out.group_handle);
1005 *r->out.rid = 0;
1007 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1009 d_state = h->data;
1011 if (d_state->builtin) {
1012 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1013 return NT_STATUS_ACCESS_DENIED;
1016 groupname = r->in.name->string;
1018 if (groupname == NULL) {
1019 return NT_STATUS_INVALID_PARAMETER;
1022 status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1023 if (!NT_STATUS_IS_OK(status)) {
1024 return status;
1027 a_state = talloc(mem_ctx, struct samr_account_state);
1028 if (!a_state) {
1029 return NT_STATUS_NO_MEMORY;
1031 a_state->sam_ctx = d_state->sam_ctx;
1032 a_state->access_mask = r->in.access_mask;
1033 a_state->domain_state = talloc_reference(a_state, d_state);
1034 a_state->account_dn = talloc_steal(a_state, group_dn);
1036 a_state->account_name = talloc_steal(a_state, groupname);
1038 /* create the policy handle */
1039 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1040 if (!g_handle) {
1041 return NT_STATUS_NO_MEMORY;
1044 g_handle->data = talloc_steal(g_handle, a_state);
1046 *r->out.group_handle = g_handle->wire_handle;
1047 *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1049 return NT_STATUS_OK;
1054 comparison function for sorting SamEntry array
1056 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1058 return e1->idx - e2->idx;
1062 samr_EnumDomainGroups
1064 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1065 struct samr_EnumDomainGroups *r)
1067 struct dcesrv_handle *h;
1068 struct samr_domain_state *d_state;
1069 struct ldb_message **res;
1070 int i, ldb_cnt;
1071 uint32_t first, count;
1072 struct samr_SamEntry *entries;
1073 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1074 struct samr_SamArray *sam;
1076 *r->out.resume_handle = 0;
1077 *r->out.sam = NULL;
1078 *r->out.num_entries = 0;
1080 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1082 d_state = h->data;
1084 /* search for all domain groups in this domain. This could possibly be
1085 cached and resumed based on resume_key */
1086 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1087 d_state->domain_dn, &res, attrs,
1088 d_state->domain_sid,
1089 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1090 GTYPE_SECURITY_UNIVERSAL_GROUP,
1091 GTYPE_SECURITY_GLOBAL_GROUP);
1092 if (ldb_cnt < 0) {
1093 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1096 /* convert to SamEntry format */
1097 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1098 if (!entries) {
1099 return NT_STATUS_NO_MEMORY;
1102 count = 0;
1104 for (i=0;i<ldb_cnt;i++) {
1105 struct dom_sid *group_sid;
1107 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1108 "objectSid");
1109 if (group_sid == NULL) {
1110 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1113 entries[count].idx =
1114 group_sid->sub_auths[group_sid->num_auths-1];
1115 entries[count].name.string =
1116 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1117 count += 1;
1120 /* sort the results by rid */
1121 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1123 /* find the first entry to return */
1124 for (first=0;
1125 first<count && entries[first].idx <= *r->in.resume_handle;
1126 first++) ;
1128 /* return the rest, limit by max_size. Note that we
1129 use the w2k3 element size value of 54 */
1130 *r->out.num_entries = count - first;
1131 *r->out.num_entries = MIN(*r->out.num_entries,
1132 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1134 sam = talloc(mem_ctx, struct samr_SamArray);
1135 if (!sam) {
1136 return NT_STATUS_NO_MEMORY;
1139 sam->entries = entries+first;
1140 sam->count = *r->out.num_entries;
1142 *r->out.sam = sam;
1144 if (first == count) {
1145 return NT_STATUS_OK;
1148 if (*r->out.num_entries < count - first) {
1149 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1150 return STATUS_MORE_ENTRIES;
1153 return NT_STATUS_OK;
1158 samr_CreateUser2
1160 This call uses transactions to ensure we don't get a new conflicting
1161 user while we are processing this, and to ensure the user either
1162 completly exists, or does not.
1164 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1165 struct samr_CreateUser2 *r)
1167 NTSTATUS status;
1168 struct samr_domain_state *d_state;
1169 struct samr_account_state *a_state;
1170 struct dcesrv_handle *h;
1171 struct ldb_dn *dn;
1172 struct dom_sid *sid;
1173 struct dcesrv_handle *u_handle;
1174 const char *account_name;
1176 ZERO_STRUCTP(r->out.user_handle);
1177 *r->out.access_granted = 0;
1178 *r->out.rid = 0;
1180 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1182 d_state = h->data;
1184 if (d_state->builtin) {
1185 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1186 return NT_STATUS_ACCESS_DENIED;
1187 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1188 /* Domain trust accounts must be created by the LSA calls */
1189 return NT_STATUS_ACCESS_DENIED;
1191 account_name = r->in.account_name->string;
1193 if (account_name == NULL) {
1194 return NT_STATUS_INVALID_PARAMETER;
1197 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
1198 &sid, &dn);
1199 if (!NT_STATUS_IS_OK(status)) {
1200 return status;
1202 a_state = talloc(mem_ctx, struct samr_account_state);
1203 if (!a_state) {
1204 return NT_STATUS_NO_MEMORY;
1206 a_state->sam_ctx = d_state->sam_ctx;
1207 a_state->access_mask = r->in.access_mask;
1208 a_state->domain_state = talloc_reference(a_state, d_state);
1209 a_state->account_dn = talloc_steal(a_state, dn);
1211 a_state->account_name = talloc_steal(a_state, account_name);
1212 if (!a_state->account_name) {
1213 return NT_STATUS_NO_MEMORY;
1216 /* create the policy handle */
1217 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1218 if (!u_handle) {
1219 return NT_STATUS_NO_MEMORY;
1222 u_handle->data = talloc_steal(u_handle, a_state);
1224 *r->out.user_handle = u_handle->wire_handle;
1225 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1227 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1229 return NT_STATUS_OK;
1234 samr_CreateUser
1236 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1237 struct samr_CreateUser *r)
1239 struct samr_CreateUser2 r2;
1240 uint32_t access_granted = 0;
1243 /* a simple wrapper around samr_CreateUser2 works nicely */
1244 r2.in.domain_handle = r->in.domain_handle;
1245 r2.in.account_name = r->in.account_name;
1246 r2.in.acct_flags = ACB_NORMAL;
1247 r2.in.access_mask = r->in.access_mask;
1248 r2.out.user_handle = r->out.user_handle;
1249 r2.out.access_granted = &access_granted;
1250 r2.out.rid = r->out.rid;
1252 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1256 samr_EnumDomainUsers
1258 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1259 struct samr_EnumDomainUsers *r)
1261 struct dcesrv_handle *h;
1262 struct samr_domain_state *d_state;
1263 struct ldb_message **res;
1264 int i, ldb_cnt;
1265 uint32_t first, count;
1266 struct samr_SamEntry *entries;
1267 const char * const attrs[] = { "objectSid", "sAMAccountName",
1268 "userAccountControl", NULL };
1269 struct samr_SamArray *sam;
1271 *r->out.resume_handle = 0;
1272 *r->out.sam = NULL;
1273 *r->out.num_entries = 0;
1275 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1277 d_state = h->data;
1279 /* search for all domain users in this domain. This could possibly be
1280 cached and resumed on resume_key */
1281 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1282 d_state->domain_dn,
1283 &res, attrs,
1284 d_state->domain_sid,
1285 "(objectClass=user)");
1286 if (ldb_cnt < 0) {
1287 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1290 /* convert to SamEntry format */
1291 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1292 if (!entries) {
1293 return NT_STATUS_NO_MEMORY;
1296 count = 0;
1298 for (i=0;i<ldb_cnt;i++) {
1299 /* Check if a mask has been requested */
1300 if (r->in.acct_flags
1301 && ((samdb_result_acct_flags(res[i], NULL) & r->in.acct_flags) == 0)) {
1302 continue;
1304 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1305 "objectSid", 0);
1306 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1307 "sAMAccountName", "");
1308 count += 1;
1311 /* sort the results by rid */
1312 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1314 /* find the first entry to return */
1315 for (first=0;
1316 first<count && entries[first].idx <= *r->in.resume_handle;
1317 first++) ;
1319 /* return the rest, limit by max_size. Note that we
1320 use the w2k3 element size value of 54 */
1321 *r->out.num_entries = count - first;
1322 *r->out.num_entries = MIN(*r->out.num_entries,
1323 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1325 sam = talloc(mem_ctx, struct samr_SamArray);
1326 if (!sam) {
1327 return NT_STATUS_NO_MEMORY;
1330 sam->entries = entries+first;
1331 sam->count = *r->out.num_entries;
1333 *r->out.sam = sam;
1335 if (first == count) {
1336 return NT_STATUS_OK;
1339 if (*r->out.num_entries < count - first) {
1340 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1341 return STATUS_MORE_ENTRIES;
1344 return NT_STATUS_OK;
1349 samr_CreateDomAlias
1351 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1352 struct samr_CreateDomAlias *r)
1354 struct samr_domain_state *d_state;
1355 struct samr_account_state *a_state;
1356 struct dcesrv_handle *h;
1357 const char *alias_name;
1358 struct dom_sid *sid;
1359 struct dcesrv_handle *a_handle;
1360 struct ldb_dn *dn;
1361 NTSTATUS status;
1363 ZERO_STRUCTP(r->out.alias_handle);
1364 *r->out.rid = 0;
1366 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1368 d_state = h->data;
1370 if (d_state->builtin) {
1371 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1372 return NT_STATUS_ACCESS_DENIED;
1375 alias_name = r->in.alias_name->string;
1377 if (alias_name == NULL) {
1378 return NT_STATUS_INVALID_PARAMETER;
1381 status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1382 if (!NT_STATUS_IS_OK(status)) {
1383 return status;
1386 a_state = talloc(mem_ctx, struct samr_account_state);
1387 if (!a_state) {
1388 return NT_STATUS_NO_MEMORY;
1391 a_state->sam_ctx = d_state->sam_ctx;
1392 a_state->access_mask = r->in.access_mask;
1393 a_state->domain_state = talloc_reference(a_state, d_state);
1394 a_state->account_dn = talloc_steal(a_state, dn);
1396 a_state->account_name = talloc_steal(a_state, alias_name);
1398 /* create the policy handle */
1399 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1400 if (a_handle == NULL)
1401 return NT_STATUS_NO_MEMORY;
1403 a_handle->data = talloc_steal(a_handle, a_state);
1405 *r->out.alias_handle = a_handle->wire_handle;
1407 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1409 return NT_STATUS_OK;
1414 samr_EnumDomainAliases
1416 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1417 struct samr_EnumDomainAliases *r)
1419 struct dcesrv_handle *h;
1420 struct samr_domain_state *d_state;
1421 struct ldb_message **res;
1422 int i, ldb_cnt;
1423 uint32_t first, count;
1424 struct samr_SamEntry *entries;
1425 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1426 struct samr_SamArray *sam;
1428 *r->out.resume_handle = 0;
1429 *r->out.sam = NULL;
1430 *r->out.num_entries = 0;
1432 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1434 d_state = h->data;
1436 /* search for all domain aliases in this domain. This could possibly be
1437 cached and resumed based on resume_key */
1438 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1439 &res, attrs,
1440 d_state->domain_sid,
1441 "(&(|(grouptype=%d)(grouptype=%d)))"
1442 "(objectclass=group))",
1443 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1444 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1445 if (ldb_cnt < 0) {
1446 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1449 /* convert to SamEntry format */
1450 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1451 if (!entries) {
1452 return NT_STATUS_NO_MEMORY;
1455 count = 0;
1457 for (i=0;i<ldb_cnt;i++) {
1458 struct dom_sid *alias_sid;
1460 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1461 "objectSid");
1463 if (alias_sid == NULL) {
1464 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1467 entries[count].idx =
1468 alias_sid->sub_auths[alias_sid->num_auths-1];
1469 entries[count].name.string =
1470 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1471 count += 1;
1474 /* sort the results by rid */
1475 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1477 /* find the first entry to return */
1478 for (first=0;
1479 first<count && entries[first].idx <= *r->in.resume_handle;
1480 first++) ;
1482 /* return the rest, limit by max_size. Note that we
1483 use the w2k3 element size value of 54 */
1484 *r->out.num_entries = count - first;
1485 *r->out.num_entries = MIN(*r->out.num_entries,
1486 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1488 sam = talloc(mem_ctx, struct samr_SamArray);
1489 if (!sam) {
1490 return NT_STATUS_NO_MEMORY;
1493 sam->entries = entries+first;
1494 sam->count = *r->out.num_entries;
1496 *r->out.sam = sam;
1498 if (first == count) {
1499 return NT_STATUS_OK;
1502 if (*r->out.num_entries < count - first) {
1503 *r->out.resume_handle =
1504 entries[first+*r->out.num_entries-1].idx;
1505 return STATUS_MORE_ENTRIES;
1508 return NT_STATUS_OK;
1513 samr_GetAliasMembership
1515 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1516 struct samr_GetAliasMembership *r)
1518 struct dcesrv_handle *h;
1519 struct samr_domain_state *d_state;
1520 const char *filter;
1521 const char * const attrs[] = { "objectSid", NULL };
1522 struct ldb_message **res;
1523 uint32_t i;
1524 int count = 0;
1526 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1528 d_state = h->data;
1530 filter = talloc_asprintf(mem_ctx,
1531 "(&(|(grouptype=%d)(grouptype=%d))"
1532 "(objectclass=group)(|",
1533 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1534 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1535 if (filter == NULL) {
1536 return NT_STATUS_NO_MEMORY;
1539 for (i=0; i<r->in.sids->num_sids; i++) {
1540 const char *memberdn;
1542 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1543 "distinguishedName",
1544 "(objectSid=%s)",
1545 ldap_encode_ndr_dom_sid(mem_ctx,
1546 r->in.sids->sids[i].sid));
1547 if (memberdn == NULL) {
1548 continue;
1551 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1552 memberdn);
1553 if (filter == NULL) {
1554 return NT_STATUS_NO_MEMORY;
1558 /* Find out if we had at least one valid member SID passed - otherwise
1559 * just skip the search. */
1560 if (strstr(filter, "member") != NULL) {
1561 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1562 &res, attrs, d_state->domain_sid,
1563 "%s))", filter);
1564 if (count < 0) {
1565 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1569 r->out.rids->count = 0;
1570 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1571 if (r->out.rids->ids == NULL)
1572 return NT_STATUS_NO_MEMORY;
1574 for (i=0; i<count; i++) {
1575 struct dom_sid *alias_sid;
1577 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1578 if (alias_sid == NULL) {
1579 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1582 r->out.rids->ids[r->out.rids->count] =
1583 alias_sid->sub_auths[alias_sid->num_auths-1];
1584 r->out.rids->count += 1;
1587 return NT_STATUS_OK;
1592 samr_LookupNames
1594 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1595 struct samr_LookupNames *r)
1597 struct dcesrv_handle *h;
1598 struct samr_domain_state *d_state;
1599 uint32_t i, num_mapped;
1600 NTSTATUS status = NT_STATUS_OK;
1601 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1602 int count;
1604 ZERO_STRUCTP(r->out.rids);
1605 ZERO_STRUCTP(r->out.types);
1607 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1609 d_state = h->data;
1611 if (r->in.num_names == 0) {
1612 return NT_STATUS_OK;
1615 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1616 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1617 if (!r->out.rids->ids || !r->out.types->ids) {
1618 return NT_STATUS_NO_MEMORY;
1620 r->out.rids->count = r->in.num_names;
1621 r->out.types->count = r->in.num_names;
1623 num_mapped = 0;
1625 for (i=0;i<r->in.num_names;i++) {
1626 struct ldb_message **res;
1627 struct dom_sid *sid;
1628 uint32_t atype, rtype;
1630 r->out.rids->ids[i] = 0;
1631 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1633 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1634 "sAMAccountName=%s",
1635 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1636 if (count != 1) {
1637 status = STATUS_SOME_UNMAPPED;
1638 continue;
1641 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1642 if (sid == NULL) {
1643 status = STATUS_SOME_UNMAPPED;
1644 continue;
1647 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1648 if (atype == 0) {
1649 status = STATUS_SOME_UNMAPPED;
1650 continue;
1653 rtype = ds_atype_map(atype);
1655 if (rtype == SID_NAME_UNKNOWN) {
1656 status = STATUS_SOME_UNMAPPED;
1657 continue;
1660 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1661 r->out.types->ids[i] = rtype;
1662 num_mapped++;
1665 if (num_mapped == 0) {
1666 return NT_STATUS_NONE_MAPPED;
1668 return status;
1673 samr_LookupRids
1675 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1676 struct samr_LookupRids *r)
1678 NTSTATUS status;
1679 struct dcesrv_handle *h;
1680 struct samr_domain_state *d_state;
1681 const char **names;
1682 struct lsa_String *lsa_names;
1683 enum lsa_SidType *ids;
1685 ZERO_STRUCTP(r->out.names);
1686 ZERO_STRUCTP(r->out.types);
1688 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1690 d_state = h->data;
1692 if (r->in.num_rids == 0)
1693 return NT_STATUS_OK;
1695 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1696 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1697 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1699 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1700 return NT_STATUS_NO_MEMORY;
1702 r->out.names->names = lsa_names;
1703 r->out.names->count = r->in.num_rids;
1705 r->out.types->ids = (uint32_t *) ids;
1706 r->out.types->count = r->in.num_rids;
1708 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1709 r->in.num_rids, r->in.rids, names, ids);
1710 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1711 uint32_t i;
1712 for (i = 0; i < r->in.num_rids; i++) {
1713 lsa_names[i].string = names[i];
1716 return status;
1721 samr_OpenGroup
1723 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1724 struct samr_OpenGroup *r)
1726 struct samr_domain_state *d_state;
1727 struct samr_account_state *a_state;
1728 struct dcesrv_handle *h;
1729 const char *groupname;
1730 struct dom_sid *sid;
1731 struct ldb_message **msgs;
1732 struct dcesrv_handle *g_handle;
1733 const char * const attrs[2] = { "sAMAccountName", NULL };
1734 int ret;
1736 ZERO_STRUCTP(r->out.group_handle);
1738 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1740 d_state = h->data;
1742 /* form the group SID */
1743 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1744 if (!sid) {
1745 return NT_STATUS_NO_MEMORY;
1748 /* search for the group record */
1749 if (d_state->builtin) {
1750 ret = gendb_search(d_state->sam_ctx,
1751 mem_ctx, d_state->domain_dn, &msgs, attrs,
1752 "(&(objectSid=%s)(objectClass=group)"
1753 "(groupType=%d))",
1754 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1755 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
1756 } else {
1757 ret = gendb_search(d_state->sam_ctx,
1758 mem_ctx, d_state->domain_dn, &msgs, attrs,
1759 "(&(objectSid=%s)(objectClass=group)"
1760 "(|(groupType=%d)(groupType=%d)))",
1761 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1762 GTYPE_SECURITY_UNIVERSAL_GROUP,
1763 GTYPE_SECURITY_GLOBAL_GROUP);
1765 if (ret == 0) {
1766 return NT_STATUS_NO_SUCH_GROUP;
1768 if (ret != 1) {
1769 DEBUG(0,("Found %d records matching sid %s\n",
1770 ret, dom_sid_string(mem_ctx, sid)));
1771 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1774 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1775 if (groupname == NULL) {
1776 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1777 dom_sid_string(mem_ctx, sid)));
1778 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1781 a_state = talloc(mem_ctx, struct samr_account_state);
1782 if (!a_state) {
1783 return NT_STATUS_NO_MEMORY;
1785 a_state->sam_ctx = d_state->sam_ctx;
1786 a_state->access_mask = r->in.access_mask;
1787 a_state->domain_state = talloc_reference(a_state, d_state);
1788 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1789 a_state->account_sid = talloc_steal(a_state, sid);
1790 a_state->account_name = talloc_strdup(a_state, groupname);
1791 if (!a_state->account_name) {
1792 return NT_STATUS_NO_MEMORY;
1795 /* create the policy handle */
1796 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1797 if (!g_handle) {
1798 return NT_STATUS_NO_MEMORY;
1801 g_handle->data = talloc_steal(g_handle, a_state);
1803 *r->out.group_handle = g_handle->wire_handle;
1805 return NT_STATUS_OK;
1809 samr_QueryGroupInfo
1811 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1812 struct samr_QueryGroupInfo *r)
1814 struct dcesrv_handle *h;
1815 struct samr_account_state *a_state;
1816 struct ldb_message *msg, **res;
1817 const char * const attrs[4] = { "sAMAccountName", "description",
1818 "numMembers", NULL };
1819 int ret;
1820 union samr_GroupInfo *info;
1822 *r->out.info = NULL;
1824 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1826 a_state = h->data;
1828 /* pull all the group attributes */
1829 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1830 a_state->account_dn, &res, attrs);
1831 if (ret == 0) {
1832 return NT_STATUS_NO_SUCH_GROUP;
1834 if (ret != 1) {
1835 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1837 msg = res[0];
1839 /* allocate the info structure */
1840 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1841 if (info == NULL) {
1842 return NT_STATUS_NO_MEMORY;
1845 /* Fill in the level */
1846 switch (r->in.level) {
1847 case GROUPINFOALL:
1848 QUERY_STRING(msg, all.name, "sAMAccountName");
1849 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1850 QUERY_UINT (msg, all.num_members, "numMembers")
1851 QUERY_STRING(msg, all.description, "description");
1852 break;
1853 case GROUPINFONAME:
1854 QUERY_STRING(msg, name, "sAMAccountName");
1855 break;
1856 case GROUPINFOATTRIBUTES:
1857 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1858 break;
1859 case GROUPINFODESCRIPTION:
1860 QUERY_STRING(msg, description, "description");
1861 break;
1862 case GROUPINFOALL2:
1863 QUERY_STRING(msg, all2.name, "sAMAccountName");
1864 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1865 QUERY_UINT (msg, all2.num_members, "numMembers")
1866 QUERY_STRING(msg, all2.description, "description");
1867 break;
1868 default:
1869 talloc_free(info);
1870 return NT_STATUS_INVALID_INFO_CLASS;
1873 *r->out.info = info;
1875 return NT_STATUS_OK;
1880 samr_SetGroupInfo
1882 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1883 struct samr_SetGroupInfo *r)
1885 struct dcesrv_handle *h;
1886 struct samr_account_state *g_state;
1887 struct ldb_message *msg;
1888 struct ldb_context *sam_ctx;
1889 int ret;
1891 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1893 g_state = h->data;
1894 sam_ctx = g_state->sam_ctx;
1896 msg = ldb_msg_new(mem_ctx);
1897 if (msg == NULL) {
1898 return NT_STATUS_NO_MEMORY;
1901 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1902 if (!msg->dn) {
1903 return NT_STATUS_NO_MEMORY;
1906 switch (r->in.level) {
1907 case GROUPINFODESCRIPTION:
1908 SET_STRING(msg, description, "description");
1909 break;
1910 case GROUPINFONAME:
1911 /* On W2k3 this does not change the name, it changes the
1912 * sAMAccountName attribute */
1913 SET_STRING(msg, name, "sAMAccountName");
1914 break;
1915 case GROUPINFOATTRIBUTES:
1916 /* This does not do anything obviously visible in W2k3 LDAP */
1917 return NT_STATUS_OK;
1918 default:
1919 return NT_STATUS_INVALID_INFO_CLASS;
1922 /* modify the samdb record */
1923 ret = ldb_modify(g_state->sam_ctx, msg);
1924 if (ret != LDB_SUCCESS) {
1925 return dsdb_ldb_err_to_ntstatus(ret);
1928 return NT_STATUS_OK;
1933 samr_AddGroupMember
1935 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1936 struct samr_AddGroupMember *r)
1938 struct dcesrv_handle *h;
1939 struct samr_account_state *a_state;
1940 struct samr_domain_state *d_state;
1941 struct ldb_message *mod;
1942 struct dom_sid *membersid;
1943 const char *memberdn;
1944 struct ldb_result *res;
1945 const char * const attrs[] = { NULL };
1946 int ret;
1948 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1950 a_state = h->data;
1951 d_state = a_state->domain_state;
1953 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1954 if (membersid == NULL) {
1955 return NT_STATUS_NO_MEMORY;
1958 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1959 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1960 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1961 "(objectSid=%s)",
1962 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1964 if (ret != LDB_SUCCESS) {
1965 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1968 if (res->count == 0) {
1969 return NT_STATUS_NO_SUCH_USER;
1972 if (res->count > 1) {
1973 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1976 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1978 if (memberdn == NULL)
1979 return NT_STATUS_NO_MEMORY;
1981 mod = ldb_msg_new(mem_ctx);
1982 if (mod == NULL) {
1983 return NT_STATUS_NO_MEMORY;
1986 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1988 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1989 memberdn);
1990 if (ret != LDB_SUCCESS) {
1991 return dsdb_ldb_err_to_ntstatus(ret);
1994 ret = ldb_modify(a_state->sam_ctx, mod);
1995 switch (ret) {
1996 case LDB_SUCCESS:
1997 return NT_STATUS_OK;
1998 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1999 return NT_STATUS_MEMBER_IN_GROUP;
2000 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2001 return NT_STATUS_ACCESS_DENIED;
2002 default:
2003 return dsdb_ldb_err_to_ntstatus(ret);
2009 samr_DeleteDomainGroup
2011 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2012 struct samr_DeleteDomainGroup *r)
2014 struct dcesrv_handle *h;
2015 struct samr_account_state *a_state;
2016 int ret;
2018 *r->out.group_handle = *r->in.group_handle;
2020 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2022 a_state = h->data;
2024 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2025 if (ret != LDB_SUCCESS) {
2026 return dsdb_ldb_err_to_ntstatus(ret);
2029 talloc_free(h);
2030 ZERO_STRUCTP(r->out.group_handle);
2032 return NT_STATUS_OK;
2037 samr_DeleteGroupMember
2039 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2040 struct samr_DeleteGroupMember *r)
2042 struct dcesrv_handle *h;
2043 struct samr_account_state *a_state;
2044 struct samr_domain_state *d_state;
2045 struct ldb_message *mod;
2046 struct dom_sid *membersid;
2047 const char *memberdn;
2048 struct ldb_result *res;
2049 const char * const attrs[] = { NULL };
2050 int ret;
2052 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2054 a_state = h->data;
2055 d_state = a_state->domain_state;
2057 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2058 if (membersid == NULL) {
2059 return NT_STATUS_NO_MEMORY;
2062 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2063 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2064 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2065 "(objectSid=%s)",
2066 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2068 if (ret != LDB_SUCCESS) {
2069 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2072 if (res->count == 0) {
2073 return NT_STATUS_NO_SUCH_USER;
2076 if (res->count > 1) {
2077 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2080 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2082 if (memberdn == NULL)
2083 return NT_STATUS_NO_MEMORY;
2085 mod = ldb_msg_new(mem_ctx);
2086 if (mod == NULL) {
2087 return NT_STATUS_NO_MEMORY;
2090 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2092 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2093 memberdn);
2094 if (ret != LDB_SUCCESS) {
2095 return NT_STATUS_NO_MEMORY;
2098 ret = ldb_modify(a_state->sam_ctx, mod);
2099 switch (ret) {
2100 case LDB_SUCCESS:
2101 return NT_STATUS_OK;
2102 case LDB_ERR_UNWILLING_TO_PERFORM:
2103 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2104 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2105 return NT_STATUS_ACCESS_DENIED;
2106 default:
2107 return dsdb_ldb_err_to_ntstatus(ret);
2113 samr_QueryGroupMember
2115 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2116 struct samr_QueryGroupMember *r)
2118 struct dcesrv_handle *h;
2119 struct samr_account_state *a_state;
2120 struct samr_domain_state *d_state;
2121 struct samr_RidAttrArray *array;
2122 unsigned int i, num_members;
2123 struct dom_sid *members;
2124 NTSTATUS status;
2126 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2128 a_state = h->data;
2129 d_state = a_state->domain_state;
2131 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2132 a_state->account_dn, &members,
2133 &num_members);
2134 if (!NT_STATUS_IS_OK(status)) {
2135 return status;
2138 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2139 if (array == NULL) {
2140 return NT_STATUS_NO_MEMORY;
2143 if (num_members == 0) {
2144 *r->out.rids = array;
2146 return NT_STATUS_OK;
2149 array->rids = talloc_array(array, uint32_t, num_members);
2150 if (array->rids == NULL) {
2151 return NT_STATUS_NO_MEMORY;
2154 array->attributes = talloc_array(array, uint32_t, num_members);
2155 if (array->attributes == NULL) {
2156 return NT_STATUS_NO_MEMORY;
2159 array->count = 0;
2160 for (i=0; i<num_members; i++) {
2161 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2162 continue;
2165 status = dom_sid_split_rid(NULL, &members[i], NULL,
2166 &array->rids[array->count]);
2167 if (!NT_STATUS_IS_OK(status)) {
2168 return status;
2171 array->attributes[array->count] = SE_GROUP_MANDATORY |
2172 SE_GROUP_ENABLED_BY_DEFAULT |
2173 SE_GROUP_ENABLED;
2174 array->count++;
2177 *r->out.rids = array;
2179 return NT_STATUS_OK;
2184 samr_SetMemberAttributesOfGroup
2186 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2187 struct samr_SetMemberAttributesOfGroup *r)
2189 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2194 samr_OpenAlias
2196 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2197 struct samr_OpenAlias *r)
2199 struct samr_domain_state *d_state;
2200 struct samr_account_state *a_state;
2201 struct dcesrv_handle *h;
2202 const char *alias_name;
2203 struct dom_sid *sid;
2204 struct ldb_message **msgs;
2205 struct dcesrv_handle *g_handle;
2206 const char * const attrs[2] = { "sAMAccountName", NULL };
2207 int ret;
2209 ZERO_STRUCTP(r->out.alias_handle);
2211 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2213 d_state = h->data;
2215 /* form the alias SID */
2216 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2217 if (sid == NULL)
2218 return NT_STATUS_NO_MEMORY;
2220 /* search for the group record */
2221 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2222 "(&(objectSid=%s)(objectclass=group)"
2223 "(|(grouptype=%d)(grouptype=%d)))",
2224 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2225 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2226 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2227 if (ret == 0) {
2228 return NT_STATUS_NO_SUCH_ALIAS;
2230 if (ret != 1) {
2231 DEBUG(0,("Found %d records matching sid %s\n",
2232 ret, dom_sid_string(mem_ctx, sid)));
2233 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2236 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2237 if (alias_name == NULL) {
2238 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2239 dom_sid_string(mem_ctx, sid)));
2240 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2243 a_state = talloc(mem_ctx, struct samr_account_state);
2244 if (!a_state) {
2245 return NT_STATUS_NO_MEMORY;
2247 a_state->sam_ctx = d_state->sam_ctx;
2248 a_state->access_mask = r->in.access_mask;
2249 a_state->domain_state = talloc_reference(a_state, d_state);
2250 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2251 a_state->account_sid = talloc_steal(a_state, sid);
2252 a_state->account_name = talloc_strdup(a_state, alias_name);
2253 if (!a_state->account_name) {
2254 return NT_STATUS_NO_MEMORY;
2257 /* create the policy handle */
2258 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2259 if (!g_handle) {
2260 return NT_STATUS_NO_MEMORY;
2263 g_handle->data = talloc_steal(g_handle, a_state);
2265 *r->out.alias_handle = g_handle->wire_handle;
2267 return NT_STATUS_OK;
2272 samr_QueryAliasInfo
2274 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2275 struct samr_QueryAliasInfo *r)
2277 struct dcesrv_handle *h;
2278 struct samr_account_state *a_state;
2279 struct ldb_message *msg, **res;
2280 const char * const attrs[4] = { "sAMAccountName", "description",
2281 "numMembers", NULL };
2282 int ret;
2283 union samr_AliasInfo *info;
2285 *r->out.info = NULL;
2287 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2289 a_state = h->data;
2291 /* pull all the alias attributes */
2292 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2293 a_state->account_dn, &res, attrs);
2294 if (ret == 0) {
2295 return NT_STATUS_NO_SUCH_ALIAS;
2297 if (ret != 1) {
2298 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2300 msg = res[0];
2302 /* allocate the info structure */
2303 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2304 if (info == NULL) {
2305 return NT_STATUS_NO_MEMORY;
2308 switch(r->in.level) {
2309 case ALIASINFOALL:
2310 QUERY_STRING(msg, all.name, "sAMAccountName");
2311 QUERY_UINT (msg, all.num_members, "numMembers");
2312 QUERY_STRING(msg, all.description, "description");
2313 break;
2314 case ALIASINFONAME:
2315 QUERY_STRING(msg, name, "sAMAccountName");
2316 break;
2317 case ALIASINFODESCRIPTION:
2318 QUERY_STRING(msg, description, "description");
2319 break;
2320 default:
2321 talloc_free(info);
2322 return NT_STATUS_INVALID_INFO_CLASS;
2325 *r->out.info = info;
2327 return NT_STATUS_OK;
2332 samr_SetAliasInfo
2334 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2335 struct samr_SetAliasInfo *r)
2337 struct dcesrv_handle *h;
2338 struct samr_account_state *a_state;
2339 struct ldb_message *msg;
2340 struct ldb_context *sam_ctx;
2341 int ret;
2343 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2345 a_state = h->data;
2346 sam_ctx = a_state->sam_ctx;
2348 msg = ldb_msg_new(mem_ctx);
2349 if (msg == NULL) {
2350 return NT_STATUS_NO_MEMORY;
2353 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2354 if (!msg->dn) {
2355 return NT_STATUS_NO_MEMORY;
2358 switch (r->in.level) {
2359 case ALIASINFODESCRIPTION:
2360 SET_STRING(msg, description, "description");
2361 break;
2362 case ALIASINFONAME:
2363 /* On W2k3 this does not change the name, it changes the
2364 * sAMAccountName attribute */
2365 SET_STRING(msg, name, "sAMAccountName");
2366 break;
2367 default:
2368 return NT_STATUS_INVALID_INFO_CLASS;
2371 /* modify the samdb record */
2372 ret = ldb_modify(a_state->sam_ctx, msg);
2373 if (ret != LDB_SUCCESS) {
2374 return dsdb_ldb_err_to_ntstatus(ret);
2377 return NT_STATUS_OK;
2382 samr_DeleteDomAlias
2384 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2385 struct samr_DeleteDomAlias *r)
2387 struct dcesrv_handle *h;
2388 struct samr_account_state *a_state;
2389 int ret;
2391 *r->out.alias_handle = *r->in.alias_handle;
2393 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2395 a_state = h->data;
2397 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2398 if (ret != LDB_SUCCESS) {
2399 return dsdb_ldb_err_to_ntstatus(ret);
2402 talloc_free(h);
2403 ZERO_STRUCTP(r->out.alias_handle);
2405 return NT_STATUS_OK;
2410 samr_AddAliasMember
2412 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2413 struct samr_AddAliasMember *r)
2415 struct dcesrv_handle *h;
2416 struct samr_account_state *a_state;
2417 struct samr_domain_state *d_state;
2418 struct ldb_message *mod;
2419 struct ldb_message **msgs;
2420 const char * const attrs[] = { NULL };
2421 struct ldb_dn *memberdn = NULL;
2422 int ret;
2423 NTSTATUS status;
2425 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2427 a_state = h->data;
2428 d_state = a_state->domain_state;
2430 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2431 &msgs, attrs, "(objectsid=%s)",
2432 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2434 if (ret == 1) {
2435 memberdn = msgs[0]->dn;
2436 } else if (ret == 0) {
2437 status = samdb_create_foreign_security_principal(
2438 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2439 if (!NT_STATUS_IS_OK(status)) {
2440 return status;
2442 } else {
2443 DEBUG(0,("Found %d records matching sid %s\n",
2444 ret, dom_sid_string(mem_ctx, r->in.sid)));
2445 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2448 if (memberdn == NULL) {
2449 DEBUG(0, ("Could not find memberdn\n"));
2450 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2453 mod = ldb_msg_new(mem_ctx);
2454 if (mod == NULL) {
2455 return NT_STATUS_NO_MEMORY;
2458 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2460 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2461 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2462 if (ret != LDB_SUCCESS) {
2463 return dsdb_ldb_err_to_ntstatus(ret);
2466 ret = ldb_modify(a_state->sam_ctx, mod);
2467 switch (ret) {
2468 case LDB_SUCCESS:
2469 return NT_STATUS_OK;
2470 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2471 return NT_STATUS_MEMBER_IN_GROUP;
2472 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2473 return NT_STATUS_ACCESS_DENIED;
2474 default:
2475 return dsdb_ldb_err_to_ntstatus(ret);
2481 samr_DeleteAliasMember
2483 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2484 struct samr_DeleteAliasMember *r)
2486 struct dcesrv_handle *h;
2487 struct samr_account_state *a_state;
2488 struct samr_domain_state *d_state;
2489 struct ldb_message *mod;
2490 const char *memberdn;
2491 int ret;
2493 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2495 a_state = h->data;
2496 d_state = a_state->domain_state;
2498 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2499 "distinguishedName", "(objectSid=%s)",
2500 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2501 if (memberdn == NULL) {
2502 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2505 mod = ldb_msg_new(mem_ctx);
2506 if (mod == NULL) {
2507 return NT_STATUS_NO_MEMORY;
2510 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2512 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2513 memberdn);
2514 if (ret != LDB_SUCCESS) {
2515 return dsdb_ldb_err_to_ntstatus(ret);
2518 ret = ldb_modify(a_state->sam_ctx, mod);
2519 switch (ret) {
2520 case LDB_SUCCESS:
2521 return NT_STATUS_OK;
2522 case LDB_ERR_UNWILLING_TO_PERFORM:
2523 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2524 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2525 return NT_STATUS_ACCESS_DENIED;
2526 default:
2527 return dsdb_ldb_err_to_ntstatus(ret);
2533 samr_GetMembersInAlias
2535 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2536 struct samr_GetMembersInAlias *r)
2538 struct dcesrv_handle *h;
2539 struct samr_account_state *a_state;
2540 struct samr_domain_state *d_state;
2541 struct lsa_SidPtr *array;
2542 unsigned int i, num_members;
2543 struct dom_sid *members;
2544 NTSTATUS status;
2546 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2548 a_state = h->data;
2549 d_state = a_state->domain_state;
2551 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2552 a_state->account_dn, &members,
2553 &num_members);
2554 if (!NT_STATUS_IS_OK(status)) {
2555 return status;
2558 if (num_members == 0) {
2559 r->out.sids->sids = NULL;
2561 return NT_STATUS_OK;
2564 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2565 if (array == NULL) {
2566 return NT_STATUS_NO_MEMORY;
2569 for (i=0; i<num_members; i++) {
2570 array[i].sid = &members[i];
2573 r->out.sids->num_sids = num_members;
2574 r->out.sids->sids = array;
2576 return NT_STATUS_OK;
2580 samr_OpenUser
2582 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2583 struct samr_OpenUser *r)
2585 struct samr_domain_state *d_state;
2586 struct samr_account_state *a_state;
2587 struct dcesrv_handle *h;
2588 const char *account_name;
2589 struct dom_sid *sid;
2590 struct ldb_message **msgs;
2591 struct dcesrv_handle *u_handle;
2592 const char * const attrs[2] = { "sAMAccountName", NULL };
2593 int ret;
2595 ZERO_STRUCTP(r->out.user_handle);
2597 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2599 d_state = h->data;
2601 /* form the users SID */
2602 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2603 if (!sid) {
2604 return NT_STATUS_NO_MEMORY;
2607 /* search for the user record */
2608 ret = gendb_search(d_state->sam_ctx,
2609 mem_ctx, d_state->domain_dn, &msgs, attrs,
2610 "(&(objectSid=%s)(objectclass=user))",
2611 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2612 if (ret == 0) {
2613 return NT_STATUS_NO_SUCH_USER;
2615 if (ret != 1) {
2616 DEBUG(0,("Found %d records matching sid %s\n", ret,
2617 dom_sid_string(mem_ctx, sid)));
2618 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2621 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2622 if (account_name == NULL) {
2623 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2624 dom_sid_string(mem_ctx, sid)));
2625 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2628 a_state = talloc(mem_ctx, struct samr_account_state);
2629 if (!a_state) {
2630 return NT_STATUS_NO_MEMORY;
2632 a_state->sam_ctx = d_state->sam_ctx;
2633 a_state->access_mask = r->in.access_mask;
2634 a_state->domain_state = talloc_reference(a_state, d_state);
2635 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2636 a_state->account_sid = talloc_steal(a_state, sid);
2637 a_state->account_name = talloc_strdup(a_state, account_name);
2638 if (!a_state->account_name) {
2639 return NT_STATUS_NO_MEMORY;
2642 /* create the policy handle */
2643 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2644 if (!u_handle) {
2645 return NT_STATUS_NO_MEMORY;
2648 u_handle->data = talloc_steal(u_handle, a_state);
2650 *r->out.user_handle = u_handle->wire_handle;
2652 return NT_STATUS_OK;
2658 samr_DeleteUser
2660 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2661 struct samr_DeleteUser *r)
2663 struct dcesrv_handle *h;
2664 struct samr_account_state *a_state;
2665 int ret;
2667 *r->out.user_handle = *r->in.user_handle;
2669 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2671 a_state = h->data;
2673 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2674 if (ret != LDB_SUCCESS) {
2675 DEBUG(1, ("Failed to delete user: %s: %s\n",
2676 ldb_dn_get_linearized(a_state->account_dn),
2677 ldb_errstring(a_state->sam_ctx)));
2678 return dsdb_ldb_err_to_ntstatus(ret);
2681 talloc_free(h);
2682 ZERO_STRUCTP(r->out.user_handle);
2684 return NT_STATUS_OK;
2689 samr_QueryUserInfo
2691 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2692 struct samr_QueryUserInfo *r)
2694 struct dcesrv_handle *h;
2695 struct samr_account_state *a_state;
2696 struct ldb_message *msg, **res;
2697 int ret;
2698 struct ldb_context *sam_ctx;
2700 const char * const *attrs = NULL;
2701 union samr_UserInfo *info;
2703 *r->out.info = NULL;
2705 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2707 a_state = h->data;
2708 sam_ctx = a_state->sam_ctx;
2710 /* fill in the reply */
2711 switch (r->in.level) {
2712 case 1:
2714 static const char * const attrs2[] = {"sAMAccountName",
2715 "displayName",
2716 "primaryroupID",
2717 "description",
2718 "comment",
2719 NULL};
2720 attrs = attrs2;
2721 break;
2723 case 2:
2725 static const char * const attrs2[] = {"comment",
2726 "countryCode",
2727 "codePage",
2728 NULL};
2729 attrs = attrs2;
2730 break;
2732 case 3:
2734 static const char * const attrs2[] = {"sAMAccountName",
2735 "displayName",
2736 "objectSid",
2737 "primaryGroupID",
2738 "homeDirectory",
2739 "homeDrive",
2740 "scriptPath",
2741 "profilePath",
2742 "userWorkstations",
2743 "lastLogon",
2744 "lastLogoff",
2745 "pwdLastSet",
2746 "logonHours",
2747 "badPwdCount",
2748 "badPasswordTime",
2749 "logonCount",
2750 "userAccountControl",
2751 "msDS-User-Account-Control-Computed",
2752 NULL};
2753 attrs = attrs2;
2754 break;
2756 case 4:
2758 static const char * const attrs2[] = {"logonHours",
2759 NULL};
2760 attrs = attrs2;
2761 break;
2763 case 5:
2765 static const char * const attrs2[] = {"sAMAccountName",
2766 "displayName",
2767 "objectSid",
2768 "primaryGroupID",
2769 "homeDirectory",
2770 "homeDrive",
2771 "scriptPath",
2772 "profilePath",
2773 "description",
2774 "userWorkstations",
2775 "lastLogon",
2776 "lastLogoff",
2777 "logonHours",
2778 "badPwdCount",
2779 "badPasswordTime",
2780 "logonCount",
2781 "pwdLastSet",
2782 "accountExpires",
2783 "userAccountControl",
2784 "msDS-User-Account-Control-Computed",
2785 NULL};
2786 attrs = attrs2;
2787 break;
2789 case 6:
2791 static const char * const attrs2[] = {"sAMAccountName",
2792 "displayName",
2793 NULL};
2794 attrs = attrs2;
2795 break;
2797 case 7:
2799 static const char * const attrs2[] = {"sAMAccountName",
2800 NULL};
2801 attrs = attrs2;
2802 break;
2804 case 8:
2806 static const char * const attrs2[] = {"displayName",
2807 NULL};
2808 attrs = attrs2;
2809 break;
2811 case 9:
2813 static const char * const attrs2[] = {"primaryGroupID",
2814 NULL};
2815 attrs = attrs2;
2816 break;
2818 case 10:
2820 static const char * const attrs2[] = {"homeDirectory",
2821 "homeDrive",
2822 NULL};
2823 attrs = attrs2;
2824 break;
2826 case 11:
2828 static const char * const attrs2[] = {"scriptPath",
2829 NULL};
2830 attrs = attrs2;
2831 break;
2833 case 12:
2835 static const char * const attrs2[] = {"profilePath",
2836 NULL};
2837 attrs = attrs2;
2838 break;
2840 case 13:
2842 static const char * const attrs2[] = {"description",
2843 NULL};
2844 attrs = attrs2;
2845 break;
2847 case 14:
2849 static const char * const attrs2[] = {"userWorkstations",
2850 NULL};
2851 attrs = attrs2;
2852 break;
2854 case 16:
2856 static const char * const attrs2[] = {"userAccountControl",
2857 "msDS-User-Account-Control-Computed",
2858 "pwdLastSet",
2859 NULL};
2860 attrs = attrs2;
2861 break;
2863 case 17:
2865 static const char * const attrs2[] = {"accountExpires",
2866 NULL};
2867 attrs = attrs2;
2868 break;
2870 case 18:
2872 return NT_STATUS_NOT_SUPPORTED;
2874 case 20:
2876 static const char * const attrs2[] = {"userParameters",
2877 NULL};
2878 attrs = attrs2;
2879 break;
2881 case 21:
2883 static const char * const attrs2[] = {"lastLogon",
2884 "lastLogoff",
2885 "pwdLastSet",
2886 "accountExpires",
2887 "sAMAccountName",
2888 "displayName",
2889 "homeDirectory",
2890 "homeDrive",
2891 "scriptPath",
2892 "profilePath",
2893 "description",
2894 "userWorkstations",
2895 "comment",
2896 "userParameters",
2897 "objectSid",
2898 "primaryGroupID",
2899 "userAccountControl",
2900 "msDS-User-Account-Control-Computed",
2901 "logonHours",
2902 "badPwdCount",
2903 "badPasswordTime",
2904 "logonCount",
2905 "countryCode",
2906 "codePage",
2907 NULL};
2908 attrs = attrs2;
2909 break;
2911 case 23:
2912 case 24:
2913 case 25:
2914 case 26:
2916 return NT_STATUS_NOT_SUPPORTED;
2918 default:
2920 return NT_STATUS_INVALID_INFO_CLASS;
2924 /* pull all the user attributes */
2925 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2926 a_state->account_dn, &res, attrs);
2927 if (ret == 0) {
2928 return NT_STATUS_NO_SUCH_USER;
2930 if (ret != 1) {
2931 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2933 msg = res[0];
2935 /* allocate the info structure */
2936 info = talloc_zero(mem_ctx, union samr_UserInfo);
2937 if (info == NULL) {
2938 return NT_STATUS_NO_MEMORY;
2941 /* fill in the reply */
2942 switch (r->in.level) {
2943 case 1:
2944 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2945 QUERY_STRING(msg, info1.full_name, "displayName");
2946 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2947 QUERY_STRING(msg, info1.description, "description");
2948 QUERY_STRING(msg, info1.comment, "comment");
2949 break;
2951 case 2:
2952 QUERY_STRING(msg, info2.comment, "comment");
2953 QUERY_UINT (msg, info2.country_code, "countryCode");
2954 QUERY_UINT (msg, info2.code_page, "codePage");
2955 break;
2957 case 3:
2958 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2959 QUERY_STRING(msg, info3.full_name, "displayName");
2960 QUERY_RID (msg, info3.rid, "objectSid");
2961 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2962 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2963 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2964 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2965 QUERY_STRING(msg, info3.profile_path, "profilePath");
2966 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2967 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2968 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2969 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2970 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2971 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2972 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2973 /* level 3 gives the raw badPwdCount value */
2974 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2975 QUERY_UINT (msg, info3.logon_count, "logonCount");
2976 QUERY_AFLAGS(msg, info3.acct_flags, "msDS-User-Account-Control-Computed");
2977 break;
2979 case 4:
2980 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2981 break;
2983 case 5:
2984 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2985 QUERY_STRING(msg, info5.full_name, "displayName");
2986 QUERY_RID (msg, info5.rid, "objectSid");
2987 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2988 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2989 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2990 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2991 QUERY_STRING(msg, info5.profile_path, "profilePath");
2992 QUERY_STRING(msg, info5.description, "description");
2993 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2994 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2995 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2996 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2997 QUERY_BPWDCT(msg, info5.bad_password_count, "badPwdCount");
2998 QUERY_UINT (msg, info5.logon_count, "logonCount");
2999 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3000 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3001 QUERY_AFLAGS(msg, info5.acct_flags, "msDS-User-Account-Control-Computed");
3002 break;
3004 case 6:
3005 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3006 QUERY_STRING(msg, info6.full_name, "displayName");
3007 break;
3009 case 7:
3010 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3011 break;
3013 case 8:
3014 QUERY_STRING(msg, info8.full_name, "displayName");
3015 break;
3017 case 9:
3018 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3019 break;
3021 case 10:
3022 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3023 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3024 break;
3026 case 11:
3027 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3028 break;
3030 case 12:
3031 QUERY_STRING(msg, info12.profile_path, "profilePath");
3032 break;
3034 case 13:
3035 QUERY_STRING(msg, info13.description, "description");
3036 break;
3038 case 14:
3039 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3040 break;
3042 case 16:
3043 QUERY_AFLAGS(msg, info16.acct_flags, "msDS-User-Account-Control-Computed");
3044 break;
3046 case 17:
3047 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3048 break;
3050 case 20:
3051 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3052 break;
3054 case 21:
3055 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3056 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3057 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3058 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3059 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3060 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3061 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3062 QUERY_STRING(msg, info21.full_name, "displayName");
3063 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3064 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3065 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3066 QUERY_STRING(msg, info21.profile_path, "profilePath");
3067 QUERY_STRING(msg, info21.description, "description");
3068 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3069 QUERY_STRING(msg, info21.comment, "comment");
3070 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3071 QUERY_RID (msg, info21.rid, "objectSid");
3072 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3073 QUERY_AFLAGS(msg, info21.acct_flags, "msDS-User-Account-Control-Computed");
3074 info->info21.fields_present = 0x08FFFFFF;
3075 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3076 QUERY_BPWDCT(msg, info21.bad_password_count, "badPwdCount");
3077 QUERY_UINT (msg, info21.logon_count, "logonCount");
3078 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3079 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3080 } else {
3081 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3083 QUERY_UINT (msg, info21.country_code, "countryCode");
3084 QUERY_UINT (msg, info21.code_page, "codePage");
3085 break;
3088 default:
3089 talloc_free(info);
3090 return NT_STATUS_INVALID_INFO_CLASS;
3093 *r->out.info = info;
3095 return NT_STATUS_OK;
3100 samr_SetUserInfo
3102 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3103 struct samr_SetUserInfo *r)
3105 struct dcesrv_handle *h;
3106 struct samr_account_state *a_state;
3107 struct ldb_message *msg;
3108 int ret;
3109 NTSTATUS status = NT_STATUS_OK;
3110 struct ldb_context *sam_ctx;
3112 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3114 a_state = h->data;
3115 sam_ctx = a_state->sam_ctx;
3117 msg = ldb_msg_new(mem_ctx);
3118 if (msg == NULL) {
3119 return NT_STATUS_NO_MEMORY;
3122 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3123 if (!msg->dn) {
3124 return NT_STATUS_NO_MEMORY;
3127 switch (r->in.level) {
3128 case 2:
3129 SET_STRING(msg, info2.comment, "comment");
3130 SET_UINT (msg, info2.country_code, "countryCode");
3131 SET_UINT (msg, info2.code_page, "codePage");
3132 break;
3134 case 4:
3135 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3136 break;
3138 case 6:
3139 SET_STRING(msg, info6.account_name, "samAccountName");
3140 SET_STRING(msg, info6.full_name, "displayName");
3141 break;
3143 case 7:
3144 SET_STRING(msg, info7.account_name, "samAccountName");
3145 break;
3147 case 8:
3148 SET_STRING(msg, info8.full_name, "displayName");
3149 break;
3151 case 9:
3152 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3153 break;
3155 case 10:
3156 SET_STRING(msg, info10.home_directory, "homeDirectory");
3157 SET_STRING(msg, info10.home_drive, "homeDrive");
3158 break;
3160 case 11:
3161 SET_STRING(msg, info11.logon_script, "scriptPath");
3162 break;
3164 case 12:
3165 SET_STRING(msg, info12.profile_path, "profilePath");
3166 break;
3168 case 13:
3169 SET_STRING(msg, info13.description, "description");
3170 break;
3172 case 14:
3173 SET_STRING(msg, info14.workstations, "userWorkstations");
3174 break;
3176 case 16:
3177 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3178 break;
3180 case 17:
3181 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3182 break;
3184 case 18:
3185 status = samr_set_password_buffers(dce_call,
3186 a_state->sam_ctx,
3187 a_state->account_dn,
3188 a_state->domain_state->domain_dn,
3189 mem_ctx,
3190 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3191 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3192 if (!NT_STATUS_IS_OK(status)) {
3193 return status;
3196 if (r->in.info->info18.password_expired > 0) {
3197 struct ldb_message_element *set_el;
3198 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3199 return NT_STATUS_NO_MEMORY;
3201 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3202 set_el->flags = LDB_FLAG_MOD_REPLACE;
3204 break;
3206 case 20:
3207 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3208 break;
3210 case 21:
3211 if (r->in.info->info21.fields_present == 0)
3212 return NT_STATUS_INVALID_PARAMETER;
3214 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3215 IFSET(SAMR_FIELD_LAST_LOGON)
3216 SET_UINT64(msg, info21.last_logon, "lastLogon");
3217 IFSET(SAMR_FIELD_LAST_LOGOFF)
3218 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3219 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3220 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3221 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3222 SET_STRING(msg, info21.account_name, "samAccountName");
3223 IFSET(SAMR_FIELD_FULL_NAME)
3224 SET_STRING(msg, info21.full_name, "displayName");
3225 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3226 SET_STRING(msg, info21.home_directory, "homeDirectory");
3227 IFSET(SAMR_FIELD_HOME_DRIVE)
3228 SET_STRING(msg, info21.home_drive, "homeDrive");
3229 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3230 SET_STRING(msg, info21.logon_script, "scriptPath");
3231 IFSET(SAMR_FIELD_PROFILE_PATH)
3232 SET_STRING(msg, info21.profile_path, "profilePath");
3233 IFSET(SAMR_FIELD_DESCRIPTION)
3234 SET_STRING(msg, info21.description, "description");
3235 IFSET(SAMR_FIELD_WORKSTATIONS)
3236 SET_STRING(msg, info21.workstations, "userWorkstations");
3237 IFSET(SAMR_FIELD_COMMENT)
3238 SET_STRING(msg, info21.comment, "comment");
3239 IFSET(SAMR_FIELD_PARAMETERS)
3240 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3241 IFSET(SAMR_FIELD_PRIMARY_GID)
3242 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3243 IFSET(SAMR_FIELD_ACCT_FLAGS)
3244 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3245 IFSET(SAMR_FIELD_LOGON_HOURS)
3246 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3247 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3248 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3249 IFSET(SAMR_FIELD_NUM_LOGONS)
3250 SET_UINT (msg, info21.logon_count, "logonCount");
3251 IFSET(SAMR_FIELD_COUNTRY_CODE)
3252 SET_UINT (msg, info21.country_code, "countryCode");
3253 IFSET(SAMR_FIELD_CODE_PAGE)
3254 SET_UINT (msg, info21.code_page, "codePage");
3256 /* password change fields */
3257 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3258 return NT_STATUS_ACCESS_DENIED;
3260 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3261 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3262 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3264 if (r->in.info->info21.lm_password_set) {
3265 if ((r->in.info->info21.lm_owf_password.length != 16)
3266 || (r->in.info->info21.lm_owf_password.size != 16)) {
3267 return NT_STATUS_INVALID_PARAMETER;
3270 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3272 if (r->in.info->info21.nt_password_set) {
3273 if ((r->in.info->info21.nt_owf_password.length != 16)
3274 || (r->in.info->info21.nt_owf_password.size != 16)) {
3275 return NT_STATUS_INVALID_PARAMETER;
3278 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3280 status = samr_set_password_buffers(dce_call,
3281 a_state->sam_ctx,
3282 a_state->account_dn,
3283 a_state->domain_state->domain_dn,
3284 mem_ctx,
3285 lm_pwd_hash,
3286 nt_pwd_hash);
3287 if (!NT_STATUS_IS_OK(status)) {
3288 return status;
3293 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3294 NTTIME t = 0;
3295 struct ldb_message_element *set_el;
3296 if (r->in.info->info21.password_expired
3297 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3298 unix_to_nt_time(&t, time(NULL));
3300 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3301 "pwdLastSet", t) != LDB_SUCCESS) {
3302 return NT_STATUS_NO_MEMORY;
3304 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3305 set_el->flags = LDB_FLAG_MOD_REPLACE;
3307 #undef IFSET
3308 break;
3310 case 23:
3311 if (r->in.info->info23.info.fields_present == 0)
3312 return NT_STATUS_INVALID_PARAMETER;
3314 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3315 IFSET(SAMR_FIELD_LAST_LOGON)
3316 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3317 IFSET(SAMR_FIELD_LAST_LOGOFF)
3318 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3319 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3320 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3321 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3322 SET_STRING(msg, info23.info.account_name, "samAccountName");
3323 IFSET(SAMR_FIELD_FULL_NAME)
3324 SET_STRING(msg, info23.info.full_name, "displayName");
3325 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3326 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3327 IFSET(SAMR_FIELD_HOME_DRIVE)
3328 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3329 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3330 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3331 IFSET(SAMR_FIELD_PROFILE_PATH)
3332 SET_STRING(msg, info23.info.profile_path, "profilePath");
3333 IFSET(SAMR_FIELD_DESCRIPTION)
3334 SET_STRING(msg, info23.info.description, "description");
3335 IFSET(SAMR_FIELD_WORKSTATIONS)
3336 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3337 IFSET(SAMR_FIELD_COMMENT)
3338 SET_STRING(msg, info23.info.comment, "comment");
3339 IFSET(SAMR_FIELD_PARAMETERS)
3340 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3341 IFSET(SAMR_FIELD_PRIMARY_GID)
3342 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3343 IFSET(SAMR_FIELD_ACCT_FLAGS)
3344 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3345 IFSET(SAMR_FIELD_LOGON_HOURS)
3346 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3347 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3348 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3349 IFSET(SAMR_FIELD_NUM_LOGONS)
3350 SET_UINT (msg, info23.info.logon_count, "logonCount");
3352 IFSET(SAMR_FIELD_COUNTRY_CODE)
3353 SET_UINT (msg, info23.info.country_code, "countryCode");
3354 IFSET(SAMR_FIELD_CODE_PAGE)
3355 SET_UINT (msg, info23.info.code_page, "codePage");
3357 /* password change fields */
3358 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3359 return NT_STATUS_ACCESS_DENIED;
3361 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3362 status = samr_set_password(dce_call,
3363 a_state->sam_ctx,
3364 a_state->account_dn,
3365 a_state->domain_state->domain_dn,
3366 mem_ctx,
3367 &r->in.info->info23.password);
3368 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3369 status = samr_set_password(dce_call,
3370 a_state->sam_ctx,
3371 a_state->account_dn,
3372 a_state->domain_state->domain_dn,
3373 mem_ctx,
3374 &r->in.info->info23.password);
3376 if (!NT_STATUS_IS_OK(status)) {
3377 return status;
3380 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3381 NTTIME t = 0;
3382 struct ldb_message_element *set_el;
3383 if (r->in.info->info23.info.password_expired
3384 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3385 unix_to_nt_time(&t, time(NULL));
3387 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3388 "pwdLastSet", t) != LDB_SUCCESS) {
3389 return NT_STATUS_NO_MEMORY;
3391 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3392 set_el->flags = LDB_FLAG_MOD_REPLACE;
3394 #undef IFSET
3395 break;
3397 /* the set password levels are handled separately */
3398 case 24:
3399 status = samr_set_password(dce_call,
3400 a_state->sam_ctx,
3401 a_state->account_dn,
3402 a_state->domain_state->domain_dn,
3403 mem_ctx,
3404 &r->in.info->info24.password);
3405 if (!NT_STATUS_IS_OK(status)) {
3406 return status;
3409 if (r->in.info->info24.password_expired > 0) {
3410 struct ldb_message_element *set_el;
3411 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3412 return NT_STATUS_NO_MEMORY;
3414 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3415 set_el->flags = LDB_FLAG_MOD_REPLACE;
3417 break;
3419 case 25:
3420 if (r->in.info->info25.info.fields_present == 0)
3421 return NT_STATUS_INVALID_PARAMETER;
3423 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3424 IFSET(SAMR_FIELD_LAST_LOGON)
3425 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3426 IFSET(SAMR_FIELD_LAST_LOGOFF)
3427 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3428 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3429 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3430 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3431 SET_STRING(msg, info25.info.account_name, "samAccountName");
3432 IFSET(SAMR_FIELD_FULL_NAME)
3433 SET_STRING(msg, info25.info.full_name, "displayName");
3434 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3435 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3436 IFSET(SAMR_FIELD_HOME_DRIVE)
3437 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3438 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3439 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3440 IFSET(SAMR_FIELD_PROFILE_PATH)
3441 SET_STRING(msg, info25.info.profile_path, "profilePath");
3442 IFSET(SAMR_FIELD_DESCRIPTION)
3443 SET_STRING(msg, info25.info.description, "description");
3444 IFSET(SAMR_FIELD_WORKSTATIONS)
3445 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3446 IFSET(SAMR_FIELD_COMMENT)
3447 SET_STRING(msg, info25.info.comment, "comment");
3448 IFSET(SAMR_FIELD_PARAMETERS)
3449 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3450 IFSET(SAMR_FIELD_PRIMARY_GID)
3451 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3452 IFSET(SAMR_FIELD_ACCT_FLAGS)
3453 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3454 IFSET(SAMR_FIELD_LOGON_HOURS)
3455 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3456 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3457 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3458 IFSET(SAMR_FIELD_NUM_LOGONS)
3459 SET_UINT (msg, info25.info.logon_count, "logonCount");
3460 IFSET(SAMR_FIELD_COUNTRY_CODE)
3461 SET_UINT (msg, info25.info.country_code, "countryCode");
3462 IFSET(SAMR_FIELD_CODE_PAGE)
3463 SET_UINT (msg, info25.info.code_page, "codePage");
3465 /* password change fields */
3466 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3467 return NT_STATUS_ACCESS_DENIED;
3469 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3470 status = samr_set_password_ex(dce_call,
3471 a_state->sam_ctx,
3472 a_state->account_dn,
3473 a_state->domain_state->domain_dn,
3474 mem_ctx,
3475 &r->in.info->info25.password);
3476 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3477 status = samr_set_password_ex(dce_call,
3478 a_state->sam_ctx,
3479 a_state->account_dn,
3480 a_state->domain_state->domain_dn,
3481 mem_ctx,
3482 &r->in.info->info25.password);
3484 if (!NT_STATUS_IS_OK(status)) {
3485 return status;
3488 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3489 NTTIME t = 0;
3490 struct ldb_message_element *set_el;
3491 if (r->in.info->info25.info.password_expired
3492 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3493 unix_to_nt_time(&t, time(NULL));
3495 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3496 "pwdLastSet", t) != LDB_SUCCESS) {
3497 return NT_STATUS_NO_MEMORY;
3499 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3500 set_el->flags = LDB_FLAG_MOD_REPLACE;
3502 #undef IFSET
3503 break;
3505 /* the set password levels are handled separately */
3506 case 26:
3507 status = samr_set_password_ex(dce_call,
3508 a_state->sam_ctx,
3509 a_state->account_dn,
3510 a_state->domain_state->domain_dn,
3511 mem_ctx,
3512 &r->in.info->info26.password);
3513 if (!NT_STATUS_IS_OK(status)) {
3514 return status;
3517 if (r->in.info->info26.password_expired > 0) {
3518 NTTIME t = 0;
3519 struct ldb_message_element *set_el;
3520 if (r->in.info->info26.password_expired
3521 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3522 unix_to_nt_time(&t, time(NULL));
3524 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3525 "pwdLastSet", t) != LDB_SUCCESS) {
3526 return NT_STATUS_NO_MEMORY;
3528 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3529 set_el->flags = LDB_FLAG_MOD_REPLACE;
3531 break;
3533 default:
3534 /* many info classes are not valid for SetUserInfo */
3535 return NT_STATUS_INVALID_INFO_CLASS;
3538 if (!NT_STATUS_IS_OK(status)) {
3539 return status;
3542 /* modify the samdb record */
3543 if (msg->num_elements > 0) {
3544 ret = ldb_modify(a_state->sam_ctx, msg);
3545 if (ret != LDB_SUCCESS) {
3546 DEBUG(1,("Failed to modify record %s: %s\n",
3547 ldb_dn_get_linearized(a_state->account_dn),
3548 ldb_errstring(a_state->sam_ctx)));
3550 return dsdb_ldb_err_to_ntstatus(ret);
3554 return NT_STATUS_OK;
3559 samr_GetGroupsForUser
3561 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3562 struct samr_GetGroupsForUser *r)
3564 struct dcesrv_handle *h;
3565 struct samr_account_state *a_state;
3566 struct samr_domain_state *d_state;
3567 struct ldb_message **res;
3568 const char * const attrs[2] = { "objectSid", NULL };
3569 struct samr_RidWithAttributeArray *array;
3570 int i, count;
3572 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3574 a_state = h->data;
3575 d_state = a_state->domain_state;
3577 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3578 d_state->domain_dn, &res,
3579 attrs, d_state->domain_sid,
3580 "(&(member=%s)(|(grouptype=%d)(grouptype=%d))(objectclass=group))",
3581 ldb_dn_get_linearized(a_state->account_dn),
3582 GTYPE_SECURITY_UNIVERSAL_GROUP,
3583 GTYPE_SECURITY_GLOBAL_GROUP);
3584 if (count < 0)
3585 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3587 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3588 if (array == NULL)
3589 return NT_STATUS_NO_MEMORY;
3591 array->count = 0;
3592 array->rids = NULL;
3594 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3595 count + 1);
3596 if (array->rids == NULL)
3597 return NT_STATUS_NO_MEMORY;
3599 /* Adds the primary group */
3600 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3601 ~0, a_state->account_dn,
3602 "primaryGroupID", NULL);
3603 array->rids[0].attributes = SE_GROUP_MANDATORY
3604 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3605 array->count += 1;
3607 /* Adds the additional groups */
3608 for (i = 0; i < count; i++) {
3609 struct dom_sid *group_sid;
3611 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3612 if (group_sid == NULL) {
3613 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3616 array->rids[i + 1].rid =
3617 group_sid->sub_auths[group_sid->num_auths-1];
3618 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3619 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3620 array->count += 1;
3623 *r->out.rids = array;
3625 return NT_STATUS_OK;
3630 samr_QueryDisplayInfo
3632 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3633 struct samr_QueryDisplayInfo *r)
3635 struct dcesrv_handle *h;
3636 struct samr_domain_state *d_state;
3637 struct ldb_result *res;
3638 unsigned int i;
3639 uint32_t count;
3640 const char * const attrs[] = { "objectSid", "sAMAccountName",
3641 "displayName", "description", "userAccountControl",
3642 "pwdLastSet", NULL };
3643 struct samr_DispEntryFull *entriesFull = NULL;
3644 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3645 struct samr_DispEntryAscii *entriesAscii = NULL;
3646 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3647 const char *filter;
3648 int ret;
3650 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3652 d_state = h->data;
3654 switch (r->in.level) {
3655 case 1:
3656 case 4:
3657 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3658 "(sAMAccountType=%d))",
3659 ATYPE_NORMAL_ACCOUNT);
3660 break;
3661 case 2:
3662 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3663 "(sAMAccountType=%d))",
3664 ATYPE_WORKSTATION_TRUST);
3665 break;
3666 case 3:
3667 case 5:
3668 filter = talloc_asprintf(mem_ctx,
3669 "(&(|(groupType=%d)(groupType=%d))"
3670 "(objectClass=group))",
3671 GTYPE_SECURITY_UNIVERSAL_GROUP,
3672 GTYPE_SECURITY_GLOBAL_GROUP);
3673 break;
3674 default:
3675 return NT_STATUS_INVALID_INFO_CLASS;
3678 /* search for all requested objects in all domains. This could
3679 possibly be cached and resumed based on resume_key */
3680 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, ldb_get_default_basedn(d_state->sam_ctx),
3681 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3682 if (ret != LDB_SUCCESS) {
3683 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3685 if ((res->count == 0) || (r->in.max_entries == 0)) {
3686 return NT_STATUS_OK;
3689 switch (r->in.level) {
3690 case 1:
3691 entriesGeneral = talloc_array(mem_ctx,
3692 struct samr_DispEntryGeneral,
3693 res->count);
3694 break;
3695 case 2:
3696 entriesFull = talloc_array(mem_ctx,
3697 struct samr_DispEntryFull,
3698 res->count);
3699 break;
3700 case 3:
3701 entriesFullGroup = talloc_array(mem_ctx,
3702 struct samr_DispEntryFullGroup,
3703 res->count);
3704 break;
3705 case 4:
3706 case 5:
3707 entriesAscii = talloc_array(mem_ctx,
3708 struct samr_DispEntryAscii,
3709 res->count);
3710 break;
3713 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3714 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3715 return NT_STATUS_NO_MEMORY;
3717 count = 0;
3719 for (i = 0; i < res->count; i++) {
3720 struct dom_sid *objectsid;
3722 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3723 "objectSid");
3724 if (objectsid == NULL)
3725 continue;
3727 switch(r->in.level) {
3728 case 1:
3729 entriesGeneral[count].idx = count + 1;
3730 entriesGeneral[count].rid =
3731 objectsid->sub_auths[objectsid->num_auths-1];
3732 entriesGeneral[count].acct_flags =
3733 samdb_result_acct_flags(res->msgs[i], NULL);
3734 entriesGeneral[count].account_name.string =
3735 ldb_msg_find_attr_as_string(res->msgs[i],
3736 "sAMAccountName", "");
3737 entriesGeneral[count].full_name.string =
3738 ldb_msg_find_attr_as_string(res->msgs[i],
3739 "displayName", "");
3740 entriesGeneral[count].description.string =
3741 ldb_msg_find_attr_as_string(res->msgs[i],
3742 "description", "");
3743 break;
3744 case 2:
3745 entriesFull[count].idx = count + 1;
3746 entriesFull[count].rid =
3747 objectsid->sub_auths[objectsid->num_auths-1];
3749 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3750 entriesFull[count].acct_flags =
3751 samdb_result_acct_flags(res->msgs[i],
3752 NULL) | ACB_NORMAL;
3753 entriesFull[count].account_name.string =
3754 ldb_msg_find_attr_as_string(res->msgs[i],
3755 "sAMAccountName", "");
3756 entriesFull[count].description.string =
3757 ldb_msg_find_attr_as_string(res->msgs[i],
3758 "description", "");
3759 break;
3760 case 3:
3761 entriesFullGroup[count].idx = count + 1;
3762 entriesFullGroup[count].rid =
3763 objectsid->sub_auths[objectsid->num_auths-1];
3764 /* We get a "7" here for groups */
3765 entriesFullGroup[count].acct_flags
3766 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3767 entriesFullGroup[count].account_name.string =
3768 ldb_msg_find_attr_as_string(res->msgs[i],
3769 "sAMAccountName", "");
3770 entriesFullGroup[count].description.string =
3771 ldb_msg_find_attr_as_string(res->msgs[i],
3772 "description", "");
3773 break;
3774 case 4:
3775 case 5:
3776 entriesAscii[count].idx = count + 1;
3777 entriesAscii[count].account_name.string =
3778 ldb_msg_find_attr_as_string(res->msgs[i],
3779 "sAMAccountName", "");
3780 break;
3783 count += 1;
3786 *r->out.total_size = count;
3788 if (r->in.start_idx >= count) {
3789 *r->out.returned_size = 0;
3790 switch(r->in.level) {
3791 case 1:
3792 r->out.info->info1.count = *r->out.returned_size;
3793 r->out.info->info1.entries = NULL;
3794 break;
3795 case 2:
3796 r->out.info->info2.count = *r->out.returned_size;
3797 r->out.info->info2.entries = NULL;
3798 break;
3799 case 3:
3800 r->out.info->info3.count = *r->out.returned_size;
3801 r->out.info->info3.entries = NULL;
3802 break;
3803 case 4:
3804 r->out.info->info4.count = *r->out.returned_size;
3805 r->out.info->info4.entries = NULL;
3806 break;
3807 case 5:
3808 r->out.info->info5.count = *r->out.returned_size;
3809 r->out.info->info5.entries = NULL;
3810 break;
3812 } else {
3813 *r->out.returned_size = MIN(count - r->in.start_idx,
3814 r->in.max_entries);
3815 switch(r->in.level) {
3816 case 1:
3817 r->out.info->info1.count = *r->out.returned_size;
3818 r->out.info->info1.entries =
3819 &(entriesGeneral[r->in.start_idx]);
3820 break;
3821 case 2:
3822 r->out.info->info2.count = *r->out.returned_size;
3823 r->out.info->info2.entries =
3824 &(entriesFull[r->in.start_idx]);
3825 break;
3826 case 3:
3827 r->out.info->info3.count = *r->out.returned_size;
3828 r->out.info->info3.entries =
3829 &(entriesFullGroup[r->in.start_idx]);
3830 break;
3831 case 4:
3832 r->out.info->info4.count = *r->out.returned_size;
3833 r->out.info->info4.entries =
3834 &(entriesAscii[r->in.start_idx]);
3835 break;
3836 case 5:
3837 r->out.info->info5.count = *r->out.returned_size;
3838 r->out.info->info5.entries =
3839 &(entriesAscii[r->in.start_idx]);
3840 break;
3844 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3845 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3850 samr_GetDisplayEnumerationIndex
3852 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3853 struct samr_GetDisplayEnumerationIndex *r)
3855 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3860 samr_TestPrivateFunctionsDomain
3862 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3863 struct samr_TestPrivateFunctionsDomain *r)
3865 return NT_STATUS_NOT_IMPLEMENTED;
3870 samr_TestPrivateFunctionsUser
3872 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3873 struct samr_TestPrivateFunctionsUser *r)
3875 return NT_STATUS_NOT_IMPLEMENTED;
3880 samr_GetUserPwInfo
3882 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3883 struct samr_GetUserPwInfo *r)
3885 struct dcesrv_handle *h;
3886 struct samr_account_state *a_state;
3888 ZERO_STRUCTP(r->out.info);
3890 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3892 a_state = h->data;
3894 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3895 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3896 NULL);
3897 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3898 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3900 return NT_STATUS_OK;
3905 samr_RemoveMemberFromForeignDomain
3907 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3908 TALLOC_CTX *mem_ctx,
3909 struct samr_RemoveMemberFromForeignDomain *r)
3911 struct dcesrv_handle *h;
3912 struct samr_domain_state *d_state;
3913 const char *memberdn;
3914 struct ldb_message **res;
3915 const char *no_attrs[] = { NULL };
3916 int i, count;
3918 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3920 d_state = h->data;
3922 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3923 "distinguishedName", "(objectSid=%s)",
3924 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3925 /* Nothing to do */
3926 if (memberdn == NULL) {
3927 return NT_STATUS_OK;
3930 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3931 d_state->domain_dn, &res, no_attrs,
3932 d_state->domain_sid,
3933 "(&(member=%s)(objectClass=group)"
3934 "(|(groupType=%d)(groupType=%d)))",
3935 memberdn,
3936 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3937 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3939 if (count < 0)
3940 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3942 for (i=0; i<count; i++) {
3943 struct ldb_message *mod;
3944 int ret;
3946 mod = ldb_msg_new(mem_ctx);
3947 if (mod == NULL) {
3948 return NT_STATUS_NO_MEMORY;
3951 mod->dn = res[i]->dn;
3953 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3954 "member", memberdn) != LDB_SUCCESS)
3955 return NT_STATUS_NO_MEMORY;
3957 ret = ldb_modify(d_state->sam_ctx, mod);
3958 talloc_free(mod);
3959 if (ret != LDB_SUCCESS) {
3960 return dsdb_ldb_err_to_ntstatus(ret);
3964 return NT_STATUS_OK;
3969 samr_QueryDomainInfo2
3971 just an alias for samr_QueryDomainInfo
3973 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3974 struct samr_QueryDomainInfo2 *r)
3976 struct samr_QueryDomainInfo r1;
3977 NTSTATUS status;
3979 ZERO_STRUCT(r1.out);
3980 r1.in.domain_handle = r->in.domain_handle;
3981 r1.in.level = r->in.level;
3982 r1.out.info = r->out.info;
3984 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3986 return status;
3991 samr_QueryUserInfo2
3993 just an alias for samr_QueryUserInfo
3995 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3996 struct samr_QueryUserInfo2 *r)
3998 struct samr_QueryUserInfo r1;
3999 NTSTATUS status;
4001 r1.in.user_handle = r->in.user_handle;
4002 r1.in.level = r->in.level;
4003 r1.out.info = r->out.info;
4005 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4007 return status;
4012 samr_QueryDisplayInfo2
4014 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4015 struct samr_QueryDisplayInfo2 *r)
4017 struct samr_QueryDisplayInfo q;
4018 NTSTATUS result;
4020 q.in.domain_handle = r->in.domain_handle;
4021 q.in.level = r->in.level;
4022 q.in.start_idx = r->in.start_idx;
4023 q.in.max_entries = r->in.max_entries;
4024 q.in.buf_size = r->in.buf_size;
4025 q.out.total_size = r->out.total_size;
4026 q.out.returned_size = r->out.returned_size;
4027 q.out.info = r->out.info;
4029 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4031 return result;
4036 samr_GetDisplayEnumerationIndex2
4038 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4039 struct samr_GetDisplayEnumerationIndex2 *r)
4041 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4046 samr_QueryDisplayInfo3
4048 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4049 struct samr_QueryDisplayInfo3 *r)
4051 struct samr_QueryDisplayInfo q;
4052 NTSTATUS result;
4054 q.in.domain_handle = r->in.domain_handle;
4055 q.in.level = r->in.level;
4056 q.in.start_idx = r->in.start_idx;
4057 q.in.max_entries = r->in.max_entries;
4058 q.in.buf_size = r->in.buf_size;
4059 q.out.total_size = r->out.total_size;
4060 q.out.returned_size = r->out.returned_size;
4061 q.out.info = r->out.info;
4063 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4065 return result;
4070 samr_AddMultipleMembersToAlias
4072 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4073 struct samr_AddMultipleMembersToAlias *r)
4075 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4080 samr_RemoveMultipleMembersFromAlias
4082 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4083 struct samr_RemoveMultipleMembersFromAlias *r)
4085 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4090 samr_GetDomPwInfo
4092 this fetches the default password properties for a domain
4094 note that w2k3 completely ignores the domain name in this call, and
4095 always returns the information for the servers primary domain
4097 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4098 struct samr_GetDomPwInfo *r)
4100 struct ldb_message **msgs;
4101 int ret;
4102 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4103 struct ldb_context *sam_ctx;
4105 ZERO_STRUCTP(r->out.info);
4107 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4108 dce_call->conn->dce_ctx->lp_ctx,
4109 dce_call->conn->auth_state.session_info, 0);
4110 if (sam_ctx == NULL) {
4111 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4114 /* The domain name in this call is ignored */
4115 ret = gendb_search_dn(sam_ctx,
4116 mem_ctx, NULL, &msgs, attrs);
4117 if (ret <= 0) {
4118 talloc_free(sam_ctx);
4120 return NT_STATUS_NO_SUCH_DOMAIN;
4122 if (ret > 1) {
4123 talloc_free(msgs);
4124 talloc_free(sam_ctx);
4126 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4129 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4130 "minPwdLength", 0);
4131 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4132 "pwdProperties", 1);
4134 talloc_free(msgs);
4135 talloc_unlink(mem_ctx, sam_ctx);
4137 return NT_STATUS_OK;
4142 samr_Connect2
4144 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4145 struct samr_Connect2 *r)
4147 struct samr_Connect c;
4149 c.in.system_name = NULL;
4150 c.in.access_mask = r->in.access_mask;
4151 c.out.connect_handle = r->out.connect_handle;
4153 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4158 samr_SetUserInfo2
4160 just an alias for samr_SetUserInfo
4162 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4163 struct samr_SetUserInfo2 *r)
4165 struct samr_SetUserInfo r2;
4167 r2.in.user_handle = r->in.user_handle;
4168 r2.in.level = r->in.level;
4169 r2.in.info = r->in.info;
4171 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4176 samr_SetBootKeyInformation
4178 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4179 struct samr_SetBootKeyInformation *r)
4181 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4186 samr_GetBootKeyInformation
4188 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4189 struct samr_GetBootKeyInformation *r)
4191 /* Windows Server 2008 returns this */
4192 return NT_STATUS_NOT_SUPPORTED;
4197 samr_Connect3
4199 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4200 struct samr_Connect3 *r)
4202 struct samr_Connect c;
4204 c.in.system_name = NULL;
4205 c.in.access_mask = r->in.access_mask;
4206 c.out.connect_handle = r->out.connect_handle;
4208 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4213 samr_Connect4
4215 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4216 struct samr_Connect4 *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_Connect5
4231 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4232 struct samr_Connect5 *r)
4234 struct samr_Connect c;
4235 NTSTATUS status;
4237 c.in.system_name = NULL;
4238 c.in.access_mask = r->in.access_mask;
4239 c.out.connect_handle = r->out.connect_handle;
4241 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4243 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4244 r->out.info_out->info1.unknown2 = 0;
4245 *r->out.level_out = r->in.level_in;
4247 return status;
4252 samr_RidToSid
4254 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4255 struct samr_RidToSid *r)
4257 struct samr_domain_state *d_state;
4258 struct dcesrv_handle *h;
4260 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4262 d_state = h->data;
4264 /* form the users SID */
4265 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4266 if (!*r->out.sid) {
4267 return NT_STATUS_NO_MEMORY;
4270 return NT_STATUS_OK;
4275 samr_SetDsrmPassword
4277 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4278 struct samr_SetDsrmPassword *r)
4280 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4285 samr_ValidatePassword
4287 For now the call checks the password complexity (if active) and the minimum
4288 password length on level 2 and 3. Level 1 is ignored for now.
4290 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4291 TALLOC_CTX *mem_ctx,
4292 struct samr_ValidatePassword *r)
4294 struct samr_GetDomPwInfo r2;
4295 struct samr_PwInfo pwInfo;
4296 DATA_BLOB password;
4297 enum samr_ValidationStatus res;
4298 NTSTATUS status;
4299 enum dcerpc_transport_t transport =
4300 dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
4302 if (transport != NCACN_IP_TCP && transport != NCALRPC) {
4303 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4306 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4308 r2.in.domain_name = NULL;
4309 r2.out.info = &pwInfo;
4310 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4311 if (!NT_STATUS_IS_OK(status)) {
4312 return status;
4315 switch (r->in.level) {
4316 case NetValidateAuthentication:
4317 /* we don't support this yet */
4318 return NT_STATUS_NOT_SUPPORTED;
4319 break;
4320 case NetValidatePasswordChange:
4321 password = data_blob_const(r->in.req->req2.password.string,
4322 r->in.req->req2.password.length);
4323 res = samdb_check_password(&password,
4324 pwInfo.password_properties,
4325 pwInfo.min_password_length);
4326 (*r->out.rep)->ctr2.status = res;
4327 break;
4328 case NetValidatePasswordReset:
4329 password = data_blob_const(r->in.req->req3.password.string,
4330 r->in.req->req3.password.length);
4331 res = samdb_check_password(&password,
4332 pwInfo.password_properties,
4333 pwInfo.min_password_length);
4334 (*r->out.rep)->ctr3.status = res;
4335 break;
4336 default:
4337 return NT_STATUS_INVALID_INFO_CLASS;
4338 break;
4341 return NT_STATUS_OK;
4345 /* include the generated boilerplate */
4346 #include "librpc/gen_ndr/ndr_samr_s.c"