Merge ldb_search() and ldb_search_exp_fmt() into a simgle function.
[Samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
blob9daf4f2194c6c8900008b4abde09ff766a2eb51f
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 "util/util_ldb.h"
38 #include "param/param.h"
40 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
42 #define QUERY_STRING(msg, field, attr) \
43 r->out.info->field.string = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45 r->out.info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_UINT64(msg, field, attr) \
49 r->out.info->field = samdb_result_uint64(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51 r->out.info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
52 a_state->domain_state->domain_dn, msg, attr);
53 #define QUERY_FPASSC(msg, field, attr) \
54 r->out.info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
55 a_state->domain_state->domain_dn, msg);
56 #define QUERY_LHOURS(msg, field, attr) \
57 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59 r->out.info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
62 /* these are used to make the Set[User|Group]Info code easier to follow */
64 #define SET_STRING(msg, field, attr) do { \
65 struct ldb_message_element *set_el; \
66 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
67 if (r->in.info->field.string[0] == '\0') { \
68 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
69 return NT_STATUS_NO_MEMORY; \
70 } \
71 } \
72 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
73 return NT_STATUS_NO_MEMORY; \
74 } \
75 set_el = ldb_msg_find_element(msg, attr); \
76 set_el->flags = LDB_FLAG_MOD_REPLACE; \
77 } while (0)
79 #define SET_UINT(msg, field, attr) do { \
80 struct ldb_message_element *set_el; \
81 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
82 return NT_STATUS_NO_MEMORY; \
83 } \
84 set_el = ldb_msg_find_element(msg, attr); \
85 set_el->flags = LDB_FLAG_MOD_REPLACE; \
86 } while (0)
88 #define SET_INT64(msg, field, attr) do { \
89 struct ldb_message_element *set_el; \
90 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
91 return NT_STATUS_NO_MEMORY; \
92 } \
93 set_el = ldb_msg_find_element(msg, attr); \
94 set_el->flags = LDB_FLAG_MOD_REPLACE; \
95 } while (0)
97 #define SET_UINT64(msg, field, attr) do { \
98 struct ldb_message_element *set_el; \
99 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
100 return NT_STATUS_NO_MEMORY; \
102 set_el = ldb_msg_find_element(msg, attr); \
103 set_el->flags = LDB_FLAG_MOD_REPLACE; \
104 } while (0)
106 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
107 do { \
108 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
109 return NT_STATUS_INVALID_PARAMETER; \
111 } while (0) \
113 /* Set account flags, discarding flags that cannot be set with SAMR */
114 #define SET_AFLAGS(msg, field, attr) do { \
115 struct ldb_message_element *set_el; \
116 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
117 return NT_STATUS_INVALID_PARAMETER; \
119 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
120 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
121 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
122 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
124 return NT_STATUS_NO_MEMORY; \
126 set_el = ldb_msg_find_element(msg, attr); \
127 set_el->flags = LDB_FLAG_MOD_REPLACE; \
128 } while (0)
130 #define SET_LHOURS(msg, field, attr) do { \
131 struct ldb_message_element *set_el; \
132 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
133 return NT_STATUS_NO_MEMORY; \
135 set_el = ldb_msg_find_element(msg, attr); \
136 set_el->flags = LDB_FLAG_MOD_REPLACE; \
137 } while (0)
141 samr_Connect
143 create a connection to the SAM database
145 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
146 struct samr_Connect *r)
148 struct samr_connect_state *c_state;
149 struct dcesrv_handle *handle;
151 ZERO_STRUCTP(r->out.connect_handle);
153 c_state = talloc(dce_call->conn, struct samr_connect_state);
154 if (!c_state) {
155 return NT_STATUS_NO_MEMORY;
158 /* make sure the sam database is accessible */
159 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);
160 if (c_state->sam_ctx == NULL) {
161 talloc_free(c_state);
162 return NT_STATUS_INVALID_SYSTEM_SERVICE;
166 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
167 if (!handle) {
168 talloc_free(c_state);
169 return NT_STATUS_NO_MEMORY;
172 handle->data = talloc_steal(handle, c_state);
174 c_state->access_mask = r->in.access_mask;
175 *r->out.connect_handle = handle->wire_handle;
177 return NT_STATUS_OK;
182 samr_Close
184 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
185 struct samr_Close *r)
187 struct dcesrv_handle *h;
189 *r->out.handle = *r->in.handle;
191 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
193 talloc_free(h);
195 ZERO_STRUCTP(r->out.handle);
197 return NT_STATUS_OK;
202 samr_SetSecurity
204 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
205 struct samr_SetSecurity *r)
207 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
212 samr_QuerySecurity
214 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
215 struct samr_QuerySecurity *r)
217 struct dcesrv_handle *h;
218 struct sec_desc_buf *sd;
220 r->out.sdbuf = NULL;
222 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
224 sd = talloc(mem_ctx, struct sec_desc_buf);
225 if (sd == NULL) {
226 return NT_STATUS_NO_MEMORY;
229 sd->sd = samdb_default_security_descriptor(mem_ctx);
231 r->out.sdbuf = sd;
233 return NT_STATUS_OK;
238 samr_Shutdown
240 we refuse this operation completely. If a admin wants to shutdown samr
241 in Samba then they should use the samba admin tools to disable the samr pipe
243 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
244 struct samr_Shutdown *r)
246 return NT_STATUS_ACCESS_DENIED;
251 samr_LookupDomain
253 this maps from a domain name to a SID
255 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
256 struct samr_LookupDomain *r)
258 struct samr_connect_state *c_state;
259 struct dcesrv_handle *h;
260 struct dom_sid *sid;
261 const char * const dom_attrs[] = { "objectSid", NULL};
262 const char * const ref_attrs[] = { "ncName", NULL};
263 struct ldb_message **dom_msgs;
264 struct ldb_message **ref_msgs;
265 int ret;
266 struct ldb_dn *partitions_basedn;
268 r->out.sid = NULL;
270 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
272 c_state = h->data;
274 if (r->in.domain_name->string == NULL) {
275 return NT_STATUS_INVALID_PARAMETER;
278 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
280 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
281 ret = gendb_search(c_state->sam_ctx,
282 mem_ctx, NULL, &dom_msgs, dom_attrs,
283 "(objectClass=builtinDomain)");
284 } else {
285 ret = gendb_search(c_state->sam_ctx,
286 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
287 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
288 ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
289 if (ret != 1) {
290 return NT_STATUS_NO_SUCH_DOMAIN;
293 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx,
294 samdb_result_dn(c_state->sam_ctx, mem_ctx,
295 ref_msgs[0], "ncName", NULL),
296 &dom_msgs, dom_attrs);
299 if (ret != 1) {
300 return NT_STATUS_NO_SUCH_DOMAIN;
303 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
304 "objectSid");
306 if (sid == NULL) {
307 return NT_STATUS_NO_SUCH_DOMAIN;
310 r->out.sid = sid;
312 return NT_STATUS_OK;
317 samr_EnumDomains
319 list the domains in the SAM
321 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
322 struct samr_EnumDomains *r)
324 struct samr_connect_state *c_state;
325 struct dcesrv_handle *h;
326 struct samr_SamArray *array;
327 int i, start_i, ret;
328 const char * const dom_attrs[] = { "cn", NULL};
329 const char * const ref_attrs[] = { "nETBIOSName", NULL};
330 struct ldb_result *dom_res;
331 struct ldb_result *ref_res;
332 struct ldb_dn *partitions_basedn;
334 *r->out.resume_handle = 0;
335 r->out.sam = NULL;
336 r->out.num_entries = 0;
338 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
340 c_state = h->data;
342 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
344 ret = ldb_search(c_state->sam_ctx, mem_ctx, &dom_res, ldb_get_default_basedn(c_state->sam_ctx),
345 LDB_SCOPE_SUBTREE, dom_attrs, "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
346 if (ret != LDB_SUCCESS) {
347 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
348 return NT_STATUS_INTERNAL_DB_CORRUPTION;
351 *r->out.resume_handle = dom_res->count;
353 start_i = *r->in.resume_handle;
355 if (start_i >= dom_res->count) {
356 /* search past end of list is not an error for this call */
357 return NT_STATUS_OK;
360 array = talloc(mem_ctx, struct samr_SamArray);
361 if (array == NULL) {
362 return NT_STATUS_NO_MEMORY;
365 array->count = 0;
366 array->entries = NULL;
368 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, dom_res->count - start_i);
369 if (array->entries == NULL) {
370 return NT_STATUS_NO_MEMORY;
373 for (i=0;i<dom_res->count-start_i;i++) {
374 array->entries[i].idx = start_i + i;
375 /* try and find the domain */
376 ret = ldb_search(c_state->sam_ctx, mem_ctx, &ref_res, partitions_basedn,
377 LDB_SCOPE_SUBTREE, ref_attrs, "(&(objectClass=crossRef)(ncName=%s))",
378 ldb_dn_get_linearized(dom_res->msgs[i]->dn));
380 if (ret != LDB_SUCCESS) {
381 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
382 return NT_STATUS_INTERNAL_DB_CORRUPTION;
385 if (ref_res->count == 1) {
386 array->entries[i].name.string = samdb_result_string(ref_res->msgs[0], "nETBIOSName", NULL);
387 } else {
388 array->entries[i].name.string = samdb_result_string(dom_res->msgs[i], "cn", NULL);
392 r->out.sam = array;
393 r->out.num_entries = i;
394 array->count = r->out.num_entries;
396 return NT_STATUS_OK;
401 samr_OpenDomain
403 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
404 struct samr_OpenDomain *r)
406 struct dcesrv_handle *h_conn, *h_domain;
407 const char *domain_name;
408 struct samr_connect_state *c_state;
409 struct samr_domain_state *d_state;
410 const char * const dom_attrs[] = { "cn", NULL};
411 const char * const ref_attrs[] = { "nETBIOSName", NULL};
412 struct ldb_message **dom_msgs;
413 struct ldb_message **ref_msgs;
414 int ret;
415 struct ldb_dn *partitions_basedn;
417 ZERO_STRUCTP(r->out.domain_handle);
419 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
421 c_state = h_conn->data;
423 if (r->in.sid == NULL) {
424 return NT_STATUS_INVALID_PARAMETER;
427 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
429 ret = gendb_search(c_state->sam_ctx,
430 mem_ctx, NULL, &dom_msgs, dom_attrs,
431 "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
432 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
433 if (ret == 0) {
434 return NT_STATUS_NO_SUCH_DOMAIN;
435 } else if (ret > 1) {
436 return NT_STATUS_INTERNAL_DB_CORRUPTION;
437 } else if (ret == -1) {
438 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
439 return NT_STATUS_INTERNAL_DB_CORRUPTION;
440 } else {
441 ret = gendb_search(c_state->sam_ctx,
442 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
443 "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))",
444 ldb_dn_get_linearized(dom_msgs[0]->dn));
445 if (ret == 0) {
446 domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL);
447 if (domain_name == NULL) {
448 return NT_STATUS_NO_SUCH_DOMAIN;
450 } else if (ret == 1) {
452 domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL);
453 if (domain_name == NULL) {
454 return NT_STATUS_NO_SUCH_DOMAIN;
456 } else {
457 return NT_STATUS_NO_SUCH_DOMAIN;
461 d_state = talloc(c_state, struct samr_domain_state);
462 if (!d_state) {
463 return NT_STATUS_NO_MEMORY;
466 d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
467 d_state->connect_state = talloc_reference(d_state, c_state);
468 d_state->sam_ctx = c_state->sam_ctx;
469 d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
470 d_state->domain_name = talloc_strdup(d_state, domain_name);
471 d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
472 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
473 talloc_free(d_state);
474 return NT_STATUS_NO_MEMORY;
476 d_state->access_mask = r->in.access_mask;
478 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
479 d_state->builtin = true;
480 } else {
481 d_state->builtin = false;
484 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
486 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
487 if (!h_domain) {
488 talloc_free(d_state);
489 return NT_STATUS_NO_MEMORY;
492 h_domain->data = talloc_steal(h_domain, d_state);
494 *r->out.domain_handle = h_domain->wire_handle;
496 return NT_STATUS_OK;
500 return DomInfo1
502 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
503 TALLOC_CTX *mem_ctx,
504 struct ldb_message **dom_msgs,
505 struct samr_DomInfo1 *info)
507 info->min_password_length =
508 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
509 info->password_history_length =
510 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
511 info->password_properties =
512 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
513 info->max_password_age =
514 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
515 info->min_password_age =
516 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
518 return NT_STATUS_OK;
522 return DomInfo2
524 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
525 TALLOC_CTX *mem_ctx,
526 struct ldb_message **dom_msgs,
527 struct samr_DomGeneralInformation *info)
529 /* This pulls the NetBIOS name from the
530 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
531 string */
532 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
534 if (!info->primary.string) {
535 info->primary.string = lp_netbios_name(state->lp_ctx);
538 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
539 0x8000000000000000LL);
541 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
542 info->domain_name.string = state->domain_name;
544 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
546 switch (state->role) {
547 case ROLE_DOMAIN_CONTROLLER:
548 /* This pulls the NetBIOS name from the
549 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
550 string */
551 if (samdb_is_pdc(state->sam_ctx)) {
552 info->role = SAMR_ROLE_DOMAIN_PDC;
553 } else {
554 info->role = SAMR_ROLE_DOMAIN_BDC;
556 break;
557 case ROLE_DOMAIN_MEMBER:
558 info->role = SAMR_ROLE_DOMAIN_MEMBER;
559 break;
560 case ROLE_STANDALONE:
561 info->role = SAMR_ROLE_STANDALONE;
562 break;
565 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
566 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
567 "(objectClass=user)");
568 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
569 "(&(objectClass=group)(sAMAccountType=%u))",
570 ATYPE_GLOBAL_GROUP);
571 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
572 "(&(objectClass=group)(sAMAccountType=%u))",
573 ATYPE_LOCAL_GROUP);
575 return NT_STATUS_OK;
579 return DomInfo3
581 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
582 TALLOC_CTX *mem_ctx,
583 struct ldb_message **dom_msgs,
584 struct samr_DomInfo3 *info)
586 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
587 0x8000000000000000LL);
589 return NT_STATUS_OK;
593 return DomInfo4
595 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
596 TALLOC_CTX *mem_ctx,
597 struct ldb_message **dom_msgs,
598 struct samr_DomOEMInformation *info)
600 info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
602 return NT_STATUS_OK;
606 return DomInfo5
608 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
609 TALLOC_CTX *mem_ctx,
610 struct ldb_message **dom_msgs,
611 struct samr_DomInfo5 *info)
613 info->domain_name.string = state->domain_name;
615 return NT_STATUS_OK;
619 return DomInfo6
621 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
622 TALLOC_CTX *mem_ctx,
623 struct ldb_message **dom_msgs,
624 struct samr_DomInfo6 *info)
626 /* This pulls the NetBIOS name from the
627 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
628 string */
629 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
630 dom_msgs[0], "fSMORoleOwner");
632 if (!info->primary.string) {
633 info->primary.string = lp_netbios_name(state->lp_ctx);
636 return NT_STATUS_OK;
640 return DomInfo7
642 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
643 TALLOC_CTX *mem_ctx,
644 struct ldb_message **dom_msgs,
645 struct samr_DomInfo7 *info)
648 switch (state->role) {
649 case ROLE_DOMAIN_CONTROLLER:
650 /* This pulls the NetBIOS name from the
651 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
652 string */
653 if (samdb_is_pdc(state->sam_ctx)) {
654 info->role = SAMR_ROLE_DOMAIN_PDC;
655 } else {
656 info->role = SAMR_ROLE_DOMAIN_BDC;
658 break;
659 case ROLE_DOMAIN_MEMBER:
660 info->role = SAMR_ROLE_DOMAIN_MEMBER;
661 break;
662 case ROLE_STANDALONE:
663 info->role = SAMR_ROLE_STANDALONE;
664 break;
667 return NT_STATUS_OK;
671 return DomInfo8
673 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
674 TALLOC_CTX *mem_ctx,
675 struct ldb_message **dom_msgs,
676 struct samr_DomInfo8 *info)
678 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
679 time(NULL));
681 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
682 0x0LL);
684 return NT_STATUS_OK;
688 return DomInfo9
690 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
691 TALLOC_CTX *mem_ctx,
692 struct ldb_message **dom_msgs,
693 struct samr_DomInfo9 *info)
695 info->unknown = 1;
697 return NT_STATUS_OK;
701 return DomInfo11
703 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
704 TALLOC_CTX *mem_ctx,
705 struct ldb_message **dom_msgs,
706 struct samr_DomGeneralInformation2 *info)
708 NTSTATUS status;
709 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
710 if (!NT_STATUS_IS_OK(status)) {
711 return status;
714 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
715 -18000000000LL);
716 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
717 -18000000000LL);
718 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
720 return NT_STATUS_OK;
724 return DomInfo12
726 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
727 TALLOC_CTX *mem_ctx,
728 struct ldb_message **dom_msgs,
729 struct samr_DomInfo12 *info)
731 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
732 -18000000000LL);
733 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
734 -18000000000LL);
735 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
737 return NT_STATUS_OK;
741 return DomInfo13
743 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
744 TALLOC_CTX *mem_ctx,
745 struct ldb_message **dom_msgs,
746 struct samr_DomInfo13 *info)
748 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
749 time(NULL));
751 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
752 0x0LL);
754 info->unknown1 = 0;
755 info->unknown2 = 0;
757 return NT_STATUS_OK;
761 samr_QueryDomainInfo
763 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
764 struct samr_QueryDomainInfo *r)
766 struct dcesrv_handle *h;
767 struct samr_domain_state *d_state;
769 struct ldb_message **dom_msgs;
770 const char * const *attrs = NULL;
772 r->out.info = NULL;
774 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
776 d_state = h->data;
778 r->out.info = talloc(mem_ctx, union samr_DomainInfo);
779 if (!r->out.info) {
780 return NT_STATUS_NO_MEMORY;
783 switch (r->in.level) {
784 case 1:
786 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
787 "pwdProperties", "maxPwdAge",
788 "minPwdAge", NULL };
789 attrs = attrs2;
790 break;
792 case 2:
794 static const char * const attrs2[] = {"forceLogoff",
795 "oEMInformation",
796 "modifiedCount",
797 "fSMORoleOwner",
798 NULL};
799 attrs = attrs2;
800 break;
802 case 3:
804 static const char * const attrs2[] = {"forceLogoff",
805 NULL};
806 attrs = attrs2;
807 break;
809 case 4:
811 static const char * const attrs2[] = {"oEMInformation",
812 NULL};
813 attrs = attrs2;
814 break;
816 case 5:
818 attrs = NULL;
819 break;
821 case 6:
823 static const char * const attrs2[] = {"fSMORoleOwner",
824 NULL};
825 attrs = attrs2;
826 break;
828 case 7:
830 attrs = NULL;
831 break;
833 case 8:
835 static const char * const attrs2[] = { "modifiedCount",
836 "creationTime",
837 NULL };
838 attrs = attrs2;
839 break;
841 case 9:
842 attrs = NULL;
843 break;
844 case 11:
846 static const char * const attrs2[] = { "oEMInformation", "forceLogoff",
847 "modifiedCount",
848 "lockoutDuration",
849 "lockOutObservationWindow",
850 "lockoutThreshold",
851 NULL};
852 attrs = attrs2;
853 break;
855 case 12:
857 static const char * const attrs2[] = { "lockoutDuration",
858 "lockOutObservationWindow",
859 "lockoutThreshold",
860 NULL};
861 attrs = attrs2;
862 break;
864 case 13:
866 static const char * const attrs2[] = { "modifiedCount",
867 "creationTime",
868 NULL };
869 attrs = attrs2;
870 break;
874 /* some levels don't need a search */
875 if (attrs) {
876 int ret;
877 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
878 d_state->domain_dn, &dom_msgs, attrs);
879 if (ret != 1) {
880 return NT_STATUS_INTERNAL_DB_CORRUPTION;
884 ZERO_STRUCTP(r->out.info);
886 switch (r->in.level) {
887 case 1:
888 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
889 &r->out.info->info1);
890 case 2:
891 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
892 &r->out.info->general);
893 case 3:
894 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
895 &r->out.info->info3);
896 case 4:
897 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
898 &r->out.info->oem);
899 case 5:
900 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
901 &r->out.info->info5);
902 case 6:
903 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
904 &r->out.info->info6);
905 case 7:
906 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
907 &r->out.info->info7);
908 case 8:
909 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
910 &r->out.info->info8);
911 case 9:
912 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
913 &r->out.info->info9);
914 case 11:
915 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
916 &r->out.info->general2);
917 case 12:
918 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
919 &r->out.info->info12);
920 case 13:
921 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
922 &r->out.info->info13);
925 return NT_STATUS_INVALID_INFO_CLASS;
930 samr_SetDomainInfo
932 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
933 struct samr_SetDomainInfo *r)
935 struct dcesrv_handle *h;
936 struct samr_domain_state *d_state;
937 struct ldb_message *msg;
938 int ret;
939 struct ldb_context *sam_ctx;
941 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
943 d_state = h->data;
944 sam_ctx = d_state->sam_ctx;
946 msg = ldb_msg_new(mem_ctx);
947 if (msg == NULL) {
948 return NT_STATUS_NO_MEMORY;
951 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
952 if (!msg->dn) {
953 return NT_STATUS_NO_MEMORY;
956 switch (r->in.level) {
957 case 1:
958 SET_UINT (msg, info1.min_password_length, "minPwdLength");
959 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
960 SET_UINT (msg, info1.password_properties, "pwdProperties");
961 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
962 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
963 break;
964 case 3:
965 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
966 break;
967 case 4:
968 SET_STRING(msg, oem.oem_information, "oEMInformation");
969 break;
971 case 6:
972 case 7:
973 case 9:
974 /* No op, we don't know where to set these */
975 return NT_STATUS_OK;
977 case 12:
979 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
980 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
981 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
982 break;
984 default:
985 /* many info classes are not valid for SetDomainInfo */
986 return NT_STATUS_INVALID_INFO_CLASS;
989 /* modify the samdb record */
990 ret = ldb_modify(sam_ctx, msg);
991 if (ret != 0) {
992 DEBUG(1,("Failed to modify record %s: %s\n",
993 ldb_dn_get_linearized(d_state->domain_dn),
994 ldb_errstring(sam_ctx)));
996 /* we really need samdb.c to return NTSTATUS */
997 return NT_STATUS_UNSUCCESSFUL;
1000 return NT_STATUS_OK;
1004 samr_CreateDomainGroup
1006 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1007 struct samr_CreateDomainGroup *r)
1009 struct samr_domain_state *d_state;
1010 struct samr_account_state *a_state;
1011 struct dcesrv_handle *h;
1012 const char *name;
1013 struct ldb_message *msg;
1014 struct dom_sid *sid;
1015 const char *groupname;
1016 struct dcesrv_handle *g_handle;
1017 int ret;
1019 ZERO_STRUCTP(r->out.group_handle);
1020 *r->out.rid = 0;
1022 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1024 d_state = h->data;
1026 if (d_state->builtin) {
1027 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1028 return NT_STATUS_ACCESS_DENIED;
1031 groupname = r->in.name->string;
1033 if (groupname == NULL) {
1034 return NT_STATUS_INVALID_PARAMETER;
1037 /* check if the group already exists */
1038 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1039 "sAMAccountName",
1040 "(&(sAMAccountName=%s)(objectclass=group))",
1041 ldb_binary_encode_string(mem_ctx, groupname));
1042 if (name != NULL) {
1043 return NT_STATUS_GROUP_EXISTS;
1046 msg = ldb_msg_new(mem_ctx);
1047 if (msg == NULL) {
1048 return NT_STATUS_NO_MEMORY;
1051 /* add core elements to the ldb_message for the user */
1052 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1053 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1054 if (!msg->dn) {
1055 return NT_STATUS_NO_MEMORY;
1057 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1058 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1060 /* create the group */
1061 ret = ldb_add(d_state->sam_ctx, msg);
1062 switch (ret) {
1063 case LDB_SUCCESS:
1064 break;
1065 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1066 DEBUG(0,("Failed to create group record %s: %s\n",
1067 ldb_dn_get_linearized(msg->dn),
1068 ldb_errstring(d_state->sam_ctx)));
1069 return NT_STATUS_GROUP_EXISTS;
1070 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1071 DEBUG(0,("Failed to create group record %s: %s\n",
1072 ldb_dn_get_linearized(msg->dn),
1073 ldb_errstring(d_state->sam_ctx)));
1074 return NT_STATUS_ACCESS_DENIED;
1075 default:
1076 DEBUG(0,("Failed to create group record %s: %s\n",
1077 ldb_dn_get_linearized(msg->dn),
1078 ldb_errstring(d_state->sam_ctx)));
1079 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1082 a_state = talloc(d_state, struct samr_account_state);
1083 if (!a_state) {
1084 return NT_STATUS_NO_MEMORY;
1086 a_state->sam_ctx = d_state->sam_ctx;
1087 a_state->access_mask = r->in.access_mask;
1088 a_state->domain_state = talloc_reference(a_state, d_state);
1089 a_state->account_dn = talloc_steal(a_state, msg->dn);
1091 /* retrieve the sid for the group just created */
1092 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1093 msg->dn, "objectSid", NULL);
1094 if (sid == NULL) {
1095 return NT_STATUS_UNSUCCESSFUL;
1098 a_state->account_name = talloc_strdup(a_state, groupname);
1099 if (!a_state->account_name) {
1100 return NT_STATUS_NO_MEMORY;
1103 /* create the policy handle */
1104 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1105 if (!g_handle) {
1106 return NT_STATUS_NO_MEMORY;
1109 g_handle->data = talloc_steal(g_handle, a_state);
1111 *r->out.group_handle = g_handle->wire_handle;
1112 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1114 return NT_STATUS_OK;
1119 comparison function for sorting SamEntry array
1121 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1123 return e1->idx - e2->idx;
1127 samr_EnumDomainGroups
1129 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1130 struct samr_EnumDomainGroups *r)
1132 struct dcesrv_handle *h;
1133 struct samr_domain_state *d_state;
1134 struct ldb_message **res;
1135 int ldb_cnt, count, i, first;
1136 struct samr_SamEntry *entries;
1137 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1139 *r->out.resume_handle = 0;
1140 r->out.sam = NULL;
1141 r->out.num_entries = 0;
1143 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1145 d_state = h->data;
1147 /* search for all domain groups in this domain. This could possibly be
1148 cached and resumed based on resume_key */
1149 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1150 d_state->domain_dn, &res, attrs,
1151 d_state->domain_sid,
1152 "(&(grouptype=%d)(objectclass=group))",
1153 GTYPE_SECURITY_GLOBAL_GROUP);
1154 if (ldb_cnt == -1) {
1155 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1158 /* convert to SamEntry format */
1159 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1160 if (!entries) {
1161 return NT_STATUS_NO_MEMORY;
1164 count = 0;
1166 for (i=0;i<ldb_cnt;i++) {
1167 struct dom_sid *group_sid;
1169 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1170 "objectSid");
1171 if (group_sid == NULL)
1172 continue;
1174 entries[count].idx =
1175 group_sid->sub_auths[group_sid->num_auths-1];
1176 entries[count].name.string =
1177 samdb_result_string(res[i], "sAMAccountName", "");
1178 count += 1;
1181 /* sort the results by rid */
1182 qsort(entries, count, sizeof(struct samr_SamEntry),
1183 (comparison_fn_t)compare_SamEntry);
1185 /* find the first entry to return */
1186 for (first=0;
1187 first<count && entries[first].idx <= *r->in.resume_handle;
1188 first++) ;
1190 /* return the rest, limit by max_size. Note that we
1191 use the w2k3 element size value of 54 */
1192 r->out.num_entries = count - first;
1193 r->out.num_entries = MIN(r->out.num_entries,
1194 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1196 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1197 if (!r->out.sam) {
1198 return NT_STATUS_NO_MEMORY;
1201 r->out.sam->entries = entries+first;
1202 r->out.sam->count = r->out.num_entries;
1204 if (r->out.num_entries < count - first) {
1205 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1206 return STATUS_MORE_ENTRIES;
1209 return NT_STATUS_OK;
1214 samr_CreateUser2
1216 This call uses transactions to ensure we don't get a new conflicting
1217 user while we are processing this, and to ensure the user either
1218 completly exists, or does not.
1220 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1221 struct samr_CreateUser2 *r)
1223 struct samr_domain_state *d_state;
1224 struct samr_account_state *a_state;
1225 struct dcesrv_handle *h;
1226 const char *name;
1227 struct ldb_message *msg;
1228 struct dom_sid *sid;
1229 const char *account_name;
1230 struct dcesrv_handle *u_handle;
1231 int ret;
1232 const char *container, *obj_class=NULL;
1233 char *cn_name;
1234 int cn_name_len;
1236 const char *attrs[] = {
1237 "objectSid",
1238 "userAccountControl",
1239 NULL
1242 uint32_t user_account_control;
1244 struct ldb_message **msgs;
1246 ZERO_STRUCTP(r->out.user_handle);
1247 *r->out.access_granted = 0;
1248 *r->out.rid = 0;
1250 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1252 d_state = h->data;
1254 if (d_state->builtin) {
1255 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1256 return NT_STATUS_ACCESS_DENIED;
1258 account_name = r->in.account_name->string;
1260 if (account_name == NULL) {
1261 return NT_STATUS_INVALID_PARAMETER;
1264 ret = ldb_transaction_start(d_state->sam_ctx);
1265 if (ret != 0) {
1266 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1267 ldb_errstring(d_state->sam_ctx)));
1268 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1271 /* check if the user already exists */
1272 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1273 "sAMAccountName",
1274 "(&(sAMAccountName=%s)(objectclass=user))",
1275 ldb_binary_encode_string(mem_ctx, account_name));
1276 if (name != NULL) {
1277 ldb_transaction_cancel(d_state->sam_ctx);
1278 return NT_STATUS_USER_EXISTS;
1281 msg = ldb_msg_new(mem_ctx);
1282 if (msg == NULL) {
1283 ldb_transaction_cancel(d_state->sam_ctx);
1284 return NT_STATUS_NO_MEMORY;
1287 cn_name = talloc_strdup(mem_ctx, account_name);
1288 if (!cn_name) {
1289 ldb_transaction_cancel(d_state->sam_ctx);
1290 return NT_STATUS_NO_MEMORY;
1293 cn_name_len = strlen(cn_name);
1295 /* This must be one of these values *only* */
1296 if (r->in.acct_flags == ACB_NORMAL) {
1297 container = "CN=Users";
1298 obj_class = "user";
1300 } else if (r->in.acct_flags == ACB_WSTRUST) {
1301 if (cn_name[cn_name_len - 1] != '$') {
1302 return NT_STATUS_FOOBAR;
1304 cn_name[cn_name_len - 1] = '\0';
1305 container = "CN=Computers";
1306 obj_class = "computer";
1307 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1309 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1310 if (cn_name[cn_name_len - 1] != '$') {
1311 return NT_STATUS_FOOBAR;
1313 cn_name[cn_name_len - 1] = '\0';
1314 container = "OU=Domain Controllers";
1315 obj_class = "computer";
1316 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS);
1318 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1319 container = "CN=Users";
1320 obj_class = "user";
1322 } else {
1323 ldb_transaction_cancel(d_state->sam_ctx);
1324 return NT_STATUS_INVALID_PARAMETER;
1327 /* add core elements to the ldb_message for the user */
1328 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1329 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1330 ldb_transaction_cancel(d_state->sam_ctx);
1331 return NT_STATUS_FOOBAR;
1334 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1335 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1337 /* Start a transaction, so we can query and do a subsequent atomic modify */
1339 /* create the user */
1340 ret = ldb_add(d_state->sam_ctx, msg);
1341 switch (ret) {
1342 case LDB_SUCCESS:
1343 break;
1344 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1345 ldb_transaction_cancel(d_state->sam_ctx);
1346 DEBUG(0,("Failed to create user record %s: %s\n",
1347 ldb_dn_get_linearized(msg->dn),
1348 ldb_errstring(d_state->sam_ctx)));
1349 return NT_STATUS_USER_EXISTS;
1350 case LDB_ERR_UNWILLING_TO_PERFORM:
1351 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1352 ldb_transaction_cancel(d_state->sam_ctx);
1353 DEBUG(0,("Failed to create user record %s: %s\n",
1354 ldb_dn_get_linearized(msg->dn),
1355 ldb_errstring(d_state->sam_ctx)));
1356 return NT_STATUS_ACCESS_DENIED;
1357 default:
1358 ldb_transaction_cancel(d_state->sam_ctx);
1359 DEBUG(0,("Failed to create user record %s: %s\n",
1360 ldb_dn_get_linearized(msg->dn),
1361 ldb_errstring(d_state->sam_ctx)));
1362 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1365 a_state = talloc(d_state, struct samr_account_state);
1366 if (!a_state) {
1367 ldb_transaction_cancel(d_state->sam_ctx);
1368 return NT_STATUS_NO_MEMORY;
1370 a_state->sam_ctx = d_state->sam_ctx;
1371 a_state->access_mask = r->in.access_mask;
1372 a_state->domain_state = talloc_reference(a_state, d_state);
1373 a_state->account_dn = talloc_steal(a_state, msg->dn);
1375 /* retrieve the sid and account control bits for the user just created */
1376 ret = gendb_search_dn(d_state->sam_ctx, a_state,
1377 msg->dn, &msgs, attrs);
1379 if (ret != 1) {
1380 ldb_transaction_cancel(d_state->sam_ctx);
1381 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1382 ldb_dn_get_linearized(msg->dn)));
1383 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1385 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1386 if (sid == NULL) {
1387 ldb_transaction_cancel(d_state->sam_ctx);
1388 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1389 ldb_dn_get_linearized(msg->dn)));
1390 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1393 /* Change the account control to be the correct account type.
1394 * The default is for a workstation account */
1395 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1396 user_account_control = (user_account_control &
1397 ~(UF_NORMAL_ACCOUNT |
1398 UF_INTERDOMAIN_TRUST_ACCOUNT |
1399 UF_WORKSTATION_TRUST_ACCOUNT |
1400 UF_SERVER_TRUST_ACCOUNT));
1401 user_account_control |= samdb_acb2uf(r->in.acct_flags);
1403 talloc_free(msg);
1404 msg = ldb_msg_new(mem_ctx);
1405 if (msg == NULL) {
1406 ldb_transaction_cancel(d_state->sam_ctx);
1407 return NT_STATUS_NO_MEMORY;
1410 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1412 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1413 "userAccountControl",
1414 user_account_control) != 0) {
1415 ldb_transaction_cancel(d_state->sam_ctx);
1416 return NT_STATUS_NO_MEMORY;
1419 /* modify the samdb record */
1420 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1421 if (ret != 0) {
1422 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1423 ldb_dn_get_linearized(msg->dn),
1424 ldb_errstring(d_state->sam_ctx)));
1425 ldb_transaction_cancel(d_state->sam_ctx);
1427 /* we really need samdb.c to return NTSTATUS */
1428 return NT_STATUS_UNSUCCESSFUL;
1431 ret = ldb_transaction_commit(d_state->sam_ctx);
1432 if (ret != 0) {
1433 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1434 ldb_dn_get_linearized(msg->dn),
1435 ldb_errstring(d_state->sam_ctx)));
1436 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1439 a_state->account_name = talloc_steal(a_state, account_name);
1440 if (!a_state->account_name) {
1441 return NT_STATUS_NO_MEMORY;
1444 /* create the policy handle */
1445 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1446 if (!u_handle) {
1447 return NT_STATUS_NO_MEMORY;
1450 u_handle->data = talloc_steal(u_handle, a_state);
1452 *r->out.user_handle = u_handle->wire_handle;
1453 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1455 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1457 return NT_STATUS_OK;
1462 samr_CreateUser
1464 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1465 struct samr_CreateUser *r)
1467 struct samr_CreateUser2 r2;
1468 uint32_t access_granted = 0;
1471 /* a simple wrapper around samr_CreateUser2 works nicely */
1472 r2.in.domain_handle = r->in.domain_handle;
1473 r2.in.account_name = r->in.account_name;
1474 r2.in.acct_flags = ACB_NORMAL;
1475 r2.in.access_mask = r->in.access_mask;
1476 r2.out.user_handle = r->out.user_handle;
1477 r2.out.access_granted = &access_granted;
1478 r2.out.rid = r->out.rid;
1480 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1484 samr_EnumDomainUsers
1486 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1487 struct samr_EnumDomainUsers *r)
1489 struct dcesrv_handle *h;
1490 struct samr_domain_state *d_state;
1491 struct ldb_result *res;
1492 int ret, num_filtered_entries, i, first;
1493 struct samr_SamEntry *entries;
1494 const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
1496 *r->out.resume_handle = 0;
1497 r->out.sam = NULL;
1498 r->out.num_entries = 0;
1500 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1502 d_state = h->data;
1504 /* don't have to worry about users in the builtin domain, as there are none */
1505 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1507 if (ret != LDB_SUCCESS) {
1508 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n",
1509 ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1510 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1513 /* convert to SamEntry format */
1514 entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1515 if (!entries) {
1516 return NT_STATUS_NO_MEMORY;
1518 num_filtered_entries = 0;
1519 for (i=0;i<res->count;i++) {
1520 /* Check if a mask has been requested */
1521 if (r->in.acct_flags
1522 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i],
1523 d_state->domain_dn) & r->in.acct_flags) == 0)) {
1524 continue;
1526 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1527 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1528 num_filtered_entries++;
1531 /* sort the results by rid */
1532 qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry),
1533 (comparison_fn_t)compare_SamEntry);
1535 /* find the first entry to return */
1536 for (first=0;
1537 first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1538 first++) ;
1540 /* return the rest, limit by max_size. Note that we
1541 use the w2k3 element size value of 54 */
1542 r->out.num_entries = num_filtered_entries - first;
1543 r->out.num_entries = MIN(r->out.num_entries,
1544 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1546 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1547 if (!r->out.sam) {
1548 return NT_STATUS_NO_MEMORY;
1551 r->out.sam->entries = entries+first;
1552 r->out.sam->count = r->out.num_entries;
1554 if (first == num_filtered_entries) {
1555 return NT_STATUS_OK;
1558 if (r->out.num_entries < num_filtered_entries - first) {
1559 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1560 return STATUS_MORE_ENTRIES;
1563 return NT_STATUS_OK;
1568 samr_CreateDomAlias
1570 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1571 struct samr_CreateDomAlias *r)
1573 struct samr_domain_state *d_state;
1574 struct samr_account_state *a_state;
1575 struct dcesrv_handle *h;
1576 const char *alias_name, *name;
1577 struct ldb_message *msg;
1578 struct dom_sid *sid;
1579 struct dcesrv_handle *a_handle;
1580 int ret;
1582 ZERO_STRUCTP(r->out.alias_handle);
1583 *r->out.rid = 0;
1585 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1587 d_state = h->data;
1589 if (d_state->builtin) {
1590 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1591 return NT_STATUS_ACCESS_DENIED;
1594 alias_name = r->in.alias_name->string;
1596 if (alias_name == NULL) {
1597 return NT_STATUS_INVALID_PARAMETER;
1600 /* Check if alias already exists */
1601 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1602 "sAMAccountName",
1603 "(sAMAccountName=%s)(objectclass=group))",
1604 ldb_binary_encode_string(mem_ctx, alias_name));
1606 if (name != NULL) {
1607 return NT_STATUS_ALIAS_EXISTS;
1610 msg = ldb_msg_new(mem_ctx);
1611 if (msg == NULL) {
1612 return NT_STATUS_NO_MEMORY;
1615 /* add core elements to the ldb_message for the alias */
1616 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1617 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1618 if (!msg->dn) {
1619 return NT_STATUS_NO_MEMORY;
1622 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1623 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1624 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1626 /* create the alias */
1627 ret = ldb_add(d_state->sam_ctx, msg);
1628 switch (ret) {
1629 case LDB_SUCCESS:
1630 break;
1631 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1632 return NT_STATUS_ALIAS_EXISTS;
1633 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1634 return NT_STATUS_ACCESS_DENIED;
1635 default:
1636 DEBUG(0,("Failed to create alias record %s: %s\n",
1637 ldb_dn_get_linearized(msg->dn),
1638 ldb_errstring(d_state->sam_ctx)));
1639 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1642 a_state = talloc(d_state, struct samr_account_state);
1643 if (!a_state) {
1644 return NT_STATUS_NO_MEMORY;
1647 a_state->sam_ctx = d_state->sam_ctx;
1648 a_state->access_mask = r->in.access_mask;
1649 a_state->domain_state = talloc_reference(a_state, d_state);
1650 a_state->account_dn = talloc_steal(a_state, msg->dn);
1652 /* retrieve the sid for the alias just created */
1653 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1654 msg->dn, "objectSid", NULL);
1656 a_state->account_name = talloc_strdup(a_state, alias_name);
1657 if (!a_state->account_name) {
1658 return NT_STATUS_NO_MEMORY;
1661 /* create the policy handle */
1662 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1663 if (a_handle == NULL)
1664 return NT_STATUS_NO_MEMORY;
1666 a_handle->data = talloc_steal(a_handle, a_state);
1668 *r->out.alias_handle = a_handle->wire_handle;
1670 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1672 return NT_STATUS_OK;
1677 samr_EnumDomainAliases
1679 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1680 struct samr_EnumDomainAliases *r)
1682 struct dcesrv_handle *h;
1683 struct samr_domain_state *d_state;
1684 struct ldb_message **res;
1685 int ldb_cnt, count, i, first;
1686 struct samr_SamEntry *entries;
1687 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1689 *r->out.resume_handle = 0;
1690 r->out.sam = NULL;
1691 r->out.num_entries = 0;
1693 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1695 d_state = h->data;
1697 /* search for all domain groups in this domain. This could possibly be
1698 cached and resumed based on resume_key */
1699 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1700 d_state->domain_dn,
1701 &res, attrs,
1702 d_state->domain_sid,
1703 "(&(|(grouptype=%d)(grouptype=%d)))"
1704 "(objectclass=group))",
1705 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1706 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1707 if (ldb_cnt == -1) {
1708 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1710 if (ldb_cnt == 0) {
1711 return NT_STATUS_OK;
1714 /* convert to SamEntry format */
1715 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1716 if (!entries) {
1717 return NT_STATUS_NO_MEMORY;
1720 count = 0;
1722 for (i=0;i<ldb_cnt;i++) {
1723 struct dom_sid *alias_sid;
1725 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1726 "objectSid");
1728 if (alias_sid == NULL)
1729 continue;
1731 entries[count].idx =
1732 alias_sid->sub_auths[alias_sid->num_auths-1];
1733 entries[count].name.string =
1734 samdb_result_string(res[i], "sAMAccountName", "");
1735 count += 1;
1738 /* sort the results by rid */
1739 qsort(entries, count, sizeof(struct samr_SamEntry),
1740 (comparison_fn_t)compare_SamEntry);
1742 /* find the first entry to return */
1743 for (first=0;
1744 first<count && entries[first].idx <= *r->in.resume_handle;
1745 first++) ;
1747 if (first == count) {
1748 return NT_STATUS_OK;
1751 r->out.num_entries = count - first;
1752 r->out.num_entries = MIN(r->out.num_entries, 1000);
1754 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1755 if (!r->out.sam) {
1756 return NT_STATUS_NO_MEMORY;
1759 r->out.sam->entries = entries+first;
1760 r->out.sam->count = r->out.num_entries;
1762 if (r->out.num_entries < count - first) {
1763 *r->out.resume_handle =
1764 entries[first+r->out.num_entries-1].idx;
1765 return STATUS_MORE_ENTRIES;
1768 return NT_STATUS_OK;
1773 samr_GetAliasMembership
1775 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1776 struct samr_GetAliasMembership *r)
1778 struct dcesrv_handle *h;
1779 struct samr_domain_state *d_state;
1780 struct ldb_message **res;
1781 int i, count = 0;
1783 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1785 d_state = h->data;
1787 if (r->in.sids->num_sids > 0) {
1788 const char *filter;
1789 const char * const attrs[2] = { "objectSid", NULL };
1791 filter = talloc_asprintf(mem_ctx,
1792 "(&(|(grouptype=%d)(grouptype=%d))"
1793 "(objectclass=group)(|",
1794 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1795 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1796 if (filter == NULL)
1797 return NT_STATUS_NO_MEMORY;
1799 for (i=0; i<r->in.sids->num_sids; i++) {
1800 const char *memberdn;
1802 memberdn =
1803 samdb_search_string(d_state->sam_ctx,
1804 mem_ctx, NULL, "distinguishedName",
1805 "(objectSid=%s)",
1806 ldap_encode_ndr_dom_sid(mem_ctx,
1807 r->in.sids->sids[i].sid));
1809 if (memberdn == NULL)
1810 continue;
1812 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1813 filter, memberdn);
1814 if (filter == NULL)
1815 return NT_STATUS_NO_MEMORY;
1818 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1819 d_state->domain_dn, &res, attrs,
1820 d_state->domain_sid, "%s))", filter);
1821 if (count < 0)
1822 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1825 r->out.rids->count = 0;
1826 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1827 if (r->out.rids->ids == NULL)
1828 return NT_STATUS_NO_MEMORY;
1830 for (i=0; i<count; i++) {
1831 struct dom_sid *alias_sid;
1833 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1835 if (alias_sid == NULL) {
1836 DEBUG(0, ("Could not find objectSid\n"));
1837 continue;
1840 r->out.rids->ids[r->out.rids->count] =
1841 alias_sid->sub_auths[alias_sid->num_auths-1];
1842 r->out.rids->count += 1;
1845 return NT_STATUS_OK;
1850 samr_LookupNames
1852 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1853 struct samr_LookupNames *r)
1855 struct dcesrv_handle *h;
1856 struct samr_domain_state *d_state;
1857 int i, num_mapped;
1858 NTSTATUS status = NT_STATUS_OK;
1859 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1860 int count;
1862 ZERO_STRUCT(r->out.rids);
1863 ZERO_STRUCT(r->out.types);
1865 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1867 d_state = h->data;
1869 if (r->in.num_names == 0) {
1870 return NT_STATUS_OK;
1873 r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1874 r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1875 if (!r->out.rids.ids || !r->out.types.ids) {
1876 return NT_STATUS_NO_MEMORY;
1878 r->out.rids.count = r->in.num_names;
1879 r->out.types.count = r->in.num_names;
1881 num_mapped = 0;
1883 for (i=0;i<r->in.num_names;i++) {
1884 struct ldb_message **res;
1885 struct dom_sid *sid;
1886 uint32_t atype, rtype;
1888 r->out.rids.ids[i] = 0;
1889 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1891 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1892 "sAMAccountName=%s",
1893 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1894 if (count != 1) {
1895 status = STATUS_SOME_UNMAPPED;
1896 continue;
1899 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1900 if (sid == NULL) {
1901 status = STATUS_SOME_UNMAPPED;
1902 continue;
1905 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1906 if (atype == 0) {
1907 status = STATUS_SOME_UNMAPPED;
1908 continue;
1911 rtype = samdb_atype_map(atype);
1913 if (rtype == SID_NAME_UNKNOWN) {
1914 status = STATUS_SOME_UNMAPPED;
1915 continue;
1918 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1919 r->out.types.ids[i] = rtype;
1920 num_mapped++;
1923 if (num_mapped == 0) {
1924 return NT_STATUS_NONE_MAPPED;
1926 return status;
1931 samr_LookupRids
1933 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1934 struct samr_LookupRids *r)
1936 struct dcesrv_handle *h;
1937 struct samr_domain_state *d_state;
1938 int i, total;
1939 NTSTATUS status = NT_STATUS_OK;
1940 struct lsa_String *names;
1941 uint32_t *ids;
1943 ZERO_STRUCT(r->out.names);
1944 ZERO_STRUCT(r->out.types);
1946 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1948 d_state = h->data;
1950 if (r->in.num_rids == 0)
1951 return NT_STATUS_OK;
1953 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1954 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1956 if ((names == NULL) || (ids == NULL))
1957 return NT_STATUS_NO_MEMORY;
1959 total = 0;
1961 for (i=0; i<r->in.num_rids; i++) {
1962 struct ldb_message **res;
1963 int count;
1964 const char * const attrs[] = { "sAMAccountType",
1965 "sAMAccountName", NULL };
1966 uint32_t atype;
1967 struct dom_sid *sid;
1969 ids[i] = SID_NAME_UNKNOWN;
1971 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1972 if (sid == NULL) {
1973 names[i].string = NULL;
1974 status = STATUS_SOME_UNMAPPED;
1975 continue;
1978 count = gendb_search(d_state->sam_ctx, mem_ctx,
1979 d_state->domain_dn, &res, attrs,
1980 "(objectSid=%s)",
1981 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1982 if (count != 1) {
1983 names[i].string = NULL;
1984 status = STATUS_SOME_UNMAPPED;
1985 continue;
1988 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1989 NULL);
1991 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1992 if (atype == 0) {
1993 status = STATUS_SOME_UNMAPPED;
1994 continue;
1997 ids[i] = samdb_atype_map(atype);
1999 if (ids[i] == SID_NAME_UNKNOWN) {
2000 status = STATUS_SOME_UNMAPPED;
2001 continue;
2005 r->out.names.names = names;
2006 r->out.names.count = r->in.num_rids;
2008 r->out.types.ids = ids;
2009 r->out.types.count = r->in.num_rids;
2011 return status;
2016 samr_OpenGroup
2018 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2019 struct samr_OpenGroup *r)
2021 struct samr_domain_state *d_state;
2022 struct samr_account_state *a_state;
2023 struct dcesrv_handle *h;
2024 const char *groupname;
2025 struct dom_sid *sid;
2026 struct ldb_message **msgs;
2027 struct dcesrv_handle *g_handle;
2028 const char * const attrs[2] = { "sAMAccountName", NULL };
2029 int ret;
2031 ZERO_STRUCTP(r->out.group_handle);
2033 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2035 d_state = h->data;
2037 /* form the group SID */
2038 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2039 if (!sid) {
2040 return NT_STATUS_NO_MEMORY;
2043 /* search for the group record */
2044 ret = gendb_search(d_state->sam_ctx,
2045 mem_ctx, d_state->domain_dn, &msgs, attrs,
2046 "(&(objectSid=%s)(objectclass=group)"
2047 "(grouptype=%d))",
2048 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2049 GTYPE_SECURITY_GLOBAL_GROUP);
2050 if (ret == 0) {
2051 return NT_STATUS_NO_SUCH_GROUP;
2053 if (ret != 1) {
2054 DEBUG(0,("Found %d records matching sid %s\n",
2055 ret, dom_sid_string(mem_ctx, sid)));
2056 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2059 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2060 if (groupname == NULL) {
2061 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2062 dom_sid_string(mem_ctx, sid)));
2063 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2066 a_state = talloc(d_state, struct samr_account_state);
2067 if (!a_state) {
2068 return NT_STATUS_NO_MEMORY;
2070 a_state->sam_ctx = d_state->sam_ctx;
2071 a_state->access_mask = r->in.access_mask;
2072 a_state->domain_state = talloc_reference(a_state, d_state);
2073 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2074 a_state->account_sid = talloc_steal(a_state, sid);
2075 a_state->account_name = talloc_strdup(a_state, groupname);
2076 if (!a_state->account_name) {
2077 return NT_STATUS_NO_MEMORY;
2080 /* create the policy handle */
2081 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2082 if (!g_handle) {
2083 return NT_STATUS_NO_MEMORY;
2086 g_handle->data = talloc_steal(g_handle, a_state);
2088 *r->out.group_handle = g_handle->wire_handle;
2090 return NT_STATUS_OK;
2094 samr_QueryGroupInfo
2096 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2097 struct samr_QueryGroupInfo *r)
2099 struct dcesrv_handle *h;
2100 struct samr_account_state *a_state;
2101 struct ldb_message *msg;
2102 struct ldb_result *res;
2103 const char * const attrs[4] = { "sAMAccountName", "description",
2104 "numMembers", NULL };
2105 int ret;
2107 r->out.info = NULL;
2109 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2111 a_state = h->data;
2113 ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2115 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2116 return NT_STATUS_NO_SUCH_GROUP;
2117 } else if (ret != LDB_SUCCESS) {
2118 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2119 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2122 if (res->count != 1) {
2123 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2125 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2127 msg = res->msgs[0];
2129 /* allocate the info structure */
2130 r->out.info = talloc(mem_ctx, union samr_GroupInfo);
2131 if (r->out.info == NULL) {
2132 return NT_STATUS_NO_MEMORY;
2134 ZERO_STRUCTP(r->out.info);
2136 /* Fill in the level */
2137 switch (r->in.level) {
2138 case GROUPINFOALL:
2139 QUERY_STRING(msg, all.name, "sAMAccountName");
2140 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2141 QUERY_UINT (msg, all.num_members, "numMembers")
2142 QUERY_STRING(msg, all.description, "description");
2143 break;
2144 case GROUPINFONAME:
2145 QUERY_STRING(msg, name, "sAMAccountName");
2146 break;
2147 case GROUPINFOATTRIBUTES:
2148 r->out.info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2149 break;
2150 case GROUPINFODESCRIPTION:
2151 QUERY_STRING(msg, description, "description");
2152 break;
2153 case GROUPINFOALL2:
2154 QUERY_STRING(msg, all2.name, "sAMAccountName");
2155 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2156 QUERY_UINT (msg, all2.num_members, "numMembers")
2157 QUERY_STRING(msg, all2.description, "description");
2158 break;
2159 default:
2160 r->out.info = NULL;
2161 return NT_STATUS_INVALID_INFO_CLASS;
2164 return NT_STATUS_OK;
2169 samr_SetGroupInfo
2171 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2172 struct samr_SetGroupInfo *r)
2174 struct dcesrv_handle *h;
2175 struct samr_account_state *g_state;
2176 struct ldb_message *msg;
2177 struct ldb_context *sam_ctx;
2178 int ret;
2180 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2182 g_state = h->data;
2183 sam_ctx = g_state->sam_ctx;
2185 msg = ldb_msg_new(mem_ctx);
2186 if (msg == NULL) {
2187 return NT_STATUS_NO_MEMORY;
2190 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2191 if (!msg->dn) {
2192 return NT_STATUS_NO_MEMORY;
2195 switch (r->in.level) {
2196 case GROUPINFODESCRIPTION:
2197 SET_STRING(msg, description, "description");
2198 break;
2199 case GROUPINFONAME:
2200 /* On W2k3 this does not change the name, it changes the
2201 * sAMAccountName attribute */
2202 SET_STRING(msg, name, "sAMAccountName");
2203 break;
2204 case GROUPINFOATTRIBUTES:
2205 /* This does not do anything obviously visible in W2k3 LDAP */
2206 return NT_STATUS_OK;
2207 default:
2208 return NT_STATUS_INVALID_INFO_CLASS;
2211 /* modify the samdb record */
2212 ret = ldb_modify(g_state->sam_ctx, msg);
2213 if (ret != 0) {
2214 /* we really need samdb.c to return NTSTATUS */
2215 return NT_STATUS_UNSUCCESSFUL;
2218 return NT_STATUS_OK;
2223 samr_AddGroupMember
2225 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2226 struct samr_AddGroupMember *r)
2228 struct dcesrv_handle *h;
2229 struct samr_account_state *a_state;
2230 struct samr_domain_state *d_state;
2231 struct ldb_message *mod;
2232 struct dom_sid *membersid;
2233 const char *memberdn;
2234 struct ldb_result *res;
2235 const char * const attrs[] = { NULL };
2236 int ret;
2238 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2240 a_state = h->data;
2241 d_state = a_state->domain_state;
2243 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2244 if (membersid == NULL)
2245 return NT_STATUS_NO_MEMORY;
2247 /* In native mode, AD can also nest domain groups. Not sure yet
2248 * whether this is also available via RPC. */
2249 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2250 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2251 "(&(objectSid=%s)(objectclass=user))",
2252 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2254 if (ret != 0) {
2255 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2258 if (res->count == 0) {
2259 return NT_STATUS_NO_SUCH_USER;
2262 if (res->count > 1) {
2263 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2266 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2268 if (memberdn == NULL)
2269 return NT_STATUS_NO_MEMORY;
2271 mod = ldb_msg_new(mem_ctx);
2272 if (mod == NULL) {
2273 return NT_STATUS_NO_MEMORY;
2276 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2278 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2279 memberdn) != 0)
2280 return NT_STATUS_UNSUCCESSFUL;
2282 ret = ldb_modify(a_state->sam_ctx, mod);
2283 switch (ret) {
2284 case LDB_SUCCESS:
2285 return NT_STATUS_OK;
2286 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2287 return NT_STATUS_MEMBER_IN_GROUP;
2288 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2289 return NT_STATUS_ACCESS_DENIED;
2290 default:
2291 return NT_STATUS_UNSUCCESSFUL;
2298 samr_DeleteDomainGroup
2300 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2301 struct samr_DeleteDomainGroup *r)
2303 struct dcesrv_handle *h;
2304 struct samr_account_state *a_state;
2305 int ret;
2307 *r->out.group_handle = *r->in.group_handle;
2309 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2311 a_state = h->data;
2313 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2314 if (ret != 0) {
2315 return NT_STATUS_UNSUCCESSFUL;
2318 ZERO_STRUCTP(r->out.group_handle);
2320 return NT_STATUS_OK;
2325 samr_DeleteGroupMember
2327 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2328 struct samr_DeleteGroupMember *r)
2330 struct dcesrv_handle *h;
2331 struct samr_account_state *a_state;
2332 struct samr_domain_state *d_state;
2333 struct ldb_message *mod;
2334 struct dom_sid *membersid;
2335 const char *memberdn;
2336 struct ldb_result *res;
2337 const char * const attrs[] = { NULL };
2338 int ret;
2340 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2342 a_state = h->data;
2343 d_state = a_state->domain_state;
2345 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2346 if (membersid == NULL)
2347 return NT_STATUS_NO_MEMORY;
2349 /* In native mode, AD can also nest domain groups. Not sure yet
2350 * whether this is also available via RPC. */
2351 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2352 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2353 "(&(objectSid=%s)(objectclass=user))",
2354 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2356 if (ret != 0) {
2357 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2360 if (res->count == 0) {
2361 return NT_STATUS_NO_SUCH_USER;
2364 if (res->count > 1) {
2365 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2368 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2370 if (memberdn == NULL)
2371 return NT_STATUS_NO_MEMORY;
2373 mod = ldb_msg_new(mem_ctx);
2374 if (mod == NULL) {
2375 return NT_STATUS_NO_MEMORY;
2378 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2380 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2381 memberdn) != 0) {
2382 return NT_STATUS_NO_MEMORY;
2385 ret = ldb_modify(a_state->sam_ctx, mod);
2386 switch (ret) {
2387 case LDB_SUCCESS:
2388 return NT_STATUS_OK;
2389 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2390 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2391 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2392 return NT_STATUS_ACCESS_DENIED;
2393 default:
2394 return NT_STATUS_UNSUCCESSFUL;
2401 samr_QueryGroupMember
2403 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2404 struct samr_QueryGroupMember *r)
2406 struct dcesrv_handle *h;
2407 struct samr_account_state *a_state;
2408 struct ldb_message **res;
2409 struct ldb_message_element *el;
2410 struct samr_RidTypeArray *array;
2411 const char * const attrs[2] = { "member", NULL };
2412 int ret;
2414 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2416 a_state = h->data;
2418 /* pull the member attribute */
2419 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2420 a_state->account_dn, &res, attrs);
2422 if (ret != 1) {
2423 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2426 array = talloc(mem_ctx, struct samr_RidTypeArray);
2428 if (array == NULL)
2429 return NT_STATUS_NO_MEMORY;
2431 ZERO_STRUCTP(array);
2433 el = ldb_msg_find_element(res[0], "member");
2435 if (el != NULL) {
2436 int i;
2438 array->count = el->num_values;
2440 array->rids = talloc_array(mem_ctx, uint32_t,
2441 el->num_values);
2442 if (array->rids == NULL)
2443 return NT_STATUS_NO_MEMORY;
2445 array->types = talloc_array(mem_ctx, uint32_t,
2446 el->num_values);
2447 if (array->types == NULL)
2448 return NT_STATUS_NO_MEMORY;
2450 for (i=0; i<el->num_values; i++) {
2451 struct ldb_message **res2;
2452 const char * const attrs2[2] = { "objectSid", NULL };
2453 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2454 ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2455 &res2, attrs2);
2456 if (ret != 1)
2457 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2459 array->rids[i] =
2460 samdb_result_rid_from_sid(mem_ctx, res2[0],
2461 "objectSid", 0);
2463 if (array->rids[i] == 0)
2464 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2466 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2470 r->out.rids = array;
2472 return NT_STATUS_OK;
2477 samr_SetMemberAttributesOfGroup
2479 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2480 struct samr_SetMemberAttributesOfGroup *r)
2482 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2487 samr_OpenAlias
2489 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2490 struct samr_OpenAlias *r)
2492 struct samr_domain_state *d_state;
2493 struct samr_account_state *a_state;
2494 struct dcesrv_handle *h;
2495 const char *alias_name;
2496 struct dom_sid *sid;
2497 struct ldb_message **msgs;
2498 struct dcesrv_handle *g_handle;
2499 const char * const attrs[2] = { "sAMAccountName", NULL };
2500 int ret;
2502 ZERO_STRUCTP(r->out.alias_handle);
2504 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2506 d_state = h->data;
2508 /* form the alias SID */
2509 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2510 if (sid == NULL)
2511 return NT_STATUS_NO_MEMORY;
2513 /* search for the group record */
2514 ret = gendb_search(d_state->sam_ctx,
2515 mem_ctx, d_state->domain_dn, &msgs, attrs,
2516 "(&(objectSid=%s)(objectclass=group)"
2517 "(|(grouptype=%d)(grouptype=%d)))",
2518 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2519 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2520 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2521 if (ret == 0) {
2522 return NT_STATUS_NO_SUCH_ALIAS;
2524 if (ret != 1) {
2525 DEBUG(0,("Found %d records matching sid %s\n",
2526 ret, dom_sid_string(mem_ctx, sid)));
2527 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2530 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2531 if (alias_name == NULL) {
2532 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2533 dom_sid_string(mem_ctx, sid)));
2534 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2537 a_state = talloc(d_state, struct samr_account_state);
2538 if (!a_state) {
2539 return NT_STATUS_NO_MEMORY;
2541 a_state->sam_ctx = d_state->sam_ctx;
2542 a_state->access_mask = r->in.access_mask;
2543 a_state->domain_state = talloc_reference(a_state, d_state);
2544 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2545 a_state->account_sid = talloc_steal(a_state, sid);
2546 a_state->account_name = talloc_strdup(a_state, alias_name);
2547 if (!a_state->account_name) {
2548 return NT_STATUS_NO_MEMORY;
2551 /* create the policy handle */
2552 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2553 if (!g_handle) {
2554 return NT_STATUS_NO_MEMORY;
2557 g_handle->data = talloc_steal(g_handle, a_state);
2559 *r->out.alias_handle = g_handle->wire_handle;
2561 return NT_STATUS_OK;
2566 samr_QueryAliasInfo
2568 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2569 struct samr_QueryAliasInfo *r)
2571 struct dcesrv_handle *h;
2572 struct samr_account_state *a_state;
2573 struct ldb_message *msg, **res;
2574 const char * const attrs[4] = { "sAMAccountName", "description",
2575 "numMembers", NULL };
2576 int ret;
2578 r->out.info = NULL;
2580 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2582 a_state = h->data;
2584 /* pull all the alias attributes */
2585 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2586 a_state->account_dn ,&res, attrs);
2587 if (ret != 1) {
2588 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2590 msg = res[0];
2592 /* allocate the info structure */
2593 r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2594 if (r->out.info == NULL) {
2595 return NT_STATUS_NO_MEMORY;
2597 ZERO_STRUCTP(r->out.info);
2599 switch(r->in.level) {
2600 case ALIASINFOALL:
2601 QUERY_STRING(msg, all.name, "sAMAccountName");
2602 QUERY_UINT (msg, all.num_members, "numMembers");
2603 QUERY_STRING(msg, all.description, "description");
2604 break;
2605 case ALIASINFONAME:
2606 QUERY_STRING(msg, name, "sAMAccountName");
2607 break;
2608 case ALIASINFODESCRIPTION:
2609 QUERY_STRING(msg, description, "description");
2610 break;
2611 default:
2612 r->out.info = NULL;
2613 return NT_STATUS_INVALID_INFO_CLASS;
2616 return NT_STATUS_OK;
2621 samr_SetAliasInfo
2623 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2624 struct samr_SetAliasInfo *r)
2626 struct dcesrv_handle *h;
2627 struct samr_account_state *a_state;
2628 struct ldb_message *msg;
2629 struct ldb_context *sam_ctx;
2630 int ret;
2632 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2634 a_state = h->data;
2635 sam_ctx = a_state->sam_ctx;
2637 msg = ldb_msg_new(mem_ctx);
2638 if (msg == NULL) {
2639 return NT_STATUS_NO_MEMORY;
2642 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2643 if (!msg->dn) {
2644 return NT_STATUS_NO_MEMORY;
2647 switch (r->in.level) {
2648 case ALIASINFODESCRIPTION:
2649 SET_STRING(msg, description, "description");
2650 break;
2651 case ALIASINFONAME:
2652 /* On W2k3 this does not change the name, it changes the
2653 * sAMAccountName attribute */
2654 SET_STRING(msg, name, "sAMAccountName");
2655 break;
2656 default:
2657 return NT_STATUS_INVALID_INFO_CLASS;
2660 /* modify the samdb record */
2661 ret = ldb_modify(a_state->sam_ctx, msg);
2662 if (ret != 0) {
2663 /* we really need samdb.c to return NTSTATUS */
2664 return NT_STATUS_UNSUCCESSFUL;
2667 return NT_STATUS_OK;
2672 samr_DeleteDomAlias
2674 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2675 struct samr_DeleteDomAlias *r)
2677 struct dcesrv_handle *h;
2678 struct samr_account_state *a_state;
2679 int ret;
2681 *r->out.alias_handle = *r->in.alias_handle;
2683 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2685 a_state = h->data;
2687 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2688 if (ret != 0) {
2689 return NT_STATUS_UNSUCCESSFUL;
2692 ZERO_STRUCTP(r->out.alias_handle);
2694 return NT_STATUS_OK;
2699 samr_AddAliasMember
2701 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2702 struct samr_AddAliasMember *r)
2704 struct dcesrv_handle *h;
2705 struct samr_account_state *a_state;
2706 struct samr_domain_state *d_state;
2707 struct ldb_message *mod;
2708 struct ldb_message **msgs;
2709 const char * const attrs[] = { NULL };
2710 struct ldb_dn *memberdn = NULL;
2711 int ret;
2712 NTSTATUS status;
2714 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2716 a_state = h->data;
2717 d_state = a_state->domain_state;
2719 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2720 &msgs, attrs, "(objectsid=%s)",
2721 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2723 if (ret == 1) {
2724 memberdn = msgs[0]->dn;
2725 } else if (ret > 1) {
2726 DEBUG(0,("Found %d records matching sid %s\n",
2727 ret, dom_sid_string(mem_ctx, r->in.sid)));
2728 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2729 } else if (ret == 0) {
2730 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx,
2731 r->in.sid, &memberdn);
2732 if (!NT_STATUS_IS_OK(status)) {
2733 return status;
2735 } else {
2736 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2739 if (memberdn == NULL) {
2740 DEBUG(0, ("Could not find memberdn\n"));
2741 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2744 mod = ldb_msg_new(mem_ctx);
2745 if (mod == NULL) {
2746 return NT_STATUS_NO_MEMORY;
2749 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2751 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2752 ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2753 return NT_STATUS_UNSUCCESSFUL;
2755 if (ldb_modify(a_state->sam_ctx, mod) != 0)
2756 return NT_STATUS_UNSUCCESSFUL;
2758 return NT_STATUS_OK;
2763 samr_DeleteAliasMember
2765 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2766 struct samr_DeleteAliasMember *r)
2768 struct dcesrv_handle *h;
2769 struct samr_account_state *a_state;
2770 struct samr_domain_state *d_state;
2771 struct ldb_message *mod;
2772 const char *memberdn;
2774 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2776 a_state = h->data;
2777 d_state = a_state->domain_state;
2779 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2780 "distinguishedName", "(objectSid=%s)",
2781 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2783 if (memberdn == NULL)
2784 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2786 mod = ldb_msg_new(mem_ctx);
2787 if (mod == NULL) {
2788 return NT_STATUS_NO_MEMORY;
2791 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2793 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2794 memberdn) != 0)
2795 return NT_STATUS_UNSUCCESSFUL;
2797 if (ldb_modify(a_state->sam_ctx, mod) != 0)
2798 return NT_STATUS_UNSUCCESSFUL;
2800 return NT_STATUS_OK;
2805 samr_GetMembersInAlias
2807 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2808 struct samr_GetMembersInAlias *r)
2810 struct dcesrv_handle *h;
2811 struct samr_account_state *a_state;
2812 struct samr_domain_state *d_state;
2813 struct ldb_message **msgs;
2814 struct lsa_SidPtr *sids;
2815 struct ldb_message_element *el;
2816 const char * const attrs[2] = { "member", NULL};
2817 int ret;
2819 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2821 a_state = h->data;
2822 d_state = a_state->domain_state;
2824 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2825 a_state->account_dn, &msgs, attrs);
2827 if (ret != 1)
2828 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2830 r->out.sids->num_sids = 0;
2831 r->out.sids->sids = NULL;
2833 el = ldb_msg_find_element(msgs[0], "member");
2835 if (el != NULL) {
2836 int i;
2838 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2839 el->num_values);
2841 if (sids == NULL)
2842 return NT_STATUS_NO_MEMORY;
2844 for (i=0; i<el->num_values; i++) {
2845 struct ldb_message **msgs2;
2846 const char * const attrs2[2] = { "objectSid", NULL };
2847 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2848 ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2849 &msgs2, attrs2);
2850 if (ret != 1)
2851 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2853 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2854 "objectSid");
2856 if (sids[i].sid == NULL)
2857 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2859 r->out.sids->num_sids = el->num_values;
2860 r->out.sids->sids = sids;
2863 return NT_STATUS_OK;
2867 samr_OpenUser
2869 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2870 struct samr_OpenUser *r)
2872 struct samr_domain_state *d_state;
2873 struct samr_account_state *a_state;
2874 struct dcesrv_handle *h;
2875 const char *account_name;
2876 struct dom_sid *sid;
2877 struct ldb_message **msgs;
2878 struct dcesrv_handle *u_handle;
2879 const char * const attrs[2] = { "sAMAccountName", NULL };
2880 int ret;
2882 ZERO_STRUCTP(r->out.user_handle);
2884 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2886 d_state = h->data;
2888 /* form the users SID */
2889 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2890 if (!sid) {
2891 return NT_STATUS_NO_MEMORY;
2894 /* search for the user record */
2895 ret = gendb_search(d_state->sam_ctx,
2896 mem_ctx, d_state->domain_dn, &msgs, attrs,
2897 "(&(objectSid=%s)(objectclass=user))",
2898 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2899 if (ret == 0) {
2900 return NT_STATUS_NO_SUCH_USER;
2902 if (ret != 1) {
2903 DEBUG(0,("Found %d records matching sid %s\n", ret,
2904 dom_sid_string(mem_ctx, sid)));
2905 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2908 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2909 if (account_name == NULL) {
2910 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2911 dom_sid_string(mem_ctx, sid)));
2912 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2915 a_state = talloc(mem_ctx, struct samr_account_state);
2916 if (!a_state) {
2917 return NT_STATUS_NO_MEMORY;
2919 a_state->sam_ctx = d_state->sam_ctx;
2920 a_state->access_mask = r->in.access_mask;
2921 a_state->domain_state = talloc_reference(a_state, d_state);
2922 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2923 a_state->account_sid = talloc_steal(a_state, sid);
2924 a_state->account_name = talloc_strdup(a_state, account_name);
2925 if (!a_state->account_name) {
2926 return NT_STATUS_NO_MEMORY;
2929 /* create the policy handle */
2930 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2931 if (!u_handle) {
2932 return NT_STATUS_NO_MEMORY;
2935 u_handle->data = talloc_steal(u_handle, a_state);
2937 *r->out.user_handle = u_handle->wire_handle;
2939 return NT_STATUS_OK;
2945 samr_DeleteUser
2947 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2948 struct samr_DeleteUser *r)
2950 struct dcesrv_handle *h;
2951 struct samr_account_state *a_state;
2952 int ret;
2954 *r->out.user_handle = *r->in.user_handle;
2956 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2958 a_state = h->data;
2960 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2961 if (ret != 0) {
2962 DEBUG(1, ("Failed to delete user: %s: %s\n",
2963 ldb_dn_get_linearized(a_state->account_dn),
2964 ldb_errstring(a_state->sam_ctx)));
2965 return NT_STATUS_UNSUCCESSFUL;
2968 ZERO_STRUCTP(r->out.user_handle);
2970 return NT_STATUS_OK;
2975 samr_QueryUserInfo
2977 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2978 struct samr_QueryUserInfo *r)
2980 struct dcesrv_handle *h;
2981 struct samr_account_state *a_state;
2982 struct ldb_message *msg, **res;
2983 int ret;
2984 struct ldb_context *sam_ctx;
2986 const char * const *attrs = NULL;
2988 r->out.info = NULL;
2990 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2992 a_state = h->data;
2993 sam_ctx = a_state->sam_ctx;
2995 /* fill in the reply */
2996 switch (r->in.level) {
2997 case 1:
2999 static const char * const attrs2[] = {"sAMAccountName", "displayName",
3000 "primaryroupID", "description",
3001 "comment", NULL};
3002 attrs = attrs2;
3003 break;
3005 case 2:
3007 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
3008 attrs = attrs2;
3009 break;
3011 case 3:
3013 static const char * const attrs2[] = {"sAMAccountName",
3014 "displayName",
3015 "objectSid",
3016 "primaryGroupID",
3017 "homeDirectory",
3018 "homeDrive",
3019 "scriptPath",
3020 "profilePath",
3021 "userWorkstations",
3022 "lastLogon",
3023 "lastLogoff",
3024 "pwdLastSet",
3025 "logonHours",
3026 "badPwdCount",
3027 "logonCount",
3028 "userAccountControl", NULL};
3029 attrs = attrs2;
3030 break;
3032 case 4:
3034 static const char * const attrs2[] = {"logonHours", NULL};
3035 attrs = attrs2;
3036 break;
3038 case 5:
3040 static const char * const attrs2[] = {"sAMAccountName",
3041 "displayName",
3042 "objectSid",
3043 "primaryGroupID",
3044 "homeDirectory",
3045 "homeDrive",
3046 "scriptPath",
3047 "profilePath",
3048 "description",
3049 "userWorkstations",
3050 "lastLogon",
3051 "lastLogoff",
3052 "logonHours",
3053 "badPwdCount",
3054 "logonCount",
3055 "pwdLastSet",
3056 "accountExpires",
3057 "userAccountControl",
3058 NULL};
3059 attrs = attrs2;
3060 break;
3062 case 6:
3064 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
3065 attrs = attrs2;
3066 break;
3068 case 7:
3070 static const char * const attrs2[] = {"sAMAccountName", NULL};
3071 attrs = attrs2;
3072 break;
3074 case 8:
3076 static const char * const attrs2[] = {"displayName", NULL};
3077 attrs = attrs2;
3078 break;
3080 case 9:
3082 static const char * const attrs2[] = {"primaryGroupID", NULL};
3083 attrs = attrs2;
3084 break;
3086 case 10:
3088 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3089 attrs = attrs2;
3090 break;
3092 case 11:
3094 static const char * const attrs2[] = {"scriptPath", NULL};
3095 attrs = attrs2;
3096 break;
3098 case 12:
3100 static const char * const attrs2[] = {"profilePath", NULL};
3101 attrs = attrs2;
3102 break;
3104 case 13:
3106 static const char * const attrs2[] = {"description", NULL};
3107 attrs = attrs2;
3108 break;
3110 case 14:
3112 static const char * const attrs2[] = {"userWorkstations", NULL};
3113 attrs = attrs2;
3114 break;
3116 case 16:
3118 static const char * const attrs2[] = {"userAccountControl", "pwdLastSet", NULL};
3119 attrs = attrs2;
3120 break;
3122 case 17:
3124 static const char * const attrs2[] = {"accountExpires", NULL};
3125 attrs = attrs2;
3126 break;
3128 case 20:
3130 static const char * const attrs2[] = {"userParameters", NULL};
3131 attrs = attrs2;
3132 break;
3134 case 21:
3136 static const char * const attrs2[] = {"lastLogon",
3137 "lastLogoff",
3138 "pwdLastSet",
3139 "accountExpires",
3140 "sAMAccountName",
3141 "displayName",
3142 "homeDirectory",
3143 "homeDrive",
3144 "scriptPath",
3145 "profilePath",
3146 "description",
3147 "userWorkstations",
3148 "comment",
3149 "userParameters",
3150 "objectSid",
3151 "primaryGroupID",
3152 "userAccountControl",
3153 "logonHours",
3154 "badPwdCount",
3155 "logonCount",
3156 "countryCode",
3157 "codePage",
3158 NULL};
3159 attrs = attrs2;
3160 break;
3164 /* pull all the user attributes */
3165 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3166 a_state->account_dn ,&res, attrs);
3167 if (ret != 1) {
3168 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3170 msg = res[0];
3172 /* allocate the info structure */
3173 r->out.info = talloc(mem_ctx, union samr_UserInfo);
3174 if (r->out.info == NULL) {
3175 return NT_STATUS_NO_MEMORY;
3177 ZERO_STRUCTP(r->out.info);
3179 /* fill in the reply */
3180 switch (r->in.level) {
3181 case 1:
3182 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3183 QUERY_STRING(msg, info1.full_name, "displayName");
3184 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3185 QUERY_STRING(msg, info1.description, "description");
3186 QUERY_STRING(msg, info1.comment, "comment");
3187 break;
3189 case 2:
3190 QUERY_STRING(msg, info2.comment, "comment");
3191 QUERY_UINT (msg, info2.country_code, "countryCode");
3192 QUERY_UINT (msg, info2.code_page, "codePage");
3193 break;
3195 case 3:
3196 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3197 QUERY_STRING(msg, info3.full_name, "displayName");
3198 QUERY_RID (msg, info3.rid, "objectSid");
3199 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3200 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3201 QUERY_STRING(msg, info3.home_drive, "homeDrive");
3202 QUERY_STRING(msg, info3.logon_script, "scriptPath");
3203 QUERY_STRING(msg, info3.profile_path, "profilePath");
3204 QUERY_STRING(msg, info3.workstations, "userWorkstations");
3205 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3206 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3207 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3208 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3209 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3210 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3211 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3212 QUERY_UINT (msg, info3.logon_count, "logonCount");
3213 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3214 break;
3216 case 4:
3217 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3218 break;
3220 case 5:
3221 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3222 QUERY_STRING(msg, info5.full_name, "displayName");
3223 QUERY_RID (msg, info5.rid, "objectSid");
3224 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3225 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3226 QUERY_STRING(msg, info5.home_drive, "homeDrive");
3227 QUERY_STRING(msg, info5.logon_script, "scriptPath");
3228 QUERY_STRING(msg, info5.profile_path, "profilePath");
3229 QUERY_STRING(msg, info5.description, "description");
3230 QUERY_STRING(msg, info5.workstations, "userWorkstations");
3231 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3232 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3233 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3234 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3235 QUERY_UINT (msg, info5.logon_count, "logonCount");
3236 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3237 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3238 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3239 break;
3241 case 6:
3242 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3243 QUERY_STRING(msg, info6.full_name, "displayName");
3244 break;
3246 case 7:
3247 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3248 break;
3250 case 8:
3251 QUERY_STRING(msg, info8.full_name, "displayName");
3252 break;
3254 case 9:
3255 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3256 break;
3258 case 10:
3259 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3260 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3261 break;
3263 case 11:
3264 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3265 break;
3267 case 12:
3268 QUERY_STRING(msg, info12.profile_path, "profilePath");
3269 break;
3271 case 13:
3272 QUERY_STRING(msg, info13.description, "description");
3273 break;
3275 case 14:
3276 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3277 break;
3279 case 16:
3280 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3281 break;
3283 case 17:
3284 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3285 break;
3287 case 20:
3288 QUERY_STRING(msg, info20.parameters, "userParameters");
3289 break;
3291 case 21:
3292 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3293 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3294 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3295 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3296 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3297 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3298 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3299 QUERY_STRING(msg, info21.full_name, "displayName");
3300 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3301 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3302 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3303 QUERY_STRING(msg, info21.profile_path, "profilePath");
3304 QUERY_STRING(msg, info21.description, "description");
3305 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3306 QUERY_STRING(msg, info21.comment, "comment");
3307 QUERY_STRING(msg, info21.parameters, "userParameters");
3308 QUERY_RID (msg, info21.rid, "objectSid");
3309 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3310 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3311 r->out.info->info21.fields_present = 0x00FFFFFF;
3312 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3313 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3314 QUERY_UINT (msg, info21.logon_count, "logonCount");
3315 QUERY_UINT (msg, info21.country_code, "countryCode");
3316 QUERY_UINT (msg, info21.code_page, "codePage");
3317 break;
3320 default:
3321 r->out.info = NULL;
3322 return NT_STATUS_INVALID_INFO_CLASS;
3325 return NT_STATUS_OK;
3330 samr_SetUserInfo
3332 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3333 struct samr_SetUserInfo *r)
3335 struct dcesrv_handle *h;
3336 struct samr_account_state *a_state;
3337 struct ldb_message *msg;
3338 int ret;
3339 NTSTATUS status = NT_STATUS_OK;
3340 struct ldb_context *sam_ctx;
3342 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3344 a_state = h->data;
3345 sam_ctx = a_state->sam_ctx;
3347 msg = ldb_msg_new(mem_ctx);
3348 if (msg == NULL) {
3349 return NT_STATUS_NO_MEMORY;
3352 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3353 if (!msg->dn) {
3354 return NT_STATUS_NO_MEMORY;
3357 switch (r->in.level) {
3358 case 2:
3359 SET_STRING(msg, info2.comment, "comment");
3360 SET_UINT (msg, info2.country_code, "countryCode");
3361 SET_UINT (msg, info2.code_page, "codePage");
3362 break;
3364 case 4:
3365 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3366 break;
3368 case 6:
3369 SET_STRING(msg, info6.full_name, "displayName");
3370 break;
3372 case 7:
3373 SET_STRING(msg, info7.account_name, "samAccountName");
3374 break;
3376 case 8:
3377 SET_STRING(msg, info8.full_name, "displayName");
3378 break;
3380 case 9:
3381 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3382 break;
3384 case 10:
3385 SET_STRING(msg, info10.home_directory, "homeDirectory");
3386 SET_STRING(msg, info10.home_drive, "homeDrive");
3387 break;
3389 case 11:
3390 SET_STRING(msg, info11.logon_script, "scriptPath");
3391 break;
3393 case 12:
3394 SET_STRING(msg, info12.profile_path, "profilePath");
3395 break;
3397 case 13:
3398 SET_STRING(msg, info13.description, "description");
3399 break;
3401 case 14:
3402 SET_STRING(msg, info14.workstations, "userWorkstations");
3403 break;
3405 case 16:
3406 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3407 break;
3409 case 17:
3410 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3411 break;
3413 case 20:
3414 SET_STRING(msg, info20.parameters, "userParameters");
3415 break;
3417 case 21:
3418 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3419 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3420 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3421 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3422 SET_STRING(msg, info21.account_name, "samAccountName");
3423 IFSET(SAMR_FIELD_FULL_NAME)
3424 SET_STRING(msg, info21.full_name, "displayName");
3425 IFSET(SAMR_FIELD_DESCRIPTION)
3426 SET_STRING(msg, info21.description, "description");
3427 IFSET(SAMR_FIELD_COMMENT)
3428 SET_STRING(msg, info21.comment, "comment");
3429 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3430 SET_STRING(msg, info21.logon_script, "scriptPath");
3431 IFSET(SAMR_FIELD_PROFILE_PATH)
3432 SET_STRING(msg, info21.profile_path, "profilePath");
3433 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3434 SET_STRING(msg, info21.home_directory, "homeDirectory");
3435 IFSET(SAMR_FIELD_HOME_DRIVE)
3436 SET_STRING(msg, info21.home_drive, "homeDrive");
3437 IFSET(SAMR_FIELD_WORKSTATIONS)
3438 SET_STRING(msg, info21.workstations, "userWorkstations");
3439 IFSET(SAMR_FIELD_LOGON_HOURS)
3440 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3441 IFSET(SAMR_FIELD_ACCT_FLAGS)
3442 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3443 IFSET(SAMR_FIELD_PARAMETERS)
3444 SET_STRING(msg, info21.parameters, "userParameters");
3445 IFSET(SAMR_FIELD_COUNTRY_CODE)
3446 SET_UINT (msg, info21.country_code, "countryCode");
3447 IFSET(SAMR_FIELD_CODE_PAGE)
3448 SET_UINT (msg, info21.code_page, "codePage");
3449 #undef IFSET
3450 break;
3452 case 23:
3453 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3454 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3455 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3456 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3457 SET_STRING(msg, info23.info.account_name, "samAccountName");
3458 IFSET(SAMR_FIELD_FULL_NAME)
3459 SET_STRING(msg, info23.info.full_name, "displayName");
3460 IFSET(SAMR_FIELD_DESCRIPTION)
3461 SET_STRING(msg, info23.info.description, "description");
3462 IFSET(SAMR_FIELD_COMMENT)
3463 SET_STRING(msg, info23.info.comment, "comment");
3464 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3465 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3466 IFSET(SAMR_FIELD_PROFILE_PATH)
3467 SET_STRING(msg, info23.info.profile_path, "profilePath");
3468 IFSET(SAMR_FIELD_WORKSTATIONS)
3469 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3470 IFSET(SAMR_FIELD_LOGON_HOURS)
3471 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3472 IFSET(SAMR_FIELD_ACCT_FLAGS)
3473 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3474 IFSET(SAMR_FIELD_PARAMETERS)
3475 SET_STRING(msg, info23.info.parameters, "userParameters");
3476 IFSET(SAMR_FIELD_COUNTRY_CODE)
3477 SET_UINT (msg, info23.info.country_code, "countryCode");
3478 IFSET(SAMR_FIELD_CODE_PAGE)
3479 SET_UINT (msg, info23.info.code_page, "codePage");
3480 IFSET(SAMR_FIELD_PASSWORD) {
3481 status = samr_set_password(dce_call,
3482 a_state->sam_ctx,
3483 a_state->account_dn,
3484 a_state->domain_state->domain_dn,
3485 mem_ctx, msg,
3486 &r->in.info->info23.password);
3487 } else IFSET(SAMR_FIELD_PASSWORD2) {
3488 status = samr_set_password(dce_call,
3489 a_state->sam_ctx,
3490 a_state->account_dn,
3491 a_state->domain_state->domain_dn,
3492 mem_ctx, msg,
3493 &r->in.info->info23.password);
3495 #undef IFSET
3496 break;
3498 /* the set password levels are handled separately */
3499 case 24:
3500 status = samr_set_password(dce_call,
3501 a_state->sam_ctx,
3502 a_state->account_dn,
3503 a_state->domain_state->domain_dn,
3504 mem_ctx, msg,
3505 &r->in.info->info24.password);
3506 break;
3508 case 25:
3509 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3510 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3511 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3512 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3513 SET_STRING(msg, info25.info.account_name, "samAccountName");
3514 IFSET(SAMR_FIELD_FULL_NAME)
3515 SET_STRING(msg, info25.info.full_name, "displayName");
3516 IFSET(SAMR_FIELD_DESCRIPTION)
3517 SET_STRING(msg, info25.info.description, "description");
3518 IFSET(SAMR_FIELD_COMMENT)
3519 SET_STRING(msg, info25.info.comment, "comment");
3520 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3521 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3522 IFSET(SAMR_FIELD_PROFILE_PATH)
3523 SET_STRING(msg, info25.info.profile_path, "profilePath");
3524 IFSET(SAMR_FIELD_WORKSTATIONS)
3525 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3526 IFSET(SAMR_FIELD_LOGON_HOURS)
3527 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3528 IFSET(SAMR_FIELD_ACCT_FLAGS)
3529 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3530 IFSET(SAMR_FIELD_PARAMETERS)
3531 SET_STRING(msg, info25.info.parameters, "userParameters");
3532 IFSET(SAMR_FIELD_COUNTRY_CODE)
3533 SET_UINT (msg, info25.info.country_code, "countryCode");
3534 IFSET(SAMR_FIELD_CODE_PAGE)
3535 SET_UINT (msg, info25.info.code_page, "codePage");
3536 IFSET(SAMR_FIELD_PASSWORD) {
3537 status = samr_set_password_ex(dce_call,
3538 a_state->sam_ctx,
3539 a_state->account_dn,
3540 a_state->domain_state->domain_dn,
3541 mem_ctx, msg,
3542 &r->in.info->info25.password);
3543 } else IFSET(SAMR_FIELD_PASSWORD2) {
3544 status = samr_set_password_ex(dce_call,
3545 a_state->sam_ctx,
3546 a_state->account_dn,
3547 a_state->domain_state->domain_dn,
3548 mem_ctx, msg,
3549 &r->in.info->info25.password);
3551 #undef IFSET
3552 break;
3554 /* the set password levels are handled separately */
3555 case 26:
3556 status = samr_set_password_ex(dce_call,
3557 a_state->sam_ctx,
3558 a_state->account_dn,
3559 a_state->domain_state->domain_dn,
3560 mem_ctx, msg,
3561 &r->in.info->info26.password);
3562 break;
3565 default:
3566 /* many info classes are not valid for SetUserInfo */
3567 return NT_STATUS_INVALID_INFO_CLASS;
3570 if (!NT_STATUS_IS_OK(status)) {
3571 return status;
3574 /* modify the samdb record */
3575 ret = ldb_modify(a_state->sam_ctx, msg);
3576 if (ret != 0) {
3577 DEBUG(1,("Failed to modify record %s: %s\n",
3578 ldb_dn_get_linearized(a_state->account_dn),
3579 ldb_errstring(a_state->sam_ctx)));
3581 /* we really need samdb.c to return NTSTATUS */
3582 return NT_STATUS_UNSUCCESSFUL;
3585 return NT_STATUS_OK;
3590 samr_GetGroupsForUser
3592 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3593 struct samr_GetGroupsForUser *r)
3595 struct dcesrv_handle *h;
3596 struct samr_account_state *a_state;
3597 struct samr_domain_state *d_state;
3598 struct ldb_message **res;
3599 const char * const attrs[2] = { "objectSid", NULL };
3600 struct samr_RidWithAttributeArray *array;
3601 int count;
3603 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3605 a_state = h->data;
3606 d_state = a_state->domain_state;
3608 count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3609 attrs, d_state->domain_sid,
3610 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3611 ldb_dn_get_linearized(a_state->account_dn),
3612 GTYPE_SECURITY_GLOBAL_GROUP);
3613 if (count < 0)
3614 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3616 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3617 if (array == NULL)
3618 return NT_STATUS_NO_MEMORY;
3620 array->count = 0;
3621 array->rids = NULL;
3623 if (count > 0) {
3624 int i;
3625 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3626 count);
3628 if (array->rids == NULL)
3629 return NT_STATUS_NO_MEMORY;
3631 for (i=0; i<count; i++) {
3632 struct dom_sid *group_sid;
3634 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3635 "objectSid");
3636 if (group_sid == NULL) {
3637 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3638 continue;
3641 array->rids[array->count].rid =
3642 group_sid->sub_auths[group_sid->num_auths-1];
3643 array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3644 array->count += 1;
3648 r->out.rids = array;
3650 return NT_STATUS_OK;
3655 samr_QueryDisplayInfo
3657 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3658 struct samr_QueryDisplayInfo *r)
3660 struct dcesrv_handle *h;
3661 struct samr_domain_state *d_state;
3662 struct ldb_message **res;
3663 int ldb_cnt, count, i;
3664 const char * const attrs[] = { "objectSid", "sAMAccountName", "displayName",
3665 "description", "userAccountControl", "pwdLastSet", NULL };
3666 struct samr_DispEntryFull *entriesFull = NULL;
3667 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3668 struct samr_DispEntryAscii *entriesAscii = NULL;
3669 struct samr_DispEntryGeneral * entriesGeneral = NULL;
3670 const char *filter;
3672 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3674 d_state = h->data;
3676 switch (r->in.level) {
3677 case 1:
3678 case 4:
3679 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3680 "(sAMAccountType=%u))",
3681 ATYPE_NORMAL_ACCOUNT);
3682 break;
3683 case 2:
3684 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3685 "(sAMAccountType=%u))",
3686 ATYPE_WORKSTATION_TRUST);
3687 break;
3688 case 3:
3689 case 5:
3690 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3691 "(objectclass=group))",
3692 GTYPE_SECURITY_GLOBAL_GROUP);
3693 break;
3694 default:
3695 return NT_STATUS_INVALID_INFO_CLASS;
3698 /* search for all requested objects in this domain. This could
3699 possibly be cached and resumed based on resume_key */
3700 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3701 d_state->domain_dn, &res, attrs,
3702 d_state->domain_sid, "%s", filter);
3703 if (ldb_cnt == -1) {
3704 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3706 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3707 return NT_STATUS_OK;
3710 switch (r->in.level) {
3711 case 1:
3712 entriesGeneral = talloc_array(mem_ctx,
3713 struct samr_DispEntryGeneral,
3714 ldb_cnt);
3715 break;
3716 case 2:
3717 entriesFull = talloc_array(mem_ctx,
3718 struct samr_DispEntryFull,
3719 ldb_cnt);
3720 break;
3721 case 3:
3722 entriesFullGroup = talloc_array(mem_ctx,
3723 struct samr_DispEntryFullGroup,
3724 ldb_cnt);
3725 break;
3726 case 4:
3727 case 5:
3728 entriesAscii = talloc_array(mem_ctx,
3729 struct samr_DispEntryAscii,
3730 ldb_cnt);
3731 break;
3734 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3735 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3736 return NT_STATUS_NO_MEMORY;
3738 count = 0;
3740 for (i=0; i<ldb_cnt; i++) {
3741 struct dom_sid *objectsid;
3743 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3744 "objectSid");
3745 if (objectsid == NULL)
3746 continue;
3748 switch(r->in.level) {
3749 case 1:
3750 entriesGeneral[count].idx = count + 1;
3751 entriesGeneral[count].rid =
3752 objectsid->sub_auths[objectsid->num_auths-1];
3753 entriesGeneral[count].acct_flags =
3754 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3755 res[i],
3756 d_state->domain_dn);
3757 entriesGeneral[count].account_name.string =
3758 samdb_result_string(res[i],
3759 "sAMAccountName", "");
3760 entriesGeneral[count].full_name.string =
3761 samdb_result_string(res[i], "displayName", "");
3762 entriesGeneral[count].description.string =
3763 samdb_result_string(res[i], "description", "");
3764 break;
3765 case 2:
3766 entriesFull[count].idx = count + 1;
3767 entriesFull[count].rid =
3768 objectsid->sub_auths[objectsid->num_auths-1];
3770 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3771 entriesFull[count].acct_flags =
3772 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3773 res[i],
3774 d_state->domain_dn) | ACB_NORMAL;
3775 entriesFull[count].account_name.string =
3776 samdb_result_string(res[i], "sAMAccountName",
3777 "");
3778 entriesFull[count].description.string =
3779 samdb_result_string(res[i], "description", "");
3780 break;
3781 case 3:
3782 entriesFullGroup[count].idx = count + 1;
3783 entriesFullGroup[count].rid =
3784 objectsid->sub_auths[objectsid->num_auths-1];
3785 /* We get a "7" here for groups */
3786 entriesFullGroup[count].acct_flags
3787 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3788 entriesFullGroup[count].account_name.string =
3789 samdb_result_string(res[i], "sAMAccountName",
3790 "");
3791 entriesFullGroup[count].description.string =
3792 samdb_result_string(res[i], "description", "");
3793 break;
3794 case 4:
3795 case 5:
3796 entriesAscii[count].idx = count + 1;
3797 entriesAscii[count].account_name.string =
3798 samdb_result_string(res[i], "sAMAccountName",
3799 "");
3800 break;
3803 count += 1;
3806 r->out.total_size = count;
3808 if (r->in.start_idx >= count) {
3809 r->out.returned_size = 0;
3810 switch(r->in.level) {
3811 case 1:
3812 r->out.info.info1.count = r->out.returned_size;
3813 r->out.info.info1.entries = NULL;
3814 break;
3815 case 2:
3816 r->out.info.info2.count = r->out.returned_size;
3817 r->out.info.info2.entries = NULL;
3818 break;
3819 case 3:
3820 r->out.info.info3.count = r->out.returned_size;
3821 r->out.info.info3.entries = NULL;
3822 break;
3823 case 4:
3824 r->out.info.info4.count = r->out.returned_size;
3825 r->out.info.info4.entries = NULL;
3826 break;
3827 case 5:
3828 r->out.info.info5.count = r->out.returned_size;
3829 r->out.info.info5.entries = NULL;
3830 break;
3832 } else {
3833 r->out.returned_size = MIN(count - r->in.start_idx,
3834 r->in.max_entries);
3835 switch(r->in.level) {
3836 case 1:
3837 r->out.info.info1.count = r->out.returned_size;
3838 r->out.info.info1.entries =
3839 &(entriesGeneral[r->in.start_idx]);
3840 break;
3841 case 2:
3842 r->out.info.info2.count = r->out.returned_size;
3843 r->out.info.info2.entries =
3844 &(entriesFull[r->in.start_idx]);
3845 break;
3846 case 3:
3847 r->out.info.info3.count = r->out.returned_size;
3848 r->out.info.info3.entries =
3849 &(entriesFullGroup[r->in.start_idx]);
3850 break;
3851 case 4:
3852 r->out.info.info4.count = r->out.returned_size;
3853 r->out.info.info4.entries =
3854 &(entriesAscii[r->in.start_idx]);
3855 break;
3856 case 5:
3857 r->out.info.info5.count = r->out.returned_size;
3858 r->out.info.info5.entries =
3859 &(entriesAscii[r->in.start_idx]);
3860 break;
3864 return (r->out.returned_size < (count - r->in.start_idx)) ?
3865 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3870 samr_GetDisplayEnumerationIndex
3872 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3873 struct samr_GetDisplayEnumerationIndex *r)
3875 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3880 samr_TestPrivateFunctionsDomain
3882 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3883 struct samr_TestPrivateFunctionsDomain *r)
3885 return NT_STATUS_NOT_IMPLEMENTED;
3890 samr_TestPrivateFunctionsUser
3892 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3893 struct samr_TestPrivateFunctionsUser *r)
3895 return NT_STATUS_NOT_IMPLEMENTED;
3900 samr_GetUserPwInfo
3902 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3903 struct samr_GetUserPwInfo *r)
3905 struct dcesrv_handle *h;
3906 struct samr_account_state *a_state;
3908 ZERO_STRUCT(r->out.info);
3910 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3912 a_state = h->data;
3914 r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3915 a_state->domain_state->domain_dn, "minPwdLength",
3916 NULL);
3917 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3918 a_state->account_dn,
3919 "pwdProperties", NULL);
3920 return NT_STATUS_OK;
3925 samr_RemoveMemberFromForeignDomain
3927 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3928 struct samr_RemoveMemberFromForeignDomain *r)
3930 struct dcesrv_handle *h;
3931 struct samr_domain_state *d_state;
3932 const char *memberdn;
3933 struct ldb_message **res;
3934 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3935 int i, count;
3937 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3939 d_state = h->data;
3941 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3942 "distinguishedName", "(objectSid=%s)",
3943 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3944 /* Nothing to do */
3945 if (memberdn == NULL) {
3946 return NT_STATUS_OK;
3949 /* TODO: Does this call only remove alias members, or does it do this
3950 * for domain groups as well? */
3952 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3953 d_state->domain_dn, &res, attrs,
3954 d_state->domain_sid,
3955 "(&(member=%s)(objectClass=group)"
3956 "(|(groupType=%d)(groupType=%d)))",
3957 memberdn,
3958 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3959 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3961 if (count < 0)
3962 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3964 for (i=0; i<count; i++) {
3965 struct ldb_message *mod;
3967 mod = ldb_msg_new(mem_ctx);
3968 if (mod == NULL) {
3969 return NT_STATUS_NO_MEMORY;
3972 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
3973 if (mod->dn == NULL) {
3974 talloc_free(mod);
3975 continue;
3978 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3979 "member", memberdn) != 0)
3980 return NT_STATUS_NO_MEMORY;
3982 if (ldb_modify(d_state->sam_ctx, mod) != 0)
3983 return NT_STATUS_UNSUCCESSFUL;
3985 talloc_free(mod);
3988 return NT_STATUS_OK;
3993 samr_QueryDomainInfo2
3995 just an alias for samr_QueryDomainInfo
3997 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3998 struct samr_QueryDomainInfo2 *r)
4000 struct samr_QueryDomainInfo r1;
4001 NTSTATUS status;
4003 ZERO_STRUCT(r1.out);
4004 r1.in.domain_handle = r->in.domain_handle;
4005 r1.in.level = r->in.level;
4007 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4009 r->out.info = r1.out.info;
4011 return status;
4016 samr_QueryUserInfo2
4018 just an alias for samr_QueryUserInfo
4020 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4021 struct samr_QueryUserInfo2 *r)
4023 struct samr_QueryUserInfo r1;
4024 NTSTATUS status;
4026 ZERO_STRUCT(r1.out);
4027 r1.in.user_handle = r->in.user_handle;
4028 r1.in.level = r->in.level;
4030 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4032 r->out.info = r1.out.info;
4034 return status;
4039 samr_QueryDisplayInfo2
4041 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4042 struct samr_QueryDisplayInfo2 *r)
4044 struct samr_QueryDisplayInfo q;
4045 NTSTATUS result;
4047 q.in.domain_handle = r->in.domain_handle;
4048 q.in.level = r->in.level;
4049 q.in.start_idx = r->in.start_idx;
4050 q.in.max_entries = r->in.max_entries;
4051 q.in.buf_size = r->in.buf_size;
4052 ZERO_STRUCT(q.out);
4054 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4056 r->out.total_size = q.out.total_size;
4057 r->out.returned_size = q.out.returned_size;
4058 r->out.info = q.out.info;
4060 return result;
4065 samr_GetDisplayEnumerationIndex2
4067 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4068 struct samr_GetDisplayEnumerationIndex2 *r)
4070 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4075 samr_QueryDisplayInfo3
4077 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4078 struct samr_QueryDisplayInfo3 *r)
4080 struct samr_QueryDisplayInfo q;
4081 NTSTATUS result;
4083 q.in.domain_handle = r->in.domain_handle;
4084 q.in.level = r->in.level;
4085 q.in.start_idx = r->in.start_idx;
4086 q.in.max_entries = r->in.max_entries;
4087 q.in.buf_size = r->in.buf_size;
4088 ZERO_STRUCT(q.out);
4090 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4092 r->out.total_size = q.out.total_size;
4093 r->out.returned_size = q.out.returned_size;
4094 r->out.info = q.out.info;
4096 return result;
4101 samr_AddMultipleMembersToAlias
4103 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4104 struct samr_AddMultipleMembersToAlias *r)
4106 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4111 samr_RemoveMultipleMembersFromAlias
4113 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4114 struct samr_RemoveMultipleMembersFromAlias *r)
4116 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4121 samr_GetDomPwInfo
4123 this fetches the default password properties for a domain
4125 note that w2k3 completely ignores the domain name in this call, and
4126 always returns the information for the servers primary domain
4128 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4129 struct samr_GetDomPwInfo *r)
4131 struct ldb_message **msgs;
4132 int ret;
4133 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4134 struct ldb_context *sam_ctx;
4136 ZERO_STRUCT(r->out.info);
4138 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
4139 if (sam_ctx == NULL) {
4140 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4143 /* The domain name in this call is ignored */
4144 ret = gendb_search_dn(sam_ctx,
4145 mem_ctx, NULL, &msgs, attrs);
4146 if (ret <= 0) {
4147 return NT_STATUS_NO_SUCH_DOMAIN;
4149 if (ret > 1) {
4150 talloc_free(msgs);
4151 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4154 r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
4155 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
4157 talloc_free(msgs);
4159 talloc_free(sam_ctx);
4160 return NT_STATUS_OK;
4165 samr_Connect2
4167 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4168 struct samr_Connect2 *r)
4170 struct samr_Connect c;
4172 c.in.system_name = NULL;
4173 c.in.access_mask = r->in.access_mask;
4174 c.out.connect_handle = r->out.connect_handle;
4176 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4181 samr_SetUserInfo2
4183 just an alias for samr_SetUserInfo
4185 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4186 struct samr_SetUserInfo2 *r)
4188 struct samr_SetUserInfo r2;
4190 r2.in.user_handle = r->in.user_handle;
4191 r2.in.level = r->in.level;
4192 r2.in.info = r->in.info;
4194 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4199 samr_SetBootKeyInformation
4201 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4202 struct samr_SetBootKeyInformation *r)
4204 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4209 samr_GetBootKeyInformation
4211 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4212 struct samr_GetBootKeyInformation *r)
4214 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4219 samr_Connect3
4221 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4222 struct samr_Connect3 *r)
4224 struct samr_Connect c;
4226 c.in.system_name = NULL;
4227 c.in.access_mask = r->in.access_mask;
4228 c.out.connect_handle = r->out.connect_handle;
4230 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4235 samr_Connect4
4237 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4238 struct samr_Connect4 *r)
4240 struct samr_Connect c;
4242 c.in.system_name = NULL;
4243 c.in.access_mask = r->in.access_mask;
4244 c.out.connect_handle = r->out.connect_handle;
4246 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4251 samr_Connect5
4253 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4254 struct samr_Connect5 *r)
4256 struct samr_Connect c;
4257 NTSTATUS status;
4259 c.in.system_name = NULL;
4260 c.in.access_mask = r->in.access_mask;
4261 c.out.connect_handle = r->out.connect_handle;
4263 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4265 r->out.info->info1.unknown1 = 3;
4266 r->out.info->info1.unknown2 = 0;
4267 r->out.level = r->in.level;
4269 return status;
4274 samr_RidToSid
4276 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4277 struct samr_RidToSid *r)
4279 struct samr_domain_state *d_state;
4280 struct dcesrv_handle *h;
4282 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4284 d_state = h->data;
4286 /* form the users SID */
4287 r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4288 if (!r->out.sid) {
4289 return NT_STATUS_NO_MEMORY;
4292 return NT_STATUS_OK;
4297 samr_SetDsrmPassword
4299 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4300 struct samr_SetDsrmPassword *r)
4302 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4307 samr_ValidatePassword
4309 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4310 struct samr_ValidatePassword *r)
4312 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4316 /* include the generated boilerplate */
4317 #include "librpc/gen_ndr/ndr_samr_s.c"