s4:rpc_server/dcesrv_samr.c - quiet enum warnings
[Samba/gebeck_regimport.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob32aafcd23faa88660c275396b7f69117cb92ee62
1 /*
2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include <ldb.h>
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
44 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
46 #define QUERY_STRING(msg, field, attr) \
47 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
48 #define QUERY_UINT(msg, field, attr) \
49 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
50 #define QUERY_RID(msg, field, attr) \
51 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
52 #define QUERY_UINT64(msg, field, attr) \
53 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
54 #define QUERY_APASSC(msg, field, attr) \
55 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
56 a_state->domain_state->domain_dn, msg, attr);
57 #define QUERY_FPASSC(msg, field, attr) \
58 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
59 a_state->domain_state->domain_dn, msg);
60 #define QUERY_LHOURS(msg, field, attr) \
61 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
62 #define QUERY_AFLAGS(msg, field, attr) \
63 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
64 #define QUERY_PARAMETERS(msg, field, attr) \
65 info->field = samdb_result_parameters(mem_ctx, msg, attr);
68 /* these are used to make the Set[User|Group]Info code easier to follow */
70 #define SET_STRING(msg, field, attr) do { \
71 struct ldb_message_element *set_el; \
72 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
73 if (r->in.info->field.string[0] == '\0') { \
74 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
75 return NT_STATUS_NO_MEMORY; \
76 } \
77 } \
78 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
79 return NT_STATUS_NO_MEMORY; \
80 } \
81 set_el = ldb_msg_find_element(msg, attr); \
82 set_el->flags = LDB_FLAG_MOD_REPLACE; \
83 } while (0)
85 #define SET_UINT(msg, field, attr) do { \
86 struct ldb_message_element *set_el; \
87 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
88 return NT_STATUS_NO_MEMORY; \
89 } \
90 set_el = ldb_msg_find_element(msg, attr); \
91 set_el->flags = LDB_FLAG_MOD_REPLACE; \
92 } while (0)
94 #define SET_INT64(msg, field, attr) do { \
95 struct ldb_message_element *set_el; \
96 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
97 return NT_STATUS_NO_MEMORY; \
98 } \
99 set_el = ldb_msg_find_element(msg, attr); \
100 set_el->flags = LDB_FLAG_MOD_REPLACE; \
101 } while (0)
103 #define SET_UINT64(msg, field, attr) do { \
104 struct ldb_message_element *set_el; \
105 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
106 return NT_STATUS_NO_MEMORY; \
108 set_el = ldb_msg_find_element(msg, attr); \
109 set_el->flags = LDB_FLAG_MOD_REPLACE; \
110 } while (0)
112 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
113 do { \
114 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
115 return NT_STATUS_INVALID_PARAMETER; \
117 } while (0) \
119 /* Set account flags, discarding flags that cannot be set with SAMR */
120 #define SET_AFLAGS(msg, field, attr) do { \
121 struct ldb_message_element *set_el; \
122 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
123 return NT_STATUS_INVALID_PARAMETER; \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
128 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
129 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
130 return NT_STATUS_NO_MEMORY; \
132 set_el = ldb_msg_find_element(msg, attr); \
133 set_el->flags = LDB_FLAG_MOD_REPLACE; \
134 } while (0)
136 #define SET_LHOURS(msg, field, attr) do { \
137 struct ldb_message_element *set_el; \
138 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
139 return NT_STATUS_NO_MEMORY; \
141 set_el = ldb_msg_find_element(msg, attr); \
142 set_el->flags = LDB_FLAG_MOD_REPLACE; \
143 } while (0)
145 #define SET_PARAMETERS(msg, field, attr) do { \
146 struct ldb_message_element *set_el; \
147 if (r->in.info->field.length != 0) { \
148 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
149 return NT_STATUS_NO_MEMORY; \
151 set_el = ldb_msg_find_element(msg, attr); \
152 set_el->flags = LDB_FLAG_MOD_REPLACE; \
154 } while (0)
159 samr_Connect
161 create a connection to the SAM database
163 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
164 struct samr_Connect *r)
166 struct samr_connect_state *c_state;
167 struct dcesrv_handle *handle;
169 ZERO_STRUCTP(r->out.connect_handle);
171 c_state = talloc(mem_ctx, struct samr_connect_state);
172 if (!c_state) {
173 return NT_STATUS_NO_MEMORY;
176 /* make sure the sam database is accessible */
177 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0);
178 if (c_state->sam_ctx == NULL) {
179 talloc_free(c_state);
180 return NT_STATUS_INVALID_SYSTEM_SERVICE;
184 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
185 if (!handle) {
186 talloc_free(c_state);
187 return NT_STATUS_NO_MEMORY;
190 handle->data = talloc_steal(handle, c_state);
192 c_state->access_mask = r->in.access_mask;
193 *r->out.connect_handle = handle->wire_handle;
195 return NT_STATUS_OK;
200 samr_Close
202 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
203 struct samr_Close *r)
205 struct dcesrv_handle *h;
207 *r->out.handle = *r->in.handle;
209 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
211 talloc_free(h);
213 ZERO_STRUCTP(r->out.handle);
215 return NT_STATUS_OK;
220 samr_SetSecurity
222 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
223 struct samr_SetSecurity *r)
225 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
230 samr_QuerySecurity
232 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
233 struct samr_QuerySecurity *r)
235 struct dcesrv_handle *h;
236 struct sec_desc_buf *sd;
238 *r->out.sdbuf = NULL;
240 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
242 sd = talloc(mem_ctx, struct sec_desc_buf);
243 if (sd == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 sd->sd = samdb_default_security_descriptor(mem_ctx);
249 *r->out.sdbuf = sd;
251 return NT_STATUS_OK;
256 samr_Shutdown
258 we refuse this operation completely. If a admin wants to shutdown samr
259 in Samba then they should use the samba admin tools to disable the samr pipe
261 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
262 struct samr_Shutdown *r)
264 return NT_STATUS_ACCESS_DENIED;
269 samr_LookupDomain
271 this maps from a domain name to a SID
273 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
274 struct samr_LookupDomain *r)
276 struct samr_connect_state *c_state;
277 struct dcesrv_handle *h;
278 struct dom_sid *sid;
279 const char * const dom_attrs[] = { "objectSid", NULL};
280 struct ldb_message **dom_msgs;
281 int ret;
283 *r->out.sid = NULL;
285 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
287 c_state = h->data;
289 if (r->in.domain_name->string == NULL) {
290 return NT_STATUS_INVALID_PARAMETER;
293 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
294 ret = gendb_search(c_state->sam_ctx,
295 mem_ctx, NULL, &dom_msgs, dom_attrs,
296 "(objectClass=builtinDomain)");
297 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
298 ret = gendb_search_dn(c_state->sam_ctx,
299 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
300 &dom_msgs, dom_attrs);
301 } else {
302 return NT_STATUS_NO_SUCH_DOMAIN;
304 if (ret != 1) {
305 return NT_STATUS_NO_SUCH_DOMAIN;
308 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
309 "objectSid");
311 if (sid == NULL) {
312 return NT_STATUS_NO_SUCH_DOMAIN;
315 *r->out.sid = sid;
317 return NT_STATUS_OK;
322 samr_EnumDomains
324 list the domains in the SAM
326 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
327 struct samr_EnumDomains *r)
329 struct samr_connect_state *c_state;
330 struct dcesrv_handle *h;
331 struct samr_SamArray *array;
332 uint32_t i, start_i;
334 *r->out.resume_handle = 0;
335 *r->out.sam = NULL;
336 *r->out.num_entries = 0;
338 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
340 c_state = h->data;
342 *r->out.resume_handle = 2;
344 start_i = *r->in.resume_handle;
346 if (start_i >= 2) {
347 /* search past end of list is not an error for this call */
348 return NT_STATUS_OK;
351 array = talloc(mem_ctx, struct samr_SamArray);
352 if (array == NULL) {
353 return NT_STATUS_NO_MEMORY;
356 array->count = 0;
357 array->entries = NULL;
359 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
360 if (array->entries == NULL) {
361 return NT_STATUS_NO_MEMORY;
364 for (i=0;i<2-start_i;i++) {
365 array->entries[i].idx = start_i + i;
366 if (i == 0) {
367 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
368 } else {
369 array->entries[i].name.string = "BUILTIN";
373 *r->out.sam = array;
374 *r->out.num_entries = i;
375 array->count = *r->out.num_entries;
377 return NT_STATUS_OK;
382 samr_OpenDomain
384 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
385 struct samr_OpenDomain *r)
387 struct dcesrv_handle *h_conn, *h_domain;
388 struct samr_connect_state *c_state;
389 struct samr_domain_state *d_state;
390 const char * const dom_attrs[] = { "cn", NULL};
391 struct ldb_message **dom_msgs;
392 int ret;
394 ZERO_STRUCTP(r->out.domain_handle);
396 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
398 c_state = h_conn->data;
400 if (r->in.sid == NULL) {
401 return NT_STATUS_INVALID_PARAMETER;
404 d_state = talloc(mem_ctx, struct samr_domain_state);
405 if (!d_state) {
406 return NT_STATUS_NO_MEMORY;
409 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
411 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
412 d_state->builtin = true;
413 d_state->domain_name = "BUILTIN";
414 } else {
415 d_state->builtin = false;
416 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
419 ret = gendb_search(c_state->sam_ctx,
420 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
421 "(objectSid=%s)",
422 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
424 if (ret == 0) {
425 talloc_free(d_state);
426 return NT_STATUS_NO_SUCH_DOMAIN;
427 } else if (ret > 1) {
428 talloc_free(d_state);
429 return NT_STATUS_INTERNAL_DB_CORRUPTION;
430 } else if (ret == -1) {
431 talloc_free(d_state);
432 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
433 return NT_STATUS_INTERNAL_DB_CORRUPTION;
436 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
437 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
438 d_state->connect_state = talloc_reference(d_state, c_state);
439 d_state->sam_ctx = c_state->sam_ctx;
440 d_state->access_mask = r->in.access_mask;
442 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
444 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
445 if (!h_domain) {
446 talloc_free(d_state);
447 return NT_STATUS_NO_MEMORY;
450 h_domain->data = talloc_steal(h_domain, d_state);
452 *r->out.domain_handle = h_domain->wire_handle;
454 return NT_STATUS_OK;
458 return DomInfo1
460 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
461 TALLOC_CTX *mem_ctx,
462 struct ldb_message **dom_msgs,
463 struct samr_DomInfo1 *info)
465 info->min_password_length =
466 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
467 info->password_history_length =
468 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
469 info->password_properties =
470 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
471 info->max_password_age =
472 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
473 info->min_password_age =
474 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
476 return NT_STATUS_OK;
480 return DomInfo2
482 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
483 TALLOC_CTX *mem_ctx,
484 struct ldb_message **dom_msgs,
485 struct samr_DomGeneralInformation *info)
487 /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
488 info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
489 "domainReplica",
490 "");
492 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
493 0x8000000000000000LL);
495 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
496 "oEMInformation",
497 "");
498 info->domain_name.string = state->domain_name;
500 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
502 switch (state->role) {
503 case ROLE_DOMAIN_CONTROLLER:
504 /* This pulls the NetBIOS name from the
505 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
506 string */
507 if (samdb_is_pdc(state->sam_ctx)) {
508 info->role = SAMR_ROLE_DOMAIN_PDC;
509 } else {
510 info->role = SAMR_ROLE_DOMAIN_BDC;
512 break;
513 case ROLE_DOMAIN_PDC:
514 info->role = SAMR_ROLE_DOMAIN_PDC;
515 break;
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_DOMAIN_CONTROLLER:
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, &sid, &dn);
1209 if (!NT_STATUS_IS_OK(status)) {
1210 return status;
1212 a_state = talloc(mem_ctx, struct samr_account_state);
1213 if (!a_state) {
1214 return NT_STATUS_NO_MEMORY;
1216 a_state->sam_ctx = d_state->sam_ctx;
1217 a_state->access_mask = r->in.access_mask;
1218 a_state->domain_state = talloc_reference(a_state, d_state);
1219 a_state->account_dn = talloc_steal(a_state, dn);
1221 a_state->account_name = talloc_steal(a_state, account_name);
1222 if (!a_state->account_name) {
1223 return NT_STATUS_NO_MEMORY;
1226 /* create the policy handle */
1227 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1228 if (!u_handle) {
1229 return NT_STATUS_NO_MEMORY;
1232 u_handle->data = talloc_steal(u_handle, a_state);
1234 *r->out.user_handle = u_handle->wire_handle;
1235 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1237 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1239 return NT_STATUS_OK;
1244 samr_CreateUser
1246 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1247 struct samr_CreateUser *r)
1249 struct samr_CreateUser2 r2;
1250 uint32_t access_granted = 0;
1253 /* a simple wrapper around samr_CreateUser2 works nicely */
1254 r2.in.domain_handle = r->in.domain_handle;
1255 r2.in.account_name = r->in.account_name;
1256 r2.in.acct_flags = ACB_NORMAL;
1257 r2.in.access_mask = r->in.access_mask;
1258 r2.out.user_handle = r->out.user_handle;
1259 r2.out.access_granted = &access_granted;
1260 r2.out.rid = r->out.rid;
1262 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1266 samr_EnumDomainUsers
1268 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1269 struct samr_EnumDomainUsers *r)
1271 struct dcesrv_handle *h;
1272 struct samr_domain_state *d_state;
1273 struct ldb_message **res;
1274 int i, ldb_cnt;
1275 uint32_t first, count;
1276 struct samr_SamEntry *entries;
1277 const char * const attrs[] = { "objectSid", "sAMAccountName",
1278 "userAccountControl", NULL };
1279 struct samr_SamArray *sam;
1281 *r->out.resume_handle = 0;
1282 *r->out.sam = NULL;
1283 *r->out.num_entries = 0;
1285 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1287 d_state = h->data;
1289 /* search for all domain users in this domain. This could possibly be
1290 cached and resumed on resume_key */
1291 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1292 d_state->domain_dn,
1293 &res, attrs,
1294 d_state->domain_sid,
1295 "(objectClass=user)");
1296 if (ldb_cnt < 0) {
1297 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1300 /* convert to SamEntry format */
1301 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1302 if (!entries) {
1303 return NT_STATUS_NO_MEMORY;
1306 count = 0;
1308 for (i=0;i<ldb_cnt;i++) {
1309 /* Check if a mask has been requested */
1310 if (r->in.acct_flags
1311 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
1312 res[i], d_state->domain_dn) & r->in.acct_flags) == 0)) {
1313 continue;
1315 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1316 "objectSid", 0);
1317 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1318 "sAMAccountName", "");
1319 count += 1;
1322 /* sort the results by rid */
1323 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1325 /* find the first entry to return */
1326 for (first=0;
1327 first<count && entries[first].idx <= *r->in.resume_handle;
1328 first++) ;
1330 /* return the rest, limit by max_size. Note that we
1331 use the w2k3 element size value of 54 */
1332 *r->out.num_entries = count - first;
1333 *r->out.num_entries = MIN(*r->out.num_entries,
1334 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1336 sam = talloc(mem_ctx, struct samr_SamArray);
1337 if (!sam) {
1338 return NT_STATUS_NO_MEMORY;
1341 sam->entries = entries+first;
1342 sam->count = *r->out.num_entries;
1344 *r->out.sam = sam;
1346 if (first == count) {
1347 return NT_STATUS_OK;
1350 if (*r->out.num_entries < count - first) {
1351 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1352 return STATUS_MORE_ENTRIES;
1355 return NT_STATUS_OK;
1360 samr_CreateDomAlias
1362 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1363 struct samr_CreateDomAlias *r)
1365 struct samr_domain_state *d_state;
1366 struct samr_account_state *a_state;
1367 struct dcesrv_handle *h;
1368 const char *alias_name;
1369 struct dom_sid *sid;
1370 struct dcesrv_handle *a_handle;
1371 struct ldb_dn *dn;
1372 NTSTATUS status;
1374 ZERO_STRUCTP(r->out.alias_handle);
1375 *r->out.rid = 0;
1377 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1379 d_state = h->data;
1381 if (d_state->builtin) {
1382 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1383 return NT_STATUS_ACCESS_DENIED;
1386 alias_name = r->in.alias_name->string;
1388 if (alias_name == NULL) {
1389 return NT_STATUS_INVALID_PARAMETER;
1392 status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1393 if (!NT_STATUS_IS_OK(status)) {
1394 return status;
1397 a_state = talloc(mem_ctx, struct samr_account_state);
1398 if (!a_state) {
1399 return NT_STATUS_NO_MEMORY;
1402 a_state->sam_ctx = d_state->sam_ctx;
1403 a_state->access_mask = r->in.access_mask;
1404 a_state->domain_state = talloc_reference(a_state, d_state);
1405 a_state->account_dn = talloc_steal(a_state, dn);
1407 a_state->account_name = talloc_steal(a_state, alias_name);
1409 /* create the policy handle */
1410 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1411 if (a_handle == NULL)
1412 return NT_STATUS_NO_MEMORY;
1414 a_handle->data = talloc_steal(a_handle, a_state);
1416 *r->out.alias_handle = a_handle->wire_handle;
1418 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1420 return NT_STATUS_OK;
1425 samr_EnumDomainAliases
1427 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1428 struct samr_EnumDomainAliases *r)
1430 struct dcesrv_handle *h;
1431 struct samr_domain_state *d_state;
1432 struct ldb_message **res;
1433 int i, ldb_cnt;
1434 uint32_t first, count;
1435 struct samr_SamEntry *entries;
1436 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1437 struct samr_SamArray *sam;
1439 *r->out.resume_handle = 0;
1440 *r->out.sam = NULL;
1441 *r->out.num_entries = 0;
1443 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1445 d_state = h->data;
1447 /* search for all domain aliases in this domain. This could possibly be
1448 cached and resumed based on resume_key */
1449 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1450 &res, attrs,
1451 d_state->domain_sid,
1452 "(&(|(grouptype=%d)(grouptype=%d)))"
1453 "(objectclass=group))",
1454 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1455 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1456 if (ldb_cnt < 0) {
1457 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1460 /* convert to SamEntry format */
1461 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1462 if (!entries) {
1463 return NT_STATUS_NO_MEMORY;
1466 count = 0;
1468 for (i=0;i<ldb_cnt;i++) {
1469 struct dom_sid *alias_sid;
1471 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1472 "objectSid");
1474 if (alias_sid == NULL) {
1475 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1478 entries[count].idx =
1479 alias_sid->sub_auths[alias_sid->num_auths-1];
1480 entries[count].name.string =
1481 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1482 count += 1;
1485 /* sort the results by rid */
1486 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1488 /* find the first entry to return */
1489 for (first=0;
1490 first<count && entries[first].idx <= *r->in.resume_handle;
1491 first++) ;
1493 /* return the rest, limit by max_size. Note that we
1494 use the w2k3 element size value of 54 */
1495 *r->out.num_entries = count - first;
1496 *r->out.num_entries = MIN(*r->out.num_entries,
1497 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1499 sam = talloc(mem_ctx, struct samr_SamArray);
1500 if (!sam) {
1501 return NT_STATUS_NO_MEMORY;
1504 sam->entries = entries+first;
1505 sam->count = *r->out.num_entries;
1507 *r->out.sam = sam;
1509 if (first == count) {
1510 return NT_STATUS_OK;
1513 if (*r->out.num_entries < count - first) {
1514 *r->out.resume_handle =
1515 entries[first+*r->out.num_entries-1].idx;
1516 return STATUS_MORE_ENTRIES;
1519 return NT_STATUS_OK;
1524 samr_GetAliasMembership
1526 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1527 struct samr_GetAliasMembership *r)
1529 struct dcesrv_handle *h;
1530 struct samr_domain_state *d_state;
1531 const char *filter;
1532 const char * const attrs[] = { "objectSid", NULL };
1533 struct ldb_message **res;
1534 uint32_t i;
1535 int count = 0;
1537 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1539 d_state = h->data;
1541 filter = talloc_asprintf(mem_ctx,
1542 "(&(|(grouptype=%d)(grouptype=%d))"
1543 "(objectclass=group)(|",
1544 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1545 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1546 if (filter == NULL) {
1547 return NT_STATUS_NO_MEMORY;
1550 for (i=0; i<r->in.sids->num_sids; i++) {
1551 const char *memberdn;
1553 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1554 "distinguishedName",
1555 "(objectSid=%s)",
1556 ldap_encode_ndr_dom_sid(mem_ctx,
1557 r->in.sids->sids[i].sid));
1558 if (memberdn == NULL) {
1559 continue;
1562 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1563 memberdn);
1564 if (filter == NULL) {
1565 return NT_STATUS_NO_MEMORY;
1569 /* Find out if we had at least one valid member SID passed - otherwise
1570 * just skip the search. */
1571 if (strstr(filter, "member") != NULL) {
1572 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1573 &res, attrs, d_state->domain_sid,
1574 "%s))", filter);
1575 if (count < 0) {
1576 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1580 r->out.rids->count = 0;
1581 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1582 if (r->out.rids->ids == NULL)
1583 return NT_STATUS_NO_MEMORY;
1585 for (i=0; i<count; i++) {
1586 struct dom_sid *alias_sid;
1588 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1589 if (alias_sid == NULL) {
1590 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1593 r->out.rids->ids[r->out.rids->count] =
1594 alias_sid->sub_auths[alias_sid->num_auths-1];
1595 r->out.rids->count += 1;
1598 return NT_STATUS_OK;
1603 samr_LookupNames
1605 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1606 struct samr_LookupNames *r)
1608 struct dcesrv_handle *h;
1609 struct samr_domain_state *d_state;
1610 uint32_t i, num_mapped;
1611 NTSTATUS status = NT_STATUS_OK;
1612 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1613 int count;
1615 ZERO_STRUCTP(r->out.rids);
1616 ZERO_STRUCTP(r->out.types);
1618 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1620 d_state = h->data;
1622 if (r->in.num_names == 0) {
1623 return NT_STATUS_OK;
1626 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1627 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1628 if (!r->out.rids->ids || !r->out.types->ids) {
1629 return NT_STATUS_NO_MEMORY;
1631 r->out.rids->count = r->in.num_names;
1632 r->out.types->count = r->in.num_names;
1634 num_mapped = 0;
1636 for (i=0;i<r->in.num_names;i++) {
1637 struct ldb_message **res;
1638 struct dom_sid *sid;
1639 uint32_t atype, rtype;
1641 r->out.rids->ids[i] = 0;
1642 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1644 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1645 "sAMAccountName=%s",
1646 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1647 if (count != 1) {
1648 status = STATUS_SOME_UNMAPPED;
1649 continue;
1652 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1653 if (sid == NULL) {
1654 status = STATUS_SOME_UNMAPPED;
1655 continue;
1658 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1659 if (atype == 0) {
1660 status = STATUS_SOME_UNMAPPED;
1661 continue;
1664 rtype = ds_atype_map(atype);
1666 if (rtype == SID_NAME_UNKNOWN) {
1667 status = STATUS_SOME_UNMAPPED;
1668 continue;
1671 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1672 r->out.types->ids[i] = rtype;
1673 num_mapped++;
1676 if (num_mapped == 0) {
1677 return NT_STATUS_NONE_MAPPED;
1679 return status;
1684 samr_LookupRids
1686 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1687 struct samr_LookupRids *r)
1689 NTSTATUS status;
1690 struct dcesrv_handle *h;
1691 struct samr_domain_state *d_state;
1692 const char **names;
1693 struct lsa_String *lsa_names;
1694 enum lsa_SidType *ids;
1696 ZERO_STRUCTP(r->out.names);
1697 ZERO_STRUCTP(r->out.types);
1699 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1701 d_state = h->data;
1703 if (r->in.num_rids == 0)
1704 return NT_STATUS_OK;
1706 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1707 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1708 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1710 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1711 return NT_STATUS_NO_MEMORY;
1713 r->out.names->names = lsa_names;
1714 r->out.names->count = r->in.num_rids;
1716 r->out.types->ids = (uint32_t *) ids;
1717 r->out.types->count = r->in.num_rids;
1719 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1720 r->in.num_rids, r->in.rids, names, ids);
1721 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1722 uint32_t i;
1723 for (i = 0; i < r->in.num_rids; i++) {
1724 lsa_names[i].string = names[i];
1727 return status;
1732 samr_OpenGroup
1734 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1735 struct samr_OpenGroup *r)
1737 struct samr_domain_state *d_state;
1738 struct samr_account_state *a_state;
1739 struct dcesrv_handle *h;
1740 const char *groupname;
1741 struct dom_sid *sid;
1742 struct ldb_message **msgs;
1743 struct dcesrv_handle *g_handle;
1744 const char * const attrs[2] = { "sAMAccountName", NULL };
1745 int ret;
1747 ZERO_STRUCTP(r->out.group_handle);
1749 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1751 d_state = h->data;
1753 /* form the group SID */
1754 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1755 if (!sid) {
1756 return NT_STATUS_NO_MEMORY;
1759 /* search for the group record */
1760 ret = gendb_search(d_state->sam_ctx,
1761 mem_ctx, d_state->domain_dn, &msgs, attrs,
1762 "(&(objectSid=%s)(objectClass=group)"
1763 "(|(groupType=%d)(groupType=%d)))",
1764 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1765 GTYPE_SECURITY_UNIVERSAL_GROUP,
1766 GTYPE_SECURITY_GLOBAL_GROUP);
1767 if (ret == 0) {
1768 return NT_STATUS_NO_SUCH_GROUP;
1770 if (ret != 1) {
1771 DEBUG(0,("Found %d records matching sid %s\n",
1772 ret, dom_sid_string(mem_ctx, sid)));
1773 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1776 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1777 if (groupname == NULL) {
1778 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1779 dom_sid_string(mem_ctx, sid)));
1780 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1783 a_state = talloc(mem_ctx, struct samr_account_state);
1784 if (!a_state) {
1785 return NT_STATUS_NO_MEMORY;
1787 a_state->sam_ctx = d_state->sam_ctx;
1788 a_state->access_mask = r->in.access_mask;
1789 a_state->domain_state = talloc_reference(a_state, d_state);
1790 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1791 a_state->account_sid = talloc_steal(a_state, sid);
1792 a_state->account_name = talloc_strdup(a_state, groupname);
1793 if (!a_state->account_name) {
1794 return NT_STATUS_NO_MEMORY;
1797 /* create the policy handle */
1798 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1799 if (!g_handle) {
1800 return NT_STATUS_NO_MEMORY;
1803 g_handle->data = talloc_steal(g_handle, a_state);
1805 *r->out.group_handle = g_handle->wire_handle;
1807 return NT_STATUS_OK;
1811 samr_QueryGroupInfo
1813 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1814 struct samr_QueryGroupInfo *r)
1816 struct dcesrv_handle *h;
1817 struct samr_account_state *a_state;
1818 struct ldb_message *msg, **res;
1819 const char * const attrs[4] = { "sAMAccountName", "description",
1820 "numMembers", NULL };
1821 int ret;
1822 union samr_GroupInfo *info;
1824 *r->out.info = NULL;
1826 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1828 a_state = h->data;
1830 /* pull all the group attributes */
1831 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1832 a_state->account_dn, &res, attrs);
1833 if (ret == 0) {
1834 return NT_STATUS_NO_SUCH_GROUP;
1836 if (ret != 1) {
1837 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1839 msg = res[0];
1841 /* allocate the info structure */
1842 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1843 if (info == NULL) {
1844 return NT_STATUS_NO_MEMORY;
1847 /* Fill in the level */
1848 switch (r->in.level) {
1849 case GROUPINFOALL:
1850 QUERY_STRING(msg, all.name, "sAMAccountName");
1851 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1852 QUERY_UINT (msg, all.num_members, "numMembers")
1853 QUERY_STRING(msg, all.description, "description");
1854 break;
1855 case GROUPINFONAME:
1856 QUERY_STRING(msg, name, "sAMAccountName");
1857 break;
1858 case GROUPINFOATTRIBUTES:
1859 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1860 break;
1861 case GROUPINFODESCRIPTION:
1862 QUERY_STRING(msg, description, "description");
1863 break;
1864 case GROUPINFOALL2:
1865 QUERY_STRING(msg, all2.name, "sAMAccountName");
1866 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1867 QUERY_UINT (msg, all2.num_members, "numMembers")
1868 QUERY_STRING(msg, all2.description, "description");
1869 break;
1870 default:
1871 talloc_free(info);
1872 return NT_STATUS_INVALID_INFO_CLASS;
1875 *r->out.info = info;
1877 return NT_STATUS_OK;
1882 samr_SetGroupInfo
1884 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1885 struct samr_SetGroupInfo *r)
1887 struct dcesrv_handle *h;
1888 struct samr_account_state *g_state;
1889 struct ldb_message *msg;
1890 struct ldb_context *sam_ctx;
1891 int ret;
1893 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1895 g_state = h->data;
1896 sam_ctx = g_state->sam_ctx;
1898 msg = ldb_msg_new(mem_ctx);
1899 if (msg == NULL) {
1900 return NT_STATUS_NO_MEMORY;
1903 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1904 if (!msg->dn) {
1905 return NT_STATUS_NO_MEMORY;
1908 switch (r->in.level) {
1909 case GROUPINFODESCRIPTION:
1910 SET_STRING(msg, description, "description");
1911 break;
1912 case GROUPINFONAME:
1913 /* On W2k3 this does not change the name, it changes the
1914 * sAMAccountName attribute */
1915 SET_STRING(msg, name, "sAMAccountName");
1916 break;
1917 case GROUPINFOATTRIBUTES:
1918 /* This does not do anything obviously visible in W2k3 LDAP */
1919 return NT_STATUS_OK;
1920 default:
1921 return NT_STATUS_INVALID_INFO_CLASS;
1924 /* modify the samdb record */
1925 ret = ldb_modify(g_state->sam_ctx, msg);
1926 if (ret != LDB_SUCCESS) {
1927 return dsdb_ldb_err_to_ntstatus(ret);
1930 return NT_STATUS_OK;
1935 samr_AddGroupMember
1937 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1938 struct samr_AddGroupMember *r)
1940 struct dcesrv_handle *h;
1941 struct samr_account_state *a_state;
1942 struct samr_domain_state *d_state;
1943 struct ldb_message *mod;
1944 struct dom_sid *membersid;
1945 const char *memberdn;
1946 struct ldb_result *res;
1947 const char * const attrs[] = { NULL };
1948 int ret;
1950 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1952 a_state = h->data;
1953 d_state = a_state->domain_state;
1955 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1956 if (membersid == NULL) {
1957 return NT_STATUS_NO_MEMORY;
1960 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1961 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1962 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1963 "(objectSid=%s)",
1964 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1966 if (ret != LDB_SUCCESS) {
1967 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1970 if (res->count == 0) {
1971 return NT_STATUS_NO_SUCH_USER;
1974 if (res->count > 1) {
1975 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1978 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1980 if (memberdn == NULL)
1981 return NT_STATUS_NO_MEMORY;
1983 mod = ldb_msg_new(mem_ctx);
1984 if (mod == NULL) {
1985 return NT_STATUS_NO_MEMORY;
1988 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1990 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1991 memberdn);
1992 if (ret != LDB_SUCCESS) {
1993 return dsdb_ldb_err_to_ntstatus(ret);
1996 ret = ldb_modify(a_state->sam_ctx, mod);
1997 switch (ret) {
1998 case LDB_SUCCESS:
1999 return NT_STATUS_OK;
2000 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2001 return NT_STATUS_MEMBER_IN_GROUP;
2002 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2003 return NT_STATUS_ACCESS_DENIED;
2004 default:
2005 return dsdb_ldb_err_to_ntstatus(ret);
2011 samr_DeleteDomainGroup
2013 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2014 struct samr_DeleteDomainGroup *r)
2016 struct dcesrv_handle *h;
2017 struct samr_account_state *a_state;
2018 int ret;
2020 *r->out.group_handle = *r->in.group_handle;
2022 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2024 a_state = h->data;
2026 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2027 if (ret != LDB_SUCCESS) {
2028 return dsdb_ldb_err_to_ntstatus(ret);
2031 talloc_free(h);
2032 ZERO_STRUCTP(r->out.group_handle);
2034 return NT_STATUS_OK;
2039 samr_DeleteGroupMember
2041 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2042 struct samr_DeleteGroupMember *r)
2044 struct dcesrv_handle *h;
2045 struct samr_account_state *a_state;
2046 struct samr_domain_state *d_state;
2047 struct ldb_message *mod;
2048 struct dom_sid *membersid;
2049 const char *memberdn;
2050 struct ldb_result *res;
2051 const char * const attrs[] = { NULL };
2052 int ret;
2054 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2056 a_state = h->data;
2057 d_state = a_state->domain_state;
2059 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2060 if (membersid == NULL) {
2061 return NT_STATUS_NO_MEMORY;
2064 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2065 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2066 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2067 "(objectSid=%s)",
2068 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2070 if (ret != LDB_SUCCESS) {
2071 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2074 if (res->count == 0) {
2075 return NT_STATUS_NO_SUCH_USER;
2078 if (res->count > 1) {
2079 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2082 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2084 if (memberdn == NULL)
2085 return NT_STATUS_NO_MEMORY;
2087 mod = ldb_msg_new(mem_ctx);
2088 if (mod == NULL) {
2089 return NT_STATUS_NO_MEMORY;
2092 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2094 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2095 memberdn);
2096 if (ret != LDB_SUCCESS) {
2097 return NT_STATUS_NO_MEMORY;
2100 ret = ldb_modify(a_state->sam_ctx, mod);
2101 switch (ret) {
2102 case LDB_SUCCESS:
2103 return NT_STATUS_OK;
2104 case LDB_ERR_UNWILLING_TO_PERFORM:
2105 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2106 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2107 return NT_STATUS_ACCESS_DENIED;
2108 default:
2109 return dsdb_ldb_err_to_ntstatus(ret);
2115 samr_QueryGroupMember
2117 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2118 struct samr_QueryGroupMember *r)
2120 struct dcesrv_handle *h;
2121 struct samr_account_state *a_state;
2122 struct samr_domain_state *d_state;
2123 struct samr_RidAttrArray *array;
2124 unsigned int i, num_members;
2125 struct dom_sid *members;
2126 NTSTATUS status;
2128 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2130 a_state = h->data;
2131 d_state = a_state->domain_state;
2133 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2134 a_state->account_dn, &members,
2135 &num_members);
2136 if (!NT_STATUS_IS_OK(status)) {
2137 return status;
2140 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2141 if (array == NULL) {
2142 return NT_STATUS_NO_MEMORY;
2145 if (num_members == 0) {
2146 *r->out.rids = array;
2148 return NT_STATUS_OK;
2151 array->rids = talloc_array(array, uint32_t, num_members);
2152 if (array->rids == NULL) {
2153 return NT_STATUS_NO_MEMORY;
2156 array->attributes = talloc_array(array, uint32_t, num_members);
2157 if (array->attributes == NULL) {
2158 return NT_STATUS_NO_MEMORY;
2161 array->count = 0;
2162 for (i=0; i<num_members; i++) {
2163 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2164 continue;
2167 status = dom_sid_split_rid(NULL, &members[i], NULL,
2168 &array->rids[array->count]);
2169 if (!NT_STATUS_IS_OK(status)) {
2170 return status;
2173 array->attributes[array->count] = SE_GROUP_MANDATORY |
2174 SE_GROUP_ENABLED_BY_DEFAULT |
2175 SE_GROUP_ENABLED;
2176 array->count++;
2179 *r->out.rids = array;
2181 return NT_STATUS_OK;
2186 samr_SetMemberAttributesOfGroup
2188 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2189 struct samr_SetMemberAttributesOfGroup *r)
2191 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2196 samr_OpenAlias
2198 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2199 struct samr_OpenAlias *r)
2201 struct samr_domain_state *d_state;
2202 struct samr_account_state *a_state;
2203 struct dcesrv_handle *h;
2204 const char *alias_name;
2205 struct dom_sid *sid;
2206 struct ldb_message **msgs;
2207 struct dcesrv_handle *g_handle;
2208 const char * const attrs[2] = { "sAMAccountName", NULL };
2209 int ret;
2211 ZERO_STRUCTP(r->out.alias_handle);
2213 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2215 d_state = h->data;
2217 /* form the alias SID */
2218 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2219 if (sid == NULL)
2220 return NT_STATUS_NO_MEMORY;
2222 /* search for the group record */
2223 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2224 "(&(objectSid=%s)(objectclass=group)"
2225 "(|(grouptype=%d)(grouptype=%d)))",
2226 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2227 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2228 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2229 if (ret == 0) {
2230 return NT_STATUS_NO_SUCH_ALIAS;
2232 if (ret != 1) {
2233 DEBUG(0,("Found %d records matching sid %s\n",
2234 ret, dom_sid_string(mem_ctx, sid)));
2235 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2238 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2239 if (alias_name == NULL) {
2240 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2241 dom_sid_string(mem_ctx, sid)));
2242 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2245 a_state = talloc(mem_ctx, struct samr_account_state);
2246 if (!a_state) {
2247 return NT_STATUS_NO_MEMORY;
2249 a_state->sam_ctx = d_state->sam_ctx;
2250 a_state->access_mask = r->in.access_mask;
2251 a_state->domain_state = talloc_reference(a_state, d_state);
2252 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2253 a_state->account_sid = talloc_steal(a_state, sid);
2254 a_state->account_name = talloc_strdup(a_state, alias_name);
2255 if (!a_state->account_name) {
2256 return NT_STATUS_NO_MEMORY;
2259 /* create the policy handle */
2260 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2261 if (!g_handle) {
2262 return NT_STATUS_NO_MEMORY;
2265 g_handle->data = talloc_steal(g_handle, a_state);
2267 *r->out.alias_handle = g_handle->wire_handle;
2269 return NT_STATUS_OK;
2274 samr_QueryAliasInfo
2276 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2277 struct samr_QueryAliasInfo *r)
2279 struct dcesrv_handle *h;
2280 struct samr_account_state *a_state;
2281 struct ldb_message *msg, **res;
2282 const char * const attrs[4] = { "sAMAccountName", "description",
2283 "numMembers", NULL };
2284 int ret;
2285 union samr_AliasInfo *info;
2287 *r->out.info = NULL;
2289 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2291 a_state = h->data;
2293 /* pull all the alias attributes */
2294 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2295 a_state->account_dn, &res, attrs);
2296 if (ret == 0) {
2297 return NT_STATUS_NO_SUCH_ALIAS;
2299 if (ret != 1) {
2300 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2302 msg = res[0];
2304 /* allocate the info structure */
2305 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2306 if (info == NULL) {
2307 return NT_STATUS_NO_MEMORY;
2310 switch(r->in.level) {
2311 case ALIASINFOALL:
2312 QUERY_STRING(msg, all.name, "sAMAccountName");
2313 QUERY_UINT (msg, all.num_members, "numMembers");
2314 QUERY_STRING(msg, all.description, "description");
2315 break;
2316 case ALIASINFONAME:
2317 QUERY_STRING(msg, name, "sAMAccountName");
2318 break;
2319 case ALIASINFODESCRIPTION:
2320 QUERY_STRING(msg, description, "description");
2321 break;
2322 default:
2323 talloc_free(info);
2324 return NT_STATUS_INVALID_INFO_CLASS;
2327 *r->out.info = info;
2329 return NT_STATUS_OK;
2334 samr_SetAliasInfo
2336 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2337 struct samr_SetAliasInfo *r)
2339 struct dcesrv_handle *h;
2340 struct samr_account_state *a_state;
2341 struct ldb_message *msg;
2342 struct ldb_context *sam_ctx;
2343 int ret;
2345 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2347 a_state = h->data;
2348 sam_ctx = a_state->sam_ctx;
2350 msg = ldb_msg_new(mem_ctx);
2351 if (msg == NULL) {
2352 return NT_STATUS_NO_MEMORY;
2355 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2356 if (!msg->dn) {
2357 return NT_STATUS_NO_MEMORY;
2360 switch (r->in.level) {
2361 case ALIASINFODESCRIPTION:
2362 SET_STRING(msg, description, "description");
2363 break;
2364 case ALIASINFONAME:
2365 /* On W2k3 this does not change the name, it changes the
2366 * sAMAccountName attribute */
2367 SET_STRING(msg, name, "sAMAccountName");
2368 break;
2369 default:
2370 return NT_STATUS_INVALID_INFO_CLASS;
2373 /* modify the samdb record */
2374 ret = ldb_modify(a_state->sam_ctx, msg);
2375 if (ret != LDB_SUCCESS) {
2376 return dsdb_ldb_err_to_ntstatus(ret);
2379 return NT_STATUS_OK;
2384 samr_DeleteDomAlias
2386 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2387 struct samr_DeleteDomAlias *r)
2389 struct dcesrv_handle *h;
2390 struct samr_account_state *a_state;
2391 int ret;
2393 *r->out.alias_handle = *r->in.alias_handle;
2395 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2397 a_state = h->data;
2399 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2400 if (ret != LDB_SUCCESS) {
2401 return dsdb_ldb_err_to_ntstatus(ret);
2404 talloc_free(h);
2405 ZERO_STRUCTP(r->out.alias_handle);
2407 return NT_STATUS_OK;
2412 samr_AddAliasMember
2414 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2415 struct samr_AddAliasMember *r)
2417 struct dcesrv_handle *h;
2418 struct samr_account_state *a_state;
2419 struct samr_domain_state *d_state;
2420 struct ldb_message *mod;
2421 struct ldb_message **msgs;
2422 const char * const attrs[] = { NULL };
2423 struct ldb_dn *memberdn = NULL;
2424 int ret;
2425 NTSTATUS status;
2427 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2429 a_state = h->data;
2430 d_state = a_state->domain_state;
2432 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2433 &msgs, attrs, "(objectsid=%s)",
2434 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2436 if (ret == 1) {
2437 memberdn = msgs[0]->dn;
2438 } else if (ret == 0) {
2439 status = samdb_create_foreign_security_principal(
2440 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2441 if (!NT_STATUS_IS_OK(status)) {
2442 return status;
2444 } else {
2445 DEBUG(0,("Found %d records matching sid %s\n",
2446 ret, dom_sid_string(mem_ctx, r->in.sid)));
2447 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2450 if (memberdn == NULL) {
2451 DEBUG(0, ("Could not find memberdn\n"));
2452 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2455 mod = ldb_msg_new(mem_ctx);
2456 if (mod == NULL) {
2457 return NT_STATUS_NO_MEMORY;
2460 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2462 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2463 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2464 if (ret != LDB_SUCCESS) {
2465 return dsdb_ldb_err_to_ntstatus(ret);
2468 ret = ldb_modify(a_state->sam_ctx, mod);
2469 switch (ret) {
2470 case LDB_SUCCESS:
2471 return NT_STATUS_OK;
2472 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2473 return NT_STATUS_MEMBER_IN_GROUP;
2474 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2475 return NT_STATUS_ACCESS_DENIED;
2476 default:
2477 return dsdb_ldb_err_to_ntstatus(ret);
2483 samr_DeleteAliasMember
2485 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2486 struct samr_DeleteAliasMember *r)
2488 struct dcesrv_handle *h;
2489 struct samr_account_state *a_state;
2490 struct samr_domain_state *d_state;
2491 struct ldb_message *mod;
2492 const char *memberdn;
2493 int ret;
2495 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2497 a_state = h->data;
2498 d_state = a_state->domain_state;
2500 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2501 "distinguishedName", "(objectSid=%s)",
2502 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2503 if (memberdn == NULL) {
2504 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2507 mod = ldb_msg_new(mem_ctx);
2508 if (mod == NULL) {
2509 return NT_STATUS_NO_MEMORY;
2512 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2514 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2515 memberdn);
2516 if (ret != LDB_SUCCESS) {
2517 return dsdb_ldb_err_to_ntstatus(ret);
2520 ret = ldb_modify(a_state->sam_ctx, mod);
2521 switch (ret) {
2522 case LDB_SUCCESS:
2523 return NT_STATUS_OK;
2524 case LDB_ERR_UNWILLING_TO_PERFORM:
2525 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2526 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2527 return NT_STATUS_ACCESS_DENIED;
2528 default:
2529 return dsdb_ldb_err_to_ntstatus(ret);
2535 samr_GetMembersInAlias
2537 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2538 struct samr_GetMembersInAlias *r)
2540 struct dcesrv_handle *h;
2541 struct samr_account_state *a_state;
2542 struct samr_domain_state *d_state;
2543 struct lsa_SidPtr *array;
2544 unsigned int i, num_members;
2545 struct dom_sid *members;
2546 NTSTATUS status;
2548 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2550 a_state = h->data;
2551 d_state = a_state->domain_state;
2553 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2554 a_state->account_dn, &members,
2555 &num_members);
2556 if (!NT_STATUS_IS_OK(status)) {
2557 return status;
2560 if (num_members == 0) {
2561 r->out.sids->sids = NULL;
2563 return NT_STATUS_OK;
2566 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2567 if (array == NULL) {
2568 return NT_STATUS_NO_MEMORY;
2571 for (i=0; i<num_members; i++) {
2572 array[i].sid = &members[i];
2575 r->out.sids->num_sids = num_members;
2576 r->out.sids->sids = array;
2578 return NT_STATUS_OK;
2582 samr_OpenUser
2584 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2585 struct samr_OpenUser *r)
2587 struct samr_domain_state *d_state;
2588 struct samr_account_state *a_state;
2589 struct dcesrv_handle *h;
2590 const char *account_name;
2591 struct dom_sid *sid;
2592 struct ldb_message **msgs;
2593 struct dcesrv_handle *u_handle;
2594 const char * const attrs[2] = { "sAMAccountName", NULL };
2595 int ret;
2597 ZERO_STRUCTP(r->out.user_handle);
2599 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2601 d_state = h->data;
2603 /* form the users SID */
2604 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2605 if (!sid) {
2606 return NT_STATUS_NO_MEMORY;
2609 /* search for the user record */
2610 ret = gendb_search(d_state->sam_ctx,
2611 mem_ctx, d_state->domain_dn, &msgs, attrs,
2612 "(&(objectSid=%s)(objectclass=user))",
2613 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2614 if (ret == 0) {
2615 return NT_STATUS_NO_SUCH_USER;
2617 if (ret != 1) {
2618 DEBUG(0,("Found %d records matching sid %s\n", ret,
2619 dom_sid_string(mem_ctx, sid)));
2620 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2623 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2624 if (account_name == NULL) {
2625 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2626 dom_sid_string(mem_ctx, sid)));
2627 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2630 a_state = talloc(mem_ctx, struct samr_account_state);
2631 if (!a_state) {
2632 return NT_STATUS_NO_MEMORY;
2634 a_state->sam_ctx = d_state->sam_ctx;
2635 a_state->access_mask = r->in.access_mask;
2636 a_state->domain_state = talloc_reference(a_state, d_state);
2637 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2638 a_state->account_sid = talloc_steal(a_state, sid);
2639 a_state->account_name = talloc_strdup(a_state, account_name);
2640 if (!a_state->account_name) {
2641 return NT_STATUS_NO_MEMORY;
2644 /* create the policy handle */
2645 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2646 if (!u_handle) {
2647 return NT_STATUS_NO_MEMORY;
2650 u_handle->data = talloc_steal(u_handle, a_state);
2652 *r->out.user_handle = u_handle->wire_handle;
2654 return NT_STATUS_OK;
2660 samr_DeleteUser
2662 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2663 struct samr_DeleteUser *r)
2665 struct dcesrv_handle *h;
2666 struct samr_account_state *a_state;
2667 int ret;
2669 *r->out.user_handle = *r->in.user_handle;
2671 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2673 a_state = h->data;
2675 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2676 if (ret != LDB_SUCCESS) {
2677 DEBUG(1, ("Failed to delete user: %s: %s\n",
2678 ldb_dn_get_linearized(a_state->account_dn),
2679 ldb_errstring(a_state->sam_ctx)));
2680 return dsdb_ldb_err_to_ntstatus(ret);
2683 talloc_free(h);
2684 ZERO_STRUCTP(r->out.user_handle);
2686 return NT_STATUS_OK;
2691 samr_QueryUserInfo
2693 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2694 struct samr_QueryUserInfo *r)
2696 struct dcesrv_handle *h;
2697 struct samr_account_state *a_state;
2698 struct ldb_message *msg, **res;
2699 int ret;
2700 struct ldb_context *sam_ctx;
2702 const char * const *attrs = NULL;
2703 union samr_UserInfo *info;
2705 *r->out.info = NULL;
2707 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2709 a_state = h->data;
2710 sam_ctx = a_state->sam_ctx;
2712 /* fill in the reply */
2713 switch (r->in.level) {
2714 case 1:
2716 static const char * const attrs2[] = {"sAMAccountName",
2717 "displayName",
2718 "primaryroupID",
2719 "description",
2720 "comment",
2721 NULL};
2722 attrs = attrs2;
2723 break;
2725 case 2:
2727 static const char * const attrs2[] = {"comment",
2728 "countryCode",
2729 "codePage",
2730 NULL};
2731 attrs = attrs2;
2732 break;
2734 case 3:
2736 static const char * const attrs2[] = {"sAMAccountName",
2737 "displayName",
2738 "objectSid",
2739 "primaryGroupID",
2740 "homeDirectory",
2741 "homeDrive",
2742 "scriptPath",
2743 "profilePath",
2744 "userWorkstations",
2745 "lastLogon",
2746 "lastLogoff",
2747 "pwdLastSet",
2748 "logonHours",
2749 "badPwdCount",
2750 "logonCount",
2751 "userAccountControl",
2752 NULL};
2753 attrs = attrs2;
2754 break;
2756 case 4:
2758 static const char * const attrs2[] = {"logonHours",
2759 NULL};
2760 attrs = attrs2;
2761 break;
2763 case 5:
2765 static const char * const attrs2[] = {"sAMAccountName",
2766 "displayName",
2767 "objectSid",
2768 "primaryGroupID",
2769 "homeDirectory",
2770 "homeDrive",
2771 "scriptPath",
2772 "profilePath",
2773 "description",
2774 "userWorkstations",
2775 "lastLogon",
2776 "lastLogoff",
2777 "logonHours",
2778 "badPwdCount",
2779 "logonCount",
2780 "pwdLastSet",
2781 "accountExpires",
2782 "userAccountControl",
2783 NULL};
2784 attrs = attrs2;
2785 break;
2787 case 6:
2789 static const char * const attrs2[] = {"sAMAccountName",
2790 "displayName",
2791 NULL};
2792 attrs = attrs2;
2793 break;
2795 case 7:
2797 static const char * const attrs2[] = {"sAMAccountName",
2798 NULL};
2799 attrs = attrs2;
2800 break;
2802 case 8:
2804 static const char * const attrs2[] = {"displayName",
2805 NULL};
2806 attrs = attrs2;
2807 break;
2809 case 9:
2811 static const char * const attrs2[] = {"primaryGroupID",
2812 NULL};
2813 attrs = attrs2;
2814 break;
2816 case 10:
2818 static const char * const attrs2[] = {"homeDirectory",
2819 "homeDrive",
2820 NULL};
2821 attrs = attrs2;
2822 break;
2824 case 11:
2826 static const char * const attrs2[] = {"scriptPath",
2827 NULL};
2828 attrs = attrs2;
2829 break;
2831 case 12:
2833 static const char * const attrs2[] = {"profilePath",
2834 NULL};
2835 attrs = attrs2;
2836 break;
2838 case 13:
2840 static const char * const attrs2[] = {"description",
2841 NULL};
2842 attrs = attrs2;
2843 break;
2845 case 14:
2847 static const char * const attrs2[] = {"userWorkstations",
2848 NULL};
2849 attrs = attrs2;
2850 break;
2852 case 16:
2854 static const char * const attrs2[] = {"userAccountControl",
2855 "pwdLastSet",
2856 NULL};
2857 attrs = attrs2;
2858 break;
2860 case 17:
2862 static const char * const attrs2[] = {"accountExpires",
2863 NULL};
2864 attrs = attrs2;
2865 break;
2867 case 18:
2869 return NT_STATUS_NOT_SUPPORTED;
2871 case 20:
2873 static const char * const attrs2[] = {"userParameters",
2874 NULL};
2875 attrs = attrs2;
2876 break;
2878 case 21:
2880 static const char * const attrs2[] = {"lastLogon",
2881 "lastLogoff",
2882 "pwdLastSet",
2883 "accountExpires",
2884 "sAMAccountName",
2885 "displayName",
2886 "homeDirectory",
2887 "homeDrive",
2888 "scriptPath",
2889 "profilePath",
2890 "description",
2891 "userWorkstations",
2892 "comment",
2893 "userParameters",
2894 "objectSid",
2895 "primaryGroupID",
2896 "userAccountControl",
2897 "logonHours",
2898 "badPwdCount",
2899 "logonCount",
2900 "countryCode",
2901 "codePage",
2902 NULL};
2903 attrs = attrs2;
2904 break;
2906 case 23:
2907 case 24:
2908 case 25:
2909 case 26:
2911 return NT_STATUS_NOT_SUPPORTED;
2913 default:
2915 return NT_STATUS_INVALID_INFO_CLASS;
2919 /* pull all the user attributes */
2920 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2921 a_state->account_dn, &res, attrs);
2922 if (ret == 0) {
2923 return NT_STATUS_NO_SUCH_USER;
2925 if (ret != 1) {
2926 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2928 msg = res[0];
2930 /* allocate the info structure */
2931 info = talloc_zero(mem_ctx, union samr_UserInfo);
2932 if (info == NULL) {
2933 return NT_STATUS_NO_MEMORY;
2936 /* fill in the reply */
2937 switch (r->in.level) {
2938 case 1:
2939 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2940 QUERY_STRING(msg, info1.full_name, "displayName");
2941 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2942 QUERY_STRING(msg, info1.description, "description");
2943 QUERY_STRING(msg, info1.comment, "comment");
2944 break;
2946 case 2:
2947 QUERY_STRING(msg, info2.comment, "comment");
2948 QUERY_UINT (msg, info2.country_code, "countryCode");
2949 QUERY_UINT (msg, info2.code_page, "codePage");
2950 break;
2952 case 3:
2953 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2954 QUERY_STRING(msg, info3.full_name, "displayName");
2955 QUERY_RID (msg, info3.rid, "objectSid");
2956 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2957 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2958 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2959 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2960 QUERY_STRING(msg, info3.profile_path, "profilePath");
2961 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2962 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2963 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2964 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2965 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2966 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2967 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2968 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2969 QUERY_UINT (msg, info3.logon_count, "logonCount");
2970 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
2971 break;
2973 case 4:
2974 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2975 break;
2977 case 5:
2978 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2979 QUERY_STRING(msg, info5.full_name, "displayName");
2980 QUERY_RID (msg, info5.rid, "objectSid");
2981 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2982 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2983 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2984 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2985 QUERY_STRING(msg, info5.profile_path, "profilePath");
2986 QUERY_STRING(msg, info5.description, "description");
2987 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2988 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2989 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2990 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2991 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
2992 QUERY_UINT (msg, info5.logon_count, "logonCount");
2993 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2994 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
2995 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
2996 break;
2998 case 6:
2999 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3000 QUERY_STRING(msg, info6.full_name, "displayName");
3001 break;
3003 case 7:
3004 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3005 break;
3007 case 8:
3008 QUERY_STRING(msg, info8.full_name, "displayName");
3009 break;
3011 case 9:
3012 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3013 break;
3015 case 10:
3016 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3017 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3018 break;
3020 case 11:
3021 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3022 break;
3024 case 12:
3025 QUERY_STRING(msg, info12.profile_path, "profilePath");
3026 break;
3028 case 13:
3029 QUERY_STRING(msg, info13.description, "description");
3030 break;
3032 case 14:
3033 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3034 break;
3036 case 16:
3037 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3038 break;
3040 case 17:
3041 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3042 break;
3044 case 20:
3045 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3046 break;
3048 case 21:
3049 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3050 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3051 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3052 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3053 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3054 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3055 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3056 QUERY_STRING(msg, info21.full_name, "displayName");
3057 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3058 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3059 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3060 QUERY_STRING(msg, info21.profile_path, "profilePath");
3061 QUERY_STRING(msg, info21.description, "description");
3062 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3063 QUERY_STRING(msg, info21.comment, "comment");
3064 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3065 QUERY_RID (msg, info21.rid, "objectSid");
3066 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3067 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3068 info->info21.fields_present = 0x08FFFFFF;
3069 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3070 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3071 QUERY_UINT (msg, info21.logon_count, "logonCount");
3072 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3073 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3074 } else {
3075 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3077 QUERY_UINT (msg, info21.country_code, "countryCode");
3078 QUERY_UINT (msg, info21.code_page, "codePage");
3079 break;
3082 default:
3083 talloc_free(info);
3084 return NT_STATUS_INVALID_INFO_CLASS;
3087 *r->out.info = info;
3089 return NT_STATUS_OK;
3094 samr_SetUserInfo
3096 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3097 struct samr_SetUserInfo *r)
3099 struct dcesrv_handle *h;
3100 struct samr_account_state *a_state;
3101 struct ldb_message *msg;
3102 int ret;
3103 NTSTATUS status = NT_STATUS_OK;
3104 struct ldb_context *sam_ctx;
3106 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3108 a_state = h->data;
3109 sam_ctx = a_state->sam_ctx;
3111 msg = ldb_msg_new(mem_ctx);
3112 if (msg == NULL) {
3113 return NT_STATUS_NO_MEMORY;
3116 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3117 if (!msg->dn) {
3118 return NT_STATUS_NO_MEMORY;
3121 switch (r->in.level) {
3122 case 2:
3123 SET_STRING(msg, info2.comment, "comment");
3124 SET_UINT (msg, info2.country_code, "countryCode");
3125 SET_UINT (msg, info2.code_page, "codePage");
3126 break;
3128 case 4:
3129 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3130 break;
3132 case 6:
3133 SET_STRING(msg, info6.account_name, "samAccountName");
3134 SET_STRING(msg, info6.full_name, "displayName");
3135 break;
3137 case 7:
3138 SET_STRING(msg, info7.account_name, "samAccountName");
3139 break;
3141 case 8:
3142 SET_STRING(msg, info8.full_name, "displayName");
3143 break;
3145 case 9:
3146 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3147 break;
3149 case 10:
3150 SET_STRING(msg, info10.home_directory, "homeDirectory");
3151 SET_STRING(msg, info10.home_drive, "homeDrive");
3152 break;
3154 case 11:
3155 SET_STRING(msg, info11.logon_script, "scriptPath");
3156 break;
3158 case 12:
3159 SET_STRING(msg, info12.profile_path, "profilePath");
3160 break;
3162 case 13:
3163 SET_STRING(msg, info13.description, "description");
3164 break;
3166 case 14:
3167 SET_STRING(msg, info14.workstations, "userWorkstations");
3168 break;
3170 case 16:
3171 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3172 break;
3174 case 17:
3175 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3176 break;
3178 case 18:
3179 status = samr_set_password_buffers(dce_call,
3180 a_state->sam_ctx,
3181 a_state->account_dn,
3182 a_state->domain_state->domain_dn,
3183 mem_ctx,
3184 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3185 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3186 if (!NT_STATUS_IS_OK(status)) {
3187 return status;
3190 if (r->in.info->info18.password_expired > 0) {
3191 struct ldb_message_element *set_el;
3192 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3193 return NT_STATUS_NO_MEMORY;
3195 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3196 set_el->flags = LDB_FLAG_MOD_REPLACE;
3198 break;
3200 case 20:
3201 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3202 break;
3204 case 21:
3205 if (r->in.info->info21.fields_present == 0)
3206 return NT_STATUS_INVALID_PARAMETER;
3208 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3209 IFSET(SAMR_FIELD_LAST_LOGON)
3210 SET_UINT64(msg, info21.last_logon, "lastLogon");
3211 IFSET(SAMR_FIELD_LAST_LOGOFF)
3212 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3213 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3214 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3215 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3216 SET_STRING(msg, info21.account_name, "samAccountName");
3217 IFSET(SAMR_FIELD_FULL_NAME)
3218 SET_STRING(msg, info21.full_name, "displayName");
3219 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3220 SET_STRING(msg, info21.home_directory, "homeDirectory");
3221 IFSET(SAMR_FIELD_HOME_DRIVE)
3222 SET_STRING(msg, info21.home_drive, "homeDrive");
3223 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3224 SET_STRING(msg, info21.logon_script, "scriptPath");
3225 IFSET(SAMR_FIELD_PROFILE_PATH)
3226 SET_STRING(msg, info21.profile_path, "profilePath");
3227 IFSET(SAMR_FIELD_DESCRIPTION)
3228 SET_STRING(msg, info21.description, "description");
3229 IFSET(SAMR_FIELD_WORKSTATIONS)
3230 SET_STRING(msg, info21.workstations, "userWorkstations");
3231 IFSET(SAMR_FIELD_COMMENT)
3232 SET_STRING(msg, info21.comment, "comment");
3233 IFSET(SAMR_FIELD_PARAMETERS)
3234 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3235 IFSET(SAMR_FIELD_PRIMARY_GID)
3236 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3237 IFSET(SAMR_FIELD_ACCT_FLAGS)
3238 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3239 IFSET(SAMR_FIELD_LOGON_HOURS)
3240 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3241 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3242 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3243 IFSET(SAMR_FIELD_NUM_LOGONS)
3244 SET_UINT (msg, info21.logon_count, "logonCount");
3245 IFSET(SAMR_FIELD_COUNTRY_CODE)
3246 SET_UINT (msg, info21.country_code, "countryCode");
3247 IFSET(SAMR_FIELD_CODE_PAGE)
3248 SET_UINT (msg, info21.code_page, "codePage");
3250 /* password change fields */
3251 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3252 return NT_STATUS_ACCESS_DENIED;
3254 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3255 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3256 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3258 if (r->in.info->info21.lm_password_set) {
3259 if ((r->in.info->info21.lm_owf_password.length != 16)
3260 || (r->in.info->info21.lm_owf_password.size != 16)) {
3261 return NT_STATUS_INVALID_PARAMETER;
3264 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3266 if (r->in.info->info21.nt_password_set) {
3267 if ((r->in.info->info21.nt_owf_password.length != 16)
3268 || (r->in.info->info21.nt_owf_password.size != 16)) {
3269 return NT_STATUS_INVALID_PARAMETER;
3272 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3274 status = samr_set_password_buffers(dce_call,
3275 a_state->sam_ctx,
3276 a_state->account_dn,
3277 a_state->domain_state->domain_dn,
3278 mem_ctx,
3279 lm_pwd_hash,
3280 nt_pwd_hash);
3281 if (!NT_STATUS_IS_OK(status)) {
3282 return status;
3287 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3288 NTTIME t = 0;
3289 struct ldb_message_element *set_el;
3290 if (r->in.info->info21.password_expired
3291 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3292 unix_to_nt_time(&t, time(NULL));
3294 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3295 "pwdLastSet", t) != LDB_SUCCESS) {
3296 return NT_STATUS_NO_MEMORY;
3298 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3299 set_el->flags = LDB_FLAG_MOD_REPLACE;
3301 #undef IFSET
3302 break;
3304 case 23:
3305 if (r->in.info->info23.info.fields_present == 0)
3306 return NT_STATUS_INVALID_PARAMETER;
3308 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3309 IFSET(SAMR_FIELD_LAST_LOGON)
3310 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3311 IFSET(SAMR_FIELD_LAST_LOGOFF)
3312 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3313 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3314 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3315 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3316 SET_STRING(msg, info23.info.account_name, "samAccountName");
3317 IFSET(SAMR_FIELD_FULL_NAME)
3318 SET_STRING(msg, info23.info.full_name, "displayName");
3319 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3320 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3321 IFSET(SAMR_FIELD_HOME_DRIVE)
3322 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3323 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3324 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3325 IFSET(SAMR_FIELD_PROFILE_PATH)
3326 SET_STRING(msg, info23.info.profile_path, "profilePath");
3327 IFSET(SAMR_FIELD_DESCRIPTION)
3328 SET_STRING(msg, info23.info.description, "description");
3329 IFSET(SAMR_FIELD_WORKSTATIONS)
3330 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3331 IFSET(SAMR_FIELD_COMMENT)
3332 SET_STRING(msg, info23.info.comment, "comment");
3333 IFSET(SAMR_FIELD_PARAMETERS)
3334 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3335 IFSET(SAMR_FIELD_PRIMARY_GID)
3336 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3337 IFSET(SAMR_FIELD_ACCT_FLAGS)
3338 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3339 IFSET(SAMR_FIELD_LOGON_HOURS)
3340 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3341 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3342 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3343 IFSET(SAMR_FIELD_NUM_LOGONS)
3344 SET_UINT (msg, info23.info.logon_count, "logonCount");
3346 IFSET(SAMR_FIELD_COUNTRY_CODE)
3347 SET_UINT (msg, info23.info.country_code, "countryCode");
3348 IFSET(SAMR_FIELD_CODE_PAGE)
3349 SET_UINT (msg, info23.info.code_page, "codePage");
3351 /* password change fields */
3352 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3353 return NT_STATUS_ACCESS_DENIED;
3355 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3356 status = samr_set_password(dce_call,
3357 a_state->sam_ctx,
3358 a_state->account_dn,
3359 a_state->domain_state->domain_dn,
3360 mem_ctx,
3361 &r->in.info->info23.password);
3362 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3363 status = samr_set_password(dce_call,
3364 a_state->sam_ctx,
3365 a_state->account_dn,
3366 a_state->domain_state->domain_dn,
3367 mem_ctx,
3368 &r->in.info->info23.password);
3370 if (!NT_STATUS_IS_OK(status)) {
3371 return status;
3374 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3375 NTTIME t = 0;
3376 struct ldb_message_element *set_el;
3377 if (r->in.info->info23.info.password_expired
3378 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3379 unix_to_nt_time(&t, time(NULL));
3381 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3382 "pwdLastSet", t) != LDB_SUCCESS) {
3383 return NT_STATUS_NO_MEMORY;
3385 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3386 set_el->flags = LDB_FLAG_MOD_REPLACE;
3388 #undef IFSET
3389 break;
3391 /* the set password levels are handled separately */
3392 case 24:
3393 status = samr_set_password(dce_call,
3394 a_state->sam_ctx,
3395 a_state->account_dn,
3396 a_state->domain_state->domain_dn,
3397 mem_ctx,
3398 &r->in.info->info24.password);
3399 if (!NT_STATUS_IS_OK(status)) {
3400 return status;
3403 if (r->in.info->info24.password_expired > 0) {
3404 struct ldb_message_element *set_el;
3405 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3406 return NT_STATUS_NO_MEMORY;
3408 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3409 set_el->flags = LDB_FLAG_MOD_REPLACE;
3411 break;
3413 case 25:
3414 if (r->in.info->info25.info.fields_present == 0)
3415 return NT_STATUS_INVALID_PARAMETER;
3417 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3418 IFSET(SAMR_FIELD_LAST_LOGON)
3419 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3420 IFSET(SAMR_FIELD_LAST_LOGOFF)
3421 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3422 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3423 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3424 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3425 SET_STRING(msg, info25.info.account_name, "samAccountName");
3426 IFSET(SAMR_FIELD_FULL_NAME)
3427 SET_STRING(msg, info25.info.full_name, "displayName");
3428 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3429 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3430 IFSET(SAMR_FIELD_HOME_DRIVE)
3431 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3432 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3433 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3434 IFSET(SAMR_FIELD_PROFILE_PATH)
3435 SET_STRING(msg, info25.info.profile_path, "profilePath");
3436 IFSET(SAMR_FIELD_DESCRIPTION)
3437 SET_STRING(msg, info25.info.description, "description");
3438 IFSET(SAMR_FIELD_WORKSTATIONS)
3439 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3440 IFSET(SAMR_FIELD_COMMENT)
3441 SET_STRING(msg, info25.info.comment, "comment");
3442 IFSET(SAMR_FIELD_PARAMETERS)
3443 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3444 IFSET(SAMR_FIELD_PRIMARY_GID)
3445 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3446 IFSET(SAMR_FIELD_ACCT_FLAGS)
3447 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3448 IFSET(SAMR_FIELD_LOGON_HOURS)
3449 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3450 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3451 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3452 IFSET(SAMR_FIELD_NUM_LOGONS)
3453 SET_UINT (msg, info25.info.logon_count, "logonCount");
3454 IFSET(SAMR_FIELD_COUNTRY_CODE)
3455 SET_UINT (msg, info25.info.country_code, "countryCode");
3456 IFSET(SAMR_FIELD_CODE_PAGE)
3457 SET_UINT (msg, info25.info.code_page, "codePage");
3459 /* password change fields */
3460 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3461 return NT_STATUS_ACCESS_DENIED;
3463 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3464 status = samr_set_password_ex(dce_call,
3465 a_state->sam_ctx,
3466 a_state->account_dn,
3467 a_state->domain_state->domain_dn,
3468 mem_ctx,
3469 &r->in.info->info25.password);
3470 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3471 status = samr_set_password_ex(dce_call,
3472 a_state->sam_ctx,
3473 a_state->account_dn,
3474 a_state->domain_state->domain_dn,
3475 mem_ctx,
3476 &r->in.info->info25.password);
3478 if (!NT_STATUS_IS_OK(status)) {
3479 return status;
3482 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3483 NTTIME t = 0;
3484 struct ldb_message_element *set_el;
3485 if (r->in.info->info25.info.password_expired
3486 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3487 unix_to_nt_time(&t, time(NULL));
3489 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3490 "pwdLastSet", t) != LDB_SUCCESS) {
3491 return NT_STATUS_NO_MEMORY;
3493 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3494 set_el->flags = LDB_FLAG_MOD_REPLACE;
3496 #undef IFSET
3497 break;
3499 /* the set password levels are handled separately */
3500 case 26:
3501 status = samr_set_password_ex(dce_call,
3502 a_state->sam_ctx,
3503 a_state->account_dn,
3504 a_state->domain_state->domain_dn,
3505 mem_ctx,
3506 &r->in.info->info26.password);
3507 if (!NT_STATUS_IS_OK(status)) {
3508 return status;
3511 if (r->in.info->info26.password_expired > 0) {
3512 struct ldb_message_element *set_el;
3513 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3514 return NT_STATUS_NO_MEMORY;
3516 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3517 set_el->flags = LDB_FLAG_MOD_REPLACE;
3519 break;
3521 default:
3522 /* many info classes are not valid for SetUserInfo */
3523 return NT_STATUS_INVALID_INFO_CLASS;
3526 if (!NT_STATUS_IS_OK(status)) {
3527 return status;
3530 /* modify the samdb record */
3531 if (msg->num_elements > 0) {
3532 ret = ldb_modify(a_state->sam_ctx, msg);
3533 if (ret != LDB_SUCCESS) {
3534 DEBUG(1,("Failed to modify record %s: %s\n",
3535 ldb_dn_get_linearized(a_state->account_dn),
3536 ldb_errstring(a_state->sam_ctx)));
3538 return dsdb_ldb_err_to_ntstatus(ret);
3542 return NT_STATUS_OK;
3547 samr_GetGroupsForUser
3549 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3550 struct samr_GetGroupsForUser *r)
3552 struct dcesrv_handle *h;
3553 struct samr_account_state *a_state;
3554 struct samr_domain_state *d_state;
3555 struct ldb_message **res;
3556 const char * const attrs[2] = { "objectSid", NULL };
3557 struct samr_RidWithAttributeArray *array;
3558 int i, count;
3560 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3562 a_state = h->data;
3563 d_state = a_state->domain_state;
3565 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3566 d_state->domain_dn, &res,
3567 attrs, d_state->domain_sid,
3568 "(&(member=%s)(|(grouptype=%d)(grouptype=%d))(objectclass=group))",
3569 ldb_dn_get_linearized(a_state->account_dn),
3570 GTYPE_SECURITY_UNIVERSAL_GROUP,
3571 GTYPE_SECURITY_GLOBAL_GROUP);
3572 if (count < 0)
3573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3575 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3576 if (array == NULL)
3577 return NT_STATUS_NO_MEMORY;
3579 array->count = 0;
3580 array->rids = NULL;
3582 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3583 count + 1);
3584 if (array->rids == NULL)
3585 return NT_STATUS_NO_MEMORY;
3587 /* Adds the primary group */
3588 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3589 ~0, a_state->account_dn,
3590 "primaryGroupID", NULL);
3591 array->rids[0].attributes = SE_GROUP_MANDATORY
3592 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3593 array->count += 1;
3595 /* Adds the additional groups */
3596 for (i = 0; i < count; i++) {
3597 struct dom_sid *group_sid;
3599 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3600 if (group_sid == NULL) {
3601 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3604 array->rids[i + 1].rid =
3605 group_sid->sub_auths[group_sid->num_auths-1];
3606 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3607 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3608 array->count += 1;
3611 *r->out.rids = array;
3613 return NT_STATUS_OK;
3618 samr_QueryDisplayInfo
3620 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3621 struct samr_QueryDisplayInfo *r)
3623 struct dcesrv_handle *h;
3624 struct samr_domain_state *d_state;
3625 struct ldb_result *res;
3626 unsigned int i;
3627 uint32_t count;
3628 const char * const attrs[] = { "objectSid", "sAMAccountName",
3629 "displayName", "description", "userAccountControl",
3630 "pwdLastSet", NULL };
3631 struct samr_DispEntryFull *entriesFull = NULL;
3632 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3633 struct samr_DispEntryAscii *entriesAscii = NULL;
3634 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3635 const char *filter;
3636 int ret;
3638 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3640 d_state = h->data;
3642 switch (r->in.level) {
3643 case 1:
3644 case 4:
3645 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3646 "(sAMAccountType=%d))",
3647 ATYPE_NORMAL_ACCOUNT);
3648 break;
3649 case 2:
3650 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3651 "(sAMAccountType=%d))",
3652 ATYPE_WORKSTATION_TRUST);
3653 break;
3654 case 3:
3655 case 5:
3656 filter = talloc_asprintf(mem_ctx,
3657 "(&(|(groupType=%d)(groupType=%d))"
3658 "(objectClass=group))",
3659 GTYPE_SECURITY_UNIVERSAL_GROUP,
3660 GTYPE_SECURITY_GLOBAL_GROUP);
3661 break;
3662 default:
3663 return NT_STATUS_INVALID_INFO_CLASS;
3666 /* search for all requested objects in all domains. This could
3667 possibly be cached and resumed based on resume_key */
3668 ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, NULL,
3669 LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3670 if (ret != LDB_SUCCESS) {
3671 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3673 if ((res->count == 0) || (r->in.max_entries == 0)) {
3674 return NT_STATUS_OK;
3677 switch (r->in.level) {
3678 case 1:
3679 entriesGeneral = talloc_array(mem_ctx,
3680 struct samr_DispEntryGeneral,
3681 res->count);
3682 break;
3683 case 2:
3684 entriesFull = talloc_array(mem_ctx,
3685 struct samr_DispEntryFull,
3686 res->count);
3687 break;
3688 case 3:
3689 entriesFullGroup = talloc_array(mem_ctx,
3690 struct samr_DispEntryFullGroup,
3691 res->count);
3692 break;
3693 case 4:
3694 case 5:
3695 entriesAscii = talloc_array(mem_ctx,
3696 struct samr_DispEntryAscii,
3697 res->count);
3698 break;
3701 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3702 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3703 return NT_STATUS_NO_MEMORY;
3705 count = 0;
3707 for (i = 0; i < res->count; i++) {
3708 struct dom_sid *objectsid;
3710 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3711 "objectSid");
3712 if (objectsid == NULL)
3713 continue;
3715 switch(r->in.level) {
3716 case 1:
3717 entriesGeneral[count].idx = count + 1;
3718 entriesGeneral[count].rid =
3719 objectsid->sub_auths[objectsid->num_auths-1];
3720 entriesGeneral[count].acct_flags =
3721 samdb_result_acct_flags(d_state->sam_ctx,
3722 mem_ctx,
3723 res->msgs[i],
3724 d_state->domain_dn);
3725 entriesGeneral[count].account_name.string =
3726 ldb_msg_find_attr_as_string(res->msgs[i],
3727 "sAMAccountName", "");
3728 entriesGeneral[count].full_name.string =
3729 ldb_msg_find_attr_as_string(res->msgs[i],
3730 "displayName", "");
3731 entriesGeneral[count].description.string =
3732 ldb_msg_find_attr_as_string(res->msgs[i],
3733 "description", "");
3734 break;
3735 case 2:
3736 entriesFull[count].idx = count + 1;
3737 entriesFull[count].rid =
3738 objectsid->sub_auths[objectsid->num_auths-1];
3740 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3741 entriesFull[count].acct_flags =
3742 samdb_result_acct_flags(d_state->sam_ctx,
3743 mem_ctx,
3744 res->msgs[i],
3745 d_state->domain_dn) | ACB_NORMAL;
3746 entriesFull[count].account_name.string =
3747 ldb_msg_find_attr_as_string(res->msgs[i],
3748 "sAMAccountName", "");
3749 entriesFull[count].description.string =
3750 ldb_msg_find_attr_as_string(res->msgs[i],
3751 "description", "");
3752 break;
3753 case 3:
3754 entriesFullGroup[count].idx = count + 1;
3755 entriesFullGroup[count].rid =
3756 objectsid->sub_auths[objectsid->num_auths-1];
3757 /* We get a "7" here for groups */
3758 entriesFullGroup[count].acct_flags
3759 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3760 entriesFullGroup[count].account_name.string =
3761 ldb_msg_find_attr_as_string(res->msgs[i],
3762 "sAMAccountName", "");
3763 entriesFullGroup[count].description.string =
3764 ldb_msg_find_attr_as_string(res->msgs[i],
3765 "description", "");
3766 break;
3767 case 4:
3768 case 5:
3769 entriesAscii[count].idx = count + 1;
3770 entriesAscii[count].account_name.string =
3771 ldb_msg_find_attr_as_string(res->msgs[i],
3772 "sAMAccountName", "");
3773 break;
3776 count += 1;
3779 *r->out.total_size = count;
3781 if (r->in.start_idx >= count) {
3782 *r->out.returned_size = 0;
3783 switch(r->in.level) {
3784 case 1:
3785 r->out.info->info1.count = *r->out.returned_size;
3786 r->out.info->info1.entries = NULL;
3787 break;
3788 case 2:
3789 r->out.info->info2.count = *r->out.returned_size;
3790 r->out.info->info2.entries = NULL;
3791 break;
3792 case 3:
3793 r->out.info->info3.count = *r->out.returned_size;
3794 r->out.info->info3.entries = NULL;
3795 break;
3796 case 4:
3797 r->out.info->info4.count = *r->out.returned_size;
3798 r->out.info->info4.entries = NULL;
3799 break;
3800 case 5:
3801 r->out.info->info5.count = *r->out.returned_size;
3802 r->out.info->info5.entries = NULL;
3803 break;
3805 } else {
3806 *r->out.returned_size = MIN(count - r->in.start_idx,
3807 r->in.max_entries);
3808 switch(r->in.level) {
3809 case 1:
3810 r->out.info->info1.count = *r->out.returned_size;
3811 r->out.info->info1.entries =
3812 &(entriesGeneral[r->in.start_idx]);
3813 break;
3814 case 2:
3815 r->out.info->info2.count = *r->out.returned_size;
3816 r->out.info->info2.entries =
3817 &(entriesFull[r->in.start_idx]);
3818 break;
3819 case 3:
3820 r->out.info->info3.count = *r->out.returned_size;
3821 r->out.info->info3.entries =
3822 &(entriesFullGroup[r->in.start_idx]);
3823 break;
3824 case 4:
3825 r->out.info->info4.count = *r->out.returned_size;
3826 r->out.info->info4.entries =
3827 &(entriesAscii[r->in.start_idx]);
3828 break;
3829 case 5:
3830 r->out.info->info5.count = *r->out.returned_size;
3831 r->out.info->info5.entries =
3832 &(entriesAscii[r->in.start_idx]);
3833 break;
3837 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3838 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3843 samr_GetDisplayEnumerationIndex
3845 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3846 struct samr_GetDisplayEnumerationIndex *r)
3848 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3853 samr_TestPrivateFunctionsDomain
3855 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3856 struct samr_TestPrivateFunctionsDomain *r)
3858 return NT_STATUS_NOT_IMPLEMENTED;
3863 samr_TestPrivateFunctionsUser
3865 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3866 struct samr_TestPrivateFunctionsUser *r)
3868 return NT_STATUS_NOT_IMPLEMENTED;
3873 samr_GetUserPwInfo
3875 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3876 struct samr_GetUserPwInfo *r)
3878 struct dcesrv_handle *h;
3879 struct samr_account_state *a_state;
3881 ZERO_STRUCTP(r->out.info);
3883 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3885 a_state = h->data;
3887 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3888 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3889 NULL);
3890 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3891 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3893 return NT_STATUS_OK;
3898 samr_RemoveMemberFromForeignDomain
3900 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3901 TALLOC_CTX *mem_ctx,
3902 struct samr_RemoveMemberFromForeignDomain *r)
3904 struct dcesrv_handle *h;
3905 struct samr_domain_state *d_state;
3906 const char *memberdn;
3907 struct ldb_message **res;
3908 const char *no_attrs[] = { NULL };
3909 int i, count;
3911 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3913 d_state = h->data;
3915 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3916 "distinguishedName", "(objectSid=%s)",
3917 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3918 /* Nothing to do */
3919 if (memberdn == NULL) {
3920 return NT_STATUS_OK;
3923 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3924 d_state->domain_dn, &res, no_attrs,
3925 d_state->domain_sid,
3926 "(&(member=%s)(objectClass=group)"
3927 "(|(groupType=%d)(groupType=%d)))",
3928 memberdn,
3929 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3930 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3932 if (count < 0)
3933 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3935 for (i=0; i<count; i++) {
3936 struct ldb_message *mod;
3937 int ret;
3939 mod = ldb_msg_new(mem_ctx);
3940 if (mod == NULL) {
3941 return NT_STATUS_NO_MEMORY;
3944 mod->dn = res[i]->dn;
3946 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3947 "member", memberdn) != LDB_SUCCESS)
3948 return NT_STATUS_NO_MEMORY;
3950 ret = ldb_modify(d_state->sam_ctx, mod);
3951 talloc_free(mod);
3952 if (ret != LDB_SUCCESS) {
3953 return dsdb_ldb_err_to_ntstatus(ret);
3957 return NT_STATUS_OK;
3962 samr_QueryDomainInfo2
3964 just an alias for samr_QueryDomainInfo
3966 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3967 struct samr_QueryDomainInfo2 *r)
3969 struct samr_QueryDomainInfo r1;
3970 NTSTATUS status;
3972 ZERO_STRUCT(r1.out);
3973 r1.in.domain_handle = r->in.domain_handle;
3974 r1.in.level = r->in.level;
3975 r1.out.info = r->out.info;
3977 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3979 return status;
3984 samr_QueryUserInfo2
3986 just an alias for samr_QueryUserInfo
3988 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3989 struct samr_QueryUserInfo2 *r)
3991 struct samr_QueryUserInfo r1;
3992 NTSTATUS status;
3994 r1.in.user_handle = r->in.user_handle;
3995 r1.in.level = r->in.level;
3996 r1.out.info = r->out.info;
3998 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4000 return status;
4005 samr_QueryDisplayInfo2
4007 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4008 struct samr_QueryDisplayInfo2 *r)
4010 struct samr_QueryDisplayInfo q;
4011 NTSTATUS result;
4013 q.in.domain_handle = r->in.domain_handle;
4014 q.in.level = r->in.level;
4015 q.in.start_idx = r->in.start_idx;
4016 q.in.max_entries = r->in.max_entries;
4017 q.in.buf_size = r->in.buf_size;
4018 q.out.total_size = r->out.total_size;
4019 q.out.returned_size = r->out.returned_size;
4020 q.out.info = r->out.info;
4022 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4024 return result;
4029 samr_GetDisplayEnumerationIndex2
4031 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4032 struct samr_GetDisplayEnumerationIndex2 *r)
4034 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4039 samr_QueryDisplayInfo3
4041 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4042 struct samr_QueryDisplayInfo3 *r)
4044 struct samr_QueryDisplayInfo q;
4045 NTSTATUS result;
4047 q.in.domain_handle = r->in.domain_handle;
4048 q.in.level = r->in.level;
4049 q.in.start_idx = r->in.start_idx;
4050 q.in.max_entries = r->in.max_entries;
4051 q.in.buf_size = r->in.buf_size;
4052 q.out.total_size = r->out.total_size;
4053 q.out.returned_size = r->out.returned_size;
4054 q.out.info = r->out.info;
4056 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4058 return result;
4063 samr_AddMultipleMembersToAlias
4065 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4066 struct samr_AddMultipleMembersToAlias *r)
4068 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4073 samr_RemoveMultipleMembersFromAlias
4075 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4076 struct samr_RemoveMultipleMembersFromAlias *r)
4078 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4083 samr_GetDomPwInfo
4085 this fetches the default password properties for a domain
4087 note that w2k3 completely ignores the domain name in this call, and
4088 always returns the information for the servers primary domain
4090 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4091 struct samr_GetDomPwInfo *r)
4093 struct ldb_message **msgs;
4094 int ret;
4095 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4096 struct ldb_context *sam_ctx;
4098 ZERO_STRUCTP(r->out.info);
4100 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4101 dce_call->conn->dce_ctx->lp_ctx,
4102 dce_call->conn->auth_state.session_info, 0);
4103 if (sam_ctx == NULL) {
4104 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4107 /* The domain name in this call is ignored */
4108 ret = gendb_search_dn(sam_ctx,
4109 mem_ctx, NULL, &msgs, attrs);
4110 if (ret <= 0) {
4111 talloc_free(sam_ctx);
4113 return NT_STATUS_NO_SUCH_DOMAIN;
4115 if (ret > 1) {
4116 talloc_free(msgs);
4117 talloc_free(sam_ctx);
4119 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4122 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4123 "minPwdLength", 0);
4124 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4125 "pwdProperties", 1);
4127 talloc_free(msgs);
4128 talloc_unlink(mem_ctx, sam_ctx);
4130 return NT_STATUS_OK;
4135 samr_Connect2
4137 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4138 struct samr_Connect2 *r)
4140 struct samr_Connect c;
4142 c.in.system_name = NULL;
4143 c.in.access_mask = r->in.access_mask;
4144 c.out.connect_handle = r->out.connect_handle;
4146 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4151 samr_SetUserInfo2
4153 just an alias for samr_SetUserInfo
4155 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4156 struct samr_SetUserInfo2 *r)
4158 struct samr_SetUserInfo r2;
4160 r2.in.user_handle = r->in.user_handle;
4161 r2.in.level = r->in.level;
4162 r2.in.info = r->in.info;
4164 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4169 samr_SetBootKeyInformation
4171 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4172 struct samr_SetBootKeyInformation *r)
4174 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4179 samr_GetBootKeyInformation
4181 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4182 struct samr_GetBootKeyInformation *r)
4184 /* Windows Server 2008 returns this */
4185 return NT_STATUS_NOT_SUPPORTED;
4190 samr_Connect3
4192 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4193 struct samr_Connect3 *r)
4195 struct samr_Connect c;
4197 c.in.system_name = NULL;
4198 c.in.access_mask = r->in.access_mask;
4199 c.out.connect_handle = r->out.connect_handle;
4201 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4206 samr_Connect4
4208 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4209 struct samr_Connect4 *r)
4211 struct samr_Connect c;
4213 c.in.system_name = NULL;
4214 c.in.access_mask = r->in.access_mask;
4215 c.out.connect_handle = r->out.connect_handle;
4217 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4222 samr_Connect5
4224 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4225 struct samr_Connect5 *r)
4227 struct samr_Connect c;
4228 NTSTATUS status;
4230 c.in.system_name = NULL;
4231 c.in.access_mask = r->in.access_mask;
4232 c.out.connect_handle = r->out.connect_handle;
4234 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4236 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4237 r->out.info_out->info1.unknown2 = 0;
4238 *r->out.level_out = r->in.level_in;
4240 return status;
4245 samr_RidToSid
4247 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4248 struct samr_RidToSid *r)
4250 struct samr_domain_state *d_state;
4251 struct dcesrv_handle *h;
4253 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4255 d_state = h->data;
4257 /* form the users SID */
4258 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4259 if (!*r->out.sid) {
4260 return NT_STATUS_NO_MEMORY;
4263 return NT_STATUS_OK;
4268 samr_SetDsrmPassword
4270 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4271 struct samr_SetDsrmPassword *r)
4273 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4278 samr_ValidatePassword
4280 For now the call checks the password complexity (if active) and the minimum
4281 password length on level 2 and 3. Level 1 is ignored for now.
4283 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4284 TALLOC_CTX *mem_ctx,
4285 struct samr_ValidatePassword *r)
4287 struct samr_GetDomPwInfo r2;
4288 struct samr_PwInfo pwInfo;
4289 DATA_BLOB password;
4290 enum samr_ValidationStatus res;
4291 NTSTATUS status;
4293 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4295 r2.in.domain_name = NULL;
4296 r2.out.info = &pwInfo;
4297 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4298 if (!NT_STATUS_IS_OK(status)) {
4299 return status;
4302 switch (r->in.level) {
4303 case NetValidateAuthentication:
4304 /* we don't support this yet */
4305 return NT_STATUS_NOT_SUPPORTED;
4306 break;
4307 case NetValidatePasswordChange:
4308 password = data_blob_const(r->in.req->req2.password.string,
4309 r->in.req->req2.password.length);
4310 res = samdb_check_password(&password,
4311 pwInfo.password_properties,
4312 pwInfo.min_password_length);
4313 (*r->out.rep)->ctr2.status = res;
4314 break;
4315 case NetValidatePasswordReset:
4316 password = data_blob_const(r->in.req->req3.password.string,
4317 r->in.req->req3.password.length);
4318 res = samdb_check_password(&password,
4319 pwInfo.password_properties,
4320 pwInfo.min_password_length);
4321 (*r->out.rep)->ctr3.status = res;
4322 break;
4323 default:
4324 return NT_STATUS_INVALID_INFO_CLASS;
4325 break;
4328 return NT_STATUS_OK;
4332 /* include the generated boilerplate */
4333 #include "librpc/gen_ndr/ndr_samr_s.c"