Revert "Revert "s3-printing: update parent smbd pcap cache""
[Samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
blobdf23e11a67b553ae2f5d3217797a507d8981047a
1 /*
2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_samr.h"
26 #include "rpc_server/dcerpc_server.h"
27 #include "rpc_server/common/common.h"
28 #include "rpc_server/samr/dcesrv_samr.h"
29 #include "system/time.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/ldb/include/ldb_errors.h"
32 #include "dsdb/common/flags.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "libcli/ldap/ldap_ndr.h"
35 #include "libcli/security/security.h"
36 #include "rpc_server/samr/proto.h"
37 #include "../lib/util/util_ldb.h"
38 #include "param/param.h"
40 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
42 #define QUERY_STRING(msg, field, attr) \
43 info->field.string = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45 info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_UINT64(msg, field, attr) \
49 info->field = samdb_result_uint64(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51 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 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 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
60 #define QUERY_PARAMETERS(msg, field, attr) \
61 info->field = samdb_result_parameters(mem_ctx, msg, attr);
64 /* these are used to make the Set[User|Group]Info code easier to follow */
66 #define SET_STRING(msg, field, attr) do { \
67 struct ldb_message_element *set_el; \
68 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
69 if (r->in.info->field.string[0] == '\0') { \
70 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
71 return NT_STATUS_NO_MEMORY; \
72 } \
73 } \
74 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
75 return NT_STATUS_NO_MEMORY; \
76 } \
77 set_el = ldb_msg_find_element(msg, attr); \
78 set_el->flags = LDB_FLAG_MOD_REPLACE; \
79 } while (0)
81 #define SET_UINT(msg, field, attr) do { \
82 struct ldb_message_element *set_el; \
83 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
84 return NT_STATUS_NO_MEMORY; \
85 } \
86 set_el = ldb_msg_find_element(msg, attr); \
87 set_el->flags = LDB_FLAG_MOD_REPLACE; \
88 } while (0)
90 #define SET_INT64(msg, field, attr) do { \
91 struct ldb_message_element *set_el; \
92 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
93 return NT_STATUS_NO_MEMORY; \
94 } \
95 set_el = ldb_msg_find_element(msg, attr); \
96 set_el->flags = LDB_FLAG_MOD_REPLACE; \
97 } while (0)
99 #define SET_UINT64(msg, field, attr) do { \
100 struct ldb_message_element *set_el; \
101 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
102 return NT_STATUS_NO_MEMORY; \
104 set_el = ldb_msg_find_element(msg, attr); \
105 set_el->flags = LDB_FLAG_MOD_REPLACE; \
106 } while (0)
108 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
109 do { \
110 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
111 return NT_STATUS_INVALID_PARAMETER; \
113 } while (0) \
115 /* Set account flags, discarding flags that cannot be set with SAMR */
116 #define SET_AFLAGS(msg, field, attr) do { \
117 struct ldb_message_element *set_el; \
118 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
119 return NT_STATUS_INVALID_PARAMETER; \
121 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
122 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
126 return NT_STATUS_NO_MEMORY; \
128 set_el = ldb_msg_find_element(msg, attr); \
129 set_el->flags = LDB_FLAG_MOD_REPLACE; \
130 } while (0)
132 #define SET_LHOURS(msg, field, attr) do { \
133 struct ldb_message_element *set_el; \
134 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
135 return NT_STATUS_NO_MEMORY; \
137 set_el = ldb_msg_find_element(msg, attr); \
138 set_el->flags = LDB_FLAG_MOD_REPLACE; \
139 } while (0)
141 #define SET_PARAMETERS(msg, field, attr) do { \
142 struct ldb_message_element *set_el; \
143 if (r->in.info->field.length != 0) { \
144 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
145 return NT_STATUS_NO_MEMORY; \
147 set_el = ldb_msg_find_element(msg, attr); \
148 set_el->flags = LDB_FLAG_MOD_REPLACE; \
150 } while (0)
155 samr_Connect
157 create a connection to the SAM database
159 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
160 struct samr_Connect *r)
162 struct samr_connect_state *c_state;
163 struct dcesrv_handle *handle;
165 ZERO_STRUCTP(r->out.connect_handle);
167 c_state = talloc(dce_call->conn, struct samr_connect_state);
168 if (!c_state) {
169 return NT_STATUS_NO_MEMORY;
172 /* make sure the sam database is accessible */
173 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
174 if (c_state->sam_ctx == NULL) {
175 talloc_free(c_state);
176 return NT_STATUS_INVALID_SYSTEM_SERVICE;
180 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
181 if (!handle) {
182 talloc_free(c_state);
183 return NT_STATUS_NO_MEMORY;
186 handle->data = talloc_steal(handle, c_state);
188 c_state->access_mask = r->in.access_mask;
189 *r->out.connect_handle = handle->wire_handle;
191 return NT_STATUS_OK;
196 samr_Close
198 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
199 struct samr_Close *r)
201 struct dcesrv_handle *h;
203 *r->out.handle = *r->in.handle;
205 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
207 talloc_free(h);
209 ZERO_STRUCTP(r->out.handle);
211 return NT_STATUS_OK;
216 samr_SetSecurity
218 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
219 struct samr_SetSecurity *r)
221 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
226 samr_QuerySecurity
228 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
229 struct samr_QuerySecurity *r)
231 struct dcesrv_handle *h;
232 struct sec_desc_buf *sd;
234 *r->out.sdbuf = NULL;
236 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
238 sd = talloc(mem_ctx, struct sec_desc_buf);
239 if (sd == NULL) {
240 return NT_STATUS_NO_MEMORY;
243 sd->sd = samdb_default_security_descriptor(mem_ctx);
245 *r->out.sdbuf = sd;
247 return NT_STATUS_OK;
252 samr_Shutdown
254 we refuse this operation completely. If a admin wants to shutdown samr
255 in Samba then they should use the samba admin tools to disable the samr pipe
257 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
258 struct samr_Shutdown *r)
260 return NT_STATUS_ACCESS_DENIED;
265 samr_LookupDomain
267 this maps from a domain name to a SID
269 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
270 struct samr_LookupDomain *r)
272 struct samr_connect_state *c_state;
273 struct dcesrv_handle *h;
274 struct dom_sid *sid;
275 const char * const dom_attrs[] = { "objectSid", NULL};
276 const char * const ref_attrs[] = { "ncName", NULL};
277 struct ldb_message **dom_msgs;
278 struct ldb_message **ref_msgs;
279 int ret;
280 struct ldb_dn *partitions_basedn;
282 *r->out.sid = NULL;
284 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
286 c_state = h->data;
288 if (r->in.domain_name->string == NULL) {
289 return NT_STATUS_INVALID_PARAMETER;
292 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
294 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
295 ret = gendb_search(c_state->sam_ctx,
296 mem_ctx, NULL, &dom_msgs, dom_attrs,
297 "(objectClass=builtinDomain)");
298 } else {
299 ret = gendb_search(c_state->sam_ctx,
300 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
301 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
302 ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
303 if (ret != 1) {
304 return NT_STATUS_NO_SUCH_DOMAIN;
307 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx,
308 samdb_result_dn(c_state->sam_ctx, mem_ctx,
309 ref_msgs[0], "ncName", NULL),
310 &dom_msgs, dom_attrs);
313 if (ret != 1) {
314 return NT_STATUS_NO_SUCH_DOMAIN;
317 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
318 "objectSid");
320 if (sid == NULL) {
321 return NT_STATUS_NO_SUCH_DOMAIN;
324 *r->out.sid = sid;
326 return NT_STATUS_OK;
331 samr_EnumDomains
333 list the domains in the SAM
335 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
336 struct samr_EnumDomains *r)
338 struct samr_connect_state *c_state;
339 struct dcesrv_handle *h;
340 struct samr_SamArray *array;
341 int i, start_i, ret;
342 const char * const dom_attrs[] = { "cn", NULL};
343 const char * const ref_attrs[] = { "nETBIOSName", NULL};
344 struct ldb_result *dom_res;
345 struct ldb_result *ref_res;
346 struct ldb_dn *partitions_basedn;
348 *r->out.resume_handle = 0;
349 *r->out.sam = NULL;
350 *r->out.num_entries = 0;
352 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
354 c_state = h->data;
356 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
358 ret = ldb_search(c_state->sam_ctx, mem_ctx, &dom_res, ldb_get_default_basedn(c_state->sam_ctx),
359 LDB_SCOPE_SUBTREE, dom_attrs, "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
360 if (ret != LDB_SUCCESS) {
361 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
362 return NT_STATUS_INTERNAL_DB_CORRUPTION;
365 *r->out.resume_handle = dom_res->count;
367 start_i = *r->in.resume_handle;
369 if (start_i >= dom_res->count) {
370 /* search past end of list is not an error for this call */
371 return NT_STATUS_OK;
374 array = talloc(mem_ctx, struct samr_SamArray);
375 if (array == NULL) {
376 return NT_STATUS_NO_MEMORY;
379 array->count = 0;
380 array->entries = NULL;
382 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, dom_res->count - start_i);
383 if (array->entries == NULL) {
384 return NT_STATUS_NO_MEMORY;
387 for (i=0;i<dom_res->count-start_i;i++) {
388 array->entries[i].idx = start_i + i;
389 /* try and find the domain */
390 ret = ldb_search(c_state->sam_ctx, mem_ctx, &ref_res, partitions_basedn,
391 LDB_SCOPE_SUBTREE, ref_attrs, "(&(objectClass=crossRef)(ncName=%s))",
392 ldb_dn_get_linearized(dom_res->msgs[i]->dn));
394 if (ret != LDB_SUCCESS) {
395 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
396 return NT_STATUS_INTERNAL_DB_CORRUPTION;
399 if (ref_res->count == 1) {
400 array->entries[i].name.string = samdb_result_string(ref_res->msgs[0], "nETBIOSName", NULL);
401 } else {
402 array->entries[i].name.string = samdb_result_string(dom_res->msgs[i], "cn", NULL);
406 *r->out.sam = array;
407 *r->out.num_entries = i;
408 array->count = *r->out.num_entries;
410 return NT_STATUS_OK;
415 samr_OpenDomain
417 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
418 struct samr_OpenDomain *r)
420 struct dcesrv_handle *h_conn, *h_domain;
421 const char *domain_name;
422 struct samr_connect_state *c_state;
423 struct samr_domain_state *d_state;
424 const char * const dom_attrs[] = { "cn", NULL};
425 const char * const ref_attrs[] = { "nETBIOSName", NULL};
426 struct ldb_message **dom_msgs;
427 struct ldb_message **ref_msgs;
428 int ret;
429 struct ldb_dn *partitions_basedn;
431 ZERO_STRUCTP(r->out.domain_handle);
433 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
435 c_state = h_conn->data;
437 if (r->in.sid == NULL) {
438 return NT_STATUS_INVALID_PARAMETER;
441 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
443 ret = gendb_search(c_state->sam_ctx,
444 mem_ctx, NULL, &dom_msgs, dom_attrs,
445 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
446 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
447 if (ret == 0) {
448 return NT_STATUS_NO_SUCH_DOMAIN;
449 } else if (ret > 1) {
450 return NT_STATUS_INTERNAL_DB_CORRUPTION;
451 } else if (ret == -1) {
452 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
453 return NT_STATUS_INTERNAL_DB_CORRUPTION;
454 } else {
455 ret = gendb_search(c_state->sam_ctx,
456 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
457 "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))",
458 ldb_dn_get_linearized(dom_msgs[0]->dn));
459 if (ret == 0) {
460 domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL);
461 if (domain_name == NULL) {
462 return NT_STATUS_NO_SUCH_DOMAIN;
464 } else if (ret == 1) {
466 domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL);
467 if (domain_name == NULL) {
468 return NT_STATUS_NO_SUCH_DOMAIN;
470 } else {
471 return NT_STATUS_NO_SUCH_DOMAIN;
475 d_state = talloc(c_state, struct samr_domain_state);
476 if (!d_state) {
477 return NT_STATUS_NO_MEMORY;
480 d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
481 d_state->connect_state = talloc_reference(d_state, c_state);
482 d_state->sam_ctx = c_state->sam_ctx;
483 d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
484 d_state->domain_name = talloc_strdup(d_state, domain_name);
485 d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
486 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
487 talloc_free(d_state);
488 return NT_STATUS_NO_MEMORY;
490 d_state->access_mask = r->in.access_mask;
492 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
493 d_state->builtin = true;
494 } else {
495 d_state->builtin = false;
498 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
500 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
501 if (!h_domain) {
502 talloc_free(d_state);
503 return NT_STATUS_NO_MEMORY;
506 h_domain->data = talloc_steal(h_domain, d_state);
508 *r->out.domain_handle = h_domain->wire_handle;
510 return NT_STATUS_OK;
514 return DomInfo1
516 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
517 TALLOC_CTX *mem_ctx,
518 struct ldb_message **dom_msgs,
519 struct samr_DomInfo1 *info)
521 info->min_password_length =
522 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
523 info->password_history_length =
524 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
525 info->password_properties =
526 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
527 info->max_password_age =
528 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
529 info->min_password_age =
530 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
532 return NT_STATUS_OK;
536 return DomInfo2
538 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
539 TALLOC_CTX *mem_ctx,
540 struct ldb_message **dom_msgs,
541 struct samr_DomGeneralInformation *info)
543 /* This pulls the NetBIOS name from the
544 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
545 string */
546 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
548 if (!info->primary.string) {
549 info->primary.string = lp_netbios_name(state->lp_ctx);
552 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
553 0x8000000000000000LL);
555 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
556 info->domain_name.string = state->domain_name;
558 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
560 switch (state->role) {
561 case ROLE_DOMAIN_CONTROLLER:
562 /* This pulls the NetBIOS name from the
563 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
564 string */
565 if (samdb_is_pdc(state->sam_ctx)) {
566 info->role = SAMR_ROLE_DOMAIN_PDC;
567 } else {
568 info->role = SAMR_ROLE_DOMAIN_BDC;
570 break;
571 case ROLE_DOMAIN_MEMBER:
572 info->role = SAMR_ROLE_DOMAIN_MEMBER;
573 break;
574 case ROLE_STANDALONE:
575 info->role = SAMR_ROLE_STANDALONE;
576 break;
579 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
580 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
581 "(objectClass=user)");
582 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
583 "(&(objectClass=group)(sAMAccountType=%u))",
584 ATYPE_GLOBAL_GROUP);
585 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
586 "(&(objectClass=group)(sAMAccountType=%u))",
587 ATYPE_LOCAL_GROUP);
589 return NT_STATUS_OK;
593 return DomInfo3
595 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
596 TALLOC_CTX *mem_ctx,
597 struct ldb_message **dom_msgs,
598 struct samr_DomInfo3 *info)
600 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
601 0x8000000000000000LL);
603 return NT_STATUS_OK;
607 return DomInfo4
609 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
610 TALLOC_CTX *mem_ctx,
611 struct ldb_message **dom_msgs,
612 struct samr_DomOEMInformation *info)
614 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
616 return NT_STATUS_OK;
620 return DomInfo5
622 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
623 TALLOC_CTX *mem_ctx,
624 struct ldb_message **dom_msgs,
625 struct samr_DomInfo5 *info)
627 info->domain_name.string = state->domain_name;
629 return NT_STATUS_OK;
633 return DomInfo6
635 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
636 TALLOC_CTX *mem_ctx,
637 struct ldb_message **dom_msgs,
638 struct samr_DomInfo6 *info)
640 /* This pulls the NetBIOS name from the
641 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
642 string */
643 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
644 dom_msgs[0], "fSMORoleOwner");
646 if (!info->primary.string) {
647 info->primary.string = lp_netbios_name(state->lp_ctx);
650 return NT_STATUS_OK;
654 return DomInfo7
656 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
657 TALLOC_CTX *mem_ctx,
658 struct ldb_message **dom_msgs,
659 struct samr_DomInfo7 *info)
662 switch (state->role) {
663 case ROLE_DOMAIN_CONTROLLER:
664 /* This pulls the NetBIOS name from the
665 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
666 string */
667 if (samdb_is_pdc(state->sam_ctx)) {
668 info->role = SAMR_ROLE_DOMAIN_PDC;
669 } else {
670 info->role = SAMR_ROLE_DOMAIN_BDC;
672 break;
673 case ROLE_DOMAIN_MEMBER:
674 info->role = SAMR_ROLE_DOMAIN_MEMBER;
675 break;
676 case ROLE_STANDALONE:
677 info->role = SAMR_ROLE_STANDALONE;
678 break;
681 return NT_STATUS_OK;
685 return DomInfo8
687 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
688 TALLOC_CTX *mem_ctx,
689 struct ldb_message **dom_msgs,
690 struct samr_DomInfo8 *info)
692 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
693 time(NULL));
695 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
696 0x0LL);
698 return NT_STATUS_OK;
702 return DomInfo9
704 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
705 TALLOC_CTX *mem_ctx,
706 struct ldb_message **dom_msgs,
707 struct samr_DomInfo9 *info)
709 info->domain_server_state = DOMAIN_SERVER_ENABLED;
711 return NT_STATUS_OK;
715 return DomInfo11
717 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
718 TALLOC_CTX *mem_ctx,
719 struct ldb_message **dom_msgs,
720 struct samr_DomGeneralInformation2 *info)
722 NTSTATUS status;
723 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
724 if (!NT_STATUS_IS_OK(status)) {
725 return status;
728 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
729 -18000000000LL);
730 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
731 -18000000000LL);
732 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
734 return NT_STATUS_OK;
738 return DomInfo12
740 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
741 TALLOC_CTX *mem_ctx,
742 struct ldb_message **dom_msgs,
743 struct samr_DomInfo12 *info)
745 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
746 -18000000000LL);
747 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
748 -18000000000LL);
749 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
751 return NT_STATUS_OK;
755 return DomInfo13
757 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
758 TALLOC_CTX *mem_ctx,
759 struct ldb_message **dom_msgs,
760 struct samr_DomInfo13 *info)
762 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
763 time(NULL));
765 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
766 0x0LL);
768 info->modified_count_at_last_promotion = 0;
770 return NT_STATUS_OK;
774 samr_QueryDomainInfo
776 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
777 struct samr_QueryDomainInfo *r)
779 struct dcesrv_handle *h;
780 struct samr_domain_state *d_state;
781 union samr_DomainInfo *info;
783 struct ldb_message **dom_msgs;
784 const char * const *attrs = NULL;
786 *r->out.info = NULL;
788 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
790 d_state = h->data;
792 info = talloc(mem_ctx, union samr_DomainInfo);
793 if (!info) {
794 return NT_STATUS_NO_MEMORY;
797 switch (r->in.level) {
798 case 1:
800 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
801 "pwdProperties", "maxPwdAge",
802 "minPwdAge", NULL };
803 attrs = attrs2;
804 break;
806 case 2:
808 static const char * const attrs2[] = {"forceLogoff",
809 "oEMInformation",
810 "modifiedCount",
811 "fSMORoleOwner",
812 NULL};
813 attrs = attrs2;
814 break;
816 case 3:
818 static const char * const attrs2[] = {"forceLogoff",
819 NULL};
820 attrs = attrs2;
821 break;
823 case 4:
825 static const char * const attrs2[] = {"oEMInformation",
826 NULL};
827 attrs = attrs2;
828 break;
830 case 5:
832 attrs = NULL;
833 break;
835 case 6:
837 static const char * const attrs2[] = {"fSMORoleOwner",
838 NULL};
839 attrs = attrs2;
840 break;
842 case 7:
844 attrs = NULL;
845 break;
847 case 8:
849 static const char * const attrs2[] = { "modifiedCount",
850 "creationTime",
851 NULL };
852 attrs = attrs2;
853 break;
855 case 9:
856 attrs = NULL;
857 break;
858 case 11:
860 static const char * const attrs2[] = { "oEMInformation", "forceLogoff",
861 "modifiedCount",
862 "lockoutDuration",
863 "lockOutObservationWindow",
864 "lockoutThreshold",
865 NULL};
866 attrs = attrs2;
867 break;
869 case 12:
871 static const char * const attrs2[] = { "lockoutDuration",
872 "lockOutObservationWindow",
873 "lockoutThreshold",
874 NULL};
875 attrs = attrs2;
876 break;
878 case 13:
880 static const char * const attrs2[] = { "modifiedCount",
881 "creationTime",
882 NULL };
883 attrs = attrs2;
884 break;
888 /* some levels don't need a search */
889 if (attrs) {
890 int ret;
891 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
892 d_state->domain_dn, &dom_msgs, attrs);
893 if (ret != 1) {
894 return NT_STATUS_INTERNAL_DB_CORRUPTION;
898 *r->out.info = info;
900 ZERO_STRUCTP(info);
902 switch (r->in.level) {
903 case 1:
904 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
905 &info->info1);
906 case 2:
907 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
908 &info->general);
909 case 3:
910 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
911 &info->info3);
912 case 4:
913 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
914 &info->oem);
915 case 5:
916 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
917 &info->info5);
918 case 6:
919 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
920 &info->info6);
921 case 7:
922 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
923 &info->info7);
924 case 8:
925 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
926 &info->info8);
927 case 9:
928 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
929 &info->info9);
930 case 11:
931 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
932 &info->general2);
933 case 12:
934 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
935 &info->info12);
936 case 13:
937 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
938 &info->info13);
941 return NT_STATUS_INVALID_INFO_CLASS;
946 samr_SetDomainInfo
948 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
949 struct samr_SetDomainInfo *r)
951 struct dcesrv_handle *h;
952 struct samr_domain_state *d_state;
953 struct ldb_message *msg;
954 int ret;
955 struct ldb_context *sam_ctx;
957 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
959 d_state = h->data;
960 sam_ctx = d_state->sam_ctx;
962 msg = ldb_msg_new(mem_ctx);
963 if (msg == NULL) {
964 return NT_STATUS_NO_MEMORY;
967 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
968 if (!msg->dn) {
969 return NT_STATUS_NO_MEMORY;
972 switch (r->in.level) {
973 case 1:
974 SET_UINT (msg, info1.min_password_length, "minPwdLength");
975 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
976 SET_UINT (msg, info1.password_properties, "pwdProperties");
977 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
978 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
979 break;
980 case 3:
981 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
982 break;
983 case 4:
984 SET_STRING(msg, oem.oem_information, "oEMInformation");
985 break;
987 case 6:
988 case 7:
989 case 9:
990 /* No op, we don't know where to set these */
991 return NT_STATUS_OK;
993 case 12:
995 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
996 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
997 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
998 break;
1000 default:
1001 /* many info classes are not valid for SetDomainInfo */
1002 return NT_STATUS_INVALID_INFO_CLASS;
1005 /* modify the samdb record */
1006 ret = ldb_modify(sam_ctx, msg);
1007 if (ret != 0) {
1008 DEBUG(1,("Failed to modify record %s: %s\n",
1009 ldb_dn_get_linearized(d_state->domain_dn),
1010 ldb_errstring(sam_ctx)));
1012 /* we really need samdb.c to return NTSTATUS */
1013 return NT_STATUS_UNSUCCESSFUL;
1016 return NT_STATUS_OK;
1020 samr_CreateDomainGroup
1022 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1023 struct samr_CreateDomainGroup *r)
1025 struct samr_domain_state *d_state;
1026 struct samr_account_state *a_state;
1027 struct dcesrv_handle *h;
1028 const char *name;
1029 struct ldb_message *msg;
1030 struct dom_sid *sid;
1031 const char *groupname;
1032 struct dcesrv_handle *g_handle;
1033 int ret;
1035 ZERO_STRUCTP(r->out.group_handle);
1036 *r->out.rid = 0;
1038 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1040 d_state = h->data;
1042 if (d_state->builtin) {
1043 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1044 return NT_STATUS_ACCESS_DENIED;
1047 groupname = r->in.name->string;
1049 if (groupname == NULL) {
1050 return NT_STATUS_INVALID_PARAMETER;
1053 /* check if the group already exists */
1054 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1055 "sAMAccountName",
1056 "(&(sAMAccountName=%s)(objectclass=group))",
1057 ldb_binary_encode_string(mem_ctx, groupname));
1058 if (name != NULL) {
1059 return NT_STATUS_GROUP_EXISTS;
1062 msg = ldb_msg_new(mem_ctx);
1063 if (msg == NULL) {
1064 return NT_STATUS_NO_MEMORY;
1067 /* add core elements to the ldb_message for the user */
1068 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1069 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1070 if (!msg->dn) {
1071 return NT_STATUS_NO_MEMORY;
1073 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1074 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1076 /* create the group */
1077 ret = ldb_add(d_state->sam_ctx, msg);
1078 switch (ret) {
1079 case LDB_SUCCESS:
1080 break;
1081 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1082 DEBUG(0,("Failed to create group record %s: %s\n",
1083 ldb_dn_get_linearized(msg->dn),
1084 ldb_errstring(d_state->sam_ctx)));
1085 return NT_STATUS_GROUP_EXISTS;
1086 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1087 DEBUG(0,("Failed to create group record %s: %s\n",
1088 ldb_dn_get_linearized(msg->dn),
1089 ldb_errstring(d_state->sam_ctx)));
1090 return NT_STATUS_ACCESS_DENIED;
1091 default:
1092 DEBUG(0,("Failed to create group record %s: %s\n",
1093 ldb_dn_get_linearized(msg->dn),
1094 ldb_errstring(d_state->sam_ctx)));
1095 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1098 a_state = talloc(d_state, struct samr_account_state);
1099 if (!a_state) {
1100 return NT_STATUS_NO_MEMORY;
1102 a_state->sam_ctx = d_state->sam_ctx;
1103 a_state->access_mask = r->in.access_mask;
1104 a_state->domain_state = talloc_reference(a_state, d_state);
1105 a_state->account_dn = talloc_steal(a_state, msg->dn);
1107 /* retrieve the sid for the group just created */
1108 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1109 msg->dn, "objectSid", NULL);
1110 if (sid == NULL) {
1111 return NT_STATUS_UNSUCCESSFUL;
1114 a_state->account_name = talloc_strdup(a_state, groupname);
1115 if (!a_state->account_name) {
1116 return NT_STATUS_NO_MEMORY;
1119 /* create the policy handle */
1120 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1121 if (!g_handle) {
1122 return NT_STATUS_NO_MEMORY;
1125 g_handle->data = talloc_steal(g_handle, a_state);
1127 *r->out.group_handle = g_handle->wire_handle;
1128 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1130 return NT_STATUS_OK;
1135 comparison function for sorting SamEntry array
1137 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1139 return e1->idx - e2->idx;
1143 samr_EnumDomainGroups
1145 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1146 struct samr_EnumDomainGroups *r)
1148 struct dcesrv_handle *h;
1149 struct samr_domain_state *d_state;
1150 struct ldb_message **res;
1151 int ldb_cnt, count, i, first;
1152 struct samr_SamEntry *entries;
1153 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1154 struct samr_SamArray *sam;
1156 *r->out.resume_handle = 0;
1157 *r->out.sam = NULL;
1158 *r->out.num_entries = 0;
1160 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1162 d_state = h->data;
1164 /* search for all domain groups in this domain. This could possibly be
1165 cached and resumed based on resume_key */
1166 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1167 d_state->domain_dn, &res, attrs,
1168 d_state->domain_sid,
1169 "(&(grouptype=%d)(objectclass=group))",
1170 GTYPE_SECURITY_GLOBAL_GROUP);
1171 if (ldb_cnt == -1) {
1172 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1175 /* convert to SamEntry format */
1176 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1177 if (!entries) {
1178 return NT_STATUS_NO_MEMORY;
1181 count = 0;
1183 for (i=0;i<ldb_cnt;i++) {
1184 struct dom_sid *group_sid;
1186 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1187 "objectSid");
1188 if (group_sid == NULL)
1189 continue;
1191 entries[count].idx =
1192 group_sid->sub_auths[group_sid->num_auths-1];
1193 entries[count].name.string =
1194 samdb_result_string(res[i], "sAMAccountName", "");
1195 count += 1;
1198 /* sort the results by rid */
1199 qsort(entries, count, sizeof(struct samr_SamEntry),
1200 (comparison_fn_t)compare_SamEntry);
1202 /* find the first entry to return */
1203 for (first=0;
1204 first<count && entries[first].idx <= *r->in.resume_handle;
1205 first++) ;
1207 /* return the rest, limit by max_size. Note that we
1208 use the w2k3 element size value of 54 */
1209 *r->out.num_entries = count - first;
1210 *r->out.num_entries = MIN(*r->out.num_entries,
1211 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1213 sam = talloc(mem_ctx, struct samr_SamArray);
1214 if (!sam) {
1215 return NT_STATUS_NO_MEMORY;
1218 sam->entries = entries+first;
1219 sam->count = *r->out.num_entries;
1221 *r->out.sam = sam;
1223 if (*r->out.num_entries < count - first) {
1224 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1225 return STATUS_MORE_ENTRIES;
1228 return NT_STATUS_OK;
1233 samr_CreateUser2
1235 This call uses transactions to ensure we don't get a new conflicting
1236 user while we are processing this, and to ensure the user either
1237 completly exists, or does not.
1239 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1240 struct samr_CreateUser2 *r)
1242 struct samr_domain_state *d_state;
1243 struct samr_account_state *a_state;
1244 struct dcesrv_handle *h;
1245 const char *name;
1246 struct ldb_message *msg;
1247 struct dom_sid *sid;
1248 const char *account_name;
1249 struct dcesrv_handle *u_handle;
1250 int ret;
1251 const char *container, *obj_class=NULL;
1252 char *cn_name;
1253 int cn_name_len;
1255 const char *attrs[] = {
1256 "objectSid",
1257 "userAccountControl",
1258 NULL
1261 uint32_t user_account_control;
1263 struct ldb_message **msgs;
1265 ZERO_STRUCTP(r->out.user_handle);
1266 *r->out.access_granted = 0;
1267 *r->out.rid = 0;
1269 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1271 d_state = h->data;
1273 if (d_state->builtin) {
1274 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1275 return NT_STATUS_ACCESS_DENIED;
1277 account_name = r->in.account_name->string;
1279 if (account_name == NULL) {
1280 return NT_STATUS_INVALID_PARAMETER;
1283 ret = ldb_transaction_start(d_state->sam_ctx);
1284 if (ret != 0) {
1285 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1286 ldb_errstring(d_state->sam_ctx)));
1287 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1290 /* check if the user already exists */
1291 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1292 "sAMAccountName",
1293 "(&(sAMAccountName=%s)(objectclass=user))",
1294 ldb_binary_encode_string(mem_ctx, account_name));
1295 if (name != NULL) {
1296 ldb_transaction_cancel(d_state->sam_ctx);
1297 return NT_STATUS_USER_EXISTS;
1300 msg = ldb_msg_new(mem_ctx);
1301 if (msg == NULL) {
1302 ldb_transaction_cancel(d_state->sam_ctx);
1303 return NT_STATUS_NO_MEMORY;
1306 cn_name = talloc_strdup(mem_ctx, account_name);
1307 if (!cn_name) {
1308 ldb_transaction_cancel(d_state->sam_ctx);
1309 return NT_STATUS_NO_MEMORY;
1312 cn_name_len = strlen(cn_name);
1314 /* This must be one of these values *only* */
1315 if (r->in.acct_flags == ACB_NORMAL) {
1316 container = "CN=Users";
1317 obj_class = "user";
1319 } else if (r->in.acct_flags == ACB_WSTRUST) {
1320 if (cn_name[cn_name_len - 1] != '$') {
1321 return NT_STATUS_FOOBAR;
1323 cn_name[cn_name_len - 1] = '\0';
1324 container = "CN=Computers";
1325 obj_class = "computer";
1326 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1328 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1329 if (cn_name[cn_name_len - 1] != '$') {
1330 return NT_STATUS_FOOBAR;
1332 cn_name[cn_name_len - 1] = '\0';
1333 container = "OU=Domain Controllers";
1334 obj_class = "computer";
1335 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS);
1337 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1338 container = "CN=Users";
1339 obj_class = "user";
1341 } else {
1342 ldb_transaction_cancel(d_state->sam_ctx);
1343 return NT_STATUS_INVALID_PARAMETER;
1346 /* add core elements to the ldb_message for the user */
1347 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1348 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1349 ldb_transaction_cancel(d_state->sam_ctx);
1350 return NT_STATUS_FOOBAR;
1353 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1354 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1356 /* Start a transaction, so we can query and do a subsequent atomic modify */
1358 /* create the user */
1359 ret = ldb_add(d_state->sam_ctx, msg);
1360 switch (ret) {
1361 case LDB_SUCCESS:
1362 break;
1363 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1364 ldb_transaction_cancel(d_state->sam_ctx);
1365 DEBUG(0,("Failed to create user record %s: %s\n",
1366 ldb_dn_get_linearized(msg->dn),
1367 ldb_errstring(d_state->sam_ctx)));
1368 return NT_STATUS_USER_EXISTS;
1369 case LDB_ERR_UNWILLING_TO_PERFORM:
1370 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1371 ldb_transaction_cancel(d_state->sam_ctx);
1372 DEBUG(0,("Failed to create user record %s: %s\n",
1373 ldb_dn_get_linearized(msg->dn),
1374 ldb_errstring(d_state->sam_ctx)));
1375 return NT_STATUS_ACCESS_DENIED;
1376 default:
1377 ldb_transaction_cancel(d_state->sam_ctx);
1378 DEBUG(0,("Failed to create user record %s: %s\n",
1379 ldb_dn_get_linearized(msg->dn),
1380 ldb_errstring(d_state->sam_ctx)));
1381 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1384 a_state = talloc(d_state, struct samr_account_state);
1385 if (!a_state) {
1386 ldb_transaction_cancel(d_state->sam_ctx);
1387 return NT_STATUS_NO_MEMORY;
1389 a_state->sam_ctx = d_state->sam_ctx;
1390 a_state->access_mask = r->in.access_mask;
1391 a_state->domain_state = talloc_reference(a_state, d_state);
1392 a_state->account_dn = talloc_steal(a_state, msg->dn);
1394 /* retrieve the sid and account control bits for the user just created */
1395 ret = gendb_search_dn(d_state->sam_ctx, a_state,
1396 msg->dn, &msgs, attrs);
1398 if (ret != 1) {
1399 ldb_transaction_cancel(d_state->sam_ctx);
1400 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1401 ldb_dn_get_linearized(msg->dn)));
1402 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1404 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1405 if (sid == NULL) {
1406 ldb_transaction_cancel(d_state->sam_ctx);
1407 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1408 ldb_dn_get_linearized(msg->dn)));
1409 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1412 /* Change the account control to be the correct account type.
1413 * The default is for a workstation account */
1414 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1415 user_account_control = (user_account_control &
1416 ~(UF_NORMAL_ACCOUNT |
1417 UF_INTERDOMAIN_TRUST_ACCOUNT |
1418 UF_WORKSTATION_TRUST_ACCOUNT |
1419 UF_SERVER_TRUST_ACCOUNT));
1420 user_account_control |= samdb_acb2uf(r->in.acct_flags);
1422 talloc_free(msg);
1423 msg = ldb_msg_new(mem_ctx);
1424 if (msg == NULL) {
1425 ldb_transaction_cancel(d_state->sam_ctx);
1426 return NT_STATUS_NO_MEMORY;
1429 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1431 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1432 "userAccountControl",
1433 user_account_control) != 0) {
1434 ldb_transaction_cancel(d_state->sam_ctx);
1435 return NT_STATUS_NO_MEMORY;
1438 /* modify the samdb record */
1439 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1440 if (ret != 0) {
1441 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1442 ldb_dn_get_linearized(msg->dn),
1443 ldb_errstring(d_state->sam_ctx)));
1444 ldb_transaction_cancel(d_state->sam_ctx);
1446 /* we really need samdb.c to return NTSTATUS */
1447 return NT_STATUS_UNSUCCESSFUL;
1450 ret = ldb_transaction_commit(d_state->sam_ctx);
1451 if (ret != 0) {
1452 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1453 ldb_dn_get_linearized(msg->dn),
1454 ldb_errstring(d_state->sam_ctx)));
1455 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1458 a_state->account_name = talloc_steal(a_state, account_name);
1459 if (!a_state->account_name) {
1460 return NT_STATUS_NO_MEMORY;
1463 /* create the policy handle */
1464 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1465 if (!u_handle) {
1466 return NT_STATUS_NO_MEMORY;
1469 u_handle->data = talloc_steal(u_handle, a_state);
1471 *r->out.user_handle = u_handle->wire_handle;
1472 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1474 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1476 return NT_STATUS_OK;
1481 samr_CreateUser
1483 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1484 struct samr_CreateUser *r)
1486 struct samr_CreateUser2 r2;
1487 uint32_t access_granted = 0;
1490 /* a simple wrapper around samr_CreateUser2 works nicely */
1491 r2.in.domain_handle = r->in.domain_handle;
1492 r2.in.account_name = r->in.account_name;
1493 r2.in.acct_flags = ACB_NORMAL;
1494 r2.in.access_mask = r->in.access_mask;
1495 r2.out.user_handle = r->out.user_handle;
1496 r2.out.access_granted = &access_granted;
1497 r2.out.rid = r->out.rid;
1499 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1503 samr_EnumDomainUsers
1505 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1506 struct samr_EnumDomainUsers *r)
1508 struct dcesrv_handle *h;
1509 struct samr_domain_state *d_state;
1510 struct ldb_result *res;
1511 int ret, num_filtered_entries, i, first;
1512 struct samr_SamEntry *entries;
1513 const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
1514 struct samr_SamArray *sam;
1516 *r->out.resume_handle = 0;
1517 *r->out.sam = NULL;
1518 *r->out.num_entries = 0;
1520 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1522 d_state = h->data;
1524 /* don't have to worry about users in the builtin domain, as there are none */
1525 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1527 if (ret != LDB_SUCCESS) {
1528 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1529 ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1530 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1533 /* convert to SamEntry format */
1534 entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1535 if (!entries) {
1536 return NT_STATUS_NO_MEMORY;
1538 num_filtered_entries = 0;
1539 for (i=0;i<res->count;i++) {
1540 /* Check if a mask has been requested */
1541 if (r->in.acct_flags
1542 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i],
1543 d_state->domain_dn) & r->in.acct_flags) == 0)) {
1544 continue;
1546 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1547 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1548 num_filtered_entries++;
1551 /* sort the results by rid */
1552 qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry),
1553 (comparison_fn_t)compare_SamEntry);
1555 /* find the first entry to return */
1556 for (first=0;
1557 first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1558 first++) ;
1560 /* return the rest, limit by max_size. Note that we
1561 use the w2k3 element size value of 54 */
1562 *r->out.num_entries = num_filtered_entries - first;
1563 *r->out.num_entries = MIN(*r->out.num_entries,
1564 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1566 sam = talloc(mem_ctx, struct samr_SamArray);
1567 if (!sam) {
1568 return NT_STATUS_NO_MEMORY;
1571 sam->entries = entries+first;
1572 sam->count = *r->out.num_entries;
1574 *r->out.sam = sam;
1576 if (first == num_filtered_entries) {
1577 return NT_STATUS_OK;
1580 if (*r->out.num_entries < num_filtered_entries - first) {
1581 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1582 return STATUS_MORE_ENTRIES;
1585 return NT_STATUS_OK;
1590 samr_CreateDomAlias
1592 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1593 struct samr_CreateDomAlias *r)
1595 struct samr_domain_state *d_state;
1596 struct samr_account_state *a_state;
1597 struct dcesrv_handle *h;
1598 const char *alias_name, *name;
1599 struct ldb_message *msg;
1600 struct dom_sid *sid;
1601 struct dcesrv_handle *a_handle;
1602 int ret;
1604 ZERO_STRUCTP(r->out.alias_handle);
1605 *r->out.rid = 0;
1607 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1609 d_state = h->data;
1611 if (d_state->builtin) {
1612 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1613 return NT_STATUS_ACCESS_DENIED;
1616 alias_name = r->in.alias_name->string;
1618 if (alias_name == NULL) {
1619 return NT_STATUS_INVALID_PARAMETER;
1622 /* Check if alias already exists */
1623 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1624 "sAMAccountName",
1625 "(sAMAccountName=%s)(objectclass=group))",
1626 ldb_binary_encode_string(mem_ctx, alias_name));
1628 if (name != NULL) {
1629 return NT_STATUS_ALIAS_EXISTS;
1632 msg = ldb_msg_new(mem_ctx);
1633 if (msg == NULL) {
1634 return NT_STATUS_NO_MEMORY;
1637 /* add core elements to the ldb_message for the alias */
1638 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1639 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1640 if (!msg->dn) {
1641 return NT_STATUS_NO_MEMORY;
1644 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1645 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1646 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1648 /* create the alias */
1649 ret = ldb_add(d_state->sam_ctx, msg);
1650 switch (ret) {
1651 case LDB_SUCCESS:
1652 break;
1653 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1654 return NT_STATUS_ALIAS_EXISTS;
1655 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1656 return NT_STATUS_ACCESS_DENIED;
1657 default:
1658 DEBUG(0,("Failed to create alias record %s: %s\n",
1659 ldb_dn_get_linearized(msg->dn),
1660 ldb_errstring(d_state->sam_ctx)));
1661 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1664 a_state = talloc(d_state, struct samr_account_state);
1665 if (!a_state) {
1666 return NT_STATUS_NO_MEMORY;
1669 a_state->sam_ctx = d_state->sam_ctx;
1670 a_state->access_mask = r->in.access_mask;
1671 a_state->domain_state = talloc_reference(a_state, d_state);
1672 a_state->account_dn = talloc_steal(a_state, msg->dn);
1674 /* retrieve the sid for the alias just created */
1675 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1676 msg->dn, "objectSid", NULL);
1678 a_state->account_name = talloc_strdup(a_state, alias_name);
1679 if (!a_state->account_name) {
1680 return NT_STATUS_NO_MEMORY;
1683 /* create the policy handle */
1684 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1685 if (a_handle == NULL)
1686 return NT_STATUS_NO_MEMORY;
1688 a_handle->data = talloc_steal(a_handle, a_state);
1690 *r->out.alias_handle = a_handle->wire_handle;
1692 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1694 return NT_STATUS_OK;
1699 samr_EnumDomainAliases
1701 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1702 struct samr_EnumDomainAliases *r)
1704 struct dcesrv_handle *h;
1705 struct samr_domain_state *d_state;
1706 struct ldb_message **res;
1707 int ldb_cnt, count, i, first;
1708 struct samr_SamEntry *entries;
1709 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1710 struct samr_SamArray *sam;
1712 *r->out.resume_handle = 0;
1713 *r->out.sam = NULL;
1714 *r->out.num_entries = 0;
1716 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1718 d_state = h->data;
1720 /* search for all domain groups in this domain. This could possibly be
1721 cached and resumed based on resume_key */
1722 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1723 d_state->domain_dn,
1724 &res, attrs,
1725 d_state->domain_sid,
1726 "(&(|(grouptype=%d)(grouptype=%d)))"
1727 "(objectclass=group))",
1728 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1729 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1730 if (ldb_cnt == -1) {
1731 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1733 if (ldb_cnt == 0) {
1734 return NT_STATUS_OK;
1737 /* convert to SamEntry format */
1738 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1739 if (!entries) {
1740 return NT_STATUS_NO_MEMORY;
1743 count = 0;
1745 for (i=0;i<ldb_cnt;i++) {
1746 struct dom_sid *alias_sid;
1748 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1749 "objectSid");
1751 if (alias_sid == NULL)
1752 continue;
1754 entries[count].idx =
1755 alias_sid->sub_auths[alias_sid->num_auths-1];
1756 entries[count].name.string =
1757 samdb_result_string(res[i], "sAMAccountName", "");
1758 count += 1;
1761 /* sort the results by rid */
1762 qsort(entries, count, sizeof(struct samr_SamEntry),
1763 (comparison_fn_t)compare_SamEntry);
1765 /* find the first entry to return */
1766 for (first=0;
1767 first<count && entries[first].idx <= *r->in.resume_handle;
1768 first++) ;
1770 if (first == count) {
1771 return NT_STATUS_OK;
1774 *r->out.num_entries = count - first;
1775 *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1777 sam = talloc(mem_ctx, struct samr_SamArray);
1778 if (!sam) {
1779 return NT_STATUS_NO_MEMORY;
1782 sam->entries = entries+first;
1783 sam->count = *r->out.num_entries;
1785 *r->out.sam = sam;
1787 if (*r->out.num_entries < count - first) {
1788 *r->out.resume_handle =
1789 entries[first+*r->out.num_entries-1].idx;
1790 return STATUS_MORE_ENTRIES;
1793 return NT_STATUS_OK;
1798 samr_GetAliasMembership
1800 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1801 struct samr_GetAliasMembership *r)
1803 struct dcesrv_handle *h;
1804 struct samr_domain_state *d_state;
1805 struct ldb_message **res;
1806 int i, count = 0;
1808 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1810 d_state = h->data;
1812 if (r->in.sids->num_sids > 0) {
1813 const char *filter;
1814 const char * const attrs[2] = { "objectSid", NULL };
1816 filter = talloc_asprintf(mem_ctx,
1817 "(&(|(grouptype=%d)(grouptype=%d))"
1818 "(objectclass=group)(|",
1819 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1820 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1821 if (filter == NULL)
1822 return NT_STATUS_NO_MEMORY;
1824 for (i=0; i<r->in.sids->num_sids; i++) {
1825 const char *memberdn;
1827 memberdn =
1828 samdb_search_string(d_state->sam_ctx,
1829 mem_ctx, NULL, "distinguishedName",
1830 "(objectSid=%s)",
1831 ldap_encode_ndr_dom_sid(mem_ctx,
1832 r->in.sids->sids[i].sid));
1834 if (memberdn == NULL)
1835 continue;
1837 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1838 filter, memberdn);
1839 if (filter == NULL)
1840 return NT_STATUS_NO_MEMORY;
1843 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1844 d_state->domain_dn, &res, attrs,
1845 d_state->domain_sid, "%s))", filter);
1846 if (count < 0)
1847 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1850 r->out.rids->count = 0;
1851 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1852 if (r->out.rids->ids == NULL)
1853 return NT_STATUS_NO_MEMORY;
1855 for (i=0; i<count; i++) {
1856 struct dom_sid *alias_sid;
1858 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1860 if (alias_sid == NULL) {
1861 DEBUG(0, ("Could not find objectSid\n"));
1862 continue;
1865 r->out.rids->ids[r->out.rids->count] =
1866 alias_sid->sub_auths[alias_sid->num_auths-1];
1867 r->out.rids->count += 1;
1870 return NT_STATUS_OK;
1875 samr_LookupNames
1877 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1878 struct samr_LookupNames *r)
1880 struct dcesrv_handle *h;
1881 struct samr_domain_state *d_state;
1882 int i, num_mapped;
1883 NTSTATUS status = NT_STATUS_OK;
1884 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1885 int count;
1887 ZERO_STRUCTP(r->out.rids);
1888 ZERO_STRUCTP(r->out.types);
1890 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1892 d_state = h->data;
1894 if (r->in.num_names == 0) {
1895 return NT_STATUS_OK;
1898 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1899 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1900 if (!r->out.rids->ids || !r->out.types->ids) {
1901 return NT_STATUS_NO_MEMORY;
1903 r->out.rids->count = r->in.num_names;
1904 r->out.types->count = r->in.num_names;
1906 num_mapped = 0;
1908 for (i=0;i<r->in.num_names;i++) {
1909 struct ldb_message **res;
1910 struct dom_sid *sid;
1911 uint32_t atype, rtype;
1913 r->out.rids->ids[i] = 0;
1914 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1916 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1917 "sAMAccountName=%s",
1918 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1919 if (count != 1) {
1920 status = STATUS_SOME_UNMAPPED;
1921 continue;
1924 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1925 if (sid == NULL) {
1926 status = STATUS_SOME_UNMAPPED;
1927 continue;
1930 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1931 if (atype == 0) {
1932 status = STATUS_SOME_UNMAPPED;
1933 continue;
1936 rtype = samdb_atype_map(atype);
1938 if (rtype == SID_NAME_UNKNOWN) {
1939 status = STATUS_SOME_UNMAPPED;
1940 continue;
1943 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1944 r->out.types->ids[i] = rtype;
1945 num_mapped++;
1948 if (num_mapped == 0) {
1949 return NT_STATUS_NONE_MAPPED;
1951 return status;
1956 samr_LookupRids
1958 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1959 struct samr_LookupRids *r)
1961 struct dcesrv_handle *h;
1962 struct samr_domain_state *d_state;
1963 int i, total;
1964 NTSTATUS status = NT_STATUS_OK;
1965 struct lsa_String *names;
1966 uint32_t *ids;
1968 ZERO_STRUCTP(r->out.names);
1969 ZERO_STRUCTP(r->out.types);
1971 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1973 d_state = h->data;
1975 if (r->in.num_rids == 0)
1976 return NT_STATUS_OK;
1978 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1979 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1981 if ((names == NULL) || (ids == NULL))
1982 return NT_STATUS_NO_MEMORY;
1984 total = 0;
1986 for (i=0; i<r->in.num_rids; i++) {
1987 struct ldb_message **res;
1988 int count;
1989 const char * const attrs[] = { "sAMAccountType",
1990 "sAMAccountName", NULL };
1991 uint32_t atype;
1992 struct dom_sid *sid;
1994 ids[i] = SID_NAME_UNKNOWN;
1996 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1997 if (sid == NULL) {
1998 names[i].string = NULL;
1999 status = STATUS_SOME_UNMAPPED;
2000 continue;
2003 count = gendb_search(d_state->sam_ctx, mem_ctx,
2004 d_state->domain_dn, &res, attrs,
2005 "(objectSid=%s)",
2006 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2007 if (count != 1) {
2008 names[i].string = NULL;
2009 status = STATUS_SOME_UNMAPPED;
2010 continue;
2013 names[i].string = samdb_result_string(res[0], "sAMAccountName",
2014 NULL);
2016 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
2017 if (atype == 0) {
2018 status = STATUS_SOME_UNMAPPED;
2019 continue;
2022 ids[i] = samdb_atype_map(atype);
2024 if (ids[i] == SID_NAME_UNKNOWN) {
2025 status = STATUS_SOME_UNMAPPED;
2026 continue;
2030 r->out.names->names = names;
2031 r->out.names->count = r->in.num_rids;
2033 r->out.types->ids = ids;
2034 r->out.types->count = r->in.num_rids;
2036 return status;
2041 samr_OpenGroup
2043 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2044 struct samr_OpenGroup *r)
2046 struct samr_domain_state *d_state;
2047 struct samr_account_state *a_state;
2048 struct dcesrv_handle *h;
2049 const char *groupname;
2050 struct dom_sid *sid;
2051 struct ldb_message **msgs;
2052 struct dcesrv_handle *g_handle;
2053 const char * const attrs[2] = { "sAMAccountName", NULL };
2054 int ret;
2056 ZERO_STRUCTP(r->out.group_handle);
2058 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2060 d_state = h->data;
2062 /* form the group SID */
2063 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2064 if (!sid) {
2065 return NT_STATUS_NO_MEMORY;
2068 /* search for the group record */
2069 ret = gendb_search(d_state->sam_ctx,
2070 mem_ctx, d_state->domain_dn, &msgs, attrs,
2071 "(&(objectSid=%s)(objectclass=group)"
2072 "(grouptype=%d))",
2073 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2074 GTYPE_SECURITY_GLOBAL_GROUP);
2075 if (ret == 0) {
2076 return NT_STATUS_NO_SUCH_GROUP;
2078 if (ret != 1) {
2079 DEBUG(0,("Found %d records matching sid %s\n",
2080 ret, dom_sid_string(mem_ctx, sid)));
2081 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2084 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2085 if (groupname == NULL) {
2086 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2087 dom_sid_string(mem_ctx, sid)));
2088 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2091 a_state = talloc(d_state, struct samr_account_state);
2092 if (!a_state) {
2093 return NT_STATUS_NO_MEMORY;
2095 a_state->sam_ctx = d_state->sam_ctx;
2096 a_state->access_mask = r->in.access_mask;
2097 a_state->domain_state = talloc_reference(a_state, d_state);
2098 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2099 a_state->account_sid = talloc_steal(a_state, sid);
2100 a_state->account_name = talloc_strdup(a_state, groupname);
2101 if (!a_state->account_name) {
2102 return NT_STATUS_NO_MEMORY;
2105 /* create the policy handle */
2106 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2107 if (!g_handle) {
2108 return NT_STATUS_NO_MEMORY;
2111 g_handle->data = talloc_steal(g_handle, a_state);
2113 *r->out.group_handle = g_handle->wire_handle;
2115 return NT_STATUS_OK;
2119 samr_QueryGroupInfo
2121 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2122 struct samr_QueryGroupInfo *r)
2124 struct dcesrv_handle *h;
2125 struct samr_account_state *a_state;
2126 struct ldb_message *msg;
2127 struct ldb_result *res;
2128 const char * const attrs[4] = { "sAMAccountName", "description",
2129 "numMembers", NULL };
2130 int ret;
2131 union samr_GroupInfo *info;
2133 *r->out.info = NULL;
2135 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2137 a_state = h->data;
2139 ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2141 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2142 return NT_STATUS_NO_SUCH_GROUP;
2143 } else if (ret != LDB_SUCCESS) {
2144 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2145 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2148 if (res->count != 1) {
2149 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2151 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2153 msg = res->msgs[0];
2155 /* allocate the info structure */
2156 info = talloc_zero(mem_ctx, union samr_GroupInfo);
2157 if (info == NULL) {
2158 return NT_STATUS_NO_MEMORY;
2161 /* Fill in the level */
2162 switch (r->in.level) {
2163 case GROUPINFOALL:
2164 QUERY_STRING(msg, all.name, "sAMAccountName");
2165 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2166 QUERY_UINT (msg, all.num_members, "numMembers")
2167 QUERY_STRING(msg, all.description, "description");
2168 break;
2169 case GROUPINFONAME:
2170 QUERY_STRING(msg, name, "sAMAccountName");
2171 break;
2172 case GROUPINFOATTRIBUTES:
2173 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2174 break;
2175 case GROUPINFODESCRIPTION:
2176 QUERY_STRING(msg, description, "description");
2177 break;
2178 case GROUPINFOALL2:
2179 QUERY_STRING(msg, all2.name, "sAMAccountName");
2180 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2181 QUERY_UINT (msg, all2.num_members, "numMembers")
2182 QUERY_STRING(msg, all2.description, "description");
2183 break;
2184 default:
2185 talloc_free(info);
2186 return NT_STATUS_INVALID_INFO_CLASS;
2189 *r->out.info = info;
2191 return NT_STATUS_OK;
2196 samr_SetGroupInfo
2198 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2199 struct samr_SetGroupInfo *r)
2201 struct dcesrv_handle *h;
2202 struct samr_account_state *g_state;
2203 struct ldb_message *msg;
2204 struct ldb_context *sam_ctx;
2205 int ret;
2207 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2209 g_state = h->data;
2210 sam_ctx = g_state->sam_ctx;
2212 msg = ldb_msg_new(mem_ctx);
2213 if (msg == NULL) {
2214 return NT_STATUS_NO_MEMORY;
2217 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2218 if (!msg->dn) {
2219 return NT_STATUS_NO_MEMORY;
2222 switch (r->in.level) {
2223 case GROUPINFODESCRIPTION:
2224 SET_STRING(msg, description, "description");
2225 break;
2226 case GROUPINFONAME:
2227 /* On W2k3 this does not change the name, it changes the
2228 * sAMAccountName attribute */
2229 SET_STRING(msg, name, "sAMAccountName");
2230 break;
2231 case GROUPINFOATTRIBUTES:
2232 /* This does not do anything obviously visible in W2k3 LDAP */
2233 return NT_STATUS_OK;
2234 default:
2235 return NT_STATUS_INVALID_INFO_CLASS;
2238 /* modify the samdb record */
2239 ret = ldb_modify(g_state->sam_ctx, msg);
2240 if (ret != 0) {
2241 /* we really need samdb.c to return NTSTATUS */
2242 return NT_STATUS_UNSUCCESSFUL;
2245 return NT_STATUS_OK;
2250 samr_AddGroupMember
2252 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2253 struct samr_AddGroupMember *r)
2255 struct dcesrv_handle *h;
2256 struct samr_account_state *a_state;
2257 struct samr_domain_state *d_state;
2258 struct ldb_message *mod;
2259 struct dom_sid *membersid;
2260 const char *memberdn;
2261 struct ldb_result *res;
2262 const char * const attrs[] = { NULL };
2263 int ret;
2265 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2267 a_state = h->data;
2268 d_state = a_state->domain_state;
2270 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2271 if (membersid == NULL)
2272 return NT_STATUS_NO_MEMORY;
2274 /* In native mode, AD can also nest domain groups. Not sure yet
2275 * whether this is also available via RPC. */
2276 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2277 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2278 "(&(objectSid=%s)(objectclass=user))",
2279 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2281 if (ret != 0) {
2282 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2285 if (res->count == 0) {
2286 return NT_STATUS_NO_SUCH_USER;
2289 if (res->count > 1) {
2290 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2293 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2295 if (memberdn == NULL)
2296 return NT_STATUS_NO_MEMORY;
2298 mod = ldb_msg_new(mem_ctx);
2299 if (mod == NULL) {
2300 return NT_STATUS_NO_MEMORY;
2303 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2305 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2306 memberdn) != 0)
2307 return NT_STATUS_UNSUCCESSFUL;
2309 ret = ldb_modify(a_state->sam_ctx, mod);
2310 switch (ret) {
2311 case LDB_SUCCESS:
2312 return NT_STATUS_OK;
2313 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2314 return NT_STATUS_MEMBER_IN_GROUP;
2315 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2316 return NT_STATUS_ACCESS_DENIED;
2317 default:
2318 return NT_STATUS_UNSUCCESSFUL;
2325 samr_DeleteDomainGroup
2327 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2328 struct samr_DeleteDomainGroup *r)
2330 struct dcesrv_handle *h;
2331 struct samr_account_state *a_state;
2332 int ret;
2334 *r->out.group_handle = *r->in.group_handle;
2336 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2338 a_state = h->data;
2340 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2341 if (ret != 0) {
2342 return NT_STATUS_UNSUCCESSFUL;
2345 ZERO_STRUCTP(r->out.group_handle);
2347 return NT_STATUS_OK;
2352 samr_DeleteGroupMember
2354 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2355 struct samr_DeleteGroupMember *r)
2357 struct dcesrv_handle *h;
2358 struct samr_account_state *a_state;
2359 struct samr_domain_state *d_state;
2360 struct ldb_message *mod;
2361 struct dom_sid *membersid;
2362 const char *memberdn;
2363 struct ldb_result *res;
2364 const char * const attrs[] = { NULL };
2365 int ret;
2367 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2369 a_state = h->data;
2370 d_state = a_state->domain_state;
2372 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2373 if (membersid == NULL)
2374 return NT_STATUS_NO_MEMORY;
2376 /* In native mode, AD can also nest domain groups. Not sure yet
2377 * whether this is also available via RPC. */
2378 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2379 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2380 "(&(objectSid=%s)(objectclass=user))",
2381 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2383 if (ret != 0) {
2384 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2387 if (res->count == 0) {
2388 return NT_STATUS_NO_SUCH_USER;
2391 if (res->count > 1) {
2392 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2395 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2397 if (memberdn == NULL)
2398 return NT_STATUS_NO_MEMORY;
2400 mod = ldb_msg_new(mem_ctx);
2401 if (mod == NULL) {
2402 return NT_STATUS_NO_MEMORY;
2405 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2407 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2408 memberdn) != 0) {
2409 return NT_STATUS_NO_MEMORY;
2412 ret = ldb_modify(a_state->sam_ctx, mod);
2413 switch (ret) {
2414 case LDB_SUCCESS:
2415 return NT_STATUS_OK;
2416 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2417 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2418 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2419 return NT_STATUS_ACCESS_DENIED;
2420 default:
2421 return NT_STATUS_UNSUCCESSFUL;
2428 samr_QueryGroupMember
2430 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2431 struct samr_QueryGroupMember *r)
2433 struct dcesrv_handle *h;
2434 struct samr_account_state *a_state;
2435 struct ldb_message **res;
2436 struct ldb_message_element *el;
2437 struct samr_RidTypeArray *array;
2438 const char * const attrs[2] = { "member", NULL };
2439 int ret;
2441 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2443 a_state = h->data;
2445 /* pull the member attribute */
2446 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2447 a_state->account_dn, &res, attrs);
2449 if (ret != 1) {
2450 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2453 array = talloc(mem_ctx, struct samr_RidTypeArray);
2455 if (array == NULL)
2456 return NT_STATUS_NO_MEMORY;
2458 ZERO_STRUCTP(array);
2460 el = ldb_msg_find_element(res[0], "member");
2462 if (el != NULL) {
2463 int i;
2465 array->count = el->num_values;
2467 array->rids = talloc_array(mem_ctx, uint32_t,
2468 el->num_values);
2469 if (array->rids == NULL)
2470 return NT_STATUS_NO_MEMORY;
2472 array->types = talloc_array(mem_ctx, uint32_t,
2473 el->num_values);
2474 if (array->types == NULL)
2475 return NT_STATUS_NO_MEMORY;
2477 for (i=0; i<el->num_values; i++) {
2478 struct ldb_message **res2;
2479 const char * const attrs2[2] = { "objectSid", NULL };
2480 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2481 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2482 &res2, attrs2);
2483 if (ret != 1)
2484 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2486 array->rids[i] =
2487 samdb_result_rid_from_sid(mem_ctx, res2[0],
2488 "objectSid", 0);
2490 if (array->rids[i] == 0)
2491 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2493 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2497 *r->out.rids = array;
2499 return NT_STATUS_OK;
2504 samr_SetMemberAttributesOfGroup
2506 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2507 struct samr_SetMemberAttributesOfGroup *r)
2509 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2514 samr_OpenAlias
2516 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2517 struct samr_OpenAlias *r)
2519 struct samr_domain_state *d_state;
2520 struct samr_account_state *a_state;
2521 struct dcesrv_handle *h;
2522 const char *alias_name;
2523 struct dom_sid *sid;
2524 struct ldb_message **msgs;
2525 struct dcesrv_handle *g_handle;
2526 const char * const attrs[2] = { "sAMAccountName", NULL };
2527 int ret;
2529 ZERO_STRUCTP(r->out.alias_handle);
2531 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2533 d_state = h->data;
2535 /* form the alias SID */
2536 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2537 if (sid == NULL)
2538 return NT_STATUS_NO_MEMORY;
2540 /* search for the group record */
2541 ret = gendb_search(d_state->sam_ctx,
2542 mem_ctx, d_state->domain_dn, &msgs, attrs,
2543 "(&(objectSid=%s)(objectclass=group)"
2544 "(|(grouptype=%d)(grouptype=%d)))",
2545 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2546 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2547 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2548 if (ret == 0) {
2549 return NT_STATUS_NO_SUCH_ALIAS;
2551 if (ret != 1) {
2552 DEBUG(0,("Found %d records matching sid %s\n",
2553 ret, dom_sid_string(mem_ctx, sid)));
2554 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2557 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2558 if (alias_name == NULL) {
2559 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2560 dom_sid_string(mem_ctx, sid)));
2561 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2564 a_state = talloc(d_state, struct samr_account_state);
2565 if (!a_state) {
2566 return NT_STATUS_NO_MEMORY;
2568 a_state->sam_ctx = d_state->sam_ctx;
2569 a_state->access_mask = r->in.access_mask;
2570 a_state->domain_state = talloc_reference(a_state, d_state);
2571 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2572 a_state->account_sid = talloc_steal(a_state, sid);
2573 a_state->account_name = talloc_strdup(a_state, alias_name);
2574 if (!a_state->account_name) {
2575 return NT_STATUS_NO_MEMORY;
2578 /* create the policy handle */
2579 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2580 if (!g_handle) {
2581 return NT_STATUS_NO_MEMORY;
2584 g_handle->data = talloc_steal(g_handle, a_state);
2586 *r->out.alias_handle = g_handle->wire_handle;
2588 return NT_STATUS_OK;
2593 samr_QueryAliasInfo
2595 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2596 struct samr_QueryAliasInfo *r)
2598 struct dcesrv_handle *h;
2599 struct samr_account_state *a_state;
2600 struct ldb_message *msg, **res;
2601 const char * const attrs[4] = { "sAMAccountName", "description",
2602 "numMembers", NULL };
2603 int ret;
2604 union samr_AliasInfo *info;
2606 *r->out.info = NULL;
2608 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2610 a_state = h->data;
2612 /* pull all the alias attributes */
2613 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2614 a_state->account_dn ,&res, attrs);
2615 if (ret != 1) {
2616 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2618 msg = res[0];
2620 /* allocate the info structure */
2621 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2622 if (info == NULL) {
2623 return NT_STATUS_NO_MEMORY;
2626 switch(r->in.level) {
2627 case ALIASINFOALL:
2628 QUERY_STRING(msg, all.name, "sAMAccountName");
2629 QUERY_UINT (msg, all.num_members, "numMembers");
2630 QUERY_STRING(msg, all.description, "description");
2631 break;
2632 case ALIASINFONAME:
2633 QUERY_STRING(msg, name, "sAMAccountName");
2634 break;
2635 case ALIASINFODESCRIPTION:
2636 QUERY_STRING(msg, description, "description");
2637 break;
2638 default:
2639 talloc_free(info);
2640 return NT_STATUS_INVALID_INFO_CLASS;
2643 *r->out.info = info;
2645 return NT_STATUS_OK;
2650 samr_SetAliasInfo
2652 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2653 struct samr_SetAliasInfo *r)
2655 struct dcesrv_handle *h;
2656 struct samr_account_state *a_state;
2657 struct ldb_message *msg;
2658 struct ldb_context *sam_ctx;
2659 int ret;
2661 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2663 a_state = h->data;
2664 sam_ctx = a_state->sam_ctx;
2666 msg = ldb_msg_new(mem_ctx);
2667 if (msg == NULL) {
2668 return NT_STATUS_NO_MEMORY;
2671 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2672 if (!msg->dn) {
2673 return NT_STATUS_NO_MEMORY;
2676 switch (r->in.level) {
2677 case ALIASINFODESCRIPTION:
2678 SET_STRING(msg, description, "description");
2679 break;
2680 case ALIASINFONAME:
2681 /* On W2k3 this does not change the name, it changes the
2682 * sAMAccountName attribute */
2683 SET_STRING(msg, name, "sAMAccountName");
2684 break;
2685 default:
2686 return NT_STATUS_INVALID_INFO_CLASS;
2689 /* modify the samdb record */
2690 ret = ldb_modify(a_state->sam_ctx, msg);
2691 if (ret != 0) {
2692 /* we really need samdb.c to return NTSTATUS */
2693 return NT_STATUS_UNSUCCESSFUL;
2696 return NT_STATUS_OK;
2701 samr_DeleteDomAlias
2703 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2704 struct samr_DeleteDomAlias *r)
2706 struct dcesrv_handle *h;
2707 struct samr_account_state *a_state;
2708 int ret;
2710 *r->out.alias_handle = *r->in.alias_handle;
2712 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2714 a_state = h->data;
2716 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2717 if (ret != 0) {
2718 return NT_STATUS_UNSUCCESSFUL;
2721 ZERO_STRUCTP(r->out.alias_handle);
2723 return NT_STATUS_OK;
2728 samr_AddAliasMember
2730 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2731 struct samr_AddAliasMember *r)
2733 struct dcesrv_handle *h;
2734 struct samr_account_state *a_state;
2735 struct samr_domain_state *d_state;
2736 struct ldb_message *mod;
2737 struct ldb_message **msgs;
2738 const char * const attrs[] = { NULL };
2739 struct ldb_dn *memberdn = NULL;
2740 int ret;
2741 NTSTATUS status;
2743 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2745 a_state = h->data;
2746 d_state = a_state->domain_state;
2748 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2749 &msgs, attrs, "(objectsid=%s)",
2750 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2752 if (ret == 1) {
2753 memberdn = msgs[0]->dn;
2754 } else if (ret > 1) {
2755 DEBUG(0,("Found %d records matching sid %s\n",
2756 ret, dom_sid_string(mem_ctx, r->in.sid)));
2757 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2758 } else if (ret == 0) {
2759 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx,
2760 r->in.sid, &memberdn);
2761 if (!NT_STATUS_IS_OK(status)) {
2762 return status;
2764 } else {
2765 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2768 if (memberdn == NULL) {
2769 DEBUG(0, ("Could not find memberdn\n"));
2770 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2773 mod = ldb_msg_new(mem_ctx);
2774 if (mod == NULL) {
2775 return NT_STATUS_NO_MEMORY;
2778 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2780 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2781 ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2782 return NT_STATUS_UNSUCCESSFUL;
2784 if (ldb_modify(a_state->sam_ctx, mod) != 0)
2785 return NT_STATUS_UNSUCCESSFUL;
2787 return NT_STATUS_OK;
2792 samr_DeleteAliasMember
2794 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2795 struct samr_DeleteAliasMember *r)
2797 struct dcesrv_handle *h;
2798 struct samr_account_state *a_state;
2799 struct samr_domain_state *d_state;
2800 struct ldb_message *mod;
2801 const char *memberdn;
2803 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2805 a_state = h->data;
2806 d_state = a_state->domain_state;
2808 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2809 "distinguishedName", "(objectSid=%s)",
2810 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2812 if (memberdn == NULL)
2813 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2815 mod = ldb_msg_new(mem_ctx);
2816 if (mod == NULL) {
2817 return NT_STATUS_NO_MEMORY;
2820 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2822 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2823 memberdn) != 0)
2824 return NT_STATUS_UNSUCCESSFUL;
2826 if (ldb_modify(a_state->sam_ctx, mod) != 0)
2827 return NT_STATUS_UNSUCCESSFUL;
2829 return NT_STATUS_OK;
2834 samr_GetMembersInAlias
2836 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2837 struct samr_GetMembersInAlias *r)
2839 struct dcesrv_handle *h;
2840 struct samr_account_state *a_state;
2841 struct samr_domain_state *d_state;
2842 struct ldb_message **msgs;
2843 struct lsa_SidPtr *sids;
2844 struct ldb_message_element *el;
2845 const char * const attrs[2] = { "member", NULL};
2846 int ret;
2848 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2850 a_state = h->data;
2851 d_state = a_state->domain_state;
2853 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2854 a_state->account_dn, &msgs, attrs);
2856 if (ret == -1) {
2857 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2858 } else if (ret == 0) {
2859 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2860 } else if (ret != 1) {
2861 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2864 r->out.sids->num_sids = 0;
2865 r->out.sids->sids = NULL;
2867 el = ldb_msg_find_element(msgs[0], "member");
2869 if (el != NULL) {
2870 int i;
2872 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2873 el->num_values);
2875 if (sids == NULL)
2876 return NT_STATUS_NO_MEMORY;
2878 for (i=0; i<el->num_values; i++) {
2879 struct ldb_message **msgs2;
2880 const char * const attrs2[2] = { "objectSid", NULL };
2881 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2882 ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2883 &msgs2, attrs2);
2884 if (ret != 1)
2885 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2887 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2888 "objectSid");
2890 if (sids[i].sid == NULL)
2891 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2893 r->out.sids->num_sids = el->num_values;
2894 r->out.sids->sids = sids;
2897 return NT_STATUS_OK;
2901 samr_OpenUser
2903 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2904 struct samr_OpenUser *r)
2906 struct samr_domain_state *d_state;
2907 struct samr_account_state *a_state;
2908 struct dcesrv_handle *h;
2909 const char *account_name;
2910 struct dom_sid *sid;
2911 struct ldb_message **msgs;
2912 struct dcesrv_handle *u_handle;
2913 const char * const attrs[2] = { "sAMAccountName", NULL };
2914 int ret;
2916 ZERO_STRUCTP(r->out.user_handle);
2918 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2920 d_state = h->data;
2922 /* form the users SID */
2923 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2924 if (!sid) {
2925 return NT_STATUS_NO_MEMORY;
2928 /* search for the user record */
2929 ret = gendb_search(d_state->sam_ctx,
2930 mem_ctx, d_state->domain_dn, &msgs, attrs,
2931 "(&(objectSid=%s)(objectclass=user))",
2932 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2933 if (ret == 0) {
2934 return NT_STATUS_NO_SUCH_USER;
2936 if (ret != 1) {
2937 DEBUG(0,("Found %d records matching sid %s\n", ret,
2938 dom_sid_string(mem_ctx, sid)));
2939 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2942 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2943 if (account_name == NULL) {
2944 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2945 dom_sid_string(mem_ctx, sid)));
2946 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2949 a_state = talloc(mem_ctx, struct samr_account_state);
2950 if (!a_state) {
2951 return NT_STATUS_NO_MEMORY;
2953 a_state->sam_ctx = d_state->sam_ctx;
2954 a_state->access_mask = r->in.access_mask;
2955 a_state->domain_state = talloc_reference(a_state, d_state);
2956 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2957 a_state->account_sid = talloc_steal(a_state, sid);
2958 a_state->account_name = talloc_strdup(a_state, account_name);
2959 if (!a_state->account_name) {
2960 return NT_STATUS_NO_MEMORY;
2963 /* create the policy handle */
2964 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2965 if (!u_handle) {
2966 return NT_STATUS_NO_MEMORY;
2969 u_handle->data = talloc_steal(u_handle, a_state);
2971 *r->out.user_handle = u_handle->wire_handle;
2973 return NT_STATUS_OK;
2979 samr_DeleteUser
2981 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2982 struct samr_DeleteUser *r)
2984 struct dcesrv_handle *h;
2985 struct samr_account_state *a_state;
2986 int ret;
2988 *r->out.user_handle = *r->in.user_handle;
2990 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2992 a_state = h->data;
2994 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2995 if (ret != 0) {
2996 DEBUG(1, ("Failed to delete user: %s: %s\n",
2997 ldb_dn_get_linearized(a_state->account_dn),
2998 ldb_errstring(a_state->sam_ctx)));
2999 return NT_STATUS_UNSUCCESSFUL;
3002 ZERO_STRUCTP(r->out.user_handle);
3004 return NT_STATUS_OK;
3009 samr_QueryUserInfo
3011 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3012 struct samr_QueryUserInfo *r)
3014 struct dcesrv_handle *h;
3015 struct samr_account_state *a_state;
3016 struct ldb_message *msg, **res;
3017 int ret;
3018 struct ldb_context *sam_ctx;
3020 const char * const *attrs = NULL;
3021 union samr_UserInfo *info;
3023 *r->out.info = NULL;
3025 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3027 a_state = h->data;
3028 sam_ctx = a_state->sam_ctx;
3030 /* fill in the reply */
3031 switch (r->in.level) {
3032 case 1:
3034 static const char * const attrs2[] = {"sAMAccountName", "displayName",
3035 "primaryroupID", "description",
3036 "comment", NULL};
3037 attrs = attrs2;
3038 break;
3040 case 2:
3042 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
3043 attrs = attrs2;
3044 break;
3046 case 3:
3048 static const char * const attrs2[] = {"sAMAccountName",
3049 "displayName",
3050 "objectSid",
3051 "primaryGroupID",
3052 "homeDirectory",
3053 "homeDrive",
3054 "scriptPath",
3055 "profilePath",
3056 "userWorkstations",
3057 "lastLogon",
3058 "lastLogoff",
3059 "pwdLastSet",
3060 "logonHours",
3061 "badPwdCount",
3062 "logonCount",
3063 "userAccountControl", NULL};
3064 attrs = attrs2;
3065 break;
3067 case 4:
3069 static const char * const attrs2[] = {"logonHours", NULL};
3070 attrs = attrs2;
3071 break;
3073 case 5:
3075 static const char * const attrs2[] = {"sAMAccountName",
3076 "displayName",
3077 "objectSid",
3078 "primaryGroupID",
3079 "homeDirectory",
3080 "homeDrive",
3081 "scriptPath",
3082 "profilePath",
3083 "description",
3084 "userWorkstations",
3085 "lastLogon",
3086 "lastLogoff",
3087 "logonHours",
3088 "badPwdCount",
3089 "logonCount",
3090 "pwdLastSet",
3091 "accountExpires",
3092 "userAccountControl",
3093 NULL};
3094 attrs = attrs2;
3095 break;
3097 case 6:
3099 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
3100 attrs = attrs2;
3101 break;
3103 case 7:
3105 static const char * const attrs2[] = {"sAMAccountName", NULL};
3106 attrs = attrs2;
3107 break;
3109 case 8:
3111 static const char * const attrs2[] = {"displayName", NULL};
3112 attrs = attrs2;
3113 break;
3115 case 9:
3117 static const char * const attrs2[] = {"primaryGroupID", NULL};
3118 attrs = attrs2;
3119 break;
3121 case 10:
3123 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3124 attrs = attrs2;
3125 break;
3127 case 11:
3129 static const char * const attrs2[] = {"scriptPath", NULL};
3130 attrs = attrs2;
3131 break;
3133 case 12:
3135 static const char * const attrs2[] = {"profilePath", NULL};
3136 attrs = attrs2;
3137 break;
3139 case 13:
3141 static const char * const attrs2[] = {"description", NULL};
3142 attrs = attrs2;
3143 break;
3145 case 14:
3147 static const char * const attrs2[] = {"userWorkstations", NULL};
3148 attrs = attrs2;
3149 break;
3151 case 16:
3153 static const char * const attrs2[] = {"userAccountControl", "pwdLastSet", NULL};
3154 attrs = attrs2;
3155 break;
3157 case 17:
3159 static const char * const attrs2[] = {"accountExpires", NULL};
3160 attrs = attrs2;
3161 break;
3163 case 20:
3165 static const char * const attrs2[] = {"userParameters", NULL};
3166 attrs = attrs2;
3167 break;
3169 case 21:
3171 static const char * const attrs2[] = {"lastLogon",
3172 "lastLogoff",
3173 "pwdLastSet",
3174 "accountExpires",
3175 "sAMAccountName",
3176 "displayName",
3177 "homeDirectory",
3178 "homeDrive",
3179 "scriptPath",
3180 "profilePath",
3181 "description",
3182 "userWorkstations",
3183 "comment",
3184 "userParameters",
3185 "objectSid",
3186 "primaryGroupID",
3187 "userAccountControl",
3188 "logonHours",
3189 "badPwdCount",
3190 "logonCount",
3191 "countryCode",
3192 "codePage",
3193 NULL};
3194 attrs = attrs2;
3195 break;
3199 /* pull all the user attributes */
3200 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3201 a_state->account_dn ,&res, attrs);
3202 if (ret != 1) {
3203 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3205 msg = res[0];
3207 /* allocate the info structure */
3208 info = talloc_zero(mem_ctx, union samr_UserInfo);
3209 if (info == NULL) {
3210 return NT_STATUS_NO_MEMORY;
3213 /* fill in the reply */
3214 switch (r->in.level) {
3215 case 1:
3216 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3217 QUERY_STRING(msg, info1.full_name, "displayName");
3218 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3219 QUERY_STRING(msg, info1.description, "description");
3220 QUERY_STRING(msg, info1.comment, "comment");
3221 break;
3223 case 2:
3224 QUERY_STRING(msg, info2.comment, "comment");
3225 QUERY_UINT (msg, info2.country_code, "countryCode");
3226 QUERY_UINT (msg, info2.code_page, "codePage");
3227 break;
3229 case 3:
3230 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3231 QUERY_STRING(msg, info3.full_name, "displayName");
3232 QUERY_RID (msg, info3.rid, "objectSid");
3233 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3234 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3235 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3236 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3237 QUERY_STRING(msg, info3.profile_path, "profilePath");
3238 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3239 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3240 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3241 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3242 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3243 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3244 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3245 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3246 QUERY_UINT (msg, info3.logon_count, "logonCount");
3247 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3248 break;
3250 case 4:
3251 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3252 break;
3254 case 5:
3255 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3256 QUERY_STRING(msg, info5.full_name, "displayName");
3257 QUERY_RID (msg, info5.rid, "objectSid");
3258 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3259 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3260 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3261 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3262 QUERY_STRING(msg, info5.profile_path, "profilePath");
3263 QUERY_STRING(msg, info5.description, "description");
3264 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3265 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3266 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3267 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3268 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3269 QUERY_UINT (msg, info5.logon_count, "logonCount");
3270 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3271 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3272 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3273 break;
3275 case 6:
3276 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3277 QUERY_STRING(msg, info6.full_name, "displayName");
3278 break;
3280 case 7:
3281 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3282 break;
3284 case 8:
3285 QUERY_STRING(msg, info8.full_name, "displayName");
3286 break;
3288 case 9:
3289 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3290 break;
3292 case 10:
3293 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3294 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3295 break;
3297 case 11:
3298 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3299 break;
3301 case 12:
3302 QUERY_STRING(msg, info12.profile_path, "profilePath");
3303 break;
3305 case 13:
3306 QUERY_STRING(msg, info13.description, "description");
3307 break;
3309 case 14:
3310 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3311 break;
3313 case 16:
3314 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3315 break;
3317 case 17:
3318 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3319 break;
3321 case 20:
3322 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3323 break;
3325 case 21:
3326 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3327 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3328 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3329 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3330 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3331 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3332 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3333 QUERY_STRING(msg, info21.full_name, "displayName");
3334 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3335 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3336 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3337 QUERY_STRING(msg, info21.profile_path, "profilePath");
3338 QUERY_STRING(msg, info21.description, "description");
3339 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3340 QUERY_STRING(msg, info21.comment, "comment");
3341 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3342 QUERY_RID (msg, info21.rid, "objectSid");
3343 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3344 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3345 info->info21.fields_present = 0x00FFFFFF;
3346 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3347 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3348 QUERY_UINT (msg, info21.logon_count, "logonCount");
3349 QUERY_UINT (msg, info21.country_code, "countryCode");
3350 QUERY_UINT (msg, info21.code_page, "codePage");
3351 break;
3354 default:
3355 talloc_free(info);
3356 return NT_STATUS_INVALID_INFO_CLASS;
3359 *r->out.info = info;
3361 return NT_STATUS_OK;
3366 samr_SetUserInfo
3368 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3369 struct samr_SetUserInfo *r)
3371 struct dcesrv_handle *h;
3372 struct samr_account_state *a_state;
3373 struct ldb_message *msg;
3374 int ret;
3375 NTSTATUS status = NT_STATUS_OK;
3376 struct ldb_context *sam_ctx;
3378 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3380 a_state = h->data;
3381 sam_ctx = a_state->sam_ctx;
3383 msg = ldb_msg_new(mem_ctx);
3384 if (msg == NULL) {
3385 return NT_STATUS_NO_MEMORY;
3388 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3389 if (!msg->dn) {
3390 return NT_STATUS_NO_MEMORY;
3393 switch (r->in.level) {
3394 case 2:
3395 SET_STRING(msg, info2.comment, "comment");
3396 SET_UINT (msg, info2.country_code, "countryCode");
3397 SET_UINT (msg, info2.code_page, "codePage");
3398 break;
3400 case 4:
3401 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3402 break;
3404 case 6:
3405 SET_STRING(msg, info6.full_name, "displayName");
3406 break;
3408 case 7:
3409 SET_STRING(msg, info7.account_name, "samAccountName");
3410 break;
3412 case 8:
3413 SET_STRING(msg, info8.full_name, "displayName");
3414 break;
3416 case 9:
3417 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3418 break;
3420 case 10:
3421 SET_STRING(msg, info10.home_directory, "homeDirectory");
3422 SET_STRING(msg, info10.home_drive, "homeDrive");
3423 break;
3425 case 11:
3426 SET_STRING(msg, info11.logon_script, "scriptPath");
3427 break;
3429 case 12:
3430 SET_STRING(msg, info12.profile_path, "profilePath");
3431 break;
3433 case 13:
3434 SET_STRING(msg, info13.description, "description");
3435 break;
3437 case 14:
3438 SET_STRING(msg, info14.workstations, "userWorkstations");
3439 break;
3441 case 16:
3442 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3443 break;
3445 case 17:
3446 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3447 break;
3449 case 20:
3450 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3451 break;
3453 case 21:
3454 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3455 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3456 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3457 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3458 SET_STRING(msg, info21.account_name, "samAccountName");
3459 IFSET(SAMR_FIELD_FULL_NAME)
3460 SET_STRING(msg, info21.full_name, "displayName");
3461 IFSET(SAMR_FIELD_DESCRIPTION)
3462 SET_STRING(msg, info21.description, "description");
3463 IFSET(SAMR_FIELD_COMMENT)
3464 SET_STRING(msg, info21.comment, "comment");
3465 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3466 SET_STRING(msg, info21.logon_script, "scriptPath");
3467 IFSET(SAMR_FIELD_PROFILE_PATH)
3468 SET_STRING(msg, info21.profile_path, "profilePath");
3469 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3470 SET_STRING(msg, info21.home_directory, "homeDirectory");
3471 IFSET(SAMR_FIELD_HOME_DRIVE)
3472 SET_STRING(msg, info21.home_drive, "homeDrive");
3473 IFSET(SAMR_FIELD_WORKSTATIONS)
3474 SET_STRING(msg, info21.workstations, "userWorkstations");
3475 IFSET(SAMR_FIELD_LOGON_HOURS)
3476 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3477 IFSET(SAMR_FIELD_ACCT_FLAGS)
3478 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3479 IFSET(SAMR_FIELD_PARAMETERS)
3480 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3481 IFSET(SAMR_FIELD_COUNTRY_CODE)
3482 SET_UINT (msg, info21.country_code, "countryCode");
3483 IFSET(SAMR_FIELD_CODE_PAGE)
3484 SET_UINT (msg, info21.code_page, "codePage");
3485 #undef IFSET
3486 break;
3488 case 23:
3489 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3490 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3491 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3492 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3493 SET_STRING(msg, info23.info.account_name, "samAccountName");
3494 IFSET(SAMR_FIELD_FULL_NAME)
3495 SET_STRING(msg, info23.info.full_name, "displayName");
3496 IFSET(SAMR_FIELD_DESCRIPTION)
3497 SET_STRING(msg, info23.info.description, "description");
3498 IFSET(SAMR_FIELD_COMMENT)
3499 SET_STRING(msg, info23.info.comment, "comment");
3500 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3501 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3502 IFSET(SAMR_FIELD_PROFILE_PATH)
3503 SET_STRING(msg, info23.info.profile_path, "profilePath");
3504 IFSET(SAMR_FIELD_WORKSTATIONS)
3505 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3506 IFSET(SAMR_FIELD_LOGON_HOURS)
3507 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3508 IFSET(SAMR_FIELD_ACCT_FLAGS)
3509 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3510 IFSET(SAMR_FIELD_PARAMETERS)
3511 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3512 IFSET(SAMR_FIELD_COUNTRY_CODE)
3513 SET_UINT (msg, info23.info.country_code, "countryCode");
3514 IFSET(SAMR_FIELD_CODE_PAGE)
3515 SET_UINT (msg, info23.info.code_page, "codePage");
3516 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3517 status = samr_set_password(dce_call,
3518 a_state->sam_ctx,
3519 a_state->account_dn,
3520 a_state->domain_state->domain_dn,
3521 mem_ctx, msg,
3522 &r->in.info->info23.password);
3523 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3524 status = samr_set_password(dce_call,
3525 a_state->sam_ctx,
3526 a_state->account_dn,
3527 a_state->domain_state->domain_dn,
3528 mem_ctx, msg,
3529 &r->in.info->info23.password);
3531 #undef IFSET
3532 break;
3534 /* the set password levels are handled separately */
3535 case 24:
3536 status = samr_set_password(dce_call,
3537 a_state->sam_ctx,
3538 a_state->account_dn,
3539 a_state->domain_state->domain_dn,
3540 mem_ctx, msg,
3541 &r->in.info->info24.password);
3542 break;
3544 case 25:
3545 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3546 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3547 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3548 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3549 SET_STRING(msg, info25.info.account_name, "samAccountName");
3550 IFSET(SAMR_FIELD_FULL_NAME)
3551 SET_STRING(msg, info25.info.full_name, "displayName");
3552 IFSET(SAMR_FIELD_DESCRIPTION)
3553 SET_STRING(msg, info25.info.description, "description");
3554 IFSET(SAMR_FIELD_COMMENT)
3555 SET_STRING(msg, info25.info.comment, "comment");
3556 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3557 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3558 IFSET(SAMR_FIELD_PROFILE_PATH)
3559 SET_STRING(msg, info25.info.profile_path, "profilePath");
3560 IFSET(SAMR_FIELD_WORKSTATIONS)
3561 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3562 IFSET(SAMR_FIELD_LOGON_HOURS)
3563 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3564 IFSET(SAMR_FIELD_ACCT_FLAGS)
3565 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3566 IFSET(SAMR_FIELD_PARAMETERS)
3567 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3568 IFSET(SAMR_FIELD_COUNTRY_CODE)
3569 SET_UINT (msg, info25.info.country_code, "countryCode");
3570 IFSET(SAMR_FIELD_CODE_PAGE)
3571 SET_UINT (msg, info25.info.code_page, "codePage");
3572 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3573 status = samr_set_password_ex(dce_call,
3574 a_state->sam_ctx,
3575 a_state->account_dn,
3576 a_state->domain_state->domain_dn,
3577 mem_ctx, msg,
3578 &r->in.info->info25.password);
3579 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3580 status = samr_set_password_ex(dce_call,
3581 a_state->sam_ctx,
3582 a_state->account_dn,
3583 a_state->domain_state->domain_dn,
3584 mem_ctx, msg,
3585 &r->in.info->info25.password);
3587 #undef IFSET
3588 break;
3590 /* the set password levels are handled separately */
3591 case 26:
3592 status = samr_set_password_ex(dce_call,
3593 a_state->sam_ctx,
3594 a_state->account_dn,
3595 a_state->domain_state->domain_dn,
3596 mem_ctx, msg,
3597 &r->in.info->info26.password);
3598 break;
3601 default:
3602 /* many info classes are not valid for SetUserInfo */
3603 return NT_STATUS_INVALID_INFO_CLASS;
3606 if (!NT_STATUS_IS_OK(status)) {
3607 return status;
3610 /* modify the samdb record */
3611 ret = ldb_modify(a_state->sam_ctx, msg);
3612 if (ret != 0) {
3613 DEBUG(1,("Failed to modify record %s: %s\n",
3614 ldb_dn_get_linearized(a_state->account_dn),
3615 ldb_errstring(a_state->sam_ctx)));
3617 /* we really need samdb.c to return NTSTATUS */
3618 return NT_STATUS_UNSUCCESSFUL;
3621 return NT_STATUS_OK;
3626 samr_GetGroupsForUser
3628 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3629 struct samr_GetGroupsForUser *r)
3631 struct dcesrv_handle *h;
3632 struct samr_account_state *a_state;
3633 struct samr_domain_state *d_state;
3634 struct ldb_message **res;
3635 const char * const attrs[2] = { "objectSid", NULL };
3636 struct samr_RidWithAttributeArray *array;
3637 int count;
3639 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3641 a_state = h->data;
3642 d_state = a_state->domain_state;
3644 count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3645 attrs, d_state->domain_sid,
3646 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3647 ldb_dn_get_linearized(a_state->account_dn),
3648 GTYPE_SECURITY_GLOBAL_GROUP);
3649 if (count < 0)
3650 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3652 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3653 if (array == NULL)
3654 return NT_STATUS_NO_MEMORY;
3656 array->count = 0;
3657 array->rids = NULL;
3659 if (count > 0) {
3660 int i;
3661 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3662 count);
3664 if (array->rids == NULL)
3665 return NT_STATUS_NO_MEMORY;
3667 for (i=0; i<count; i++) {
3668 struct dom_sid *group_sid;
3670 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3671 "objectSid");
3672 if (group_sid == NULL) {
3673 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3674 continue;
3677 array->rids[array->count].rid =
3678 group_sid->sub_auths[group_sid->num_auths-1];
3679 array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3680 array->count += 1;
3684 *r->out.rids = array;
3686 return NT_STATUS_OK;
3691 samr_QueryDisplayInfo
3693 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3694 struct samr_QueryDisplayInfo *r)
3696 struct dcesrv_handle *h;
3697 struct samr_domain_state *d_state;
3698 struct ldb_message **res;
3699 int ldb_cnt, count, i;
3700 const char * const attrs[] = { "objectSid", "sAMAccountName", "displayName",
3701 "description", "userAccountControl", "pwdLastSet", NULL };
3702 struct samr_DispEntryFull *entriesFull = NULL;
3703 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3704 struct samr_DispEntryAscii *entriesAscii = NULL;
3705 struct samr_DispEntryGeneral * entriesGeneral = NULL;
3706 const char *filter;
3708 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3710 d_state = h->data;
3712 switch (r->in.level) {
3713 case 1:
3714 case 4:
3715 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3716 "(sAMAccountType=%u))",
3717 ATYPE_NORMAL_ACCOUNT);
3718 break;
3719 case 2:
3720 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3721 "(sAMAccountType=%u))",
3722 ATYPE_WORKSTATION_TRUST);
3723 break;
3724 case 3:
3725 case 5:
3726 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3727 "(objectclass=group))",
3728 GTYPE_SECURITY_GLOBAL_GROUP);
3729 break;
3730 default:
3731 return NT_STATUS_INVALID_INFO_CLASS;
3734 /* search for all requested objects in this domain. This could
3735 possibly be cached and resumed based on resume_key */
3736 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3737 d_state->domain_dn, &res, attrs,
3738 d_state->domain_sid, "%s", filter);
3739 if (ldb_cnt == -1) {
3740 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3742 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3743 return NT_STATUS_OK;
3746 switch (r->in.level) {
3747 case 1:
3748 entriesGeneral = talloc_array(mem_ctx,
3749 struct samr_DispEntryGeneral,
3750 ldb_cnt);
3751 break;
3752 case 2:
3753 entriesFull = talloc_array(mem_ctx,
3754 struct samr_DispEntryFull,
3755 ldb_cnt);
3756 break;
3757 case 3:
3758 entriesFullGroup = talloc_array(mem_ctx,
3759 struct samr_DispEntryFullGroup,
3760 ldb_cnt);
3761 break;
3762 case 4:
3763 case 5:
3764 entriesAscii = talloc_array(mem_ctx,
3765 struct samr_DispEntryAscii,
3766 ldb_cnt);
3767 break;
3770 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3771 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3772 return NT_STATUS_NO_MEMORY;
3774 count = 0;
3776 for (i=0; i<ldb_cnt; i++) {
3777 struct dom_sid *objectsid;
3779 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3780 "objectSid");
3781 if (objectsid == NULL)
3782 continue;
3784 switch(r->in.level) {
3785 case 1:
3786 entriesGeneral[count].idx = count + 1;
3787 entriesGeneral[count].rid =
3788 objectsid->sub_auths[objectsid->num_auths-1];
3789 entriesGeneral[count].acct_flags =
3790 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3791 res[i],
3792 d_state->domain_dn);
3793 entriesGeneral[count].account_name.string =
3794 samdb_result_string(res[i],
3795 "sAMAccountName", "");
3796 entriesGeneral[count].full_name.string =
3797 samdb_result_string(res[i], "displayName", "");
3798 entriesGeneral[count].description.string =
3799 samdb_result_string(res[i], "description", "");
3800 break;
3801 case 2:
3802 entriesFull[count].idx = count + 1;
3803 entriesFull[count].rid =
3804 objectsid->sub_auths[objectsid->num_auths-1];
3806 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3807 entriesFull[count].acct_flags =
3808 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3809 res[i],
3810 d_state->domain_dn) | ACB_NORMAL;
3811 entriesFull[count].account_name.string =
3812 samdb_result_string(res[i], "sAMAccountName",
3813 "");
3814 entriesFull[count].description.string =
3815 samdb_result_string(res[i], "description", "");
3816 break;
3817 case 3:
3818 entriesFullGroup[count].idx = count + 1;
3819 entriesFullGroup[count].rid =
3820 objectsid->sub_auths[objectsid->num_auths-1];
3821 /* We get a "7" here for groups */
3822 entriesFullGroup[count].acct_flags
3823 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3824 entriesFullGroup[count].account_name.string =
3825 samdb_result_string(res[i], "sAMAccountName",
3826 "");
3827 entriesFullGroup[count].description.string =
3828 samdb_result_string(res[i], "description", "");
3829 break;
3830 case 4:
3831 case 5:
3832 entriesAscii[count].idx = count + 1;
3833 entriesAscii[count].account_name.string =
3834 samdb_result_string(res[i], "sAMAccountName",
3835 "");
3836 break;
3839 count += 1;
3842 *r->out.total_size = count;
3844 if (r->in.start_idx >= count) {
3845 *r->out.returned_size = 0;
3846 switch(r->in.level) {
3847 case 1:
3848 r->out.info->info1.count = *r->out.returned_size;
3849 r->out.info->info1.entries = NULL;
3850 break;
3851 case 2:
3852 r->out.info->info2.count = *r->out.returned_size;
3853 r->out.info->info2.entries = NULL;
3854 break;
3855 case 3:
3856 r->out.info->info3.count = *r->out.returned_size;
3857 r->out.info->info3.entries = NULL;
3858 break;
3859 case 4:
3860 r->out.info->info4.count = *r->out.returned_size;
3861 r->out.info->info4.entries = NULL;
3862 break;
3863 case 5:
3864 r->out.info->info5.count = *r->out.returned_size;
3865 r->out.info->info5.entries = NULL;
3866 break;
3868 } else {
3869 *r->out.returned_size = MIN(count - r->in.start_idx,
3870 r->in.max_entries);
3871 switch(r->in.level) {
3872 case 1:
3873 r->out.info->info1.count = *r->out.returned_size;
3874 r->out.info->info1.entries =
3875 &(entriesGeneral[r->in.start_idx]);
3876 break;
3877 case 2:
3878 r->out.info->info2.count = *r->out.returned_size;
3879 r->out.info->info2.entries =
3880 &(entriesFull[r->in.start_idx]);
3881 break;
3882 case 3:
3883 r->out.info->info3.count = *r->out.returned_size;
3884 r->out.info->info3.entries =
3885 &(entriesFullGroup[r->in.start_idx]);
3886 break;
3887 case 4:
3888 r->out.info->info4.count = *r->out.returned_size;
3889 r->out.info->info4.entries =
3890 &(entriesAscii[r->in.start_idx]);
3891 break;
3892 case 5:
3893 r->out.info->info5.count = *r->out.returned_size;
3894 r->out.info->info5.entries =
3895 &(entriesAscii[r->in.start_idx]);
3896 break;
3900 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3901 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3906 samr_GetDisplayEnumerationIndex
3908 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3909 struct samr_GetDisplayEnumerationIndex *r)
3911 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3916 samr_TestPrivateFunctionsDomain
3918 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3919 struct samr_TestPrivateFunctionsDomain *r)
3921 return NT_STATUS_NOT_IMPLEMENTED;
3926 samr_TestPrivateFunctionsUser
3928 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3929 struct samr_TestPrivateFunctionsUser *r)
3931 return NT_STATUS_NOT_IMPLEMENTED;
3936 samr_GetUserPwInfo
3938 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3939 struct samr_GetUserPwInfo *r)
3941 struct dcesrv_handle *h;
3942 struct samr_account_state *a_state;
3944 ZERO_STRUCTP(r->out.info);
3946 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3948 a_state = h->data;
3950 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3951 a_state->domain_state->domain_dn, "minPwdLength",
3952 NULL);
3953 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3954 a_state->account_dn,
3955 "pwdProperties", NULL);
3956 return NT_STATUS_OK;
3961 samr_RemoveMemberFromForeignDomain
3963 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3964 struct samr_RemoveMemberFromForeignDomain *r)
3966 struct dcesrv_handle *h;
3967 struct samr_domain_state *d_state;
3968 const char *memberdn;
3969 struct ldb_message **res;
3970 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3971 int i, count;
3973 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3975 d_state = h->data;
3977 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3978 "distinguishedName", "(objectSid=%s)",
3979 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3980 /* Nothing to do */
3981 if (memberdn == NULL) {
3982 return NT_STATUS_OK;
3985 /* TODO: Does this call only remove alias members, or does it do this
3986 * for domain groups as well? */
3988 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3989 d_state->domain_dn, &res, attrs,
3990 d_state->domain_sid,
3991 "(&(member=%s)(objectClass=group)"
3992 "(|(groupType=%d)(groupType=%d)))",
3993 memberdn,
3994 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3995 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3997 if (count < 0)
3998 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4000 for (i=0; i<count; i++) {
4001 struct ldb_message *mod;
4003 mod = ldb_msg_new(mem_ctx);
4004 if (mod == NULL) {
4005 return NT_STATUS_NO_MEMORY;
4008 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4009 if (mod->dn == NULL) {
4010 talloc_free(mod);
4011 continue;
4014 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4015 "member", memberdn) != 0)
4016 return NT_STATUS_NO_MEMORY;
4018 if (ldb_modify(d_state->sam_ctx, mod) != 0)
4019 return NT_STATUS_UNSUCCESSFUL;
4021 talloc_free(mod);
4024 return NT_STATUS_OK;
4029 samr_QueryDomainInfo2
4031 just an alias for samr_QueryDomainInfo
4033 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4034 struct samr_QueryDomainInfo2 *r)
4036 struct samr_QueryDomainInfo r1;
4037 NTSTATUS status;
4039 ZERO_STRUCT(r1.out);
4040 r1.in.domain_handle = r->in.domain_handle;
4041 r1.in.level = r->in.level;
4042 r1.out.info = r->out.info;
4044 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4046 return status;
4051 samr_QueryUserInfo2
4053 just an alias for samr_QueryUserInfo
4055 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4056 struct samr_QueryUserInfo2 *r)
4058 struct samr_QueryUserInfo r1;
4059 NTSTATUS status;
4061 r1.in.user_handle = r->in.user_handle;
4062 r1.in.level = r->in.level;
4063 r1.out.info = r->out.info;
4065 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4067 return status;
4072 samr_QueryDisplayInfo2
4074 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4075 struct samr_QueryDisplayInfo2 *r)
4077 struct samr_QueryDisplayInfo q;
4078 NTSTATUS result;
4080 q.in.domain_handle = r->in.domain_handle;
4081 q.in.level = r->in.level;
4082 q.in.start_idx = r->in.start_idx;
4083 q.in.max_entries = r->in.max_entries;
4084 q.in.buf_size = r->in.buf_size;
4085 q.out.total_size = r->out.total_size;
4086 q.out.returned_size = r->out.returned_size;
4087 q.out.info = r->out.info;
4089 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4091 return result;
4096 samr_GetDisplayEnumerationIndex2
4098 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4099 struct samr_GetDisplayEnumerationIndex2 *r)
4101 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4106 samr_QueryDisplayInfo3
4108 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4109 struct samr_QueryDisplayInfo3 *r)
4111 struct samr_QueryDisplayInfo q;
4112 NTSTATUS result;
4114 q.in.domain_handle = r->in.domain_handle;
4115 q.in.level = r->in.level;
4116 q.in.start_idx = r->in.start_idx;
4117 q.in.max_entries = r->in.max_entries;
4118 q.in.buf_size = r->in.buf_size;
4119 q.out.total_size = r->out.total_size;
4120 q.out.returned_size = r->out.returned_size;
4121 q.out.info = r->out.info;
4123 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4125 return result;
4130 samr_AddMultipleMembersToAlias
4132 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4133 struct samr_AddMultipleMembersToAlias *r)
4135 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4140 samr_RemoveMultipleMembersFromAlias
4142 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4143 struct samr_RemoveMultipleMembersFromAlias *r)
4145 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4150 samr_GetDomPwInfo
4152 this fetches the default password properties for a domain
4154 note that w2k3 completely ignores the domain name in this call, and
4155 always returns the information for the servers primary domain
4157 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4158 struct samr_GetDomPwInfo *r)
4160 struct ldb_message **msgs;
4161 int ret;
4162 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4163 struct ldb_context *sam_ctx;
4165 ZERO_STRUCTP(r->out.info);
4167 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
4168 if (sam_ctx == NULL) {
4169 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4172 /* The domain name in this call is ignored */
4173 ret = gendb_search_dn(sam_ctx,
4174 mem_ctx, NULL, &msgs, attrs);
4175 if (ret <= 0) {
4176 return NT_STATUS_NO_SUCH_DOMAIN;
4178 if (ret > 1) {
4179 talloc_free(msgs);
4180 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4183 r->out.info->min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
4184 r->out.info->password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
4186 talloc_free(msgs);
4188 talloc_free(sam_ctx);
4189 return NT_STATUS_OK;
4194 samr_Connect2
4196 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4197 struct samr_Connect2 *r)
4199 struct samr_Connect c;
4201 c.in.system_name = NULL;
4202 c.in.access_mask = r->in.access_mask;
4203 c.out.connect_handle = r->out.connect_handle;
4205 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4210 samr_SetUserInfo2
4212 just an alias for samr_SetUserInfo
4214 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4215 struct samr_SetUserInfo2 *r)
4217 struct samr_SetUserInfo r2;
4219 r2.in.user_handle = r->in.user_handle;
4220 r2.in.level = r->in.level;
4221 r2.in.info = r->in.info;
4223 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4228 samr_SetBootKeyInformation
4230 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4231 struct samr_SetBootKeyInformation *r)
4233 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4238 samr_GetBootKeyInformation
4240 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4241 struct samr_GetBootKeyInformation *r)
4243 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4248 samr_Connect3
4250 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4251 struct samr_Connect3 *r)
4253 struct samr_Connect c;
4255 c.in.system_name = NULL;
4256 c.in.access_mask = r->in.access_mask;
4257 c.out.connect_handle = r->out.connect_handle;
4259 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4264 samr_Connect4
4266 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4267 struct samr_Connect4 *r)
4269 struct samr_Connect c;
4271 c.in.system_name = NULL;
4272 c.in.access_mask = r->in.access_mask;
4273 c.out.connect_handle = r->out.connect_handle;
4275 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4280 samr_Connect5
4282 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4283 struct samr_Connect5 *r)
4285 struct samr_Connect c;
4286 NTSTATUS status;
4288 c.in.system_name = NULL;
4289 c.in.access_mask = r->in.access_mask;
4290 c.out.connect_handle = r->out.connect_handle;
4292 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4294 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4295 r->out.info_out->info1.unknown2 = 0;
4296 *r->out.level_out = r->in.level_in;
4298 return status;
4303 samr_RidToSid
4305 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4306 struct samr_RidToSid *r)
4308 struct samr_domain_state *d_state;
4309 struct dcesrv_handle *h;
4311 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4313 d_state = h->data;
4315 /* form the users SID */
4316 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4317 if (!*r->out.sid) {
4318 return NT_STATUS_NO_MEMORY;
4321 return NT_STATUS_OK;
4326 samr_SetDsrmPassword
4328 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4329 struct samr_SetDsrmPassword *r)
4331 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4336 samr_ValidatePassword
4338 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4339 struct samr_ValidatePassword *r)
4341 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4345 /* include the generated boilerplate */
4346 #include "librpc/gen_ndr/ndr_samr_s.c"