docs: ldbsearch.1.xml: Correct meta data.
[Samba/gebeck_regimport.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob3826075ebcd08968c12565bb9ff6888a9cd2f5d6
1 /*
2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include <ldb.h>
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
44 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
46 #define QUERY_STRING(msg, field, attr) \
47 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
48 #define QUERY_UINT(msg, field, attr) \
49 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
50 #define QUERY_RID(msg, field, attr) \
51 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
52 #define QUERY_UINT64(msg, field, attr) \
53 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
54 #define QUERY_APASSC(msg, field, attr) \
55 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg, attr);
57 #define QUERY_FPASSC(msg, field, attr) \
58 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
59 a_state->domain_state->domain_dn, msg);
60 #define QUERY_LHOURS(msg, field, attr) \
61 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
62 #define QUERY_AFLAGS(msg, field, attr) \
63 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
64 #define QUERY_PARAMETERS(msg, field, attr) \
65 info->field = samdb_result_parameters(mem_ctx, msg, attr);
68 /* these are used to make the Set[User|Group]Info code easier to follow */
70 #define SET_STRING(msg, field, attr) do { \
71 struct ldb_message_element *set_el; \
72 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
73 if (r->in.info->field.string[0] == '\0') { \
74 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
75 return NT_STATUS_NO_MEMORY; \
76 } \
77 } \
78 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
79 return NT_STATUS_NO_MEMORY; \
80 } \
81 set_el = ldb_msg_find_element(msg, attr); \
82 set_el->flags = LDB_FLAG_MOD_REPLACE; \
83 } while (0)
85 #define SET_UINT(msg, field, attr) do { \
86 struct ldb_message_element *set_el; \
87 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
88 return NT_STATUS_NO_MEMORY; \
89 } \
90 set_el = ldb_msg_find_element(msg, attr); \
91 set_el->flags = LDB_FLAG_MOD_REPLACE; \
92 } while (0)
94 #define SET_INT64(msg, field, attr) do { \
95 struct ldb_message_element *set_el; \
96 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
97 return NT_STATUS_NO_MEMORY; \
98 } \
99 set_el = ldb_msg_find_element(msg, attr); \
100 set_el->flags = LDB_FLAG_MOD_REPLACE; \
101 } while (0)
103 #define SET_UINT64(msg, field, attr) do { \
104 struct ldb_message_element *set_el; \
105 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
106 return NT_STATUS_NO_MEMORY; \
108 set_el = ldb_msg_find_element(msg, attr); \
109 set_el->flags = LDB_FLAG_MOD_REPLACE; \
110 } while (0)
112 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
113 do { \
114 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
115 return NT_STATUS_INVALID_PARAMETER; \
117 } while (0) \
119 /* Set account flags, discarding flags that cannot be set with SAMR */
120 #define SET_AFLAGS(msg, field, attr) do { \
121 struct ldb_message_element *set_el; \
122 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
123 return NT_STATUS_INVALID_PARAMETER; \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
128 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
129 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
130 return NT_STATUS_NO_MEMORY; \
132 set_el = ldb_msg_find_element(msg, attr); \
133 set_el->flags = LDB_FLAG_MOD_REPLACE; \
134 } while (0)
136 #define SET_LHOURS(msg, field, attr) do { \
137 struct ldb_message_element *set_el; \
138 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
139 return NT_STATUS_NO_MEMORY; \
141 set_el = ldb_msg_find_element(msg, attr); \
142 set_el->flags = LDB_FLAG_MOD_REPLACE; \
143 } while (0)
145 #define SET_PARAMETERS(msg, field, attr) do { \
146 struct ldb_message_element *set_el; \
147 if (r->in.info->field.length != 0) { \
148 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
149 return NT_STATUS_NO_MEMORY; \
151 set_el = ldb_msg_find_element(msg, attr); \
152 set_el->flags = LDB_FLAG_MOD_REPLACE; \
154 } while (0)
159 samr_Connect
161 create a connection to the SAM database
163 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
164 struct samr_Connect *r)
166 struct samr_connect_state *c_state;
167 struct dcesrv_handle *handle;
169 ZERO_STRUCTP(r->out.connect_handle);
171 c_state = talloc(mem_ctx, struct samr_connect_state);
172 if (!c_state) {
173 return NT_STATUS_NO_MEMORY;
176 /* make sure the sam database is accessible */
177 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0);
178 if (c_state->sam_ctx == NULL) {
179 talloc_free(c_state);
180 return NT_STATUS_INVALID_SYSTEM_SERVICE;
184 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
185 if (!handle) {
186 talloc_free(c_state);
187 return NT_STATUS_NO_MEMORY;
190 handle->data = talloc_steal(handle, c_state);
192 c_state->access_mask = r->in.access_mask;
193 *r->out.connect_handle = handle->wire_handle;
195 return NT_STATUS_OK;
200 samr_Close
202 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
203 struct samr_Close *r)
205 struct dcesrv_handle *h;
207 *r->out.handle = *r->in.handle;
209 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
211 talloc_free(h);
213 ZERO_STRUCTP(r->out.handle);
215 return NT_STATUS_OK;
220 samr_SetSecurity
222 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
223 struct samr_SetSecurity *r)
225 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
230 samr_QuerySecurity
232 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
233 struct samr_QuerySecurity *r)
235 struct dcesrv_handle *h;
236 struct sec_desc_buf *sd;
238 *r->out.sdbuf = NULL;
240 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
242 sd = talloc(mem_ctx, struct sec_desc_buf);
243 if (sd == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 sd->sd = samdb_default_security_descriptor(mem_ctx);
249 *r->out.sdbuf = sd;
251 return NT_STATUS_OK;
256 samr_Shutdown
258 we refuse this operation completely. If a admin wants to shutdown samr
259 in Samba then they should use the samba admin tools to disable the samr pipe
261 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
262 struct samr_Shutdown *r)
264 return NT_STATUS_ACCESS_DENIED;
269 samr_LookupDomain
271 this maps from a domain name to a SID
273 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
274 struct samr_LookupDomain *r)
276 struct samr_connect_state *c_state;
277 struct dcesrv_handle *h;
278 struct dom_sid *sid;
279 const char * const dom_attrs[] = { "objectSid", NULL};
280 struct ldb_message **dom_msgs;
281 int ret;
283 *r->out.sid = NULL;
285 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
287 c_state = h->data;
289 if (r->in.domain_name->string == NULL) {
290 return NT_STATUS_INVALID_PARAMETER;
293 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
294 ret = gendb_search(c_state->sam_ctx,
295 mem_ctx, NULL, &dom_msgs, dom_attrs,
296 "(objectClass=builtinDomain)");
297 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
298 ret = gendb_search_dn(c_state->sam_ctx,
299 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
300 &dom_msgs, dom_attrs);
301 } else {
302 return NT_STATUS_NO_SUCH_DOMAIN;
304 if (ret != 1) {
305 return NT_STATUS_NO_SUCH_DOMAIN;
308 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
309 "objectSid");
311 if (sid == NULL) {
312 return NT_STATUS_NO_SUCH_DOMAIN;
315 *r->out.sid = sid;
317 return NT_STATUS_OK;
322 samr_EnumDomains
324 list the domains in the SAM
326 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
327 struct samr_EnumDomains *r)
329 struct samr_connect_state *c_state;
330 struct dcesrv_handle *h;
331 struct samr_SamArray *array;
332 uint32_t i, start_i;
334 *r->out.resume_handle = 0;
335 *r->out.sam = NULL;
336 *r->out.num_entries = 0;
338 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
340 c_state = h->data;
342 *r->out.resume_handle = 2;
344 start_i = *r->in.resume_handle;
346 if (start_i >= 2) {
347 /* search past end of list is not an error for this call */
348 return NT_STATUS_OK;
351 array = talloc(mem_ctx, struct samr_SamArray);
352 if (array == NULL) {
353 return NT_STATUS_NO_MEMORY;
356 array->count = 0;
357 array->entries = NULL;
359 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
360 if (array->entries == NULL) {
361 return NT_STATUS_NO_MEMORY;
364 for (i=0;i<2-start_i;i++) {
365 array->entries[i].idx = start_i + i;
366 if (i == 0) {
367 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
368 } else {
369 array->entries[i].name.string = "BUILTIN";
373 *r->out.sam = array;
374 *r->out.num_entries = i;
375 array->count = *r->out.num_entries;
377 return NT_STATUS_OK;
382 samr_OpenDomain
384 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
385 struct samr_OpenDomain *r)
387 struct dcesrv_handle *h_conn, *h_domain;
388 struct samr_connect_state *c_state;
389 struct samr_domain_state *d_state;
390 const char * const dom_attrs[] = { "cn", NULL};
391 struct ldb_message **dom_msgs;
392 int ret;
394 ZERO_STRUCTP(r->out.domain_handle);
396 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
398 c_state = h_conn->data;
400 if (r->in.sid == NULL) {
401 return NT_STATUS_INVALID_PARAMETER;
404 d_state = talloc(mem_ctx, struct samr_domain_state);
405 if (!d_state) {
406 return NT_STATUS_NO_MEMORY;
409 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
411 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
412 d_state->builtin = true;
413 d_state->domain_name = "BUILTIN";
414 } else {
415 d_state->builtin = false;
416 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
419 ret = gendb_search(c_state->sam_ctx,
420 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
421 "(objectSid=%s)",
422 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
424 if (ret == 0) {
425 talloc_free(d_state);
426 return NT_STATUS_NO_SUCH_DOMAIN;
427 } else if (ret > 1) {
428 talloc_free(d_state);
429 return NT_STATUS_INTERNAL_DB_CORRUPTION;
430 } else if (ret == -1) {
431 talloc_free(d_state);
432 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
433 return NT_STATUS_INTERNAL_DB_CORRUPTION;
436 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
437 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
438 d_state->connect_state = talloc_reference(d_state, c_state);
439 d_state->sam_ctx = c_state->sam_ctx;
440 d_state->access_mask = r->in.access_mask;
442 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
444 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
445 if (!h_domain) {
446 talloc_free(d_state);
447 return NT_STATUS_NO_MEMORY;
450 h_domain->data = talloc_steal(h_domain, d_state);
452 *r->out.domain_handle = h_domain->wire_handle;
454 return NT_STATUS_OK;
458 return DomInfo1
460 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
461 TALLOC_CTX *mem_ctx,
462 struct ldb_message **dom_msgs,
463 struct samr_DomInfo1 *info)
465 info->min_password_length =
466 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
467 info->password_history_length =
468 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
469 info->password_properties =
470 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
471 info->max_password_age =
472 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
473 info->min_password_age =
474 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
476 return NT_STATUS_OK;
480 return DomInfo2
482 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
483 TALLOC_CTX *mem_ctx,
484 struct ldb_message **dom_msgs,
485 struct samr_DomGeneralInformation *info)
487 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
488 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
489 "domainReplica",
490 "");
492 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
493 0x8000000000000000LL);
495 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
496 "oEMInformation",
497 "");
498 info->domain_name.string = state->domain_name;
500 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
502 switch (state->role) {
503 case ROLE_ACTIVE_DIRECTORY_DC:
504 /* This pulls the NetBIOS name from the
505 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
506 string */
507 if (samdb_is_pdc(state->sam_ctx)) {
508 info->role = SAMR_ROLE_DOMAIN_PDC;
509 } else {
510 info->role = SAMR_ROLE_DOMAIN_BDC;
512 break;
513 case ROLE_DOMAIN_PDC:
514 case ROLE_DOMAIN_BDC:
515 return NT_STATUS_INTERNAL_ERROR;
516 case ROLE_DOMAIN_MEMBER:
517 info->role = SAMR_ROLE_DOMAIN_MEMBER;
518 break;
519 case ROLE_STANDALONE:
520 info->role = SAMR_ROLE_STANDALONE;
521 break;
524 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx,
525 state->domain_dn,
526 "(objectClass=user)");
527 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx,
528 state->domain_dn,
529 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
530 GTYPE_SECURITY_UNIVERSAL_GROUP,
531 GTYPE_SECURITY_GLOBAL_GROUP);
532 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx,
533 state->domain_dn,
534 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
535 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
536 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
538 return NT_STATUS_OK;
542 return DomInfo3
544 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
545 TALLOC_CTX *mem_ctx,
546 struct ldb_message **dom_msgs,
547 struct samr_DomInfo3 *info)
549 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
550 0x8000000000000000LL);
552 return NT_STATUS_OK;
556 return DomInfo4
558 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
559 TALLOC_CTX *mem_ctx,
560 struct ldb_message **dom_msgs,
561 struct samr_DomOEMInformation *info)
563 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
564 "oEMInformation",
565 "");
567 return NT_STATUS_OK;
571 return DomInfo5
573 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
574 TALLOC_CTX *mem_ctx,
575 struct ldb_message **dom_msgs,
576 struct samr_DomInfo5 *info)
578 info->domain_name.string = state->domain_name;
580 return NT_STATUS_OK;
584 return DomInfo6
586 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
587 TALLOC_CTX *mem_ctx,
588 struct ldb_message **dom_msgs,
589 struct samr_DomInfo6 *info)
591 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
592 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
593 "domainReplica",
594 "");
596 return NT_STATUS_OK;
600 return DomInfo7
602 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
603 TALLOC_CTX *mem_ctx,
604 struct ldb_message **dom_msgs,
605 struct samr_DomInfo7 *info)
608 switch (state->role) {
609 case ROLE_ACTIVE_DIRECTORY_DC:
610 /* This pulls the NetBIOS name from the
611 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
612 string */
613 if (samdb_is_pdc(state->sam_ctx)) {
614 info->role = SAMR_ROLE_DOMAIN_PDC;
615 } else {
616 info->role = SAMR_ROLE_DOMAIN_BDC;
618 break;
619 case ROLE_DOMAIN_PDC:
620 info->role = SAMR_ROLE_DOMAIN_PDC;
621 break;
622 case ROLE_DOMAIN_MEMBER:
623 info->role = SAMR_ROLE_DOMAIN_MEMBER;
624 break;
625 case ROLE_STANDALONE:
626 info->role = SAMR_ROLE_STANDALONE;
627 break;
630 return NT_STATUS_OK;
634 return DomInfo8
636 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
637 TALLOC_CTX *mem_ctx,
638 struct ldb_message **dom_msgs,
639 struct samr_DomInfo8 *info)
641 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
642 time(NULL));
644 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
645 0x0LL);
647 return NT_STATUS_OK;
651 return DomInfo9
653 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
654 TALLOC_CTX *mem_ctx,
655 struct ldb_message **dom_msgs,
656 struct samr_DomInfo9 *info)
658 info->domain_server_state = DOMAIN_SERVER_ENABLED;
660 return NT_STATUS_OK;
664 return DomInfo11
666 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
667 TALLOC_CTX *mem_ctx,
668 struct ldb_message **dom_msgs,
669 struct samr_DomGeneralInformation2 *info)
671 NTSTATUS status;
672 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
673 if (!NT_STATUS_IS_OK(status)) {
674 return status;
677 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
678 -18000000000LL);
679 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
680 -18000000000LL);
681 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
683 return NT_STATUS_OK;
687 return DomInfo12
689 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
690 TALLOC_CTX *mem_ctx,
691 struct ldb_message **dom_msgs,
692 struct samr_DomInfo12 *info)
694 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
695 -18000000000LL);
696 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
697 -18000000000LL);
698 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
700 return NT_STATUS_OK;
704 return DomInfo13
706 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
707 TALLOC_CTX *mem_ctx,
708 struct ldb_message **dom_msgs,
709 struct samr_DomInfo13 *info)
711 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
712 time(NULL));
714 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
715 0x0LL);
717 info->modified_count_at_last_promotion = 0;
719 return NT_STATUS_OK;
723 samr_QueryDomainInfo
725 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
726 TALLOC_CTX *mem_ctx,
727 struct samr_QueryDomainInfo *r)
729 struct dcesrv_handle *h;
730 struct samr_domain_state *d_state;
731 union samr_DomainInfo *info;
733 struct ldb_message **dom_msgs;
734 const char * const *attrs = NULL;
736 *r->out.info = NULL;
738 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
740 d_state = h->data;
742 switch (r->in.level) {
743 case 1:
745 static const char * const attrs2[] = { "minPwdLength",
746 "pwdHistoryLength",
747 "pwdProperties",
748 "maxPwdAge",
749 "minPwdAge",
750 NULL };
751 attrs = attrs2;
752 break;
754 case 2:
756 static const char * const attrs2[] = {"forceLogoff",
757 "oEMInformation",
758 "modifiedCount",
759 "domainReplica",
760 NULL};
761 attrs = attrs2;
762 break;
764 case 3:
766 static const char * const attrs2[] = {"forceLogoff",
767 NULL};
768 attrs = attrs2;
769 break;
771 case 4:
773 static const char * const attrs2[] = {"oEMInformation",
774 NULL};
775 attrs = attrs2;
776 break;
778 case 5:
780 attrs = NULL;
781 break;
783 case 6:
785 static const char * const attrs2[] = { "domainReplica",
786 NULL };
787 attrs = attrs2;
788 break;
790 case 7:
792 attrs = NULL;
793 break;
795 case 8:
797 static const char * const attrs2[] = { "modifiedCount",
798 "creationTime",
799 NULL };
800 attrs = attrs2;
801 break;
803 case 9:
805 attrs = NULL;
806 break;
808 case 11:
810 static const char * const attrs2[] = { "oEMInformation",
811 "forceLogoff",
812 "modifiedCount",
813 "lockoutDuration",
814 "lockOutObservationWindow",
815 "lockoutThreshold",
816 NULL};
817 attrs = attrs2;
818 break;
820 case 12:
822 static const char * const attrs2[] = { "lockoutDuration",
823 "lockOutObservationWindow",
824 "lockoutThreshold",
825 NULL};
826 attrs = attrs2;
827 break;
829 case 13:
831 static const char * const attrs2[] = { "modifiedCount",
832 "creationTime",
833 NULL };
834 attrs = attrs2;
835 break;
837 default:
839 return NT_STATUS_INVALID_INFO_CLASS;
843 /* some levels don't need a search */
844 if (attrs) {
845 int ret;
846 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
847 d_state->domain_dn, &dom_msgs, attrs);
848 if (ret == 0) {
849 return NT_STATUS_NO_SUCH_DOMAIN;
851 if (ret != 1) {
852 return NT_STATUS_INTERNAL_DB_CORRUPTION;
856 /* allocate the info structure */
857 info = talloc_zero(mem_ctx, union samr_DomainInfo);
858 if (info == NULL) {
859 return NT_STATUS_NO_MEMORY;
862 *r->out.info = info;
864 switch (r->in.level) {
865 case 1:
866 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
867 &info->info1);
868 case 2:
869 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
870 &info->general);
871 case 3:
872 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
873 &info->info3);
874 case 4:
875 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
876 &info->oem);
877 case 5:
878 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
879 &info->info5);
880 case 6:
881 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
882 &info->info6);
883 case 7:
884 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
885 &info->info7);
886 case 8:
887 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
888 &info->info8);
889 case 9:
890 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
891 &info->info9);
892 case 11:
893 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
894 &info->general2);
895 case 12:
896 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
897 &info->info12);
898 case 13:
899 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
900 &info->info13);
901 default:
902 return NT_STATUS_INVALID_INFO_CLASS;
908 samr_SetDomainInfo
910 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
911 struct samr_SetDomainInfo *r)
913 struct dcesrv_handle *h;
914 struct samr_domain_state *d_state;
915 struct ldb_message *msg;
916 int ret;
917 struct ldb_context *sam_ctx;
919 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
921 d_state = h->data;
922 sam_ctx = d_state->sam_ctx;
924 msg = ldb_msg_new(mem_ctx);
925 if (msg == NULL) {
926 return NT_STATUS_NO_MEMORY;
929 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
930 if (!msg->dn) {
931 return NT_STATUS_NO_MEMORY;
934 switch (r->in.level) {
935 case 1:
936 SET_UINT (msg, info1.min_password_length, "minPwdLength");
937 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
938 SET_UINT (msg, info1.password_properties, "pwdProperties");
939 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
940 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
941 break;
942 case 3:
943 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
944 break;
945 case 4:
946 SET_STRING(msg, oem.oem_information, "oEMInformation");
947 break;
949 case 6:
950 case 7:
951 case 9:
952 /* No op, we don't know where to set these */
953 return NT_STATUS_OK;
955 case 12:
957 * It is not possible to set lockout_duration < lockout_window.
958 * (The test is the other way around since the negative numbers
959 * are stored...)
961 * TODO:
962 * This check should be moved to the backend, i.e. to some
963 * ldb module under dsdb/samdb/ldb_modules/ .
965 * This constraint is documented here for the samr rpc service:
966 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
967 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
969 * And here for the ldap backend:
970 * MS-ADTS 3.1.1.5.3.2 Constraints
971 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
973 if (r->in.info->info12.lockout_duration >
974 r->in.info->info12.lockout_window)
976 return NT_STATUS_INVALID_PARAMETER;
978 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
979 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
980 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
981 break;
983 default:
984 /* many info classes are not valid for SetDomainInfo */
985 return NT_STATUS_INVALID_INFO_CLASS;
988 /* modify the samdb record */
989 ret = ldb_modify(sam_ctx, msg);
990 if (ret != LDB_SUCCESS) {
991 DEBUG(1,("Failed to modify record %s: %s\n",
992 ldb_dn_get_linearized(d_state->domain_dn),
993 ldb_errstring(sam_ctx)));
994 return dsdb_ldb_err_to_ntstatus(ret);
997 return NT_STATUS_OK;
1001 samr_CreateDomainGroup
1003 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1004 struct samr_CreateDomainGroup *r)
1006 NTSTATUS status;
1007 struct samr_domain_state *d_state;
1008 struct samr_account_state *a_state;
1009 struct dcesrv_handle *h;
1010 const char *groupname;
1011 struct dom_sid *group_sid;
1012 struct ldb_dn *group_dn;
1013 struct dcesrv_handle *g_handle;
1015 ZERO_STRUCTP(r->out.group_handle);
1016 *r->out.rid = 0;
1018 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1020 d_state = h->data;
1022 if (d_state->builtin) {
1023 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1024 return NT_STATUS_ACCESS_DENIED;
1027 groupname = r->in.name->string;
1029 if (groupname == NULL) {
1030 return NT_STATUS_INVALID_PARAMETER;
1033 status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1034 if (!NT_STATUS_IS_OK(status)) {
1035 return status;
1038 a_state = talloc(mem_ctx, struct samr_account_state);
1039 if (!a_state) {
1040 return NT_STATUS_NO_MEMORY;
1042 a_state->sam_ctx = d_state->sam_ctx;
1043 a_state->access_mask = r->in.access_mask;
1044 a_state->domain_state = talloc_reference(a_state, d_state);
1045 a_state->account_dn = talloc_steal(a_state, group_dn);
1047 a_state->account_name = talloc_steal(a_state, groupname);
1049 /* create the policy handle */
1050 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1051 if (!g_handle) {
1052 return NT_STATUS_NO_MEMORY;
1055 g_handle->data = talloc_steal(g_handle, a_state);
1057 *r->out.group_handle = g_handle->wire_handle;
1058 *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1060 return NT_STATUS_OK;
1065 comparison function for sorting SamEntry array
1067 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1069 return e1->idx - e2->idx;
1073 samr_EnumDomainGroups
1075 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1076 struct samr_EnumDomainGroups *r)
1078 struct dcesrv_handle *h;
1079 struct samr_domain_state *d_state;
1080 struct ldb_message **res;
1081 int i, ldb_cnt;
1082 uint32_t first, count;
1083 struct samr_SamEntry *entries;
1084 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1085 struct samr_SamArray *sam;
1087 *r->out.resume_handle = 0;
1088 *r->out.sam = NULL;
1089 *r->out.num_entries = 0;
1091 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1093 d_state = h->data;
1095 /* search for all domain groups in this domain. This could possibly be
1096 cached and resumed based on resume_key */
1097 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1098 d_state->domain_dn, &res, attrs,
1099 d_state->domain_sid,
1100 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1101 GTYPE_SECURITY_UNIVERSAL_GROUP,
1102 GTYPE_SECURITY_GLOBAL_GROUP);
1103 if (ldb_cnt < 0) {
1104 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1107 /* convert to SamEntry format */
1108 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1109 if (!entries) {
1110 return NT_STATUS_NO_MEMORY;
1113 count = 0;
1115 for (i=0;i<ldb_cnt;i++) {
1116 struct dom_sid *group_sid;
1118 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1119 "objectSid");
1120 if (group_sid == NULL) {
1121 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1124 entries[count].idx =
1125 group_sid->sub_auths[group_sid->num_auths-1];
1126 entries[count].name.string =
1127 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1128 count += 1;
1131 /* sort the results by rid */
1132 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1134 /* find the first entry to return */
1135 for (first=0;
1136 first<count && entries[first].idx <= *r->in.resume_handle;
1137 first++) ;
1139 /* return the rest, limit by max_size. Note that we
1140 use the w2k3 element size value of 54 */
1141 *r->out.num_entries = count - first;
1142 *r->out.num_entries = MIN(*r->out.num_entries,
1143 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1145 sam = talloc(mem_ctx, struct samr_SamArray);
1146 if (!sam) {
1147 return NT_STATUS_NO_MEMORY;
1150 sam->entries = entries+first;
1151 sam->count = *r->out.num_entries;
1153 *r->out.sam = sam;
1155 if (first == count) {
1156 return NT_STATUS_OK;
1159 if (*r->out.num_entries < count - first) {
1160 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1161 return STATUS_MORE_ENTRIES;
1164 return NT_STATUS_OK;
1169 samr_CreateUser2
1171 This call uses transactions to ensure we don't get a new conflicting
1172 user while we are processing this, and to ensure the user either
1173 completly exists, or does not.
1175 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1176 struct samr_CreateUser2 *r)
1178 NTSTATUS status;
1179 struct samr_domain_state *d_state;
1180 struct samr_account_state *a_state;
1181 struct dcesrv_handle *h;
1182 struct ldb_dn *dn;
1183 struct dom_sid *sid;
1184 struct dcesrv_handle *u_handle;
1185 const char *account_name;
1187 ZERO_STRUCTP(r->out.user_handle);
1188 *r->out.access_granted = 0;
1189 *r->out.rid = 0;
1191 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1193 d_state = h->data;
1195 if (d_state->builtin) {
1196 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1197 return NT_STATUS_ACCESS_DENIED;
1198 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1199 /* Domain trust accounts must be created by the LSA calls */
1200 return NT_STATUS_ACCESS_DENIED;
1202 account_name = r->in.account_name->string;
1204 if (account_name == NULL) {
1205 return NT_STATUS_INVALID_PARAMETER;
1208 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
1209 &sid, &dn);
1210 if (!NT_STATUS_IS_OK(status)) {
1211 return status;
1213 a_state = talloc(mem_ctx, struct samr_account_state);
1214 if (!a_state) {
1215 return NT_STATUS_NO_MEMORY;
1217 a_state->sam_ctx = d_state->sam_ctx;
1218 a_state->access_mask = r->in.access_mask;
1219 a_state->domain_state = talloc_reference(a_state, d_state);
1220 a_state->account_dn = talloc_steal(a_state, dn);
1222 a_state->account_name = talloc_steal(a_state, account_name);
1223 if (!a_state->account_name) {
1224 return NT_STATUS_NO_MEMORY;
1227 /* create the policy handle */
1228 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1229 if (!u_handle) {
1230 return NT_STATUS_NO_MEMORY;
1233 u_handle->data = talloc_steal(u_handle, a_state);
1235 *r->out.user_handle = u_handle->wire_handle;
1236 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1238 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1240 return NT_STATUS_OK;
1245 samr_CreateUser
1247 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1248 struct samr_CreateUser *r)
1250 struct samr_CreateUser2 r2;
1251 uint32_t access_granted = 0;
1254 /* a simple wrapper around samr_CreateUser2 works nicely */
1255 r2.in.domain_handle = r->in.domain_handle;
1256 r2.in.account_name = r->in.account_name;
1257 r2.in.acct_flags = ACB_NORMAL;
1258 r2.in.access_mask = r->in.access_mask;
1259 r2.out.user_handle = r->out.user_handle;
1260 r2.out.access_granted = &access_granted;
1261 r2.out.rid = r->out.rid;
1263 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1267 samr_EnumDomainUsers
1269 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1270 struct samr_EnumDomainUsers *r)
1272 struct dcesrv_handle *h;
1273 struct samr_domain_state *d_state;
1274 struct ldb_message **res;
1275 int i, ldb_cnt;
1276 uint32_t first, count;
1277 struct samr_SamEntry *entries;
1278 const char * const attrs[] = { "objectSid", "sAMAccountName",
1279 "userAccountControl", NULL };
1280 struct samr_SamArray *sam;
1282 *r->out.resume_handle = 0;
1283 *r->out.sam = NULL;
1284 *r->out.num_entries = 0;
1286 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1288 d_state = h->data;
1290 /* search for all domain users in this domain. This could possibly be
1291 cached and resumed on resume_key */
1292 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1293 d_state->domain_dn,
1294 &res, attrs,
1295 d_state->domain_sid,
1296 "(objectClass=user)");
1297 if (ldb_cnt < 0) {
1298 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1301 /* convert to SamEntry format */
1302 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1303 if (!entries) {
1304 return NT_STATUS_NO_MEMORY;
1307 count = 0;
1309 for (i=0;i<ldb_cnt;i++) {
1310 /* Check if a mask has been requested */
1311 if (r->in.acct_flags
1312 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
1313 res[i], d_state->domain_dn) & r->in.acct_flags) == 0)) {
1314 continue;
1316 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1317 "objectSid", 0);
1318 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1319 "sAMAccountName", "");
1320 count += 1;
1323 /* sort the results by rid */
1324 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1326 /* find the first entry to return */
1327 for (first=0;
1328 first<count && entries[first].idx <= *r->in.resume_handle;
1329 first++) ;
1331 /* return the rest, limit by max_size. Note that we
1332 use the w2k3 element size value of 54 */
1333 *r->out.num_entries = count - first;
1334 *r->out.num_entries = MIN(*r->out.num_entries,
1335 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1337 sam = talloc(mem_ctx, struct samr_SamArray);
1338 if (!sam) {
1339 return NT_STATUS_NO_MEMORY;
1342 sam->entries = entries+first;
1343 sam->count = *r->out.num_entries;
1345 *r->out.sam = sam;
1347 if (first == count) {
1348 return NT_STATUS_OK;
1351 if (*r->out.num_entries < count - first) {
1352 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1353 return STATUS_MORE_ENTRIES;
1356 return NT_STATUS_OK;
1361 samr_CreateDomAlias
1363 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1364 struct samr_CreateDomAlias *r)
1366 struct samr_domain_state *d_state;
1367 struct samr_account_state *a_state;
1368 struct dcesrv_handle *h;
1369 const char *alias_name;
1370 struct dom_sid *sid;
1371 struct dcesrv_handle *a_handle;
1372 struct ldb_dn *dn;
1373 NTSTATUS status;
1375 ZERO_STRUCTP(r->out.alias_handle);
1376 *r->out.rid = 0;
1378 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1380 d_state = h->data;
1382 if (d_state->builtin) {
1383 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1384 return NT_STATUS_ACCESS_DENIED;
1387 alias_name = r->in.alias_name->string;
1389 if (alias_name == NULL) {
1390 return NT_STATUS_INVALID_PARAMETER;
1393 status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1394 if (!NT_STATUS_IS_OK(status)) {
1395 return status;
1398 a_state = talloc(mem_ctx, struct samr_account_state);
1399 if (!a_state) {
1400 return NT_STATUS_NO_MEMORY;
1403 a_state->sam_ctx = d_state->sam_ctx;
1404 a_state->access_mask = r->in.access_mask;
1405 a_state->domain_state = talloc_reference(a_state, d_state);
1406 a_state->account_dn = talloc_steal(a_state, dn);
1408 a_state->account_name = talloc_steal(a_state, alias_name);
1410 /* create the policy handle */
1411 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1412 if (a_handle == NULL)
1413 return NT_STATUS_NO_MEMORY;
1415 a_handle->data = talloc_steal(a_handle, a_state);
1417 *r->out.alias_handle = a_handle->wire_handle;
1419 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1421 return NT_STATUS_OK;
1426 samr_EnumDomainAliases
1428 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1429 struct samr_EnumDomainAliases *r)
1431 struct dcesrv_handle *h;
1432 struct samr_domain_state *d_state;
1433 struct ldb_message **res;
1434 int i, ldb_cnt;
1435 uint32_t first, count;
1436 struct samr_SamEntry *entries;
1437 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1438 struct samr_SamArray *sam;
1440 *r->out.resume_handle = 0;
1441 *r->out.sam = NULL;
1442 *r->out.num_entries = 0;
1444 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1446 d_state = h->data;
1448 /* search for all domain aliases in this domain. This could possibly be
1449 cached and resumed based on resume_key */
1450 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1451 &res, attrs,
1452 d_state->domain_sid,
1453 "(&(|(grouptype=%d)(grouptype=%d)))"
1454 "(objectclass=group))",
1455 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1456 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1457 if (ldb_cnt < 0) {
1458 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1461 /* convert to SamEntry format */
1462 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1463 if (!entries) {
1464 return NT_STATUS_NO_MEMORY;
1467 count = 0;
1469 for (i=0;i<ldb_cnt;i++) {
1470 struct dom_sid *alias_sid;
1472 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1473 "objectSid");
1475 if (alias_sid == NULL) {
1476 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1479 entries[count].idx =
1480 alias_sid->sub_auths[alias_sid->num_auths-1];
1481 entries[count].name.string =
1482 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1483 count += 1;
1486 /* sort the results by rid */
1487 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1489 /* find the first entry to return */
1490 for (first=0;
1491 first<count && entries[first].idx <= *r->in.resume_handle;
1492 first++) ;
1494 /* return the rest, limit by max_size. Note that we
1495 use the w2k3 element size value of 54 */
1496 *r->out.num_entries = count - first;
1497 *r->out.num_entries = MIN(*r->out.num_entries,
1498 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1500 sam = talloc(mem_ctx, struct samr_SamArray);
1501 if (!sam) {
1502 return NT_STATUS_NO_MEMORY;
1505 sam->entries = entries+first;
1506 sam->count = *r->out.num_entries;
1508 *r->out.sam = sam;
1510 if (first == count) {
1511 return NT_STATUS_OK;
1514 if (*r->out.num_entries < count - first) {
1515 *r->out.resume_handle =
1516 entries[first+*r->out.num_entries-1].idx;
1517 return STATUS_MORE_ENTRIES;
1520 return NT_STATUS_OK;
1525 samr_GetAliasMembership
1527 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1528 struct samr_GetAliasMembership *r)
1530 struct dcesrv_handle *h;
1531 struct samr_domain_state *d_state;
1532 const char *filter;
1533 const char * const attrs[] = { "objectSid", NULL };
1534 struct ldb_message **res;
1535 uint32_t i;
1536 int count = 0;
1538 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1540 d_state = h->data;
1542 filter = talloc_asprintf(mem_ctx,
1543 "(&(|(grouptype=%d)(grouptype=%d))"
1544 "(objectclass=group)(|",
1545 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1546 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1547 if (filter == NULL) {
1548 return NT_STATUS_NO_MEMORY;
1551 for (i=0; i<r->in.sids->num_sids; i++) {
1552 const char *memberdn;
1554 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1555 "distinguishedName",
1556 "(objectSid=%s)",
1557 ldap_encode_ndr_dom_sid(mem_ctx,
1558 r->in.sids->sids[i].sid));
1559 if (memberdn == NULL) {
1560 continue;
1563 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1564 memberdn);
1565 if (filter == NULL) {
1566 return NT_STATUS_NO_MEMORY;
1570 /* Find out if we had at least one valid member SID passed - otherwise
1571 * just skip the search. */
1572 if (strstr(filter, "member") != NULL) {
1573 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1574 &res, attrs, d_state->domain_sid,
1575 "%s))", filter);
1576 if (count < 0) {
1577 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1581 r->out.rids->count = 0;
1582 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1583 if (r->out.rids->ids == NULL)
1584 return NT_STATUS_NO_MEMORY;
1586 for (i=0; i<count; i++) {
1587 struct dom_sid *alias_sid;
1589 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1590 if (alias_sid == NULL) {
1591 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1594 r->out.rids->ids[r->out.rids->count] =
1595 alias_sid->sub_auths[alias_sid->num_auths-1];
1596 r->out.rids->count += 1;
1599 return NT_STATUS_OK;
1604 samr_LookupNames
1606 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1607 struct samr_LookupNames *r)
1609 struct dcesrv_handle *h;
1610 struct samr_domain_state *d_state;
1611 uint32_t i, num_mapped;
1612 NTSTATUS status = NT_STATUS_OK;
1613 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1614 int count;
1616 ZERO_STRUCTP(r->out.rids);
1617 ZERO_STRUCTP(r->out.types);
1619 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1621 d_state = h->data;
1623 if (r->in.num_names == 0) {
1624 return NT_STATUS_OK;
1627 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1628 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1629 if (!r->out.rids->ids || !r->out.types->ids) {
1630 return NT_STATUS_NO_MEMORY;
1632 r->out.rids->count = r->in.num_names;
1633 r->out.types->count = r->in.num_names;
1635 num_mapped = 0;
1637 for (i=0;i<r->in.num_names;i++) {
1638 struct ldb_message **res;
1639 struct dom_sid *sid;
1640 uint32_t atype, rtype;
1642 r->out.rids->ids[i] = 0;
1643 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1645 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1646 "sAMAccountName=%s",
1647 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1648 if (count != 1) {
1649 status = STATUS_SOME_UNMAPPED;
1650 continue;
1653 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1654 if (sid == NULL) {
1655 status = STATUS_SOME_UNMAPPED;
1656 continue;
1659 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1660 if (atype == 0) {
1661 status = STATUS_SOME_UNMAPPED;
1662 continue;
1665 rtype = ds_atype_map(atype);
1667 if (rtype == SID_NAME_UNKNOWN) {
1668 status = STATUS_SOME_UNMAPPED;
1669 continue;
1672 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1673 r->out.types->ids[i] = rtype;
1674 num_mapped++;
1677 if (num_mapped == 0) {
1678 return NT_STATUS_NONE_MAPPED;
1680 return status;
1685 samr_LookupRids
1687 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1688 struct samr_LookupRids *r)
1690 NTSTATUS status;
1691 struct dcesrv_handle *h;
1692 struct samr_domain_state *d_state;
1693 const char **names;
1694 struct lsa_String *lsa_names;
1695 enum lsa_SidType *ids;
1697 ZERO_STRUCTP(r->out.names);
1698 ZERO_STRUCTP(r->out.types);
1700 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1702 d_state = h->data;
1704 if (r->in.num_rids == 0)
1705 return NT_STATUS_OK;
1707 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1708 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1709 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1711 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1712 return NT_STATUS_NO_MEMORY;
1714 r->out.names->names = lsa_names;
1715 r->out.names->count = r->in.num_rids;
1717 r->out.types->ids = (uint32_t *) ids;
1718 r->out.types->count = r->in.num_rids;
1720 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1721 r->in.num_rids, r->in.rids, names, ids);
1722 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1723 uint32_t i;
1724 for (i = 0; i < r->in.num_rids; i++) {
1725 lsa_names[i].string = names[i];
1728 return status;
1733 samr_OpenGroup
1735 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1736 struct samr_OpenGroup *r)
1738 struct samr_domain_state *d_state;
1739 struct samr_account_state *a_state;
1740 struct dcesrv_handle *h;
1741 const char *groupname;
1742 struct dom_sid *sid;
1743 struct ldb_message **msgs;
1744 struct dcesrv_handle *g_handle;
1745 const char * const attrs[2] = { "sAMAccountName", NULL };
1746 int ret;
1748 ZERO_STRUCTP(r->out.group_handle);
1750 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1752 d_state = h->data;
1754 /* form the group SID */
1755 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1756 if (!sid) {
1757 return NT_STATUS_NO_MEMORY;
1760 /* search for the group record */
1761 ret = gendb_search(d_state->sam_ctx,
1762 mem_ctx, d_state->domain_dn, &msgs, attrs,
1763 "(&(objectSid=%s)(objectClass=group)"
1764 "(|(groupType=%d)(groupType=%d)))",
1765 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1766 GTYPE_SECURITY_UNIVERSAL_GROUP,
1767 GTYPE_SECURITY_GLOBAL_GROUP);
1768 if (ret == 0) {
1769 return NT_STATUS_NO_SUCH_GROUP;
1771 if (ret != 1) {
1772 DEBUG(0,("Found %d records matching sid %s\n",
1773 ret, dom_sid_string(mem_ctx, sid)));
1774 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1777 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1778 if (groupname == NULL) {
1779 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1780 dom_sid_string(mem_ctx, sid)));
1781 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1784 a_state = talloc(mem_ctx, struct samr_account_state);
1785 if (!a_state) {
1786 return NT_STATUS_NO_MEMORY;
1788 a_state->sam_ctx = d_state->sam_ctx;
1789 a_state->access_mask = r->in.access_mask;
1790 a_state->domain_state = talloc_reference(a_state, d_state);
1791 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1792 a_state->account_sid = talloc_steal(a_state, sid);
1793 a_state->account_name = talloc_strdup(a_state, groupname);
1794 if (!a_state->account_name) {
1795 return NT_STATUS_NO_MEMORY;
1798 /* create the policy handle */
1799 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1800 if (!g_handle) {
1801 return NT_STATUS_NO_MEMORY;
1804 g_handle->data = talloc_steal(g_handle, a_state);
1806 *r->out.group_handle = g_handle->wire_handle;
1808 return NT_STATUS_OK;
1812 samr_QueryGroupInfo
1814 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1815 struct samr_QueryGroupInfo *r)
1817 struct dcesrv_handle *h;
1818 struct samr_account_state *a_state;
1819 struct ldb_message *msg, **res;
1820 const char * const attrs[4] = { "sAMAccountName", "description",
1821 "numMembers", NULL };
1822 int ret;
1823 union samr_GroupInfo *info;
1825 *r->out.info = NULL;
1827 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1829 a_state = h->data;
1831 /* pull all the group attributes */
1832 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1833 a_state->account_dn, &res, attrs);
1834 if (ret == 0) {
1835 return NT_STATUS_NO_SUCH_GROUP;
1837 if (ret != 1) {
1838 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1840 msg = res[0];
1842 /* allocate the info structure */
1843 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1844 if (info == NULL) {
1845 return NT_STATUS_NO_MEMORY;
1848 /* Fill in the level */
1849 switch (r->in.level) {
1850 case GROUPINFOALL:
1851 QUERY_STRING(msg, all.name, "sAMAccountName");
1852 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1853 QUERY_UINT (msg, all.num_members, "numMembers")
1854 QUERY_STRING(msg, all.description, "description");
1855 break;
1856 case GROUPINFONAME:
1857 QUERY_STRING(msg, name, "sAMAccountName");
1858 break;
1859 case GROUPINFOATTRIBUTES:
1860 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1861 break;
1862 case GROUPINFODESCRIPTION:
1863 QUERY_STRING(msg, description, "description");
1864 break;
1865 case GROUPINFOALL2:
1866 QUERY_STRING(msg, all2.name, "sAMAccountName");
1867 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1868 QUERY_UINT (msg, all2.num_members, "numMembers")
1869 QUERY_STRING(msg, all2.description, "description");
1870 break;
1871 default:
1872 talloc_free(info);
1873 return NT_STATUS_INVALID_INFO_CLASS;
1876 *r->out.info = info;
1878 return NT_STATUS_OK;
1883 samr_SetGroupInfo
1885 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1886 struct samr_SetGroupInfo *r)
1888 struct dcesrv_handle *h;
1889 struct samr_account_state *g_state;
1890 struct ldb_message *msg;
1891 struct ldb_context *sam_ctx;
1892 int ret;
1894 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1896 g_state = h->data;
1897 sam_ctx = g_state->sam_ctx;
1899 msg = ldb_msg_new(mem_ctx);
1900 if (msg == NULL) {
1901 return NT_STATUS_NO_MEMORY;
1904 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1905 if (!msg->dn) {
1906 return NT_STATUS_NO_MEMORY;
1909 switch (r->in.level) {
1910 case GROUPINFODESCRIPTION:
1911 SET_STRING(msg, description, "description");
1912 break;
1913 case GROUPINFONAME:
1914 /* On W2k3 this does not change the name, it changes the
1915 * sAMAccountName attribute */
1916 SET_STRING(msg, name, "sAMAccountName");
1917 break;
1918 case GROUPINFOATTRIBUTES:
1919 /* This does not do anything obviously visible in W2k3 LDAP */
1920 return NT_STATUS_OK;
1921 default:
1922 return NT_STATUS_INVALID_INFO_CLASS;
1925 /* modify the samdb record */
1926 ret = ldb_modify(g_state->sam_ctx, msg);
1927 if (ret != LDB_SUCCESS) {
1928 return dsdb_ldb_err_to_ntstatus(ret);
1931 return NT_STATUS_OK;
1936 samr_AddGroupMember
1938 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1939 struct samr_AddGroupMember *r)
1941 struct dcesrv_handle *h;
1942 struct samr_account_state *a_state;
1943 struct samr_domain_state *d_state;
1944 struct ldb_message *mod;
1945 struct dom_sid *membersid;
1946 const char *memberdn;
1947 struct ldb_result *res;
1948 const char * const attrs[] = { NULL };
1949 int ret;
1951 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1953 a_state = h->data;
1954 d_state = a_state->domain_state;
1956 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1957 if (membersid == NULL) {
1958 return NT_STATUS_NO_MEMORY;
1961 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1962 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1963 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1964 "(objectSid=%s)",
1965 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1967 if (ret != LDB_SUCCESS) {
1968 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1971 if (res->count == 0) {
1972 return NT_STATUS_NO_SUCH_USER;
1975 if (res->count > 1) {
1976 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1979 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1981 if (memberdn == NULL)
1982 return NT_STATUS_NO_MEMORY;
1984 mod = ldb_msg_new(mem_ctx);
1985 if (mod == NULL) {
1986 return NT_STATUS_NO_MEMORY;
1989 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1991 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1992 memberdn);
1993 if (ret != LDB_SUCCESS) {
1994 return dsdb_ldb_err_to_ntstatus(ret);
1997 ret = ldb_modify(a_state->sam_ctx, mod);
1998 switch (ret) {
1999 case LDB_SUCCESS:
2000 return NT_STATUS_OK;
2001 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2002 return NT_STATUS_MEMBER_IN_GROUP;
2003 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2004 return NT_STATUS_ACCESS_DENIED;
2005 default:
2006 return dsdb_ldb_err_to_ntstatus(ret);
2012 samr_DeleteDomainGroup
2014 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2015 struct samr_DeleteDomainGroup *r)
2017 struct dcesrv_handle *h;
2018 struct samr_account_state *a_state;
2019 int ret;
2021 *r->out.group_handle = *r->in.group_handle;
2023 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2025 a_state = h->data;
2027 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2028 if (ret != LDB_SUCCESS) {
2029 return dsdb_ldb_err_to_ntstatus(ret);
2032 talloc_free(h);
2033 ZERO_STRUCTP(r->out.group_handle);
2035 return NT_STATUS_OK;
2040 samr_DeleteGroupMember
2042 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2043 struct samr_DeleteGroupMember *r)
2045 struct dcesrv_handle *h;
2046 struct samr_account_state *a_state;
2047 struct samr_domain_state *d_state;
2048 struct ldb_message *mod;
2049 struct dom_sid *membersid;
2050 const char *memberdn;
2051 struct ldb_result *res;
2052 const char * const attrs[] = { NULL };
2053 int ret;
2055 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2057 a_state = h->data;
2058 d_state = a_state->domain_state;
2060 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2061 if (membersid == NULL) {
2062 return NT_STATUS_NO_MEMORY;
2065 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2066 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2067 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2068 "(objectSid=%s)",
2069 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2071 if (ret != LDB_SUCCESS) {
2072 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2075 if (res->count == 0) {
2076 return NT_STATUS_NO_SUCH_USER;
2079 if (res->count > 1) {
2080 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2083 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2085 if (memberdn == NULL)
2086 return NT_STATUS_NO_MEMORY;
2088 mod = ldb_msg_new(mem_ctx);
2089 if (mod == NULL) {
2090 return NT_STATUS_NO_MEMORY;
2093 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2095 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2096 memberdn);
2097 if (ret != LDB_SUCCESS) {
2098 return NT_STATUS_NO_MEMORY;
2101 ret = ldb_modify(a_state->sam_ctx, mod);
2102 switch (ret) {
2103 case LDB_SUCCESS:
2104 return NT_STATUS_OK;
2105 case LDB_ERR_UNWILLING_TO_PERFORM:
2106 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2107 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2108 return NT_STATUS_ACCESS_DENIED;
2109 default:
2110 return dsdb_ldb_err_to_ntstatus(ret);
2116 samr_QueryGroupMember
2118 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2119 struct samr_QueryGroupMember *r)
2121 struct dcesrv_handle *h;
2122 struct samr_account_state *a_state;
2123 struct samr_domain_state *d_state;
2124 struct samr_RidAttrArray *array;
2125 unsigned int i, num_members;
2126 struct dom_sid *members;
2127 NTSTATUS status;
2129 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2131 a_state = h->data;
2132 d_state = a_state->domain_state;
2134 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2135 a_state->account_dn, &members,
2136 &num_members);
2137 if (!NT_STATUS_IS_OK(status)) {
2138 return status;
2141 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2142 if (array == NULL) {
2143 return NT_STATUS_NO_MEMORY;
2146 if (num_members == 0) {
2147 *r->out.rids = array;
2149 return NT_STATUS_OK;
2152 array->rids = talloc_array(array, uint32_t, num_members);
2153 if (array->rids == NULL) {
2154 return NT_STATUS_NO_MEMORY;
2157 array->attributes = talloc_array(array, uint32_t, num_members);
2158 if (array->attributes == NULL) {
2159 return NT_STATUS_NO_MEMORY;
2162 array->count = 0;
2163 for (i=0; i<num_members; i++) {
2164 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2165 continue;
2168 status = dom_sid_split_rid(NULL, &members[i], NULL,
2169 &array->rids[array->count]);
2170 if (!NT_STATUS_IS_OK(status)) {
2171 return status;
2174 array->attributes[array->count] = SE_GROUP_MANDATORY |
2175 SE_GROUP_ENABLED_BY_DEFAULT |
2176 SE_GROUP_ENABLED;
2177 array->count++;
2180 *r->out.rids = array;
2182 return NT_STATUS_OK;
2187 samr_SetMemberAttributesOfGroup
2189 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2190 struct samr_SetMemberAttributesOfGroup *r)
2192 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2197 samr_OpenAlias
2199 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2200 struct samr_OpenAlias *r)
2202 struct samr_domain_state *d_state;
2203 struct samr_account_state *a_state;
2204 struct dcesrv_handle *h;
2205 const char *alias_name;
2206 struct dom_sid *sid;
2207 struct ldb_message **msgs;
2208 struct dcesrv_handle *g_handle;
2209 const char * const attrs[2] = { "sAMAccountName", NULL };
2210 int ret;
2212 ZERO_STRUCTP(r->out.alias_handle);
2214 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2216 d_state = h->data;
2218 /* form the alias SID */
2219 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2220 if (sid == NULL)
2221 return NT_STATUS_NO_MEMORY;
2223 /* search for the group record */
2224 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2225 "(&(objectSid=%s)(objectclass=group)"
2226 "(|(grouptype=%d)(grouptype=%d)))",
2227 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2228 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2229 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2230 if (ret == 0) {
2231 return NT_STATUS_NO_SUCH_ALIAS;
2233 if (ret != 1) {
2234 DEBUG(0,("Found %d records matching sid %s\n",
2235 ret, dom_sid_string(mem_ctx, sid)));
2236 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2239 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2240 if (alias_name == NULL) {
2241 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2242 dom_sid_string(mem_ctx, sid)));
2243 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2246 a_state = talloc(mem_ctx, struct samr_account_state);
2247 if (!a_state) {
2248 return NT_STATUS_NO_MEMORY;
2250 a_state->sam_ctx = d_state->sam_ctx;
2251 a_state->access_mask = r->in.access_mask;
2252 a_state->domain_state = talloc_reference(a_state, d_state);
2253 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2254 a_state->account_sid = talloc_steal(a_state, sid);
2255 a_state->account_name = talloc_strdup(a_state, alias_name);
2256 if (!a_state->account_name) {
2257 return NT_STATUS_NO_MEMORY;
2260 /* create the policy handle */
2261 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2262 if (!g_handle) {
2263 return NT_STATUS_NO_MEMORY;
2266 g_handle->data = talloc_steal(g_handle, a_state);
2268 *r->out.alias_handle = g_handle->wire_handle;
2270 return NT_STATUS_OK;
2275 samr_QueryAliasInfo
2277 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2278 struct samr_QueryAliasInfo *r)
2280 struct dcesrv_handle *h;
2281 struct samr_account_state *a_state;
2282 struct ldb_message *msg, **res;
2283 const char * const attrs[4] = { "sAMAccountName", "description",
2284 "numMembers", NULL };
2285 int ret;
2286 union samr_AliasInfo *info;
2288 *r->out.info = NULL;
2290 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2292 a_state = h->data;
2294 /* pull all the alias attributes */
2295 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2296 a_state->account_dn, &res, attrs);
2297 if (ret == 0) {
2298 return NT_STATUS_NO_SUCH_ALIAS;
2300 if (ret != 1) {
2301 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2303 msg = res[0];
2305 /* allocate the info structure */
2306 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2307 if (info == NULL) {
2308 return NT_STATUS_NO_MEMORY;
2311 switch(r->in.level) {
2312 case ALIASINFOALL:
2313 QUERY_STRING(msg, all.name, "sAMAccountName");
2314 QUERY_UINT (msg, all.num_members, "numMembers");
2315 QUERY_STRING(msg, all.description, "description");
2316 break;
2317 case ALIASINFONAME:
2318 QUERY_STRING(msg, name, "sAMAccountName");
2319 break;
2320 case ALIASINFODESCRIPTION:
2321 QUERY_STRING(msg, description, "description");
2322 break;
2323 default:
2324 talloc_free(info);
2325 return NT_STATUS_INVALID_INFO_CLASS;
2328 *r->out.info = info;
2330 return NT_STATUS_OK;
2335 samr_SetAliasInfo
2337 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2338 struct samr_SetAliasInfo *r)
2340 struct dcesrv_handle *h;
2341 struct samr_account_state *a_state;
2342 struct ldb_message *msg;
2343 struct ldb_context *sam_ctx;
2344 int ret;
2346 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2348 a_state = h->data;
2349 sam_ctx = a_state->sam_ctx;
2351 msg = ldb_msg_new(mem_ctx);
2352 if (msg == NULL) {
2353 return NT_STATUS_NO_MEMORY;
2356 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2357 if (!msg->dn) {
2358 return NT_STATUS_NO_MEMORY;
2361 switch (r->in.level) {
2362 case ALIASINFODESCRIPTION:
2363 SET_STRING(msg, description, "description");
2364 break;
2365 case ALIASINFONAME:
2366 /* On W2k3 this does not change the name, it changes the
2367 * sAMAccountName attribute */
2368 SET_STRING(msg, name, "sAMAccountName");
2369 break;
2370 default:
2371 return NT_STATUS_INVALID_INFO_CLASS;
2374 /* modify the samdb record */
2375 ret = ldb_modify(a_state->sam_ctx, msg);
2376 if (ret != LDB_SUCCESS) {
2377 return dsdb_ldb_err_to_ntstatus(ret);
2380 return NT_STATUS_OK;
2385 samr_DeleteDomAlias
2387 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2388 struct samr_DeleteDomAlias *r)
2390 struct dcesrv_handle *h;
2391 struct samr_account_state *a_state;
2392 int ret;
2394 *r->out.alias_handle = *r->in.alias_handle;
2396 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2398 a_state = h->data;
2400 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2401 if (ret != LDB_SUCCESS) {
2402 return dsdb_ldb_err_to_ntstatus(ret);
2405 talloc_free(h);
2406 ZERO_STRUCTP(r->out.alias_handle);
2408 return NT_STATUS_OK;
2413 samr_AddAliasMember
2415 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2416 struct samr_AddAliasMember *r)
2418 struct dcesrv_handle *h;
2419 struct samr_account_state *a_state;
2420 struct samr_domain_state *d_state;
2421 struct ldb_message *mod;
2422 struct ldb_message **msgs;
2423 const char * const attrs[] = { NULL };
2424 struct ldb_dn *memberdn = NULL;
2425 int ret;
2426 NTSTATUS status;
2428 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2430 a_state = h->data;
2431 d_state = a_state->domain_state;
2433 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2434 &msgs, attrs, "(objectsid=%s)",
2435 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2437 if (ret == 1) {
2438 memberdn = msgs[0]->dn;
2439 } else if (ret == 0) {
2440 status = samdb_create_foreign_security_principal(
2441 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2442 if (!NT_STATUS_IS_OK(status)) {
2443 return status;
2445 } else {
2446 DEBUG(0,("Found %d records matching sid %s\n",
2447 ret, dom_sid_string(mem_ctx, r->in.sid)));
2448 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2451 if (memberdn == NULL) {
2452 DEBUG(0, ("Could not find memberdn\n"));
2453 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2456 mod = ldb_msg_new(mem_ctx);
2457 if (mod == NULL) {
2458 return NT_STATUS_NO_MEMORY;
2461 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2463 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2464 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2465 if (ret != LDB_SUCCESS) {
2466 return dsdb_ldb_err_to_ntstatus(ret);
2469 ret = ldb_modify(a_state->sam_ctx, mod);
2470 switch (ret) {
2471 case LDB_SUCCESS:
2472 return NT_STATUS_OK;
2473 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2474 return NT_STATUS_MEMBER_IN_GROUP;
2475 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2476 return NT_STATUS_ACCESS_DENIED;
2477 default:
2478 return dsdb_ldb_err_to_ntstatus(ret);
2484 samr_DeleteAliasMember
2486 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2487 struct samr_DeleteAliasMember *r)
2489 struct dcesrv_handle *h;
2490 struct samr_account_state *a_state;
2491 struct samr_domain_state *d_state;
2492 struct ldb_message *mod;
2493 const char *memberdn;
2494 int ret;
2496 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2498 a_state = h->data;
2499 d_state = a_state->domain_state;
2501 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2502 "distinguishedName", "(objectSid=%s)",
2503 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2504 if (memberdn == NULL) {
2505 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2508 mod = ldb_msg_new(mem_ctx);
2509 if (mod == NULL) {
2510 return NT_STATUS_NO_MEMORY;
2513 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2515 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2516 memberdn);
2517 if (ret != LDB_SUCCESS) {
2518 return dsdb_ldb_err_to_ntstatus(ret);
2521 ret = ldb_modify(a_state->sam_ctx, mod);
2522 switch (ret) {
2523 case LDB_SUCCESS:
2524 return NT_STATUS_OK;
2525 case LDB_ERR_UNWILLING_TO_PERFORM:
2526 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2527 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2528 return NT_STATUS_ACCESS_DENIED;
2529 default:
2530 return dsdb_ldb_err_to_ntstatus(ret);
2536 samr_GetMembersInAlias
2538 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2539 struct samr_GetMembersInAlias *r)
2541 struct dcesrv_handle *h;
2542 struct samr_account_state *a_state;
2543 struct samr_domain_state *d_state;
2544 struct lsa_SidPtr *array;
2545 unsigned int i, num_members;
2546 struct dom_sid *members;
2547 NTSTATUS status;
2549 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2551 a_state = h->data;
2552 d_state = a_state->domain_state;
2554 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2555 a_state->account_dn, &members,
2556 &num_members);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 return status;
2561 if (num_members == 0) {
2562 r->out.sids->sids = NULL;
2564 return NT_STATUS_OK;
2567 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2568 if (array == NULL) {
2569 return NT_STATUS_NO_MEMORY;
2572 for (i=0; i<num_members; i++) {
2573 array[i].sid = &members[i];
2576 r->out.sids->num_sids = num_members;
2577 r->out.sids->sids = array;
2579 return NT_STATUS_OK;
2583 samr_OpenUser
2585 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2586 struct samr_OpenUser *r)
2588 struct samr_domain_state *d_state;
2589 struct samr_account_state *a_state;
2590 struct dcesrv_handle *h;
2591 const char *account_name;
2592 struct dom_sid *sid;
2593 struct ldb_message **msgs;
2594 struct dcesrv_handle *u_handle;
2595 const char * const attrs[2] = { "sAMAccountName", NULL };
2596 int ret;
2598 ZERO_STRUCTP(r->out.user_handle);
2600 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2602 d_state = h->data;
2604 /* form the users SID */
2605 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2606 if (!sid) {
2607 return NT_STATUS_NO_MEMORY;
2610 /* search for the user record */
2611 ret = gendb_search(d_state->sam_ctx,
2612 mem_ctx, d_state->domain_dn, &msgs, attrs,
2613 "(&(objectSid=%s)(objectclass=user))",
2614 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2615 if (ret == 0) {
2616 return NT_STATUS_NO_SUCH_USER;
2618 if (ret != 1) {
2619 DEBUG(0,("Found %d records matching sid %s\n", ret,
2620 dom_sid_string(mem_ctx, sid)));
2621 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2624 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2625 if (account_name == NULL) {
2626 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2627 dom_sid_string(mem_ctx, sid)));
2628 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2631 a_state = talloc(mem_ctx, struct samr_account_state);
2632 if (!a_state) {
2633 return NT_STATUS_NO_MEMORY;
2635 a_state->sam_ctx = d_state->sam_ctx;
2636 a_state->access_mask = r->in.access_mask;
2637 a_state->domain_state = talloc_reference(a_state, d_state);
2638 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2639 a_state->account_sid = talloc_steal(a_state, sid);
2640 a_state->account_name = talloc_strdup(a_state, account_name);
2641 if (!a_state->account_name) {
2642 return NT_STATUS_NO_MEMORY;
2645 /* create the policy handle */
2646 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2647 if (!u_handle) {
2648 return NT_STATUS_NO_MEMORY;
2651 u_handle->data = talloc_steal(u_handle, a_state);
2653 *r->out.user_handle = u_handle->wire_handle;
2655 return NT_STATUS_OK;
2661 samr_DeleteUser
2663 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2664 struct samr_DeleteUser *r)
2666 struct dcesrv_handle *h;
2667 struct samr_account_state *a_state;
2668 int ret;
2670 *r->out.user_handle = *r->in.user_handle;
2672 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2674 a_state = h->data;
2676 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2677 if (ret != LDB_SUCCESS) {
2678 DEBUG(1, ("Failed to delete user: %s: %s\n",
2679 ldb_dn_get_linearized(a_state->account_dn),
2680 ldb_errstring(a_state->sam_ctx)));
2681 return dsdb_ldb_err_to_ntstatus(ret);
2684 talloc_free(h);
2685 ZERO_STRUCTP(r->out.user_handle);
2687 return NT_STATUS_OK;
2692 samr_QueryUserInfo
2694 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2695 struct samr_QueryUserInfo *r)
2697 struct dcesrv_handle *h;
2698 struct samr_account_state *a_state;
2699 struct ldb_message *msg, **res;
2700 int ret;
2701 struct ldb_context *sam_ctx;
2703 const char * const *attrs = NULL;
2704 union samr_UserInfo *info;
2706 *r->out.info = NULL;
2708 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2710 a_state = h->data;
2711 sam_ctx = a_state->sam_ctx;
2713 /* fill in the reply */
2714 switch (r->in.level) {
2715 case 1:
2717 static const char * const attrs2[] = {"sAMAccountName",
2718 "displayName",
2719 "primaryroupID",
2720 "description",
2721 "comment",
2722 NULL};
2723 attrs = attrs2;
2724 break;
2726 case 2:
2728 static const char * const attrs2[] = {"comment",
2729 "countryCode",
2730 "codePage",
2731 NULL};
2732 attrs = attrs2;
2733 break;
2735 case 3:
2737 static const char * const attrs2[] = {"sAMAccountName",
2738 "displayName",
2739 "objectSid",
2740 "primaryGroupID",
2741 "homeDirectory",
2742 "homeDrive",
2743 "scriptPath",
2744 "profilePath",
2745 "userWorkstations",
2746 "lastLogon",
2747 "lastLogoff",
2748 "pwdLastSet",
2749 "logonHours",
2750 "badPwdCount",
2751 "logonCount",
2752 "userAccountControl",
2753 NULL};
2754 attrs = attrs2;
2755 break;
2757 case 4:
2759 static const char * const attrs2[] = {"logonHours",
2760 NULL};
2761 attrs = attrs2;
2762 break;
2764 case 5:
2766 static const char * const attrs2[] = {"sAMAccountName",
2767 "displayName",
2768 "objectSid",
2769 "primaryGroupID",
2770 "homeDirectory",
2771 "homeDrive",
2772 "scriptPath",
2773 "profilePath",
2774 "description",
2775 "userWorkstations",
2776 "lastLogon",
2777 "lastLogoff",
2778 "logonHours",
2779 "badPwdCount",
2780 "logonCount",
2781 "pwdLastSet",
2782 "accountExpires",
2783 "userAccountControl",
2784 NULL};
2785 attrs = attrs2;
2786 break;
2788 case 6:
2790 static const char * const attrs2[] = {"sAMAccountName",
2791 "displayName",
2792 NULL};
2793 attrs = attrs2;
2794 break;
2796 case 7:
2798 static const char * const attrs2[] = {"sAMAccountName",
2799 NULL};
2800 attrs = attrs2;
2801 break;
2803 case 8:
2805 static const char * const attrs2[] = {"displayName",
2806 NULL};
2807 attrs = attrs2;
2808 break;
2810 case 9:
2812 static const char * const attrs2[] = {"primaryGroupID",
2813 NULL};
2814 attrs = attrs2;
2815 break;
2817 case 10:
2819 static const char * const attrs2[] = {"homeDirectory",
2820 "homeDrive",
2821 NULL};
2822 attrs = attrs2;
2823 break;
2825 case 11:
2827 static const char * const attrs2[] = {"scriptPath",
2828 NULL};
2829 attrs = attrs2;
2830 break;
2832 case 12:
2834 static const char * const attrs2[] = {"profilePath",
2835 NULL};
2836 attrs = attrs2;
2837 break;
2839 case 13:
2841 static const char * const attrs2[] = {"description",
2842 NULL};
2843 attrs = attrs2;
2844 break;
2846 case 14:
2848 static const char * const attrs2[] = {"userWorkstations",
2849 NULL};
2850 attrs = attrs2;
2851 break;
2853 case 16:
2855 static const char * const attrs2[] = {"userAccountControl",
2856 "pwdLastSet",
2857 NULL};
2858 attrs = attrs2;
2859 break;
2861 case 17:
2863 static const char * const attrs2[] = {"accountExpires",
2864 NULL};
2865 attrs = attrs2;
2866 break;
2868 case 18:
2870 return NT_STATUS_NOT_SUPPORTED;
2872 case 20:
2874 static const char * const attrs2[] = {"userParameters",
2875 NULL};
2876 attrs = attrs2;
2877 break;
2879 case 21:
2881 static const char * const attrs2[] = {"lastLogon",
2882 "lastLogoff",
2883 "pwdLastSet",
2884 "accountExpires",
2885 "sAMAccountName",
2886 "displayName",
2887 "homeDirectory",
2888 "homeDrive",
2889 "scriptPath",
2890 "profilePath",
2891 "description",
2892 "userWorkstations",
2893 "comment",
2894 "userParameters",
2895 "objectSid",
2896 "primaryGroupID",
2897 "userAccountControl",
2898 "logonHours",
2899 "badPwdCount",
2900 "logonCount",
2901 "countryCode",
2902 "codePage",
2903 NULL};
2904 attrs = attrs2;
2905 break;
2907 case 23:
2908 case 24:
2909 case 25:
2910 case 26:
2912 return NT_STATUS_NOT_SUPPORTED;
2914 default:
2916 return NT_STATUS_INVALID_INFO_CLASS;
2920 /* pull all the user attributes */
2921 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2922 a_state->account_dn, &res, attrs);
2923 if (ret == 0) {
2924 return NT_STATUS_NO_SUCH_USER;
2926 if (ret != 1) {
2927 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2929 msg = res[0];
2931 /* allocate the info structure */
2932 info = talloc_zero(mem_ctx, union samr_UserInfo);
2933 if (info == NULL) {
2934 return NT_STATUS_NO_MEMORY;
2937 /* fill in the reply */
2938 switch (r->in.level) {
2939 case 1:
2940 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2941 QUERY_STRING(msg, info1.full_name, "displayName");
2942 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2943 QUERY_STRING(msg, info1.description, "description");
2944 QUERY_STRING(msg, info1.comment, "comment");
2945 break;
2947 case 2:
2948 QUERY_STRING(msg, info2.comment, "comment");
2949 QUERY_UINT (msg, info2.country_code, "countryCode");
2950 QUERY_UINT (msg, info2.code_page, "codePage");
2951 break;
2953 case 3:
2954 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2955 QUERY_STRING(msg, info3.full_name, "displayName");
2956 QUERY_RID (msg, info3.rid, "objectSid");
2957 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2958 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2959 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2960 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2961 QUERY_STRING(msg, info3.profile_path, "profilePath");
2962 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2963 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2964 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2965 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2966 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2967 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2968 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2969 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2970 QUERY_UINT (msg, info3.logon_count, "logonCount");
2971 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
2972 break;
2974 case 4:
2975 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2976 break;
2978 case 5:
2979 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2980 QUERY_STRING(msg, info5.full_name, "displayName");
2981 QUERY_RID (msg, info5.rid, "objectSid");
2982 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2983 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2984 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2985 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2986 QUERY_STRING(msg, info5.profile_path, "profilePath");
2987 QUERY_STRING(msg, info5.description, "description");
2988 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2989 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2990 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2991 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2992 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
2993 QUERY_UINT (msg, info5.logon_count, "logonCount");
2994 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2995 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
2996 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
2997 break;
2999 case 6:
3000 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3001 QUERY_STRING(msg, info6.full_name, "displayName");
3002 break;
3004 case 7:
3005 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3006 break;
3008 case 8:
3009 QUERY_STRING(msg, info8.full_name, "displayName");
3010 break;
3012 case 9:
3013 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3014 break;
3016 case 10:
3017 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3018 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3019 break;
3021 case 11:
3022 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3023 break;
3025 case 12:
3026 QUERY_STRING(msg, info12.profile_path, "profilePath");
3027 break;
3029 case 13:
3030 QUERY_STRING(msg, info13.description, "description");
3031 break;
3033 case 14:
3034 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3035 break;
3037 case 16:
3038 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3039 break;
3041 case 17:
3042 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3043 break;
3045 case 20:
3046 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3047 break;
3049 case 21:
3050 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3051 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3052 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3053 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3054 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3055 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3056 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3057 QUERY_STRING(msg, info21.full_name, "displayName");
3058 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3059 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3060 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3061 QUERY_STRING(msg, info21.profile_path, "profilePath");
3062 QUERY_STRING(msg, info21.description, "description");
3063 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3064 QUERY_STRING(msg, info21.comment, "comment");
3065 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3066 QUERY_RID (msg, info21.rid, "objectSid");
3067 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3068 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3069 info->info21.fields_present = 0x08FFFFFF;
3070 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3071 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3072 QUERY_UINT (msg, info21.logon_count, "logonCount");
3073 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3074 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3075 } else {
3076 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3078 QUERY_UINT (msg, info21.country_code, "countryCode");
3079 QUERY_UINT (msg, info21.code_page, "codePage");
3080 break;
3083 default:
3084 talloc_free(info);
3085 return NT_STATUS_INVALID_INFO_CLASS;
3088 *r->out.info = info;
3090 return NT_STATUS_OK;
3095 samr_SetUserInfo
3097 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3098 struct samr_SetUserInfo *r)
3100 struct dcesrv_handle *h;
3101 struct samr_account_state *a_state;
3102 struct ldb_message *msg;
3103 int ret;
3104 NTSTATUS status = NT_STATUS_OK;
3105 struct ldb_context *sam_ctx;
3107 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3109 a_state = h->data;
3110 sam_ctx = a_state->sam_ctx;
3112 msg = ldb_msg_new(mem_ctx);
3113 if (msg == NULL) {
3114 return NT_STATUS_NO_MEMORY;
3117 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3118 if (!msg->dn) {
3119 return NT_STATUS_NO_MEMORY;
3122 switch (r->in.level) {
3123 case 2:
3124 SET_STRING(msg, info2.comment, "comment");
3125 SET_UINT (msg, info2.country_code, "countryCode");
3126 SET_UINT (msg, info2.code_page, "codePage");
3127 break;
3129 case 4:
3130 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3131 break;
3133 case 6:
3134 SET_STRING(msg, info6.account_name, "samAccountName");
3135 SET_STRING(msg, info6.full_name, "displayName");
3136 break;
3138 case 7:
3139 SET_STRING(msg, info7.account_name, "samAccountName");
3140 break;
3142 case 8:
3143 SET_STRING(msg, info8.full_name, "displayName");
3144 break;
3146 case 9:
3147 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3148 break;
3150 case 10:
3151 SET_STRING(msg, info10.home_directory, "homeDirectory");
3152 SET_STRING(msg, info10.home_drive, "homeDrive");
3153 break;
3155 case 11:
3156 SET_STRING(msg, info11.logon_script, "scriptPath");
3157 break;
3159 case 12:
3160 SET_STRING(msg, info12.profile_path, "profilePath");
3161 break;
3163 case 13:
3164 SET_STRING(msg, info13.description, "description");
3165 break;
3167 case 14:
3168 SET_STRING(msg, info14.workstations, "userWorkstations");
3169 break;
3171 case 16:
3172 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3173 break;
3175 case 17:
3176 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3177 break;
3179 case 18:
3180 status = samr_set_password_buffers(dce_call,
3181 a_state->sam_ctx,
3182 a_state->account_dn,
3183 a_state->domain_state->domain_dn,
3184 mem_ctx,
3185 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3186 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3187 if (!NT_STATUS_IS_OK(status)) {
3188 return status;
3191 if (r->in.info->info18.password_expired > 0) {
3192 struct ldb_message_element *set_el;
3193 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3194 return NT_STATUS_NO_MEMORY;
3196 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3197 set_el->flags = LDB_FLAG_MOD_REPLACE;
3199 break;
3201 case 20:
3202 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3203 break;
3205 case 21:
3206 if (r->in.info->info21.fields_present == 0)
3207 return NT_STATUS_INVALID_PARAMETER;
3209 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3210 IFSET(SAMR_FIELD_LAST_LOGON)
3211 SET_UINT64(msg, info21.last_logon, "lastLogon");
3212 IFSET(SAMR_FIELD_LAST_LOGOFF)
3213 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3214 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3215 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3216 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3217 SET_STRING(msg, info21.account_name, "samAccountName");
3218 IFSET(SAMR_FIELD_FULL_NAME)
3219 SET_STRING(msg, info21.full_name, "displayName");
3220 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3221 SET_STRING(msg, info21.home_directory, "homeDirectory");
3222 IFSET(SAMR_FIELD_HOME_DRIVE)
3223 SET_STRING(msg, info21.home_drive, "homeDrive");
3224 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3225 SET_STRING(msg, info21.logon_script, "scriptPath");
3226 IFSET(SAMR_FIELD_PROFILE_PATH)
3227 SET_STRING(msg, info21.profile_path, "profilePath");
3228 IFSET(SAMR_FIELD_DESCRIPTION)
3229 SET_STRING(msg, info21.description, "description");
3230 IFSET(SAMR_FIELD_WORKSTATIONS)
3231 SET_STRING(msg, info21.workstations, "userWorkstations");
3232 IFSET(SAMR_FIELD_COMMENT)
3233 SET_STRING(msg, info21.comment, "comment");
3234 IFSET(SAMR_FIELD_PARAMETERS)
3235 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3236 IFSET(SAMR_FIELD_PRIMARY_GID)
3237 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3238 IFSET(SAMR_FIELD_ACCT_FLAGS)
3239 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3240 IFSET(SAMR_FIELD_LOGON_HOURS)
3241 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3242 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3243 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3244 IFSET(SAMR_FIELD_NUM_LOGONS)
3245 SET_UINT (msg, info21.logon_count, "logonCount");
3246 IFSET(SAMR_FIELD_COUNTRY_CODE)
3247 SET_UINT (msg, info21.country_code, "countryCode");
3248 IFSET(SAMR_FIELD_CODE_PAGE)
3249 SET_UINT (msg, info21.code_page, "codePage");
3251 /* password change fields */
3252 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3253 return NT_STATUS_ACCESS_DENIED;
3255 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3256 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3257 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3259 if (r->in.info->info21.lm_password_set) {
3260 if ((r->in.info->info21.lm_owf_password.length != 16)
3261 || (r->in.info->info21.lm_owf_password.size != 16)) {
3262 return NT_STATUS_INVALID_PARAMETER;
3265 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3267 if (r->in.info->info21.nt_password_set) {
3268 if ((r->in.info->info21.nt_owf_password.length != 16)
3269 || (r->in.info->info21.nt_owf_password.size != 16)) {
3270 return NT_STATUS_INVALID_PARAMETER;
3273 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3275 status = samr_set_password_buffers(dce_call,
3276 a_state->sam_ctx,
3277 a_state->account_dn,
3278 a_state->domain_state->domain_dn,
3279 mem_ctx,
3280 lm_pwd_hash,
3281 nt_pwd_hash);
3282 if (!NT_STATUS_IS_OK(status)) {
3283 return status;
3288 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3289 NTTIME t = 0;
3290 struct ldb_message_element *set_el;
3291 if (r->in.info->info21.password_expired
3292 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3293 unix_to_nt_time(&t, time(NULL));
3295 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3296 "pwdLastSet", t) != LDB_SUCCESS) {
3297 return NT_STATUS_NO_MEMORY;
3299 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3300 set_el->flags = LDB_FLAG_MOD_REPLACE;
3302 #undef IFSET
3303 break;
3305 case 23:
3306 if (r->in.info->info23.info.fields_present == 0)
3307 return NT_STATUS_INVALID_PARAMETER;
3309 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3310 IFSET(SAMR_FIELD_LAST_LOGON)
3311 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3312 IFSET(SAMR_FIELD_LAST_LOGOFF)
3313 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3314 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3315 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3316 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3317 SET_STRING(msg, info23.info.account_name, "samAccountName");
3318 IFSET(SAMR_FIELD_FULL_NAME)
3319 SET_STRING(msg, info23.info.full_name, "displayName");
3320 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3321 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3322 IFSET(SAMR_FIELD_HOME_DRIVE)
3323 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3324 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3325 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3326 IFSET(SAMR_FIELD_PROFILE_PATH)
3327 SET_STRING(msg, info23.info.profile_path, "profilePath");
3328 IFSET(SAMR_FIELD_DESCRIPTION)
3329 SET_STRING(msg, info23.info.description, "description");
3330 IFSET(SAMR_FIELD_WORKSTATIONS)
3331 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3332 IFSET(SAMR_FIELD_COMMENT)
3333 SET_STRING(msg, info23.info.comment, "comment");
3334 IFSET(SAMR_FIELD_PARAMETERS)
3335 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3336 IFSET(SAMR_FIELD_PRIMARY_GID)
3337 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3338 IFSET(SAMR_FIELD_ACCT_FLAGS)
3339 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3340 IFSET(SAMR_FIELD_LOGON_HOURS)
3341 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3342 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3343 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3344 IFSET(SAMR_FIELD_NUM_LOGONS)
3345 SET_UINT (msg, info23.info.logon_count, "logonCount");
3347 IFSET(SAMR_FIELD_COUNTRY_CODE)
3348 SET_UINT (msg, info23.info.country_code, "countryCode");
3349 IFSET(SAMR_FIELD_CODE_PAGE)
3350 SET_UINT (msg, info23.info.code_page, "codePage");
3352 /* password change fields */
3353 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3354 return NT_STATUS_ACCESS_DENIED;
3356 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3357 status = samr_set_password(dce_call,
3358 a_state->sam_ctx,
3359 a_state->account_dn,
3360 a_state->domain_state->domain_dn,
3361 mem_ctx,
3362 &r->in.info->info23.password);
3363 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3364 status = samr_set_password(dce_call,
3365 a_state->sam_ctx,
3366 a_state->account_dn,
3367 a_state->domain_state->domain_dn,
3368 mem_ctx,
3369 &r->in.info->info23.password);
3371 if (!NT_STATUS_IS_OK(status)) {
3372 return status;
3375 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3376 NTTIME t = 0;
3377 struct ldb_message_element *set_el;
3378 if (r->in.info->info23.info.password_expired
3379 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3380 unix_to_nt_time(&t, time(NULL));
3382 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3383 "pwdLastSet", t) != LDB_SUCCESS) {
3384 return NT_STATUS_NO_MEMORY;
3386 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3387 set_el->flags = LDB_FLAG_MOD_REPLACE;
3389 #undef IFSET
3390 break;
3392 /* the set password levels are handled separately */
3393 case 24:
3394 status = samr_set_password(dce_call,
3395 a_state->sam_ctx,
3396 a_state->account_dn,
3397 a_state->domain_state->domain_dn,
3398 mem_ctx,
3399 &r->in.info->info24.password);
3400 if (!NT_STATUS_IS_OK(status)) {
3401 return status;
3404 if (r->in.info->info24.password_expired > 0) {
3405 struct ldb_message_element *set_el;
3406 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3407 return NT_STATUS_NO_MEMORY;
3409 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3410 set_el->flags = LDB_FLAG_MOD_REPLACE;
3412 break;
3414 case 25:
3415 if (r->in.info->info25.info.fields_present == 0)
3416 return NT_STATUS_INVALID_PARAMETER;
3418 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3419 IFSET(SAMR_FIELD_LAST_LOGON)
3420 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3421 IFSET(SAMR_FIELD_LAST_LOGOFF)
3422 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3423 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3424 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3425 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3426 SET_STRING(msg, info25.info.account_name, "samAccountName");
3427 IFSET(SAMR_FIELD_FULL_NAME)
3428 SET_STRING(msg, info25.info.full_name, "displayName");
3429 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3430 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3431 IFSET(SAMR_FIELD_HOME_DRIVE)
3432 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3433 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3434 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3435 IFSET(SAMR_FIELD_PROFILE_PATH)
3436 SET_STRING(msg, info25.info.profile_path, "profilePath");
3437 IFSET(SAMR_FIELD_DESCRIPTION)
3438 SET_STRING(msg, info25.info.description, "description");
3439 IFSET(SAMR_FIELD_WORKSTATIONS)
3440 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3441 IFSET(SAMR_FIELD_COMMENT)
3442 SET_STRING(msg, info25.info.comment, "comment");
3443 IFSET(SAMR_FIELD_PARAMETERS)
3444 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3445 IFSET(SAMR_FIELD_PRIMARY_GID)
3446 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3447 IFSET(SAMR_FIELD_ACCT_FLAGS)
3448 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3449 IFSET(SAMR_FIELD_LOGON_HOURS)
3450 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3451 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3452 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3453 IFSET(SAMR_FIELD_NUM_LOGONS)
3454 SET_UINT (msg, info25.info.logon_count, "logonCount");
3455 IFSET(SAMR_FIELD_COUNTRY_CODE)
3456 SET_UINT (msg, info25.info.country_code, "countryCode");
3457 IFSET(SAMR_FIELD_CODE_PAGE)
3458 SET_UINT (msg, info25.info.code_page, "codePage");
3460 /* password change fields */
3461 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3462 return NT_STATUS_ACCESS_DENIED;
3464 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3465 status = samr_set_password_ex(dce_call,
3466 a_state->sam_ctx,
3467 a_state->account_dn,
3468 a_state->domain_state->domain_dn,
3469 mem_ctx,
3470 &r->in.info->info25.password);
3471 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3472 status = samr_set_password_ex(dce_call,
3473 a_state->sam_ctx,
3474 a_state->account_dn,
3475 a_state->domain_state->domain_dn,
3476 mem_ctx,
3477 &r->in.info->info25.password);
3479 if (!NT_STATUS_IS_OK(status)) {
3480 return status;
3483 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3484 NTTIME t = 0;
3485 struct ldb_message_element *set_el;
3486 if (r->in.info->info25.info.password_expired
3487 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3488 unix_to_nt_time(&t, time(NULL));
3490 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3491 "pwdLastSet", t) != LDB_SUCCESS) {
3492 return NT_STATUS_NO_MEMORY;
3494 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3495 set_el->flags = LDB_FLAG_MOD_REPLACE;
3497 #undef IFSET
3498 break;
3500 /* the set password levels are handled separately */
3501 case 26:
3502 status = samr_set_password_ex(dce_call,
3503 a_state->sam_ctx,
3504 a_state->account_dn,
3505 a_state->domain_state->domain_dn,
3506 mem_ctx,
3507 &r->in.info->info26.password);
3508 if (!NT_STATUS_IS_OK(status)) {
3509 return status;
3512 if (r->in.info->info26.password_expired > 0) {
3513 struct ldb_message_element *set_el;
3514 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3515 return NT_STATUS_NO_MEMORY;
3517 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3518 set_el->flags = LDB_FLAG_MOD_REPLACE;
3520 break;
3522 default:
3523 /* many info classes are not valid for SetUserInfo */
3524 return NT_STATUS_INVALID_INFO_CLASS;
3527 if (!NT_STATUS_IS_OK(status)) {
3528 return status;
3531 /* modify the samdb record */
3532 if (msg->num_elements > 0) {
3533 ret = ldb_modify(a_state->sam_ctx, msg);
3534 if (ret != LDB_SUCCESS) {
3535 DEBUG(1,("Failed to modify record %s: %s\n",
3536 ldb_dn_get_linearized(a_state->account_dn),
3537 ldb_errstring(a_state->sam_ctx)));
3539 return dsdb_ldb_err_to_ntstatus(ret);
3543 return NT_STATUS_OK;
3548 samr_GetGroupsForUser
3550 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3551 struct samr_GetGroupsForUser *r)
3553 struct dcesrv_handle *h;
3554 struct samr_account_state *a_state;
3555 struct samr_domain_state *d_state;
3556 struct ldb_message **res;
3557 const char * const attrs[2] = { "objectSid", NULL };
3558 struct samr_RidWithAttributeArray *array;
3559 int i, count;
3561 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3563 a_state = h->data;
3564 d_state = a_state->domain_state;
3566 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3567 d_state->domain_dn, &res,
3568 attrs, d_state->domain_sid,
3569 "(&(member=%s)(|(grouptype=%d)(grouptype=%d))(objectclass=group))",
3570 ldb_dn_get_linearized(a_state->account_dn),
3571 GTYPE_SECURITY_UNIVERSAL_GROUP,
3572 GTYPE_SECURITY_GLOBAL_GROUP);
3573 if (count < 0)
3574 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3576 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3577 if (array == NULL)
3578 return NT_STATUS_NO_MEMORY;
3580 array->count = 0;
3581 array->rids = NULL;
3583 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3584 count + 1);
3585 if (array->rids == NULL)
3586 return NT_STATUS_NO_MEMORY;
3588 /* Adds the primary group */
3589 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3590 ~0, a_state->account_dn,
3591 "primaryGroupID", NULL);
3592 array->rids[0].attributes = SE_GROUP_MANDATORY
3593 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3594 array->count += 1;
3596 /* Adds the additional groups */
3597 for (i = 0; i < count; i++) {
3598 struct dom_sid *group_sid;
3600 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3601 if (group_sid == NULL) {
3602 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3605 array->rids[i + 1].rid =
3606 group_sid->sub_auths[group_sid->num_auths-1];
3607 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3608 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3609 array->count += 1;
3612 *r->out.rids = array;
3614 return NT_STATUS_OK;
3619 samr_QueryDisplayInfo
3621 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3622 struct samr_QueryDisplayInfo *r)
3624 struct dcesrv_handle *h;
3625 struct samr_domain_state *d_state;
3626 struct ldb_result *res;
3627 unsigned int i;
3628 uint32_t count;
3629 const char * const attrs[] = { "objectSid", "sAMAccountName",
3630 "displayName", "description", "userAccountControl",
3631 "pwdLastSet", NULL };
3632 struct samr_DispEntryFull *entriesFull = NULL;
3633 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3634 struct samr_DispEntryAscii *entriesAscii = NULL;
3635 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3636 const char *filter;
3637 int ret;
3639 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3641 d_state = h->data;
3643 switch (r->in.level) {
3644 case 1:
3645 case 4:
3646 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3647 "(sAMAccountType=%d))",
3648 ATYPE_NORMAL_ACCOUNT);
3649 break;
3650 case 2:
3651 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3652 "(sAMAccountType=%d))",
3653 ATYPE_WORKSTATION_TRUST);
3654 break;
3655 case 3:
3656 case 5:
3657 filter = talloc_asprintf(mem_ctx,
3658 "(&(|(groupType=%d)(groupType=%d))"
3659 "(objectClass=group))",
3660 GTYPE_SECURITY_UNIVERSAL_GROUP,
3661 GTYPE_SECURITY_GLOBAL_GROUP);
3662 break;
3663 default:
3664 return NT_STATUS_INVALID_INFO_CLASS;
3667 /* search for all requested objects in all domains. This could
3668 possibly be cached and resumed based on resume_key */
3669 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, ldb_get_default_basedn(d_state->sam_ctx),
3670 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3671 if (ret != LDB_SUCCESS) {
3672 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3674 if ((res->count == 0) || (r->in.max_entries == 0)) {
3675 return NT_STATUS_OK;
3678 switch (r->in.level) {
3679 case 1:
3680 entriesGeneral = talloc_array(mem_ctx,
3681 struct samr_DispEntryGeneral,
3682 res->count);
3683 break;
3684 case 2:
3685 entriesFull = talloc_array(mem_ctx,
3686 struct samr_DispEntryFull,
3687 res->count);
3688 break;
3689 case 3:
3690 entriesFullGroup = talloc_array(mem_ctx,
3691 struct samr_DispEntryFullGroup,
3692 res->count);
3693 break;
3694 case 4:
3695 case 5:
3696 entriesAscii = talloc_array(mem_ctx,
3697 struct samr_DispEntryAscii,
3698 res->count);
3699 break;
3702 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3703 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3704 return NT_STATUS_NO_MEMORY;
3706 count = 0;
3708 for (i = 0; i < res->count; i++) {
3709 struct dom_sid *objectsid;
3711 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3712 "objectSid");
3713 if (objectsid == NULL)
3714 continue;
3716 switch(r->in.level) {
3717 case 1:
3718 entriesGeneral[count].idx = count + 1;
3719 entriesGeneral[count].rid =
3720 objectsid->sub_auths[objectsid->num_auths-1];
3721 entriesGeneral[count].acct_flags =
3722 samdb_result_acct_flags(d_state->sam_ctx,
3723 mem_ctx,
3724 res->msgs[i],
3725 d_state->domain_dn);
3726 entriesGeneral[count].account_name.string =
3727 ldb_msg_find_attr_as_string(res->msgs[i],
3728 "sAMAccountName", "");
3729 entriesGeneral[count].full_name.string =
3730 ldb_msg_find_attr_as_string(res->msgs[i],
3731 "displayName", "");
3732 entriesGeneral[count].description.string =
3733 ldb_msg_find_attr_as_string(res->msgs[i],
3734 "description", "");
3735 break;
3736 case 2:
3737 entriesFull[count].idx = count + 1;
3738 entriesFull[count].rid =
3739 objectsid->sub_auths[objectsid->num_auths-1];
3741 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3742 entriesFull[count].acct_flags =
3743 samdb_result_acct_flags(d_state->sam_ctx,
3744 mem_ctx,
3745 res->msgs[i],
3746 d_state->domain_dn) | ACB_NORMAL;
3747 entriesFull[count].account_name.string =
3748 ldb_msg_find_attr_as_string(res->msgs[i],
3749 "sAMAccountName", "");
3750 entriesFull[count].description.string =
3751 ldb_msg_find_attr_as_string(res->msgs[i],
3752 "description", "");
3753 break;
3754 case 3:
3755 entriesFullGroup[count].idx = count + 1;
3756 entriesFullGroup[count].rid =
3757 objectsid->sub_auths[objectsid->num_auths-1];
3758 /* We get a "7" here for groups */
3759 entriesFullGroup[count].acct_flags
3760 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3761 entriesFullGroup[count].account_name.string =
3762 ldb_msg_find_attr_as_string(res->msgs[i],
3763 "sAMAccountName", "");
3764 entriesFullGroup[count].description.string =
3765 ldb_msg_find_attr_as_string(res->msgs[i],
3766 "description", "");
3767 break;
3768 case 4:
3769 case 5:
3770 entriesAscii[count].idx = count + 1;
3771 entriesAscii[count].account_name.string =
3772 ldb_msg_find_attr_as_string(res->msgs[i],
3773 "sAMAccountName", "");
3774 break;
3777 count += 1;
3780 *r->out.total_size = count;
3782 if (r->in.start_idx >= count) {
3783 *r->out.returned_size = 0;
3784 switch(r->in.level) {
3785 case 1:
3786 r->out.info->info1.count = *r->out.returned_size;
3787 r->out.info->info1.entries = NULL;
3788 break;
3789 case 2:
3790 r->out.info->info2.count = *r->out.returned_size;
3791 r->out.info->info2.entries = NULL;
3792 break;
3793 case 3:
3794 r->out.info->info3.count = *r->out.returned_size;
3795 r->out.info->info3.entries = NULL;
3796 break;
3797 case 4:
3798 r->out.info->info4.count = *r->out.returned_size;
3799 r->out.info->info4.entries = NULL;
3800 break;
3801 case 5:
3802 r->out.info->info5.count = *r->out.returned_size;
3803 r->out.info->info5.entries = NULL;
3804 break;
3806 } else {
3807 *r->out.returned_size = MIN(count - r->in.start_idx,
3808 r->in.max_entries);
3809 switch(r->in.level) {
3810 case 1:
3811 r->out.info->info1.count = *r->out.returned_size;
3812 r->out.info->info1.entries =
3813 &(entriesGeneral[r->in.start_idx]);
3814 break;
3815 case 2:
3816 r->out.info->info2.count = *r->out.returned_size;
3817 r->out.info->info2.entries =
3818 &(entriesFull[r->in.start_idx]);
3819 break;
3820 case 3:
3821 r->out.info->info3.count = *r->out.returned_size;
3822 r->out.info->info3.entries =
3823 &(entriesFullGroup[r->in.start_idx]);
3824 break;
3825 case 4:
3826 r->out.info->info4.count = *r->out.returned_size;
3827 r->out.info->info4.entries =
3828 &(entriesAscii[r->in.start_idx]);
3829 break;
3830 case 5:
3831 r->out.info->info5.count = *r->out.returned_size;
3832 r->out.info->info5.entries =
3833 &(entriesAscii[r->in.start_idx]);
3834 break;
3838 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3839 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3844 samr_GetDisplayEnumerationIndex
3846 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3847 struct samr_GetDisplayEnumerationIndex *r)
3849 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3854 samr_TestPrivateFunctionsDomain
3856 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3857 struct samr_TestPrivateFunctionsDomain *r)
3859 return NT_STATUS_NOT_IMPLEMENTED;
3864 samr_TestPrivateFunctionsUser
3866 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3867 struct samr_TestPrivateFunctionsUser *r)
3869 return NT_STATUS_NOT_IMPLEMENTED;
3874 samr_GetUserPwInfo
3876 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3877 struct samr_GetUserPwInfo *r)
3879 struct dcesrv_handle *h;
3880 struct samr_account_state *a_state;
3882 ZERO_STRUCTP(r->out.info);
3884 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3886 a_state = h->data;
3888 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3889 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3890 NULL);
3891 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3892 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3894 return NT_STATUS_OK;
3899 samr_RemoveMemberFromForeignDomain
3901 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3902 TALLOC_CTX *mem_ctx,
3903 struct samr_RemoveMemberFromForeignDomain *r)
3905 struct dcesrv_handle *h;
3906 struct samr_domain_state *d_state;
3907 const char *memberdn;
3908 struct ldb_message **res;
3909 const char *no_attrs[] = { NULL };
3910 int i, count;
3912 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3914 d_state = h->data;
3916 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3917 "distinguishedName", "(objectSid=%s)",
3918 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3919 /* Nothing to do */
3920 if (memberdn == NULL) {
3921 return NT_STATUS_OK;
3924 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3925 d_state->domain_dn, &res, no_attrs,
3926 d_state->domain_sid,
3927 "(&(member=%s)(objectClass=group)"
3928 "(|(groupType=%d)(groupType=%d)))",
3929 memberdn,
3930 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3931 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3933 if (count < 0)
3934 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3936 for (i=0; i<count; i++) {
3937 struct ldb_message *mod;
3938 int ret;
3940 mod = ldb_msg_new(mem_ctx);
3941 if (mod == NULL) {
3942 return NT_STATUS_NO_MEMORY;
3945 mod->dn = res[i]->dn;
3947 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3948 "member", memberdn) != LDB_SUCCESS)
3949 return NT_STATUS_NO_MEMORY;
3951 ret = ldb_modify(d_state->sam_ctx, mod);
3952 talloc_free(mod);
3953 if (ret != LDB_SUCCESS) {
3954 return dsdb_ldb_err_to_ntstatus(ret);
3958 return NT_STATUS_OK;
3963 samr_QueryDomainInfo2
3965 just an alias for samr_QueryDomainInfo
3967 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3968 struct samr_QueryDomainInfo2 *r)
3970 struct samr_QueryDomainInfo r1;
3971 NTSTATUS status;
3973 ZERO_STRUCT(r1.out);
3974 r1.in.domain_handle = r->in.domain_handle;
3975 r1.in.level = r->in.level;
3976 r1.out.info = r->out.info;
3978 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3980 return status;
3985 samr_QueryUserInfo2
3987 just an alias for samr_QueryUserInfo
3989 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3990 struct samr_QueryUserInfo2 *r)
3992 struct samr_QueryUserInfo r1;
3993 NTSTATUS status;
3995 r1.in.user_handle = r->in.user_handle;
3996 r1.in.level = r->in.level;
3997 r1.out.info = r->out.info;
3999 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4001 return status;
4006 samr_QueryDisplayInfo2
4008 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4009 struct samr_QueryDisplayInfo2 *r)
4011 struct samr_QueryDisplayInfo q;
4012 NTSTATUS result;
4014 q.in.domain_handle = r->in.domain_handle;
4015 q.in.level = r->in.level;
4016 q.in.start_idx = r->in.start_idx;
4017 q.in.max_entries = r->in.max_entries;
4018 q.in.buf_size = r->in.buf_size;
4019 q.out.total_size = r->out.total_size;
4020 q.out.returned_size = r->out.returned_size;
4021 q.out.info = r->out.info;
4023 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4025 return result;
4030 samr_GetDisplayEnumerationIndex2
4032 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4033 struct samr_GetDisplayEnumerationIndex2 *r)
4035 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4040 samr_QueryDisplayInfo3
4042 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4043 struct samr_QueryDisplayInfo3 *r)
4045 struct samr_QueryDisplayInfo q;
4046 NTSTATUS result;
4048 q.in.domain_handle = r->in.domain_handle;
4049 q.in.level = r->in.level;
4050 q.in.start_idx = r->in.start_idx;
4051 q.in.max_entries = r->in.max_entries;
4052 q.in.buf_size = r->in.buf_size;
4053 q.out.total_size = r->out.total_size;
4054 q.out.returned_size = r->out.returned_size;
4055 q.out.info = r->out.info;
4057 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4059 return result;
4064 samr_AddMultipleMembersToAlias
4066 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4067 struct samr_AddMultipleMembersToAlias *r)
4069 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4074 samr_RemoveMultipleMembersFromAlias
4076 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4077 struct samr_RemoveMultipleMembersFromAlias *r)
4079 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4084 samr_GetDomPwInfo
4086 this fetches the default password properties for a domain
4088 note that w2k3 completely ignores the domain name in this call, and
4089 always returns the information for the servers primary domain
4091 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4092 struct samr_GetDomPwInfo *r)
4094 struct ldb_message **msgs;
4095 int ret;
4096 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4097 struct ldb_context *sam_ctx;
4099 ZERO_STRUCTP(r->out.info);
4101 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4102 dce_call->conn->dce_ctx->lp_ctx,
4103 dce_call->conn->auth_state.session_info, 0);
4104 if (sam_ctx == NULL) {
4105 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4108 /* The domain name in this call is ignored */
4109 ret = gendb_search_dn(sam_ctx,
4110 mem_ctx, NULL, &msgs, attrs);
4111 if (ret <= 0) {
4112 talloc_free(sam_ctx);
4114 return NT_STATUS_NO_SUCH_DOMAIN;
4116 if (ret > 1) {
4117 talloc_free(msgs);
4118 talloc_free(sam_ctx);
4120 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4123 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4124 "minPwdLength", 0);
4125 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4126 "pwdProperties", 1);
4128 talloc_free(msgs);
4129 talloc_unlink(mem_ctx, sam_ctx);
4131 return NT_STATUS_OK;
4136 samr_Connect2
4138 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4139 struct samr_Connect2 *r)
4141 struct samr_Connect c;
4143 c.in.system_name = NULL;
4144 c.in.access_mask = r->in.access_mask;
4145 c.out.connect_handle = r->out.connect_handle;
4147 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4152 samr_SetUserInfo2
4154 just an alias for samr_SetUserInfo
4156 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4157 struct samr_SetUserInfo2 *r)
4159 struct samr_SetUserInfo r2;
4161 r2.in.user_handle = r->in.user_handle;
4162 r2.in.level = r->in.level;
4163 r2.in.info = r->in.info;
4165 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4170 samr_SetBootKeyInformation
4172 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4173 struct samr_SetBootKeyInformation *r)
4175 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4180 samr_GetBootKeyInformation
4182 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4183 struct samr_GetBootKeyInformation *r)
4185 /* Windows Server 2008 returns this */
4186 return NT_STATUS_NOT_SUPPORTED;
4191 samr_Connect3
4193 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4194 struct samr_Connect3 *r)
4196 struct samr_Connect c;
4198 c.in.system_name = NULL;
4199 c.in.access_mask = r->in.access_mask;
4200 c.out.connect_handle = r->out.connect_handle;
4202 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4207 samr_Connect4
4209 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4210 struct samr_Connect4 *r)
4212 struct samr_Connect c;
4214 c.in.system_name = NULL;
4215 c.in.access_mask = r->in.access_mask;
4216 c.out.connect_handle = r->out.connect_handle;
4218 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4223 samr_Connect5
4225 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4226 struct samr_Connect5 *r)
4228 struct samr_Connect c;
4229 NTSTATUS status;
4231 c.in.system_name = NULL;
4232 c.in.access_mask = r->in.access_mask;
4233 c.out.connect_handle = r->out.connect_handle;
4235 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4237 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4238 r->out.info_out->info1.unknown2 = 0;
4239 *r->out.level_out = r->in.level_in;
4241 return status;
4246 samr_RidToSid
4248 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4249 struct samr_RidToSid *r)
4251 struct samr_domain_state *d_state;
4252 struct dcesrv_handle *h;
4254 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4256 d_state = h->data;
4258 /* form the users SID */
4259 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4260 if (!*r->out.sid) {
4261 return NT_STATUS_NO_MEMORY;
4264 return NT_STATUS_OK;
4269 samr_SetDsrmPassword
4271 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4272 struct samr_SetDsrmPassword *r)
4274 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4279 samr_ValidatePassword
4281 For now the call checks the password complexity (if active) and the minimum
4282 password length on level 2 and 3. Level 1 is ignored for now.
4284 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4285 TALLOC_CTX *mem_ctx,
4286 struct samr_ValidatePassword *r)
4288 struct samr_GetDomPwInfo r2;
4289 struct samr_PwInfo pwInfo;
4290 DATA_BLOB password;
4291 enum samr_ValidationStatus res;
4292 NTSTATUS status;
4293 enum dcerpc_transport_t transport = dce_call->conn->endpoint->ep_description->transport;
4295 if (transport != NCACN_IP_TCP && transport != NCALRPC) {
4296 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4299 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4301 r2.in.domain_name = NULL;
4302 r2.out.info = &pwInfo;
4303 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4304 if (!NT_STATUS_IS_OK(status)) {
4305 return status;
4308 switch (r->in.level) {
4309 case NetValidateAuthentication:
4310 /* we don't support this yet */
4311 return NT_STATUS_NOT_SUPPORTED;
4312 break;
4313 case NetValidatePasswordChange:
4314 password = data_blob_const(r->in.req->req2.password.string,
4315 r->in.req->req2.password.length);
4316 res = samdb_check_password(&password,
4317 pwInfo.password_properties,
4318 pwInfo.min_password_length);
4319 (*r->out.rep)->ctr2.status = res;
4320 break;
4321 case NetValidatePasswordReset:
4322 password = data_blob_const(r->in.req->req3.password.string,
4323 r->in.req->req3.password.length);
4324 res = samdb_check_password(&password,
4325 pwInfo.password_properties,
4326 pwInfo.min_password_length);
4327 (*r->out.rep)->ctr3.status = res;
4328 break;
4329 default:
4330 return NT_STATUS_INVALID_INFO_CLASS;
4331 break;
4334 return NT_STATUS_OK;
4338 /* include the generated boilerplate */
4339 #include "librpc/gen_ndr/ndr_samr_s.c"