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
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "dsdb/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "libcli/ldap/ldap.h"
36 #include "libcli/security/security.h"
37 #include "rpc_server/samr/proto.h"
40 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
42 #define QUERY_STRING(msg, field, attr) \
43 r->out.info->field = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45 r->out.info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_NTTIME(msg, field, attr) \
49 r->out.info->field = samdb_result_nttime(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51 r->out.info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
52 a_state->domain_state->domain_dn, msg, attr);
53 #define QUERY_FPASSC(msg, field, attr) \
54 r->out.info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
55 a_state->domain_state->domain_dn, msg);
56 #define QUERY_LHOURS(msg, field, attr) \
57 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59 r->out.info->field = samdb_result_acct_flags(msg, attr);
62 /* these are used to make the Set[User|Group]Info code easier to follow */
64 #define SET_STRING(mod, field, attr) do { \
65 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
66 if (samdb_msg_add_string(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
67 return NT_STATUS_NO_MEMORY; \
71 #define SET_UINT(mod, field, attr) do { \
72 if (samdb_msg_add_uint(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
73 return NT_STATUS_NO_MEMORY; \
77 #define SET_INT64(mod, field, attr) do { \
78 if (samdb_msg_add_int64(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
79 return NT_STATUS_NO_MEMORY; \
83 #define SET_UINT64(mod, field, attr) do { \
84 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
85 return NT_STATUS_NO_MEMORY; \
89 #define SET_AFLAGS(msg, field, attr) do { \
90 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
91 return NT_STATUS_NO_MEMORY; \
95 #define SET_LHOURS(msg, field, attr) do { \
96 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
97 return NT_STATUS_NO_MEMORY; \
105 create a connection to the SAM database
107 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
108 struct samr_Connect *r)
110 struct samr_connect_state *c_state;
111 struct dcesrv_handle *handle;
113 ZERO_STRUCTP(r->out.connect_handle);
115 c_state = talloc(dce_call->conn, struct samr_connect_state);
117 return NT_STATUS_NO_MEMORY;
120 /* make sure the sam database is accessible */
121 c_state->sam_ctx = samdb_connect(c_state, dce_call->conn->auth_state.session_info);
122 if (c_state->sam_ctx == NULL) {
123 talloc_free(c_state);
124 return NT_STATUS_INVALID_SYSTEM_SERVICE;
128 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
130 talloc_free(c_state);
131 return NT_STATUS_NO_MEMORY;
134 handle->data = talloc_steal(handle, c_state);
136 c_state->access_mask = r->in.access_mask;
137 *r->out.connect_handle = handle->wire_handle;
146 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
147 struct samr_Close *r)
149 struct dcesrv_handle *h;
151 *r->out.handle = *r->in.handle;
153 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
157 ZERO_STRUCTP(r->out.handle);
166 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
167 struct samr_SetSecurity *r)
169 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
176 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
177 struct samr_QuerySecurity *r)
179 struct dcesrv_handle *h;
180 struct sec_desc_buf *sd;
184 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
186 sd = talloc(mem_ctx, struct sec_desc_buf);
188 return NT_STATUS_NO_MEMORY;
191 sd->sd = samdb_default_security_descriptor(mem_ctx);
202 we refuse this operation completely. If a admin wants to shutdown samr
203 in Samba then they should use the samba admin tools to disable the samr pipe
205 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
206 struct samr_Shutdown *r)
208 return NT_STATUS_ACCESS_DENIED;
215 this maps from a domain name to a SID
217 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
218 struct samr_LookupDomain *r)
220 struct samr_connect_state *c_state;
221 struct dcesrv_handle *h;
223 const char * const dom_attrs[] = { "objectSid", NULL};
224 const char * const ref_attrs[] = { "ncName", NULL};
225 struct ldb_message **dom_msgs;
226 struct ldb_message **ref_msgs;
228 struct ldb_dn *partitions_basedn;
232 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
236 if (r->in.domain_name->string == NULL) {
237 return NT_STATUS_INVALID_PARAMETER;
240 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
242 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
243 ret = gendb_search(c_state->sam_ctx,
244 mem_ctx, NULL, &dom_msgs, dom_attrs,
245 "(objectClass=builtinDomain)");
247 ret = gendb_search(c_state->sam_ctx,
248 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
249 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
250 ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
252 return NT_STATUS_NO_SUCH_DOMAIN;
255 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx,
256 samdb_result_dn(c_state->sam_ctx, mem_ctx,
257 ref_msgs[0], "ncName", NULL),
258 &dom_msgs, dom_attrs);
262 return NT_STATUS_NO_SUCH_DOMAIN;
265 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
269 return NT_STATUS_NO_SUCH_DOMAIN;
281 list the domains in the SAM
283 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
284 struct samr_EnumDomains *r)
286 struct samr_connect_state *c_state;
287 struct dcesrv_handle *h;
288 struct samr_SamArray *array;
289 int count, i, start_i;
290 const char * const dom_attrs[] = { "cn", NULL};
291 const char * const ref_attrs[] = { "nETBIOSName", NULL};
292 struct ldb_message **dom_msgs;
293 struct ldb_message **ref_msgs;
294 struct ldb_dn *partitions_basedn;
296 *r->out.resume_handle = 0;
298 r->out.num_entries = 0;
300 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
304 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
306 count = gendb_search(c_state->sam_ctx,
307 mem_ctx, NULL, &dom_msgs, dom_attrs,
308 "(objectClass=domain)");
310 DEBUG(0,("samdb: no domains found in EnumDomains\n"));
311 return NT_STATUS_INTERNAL_DB_CORRUPTION;
314 *r->out.resume_handle = count;
316 start_i = *r->in.resume_handle;
318 if (start_i >= count) {
319 /* search past end of list is not an error for this call */
323 array = talloc(mem_ctx, struct samr_SamArray);
325 return NT_STATUS_NO_MEMORY;
329 array->entries = NULL;
331 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, count - start_i);
332 if (array->entries == NULL) {
333 return NT_STATUS_NO_MEMORY;
336 for (i=0;i<count-start_i;i++) {
338 array->entries[i].idx = start_i + i;
339 /* try and find the domain */
340 ret = gendb_search(c_state->sam_ctx, mem_ctx, partitions_basedn,
341 &ref_msgs, ref_attrs,
342 "(&(objectClass=crossRef)(ncName=%s))",
343 ldb_dn_get_linearized(dom_msgs[i]->dn));
345 array->entries[i].name.string = samdb_result_string(ref_msgs[0], "nETBIOSName", NULL);
347 array->entries[i].name.string = samdb_result_string(dom_msgs[i], "cn", NULL);
352 r->out.num_entries = i;
353 array->count = r->out.num_entries;
362 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
363 struct samr_OpenDomain *r)
365 struct dcesrv_handle *h_conn, *h_domain;
366 const char *domain_name;
367 struct samr_connect_state *c_state;
368 struct samr_domain_state *d_state;
369 const char * const dom_attrs[] = { "cn", NULL};
370 const char * const ref_attrs[] = { "nETBIOSName", NULL};
371 struct ldb_message **dom_msgs;
372 struct ldb_message **ref_msgs;
374 struct ldb_dn *partitions_basedn;
376 ZERO_STRUCTP(r->out.domain_handle);
378 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
380 c_state = h_conn->data;
382 if (r->in.sid == NULL) {
383 return NT_STATUS_INVALID_PARAMETER;
386 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
388 ret = gendb_search(c_state->sam_ctx,
389 mem_ctx, NULL, &dom_msgs, dom_attrs,
390 "(&(objectSid=%s)(&(|(objectclass=domain)(objectClass=builtinDomain))))",
391 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
393 return NT_STATUS_NO_SUCH_DOMAIN;
394 } else if (ret > 1) {
395 return NT_STATUS_INTERNAL_DB_CORRUPTION;
396 } else if (ret == -1) {
397 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
398 return NT_STATUS_INTERNAL_DB_CORRUPTION;
400 ret = gendb_search(c_state->sam_ctx,
401 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
402 "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))",
403 ldb_dn_get_linearized(dom_msgs[0]->dn));
405 domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL);
406 if (domain_name == NULL) {
407 return NT_STATUS_NO_SUCH_DOMAIN;
409 } else if (ret == 1) {
411 domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL);
412 if (domain_name == NULL) {
413 return NT_STATUS_NO_SUCH_DOMAIN;
416 return NT_STATUS_NO_SUCH_DOMAIN;
420 d_state = talloc(c_state, struct samr_domain_state);
422 return NT_STATUS_NO_MEMORY;
425 d_state->connect_state = talloc_reference(d_state, c_state);
426 d_state->sam_ctx = c_state->sam_ctx;
427 d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
428 d_state->domain_name = talloc_strdup(d_state, domain_name);
429 d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
430 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
431 talloc_free(d_state);
432 return NT_STATUS_NO_MEMORY;
434 d_state->access_mask = r->in.access_mask;
436 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
438 talloc_free(d_state);
439 return NT_STATUS_NO_MEMORY;
442 h_domain->data = talloc_steal(h_domain, d_state);
444 *r->out.domain_handle = h_domain->wire_handle;
452 static NTSTATUS samr_info_DomInfo1(struct samr_domain_state *state,
454 struct ldb_message **dom_msgs,
455 struct samr_DomInfo1 *info)
457 info->min_password_length =
458 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
459 info->password_history_length =
460 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
461 info->password_properties =
462 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
463 info->max_password_age =
464 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
465 info->min_password_age =
466 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
474 static NTSTATUS samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
475 struct ldb_message **dom_msgs,
476 struct samr_DomInfo2 *info)
478 enum server_role role = lp_server_role();
480 /* This pulls the NetBIOS name from the
481 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
483 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
485 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
486 0x8000000000000000LL);
488 info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL);
489 info->domain_name.string = state->domain_name;
491 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
494 case ROLE_DOMAIN_CONTROLLER:
495 /* This pulls the NetBIOS name from the
496 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
498 if (samdb_is_pdc(state->sam_ctx)) {
499 info->role = SAMR_ROLE_DOMAIN_PDC;
501 info->role = SAMR_ROLE_DOMAIN_BDC;
504 case ROLE_DOMAIN_MEMBER:
505 info->role = SAMR_ROLE_DOMAIN_MEMBER;
507 case ROLE_STANDALONE:
508 info->role = SAMR_ROLE_STANDALONE;
512 /* TODO: Should these filter on SID, to avoid counting BUILTIN? */
513 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
514 "(objectClass=user)");
515 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
516 "(&(objectClass=group)(sAMAccountType=%u))",
518 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
519 "(&(objectClass=group)(sAMAccountType=%u))",
528 static NTSTATUS samr_info_DomInfo3(struct samr_domain_state *state,
530 struct ldb_message **dom_msgs,
531 struct samr_DomInfo3 *info)
533 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
534 0x8000000000000000LL);
542 static NTSTATUS samr_info_DomInfo4(struct samr_domain_state *state,
544 struct ldb_message **dom_msgs,
545 struct samr_DomInfo4 *info)
547 info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL);
555 static NTSTATUS samr_info_DomInfo5(struct samr_domain_state *state,
557 struct ldb_message **dom_msgs,
558 struct samr_DomInfo5 *info)
560 info->domain_name.string = state->domain_name;
568 static NTSTATUS samr_info_DomInfo6(struct samr_domain_state *state,
570 struct ldb_message **dom_msgs,
571 struct samr_DomInfo6 *info)
573 /* This pulls the NetBIOS name from the
574 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
576 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
577 dom_msgs[0], "fSMORoleOwner");
585 static NTSTATUS samr_info_DomInfo7(struct samr_domain_state *state,
587 struct ldb_message **dom_msgs,
588 struct samr_DomInfo7 *info)
591 enum server_role role = lp_server_role();
594 case ROLE_DOMAIN_CONTROLLER:
595 /* This pulls the NetBIOS name from the
596 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
598 if (samdb_is_pdc(state->sam_ctx)) {
599 info->role = SAMR_ROLE_DOMAIN_PDC;
601 info->role = SAMR_ROLE_DOMAIN_BDC;
604 case ROLE_DOMAIN_MEMBER:
605 info->role = SAMR_ROLE_DOMAIN_MEMBER;
607 case ROLE_STANDALONE:
608 info->role = SAMR_ROLE_STANDALONE;
618 static NTSTATUS samr_info_DomInfo8(struct samr_domain_state *state,
620 struct ldb_message **dom_msgs,
621 struct samr_DomInfo8 *info)
623 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
626 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
635 static NTSTATUS samr_info_DomInfo9(struct samr_domain_state *state,
637 struct ldb_message **dom_msgs,
638 struct samr_DomInfo9 *info)
648 static NTSTATUS samr_info_DomInfo11(struct samr_domain_state *state,
650 struct ldb_message **dom_msgs,
651 struct samr_DomInfo11 *info)
654 status = samr_info_DomInfo2(state, mem_ctx, dom_msgs, &info->info2);
655 if (!NT_STATUS_IS_OK(status)) {
659 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
661 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
663 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
671 static NTSTATUS samr_info_DomInfo12(struct samr_domain_state *state,
673 struct ldb_message **dom_msgs,
674 struct samr_DomInfo12 *info)
676 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
678 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
680 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
688 static NTSTATUS samr_info_DomInfo13(struct samr_domain_state *state,
690 struct ldb_message **dom_msgs,
691 struct samr_DomInfo13 *info)
693 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
696 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
708 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
709 struct samr_QueryDomainInfo *r)
711 struct dcesrv_handle *h;
712 struct samr_domain_state *d_state;
714 struct ldb_message **dom_msgs;
715 const char * const *attrs = NULL;
719 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
723 r->out.info = talloc(mem_ctx, union samr_DomainInfo);
725 return NT_STATUS_NO_MEMORY;
728 switch (r->in.level) {
731 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
732 "pwdProperties", "maxPwdAge",
739 static const char * const attrs2[] = {"forceLogoff",
749 static const char * const attrs2[] = {"forceLogoff",
756 static const char * const attrs2[] = {"comment",
768 static const char * const attrs2[] = {"fSMORoleOwner",
780 static const char * const attrs2[] = { "modifiedCount",
791 static const char * const attrs2[] = { "comment", "forceLogoff",
794 "lockOutObservationWindow",
802 static const char * const attrs2[] = { "lockoutDuration",
803 "lockOutObservationWindow",
811 static const char * const attrs2[] = { "modifiedCount",
819 /* some levels don't need a search */
822 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
823 d_state->domain_dn, &dom_msgs, attrs);
825 return NT_STATUS_INTERNAL_DB_CORRUPTION;
829 ZERO_STRUCTP(r->out.info);
831 switch (r->in.level) {
833 return samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
834 &r->out.info->info1);
836 return samr_info_DomInfo2(d_state, mem_ctx, dom_msgs,
837 &r->out.info->info2);
839 return samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
840 &r->out.info->info3);
842 return samr_info_DomInfo4(d_state, mem_ctx, dom_msgs,
843 &r->out.info->info4);
845 return samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
846 &r->out.info->info5);
848 return samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
849 &r->out.info->info6);
851 return samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
852 &r->out.info->info7);
854 return samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
855 &r->out.info->info8);
857 return samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
858 &r->out.info->info9);
860 return samr_info_DomInfo11(d_state, mem_ctx, dom_msgs,
861 &r->out.info->info11);
863 return samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
864 &r->out.info->info12);
866 return samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
867 &r->out.info->info13);
870 return NT_STATUS_INVALID_INFO_CLASS;
877 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
878 struct samr_SetDomainInfo *r)
880 struct dcesrv_handle *h;
881 struct samr_domain_state *d_state;
882 struct ldb_message *msg;
884 struct ldb_context *sam_ctx;
886 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
889 sam_ctx = d_state->sam_ctx;
891 msg = ldb_msg_new(mem_ctx);
893 return NT_STATUS_NO_MEMORY;
896 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
898 return NT_STATUS_NO_MEMORY;
901 switch (r->in.level) {
903 SET_UINT (msg, info1.min_password_length, "minPwdLength");
904 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
905 SET_UINT (msg, info1.password_properties, "pwdProperties");
906 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
907 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
910 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
913 SET_STRING(msg, info4.comment.string, "comment");
919 /* No op, we don't know where to set these */
924 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
925 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
926 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
930 /* many info classes are not valid for SetDomainInfo */
931 return NT_STATUS_INVALID_INFO_CLASS;
934 /* modify the samdb record */
935 ret = samdb_replace(sam_ctx, mem_ctx, msg);
937 DEBUG(1,("Failed to modify record %s: %s\n",
938 ldb_dn_get_linearized(d_state->domain_dn),
939 ldb_errstring(sam_ctx)));
941 /* we really need samdb.c to return NTSTATUS */
942 return NT_STATUS_UNSUCCESSFUL;
949 samr_CreateDomainGroup
951 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
952 struct samr_CreateDomainGroup *r)
954 struct samr_domain_state *d_state;
955 struct samr_account_state *a_state;
956 struct dcesrv_handle *h;
958 struct ldb_message *msg;
960 const char *groupname;
961 struct dcesrv_handle *g_handle;
964 ZERO_STRUCTP(r->out.group_handle);
967 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
971 groupname = r->in.name->string;
973 if (groupname == NULL) {
974 return NT_STATUS_INVALID_PARAMETER;
977 /* check if the group already exists */
978 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
980 "(&(sAMAccountName=%s)(objectclass=group))",
981 ldb_binary_encode_string(mem_ctx, groupname));
983 return NT_STATUS_GROUP_EXISTS;
986 msg = ldb_msg_new(mem_ctx);
988 return NT_STATUS_NO_MEMORY;
991 /* add core elements to the ldb_message for the user */
992 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
993 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
995 return NT_STATUS_NO_MEMORY;
997 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
998 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1000 /* create the group */
1001 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1005 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1006 DEBUG(0,("Failed to create group record %s: %s\n",
1007 ldb_dn_get_linearized(msg->dn),
1008 ldb_errstring(d_state->sam_ctx)));
1009 return NT_STATUS_GROUP_EXISTS;
1010 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1011 DEBUG(0,("Failed to create group record %s: %s\n",
1012 ldb_dn_get_linearized(msg->dn),
1013 ldb_errstring(d_state->sam_ctx)));
1014 return NT_STATUS_ACCESS_DENIED;
1016 DEBUG(0,("Failed to create group record %s: %s\n",
1017 ldb_dn_get_linearized(msg->dn),
1018 ldb_errstring(d_state->sam_ctx)));
1019 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1022 a_state = talloc(d_state, struct samr_account_state);
1024 return NT_STATUS_NO_MEMORY;
1026 a_state->sam_ctx = d_state->sam_ctx;
1027 a_state->access_mask = r->in.access_mask;
1028 a_state->domain_state = talloc_reference(a_state, d_state);
1029 a_state->account_dn = talloc_steal(a_state, msg->dn);
1031 /* retrieve the sid for the group just created */
1032 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1033 msg->dn, "objectSid", NULL);
1035 return NT_STATUS_UNSUCCESSFUL;
1038 a_state->account_name = talloc_strdup(a_state, groupname);
1039 if (!a_state->account_name) {
1040 return NT_STATUS_NO_MEMORY;
1043 /* create the policy handle */
1044 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1046 return NT_STATUS_NO_MEMORY;
1049 g_handle->data = talloc_steal(g_handle, a_state);
1051 *r->out.group_handle = g_handle->wire_handle;
1052 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1054 return NT_STATUS_OK;
1059 comparison function for sorting SamEntry array
1061 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1063 return e1->idx - e2->idx;
1067 samr_EnumDomainGroups
1069 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1070 struct samr_EnumDomainGroups *r)
1072 struct dcesrv_handle *h;
1073 struct samr_domain_state *d_state;
1074 struct ldb_message **res;
1075 int ldb_cnt, count, i, first;
1076 struct samr_SamEntry *entries;
1077 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1079 *r->out.resume_handle = 0;
1081 r->out.num_entries = 0;
1083 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1087 /* search for all domain groups in this domain. This could possibly be
1088 cached and resumed based on resume_key */
1089 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1090 d_state->domain_dn, &res, attrs,
1091 d_state->domain_sid,
1092 "(&(grouptype=%d)(objectclass=group))",
1093 GTYPE_SECURITY_GLOBAL_GROUP);
1094 if (ldb_cnt == -1) {
1095 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1097 if (ldb_cnt == 0 || r->in.max_size == 0) {
1098 return NT_STATUS_OK;
1101 /* convert to SamEntry format */
1102 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1104 return NT_STATUS_NO_MEMORY;
1109 for (i=0;i<ldb_cnt;i++) {
1110 struct dom_sid *group_sid;
1112 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1114 if (group_sid == NULL)
1117 entries[count].idx =
1118 group_sid->sub_auths[group_sid->num_auths-1];
1119 entries[count].name.string =
1120 samdb_result_string(res[i], "sAMAccountName", "");
1124 /* sort the results by rid */
1125 qsort(entries, count, sizeof(struct samr_SamEntry),
1126 (comparison_fn_t)compare_SamEntry);
1128 /* find the first entry to return */
1130 first<count && entries[first].idx <= *r->in.resume_handle;
1133 if (first == count) {
1134 return NT_STATUS_OK;
1137 /* return the rest, limit by max_size. Note that we
1138 use the w2k3 element size value of 54 */
1139 r->out.num_entries = count - first;
1140 r->out.num_entries = MIN(r->out.num_entries,
1141 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1143 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1145 return NT_STATUS_NO_MEMORY;
1148 r->out.sam->entries = entries+first;
1149 r->out.sam->count = r->out.num_entries;
1151 if (r->out.num_entries < count - first) {
1152 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1153 return STATUS_MORE_ENTRIES;
1156 return NT_STATUS_OK;
1163 This call uses transactions to ensure we don't get a new conflicting
1164 user while we are processing this, and to ensure the user either
1165 completly exists, or does not.
1167 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1168 struct samr_CreateUser2 *r)
1170 struct samr_domain_state *d_state;
1171 struct samr_account_state *a_state;
1172 struct dcesrv_handle *h;
1174 struct ldb_message *msg;
1175 struct dom_sid *sid;
1176 const char *account_name;
1177 struct dcesrv_handle *u_handle;
1179 const char *container, *obj_class=NULL;
1183 const char *attrs[] = {
1185 "userAccountControl",
1189 uint32_t user_account_control;
1191 struct ldb_message **msgs;
1193 ZERO_STRUCTP(r->out.user_handle);
1194 *r->out.access_granted = 0;
1197 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1201 account_name = r->in.account_name->string;
1203 if (account_name == NULL) {
1204 return NT_STATUS_INVALID_PARAMETER;
1207 ret = ldb_transaction_start(d_state->sam_ctx);
1209 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1210 ldb_errstring(d_state->sam_ctx)));
1211 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1214 /* check if the user already exists */
1215 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1217 "(&(sAMAccountName=%s)(objectclass=user))",
1218 ldb_binary_encode_string(mem_ctx, account_name));
1220 ldb_transaction_cancel(d_state->sam_ctx);
1221 return NT_STATUS_USER_EXISTS;
1224 msg = ldb_msg_new(mem_ctx);
1226 ldb_transaction_cancel(d_state->sam_ctx);
1227 return NT_STATUS_NO_MEMORY;
1230 cn_name = talloc_strdup(mem_ctx, account_name);
1232 ldb_transaction_cancel(d_state->sam_ctx);
1233 return NT_STATUS_NO_MEMORY;
1236 cn_name_len = strlen(cn_name);
1238 /* This must be one of these values *only* */
1239 if (r->in.acct_flags == ACB_NORMAL) {
1240 container = "Users";
1243 } else if (r->in.acct_flags == ACB_WSTRUST) {
1244 if (cn_name[cn_name_len - 1] != '$') {
1245 return NT_STATUS_FOOBAR;
1247 cn_name[cn_name_len - 1] = '\0';
1248 container = "Computers";
1249 obj_class = "computer";
1251 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1252 if (cn_name[cn_name_len - 1] != '$') {
1253 return NT_STATUS_FOOBAR;
1255 cn_name[cn_name_len - 1] = '\0';
1256 container = "Domain Controllers";
1257 obj_class = "computer";
1259 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1260 container = "Users";
1264 ldb_transaction_cancel(d_state->sam_ctx);
1265 return NT_STATUS_INVALID_PARAMETER;
1268 /* add core elements to the ldb_message for the user */
1269 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1270 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container)) {
1271 ldb_transaction_cancel(d_state->sam_ctx);
1272 return NT_STATUS_FOOBAR;
1275 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1276 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1278 /* Start a transaction, so we can query and do a subsequent atomic modify */
1280 /* create the user */
1281 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1285 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1286 ldb_transaction_cancel(d_state->sam_ctx);
1287 DEBUG(0,("Failed to create user record %s: %s\n",
1288 ldb_dn_get_linearized(msg->dn),
1289 ldb_errstring(d_state->sam_ctx)));
1290 return NT_STATUS_USER_EXISTS;
1291 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1292 ldb_transaction_cancel(d_state->sam_ctx);
1293 DEBUG(0,("Failed to create user record %s: %s\n",
1294 ldb_dn_get_linearized(msg->dn),
1295 ldb_errstring(d_state->sam_ctx)));
1296 return NT_STATUS_ACCESS_DENIED;
1298 ldb_transaction_cancel(d_state->sam_ctx);
1299 DEBUG(0,("Failed to create user record %s: %s\n",
1300 ldb_dn_get_linearized(msg->dn),
1301 ldb_errstring(d_state->sam_ctx)));
1302 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1305 a_state = talloc(d_state, struct samr_account_state);
1307 ldb_transaction_cancel(d_state->sam_ctx);
1308 return NT_STATUS_NO_MEMORY;
1310 a_state->sam_ctx = d_state->sam_ctx;
1311 a_state->access_mask = r->in.access_mask;
1312 a_state->domain_state = talloc_reference(a_state, d_state);
1313 a_state->account_dn = talloc_steal(a_state, msg->dn);
1315 /* retrieve the sid and account control bits for the user just created */
1316 ret = gendb_search_dn(d_state->sam_ctx, a_state,
1317 msg->dn, &msgs, attrs);
1320 ldb_transaction_cancel(d_state->sam_ctx);
1321 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1322 ldb_dn_get_linearized(msg->dn)));
1323 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1325 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1327 ldb_transaction_cancel(d_state->sam_ctx);
1328 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1329 ldb_dn_get_linearized(msg->dn)));
1330 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1333 /* Change the account control to be the correct account type.
1334 * The default is for a workstation account */
1335 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1336 user_account_control = (user_account_control &
1337 ~(UF_NORMAL_ACCOUNT |
1338 UF_INTERDOMAIN_TRUST_ACCOUNT |
1339 UF_WORKSTATION_TRUST_ACCOUNT |
1340 UF_SERVER_TRUST_ACCOUNT));
1341 user_account_control |= samdb_acb2uf(r->in.acct_flags);
1344 msg = ldb_msg_new(mem_ctx);
1346 ldb_transaction_cancel(d_state->sam_ctx);
1347 return NT_STATUS_NO_MEMORY;
1350 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1352 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1353 "userAccountControl",
1354 user_account_control) != 0) {
1355 ldb_transaction_cancel(d_state->sam_ctx);
1356 return NT_STATUS_NO_MEMORY;
1359 /* modify the samdb record */
1360 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1362 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1363 ldb_dn_get_linearized(msg->dn),
1364 ldb_errstring(d_state->sam_ctx)));
1365 ldb_transaction_cancel(d_state->sam_ctx);
1367 /* we really need samdb.c to return NTSTATUS */
1368 return NT_STATUS_UNSUCCESSFUL;
1371 ret = ldb_transaction_commit(d_state->sam_ctx);
1373 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1374 ldb_dn_get_linearized(msg->dn),
1375 ldb_errstring(d_state->sam_ctx)));
1376 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1379 a_state->account_name = talloc_steal(a_state, account_name);
1380 if (!a_state->account_name) {
1381 return NT_STATUS_NO_MEMORY;
1384 /* create the policy handle */
1385 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1387 return NT_STATUS_NO_MEMORY;
1390 u_handle->data = talloc_steal(u_handle, a_state);
1392 *r->out.user_handle = u_handle->wire_handle;
1393 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1395 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1397 return NT_STATUS_OK;
1404 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1405 struct samr_CreateUser *r)
1407 struct samr_CreateUser2 r2;
1408 uint32_t access_granted = 0;
1411 /* a simple wrapper around samr_CreateUser2 works nicely */
1412 r2.in.domain_handle = r->in.domain_handle;
1413 r2.in.account_name = r->in.account_name;
1414 r2.in.acct_flags = ACB_NORMAL;
1415 r2.in.access_mask = r->in.access_mask;
1416 r2.out.user_handle = r->out.user_handle;
1417 r2.out.access_granted = &access_granted;
1418 r2.out.rid = r->out.rid;
1420 return samr_CreateUser2(dce_call, mem_ctx, &r2);
1424 samr_EnumDomainUsers
1426 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1427 struct samr_EnumDomainUsers *r)
1429 struct dcesrv_handle *h;
1430 struct samr_domain_state *d_state;
1431 struct ldb_message **res;
1432 int count, i, first;
1433 struct samr_SamEntry *entries;
1434 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1436 *r->out.resume_handle = 0;
1438 r->out.num_entries = 0;
1440 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1444 /* search for all users in this domain. This could possibly be cached and
1445 resumed based on resume_key */
1446 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1447 "objectclass=user");
1449 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1451 if (count == 0 || r->in.max_size == 0) {
1452 return NT_STATUS_OK;
1455 /* convert to SamEntry format */
1456 entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
1458 return NT_STATUS_NO_MEMORY;
1460 for (i=0;i<count;i++) {
1461 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
1462 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
1465 /* sort the results by rid */
1466 qsort(entries, count, sizeof(struct samr_SamEntry),
1467 (comparison_fn_t)compare_SamEntry);
1469 /* find the first entry to return */
1471 first<count && entries[first].idx <= *r->in.resume_handle;
1474 if (first == count) {
1475 return NT_STATUS_OK;
1478 /* return the rest, limit by max_size. Note that we
1479 use the w2k3 element size value of 54 */
1480 r->out.num_entries = count - first;
1481 r->out.num_entries = MIN(r->out.num_entries,
1482 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1484 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1486 return NT_STATUS_NO_MEMORY;
1489 r->out.sam->entries = entries+first;
1490 r->out.sam->count = r->out.num_entries;
1492 if (r->out.num_entries < count - first) {
1493 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1494 return STATUS_MORE_ENTRIES;
1497 return NT_STATUS_OK;
1504 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1505 struct samr_CreateDomAlias *r)
1507 struct samr_domain_state *d_state;
1508 struct samr_account_state *a_state;
1509 struct dcesrv_handle *h;
1510 const char *alias_name, *name;
1511 struct ldb_message *msg;
1512 struct dom_sid *sid;
1513 struct dcesrv_handle *a_handle;
1516 ZERO_STRUCTP(r->out.alias_handle);
1519 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1523 alias_name = r->in.alias_name->string;
1525 if (alias_name == NULL) {
1526 return NT_STATUS_INVALID_PARAMETER;
1529 /* Check if alias already exists */
1530 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1532 "(sAMAccountName=%s)(objectclass=group))",
1533 ldb_binary_encode_string(mem_ctx, alias_name));
1536 return NT_STATUS_ALIAS_EXISTS;
1539 msg = ldb_msg_new(mem_ctx);
1541 return NT_STATUS_NO_MEMORY;
1544 /* add core elements to the ldb_message for the alias */
1545 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1546 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1548 return NT_STATUS_NO_MEMORY;
1551 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1552 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1553 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1555 /* create the alias */
1556 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1560 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1561 return NT_STATUS_ALIAS_EXISTS;
1562 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1563 return NT_STATUS_ACCESS_DENIED;
1565 DEBUG(0,("Failed to create alias record %s: %s\n",
1566 ldb_dn_get_linearized(msg->dn),
1567 ldb_errstring(d_state->sam_ctx)));
1568 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1571 a_state = talloc(d_state, struct samr_account_state);
1573 return NT_STATUS_NO_MEMORY;
1576 a_state->sam_ctx = d_state->sam_ctx;
1577 a_state->access_mask = r->in.access_mask;
1578 a_state->domain_state = talloc_reference(a_state, d_state);
1579 a_state->account_dn = talloc_steal(a_state, msg->dn);
1581 /* retrieve the sid for the alias just created */
1582 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1583 msg->dn, "objectSid", NULL);
1585 a_state->account_name = talloc_strdup(a_state, alias_name);
1586 if (!a_state->account_name) {
1587 return NT_STATUS_NO_MEMORY;
1590 /* create the policy handle */
1591 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1592 if (a_handle == NULL)
1593 return NT_STATUS_NO_MEMORY;
1595 a_handle->data = talloc_steal(a_handle, a_state);
1597 *r->out.alias_handle = a_handle->wire_handle;
1599 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1601 return NT_STATUS_OK;
1606 samr_EnumDomainAliases
1608 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1609 struct samr_EnumDomainAliases *r)
1611 struct dcesrv_handle *h;
1612 struct samr_domain_state *d_state;
1613 struct ldb_message **res;
1614 int ldb_cnt, count, i, first;
1615 struct samr_SamEntry *entries;
1616 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1618 *r->out.resume_handle = 0;
1620 r->out.num_entries = 0;
1622 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1626 /* search for all domain groups in this domain. This could possibly be
1627 cached and resumed based on resume_key */
1628 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1631 d_state->domain_sid,
1632 "(&(|(grouptype=%d)(grouptype=%d)))"
1633 "(objectclass=group))",
1634 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1635 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1636 if (ldb_cnt == -1) {
1637 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1640 return NT_STATUS_OK;
1643 /* convert to SamEntry format */
1644 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1646 return NT_STATUS_NO_MEMORY;
1651 for (i=0;i<ldb_cnt;i++) {
1652 struct dom_sid *alias_sid;
1654 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1657 if (alias_sid == NULL)
1660 entries[count].idx =
1661 alias_sid->sub_auths[alias_sid->num_auths-1];
1662 entries[count].name.string =
1663 samdb_result_string(res[i], "sAMAccountName", "");
1667 /* sort the results by rid */
1668 qsort(entries, count, sizeof(struct samr_SamEntry),
1669 (comparison_fn_t)compare_SamEntry);
1671 /* find the first entry to return */
1673 first<count && entries[first].idx <= *r->in.resume_handle;
1676 if (first == count) {
1677 return NT_STATUS_OK;
1680 r->out.num_entries = count - first;
1681 r->out.num_entries = MIN(r->out.num_entries, 1000);
1683 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1685 return NT_STATUS_NO_MEMORY;
1688 r->out.sam->entries = entries+first;
1689 r->out.sam->count = r->out.num_entries;
1691 if (r->out.num_entries < count - first) {
1692 *r->out.resume_handle =
1693 entries[first+r->out.num_entries-1].idx;
1694 return STATUS_MORE_ENTRIES;
1697 return NT_STATUS_OK;
1702 samr_GetAliasMembership
1704 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1705 struct samr_GetAliasMembership *r)
1707 struct dcesrv_handle *h;
1708 struct samr_domain_state *d_state;
1709 struct ldb_message **res;
1712 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1716 if (r->in.sids->num_sids > 0) {
1718 const char * const attrs[2] = { "objectSid", NULL };
1720 filter = talloc_asprintf(mem_ctx,
1721 "(&(|(grouptype=%d)(grouptype=%d))"
1722 "(objectclass=group)(|",
1723 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1724 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1726 return NT_STATUS_NO_MEMORY;
1728 for (i=0; i<r->in.sids->num_sids; i++) {
1729 const char *memberdn;
1732 samdb_search_string(d_state->sam_ctx,
1733 mem_ctx, NULL, "distinguishedName",
1735 ldap_encode_ndr_dom_sid(mem_ctx,
1736 r->in.sids->sids[i].sid));
1738 if (memberdn == NULL)
1741 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1744 return NT_STATUS_NO_MEMORY;
1747 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1748 d_state->domain_dn, &res, attrs,
1749 d_state->domain_sid, "%s))", filter);
1751 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1754 r->out.rids->count = 0;
1755 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1756 if (r->out.rids->ids == NULL)
1757 return NT_STATUS_NO_MEMORY;
1759 for (i=0; i<count; i++) {
1760 struct dom_sid *alias_sid;
1762 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1764 if (alias_sid == NULL) {
1765 DEBUG(0, ("Could not find objectSid\n"));
1769 r->out.rids->ids[r->out.rids->count] =
1770 alias_sid->sub_auths[alias_sid->num_auths-1];
1771 r->out.rids->count += 1;
1774 return NT_STATUS_OK;
1781 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1782 struct samr_LookupNames *r)
1784 struct dcesrv_handle *h;
1785 struct samr_domain_state *d_state;
1787 NTSTATUS status = NT_STATUS_OK;
1788 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1791 ZERO_STRUCT(r->out.rids);
1792 ZERO_STRUCT(r->out.types);
1794 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1798 if (r->in.num_names == 0) {
1799 return NT_STATUS_OK;
1802 r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1803 r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1804 if (!r->out.rids.ids || !r->out.types.ids) {
1805 return NT_STATUS_NO_MEMORY;
1807 r->out.rids.count = r->in.num_names;
1808 r->out.types.count = r->in.num_names;
1810 for (i=0;i<r->in.num_names;i++) {
1811 struct ldb_message **res;
1812 struct dom_sid *sid;
1813 uint32_t atype, rtype;
1815 r->out.rids.ids[i] = 0;
1816 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1818 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1819 "sAMAccountName=%s",
1820 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1822 status = STATUS_SOME_UNMAPPED;
1826 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1828 status = STATUS_SOME_UNMAPPED;
1832 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1834 status = STATUS_SOME_UNMAPPED;
1838 rtype = samdb_atype_map(atype);
1840 if (rtype == SID_NAME_UNKNOWN) {
1841 status = STATUS_SOME_UNMAPPED;
1845 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1846 r->out.types.ids[i] = rtype;
1857 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1858 struct samr_LookupRids *r)
1860 struct dcesrv_handle *h;
1861 struct samr_domain_state *d_state;
1863 NTSTATUS status = NT_STATUS_OK;
1864 struct lsa_String *names;
1867 ZERO_STRUCT(r->out.names);
1868 ZERO_STRUCT(r->out.types);
1870 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1874 if (r->in.num_rids == 0)
1875 return NT_STATUS_OK;
1877 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1878 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1880 if ((names == NULL) || (ids == NULL))
1881 return NT_STATUS_NO_MEMORY;
1885 for (i=0; i<r->in.num_rids; i++) {
1886 struct ldb_message **res;
1888 const char * const attrs[] = { "sAMAccountType",
1889 "sAMAccountName", NULL };
1891 struct dom_sid *sid;
1893 ids[i] = SID_NAME_UNKNOWN;
1895 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1897 names[i].string = NULL;
1898 status = STATUS_SOME_UNMAPPED;
1902 count = gendb_search(d_state->sam_ctx, mem_ctx,
1903 d_state->domain_dn, &res, attrs,
1905 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1907 names[i].string = NULL;
1908 status = STATUS_SOME_UNMAPPED;
1912 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1915 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1917 status = STATUS_SOME_UNMAPPED;
1921 ids[i] = samdb_atype_map(atype);
1923 if (ids[i] == SID_NAME_UNKNOWN) {
1924 status = STATUS_SOME_UNMAPPED;
1929 r->out.names.names = names;
1930 r->out.names.count = r->in.num_rids;
1932 r->out.types.ids = ids;
1933 r->out.types.count = r->in.num_rids;
1942 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1943 struct samr_OpenGroup *r)
1945 struct samr_domain_state *d_state;
1946 struct samr_account_state *a_state;
1947 struct dcesrv_handle *h;
1948 const char *groupname;
1949 struct dom_sid *sid;
1950 struct ldb_message **msgs;
1951 struct dcesrv_handle *g_handle;
1952 const char * const attrs[2] = { "sAMAccountName", NULL };
1955 ZERO_STRUCTP(r->out.group_handle);
1957 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1961 /* form the group SID */
1962 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1964 return NT_STATUS_NO_MEMORY;
1967 /* search for the group record */
1968 ret = gendb_search(d_state->sam_ctx,
1969 mem_ctx, d_state->domain_dn, &msgs, attrs,
1970 "(&(objectSid=%s)(objectclass=group)"
1972 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1973 GTYPE_SECURITY_GLOBAL_GROUP);
1975 return NT_STATUS_NO_SUCH_GROUP;
1978 DEBUG(0,("Found %d records matching sid %s\n",
1979 ret, dom_sid_string(mem_ctx, sid)));
1980 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1983 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1984 if (groupname == NULL) {
1985 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1986 dom_sid_string(mem_ctx, sid)));
1987 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1990 a_state = talloc(d_state, struct samr_account_state);
1992 return NT_STATUS_NO_MEMORY;
1994 a_state->sam_ctx = d_state->sam_ctx;
1995 a_state->access_mask = r->in.access_mask;
1996 a_state->domain_state = talloc_reference(a_state, d_state);
1997 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1998 a_state->account_sid = talloc_steal(a_state, sid);
1999 a_state->account_name = talloc_strdup(a_state, groupname);
2000 if (!a_state->account_name) {
2001 return NT_STATUS_NO_MEMORY;
2004 /* create the policy handle */
2005 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2007 return NT_STATUS_NO_MEMORY;
2010 g_handle->data = talloc_steal(g_handle, a_state);
2012 *r->out.group_handle = g_handle->wire_handle;
2014 return NT_STATUS_OK;
2020 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2021 struct samr_QueryGroupInfo *r)
2023 struct dcesrv_handle *h;
2024 struct samr_account_state *a_state;
2025 struct ldb_message *msg, **res;
2026 const char * const attrs[4] = { "sAMAccountName", "description",
2027 "numMembers", NULL };
2032 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2036 /* pull all the group attributes */
2037 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2038 a_state->account_dn, &res, attrs);
2040 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2044 /* allocate the info structure */
2045 r->out.info = talloc(mem_ctx, union samr_GroupInfo);
2046 if (r->out.info == NULL) {
2047 return NT_STATUS_NO_MEMORY;
2049 ZERO_STRUCTP(r->out.info);
2051 /* Fill in the level */
2052 switch (r->in.level) {
2054 QUERY_STRING(msg, all.name.string, "sAMAccountName");
2055 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2056 QUERY_UINT (msg, all.num_members, "numMembers")
2057 QUERY_STRING(msg, all.description.string, "description");
2060 QUERY_STRING(msg, name.string, "sAMAccountName");
2062 case GROUPINFOATTRIBUTES:
2063 r->out.info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2065 case GROUPINFODESCRIPTION:
2066 QUERY_STRING(msg, description.string, "description");
2069 QUERY_STRING(msg, all2.name.string, "sAMAccountName");
2070 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2071 QUERY_UINT (msg, all2.num_members, "numMembers")
2072 QUERY_STRING(msg, all2.description.string, "description");
2076 return NT_STATUS_INVALID_INFO_CLASS;
2079 return NT_STATUS_OK;
2086 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2087 struct samr_SetGroupInfo *r)
2089 struct dcesrv_handle *h;
2090 struct samr_account_state *g_state;
2091 struct ldb_message *msg;
2092 struct ldb_context *sam_ctx;
2095 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2098 sam_ctx = g_state->sam_ctx;
2100 msg = ldb_msg_new(mem_ctx);
2102 return NT_STATUS_NO_MEMORY;
2105 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2107 return NT_STATUS_NO_MEMORY;
2110 switch (r->in.level) {
2111 case GROUPINFODESCRIPTION:
2112 SET_STRING(msg, description.string, "description");
2115 /* On W2k3 this does not change the name, it changes the
2116 * sAMAccountName attribute */
2117 SET_STRING(msg, name.string, "sAMAccountName");
2119 case GROUPINFOATTRIBUTES:
2120 /* This does not do anything obviously visible in W2k3 LDAP */
2121 return NT_STATUS_OK;
2123 return NT_STATUS_INVALID_INFO_CLASS;
2126 /* modify the samdb record */
2127 ret = samdb_replace(g_state->sam_ctx, mem_ctx, msg);
2129 /* we really need samdb.c to return NTSTATUS */
2130 return NT_STATUS_UNSUCCESSFUL;
2133 return NT_STATUS_OK;
2140 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2141 struct samr_AddGroupMember *r)
2143 struct dcesrv_handle *h;
2144 struct samr_account_state *a_state;
2145 struct samr_domain_state *d_state;
2146 struct ldb_message *mod;
2147 struct dom_sid *membersid;
2148 const char *memberdn;
2149 struct ldb_result *res;
2150 const char * const attrs[] = { NULL };
2153 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2156 d_state = a_state->domain_state;
2158 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2159 if (membersid == NULL)
2160 return NT_STATUS_NO_MEMORY;
2162 /* In native mode, AD can also nest domain groups. Not sure yet
2163 * whether this is also available via RPC. */
2164 ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2165 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2166 "(&(objectSid=%s)(objectclass=user))",
2167 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2170 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2173 if (res->count == 0) {
2174 return NT_STATUS_NO_SUCH_USER;
2177 if (res->count > 1) {
2178 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2181 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2183 if (memberdn == NULL)
2184 return NT_STATUS_NO_MEMORY;
2186 mod = ldb_msg_new(mem_ctx);
2188 return NT_STATUS_NO_MEMORY;
2191 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2193 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2195 return NT_STATUS_UNSUCCESSFUL;
2197 ret = samdb_modify(a_state->sam_ctx, mem_ctx, mod);
2200 return NT_STATUS_OK;
2201 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2202 return NT_STATUS_MEMBER_IN_GROUP;
2203 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2204 return NT_STATUS_ACCESS_DENIED;
2206 return NT_STATUS_UNSUCCESSFUL;
2213 samr_DeleteDomainGroup
2215 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2216 struct samr_DeleteDomainGroup *r)
2218 struct dcesrv_handle *h;
2219 struct samr_account_state *a_state;
2222 *r->out.group_handle = *r->in.group_handle;
2224 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2228 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2230 return NT_STATUS_UNSUCCESSFUL;
2233 ZERO_STRUCTP(r->out.group_handle);
2235 return NT_STATUS_OK;
2240 samr_DeleteGroupMember
2242 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2243 struct samr_DeleteGroupMember *r)
2245 struct dcesrv_handle *h;
2246 struct samr_account_state *a_state;
2247 struct samr_domain_state *d_state;
2248 struct ldb_message *mod;
2249 struct dom_sid *membersid;
2250 const char *memberdn;
2251 struct ldb_result *res;
2252 const char * const attrs[] = { NULL };
2255 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2258 d_state = a_state->domain_state;
2260 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2261 if (membersid == NULL)
2262 return NT_STATUS_NO_MEMORY;
2264 /* In native mode, AD can also nest domain groups. Not sure yet
2265 * whether this is also available via RPC. */
2266 ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2267 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2268 "(&(objectSid=%s)(objectclass=user))",
2269 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2272 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2275 if (res->count == 0) {
2276 return NT_STATUS_NO_SUCH_USER;
2279 if (res->count > 1) {
2280 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2283 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2285 if (memberdn == NULL)
2286 return NT_STATUS_NO_MEMORY;
2288 mod = ldb_msg_new(mem_ctx);
2290 return NT_STATUS_NO_MEMORY;
2293 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2295 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2297 return NT_STATUS_NO_MEMORY;
2300 ret = samdb_modify(a_state->sam_ctx, mem_ctx, mod);
2303 return NT_STATUS_OK;
2304 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2305 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2306 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2307 return NT_STATUS_ACCESS_DENIED;
2309 return NT_STATUS_UNSUCCESSFUL;
2316 samr_QueryGroupMember
2318 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2319 struct samr_QueryGroupMember *r)
2321 struct dcesrv_handle *h;
2322 struct samr_account_state *a_state;
2323 struct ldb_message **res;
2324 struct ldb_message_element *el;
2325 struct samr_RidTypeArray *array;
2326 const char * const attrs[2] = { "member", NULL };
2329 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2333 /* pull the member attribute */
2334 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2335 a_state->account_dn, &res, attrs);
2338 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2341 array = talloc(mem_ctx, struct samr_RidTypeArray);
2344 return NT_STATUS_NO_MEMORY;
2346 ZERO_STRUCTP(array);
2348 el = ldb_msg_find_element(res[0], "member");
2353 array->count = el->num_values;
2355 array->rids = talloc_array(mem_ctx, uint32_t,
2357 if (array->rids == NULL)
2358 return NT_STATUS_NO_MEMORY;
2360 array->types = talloc_array(mem_ctx, uint32_t,
2362 if (array->types == NULL)
2363 return NT_STATUS_NO_MEMORY;
2365 for (i=0; i<el->num_values; i++) {
2366 struct ldb_message **res2;
2367 const char * const attrs2[2] = { "objectSid", NULL };
2368 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2369 ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2372 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2375 samdb_result_rid_from_sid(mem_ctx, res2[0],
2378 if (array->rids[i] == 0)
2379 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2381 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2385 r->out.rids = array;
2387 return NT_STATUS_OK;
2392 samr_SetMemberAttributesOfGroup
2394 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2395 struct samr_SetMemberAttributesOfGroup *r)
2397 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2404 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2405 struct samr_OpenAlias *r)
2407 struct samr_domain_state *d_state;
2408 struct samr_account_state *a_state;
2409 struct dcesrv_handle *h;
2410 const char *alias_name;
2411 struct dom_sid *sid;
2412 struct ldb_message **msgs;
2413 struct dcesrv_handle *g_handle;
2414 const char * const attrs[2] = { "sAMAccountName", NULL };
2417 ZERO_STRUCTP(r->out.alias_handle);
2419 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2423 /* form the alias SID */
2424 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2426 return NT_STATUS_NO_MEMORY;
2428 /* search for the group record */
2429 ret = gendb_search(d_state->sam_ctx,
2430 mem_ctx, d_state->domain_dn, &msgs, attrs,
2431 "(&(objectSid=%s)(objectclass=group)"
2432 "(|(grouptype=%d)(grouptype=%d)))",
2433 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2434 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2435 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2437 return NT_STATUS_NO_SUCH_ALIAS;
2440 DEBUG(0,("Found %d records matching sid %s\n",
2441 ret, dom_sid_string(mem_ctx, sid)));
2442 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2445 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2446 if (alias_name == NULL) {
2447 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2448 dom_sid_string(mem_ctx, sid)));
2449 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2452 a_state = talloc(d_state, struct samr_account_state);
2454 return NT_STATUS_NO_MEMORY;
2456 a_state->sam_ctx = d_state->sam_ctx;
2457 a_state->access_mask = r->in.access_mask;
2458 a_state->domain_state = talloc_reference(a_state, d_state);
2459 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2460 a_state->account_sid = talloc_steal(a_state, sid);
2461 a_state->account_name = talloc_strdup(a_state, alias_name);
2462 if (!a_state->account_name) {
2463 return NT_STATUS_NO_MEMORY;
2466 /* create the policy handle */
2467 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2469 return NT_STATUS_NO_MEMORY;
2472 g_handle->data = talloc_steal(g_handle, a_state);
2474 *r->out.alias_handle = g_handle->wire_handle;
2476 return NT_STATUS_OK;
2483 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2484 struct samr_QueryAliasInfo *r)
2486 struct dcesrv_handle *h;
2487 struct samr_account_state *a_state;
2488 struct ldb_message *msg, **res;
2489 const char * const attrs[4] = { "sAMAccountName", "description",
2490 "numMembers", NULL };
2495 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2499 /* pull all the alias attributes */
2500 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2501 a_state->account_dn ,&res, attrs);
2503 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2507 /* allocate the info structure */
2508 r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2509 if (r->out.info == NULL) {
2510 return NT_STATUS_NO_MEMORY;
2512 ZERO_STRUCTP(r->out.info);
2514 switch(r->in.level) {
2516 QUERY_STRING(msg, all.name.string, "sAMAccountName");
2517 QUERY_UINT (msg, all.num_members, "numMembers");
2518 QUERY_STRING(msg, all.description.string, "description");
2521 QUERY_STRING(msg, name.string, "sAMAccountName");
2523 case ALIASINFODESCRIPTION:
2524 QUERY_STRING(msg, description.string, "description");
2528 return NT_STATUS_INVALID_INFO_CLASS;
2531 return NT_STATUS_OK;
2538 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2539 struct samr_SetAliasInfo *r)
2541 struct dcesrv_handle *h;
2542 struct samr_account_state *a_state;
2543 struct ldb_message *msg;
2544 struct ldb_context *sam_ctx;
2547 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2550 sam_ctx = a_state->sam_ctx;
2552 msg = ldb_msg_new(mem_ctx);
2554 return NT_STATUS_NO_MEMORY;
2557 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2559 return NT_STATUS_NO_MEMORY;
2562 switch (r->in.level) {
2563 case ALIASINFODESCRIPTION:
2564 SET_STRING(msg, description.string, "description");
2567 /* On W2k3 this does not change the name, it changes the
2568 * sAMAccountName attribute */
2569 SET_STRING(msg, name.string, "sAMAccountName");
2572 return NT_STATUS_INVALID_INFO_CLASS;
2575 /* modify the samdb record */
2576 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2578 /* we really need samdb.c to return NTSTATUS */
2579 return NT_STATUS_UNSUCCESSFUL;
2582 return NT_STATUS_OK;
2589 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2590 struct samr_DeleteDomAlias *r)
2592 struct dcesrv_handle *h;
2593 struct samr_account_state *a_state;
2596 *r->out.alias_handle = *r->in.alias_handle;
2598 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2602 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2604 return NT_STATUS_UNSUCCESSFUL;
2607 ZERO_STRUCTP(r->out.alias_handle);
2609 return NT_STATUS_OK;
2616 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2617 struct samr_AddAliasMember *r)
2619 struct dcesrv_handle *h;
2620 struct samr_account_state *a_state;
2621 struct samr_domain_state *d_state;
2622 struct ldb_message *mod;
2623 struct ldb_message **msgs;
2624 const char * const attrs[] = { NULL };
2625 struct ldb_dn *memberdn = NULL;
2629 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2632 d_state = a_state->domain_state;
2634 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2635 &msgs, attrs, "(objectsid=%s)",
2636 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2639 memberdn = msgs[0]->dn;
2640 } else if (ret > 1) {
2641 DEBUG(0,("Found %d records matching sid %s\n",
2642 ret, dom_sid_string(mem_ctx, r->in.sid)));
2643 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2644 } else if (ret == 0) {
2645 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx,
2646 r->in.sid, &memberdn);
2647 if (!NT_STATUS_IS_OK(status)) {
2651 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2654 if (memberdn == NULL) {
2655 DEBUG(0, ("Could not find memberdn\n"));
2656 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2659 mod = ldb_msg_new(mem_ctx);
2661 return NT_STATUS_NO_MEMORY;
2664 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2666 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2667 ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2668 return NT_STATUS_UNSUCCESSFUL;
2670 if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2671 return NT_STATUS_UNSUCCESSFUL;
2673 return NT_STATUS_OK;
2678 samr_DeleteAliasMember
2680 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2681 struct samr_DeleteAliasMember *r)
2683 struct dcesrv_handle *h;
2684 struct samr_account_state *a_state;
2685 struct samr_domain_state *d_state;
2686 struct ldb_message *mod;
2687 const char *memberdn;
2689 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2692 d_state = a_state->domain_state;
2694 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2695 "distinguishedName", "(objectSid=%s)",
2696 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2698 if (memberdn == NULL)
2699 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2701 mod = ldb_msg_new(mem_ctx);
2703 return NT_STATUS_NO_MEMORY;
2706 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2708 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2710 return NT_STATUS_UNSUCCESSFUL;
2712 if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2713 return NT_STATUS_UNSUCCESSFUL;
2715 return NT_STATUS_OK;
2720 samr_GetMembersInAlias
2722 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2723 struct samr_GetMembersInAlias *r)
2725 struct dcesrv_handle *h;
2726 struct samr_account_state *a_state;
2727 struct samr_domain_state *d_state;
2728 struct ldb_message **msgs;
2729 struct lsa_SidPtr *sids;
2730 struct ldb_message_element *el;
2731 const char * const attrs[2] = { "member", NULL};
2734 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2737 d_state = a_state->domain_state;
2739 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2740 a_state->account_dn, &msgs, attrs);
2743 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2745 r->out.sids->num_sids = 0;
2746 r->out.sids->sids = NULL;
2748 el = ldb_msg_find_element(msgs[0], "member");
2753 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2757 return NT_STATUS_NO_MEMORY;
2759 for (i=0; i<el->num_values; i++) {
2760 struct ldb_message **msgs2;
2761 const char * const attrs2[2] = { "objectSid", NULL };
2762 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2763 ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2766 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2768 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2771 if (sids[i].sid == NULL)
2772 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2774 r->out.sids->num_sids = el->num_values;
2775 r->out.sids->sids = sids;
2778 return NT_STATUS_OK;
2784 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2785 struct samr_OpenUser *r)
2787 struct samr_domain_state *d_state;
2788 struct samr_account_state *a_state;
2789 struct dcesrv_handle *h;
2790 const char *account_name;
2791 struct dom_sid *sid;
2792 struct ldb_message **msgs;
2793 struct dcesrv_handle *u_handle;
2794 const char * const attrs[2] = { "sAMAccountName", NULL };
2797 ZERO_STRUCTP(r->out.user_handle);
2799 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2803 /* form the users SID */
2804 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2806 return NT_STATUS_NO_MEMORY;
2809 /* search for the user record */
2810 ret = gendb_search(d_state->sam_ctx,
2811 mem_ctx, d_state->domain_dn, &msgs, attrs,
2812 "(&(objectSid=%s)(objectclass=user))",
2813 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2815 return NT_STATUS_NO_SUCH_USER;
2818 DEBUG(0,("Found %d records matching sid %s\n", ret,
2819 dom_sid_string(mem_ctx, sid)));
2820 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2823 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2824 if (account_name == NULL) {
2825 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2826 dom_sid_string(mem_ctx, sid)));
2827 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2830 a_state = talloc(mem_ctx, struct samr_account_state);
2832 return NT_STATUS_NO_MEMORY;
2834 a_state->sam_ctx = d_state->sam_ctx;
2835 a_state->access_mask = r->in.access_mask;
2836 a_state->domain_state = talloc_reference(a_state, d_state);
2837 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2838 a_state->account_sid = talloc_steal(a_state, sid);
2839 a_state->account_name = talloc_strdup(a_state, account_name);
2840 if (!a_state->account_name) {
2841 return NT_STATUS_NO_MEMORY;
2844 /* create the policy handle */
2845 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2847 return NT_STATUS_NO_MEMORY;
2850 u_handle->data = talloc_steal(u_handle, a_state);
2852 *r->out.user_handle = u_handle->wire_handle;
2854 return NT_STATUS_OK;
2862 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2863 struct samr_DeleteUser *r)
2865 struct dcesrv_handle *h;
2866 struct samr_account_state *a_state;
2869 *r->out.user_handle = *r->in.user_handle;
2871 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2875 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2877 return NT_STATUS_UNSUCCESSFUL;
2880 ZERO_STRUCTP(r->out.user_handle);
2882 return NT_STATUS_OK;
2889 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2890 struct samr_QueryUserInfo *r)
2892 struct dcesrv_handle *h;
2893 struct samr_account_state *a_state;
2894 struct ldb_message *msg, **res;
2896 struct ldb_context *sam_ctx;
2898 const char * const *attrs = NULL;
2902 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2905 sam_ctx = a_state->sam_ctx;
2907 /* fill in the reply */
2908 switch (r->in.level) {
2911 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2912 "primaryGroupID", "description",
2919 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2925 static const char * const attrs2[] = {"sAMAccountName",
2940 "userAccountControl", NULL};
2946 static const char * const attrs2[] = {"logonHours", NULL};
2952 static const char * const attrs2[] = {"sAMAccountName",
2969 "userAccountControl",
2976 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
2982 static const char * const attrs2[] = {"sAMAccountName", NULL};
2988 static const char * const attrs2[] = {"displayName", NULL};
2994 static const char * const attrs2[] = {"primaryGroupID", NULL};
3000 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3006 static const char * const attrs2[] = {"scriptPath", NULL};
3012 static const char * const attrs2[] = {"profilePath", NULL};
3018 static const char * const attrs2[] = {"description", NULL};
3024 static const char * const attrs2[] = {"userWorkstations", NULL};
3030 static const char * const attrs2[] = {"userAccountControl", NULL};
3036 static const char * const attrs2[] = {"accountExpires", NULL};
3042 static const char * const attrs2[] = {"userParameters", NULL};
3048 static const char * const attrs2[] = {"lastLogon",
3064 "userAccountControl",
3076 /* pull all the user attributes */
3077 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3078 a_state->account_dn ,&res, attrs);
3080 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3084 /* allocate the info structure */
3085 r->out.info = talloc(mem_ctx, union samr_UserInfo);
3086 if (r->out.info == NULL) {
3087 return NT_STATUS_NO_MEMORY;
3089 ZERO_STRUCTP(r->out.info);
3091 /* fill in the reply */
3092 switch (r->in.level) {
3094 QUERY_STRING(msg, info1.account_name.string, "sAMAccountName");
3095 QUERY_STRING(msg, info1.full_name.string, "displayName");
3096 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3097 QUERY_STRING(msg, info1.description.string, "description");
3098 QUERY_STRING(msg, info1.comment.string, "comment");
3102 QUERY_STRING(msg, info2.comment.string, "comment");
3103 QUERY_UINT (msg, info2.country_code, "countryCode");
3104 QUERY_UINT (msg, info2.code_page, "codePage");
3108 QUERY_STRING(msg, info3.account_name.string, "sAMAccountName");
3109 QUERY_STRING(msg, info3.full_name.string, "displayName");
3110 QUERY_RID (msg, info3.rid, "objectSid");
3111 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3112 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
3113 QUERY_STRING(msg, info3.home_drive.string, "homeDrive");
3114 QUERY_STRING(msg, info3.logon_script.string, "scriptPath");
3115 QUERY_STRING(msg, info3.profile_path.string, "profilePath");
3116 QUERY_STRING(msg, info3.workstations.string, "userWorkstations");
3117 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
3118 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
3119 QUERY_NTTIME(msg, info3.last_password_change, "pwdLastSet");
3120 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3121 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3122 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3123 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3124 QUERY_UINT (msg, info3.logon_count, "logonCount");
3125 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3129 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3133 QUERY_STRING(msg, info5.account_name.string, "sAMAccountName");
3134 QUERY_STRING(msg, info5.full_name.string, "displayName");
3135 QUERY_RID (msg, info5.rid, "objectSid");
3136 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3137 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
3138 QUERY_STRING(msg, info5.home_drive.string, "homeDrive");
3139 QUERY_STRING(msg, info5.logon_script.string, "scriptPath");
3140 QUERY_STRING(msg, info5.profile_path.string, "profilePath");
3141 QUERY_STRING(msg, info5.description.string, "description");
3142 QUERY_STRING(msg, info5.workstations.string, "userWorkstations");
3143 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
3144 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
3145 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3146 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3147 QUERY_UINT (msg, info5.logon_count, "logonCount");
3148 QUERY_NTTIME(msg, info5.last_password_change, "pwdLastSet");
3149 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
3150 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3154 QUERY_STRING(msg, info6.account_name.string, "sAMAccountName");
3155 QUERY_STRING(msg, info6.full_name.string, "displayName");
3159 QUERY_STRING(msg, info7.account_name.string, "sAMAccountName");
3163 QUERY_STRING(msg, info8.full_name.string, "displayName");
3167 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3171 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
3172 QUERY_STRING(msg, info10.home_drive.string, "homeDrive");
3176 QUERY_STRING(msg, info11.logon_script.string, "scriptPath");
3180 QUERY_STRING(msg, info12.profile_path.string, "profilePath");
3184 QUERY_STRING(msg, info13.description.string, "description");
3188 QUERY_STRING(msg, info14.workstations.string, "userWorkstations");
3192 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3196 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
3199 QUERY_STRING(msg, info20.parameters.string, "userParameters");
3203 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
3204 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
3205 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
3206 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
3207 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3208 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3209 QUERY_STRING(msg, info21.account_name.string, "sAMAccountName");
3210 QUERY_STRING(msg, info21.full_name.string, "displayName");
3211 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
3212 QUERY_STRING(msg, info21.home_drive.string, "homeDrive");
3213 QUERY_STRING(msg, info21.logon_script.string, "scriptPath");
3214 QUERY_STRING(msg, info21.profile_path.string, "profilePath");
3215 QUERY_STRING(msg, info21.description.string, "description");
3216 QUERY_STRING(msg, info21.workstations.string, "userWorkstations");
3217 QUERY_STRING(msg, info21.comment.string, "comment");
3218 QUERY_STRING(msg, info21.parameters.string, "userParameters");
3219 QUERY_RID (msg, info21.rid, "objectSid");
3220 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3221 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3222 r->out.info->info21.fields_present = 0x00FFFFFF;
3223 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3224 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3225 QUERY_UINT (msg, info21.logon_count, "logonCount");
3226 QUERY_UINT (msg, info21.country_code, "countryCode");
3227 QUERY_UINT (msg, info21.code_page, "codePage");
3233 return NT_STATUS_INVALID_INFO_CLASS;
3236 return NT_STATUS_OK;
3243 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3244 struct samr_SetUserInfo *r)
3246 struct dcesrv_handle *h;
3247 struct samr_account_state *a_state;
3248 struct ldb_message *msg;
3250 NTSTATUS status = NT_STATUS_OK;
3251 struct ldb_context *sam_ctx;
3253 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3256 sam_ctx = a_state->sam_ctx;
3258 msg = ldb_msg_new(mem_ctx);
3260 return NT_STATUS_NO_MEMORY;
3263 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3265 return NT_STATUS_NO_MEMORY;
3268 switch (r->in.level) {
3270 SET_STRING(msg, info2.comment.string, "comment");
3271 SET_UINT (msg, info2.country_code, "countryCode");
3272 SET_UINT (msg, info2.code_page, "codePage");
3276 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3280 SET_STRING(msg, info6.full_name.string, "displayName");
3284 SET_STRING(msg, info7.account_name.string, "samAccountName");
3288 SET_STRING(msg, info8.full_name.string, "displayName");
3292 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3296 SET_STRING(msg, info10.home_directory.string, "homeDirectory");
3297 SET_STRING(msg, info10.home_drive.string, "homeDrive");
3301 SET_STRING(msg, info11.logon_script.string, "scriptPath");
3305 SET_STRING(msg, info12.profile_path.string, "profilePath");
3309 SET_STRING(msg, info13.description.string, "description");
3313 SET_STRING(msg, info14.workstations.string, "userWorkstations");
3317 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3321 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3325 SET_STRING(msg, info20.parameters.string, "userParameters");
3329 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3330 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3331 SET_STRING(msg, info21.account_name.string, "samAccountName");
3332 IFSET(SAMR_FIELD_FULL_NAME)
3333 SET_STRING(msg, info21.full_name.string, "displayName");
3334 IFSET(SAMR_FIELD_DESCRIPTION)
3335 SET_STRING(msg, info21.description.string, "description");
3336 IFSET(SAMR_FIELD_COMMENT)
3337 SET_STRING(msg, info21.comment.string, "comment");
3338 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3339 SET_STRING(msg, info21.logon_script.string, "scriptPath");
3340 IFSET(SAMR_FIELD_PROFILE_PATH)
3341 SET_STRING(msg, info21.profile_path.string, "profilePath");
3342 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3343 SET_STRING(msg, info21.home_directory.string, "homeDirectory");
3344 IFSET(SAMR_FIELD_HOME_DRIVE)
3345 SET_STRING(msg, info21.home_drive.string, "homeDrive");
3346 IFSET(SAMR_FIELD_WORKSTATIONS)
3347 SET_STRING(msg, info21.workstations.string, "userWorkstations");
3348 IFSET(SAMR_FIELD_LOGON_HOURS)
3349 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3350 IFSET(SAMR_FIELD_ACCT_FLAGS)
3351 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3352 IFSET(SAMR_FIELD_PARAMETERS)
3353 SET_STRING(msg, info21.parameters.string, "userParameters");
3354 IFSET(SAMR_FIELD_COUNTRY_CODE)
3355 SET_UINT (msg, info21.country_code, "countryCode");
3356 IFSET(SAMR_FIELD_CODE_PAGE)
3357 SET_UINT (msg, info21.code_page, "codePage");
3360 /* Any reason the rest of these can't be set? */
3365 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3366 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3367 SET_STRING(msg, info23.info.account_name.string, "samAccountName");
3368 IFSET(SAMR_FIELD_FULL_NAME)
3369 SET_STRING(msg, info23.info.full_name.string, "displayName");
3370 IFSET(SAMR_FIELD_DESCRIPTION)
3371 SET_STRING(msg, info23.info.description.string, "description");
3372 IFSET(SAMR_FIELD_COMMENT)
3373 SET_STRING(msg, info23.info.comment.string, "comment");
3374 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3375 SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
3376 IFSET(SAMR_FIELD_PROFILE_PATH)
3377 SET_STRING(msg, info23.info.profile_path.string, "profilePath");
3378 IFSET(SAMR_FIELD_WORKSTATIONS)
3379 SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
3380 IFSET(SAMR_FIELD_LOGON_HOURS)
3381 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3382 IFSET(SAMR_FIELD_ACCT_FLAGS)
3383 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3384 IFSET(SAMR_FIELD_PARAMETERS)
3385 SET_STRING(msg, info23.info.parameters.string, "userParameters");
3386 IFSET(SAMR_FIELD_COUNTRY_CODE)
3387 SET_UINT (msg, info23.info.country_code, "countryCode");
3388 IFSET(SAMR_FIELD_CODE_PAGE)
3389 SET_UINT (msg, info23.info.code_page, "codePage");
3390 IFSET(SAMR_FIELD_PASSWORD) {
3391 status = samr_set_password(dce_call,
3393 a_state->account_dn,
3394 a_state->domain_state->domain_dn,
3396 &r->in.info->info23.password);
3397 } else IFSET(SAMR_FIELD_PASSWORD2) {
3398 status = samr_set_password(dce_call,
3400 a_state->account_dn,
3401 a_state->domain_state->domain_dn,
3403 &r->in.info->info23.password);
3408 /* the set password levels are handled separately */
3410 status = samr_set_password(dce_call,
3412 a_state->account_dn,
3413 a_state->domain_state->domain_dn,
3415 &r->in.info->info24.password);
3419 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3420 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3421 SET_STRING(msg, info25.info.account_name.string, "samAccountName");
3422 IFSET(SAMR_FIELD_FULL_NAME)
3423 SET_STRING(msg, info25.info.full_name.string, "displayName");
3424 IFSET(SAMR_FIELD_DESCRIPTION)
3425 SET_STRING(msg, info25.info.description.string, "description");
3426 IFSET(SAMR_FIELD_COMMENT)
3427 SET_STRING(msg, info25.info.comment.string, "comment");
3428 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3429 SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
3430 IFSET(SAMR_FIELD_PROFILE_PATH)
3431 SET_STRING(msg, info25.info.profile_path.string, "profilePath");
3432 IFSET(SAMR_FIELD_WORKSTATIONS)
3433 SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
3434 IFSET(SAMR_FIELD_LOGON_HOURS)
3435 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3436 IFSET(SAMR_FIELD_ACCT_FLAGS)
3437 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3438 IFSET(SAMR_FIELD_PARAMETERS)
3439 SET_STRING(msg, info25.info.parameters.string, "userParameters");
3440 IFSET(SAMR_FIELD_COUNTRY_CODE)
3441 SET_UINT (msg, info25.info.country_code, "countryCode");
3442 IFSET(SAMR_FIELD_CODE_PAGE)
3443 SET_UINT (msg, info25.info.code_page, "codePage");
3444 IFSET(SAMR_FIELD_PASSWORD) {
3445 status = samr_set_password_ex(dce_call,
3447 a_state->account_dn,
3448 a_state->domain_state->domain_dn,
3450 &r->in.info->info25.password);
3451 } else IFSET(SAMR_FIELD_PASSWORD2) {
3452 status = samr_set_password_ex(dce_call,
3454 a_state->account_dn,
3455 a_state->domain_state->domain_dn,
3457 &r->in.info->info25.password);
3462 /* the set password levels are handled separately */
3464 status = samr_set_password_ex(dce_call,
3466 a_state->account_dn,
3467 a_state->domain_state->domain_dn,
3469 &r->in.info->info26.password);
3474 /* many info classes are not valid for SetUserInfo */
3475 return NT_STATUS_INVALID_INFO_CLASS;
3478 if (!NT_STATUS_IS_OK(status)) {
3482 /* modify the samdb record */
3483 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
3485 DEBUG(1,("Failed to modify record %s: %s\n",
3486 ldb_dn_get_linearized(a_state->account_dn),
3487 ldb_errstring(a_state->sam_ctx)));
3489 /* we really need samdb.c to return NTSTATUS */
3490 return NT_STATUS_UNSUCCESSFUL;
3493 return NT_STATUS_OK;
3498 samr_GetGroupsForUser
3500 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3501 struct samr_GetGroupsForUser *r)
3503 struct dcesrv_handle *h;
3504 struct samr_account_state *a_state;
3505 struct samr_domain_state *d_state;
3506 struct ldb_message **res;
3507 const char * const attrs[2] = { "objectSid", NULL };
3508 struct samr_RidWithAttributeArray *array;
3511 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3514 d_state = a_state->domain_state;
3516 count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3517 attrs, d_state->domain_sid,
3518 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3519 ldb_dn_get_linearized(a_state->account_dn),
3520 GTYPE_SECURITY_GLOBAL_GROUP);
3522 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3524 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3526 return NT_STATUS_NO_MEMORY;
3533 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3536 if (array->rids == NULL)
3537 return NT_STATUS_NO_MEMORY;
3539 for (i=0; i<count; i++) {
3540 struct dom_sid *group_sid;
3542 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3544 if (group_sid == NULL) {
3545 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3549 array->rids[array->count].rid =
3550 group_sid->sub_auths[group_sid->num_auths-1];
3551 array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3556 r->out.rids = array;
3558 return NT_STATUS_OK;
3563 samr_QueryDisplayInfo
3565 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3566 struct samr_QueryDisplayInfo *r)
3568 struct dcesrv_handle *h;
3569 struct samr_domain_state *d_state;
3570 struct ldb_message **res;
3571 int ldb_cnt, count, i;
3572 const char * const attrs[4] = { "objectSid", "sAMAccountName",
3573 "description", NULL };
3574 struct samr_DispEntryFull *entriesFull = NULL;
3575 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3576 struct samr_DispEntryAscii *entriesAscii = NULL;
3577 struct samr_DispEntryGeneral * entriesGeneral = NULL;
3580 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3584 switch (r->in.level) {
3587 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3588 "(sAMAccountType=%u))",
3589 ATYPE_NORMAL_ACCOUNT);
3592 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3593 "(sAMAccountType=%u))",
3594 ATYPE_WORKSTATION_TRUST);
3598 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3599 "(objectclass=group))",
3600 GTYPE_SECURITY_GLOBAL_GROUP);
3603 return NT_STATUS_INVALID_INFO_CLASS;
3606 /* search for all requested objects in this domain. This could
3607 possibly be cached and resumed based on resume_key */
3608 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3609 d_state->domain_dn, &res, attrs,
3610 d_state->domain_sid, "%s", filter);
3611 if (ldb_cnt == -1) {
3612 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3614 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3615 return NT_STATUS_OK;
3618 switch (r->in.level) {
3620 entriesGeneral = talloc_array(mem_ctx,
3621 struct samr_DispEntryGeneral,
3625 entriesFull = talloc_array(mem_ctx,
3626 struct samr_DispEntryFull,
3630 entriesFullGroup = talloc_array(mem_ctx,
3631 struct samr_DispEntryFullGroup,
3636 entriesAscii = talloc_array(mem_ctx,
3637 struct samr_DispEntryAscii,
3642 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3643 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3644 return NT_STATUS_NO_MEMORY;
3648 for (i=0; i<ldb_cnt; i++) {
3649 struct dom_sid *objectsid;
3651 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3653 if (objectsid == NULL)
3656 switch(r->in.level) {
3658 entriesGeneral[count].idx = count + 1;
3659 entriesGeneral[count].rid =
3660 objectsid->sub_auths[objectsid->num_auths-1];
3661 entriesGeneral[count].acct_flags =
3662 samdb_result_acct_flags(res[i],
3663 "userAccountControl");
3664 entriesGeneral[count].account_name.string =
3665 samdb_result_string(res[i],
3666 "sAMAccountName", "");
3667 entriesGeneral[count].full_name.string =
3668 samdb_result_string(res[i], "displayName", "");
3669 entriesGeneral[count].description.string =
3670 samdb_result_string(res[i], "description", "");
3673 entriesFull[count].idx = count + 1;
3674 entriesFull[count].rid =
3675 objectsid->sub_auths[objectsid->num_auths-1];
3676 entriesFull[count].acct_flags =
3677 samdb_result_acct_flags(res[i],
3678 "userAccountControl");
3679 entriesFull[count].account_name.string =
3680 samdb_result_string(res[i], "sAMAccountName",
3682 entriesFull[count].description.string =
3683 samdb_result_string(res[i], "description", "");
3686 entriesFullGroup[count].idx = count + 1;
3687 entriesFullGroup[count].rid =
3688 objectsid->sub_auths[objectsid->num_auths-1];
3689 entriesFullGroup[count].acct_flags =
3690 samdb_result_acct_flags(res[i],
3691 "userAccountControl");
3692 /* We get a "7" here for groups */
3693 entriesFullGroup[count].acct_flags
3694 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3695 entriesFullGroup[count].account_name.string =
3696 samdb_result_string(res[i], "sAMAccountName",
3698 entriesFullGroup[count].description.string =
3699 samdb_result_string(res[i], "description", "");
3703 entriesAscii[count].idx = count + 1;
3704 entriesAscii[count].account_name.string =
3705 samdb_result_string(res[i], "sAMAccountName",
3713 r->out.total_size = count;
3715 if (r->in.start_idx >= count) {
3716 r->out.returned_size = 0;
3717 switch(r->in.level) {
3719 r->out.info.info1.count = r->out.returned_size;
3720 r->out.info.info1.entries = NULL;
3723 r->out.info.info2.count = r->out.returned_size;
3724 r->out.info.info2.entries = NULL;
3727 r->out.info.info3.count = r->out.returned_size;
3728 r->out.info.info3.entries = NULL;
3731 r->out.info.info4.count = r->out.returned_size;
3732 r->out.info.info4.entries = NULL;
3735 r->out.info.info5.count = r->out.returned_size;
3736 r->out.info.info5.entries = NULL;
3740 r->out.returned_size = MIN(count - r->in.start_idx,
3742 switch(r->in.level) {
3744 r->out.info.info1.count = r->out.returned_size;
3745 r->out.info.info1.entries =
3746 &(entriesGeneral[r->in.start_idx]);
3749 r->out.info.info2.count = r->out.returned_size;
3750 r->out.info.info2.entries =
3751 &(entriesFull[r->in.start_idx]);
3754 r->out.info.info3.count = r->out.returned_size;
3755 r->out.info.info3.entries =
3756 &(entriesFullGroup[r->in.start_idx]);
3759 r->out.info.info4.count = r->out.returned_size;
3760 r->out.info.info4.entries =
3761 &(entriesAscii[r->in.start_idx]);
3764 r->out.info.info5.count = r->out.returned_size;
3765 r->out.info.info5.entries =
3766 &(entriesAscii[r->in.start_idx]);
3771 return (r->out.returned_size < (count - r->in.start_idx)) ?
3772 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3777 samr_GetDisplayEnumerationIndex
3779 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3780 struct samr_GetDisplayEnumerationIndex *r)
3782 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3787 samr_TestPrivateFunctionsDomain
3789 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3790 struct samr_TestPrivateFunctionsDomain *r)
3792 return NT_STATUS_NOT_IMPLEMENTED;
3797 samr_TestPrivateFunctionsUser
3799 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3800 struct samr_TestPrivateFunctionsUser *r)
3802 return NT_STATUS_NOT_IMPLEMENTED;
3809 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3810 struct samr_GetUserPwInfo *r)
3812 struct dcesrv_handle *h;
3813 struct samr_account_state *a_state;
3815 ZERO_STRUCT(r->out.info);
3817 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3821 r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3822 a_state->domain_state->domain_dn, "minPwdLength",
3824 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3825 a_state->account_dn,
3826 "pwdProperties", NULL);
3827 return NT_STATUS_OK;
3832 samr_RemoveMemberFromForeignDomain
3834 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3835 struct samr_RemoveMemberFromForeignDomain *r)
3837 struct dcesrv_handle *h;
3838 struct samr_domain_state *d_state;
3839 const char *memberdn;
3840 struct ldb_message **res;
3841 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3844 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3848 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3849 "distinguishedName", "(objectSid=%s)",
3850 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3852 if (memberdn == NULL) {
3853 return NT_STATUS_OK;
3856 /* TODO: Does this call only remove alias members, or does it do this
3857 * for domain groups as well? */
3859 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3860 d_state->domain_dn, &res, attrs,
3861 d_state->domain_sid,
3862 "(&(member=%s)(objectClass=group)"
3863 "(|(groupType=%d)(groupType=%d)))",
3865 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3866 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3869 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3871 for (i=0; i<count; i++) {
3872 struct ldb_message *mod;
3874 mod = ldb_msg_new(mem_ctx);
3876 return NT_STATUS_NO_MEMORY;
3879 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
3880 if (mod->dn == NULL) {
3885 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3886 "member", memberdn) != 0)
3887 return NT_STATUS_NO_MEMORY;
3889 if (samdb_modify(d_state->sam_ctx, mem_ctx, mod) != 0)
3890 return NT_STATUS_UNSUCCESSFUL;
3895 return NT_STATUS_OK;
3900 samr_QueryDomainInfo2
3902 just an alias for samr_QueryDomainInfo
3904 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3905 struct samr_QueryDomainInfo2 *r)
3907 struct samr_QueryDomainInfo r1;
3910 ZERO_STRUCT(r1.out);
3911 r1.in.domain_handle = r->in.domain_handle;
3912 r1.in.level = r->in.level;
3914 status = samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3916 r->out.info = r1.out.info;
3925 just an alias for samr_QueryUserInfo
3927 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3928 struct samr_QueryUserInfo2 *r)
3930 struct samr_QueryUserInfo r1;
3933 ZERO_STRUCT(r1.out);
3934 r1.in.user_handle = r->in.user_handle;
3935 r1.in.level = r->in.level;
3937 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3939 r->out.info = r1.out.info;
3946 samr_QueryDisplayInfo2
3948 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3949 struct samr_QueryDisplayInfo2 *r)
3951 struct samr_QueryDisplayInfo q;
3954 q.in.domain_handle = r->in.domain_handle;
3955 q.in.level = r->in.level;
3956 q.in.start_idx = r->in.start_idx;
3957 q.in.max_entries = r->in.max_entries;
3958 q.in.buf_size = r->in.buf_size;
3961 result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3963 r->out.total_size = q.out.total_size;
3964 r->out.returned_size = q.out.returned_size;
3965 r->out.info = q.out.info;
3972 samr_GetDisplayEnumerationIndex2
3974 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3975 struct samr_GetDisplayEnumerationIndex2 *r)
3977 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3982 samr_QueryDisplayInfo3
3984 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3985 struct samr_QueryDisplayInfo3 *r)
3987 struct samr_QueryDisplayInfo q;
3990 q.in.domain_handle = r->in.domain_handle;
3991 q.in.level = r->in.level;
3992 q.in.start_idx = r->in.start_idx;
3993 q.in.max_entries = r->in.max_entries;
3994 q.in.buf_size = r->in.buf_size;
3997 result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3999 r->out.total_size = q.out.total_size;
4000 r->out.returned_size = q.out.returned_size;
4001 r->out.info = q.out.info;
4008 samr_AddMultipleMembersToAlias
4010 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4011 struct samr_AddMultipleMembersToAlias *r)
4013 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4018 samr_RemoveMultipleMembersFromAlias
4020 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4021 struct samr_RemoveMultipleMembersFromAlias *r)
4023 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4030 this fetches the default password properties for a domain
4032 note that w2k3 completely ignores the domain name in this call, and
4033 always returns the information for the servers primary domain
4035 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4036 struct samr_GetDomPwInfo *r)
4038 struct ldb_message **msgs;
4040 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4041 struct ldb_context *sam_ctx;
4043 ZERO_STRUCT(r->out.info);
4045 sam_ctx = samdb_connect(mem_ctx, dce_call->conn->auth_state.session_info);
4046 if (sam_ctx == NULL) {
4047 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4050 /* The domain name in this call is ignored */
4051 ret = gendb_search_dn(sam_ctx,
4052 mem_ctx, NULL, &msgs, attrs);
4054 return NT_STATUS_NO_SUCH_DOMAIN;
4058 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4061 r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
4062 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
4066 talloc_free(sam_ctx);
4067 return NT_STATUS_OK;
4074 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4075 struct samr_Connect2 *r)
4077 struct samr_Connect c;
4079 c.in.system_name = NULL;
4080 c.in.access_mask = r->in.access_mask;
4081 c.out.connect_handle = r->out.connect_handle;
4083 return samr_Connect(dce_call, mem_ctx, &c);
4090 just an alias for samr_SetUserInfo
4092 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4093 struct samr_SetUserInfo2 *r)
4095 struct samr_SetUserInfo r2;
4097 r2.in.user_handle = r->in.user_handle;
4098 r2.in.level = r->in.level;
4099 r2.in.info = r->in.info;
4101 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
4106 samr_SetBootKeyInformation
4108 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4109 struct samr_SetBootKeyInformation *r)
4111 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4116 samr_GetBootKeyInformation
4118 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4119 struct samr_GetBootKeyInformation *r)
4121 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4128 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4129 struct samr_Connect3 *r)
4131 struct samr_Connect c;
4133 c.in.system_name = NULL;
4134 c.in.access_mask = r->in.access_mask;
4135 c.out.connect_handle = r->out.connect_handle;
4137 return samr_Connect(dce_call, mem_ctx, &c);
4144 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4145 struct samr_Connect4 *r)
4147 struct samr_Connect c;
4149 c.in.system_name = NULL;
4150 c.in.access_mask = r->in.access_mask;
4151 c.out.connect_handle = r->out.connect_handle;
4153 return samr_Connect(dce_call, mem_ctx, &c);
4160 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4161 struct samr_Connect5 *r)
4163 struct samr_Connect c;
4166 c.in.system_name = NULL;
4167 c.in.access_mask = r->in.access_mask;
4168 c.out.connect_handle = r->out.connect_handle;
4170 status = samr_Connect(dce_call, mem_ctx, &c);
4172 r->out.info->info1.unknown1 = 3;
4173 r->out.info->info1.unknown2 = 0;
4174 r->out.level = r->in.level;
4183 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4184 struct samr_RidToSid *r)
4186 struct samr_domain_state *d_state;
4187 struct dcesrv_handle *h;
4189 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4193 /* form the users SID */
4194 r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4196 return NT_STATUS_NO_MEMORY;
4199 return NT_STATUS_OK;
4204 samr_SetDsrmPassword
4206 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4207 struct samr_SetDsrmPassword *r)
4209 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4214 samr_ValidatePassword
4216 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4217 struct samr_ValidatePassword *r)
4219 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4223 /* include the generated boilerplate */
4224 #include "librpc/gen_ndr/ndr_samr_s.c"