Revert "s4:remove "util_ldb" submodule and integrate the three gendb_* calls in ...
[Samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
blobac75b417f92c14f4d97538a830212fc346246d43
1 /*
2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
43 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
45 #define QUERY_STRING(msg, field, attr) \
46 info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
47 #define QUERY_UINT(msg, field, attr) \
48 info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
49 #define QUERY_RID(msg, field, attr) \
50 info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
51 #define QUERY_UINT64(msg, field, attr) \
52 info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
53 #define QUERY_APASSC(msg, field, attr) \
54 info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
55 a_state->domain_state->domain_dn, msg, attr);
56 #define QUERY_FPASSC(msg, field, attr) \
57 info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
58 a_state->domain_state->domain_dn, msg);
59 #define QUERY_LHOURS(msg, field, attr) \
60 info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
61 #define QUERY_AFLAGS(msg, field, attr) \
62 info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
63 #define QUERY_PARAMETERS(msg, field, attr) \
64 info->field = samdb_result_parameters(mem_ctx, msg, attr);
67 /* these are used to make the Set[User|Group]Info code easier to follow */
69 #define SET_STRING(msg, field, attr) do { \
70 struct ldb_message_element *set_el; \
71 if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
72 if (r->in.info->field.string[0] == '\0') { \
73 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
74 return NT_STATUS_NO_MEMORY; \
75 } \
76 } \
77 if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
78 return NT_STATUS_NO_MEMORY; \
79 } \
80 set_el = ldb_msg_find_element(msg, attr); \
81 set_el->flags = LDB_FLAG_MOD_REPLACE; \
82 } while (0)
84 #define SET_UINT(msg, field, attr) do { \
85 struct ldb_message_element *set_el; \
86 if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
87 return NT_STATUS_NO_MEMORY; \
88 } \
89 set_el = ldb_msg_find_element(msg, attr); \
90 set_el->flags = LDB_FLAG_MOD_REPLACE; \
91 } while (0)
93 #define SET_INT64(msg, field, attr) do { \
94 struct ldb_message_element *set_el; \
95 if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
96 return NT_STATUS_NO_MEMORY; \
97 } \
98 set_el = ldb_msg_find_element(msg, attr); \
99 set_el->flags = LDB_FLAG_MOD_REPLACE; \
100 } while (0)
102 #define SET_UINT64(msg, field, attr) do { \
103 struct ldb_message_element *set_el; \
104 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
105 return NT_STATUS_NO_MEMORY; \
107 set_el = ldb_msg_find_element(msg, attr); \
108 set_el->flags = LDB_FLAG_MOD_REPLACE; \
109 } while (0)
111 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags) \
112 do { \
113 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
114 return NT_STATUS_INVALID_PARAMETER; \
116 } while (0) \
118 /* Set account flags, discarding flags that cannot be set with SAMR */
119 #define SET_AFLAGS(msg, field, attr) do { \
120 struct ldb_message_element *set_el; \
121 if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
122 return NT_STATUS_INVALID_PARAMETER; \
124 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127 CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
128 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
129 return NT_STATUS_NO_MEMORY; \
131 set_el = ldb_msg_find_element(msg, attr); \
132 set_el->flags = LDB_FLAG_MOD_REPLACE; \
133 } while (0)
135 #define SET_LHOURS(msg, field, attr) do { \
136 struct ldb_message_element *set_el; \
137 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
138 return NT_STATUS_NO_MEMORY; \
140 set_el = ldb_msg_find_element(msg, attr); \
141 set_el->flags = LDB_FLAG_MOD_REPLACE; \
142 } while (0)
144 #define SET_PARAMETERS(msg, field, attr) do { \
145 struct ldb_message_element *set_el; \
146 if (r->in.info->field.length != 0) { \
147 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
148 return NT_STATUS_NO_MEMORY; \
150 set_el = ldb_msg_find_element(msg, attr); \
151 set_el->flags = LDB_FLAG_MOD_REPLACE; \
153 } while (0)
158 samr_Connect
160 create a connection to the SAM database
162 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
163 struct samr_Connect *r)
165 struct samr_connect_state *c_state;
166 struct dcesrv_handle *handle;
168 ZERO_STRUCTP(r->out.connect_handle);
170 c_state = talloc(mem_ctx, struct samr_connect_state);
171 if (!c_state) {
172 return NT_STATUS_NO_MEMORY;
175 /* make sure the sam database is accessible */
176 c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0);
177 if (c_state->sam_ctx == NULL) {
178 talloc_free(c_state);
179 return NT_STATUS_INVALID_SYSTEM_SERVICE;
183 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
184 if (!handle) {
185 talloc_free(c_state);
186 return NT_STATUS_NO_MEMORY;
189 handle->data = talloc_steal(handle, c_state);
191 c_state->access_mask = r->in.access_mask;
192 *r->out.connect_handle = handle->wire_handle;
194 return NT_STATUS_OK;
199 samr_Close
201 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
202 struct samr_Close *r)
204 struct dcesrv_handle *h;
206 *r->out.handle = *r->in.handle;
208 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
210 talloc_free(h);
212 ZERO_STRUCTP(r->out.handle);
214 return NT_STATUS_OK;
219 samr_SetSecurity
221 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
222 struct samr_SetSecurity *r)
224 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
229 samr_QuerySecurity
231 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
232 struct samr_QuerySecurity *r)
234 struct dcesrv_handle *h;
235 struct sec_desc_buf *sd;
237 *r->out.sdbuf = NULL;
239 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
241 sd = talloc(mem_ctx, struct sec_desc_buf);
242 if (sd == NULL) {
243 return NT_STATUS_NO_MEMORY;
246 sd->sd = samdb_default_security_descriptor(mem_ctx);
248 *r->out.sdbuf = sd;
250 return NT_STATUS_OK;
255 samr_Shutdown
257 we refuse this operation completely. If a admin wants to shutdown samr
258 in Samba then they should use the samba admin tools to disable the samr pipe
260 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
261 struct samr_Shutdown *r)
263 return NT_STATUS_ACCESS_DENIED;
268 samr_LookupDomain
270 this maps from a domain name to a SID
272 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
273 struct samr_LookupDomain *r)
275 struct samr_connect_state *c_state;
276 struct dcesrv_handle *h;
277 struct dom_sid *sid;
278 const char * const dom_attrs[] = { "objectSid", NULL};
279 struct ldb_message **dom_msgs;
280 int ret;
282 *r->out.sid = NULL;
284 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
286 c_state = h->data;
288 if (r->in.domain_name->string == NULL) {
289 return NT_STATUS_INVALID_PARAMETER;
292 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
293 ret = gendb_search(c_state->sam_ctx,
294 mem_ctx, NULL, &dom_msgs, dom_attrs,
295 "(objectClass=builtinDomain)");
296 } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
297 ret = gendb_search_dn(c_state->sam_ctx,
298 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
299 &dom_msgs, dom_attrs);
300 } else {
301 return NT_STATUS_NO_SUCH_DOMAIN;
303 if (ret != 1) {
304 return NT_STATUS_NO_SUCH_DOMAIN;
307 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
308 "objectSid");
310 if (sid == NULL) {
311 return NT_STATUS_NO_SUCH_DOMAIN;
314 *r->out.sid = sid;
316 return NT_STATUS_OK;
321 samr_EnumDomains
323 list the domains in the SAM
325 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
326 struct samr_EnumDomains *r)
328 struct samr_connect_state *c_state;
329 struct dcesrv_handle *h;
330 struct samr_SamArray *array;
331 uint32_t i, start_i;
333 *r->out.resume_handle = 0;
334 *r->out.sam = NULL;
335 *r->out.num_entries = 0;
337 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
339 c_state = h->data;
341 *r->out.resume_handle = 2;
343 start_i = *r->in.resume_handle;
345 if (start_i >= 2) {
346 /* search past end of list is not an error for this call */
347 return NT_STATUS_OK;
350 array = talloc(mem_ctx, struct samr_SamArray);
351 if (array == NULL) {
352 return NT_STATUS_NO_MEMORY;
355 array->count = 0;
356 array->entries = NULL;
358 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
359 if (array->entries == NULL) {
360 return NT_STATUS_NO_MEMORY;
363 for (i=0;i<2-start_i;i++) {
364 array->entries[i].idx = start_i + i;
365 if (i == 0) {
366 array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
367 } else {
368 array->entries[i].name.string = "BUILTIN";
372 *r->out.sam = array;
373 *r->out.num_entries = i;
374 array->count = *r->out.num_entries;
376 return NT_STATUS_OK;
381 samr_OpenDomain
383 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
384 struct samr_OpenDomain *r)
386 struct dcesrv_handle *h_conn, *h_domain;
387 struct samr_connect_state *c_state;
388 struct samr_domain_state *d_state;
389 const char * const dom_attrs[] = { "cn", NULL};
390 struct ldb_message **dom_msgs;
391 int ret;
393 ZERO_STRUCTP(r->out.domain_handle);
395 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
397 c_state = h_conn->data;
399 if (r->in.sid == NULL) {
400 return NT_STATUS_INVALID_PARAMETER;
403 d_state = talloc(mem_ctx, struct samr_domain_state);
404 if (!d_state) {
405 return NT_STATUS_NO_MEMORY;
408 d_state->domain_sid = talloc_steal(d_state, r->in.sid);
410 if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
411 d_state->builtin = true;
412 d_state->domain_name = "BUILTIN";
413 } else {
414 d_state->builtin = false;
415 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
418 ret = gendb_search(c_state->sam_ctx,
419 mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
420 "(objectSid=%s)",
421 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
423 if (ret == 0) {
424 talloc_free(d_state);
425 return NT_STATUS_NO_SUCH_DOMAIN;
426 } else if (ret > 1) {
427 talloc_free(d_state);
428 return NT_STATUS_INTERNAL_DB_CORRUPTION;
429 } else if (ret == -1) {
430 talloc_free(d_state);
431 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
432 return NT_STATUS_INTERNAL_DB_CORRUPTION;
435 d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
436 d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
437 d_state->connect_state = talloc_reference(d_state, c_state);
438 d_state->sam_ctx = c_state->sam_ctx;
439 d_state->access_mask = r->in.access_mask;
441 d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
443 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
444 if (!h_domain) {
445 talloc_free(d_state);
446 return NT_STATUS_NO_MEMORY;
449 h_domain->data = talloc_steal(h_domain, d_state);
451 *r->out.domain_handle = h_domain->wire_handle;
453 return NT_STATUS_OK;
457 return DomInfo1
459 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
460 TALLOC_CTX *mem_ctx,
461 struct ldb_message **dom_msgs,
462 struct samr_DomInfo1 *info)
464 info->min_password_length =
465 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
466 info->password_history_length =
467 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
468 info->password_properties =
469 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
470 info->max_password_age =
471 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
472 info->min_password_age =
473 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
475 return NT_STATUS_OK;
479 return DomInfo2
481 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
482 TALLOC_CTX *mem_ctx,
483 struct ldb_message **dom_msgs,
484 struct samr_DomGeneralInformation *info)
486 /* This pulls the NetBIOS name from the
487 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
488 string */
489 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
491 if (!info->primary.string) {
492 info->primary.string = lpcfg_netbios_name(state->lp_ctx);
495 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
496 0x8000000000000000LL);
498 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0], "oEMInformation", NULL);
499 info->domain_name.string = state->domain_name;
501 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
503 switch (state->role) {
504 case ROLE_DOMAIN_CONTROLLER:
505 /* This pulls the NetBIOS name from the
506 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
507 string */
508 if (samdb_is_pdc(state->sam_ctx)) {
509 info->role = SAMR_ROLE_DOMAIN_PDC;
510 } else {
511 info->role = SAMR_ROLE_DOMAIN_BDC;
513 break;
514 case ROLE_DOMAIN_MEMBER:
515 info->role = SAMR_ROLE_DOMAIN_MEMBER;
516 break;
517 case ROLE_STANDALONE:
518 info->role = SAMR_ROLE_STANDALONE;
519 break;
522 /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
523 info->num_users = samdb_search_count(state->sam_ctx, state->domain_dn,
524 "(objectClass=user)");
525 info->num_groups = samdb_search_count(state->sam_ctx, state->domain_dn,
526 "(&(objectClass=group)(groupType=%u))",
527 GTYPE_SECURITY_GLOBAL_GROUP);
528 info->num_aliases = samdb_search_count(state->sam_ctx, state->domain_dn,
529 "(&(objectClass=group)(groupType=%u))",
530 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
532 return NT_STATUS_OK;
536 return DomInfo3
538 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
539 TALLOC_CTX *mem_ctx,
540 struct ldb_message **dom_msgs,
541 struct samr_DomInfo3 *info)
543 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
544 0x8000000000000000LL);
546 return NT_STATUS_OK;
550 return DomInfo4
552 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
553 TALLOC_CTX *mem_ctx,
554 struct ldb_message **dom_msgs,
555 struct samr_DomOEMInformation *info)
557 info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0], "oEMInformation", NULL);
559 return NT_STATUS_OK;
563 return DomInfo5
565 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
566 TALLOC_CTX *mem_ctx,
567 struct ldb_message **dom_msgs,
568 struct samr_DomInfo5 *info)
570 info->domain_name.string = state->domain_name;
572 return NT_STATUS_OK;
576 return DomInfo6
578 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
579 TALLOC_CTX *mem_ctx,
580 struct ldb_message **dom_msgs,
581 struct samr_DomInfo6 *info)
583 /* This pulls the NetBIOS name from the
584 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
585 string */
586 info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx,
587 dom_msgs[0], "fSMORoleOwner");
589 if (!info->primary.string) {
590 info->primary.string = lpcfg_netbios_name(state->lp_ctx);
593 return NT_STATUS_OK;
597 return DomInfo7
599 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
600 TALLOC_CTX *mem_ctx,
601 struct ldb_message **dom_msgs,
602 struct samr_DomInfo7 *info)
605 switch (state->role) {
606 case ROLE_DOMAIN_CONTROLLER:
607 /* This pulls the NetBIOS name from the
608 cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
609 string */
610 if (samdb_is_pdc(state->sam_ctx)) {
611 info->role = SAMR_ROLE_DOMAIN_PDC;
612 } else {
613 info->role = SAMR_ROLE_DOMAIN_BDC;
615 break;
616 case ROLE_DOMAIN_MEMBER:
617 info->role = SAMR_ROLE_DOMAIN_MEMBER;
618 break;
619 case ROLE_STANDALONE:
620 info->role = SAMR_ROLE_STANDALONE;
621 break;
624 return NT_STATUS_OK;
628 return DomInfo8
630 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
631 TALLOC_CTX *mem_ctx,
632 struct ldb_message **dom_msgs,
633 struct samr_DomInfo8 *info)
635 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
636 time(NULL));
638 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
639 0x0LL);
641 return NT_STATUS_OK;
645 return DomInfo9
647 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
648 TALLOC_CTX *mem_ctx,
649 struct ldb_message **dom_msgs,
650 struct samr_DomInfo9 *info)
652 info->domain_server_state = DOMAIN_SERVER_ENABLED;
654 return NT_STATUS_OK;
658 return DomInfo11
660 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
661 TALLOC_CTX *mem_ctx,
662 struct ldb_message **dom_msgs,
663 struct samr_DomGeneralInformation2 *info)
665 NTSTATUS status;
666 status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
667 if (!NT_STATUS_IS_OK(status)) {
668 return status;
671 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
672 -18000000000LL);
673 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
674 -18000000000LL);
675 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
677 return NT_STATUS_OK;
681 return DomInfo12
683 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
684 TALLOC_CTX *mem_ctx,
685 struct ldb_message **dom_msgs,
686 struct samr_DomInfo12 *info)
688 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
689 -18000000000LL);
690 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
691 -18000000000LL);
692 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
694 return NT_STATUS_OK;
698 return DomInfo13
700 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
701 TALLOC_CTX *mem_ctx,
702 struct ldb_message **dom_msgs,
703 struct samr_DomInfo13 *info)
705 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
706 time(NULL));
708 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
709 0x0LL);
711 info->modified_count_at_last_promotion = 0;
713 return NT_STATUS_OK;
717 samr_QueryDomainInfo
719 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
720 struct samr_QueryDomainInfo *r)
722 struct dcesrv_handle *h;
723 struct samr_domain_state *d_state;
724 union samr_DomainInfo *info;
726 struct ldb_message **dom_msgs;
727 const char * const *attrs = NULL;
729 *r->out.info = NULL;
731 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
733 d_state = h->data;
735 switch (r->in.level) {
736 case 1:
738 static const char * const attrs2[] = { "minPwdLength",
739 "pwdHistoryLength",
740 "pwdProperties",
741 "maxPwdAge",
742 "minPwdAge",
743 NULL };
744 attrs = attrs2;
745 break;
747 case 2:
749 static const char * const attrs2[] = {"forceLogoff",
750 "oEMInformation",
751 "modifiedCount",
752 "fSMORoleOwner",
753 NULL};
754 attrs = attrs2;
755 break;
757 case 3:
759 static const char * const attrs2[] = {"forceLogoff",
760 NULL};
761 attrs = attrs2;
762 break;
764 case 4:
766 static const char * const attrs2[] = {"oEMInformation",
767 NULL};
768 attrs = attrs2;
769 break;
771 case 5:
773 attrs = NULL;
774 break;
776 case 6:
778 static const char * const attrs2[] = {"fSMORoleOwner",
779 NULL};
780 attrs = attrs2;
781 break;
783 case 7:
785 attrs = NULL;
786 break;
788 case 8:
790 static const char * const attrs2[] = { "modifiedCount",
791 "creationTime",
792 NULL };
793 attrs = attrs2;
794 break;
796 case 9:
798 attrs = NULL;
799 break;
801 case 11:
803 static const char * const attrs2[] = { "oEMInformation",
804 "forceLogoff",
805 "modifiedCount",
806 "lockoutDuration",
807 "lockOutObservationWindow",
808 "lockoutThreshold",
809 NULL};
810 attrs = attrs2;
811 break;
813 case 12:
815 static const char * const attrs2[] = { "lockoutDuration",
816 "lockOutObservationWindow",
817 "lockoutThreshold",
818 NULL};
819 attrs = attrs2;
820 break;
822 case 13:
824 static const char * const attrs2[] = { "modifiedCount",
825 "creationTime",
826 NULL };
827 attrs = attrs2;
828 break;
830 default:
832 return NT_STATUS_INVALID_INFO_CLASS;
836 /* some levels don't need a search */
837 if (attrs) {
838 int ret;
839 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
840 d_state->domain_dn, &dom_msgs, attrs);
841 if (ret == 0) {
842 return NT_STATUS_NO_SUCH_DOMAIN;
844 if (ret != 1) {
845 return NT_STATUS_INTERNAL_DB_CORRUPTION;
849 /* allocate the info structure */
850 info = talloc_zero(mem_ctx, union samr_DomainInfo);
851 if (info == NULL) {
852 return NT_STATUS_NO_MEMORY;
855 *r->out.info = info;
857 switch (r->in.level) {
858 case 1:
859 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
860 &info->info1);
861 case 2:
862 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
863 &info->general);
864 case 3:
865 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
866 &info->info3);
867 case 4:
868 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
869 &info->oem);
870 case 5:
871 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
872 &info->info5);
873 case 6:
874 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
875 &info->info6);
876 case 7:
877 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
878 &info->info7);
879 case 8:
880 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
881 &info->info8);
882 case 9:
883 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
884 &info->info9);
885 case 11:
886 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
887 &info->general2);
888 case 12:
889 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
890 &info->info12);
891 case 13:
892 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
893 &info->info13);
894 default:
895 return NT_STATUS_INVALID_INFO_CLASS;
901 samr_SetDomainInfo
903 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
904 struct samr_SetDomainInfo *r)
906 struct dcesrv_handle *h;
907 struct samr_domain_state *d_state;
908 struct ldb_message *msg;
909 int ret;
910 struct ldb_context *sam_ctx;
912 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
914 d_state = h->data;
915 sam_ctx = d_state->sam_ctx;
917 msg = ldb_msg_new(mem_ctx);
918 if (msg == NULL) {
919 return NT_STATUS_NO_MEMORY;
922 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
923 if (!msg->dn) {
924 return NT_STATUS_NO_MEMORY;
927 switch (r->in.level) {
928 case 1:
929 SET_UINT (msg, info1.min_password_length, "minPwdLength");
930 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
931 SET_UINT (msg, info1.password_properties, "pwdProperties");
932 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
933 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
934 break;
935 case 3:
936 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
937 break;
938 case 4:
939 SET_STRING(msg, oem.oem_information, "oEMInformation");
940 break;
942 case 6:
943 case 7:
944 case 9:
945 /* No op, we don't know where to set these */
946 return NT_STATUS_OK;
948 case 12:
950 * It is not possible to set lockout_duration < lockout_window.
951 * (The test is the other way around since the negative numbers
952 * are stored...)
954 * TODO:
955 * This check should be moved to the backend, i.e. to some
956 * ldb module under dsdb/samdb/ldb_modules/ .
958 * This constraint is documented here for the samr rpc service:
959 * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
960 * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
962 * And here for the ldap backend:
963 * MS-ADTS 3.1.1.5.3.2 Constraints
964 * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
966 if (r->in.info->info12.lockout_duration >
967 r->in.info->info12.lockout_window)
969 return NT_STATUS_INVALID_PARAMETER;
971 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
972 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
973 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
974 break;
976 default:
977 /* many info classes are not valid for SetDomainInfo */
978 return NT_STATUS_INVALID_INFO_CLASS;
981 /* modify the samdb record */
982 ret = ldb_modify(sam_ctx, msg);
983 if (ret != LDB_SUCCESS) {
984 DEBUG(1,("Failed to modify record %s: %s\n",
985 ldb_dn_get_linearized(d_state->domain_dn),
986 ldb_errstring(sam_ctx)));
988 /* we really need samdb.c to return NTSTATUS */
989 return NT_STATUS_UNSUCCESSFUL;
992 return NT_STATUS_OK;
996 samr_CreateDomainGroup
998 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
999 struct samr_CreateDomainGroup *r)
1001 NTSTATUS status;
1002 struct samr_domain_state *d_state;
1003 struct samr_account_state *a_state;
1004 struct dcesrv_handle *h;
1005 const char *groupname;
1006 struct dom_sid *group_sid;
1007 struct ldb_dn *group_dn;
1008 struct dcesrv_handle *g_handle;
1010 ZERO_STRUCTP(r->out.group_handle);
1011 *r->out.rid = 0;
1013 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1015 d_state = h->data;
1017 if (d_state->builtin) {
1018 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1019 return NT_STATUS_ACCESS_DENIED;
1022 groupname = r->in.name->string;
1024 if (groupname == NULL) {
1025 return NT_STATUS_INVALID_PARAMETER;
1028 status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1029 if (!NT_STATUS_IS_OK(status)) {
1030 return status;
1033 a_state = talloc(mem_ctx, struct samr_account_state);
1034 if (!a_state) {
1035 return NT_STATUS_NO_MEMORY;
1037 a_state->sam_ctx = d_state->sam_ctx;
1038 a_state->access_mask = r->in.access_mask;
1039 a_state->domain_state = talloc_reference(a_state, d_state);
1040 a_state->account_dn = talloc_steal(a_state, group_dn);
1042 a_state->account_name = talloc_steal(a_state, groupname);
1044 /* create the policy handle */
1045 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1046 if (!g_handle) {
1047 return NT_STATUS_NO_MEMORY;
1050 g_handle->data = talloc_steal(g_handle, a_state);
1052 *r->out.group_handle = g_handle->wire_handle;
1053 *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1055 return NT_STATUS_OK;
1060 comparison function for sorting SamEntry array
1062 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1064 return e1->idx - e2->idx;
1068 samr_EnumDomainGroups
1070 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1071 struct samr_EnumDomainGroups *r)
1073 struct dcesrv_handle *h;
1074 struct samr_domain_state *d_state;
1075 struct ldb_message **res;
1076 int i, ldb_cnt;
1077 uint32_t first, count;
1078 struct samr_SamEntry *entries;
1079 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1080 struct samr_SamArray *sam;
1082 *r->out.resume_handle = 0;
1083 *r->out.sam = NULL;
1084 *r->out.num_entries = 0;
1086 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1088 d_state = h->data;
1090 /* search for all domain groups in this domain. This could possibly be
1091 cached and resumed based on resume_key */
1092 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1093 d_state->domain_dn, &res, attrs,
1094 d_state->domain_sid,
1095 "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1096 GTYPE_SECURITY_UNIVERSAL_GROUP,
1097 GTYPE_SECURITY_GLOBAL_GROUP);
1098 if (ldb_cnt < 0) {
1099 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1102 /* convert to SamEntry format */
1103 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1104 if (!entries) {
1105 return NT_STATUS_NO_MEMORY;
1108 count = 0;
1110 for (i=0;i<ldb_cnt;i++) {
1111 struct dom_sid *group_sid;
1113 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1114 "objectSid");
1115 if (group_sid == NULL) {
1116 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1119 entries[count].idx =
1120 group_sid->sub_auths[group_sid->num_auths-1];
1121 entries[count].name.string =
1122 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1123 count += 1;
1126 /* sort the results by rid */
1127 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1129 /* find the first entry to return */
1130 for (first=0;
1131 first<count && entries[first].idx <= *r->in.resume_handle;
1132 first++) ;
1134 /* return the rest, limit by max_size. Note that we
1135 use the w2k3 element size value of 54 */
1136 *r->out.num_entries = count - first;
1137 *r->out.num_entries = MIN(*r->out.num_entries,
1138 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1140 sam = talloc(mem_ctx, struct samr_SamArray);
1141 if (!sam) {
1142 return NT_STATUS_NO_MEMORY;
1145 sam->entries = entries+first;
1146 sam->count = *r->out.num_entries;
1148 *r->out.sam = sam;
1150 if (first == count) {
1151 return NT_STATUS_OK;
1154 if (*r->out.num_entries < count - first) {
1155 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1156 return STATUS_MORE_ENTRIES;
1159 return NT_STATUS_OK;
1164 samr_CreateUser2
1166 This call uses transactions to ensure we don't get a new conflicting
1167 user while we are processing this, and to ensure the user either
1168 completly exists, or does not.
1170 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1171 struct samr_CreateUser2 *r)
1173 NTSTATUS status;
1174 struct samr_domain_state *d_state;
1175 struct samr_account_state *a_state;
1176 struct dcesrv_handle *h;
1177 struct ldb_dn *dn;
1178 struct dom_sid *sid;
1179 struct dcesrv_handle *u_handle;
1180 const char *account_name;
1182 ZERO_STRUCTP(r->out.user_handle);
1183 *r->out.access_granted = 0;
1184 *r->out.rid = 0;
1186 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1188 d_state = h->data;
1190 if (d_state->builtin) {
1191 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1192 return NT_STATUS_ACCESS_DENIED;
1193 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1194 /* Domain trust accounts must be created by the LSA calls */
1195 return NT_STATUS_ACCESS_DENIED;
1197 account_name = r->in.account_name->string;
1199 if (account_name == NULL) {
1200 return NT_STATUS_INVALID_PARAMETER;
1203 status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, &sid, &dn);
1204 if (!NT_STATUS_IS_OK(status)) {
1205 return status;
1207 a_state = talloc(mem_ctx, struct samr_account_state);
1208 if (!a_state) {
1209 ldb_transaction_cancel(d_state->sam_ctx);
1210 return NT_STATUS_NO_MEMORY;
1212 a_state->sam_ctx = d_state->sam_ctx;
1213 a_state->access_mask = r->in.access_mask;
1214 a_state->domain_state = talloc_reference(a_state, d_state);
1215 a_state->account_dn = talloc_steal(a_state, dn);
1217 a_state->account_name = talloc_steal(a_state, account_name);
1218 if (!a_state->account_name) {
1219 return NT_STATUS_NO_MEMORY;
1222 /* create the policy handle */
1223 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1224 if (!u_handle) {
1225 return NT_STATUS_NO_MEMORY;
1228 u_handle->data = talloc_steal(u_handle, a_state);
1230 *r->out.user_handle = u_handle->wire_handle;
1231 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1233 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1235 return NT_STATUS_OK;
1240 samr_CreateUser
1242 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1243 struct samr_CreateUser *r)
1245 struct samr_CreateUser2 r2;
1246 uint32_t access_granted = 0;
1249 /* a simple wrapper around samr_CreateUser2 works nicely */
1250 r2.in.domain_handle = r->in.domain_handle;
1251 r2.in.account_name = r->in.account_name;
1252 r2.in.acct_flags = ACB_NORMAL;
1253 r2.in.access_mask = r->in.access_mask;
1254 r2.out.user_handle = r->out.user_handle;
1255 r2.out.access_granted = &access_granted;
1256 r2.out.rid = r->out.rid;
1258 return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1262 samr_EnumDomainUsers
1264 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1265 struct samr_EnumDomainUsers *r)
1267 struct dcesrv_handle *h;
1268 struct samr_domain_state *d_state;
1269 struct ldb_message **res;
1270 int i, ldb_cnt;
1271 uint32_t first, count;
1272 struct samr_SamEntry *entries;
1273 const char * const attrs[] = { "objectSid", "sAMAccountName",
1274 "userAccountControl", NULL };
1275 struct samr_SamArray *sam;
1277 *r->out.resume_handle = 0;
1278 *r->out.sam = NULL;
1279 *r->out.num_entries = 0;
1281 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1283 d_state = h->data;
1285 /* search for all domain users in this domain. This could possibly be
1286 cached and resumed on resume_key */
1287 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1288 d_state->domain_dn,
1289 &res, attrs,
1290 d_state->domain_sid,
1291 "(objectClass=user)");
1292 if (ldb_cnt < 0) {
1293 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1296 /* convert to SamEntry format */
1297 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1298 if (!entries) {
1299 return NT_STATUS_NO_MEMORY;
1302 count = 0;
1304 for (i=0;i<ldb_cnt;i++) {
1305 /* Check if a mask has been requested */
1306 if (r->in.acct_flags
1307 && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
1308 res[i], d_state->domain_dn) & r->in.acct_flags) == 0)) {
1309 continue;
1311 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1312 "objectSid", 0);
1313 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1314 "sAMAccountName", "");
1315 count += 1;
1318 /* sort the results by rid */
1319 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1321 /* find the first entry to return */
1322 for (first=0;
1323 first<count && entries[first].idx <= *r->in.resume_handle;
1324 first++) ;
1326 /* return the rest, limit by max_size. Note that we
1327 use the w2k3 element size value of 54 */
1328 *r->out.num_entries = count - first;
1329 *r->out.num_entries = MIN(*r->out.num_entries,
1330 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1332 sam = talloc(mem_ctx, struct samr_SamArray);
1333 if (!sam) {
1334 return NT_STATUS_NO_MEMORY;
1337 sam->entries = entries+first;
1338 sam->count = *r->out.num_entries;
1340 *r->out.sam = sam;
1342 if (first == count) {
1343 return NT_STATUS_OK;
1346 if (*r->out.num_entries < count - first) {
1347 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1348 return STATUS_MORE_ENTRIES;
1351 return NT_STATUS_OK;
1356 samr_CreateDomAlias
1358 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1359 struct samr_CreateDomAlias *r)
1361 struct samr_domain_state *d_state;
1362 struct samr_account_state *a_state;
1363 struct dcesrv_handle *h;
1364 const char *alias_name;
1365 struct dom_sid *sid;
1366 struct dcesrv_handle *a_handle;
1367 struct ldb_dn *dn;
1368 NTSTATUS status;
1370 ZERO_STRUCTP(r->out.alias_handle);
1371 *r->out.rid = 0;
1373 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1375 d_state = h->data;
1377 if (d_state->builtin) {
1378 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1379 return NT_STATUS_ACCESS_DENIED;
1382 alias_name = r->in.alias_name->string;
1384 if (alias_name == NULL) {
1385 return NT_STATUS_INVALID_PARAMETER;
1388 status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1389 if (!NT_STATUS_IS_OK(status)) {
1390 return status;
1393 a_state = talloc(mem_ctx, struct samr_account_state);
1394 if (!a_state) {
1395 return NT_STATUS_NO_MEMORY;
1398 a_state->sam_ctx = d_state->sam_ctx;
1399 a_state->access_mask = r->in.access_mask;
1400 a_state->domain_state = talloc_reference(a_state, d_state);
1401 a_state->account_dn = talloc_steal(a_state, dn);
1403 a_state->account_name = talloc_steal(a_state, alias_name);
1405 /* create the policy handle */
1406 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1407 if (a_handle == NULL)
1408 return NT_STATUS_NO_MEMORY;
1410 a_handle->data = talloc_steal(a_handle, a_state);
1412 *r->out.alias_handle = a_handle->wire_handle;
1414 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1416 return NT_STATUS_OK;
1421 samr_EnumDomainAliases
1423 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1424 struct samr_EnumDomainAliases *r)
1426 struct dcesrv_handle *h;
1427 struct samr_domain_state *d_state;
1428 struct ldb_message **res;
1429 int i, ldb_cnt;
1430 uint32_t first, count;
1431 struct samr_SamEntry *entries;
1432 const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1433 struct samr_SamArray *sam;
1435 *r->out.resume_handle = 0;
1436 *r->out.sam = NULL;
1437 *r->out.num_entries = 0;
1439 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1441 d_state = h->data;
1443 /* search for all domain aliases in this domain. This could possibly be
1444 cached and resumed based on resume_key */
1445 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1446 &res, attrs,
1447 d_state->domain_sid,
1448 "(&(|(grouptype=%d)(grouptype=%d)))"
1449 "(objectclass=group))",
1450 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1451 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1452 if (ldb_cnt < 0) {
1453 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1456 /* convert to SamEntry format */
1457 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1458 if (!entries) {
1459 return NT_STATUS_NO_MEMORY;
1462 count = 0;
1464 for (i=0;i<ldb_cnt;i++) {
1465 struct dom_sid *alias_sid;
1467 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1468 "objectSid");
1470 if (alias_sid == NULL) {
1471 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1474 entries[count].idx =
1475 alias_sid->sub_auths[alias_sid->num_auths-1];
1476 entries[count].name.string =
1477 ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1478 count += 1;
1481 /* sort the results by rid */
1482 TYPESAFE_QSORT(entries, count, compare_SamEntry);
1484 /* find the first entry to return */
1485 for (first=0;
1486 first<count && entries[first].idx <= *r->in.resume_handle;
1487 first++) ;
1489 /* return the rest, limit by max_size. Note that we
1490 use the w2k3 element size value of 54 */
1491 *r->out.num_entries = count - first;
1492 *r->out.num_entries = MIN(*r->out.num_entries,
1493 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1495 sam = talloc(mem_ctx, struct samr_SamArray);
1496 if (!sam) {
1497 return NT_STATUS_NO_MEMORY;
1500 sam->entries = entries+first;
1501 sam->count = *r->out.num_entries;
1503 *r->out.sam = sam;
1505 if (first == count) {
1506 return NT_STATUS_OK;
1509 if (*r->out.num_entries < count - first) {
1510 *r->out.resume_handle =
1511 entries[first+*r->out.num_entries-1].idx;
1512 return STATUS_MORE_ENTRIES;
1515 return NT_STATUS_OK;
1520 samr_GetAliasMembership
1522 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1523 struct samr_GetAliasMembership *r)
1525 struct dcesrv_handle *h;
1526 struct samr_domain_state *d_state;
1527 const char *filter;
1528 const char * const attrs[] = { "objectSid", NULL };
1529 struct ldb_message **res;
1530 uint32_t i;
1531 int count = 0;
1533 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1535 d_state = h->data;
1537 filter = talloc_asprintf(mem_ctx,
1538 "(&(|(grouptype=%d)(grouptype=%d))"
1539 "(objectclass=group)(|",
1540 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1541 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1542 if (filter == NULL) {
1543 return NT_STATUS_NO_MEMORY;
1546 for (i=0; i<r->in.sids->num_sids; i++) {
1547 const char *memberdn;
1549 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1550 "distinguishedName",
1551 "(objectSid=%s)",
1552 ldap_encode_ndr_dom_sid(mem_ctx,
1553 r->in.sids->sids[i].sid));
1554 if (memberdn == NULL) {
1555 continue;
1558 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1559 memberdn);
1560 if (filter == NULL) {
1561 return NT_STATUS_NO_MEMORY;
1565 /* Find out if we had at least one valid member SID passed - otherwise
1566 * just skip the search. */
1567 if (strstr(filter, "member") != NULL) {
1568 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1569 &res, attrs, d_state->domain_sid,
1570 "%s))", filter);
1571 if (count < 0) {
1572 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1576 r->out.rids->count = 0;
1577 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1578 if (r->out.rids->ids == NULL)
1579 return NT_STATUS_NO_MEMORY;
1581 for (i=0; i<count; i++) {
1582 struct dom_sid *alias_sid;
1584 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1585 if (alias_sid == NULL) {
1586 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1589 r->out.rids->ids[r->out.rids->count] =
1590 alias_sid->sub_auths[alias_sid->num_auths-1];
1591 r->out.rids->count += 1;
1594 return NT_STATUS_OK;
1599 samr_LookupNames
1601 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1602 struct samr_LookupNames *r)
1604 struct dcesrv_handle *h;
1605 struct samr_domain_state *d_state;
1606 uint32_t i, num_mapped;
1607 NTSTATUS status = NT_STATUS_OK;
1608 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1609 int count;
1611 ZERO_STRUCTP(r->out.rids);
1612 ZERO_STRUCTP(r->out.types);
1614 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1616 d_state = h->data;
1618 if (r->in.num_names == 0) {
1619 return NT_STATUS_OK;
1622 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1623 r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1624 if (!r->out.rids->ids || !r->out.types->ids) {
1625 return NT_STATUS_NO_MEMORY;
1627 r->out.rids->count = r->in.num_names;
1628 r->out.types->count = r->in.num_names;
1630 num_mapped = 0;
1632 for (i=0;i<r->in.num_names;i++) {
1633 struct ldb_message **res;
1634 struct dom_sid *sid;
1635 uint32_t atype, rtype;
1637 r->out.rids->ids[i] = 0;
1638 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1640 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1641 "sAMAccountName=%s",
1642 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1643 if (count != 1) {
1644 status = STATUS_SOME_UNMAPPED;
1645 continue;
1648 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1649 if (sid == NULL) {
1650 status = STATUS_SOME_UNMAPPED;
1651 continue;
1654 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1655 if (atype == 0) {
1656 status = STATUS_SOME_UNMAPPED;
1657 continue;
1660 rtype = ds_atype_map(atype);
1662 if (rtype == SID_NAME_UNKNOWN) {
1663 status = STATUS_SOME_UNMAPPED;
1664 continue;
1667 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1668 r->out.types->ids[i] = rtype;
1669 num_mapped++;
1672 if (num_mapped == 0) {
1673 return NT_STATUS_NONE_MAPPED;
1675 return status;
1680 samr_LookupRids
1682 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1683 struct samr_LookupRids *r)
1685 NTSTATUS status;
1686 struct dcesrv_handle *h;
1687 struct samr_domain_state *d_state;
1688 const char **names;
1689 struct lsa_String *lsa_names;
1690 enum lsa_SidType *ids;
1692 ZERO_STRUCTP(r->out.names);
1693 ZERO_STRUCTP(r->out.types);
1695 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1697 d_state = h->data;
1699 if (r->in.num_rids == 0)
1700 return NT_STATUS_OK;
1702 lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1703 names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1704 ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1706 if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1707 return NT_STATUS_NO_MEMORY;
1709 r->out.names->names = lsa_names;
1710 r->out.names->count = r->in.num_rids;
1712 r->out.types->ids = (uint32_t *) ids;
1713 r->out.types->count = r->in.num_rids;
1715 status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1716 r->in.num_rids, r->in.rids, names, ids);
1717 if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1718 uint32_t i;
1719 for (i = 0; i < r->in.num_rids; i++) {
1720 lsa_names[i].string = names[i];
1723 return status;
1728 samr_OpenGroup
1730 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1731 struct samr_OpenGroup *r)
1733 struct samr_domain_state *d_state;
1734 struct samr_account_state *a_state;
1735 struct dcesrv_handle *h;
1736 const char *groupname;
1737 struct dom_sid *sid;
1738 struct ldb_message **msgs;
1739 struct dcesrv_handle *g_handle;
1740 const char * const attrs[2] = { "sAMAccountName", NULL };
1741 int ret;
1743 ZERO_STRUCTP(r->out.group_handle);
1745 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1747 d_state = h->data;
1749 /* form the group SID */
1750 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1751 if (!sid) {
1752 return NT_STATUS_NO_MEMORY;
1755 /* search for the group record */
1756 ret = gendb_search(d_state->sam_ctx,
1757 mem_ctx, d_state->domain_dn, &msgs, attrs,
1758 "(&(objectSid=%s)(objectClass=group)"
1759 "(|(groupType=%d)(groupType=%d)))",
1760 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1761 GTYPE_SECURITY_UNIVERSAL_GROUP,
1762 GTYPE_SECURITY_GLOBAL_GROUP);
1763 if (ret == 0) {
1764 return NT_STATUS_NO_SUCH_GROUP;
1766 if (ret != 1) {
1767 DEBUG(0,("Found %d records matching sid %s\n",
1768 ret, dom_sid_string(mem_ctx, sid)));
1769 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1772 groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1773 if (groupname == NULL) {
1774 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1775 dom_sid_string(mem_ctx, sid)));
1776 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1779 a_state = talloc(mem_ctx, struct samr_account_state);
1780 if (!a_state) {
1781 return NT_STATUS_NO_MEMORY;
1783 a_state->sam_ctx = d_state->sam_ctx;
1784 a_state->access_mask = r->in.access_mask;
1785 a_state->domain_state = talloc_reference(a_state, d_state);
1786 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1787 a_state->account_sid = talloc_steal(a_state, sid);
1788 a_state->account_name = talloc_strdup(a_state, groupname);
1789 if (!a_state->account_name) {
1790 return NT_STATUS_NO_MEMORY;
1793 /* create the policy handle */
1794 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1795 if (!g_handle) {
1796 return NT_STATUS_NO_MEMORY;
1799 g_handle->data = talloc_steal(g_handle, a_state);
1801 *r->out.group_handle = g_handle->wire_handle;
1803 return NT_STATUS_OK;
1807 samr_QueryGroupInfo
1809 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1810 struct samr_QueryGroupInfo *r)
1812 struct dcesrv_handle *h;
1813 struct samr_account_state *a_state;
1814 struct ldb_message *msg, **res;
1815 const char * const attrs[4] = { "sAMAccountName", "description",
1816 "numMembers", NULL };
1817 int ret;
1818 union samr_GroupInfo *info;
1820 *r->out.info = NULL;
1822 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1824 a_state = h->data;
1826 /* pull all the group attributes */
1827 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1828 a_state->account_dn, &res, attrs);
1829 if (ret == 0) {
1830 return NT_STATUS_NO_SUCH_GROUP;
1832 if (ret != 1) {
1833 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1835 msg = res[0];
1837 /* allocate the info structure */
1838 info = talloc_zero(mem_ctx, union samr_GroupInfo);
1839 if (info == NULL) {
1840 return NT_STATUS_NO_MEMORY;
1843 /* Fill in the level */
1844 switch (r->in.level) {
1845 case GROUPINFOALL:
1846 QUERY_STRING(msg, all.name, "sAMAccountName");
1847 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1848 QUERY_UINT (msg, all.num_members, "numMembers")
1849 QUERY_STRING(msg, all.description, "description");
1850 break;
1851 case GROUPINFONAME:
1852 QUERY_STRING(msg, name, "sAMAccountName");
1853 break;
1854 case GROUPINFOATTRIBUTES:
1855 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1856 break;
1857 case GROUPINFODESCRIPTION:
1858 QUERY_STRING(msg, description, "description");
1859 break;
1860 case GROUPINFOALL2:
1861 QUERY_STRING(msg, all2.name, "sAMAccountName");
1862 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1863 QUERY_UINT (msg, all2.num_members, "numMembers")
1864 QUERY_STRING(msg, all2.description, "description");
1865 break;
1866 default:
1867 talloc_free(info);
1868 return NT_STATUS_INVALID_INFO_CLASS;
1871 *r->out.info = info;
1873 return NT_STATUS_OK;
1878 samr_SetGroupInfo
1880 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1881 struct samr_SetGroupInfo *r)
1883 struct dcesrv_handle *h;
1884 struct samr_account_state *g_state;
1885 struct ldb_message *msg;
1886 struct ldb_context *sam_ctx;
1887 int ret;
1889 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1891 g_state = h->data;
1892 sam_ctx = g_state->sam_ctx;
1894 msg = ldb_msg_new(mem_ctx);
1895 if (msg == NULL) {
1896 return NT_STATUS_NO_MEMORY;
1899 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1900 if (!msg->dn) {
1901 return NT_STATUS_NO_MEMORY;
1904 switch (r->in.level) {
1905 case GROUPINFODESCRIPTION:
1906 SET_STRING(msg, description, "description");
1907 break;
1908 case GROUPINFONAME:
1909 /* On W2k3 this does not change the name, it changes the
1910 * sAMAccountName attribute */
1911 SET_STRING(msg, name, "sAMAccountName");
1912 break;
1913 case GROUPINFOATTRIBUTES:
1914 /* This does not do anything obviously visible in W2k3 LDAP */
1915 return NT_STATUS_OK;
1916 default:
1917 return NT_STATUS_INVALID_INFO_CLASS;
1920 /* modify the samdb record */
1921 ret = ldb_modify(g_state->sam_ctx, msg);
1922 if (ret != LDB_SUCCESS) {
1923 /* we really need samdb.c to return NTSTATUS */
1924 return NT_STATUS_UNSUCCESSFUL;
1927 return NT_STATUS_OK;
1932 samr_AddGroupMember
1934 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1935 struct samr_AddGroupMember *r)
1937 struct dcesrv_handle *h;
1938 struct samr_account_state *a_state;
1939 struct samr_domain_state *d_state;
1940 struct ldb_message *mod;
1941 struct dom_sid *membersid;
1942 const char *memberdn;
1943 struct ldb_result *res;
1944 const char * const attrs[] = { NULL };
1945 int ret;
1947 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1949 a_state = h->data;
1950 d_state = a_state->domain_state;
1952 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1953 if (membersid == NULL) {
1954 return NT_STATUS_NO_MEMORY;
1957 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1958 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1959 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1960 "(objectSid=%s)",
1961 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1963 if (ret != LDB_SUCCESS) {
1964 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1967 if (res->count == 0) {
1968 return NT_STATUS_NO_SUCH_USER;
1971 if (res->count > 1) {
1972 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1975 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1977 if (memberdn == NULL)
1978 return NT_STATUS_NO_MEMORY;
1980 mod = ldb_msg_new(mem_ctx);
1981 if (mod == NULL) {
1982 return NT_STATUS_NO_MEMORY;
1985 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1987 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1988 memberdn);
1989 if (ret != LDB_SUCCESS) {
1990 return NT_STATUS_UNSUCCESSFUL;
1993 ret = ldb_modify(a_state->sam_ctx, mod);
1994 switch (ret) {
1995 case LDB_SUCCESS:
1996 return NT_STATUS_OK;
1997 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
1998 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1999 return NT_STATUS_MEMBER_IN_GROUP;
2000 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2001 return NT_STATUS_ACCESS_DENIED;
2002 default:
2003 return NT_STATUS_UNSUCCESSFUL;
2009 samr_DeleteDomainGroup
2011 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2012 struct samr_DeleteDomainGroup *r)
2014 struct dcesrv_handle *h;
2015 struct samr_account_state *a_state;
2016 int ret;
2018 *r->out.group_handle = *r->in.group_handle;
2020 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2022 a_state = h->data;
2024 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2025 if (ret != LDB_SUCCESS) {
2026 return NT_STATUS_UNSUCCESSFUL;
2029 talloc_free(h);
2030 ZERO_STRUCTP(r->out.group_handle);
2032 return NT_STATUS_OK;
2037 samr_DeleteGroupMember
2039 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2040 struct samr_DeleteGroupMember *r)
2042 struct dcesrv_handle *h;
2043 struct samr_account_state *a_state;
2044 struct samr_domain_state *d_state;
2045 struct ldb_message *mod;
2046 struct dom_sid *membersid;
2047 const char *memberdn;
2048 struct ldb_result *res;
2049 const char * const attrs[] = { NULL };
2050 int ret;
2052 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2054 a_state = h->data;
2055 d_state = a_state->domain_state;
2057 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2058 if (membersid == NULL) {
2059 return NT_STATUS_NO_MEMORY;
2062 /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2063 ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2064 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2065 "(objectSid=%s)",
2066 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2068 if (ret != LDB_SUCCESS) {
2069 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2072 if (res->count == 0) {
2073 return NT_STATUS_NO_SUCH_USER;
2076 if (res->count > 1) {
2077 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2080 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2082 if (memberdn == NULL)
2083 return NT_STATUS_NO_MEMORY;
2085 mod = ldb_msg_new(mem_ctx);
2086 if (mod == NULL) {
2087 return NT_STATUS_NO_MEMORY;
2090 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2092 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2093 memberdn);
2094 if (ret != LDB_SUCCESS) {
2095 return NT_STATUS_NO_MEMORY;
2098 ret = ldb_modify(a_state->sam_ctx, mod);
2099 switch (ret) {
2100 case LDB_SUCCESS:
2101 return NT_STATUS_OK;
2102 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2103 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2104 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2105 return NT_STATUS_ACCESS_DENIED;
2106 default:
2107 return NT_STATUS_UNSUCCESSFUL;
2113 samr_QueryGroupMember
2115 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2116 struct samr_QueryGroupMember *r)
2118 struct dcesrv_handle *h;
2119 struct samr_account_state *a_state;
2120 struct samr_domain_state *d_state;
2121 struct samr_RidAttrArray *array;
2122 unsigned int i, num_members;
2123 struct dom_sid *members;
2124 NTSTATUS status;
2126 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2128 a_state = h->data;
2129 d_state = a_state->domain_state;
2131 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2132 a_state->account_dn, &members,
2133 &num_members);
2134 if (!NT_STATUS_IS_OK(status)) {
2135 return status;
2138 array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2139 if (array == NULL) {
2140 return NT_STATUS_NO_MEMORY;
2143 if (num_members == 0) {
2144 *r->out.rids = array;
2146 return NT_STATUS_OK;
2149 array->rids = talloc_array(array, uint32_t, num_members);
2150 if (array->rids == NULL) {
2151 return NT_STATUS_NO_MEMORY;
2154 array->attributes = talloc_array(array, uint32_t, num_members);
2155 if (array->attributes == NULL) {
2156 return NT_STATUS_NO_MEMORY;
2159 array->count = 0;
2160 for (i=0; i<num_members; i++) {
2161 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2162 continue;
2165 status = dom_sid_split_rid(NULL, &members[i], NULL,
2166 &array->rids[array->count]);
2167 if (!NT_STATUS_IS_OK(status)) {
2168 return status;
2171 array->attributes[array->count] = SE_GROUP_MANDATORY |
2172 SE_GROUP_ENABLED_BY_DEFAULT |
2173 SE_GROUP_ENABLED;
2174 array->count++;
2177 *r->out.rids = array;
2179 return NT_STATUS_OK;
2184 samr_SetMemberAttributesOfGroup
2186 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2187 struct samr_SetMemberAttributesOfGroup *r)
2189 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2194 samr_OpenAlias
2196 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2197 struct samr_OpenAlias *r)
2199 struct samr_domain_state *d_state;
2200 struct samr_account_state *a_state;
2201 struct dcesrv_handle *h;
2202 const char *alias_name;
2203 struct dom_sid *sid;
2204 struct ldb_message **msgs;
2205 struct dcesrv_handle *g_handle;
2206 const char * const attrs[2] = { "sAMAccountName", NULL };
2207 int ret;
2209 ZERO_STRUCTP(r->out.alias_handle);
2211 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2213 d_state = h->data;
2215 /* form the alias SID */
2216 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2217 if (sid == NULL)
2218 return NT_STATUS_NO_MEMORY;
2220 /* search for the group record */
2221 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2222 "(&(objectSid=%s)(objectclass=group)"
2223 "(|(grouptype=%d)(grouptype=%d)))",
2224 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2225 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2226 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2227 if (ret == 0) {
2228 return NT_STATUS_NO_SUCH_ALIAS;
2230 if (ret != 1) {
2231 DEBUG(0,("Found %d records matching sid %s\n",
2232 ret, dom_sid_string(mem_ctx, sid)));
2233 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2236 alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2237 if (alias_name == NULL) {
2238 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2239 dom_sid_string(mem_ctx, sid)));
2240 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2243 a_state = talloc(mem_ctx, struct samr_account_state);
2244 if (!a_state) {
2245 return NT_STATUS_NO_MEMORY;
2247 a_state->sam_ctx = d_state->sam_ctx;
2248 a_state->access_mask = r->in.access_mask;
2249 a_state->domain_state = talloc_reference(a_state, d_state);
2250 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2251 a_state->account_sid = talloc_steal(a_state, sid);
2252 a_state->account_name = talloc_strdup(a_state, alias_name);
2253 if (!a_state->account_name) {
2254 return NT_STATUS_NO_MEMORY;
2257 /* create the policy handle */
2258 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2259 if (!g_handle) {
2260 return NT_STATUS_NO_MEMORY;
2263 g_handle->data = talloc_steal(g_handle, a_state);
2265 *r->out.alias_handle = g_handle->wire_handle;
2267 return NT_STATUS_OK;
2272 samr_QueryAliasInfo
2274 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2275 struct samr_QueryAliasInfo *r)
2277 struct dcesrv_handle *h;
2278 struct samr_account_state *a_state;
2279 struct ldb_message *msg, **res;
2280 const char * const attrs[4] = { "sAMAccountName", "description",
2281 "numMembers", NULL };
2282 int ret;
2283 union samr_AliasInfo *info;
2285 *r->out.info = NULL;
2287 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2289 a_state = h->data;
2291 /* pull all the alias attributes */
2292 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2293 a_state->account_dn, &res, attrs);
2294 if (ret == 0) {
2295 return NT_STATUS_NO_SUCH_ALIAS;
2297 if (ret != 1) {
2298 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2300 msg = res[0];
2302 /* allocate the info structure */
2303 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2304 if (info == NULL) {
2305 return NT_STATUS_NO_MEMORY;
2308 switch(r->in.level) {
2309 case ALIASINFOALL:
2310 QUERY_STRING(msg, all.name, "sAMAccountName");
2311 QUERY_UINT (msg, all.num_members, "numMembers");
2312 QUERY_STRING(msg, all.description, "description");
2313 break;
2314 case ALIASINFONAME:
2315 QUERY_STRING(msg, name, "sAMAccountName");
2316 break;
2317 case ALIASINFODESCRIPTION:
2318 QUERY_STRING(msg, description, "description");
2319 break;
2320 default:
2321 talloc_free(info);
2322 return NT_STATUS_INVALID_INFO_CLASS;
2325 *r->out.info = info;
2327 return NT_STATUS_OK;
2332 samr_SetAliasInfo
2334 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2335 struct samr_SetAliasInfo *r)
2337 struct dcesrv_handle *h;
2338 struct samr_account_state *a_state;
2339 struct ldb_message *msg;
2340 struct ldb_context *sam_ctx;
2341 int ret;
2343 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2345 a_state = h->data;
2346 sam_ctx = a_state->sam_ctx;
2348 msg = ldb_msg_new(mem_ctx);
2349 if (msg == NULL) {
2350 return NT_STATUS_NO_MEMORY;
2353 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2354 if (!msg->dn) {
2355 return NT_STATUS_NO_MEMORY;
2358 switch (r->in.level) {
2359 case ALIASINFODESCRIPTION:
2360 SET_STRING(msg, description, "description");
2361 break;
2362 case ALIASINFONAME:
2363 /* On W2k3 this does not change the name, it changes the
2364 * sAMAccountName attribute */
2365 SET_STRING(msg, name, "sAMAccountName");
2366 break;
2367 default:
2368 return NT_STATUS_INVALID_INFO_CLASS;
2371 /* modify the samdb record */
2372 ret = ldb_modify(a_state->sam_ctx, msg);
2373 if (ret != LDB_SUCCESS) {
2374 /* we really need samdb.c to return NTSTATUS */
2375 return NT_STATUS_UNSUCCESSFUL;
2378 return NT_STATUS_OK;
2383 samr_DeleteDomAlias
2385 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2386 struct samr_DeleteDomAlias *r)
2388 struct dcesrv_handle *h;
2389 struct samr_account_state *a_state;
2390 int ret;
2392 *r->out.alias_handle = *r->in.alias_handle;
2394 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2396 a_state = h->data;
2398 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2399 if (ret != LDB_SUCCESS) {
2400 return NT_STATUS_UNSUCCESSFUL;
2403 talloc_free(h);
2404 ZERO_STRUCTP(r->out.alias_handle);
2406 return NT_STATUS_OK;
2411 samr_AddAliasMember
2413 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2414 struct samr_AddAliasMember *r)
2416 struct dcesrv_handle *h;
2417 struct samr_account_state *a_state;
2418 struct samr_domain_state *d_state;
2419 struct ldb_message *mod;
2420 struct ldb_message **msgs;
2421 const char * const attrs[] = { NULL };
2422 struct ldb_dn *memberdn = NULL;
2423 int ret;
2424 NTSTATUS status;
2426 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2428 a_state = h->data;
2429 d_state = a_state->domain_state;
2431 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2432 &msgs, attrs, "(objectsid=%s)",
2433 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2435 if (ret == 1) {
2436 memberdn = msgs[0]->dn;
2437 } else if (ret == 0) {
2438 status = samdb_create_foreign_security_principal(
2439 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2440 if (!NT_STATUS_IS_OK(status)) {
2441 return status;
2443 } else {
2444 DEBUG(0,("Found %d records matching sid %s\n",
2445 ret, dom_sid_string(mem_ctx, r->in.sid)));
2446 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2449 if (memberdn == NULL) {
2450 DEBUG(0, ("Could not find memberdn\n"));
2451 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2454 mod = ldb_msg_new(mem_ctx);
2455 if (mod == NULL) {
2456 return NT_STATUS_NO_MEMORY;
2459 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2461 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2462 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2463 if (ret != LDB_SUCCESS) {
2464 return NT_STATUS_UNSUCCESSFUL;
2467 ret = ldb_modify(a_state->sam_ctx, mod);
2468 switch (ret) {
2469 case LDB_SUCCESS:
2470 return NT_STATUS_OK;
2471 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2472 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2473 return NT_STATUS_MEMBER_IN_GROUP;
2474 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2475 return NT_STATUS_ACCESS_DENIED;
2476 default:
2477 return NT_STATUS_UNSUCCESSFUL;
2483 samr_DeleteAliasMember
2485 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2486 struct samr_DeleteAliasMember *r)
2488 struct dcesrv_handle *h;
2489 struct samr_account_state *a_state;
2490 struct samr_domain_state *d_state;
2491 struct ldb_message *mod;
2492 const char *memberdn;
2493 int ret;
2495 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2497 a_state = h->data;
2498 d_state = a_state->domain_state;
2500 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2501 "distinguishedName", "(objectSid=%s)",
2502 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2503 if (memberdn == NULL) {
2504 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2507 mod = ldb_msg_new(mem_ctx);
2508 if (mod == NULL) {
2509 return NT_STATUS_NO_MEMORY;
2512 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2514 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2515 memberdn);
2516 if (ret != LDB_SUCCESS) {
2517 return NT_STATUS_UNSUCCESSFUL;
2520 ret = ldb_modify(a_state->sam_ctx, mod);
2521 switch (ret) {
2522 case LDB_SUCCESS:
2523 return NT_STATUS_OK;
2524 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2525 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2526 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2527 return NT_STATUS_ACCESS_DENIED;
2528 default:
2529 return NT_STATUS_UNSUCCESSFUL;
2535 samr_GetMembersInAlias
2537 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2538 struct samr_GetMembersInAlias *r)
2540 struct dcesrv_handle *h;
2541 struct samr_account_state *a_state;
2542 struct samr_domain_state *d_state;
2543 struct lsa_SidPtr *array;
2544 unsigned int i, num_members;
2545 struct dom_sid *members;
2546 NTSTATUS status;
2548 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2550 a_state = h->data;
2551 d_state = a_state->domain_state;
2553 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2554 a_state->account_dn, &members,
2555 &num_members);
2556 if (!NT_STATUS_IS_OK(status)) {
2557 return status;
2560 if (num_members == 0) {
2561 r->out.sids->sids = NULL;
2563 return NT_STATUS_OK;
2566 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2567 if (array == NULL) {
2568 return NT_STATUS_NO_MEMORY;
2571 for (i=0; i<num_members; i++) {
2572 array[i].sid = &members[i];
2575 r->out.sids->num_sids = num_members;
2576 r->out.sids->sids = array;
2578 return NT_STATUS_OK;
2582 samr_OpenUser
2584 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2585 struct samr_OpenUser *r)
2587 struct samr_domain_state *d_state;
2588 struct samr_account_state *a_state;
2589 struct dcesrv_handle *h;
2590 const char *account_name;
2591 struct dom_sid *sid;
2592 struct ldb_message **msgs;
2593 struct dcesrv_handle *u_handle;
2594 const char * const attrs[2] = { "sAMAccountName", NULL };
2595 int ret;
2597 ZERO_STRUCTP(r->out.user_handle);
2599 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2601 d_state = h->data;
2603 /* form the users SID */
2604 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2605 if (!sid) {
2606 return NT_STATUS_NO_MEMORY;
2609 /* search for the user record */
2610 ret = gendb_search(d_state->sam_ctx,
2611 mem_ctx, d_state->domain_dn, &msgs, attrs,
2612 "(&(objectSid=%s)(objectclass=user))",
2613 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2614 if (ret == 0) {
2615 return NT_STATUS_NO_SUCH_USER;
2617 if (ret != 1) {
2618 DEBUG(0,("Found %d records matching sid %s\n", ret,
2619 dom_sid_string(mem_ctx, sid)));
2620 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2623 account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2624 if (account_name == NULL) {
2625 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2626 dom_sid_string(mem_ctx, sid)));
2627 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2630 a_state = talloc(mem_ctx, struct samr_account_state);
2631 if (!a_state) {
2632 return NT_STATUS_NO_MEMORY;
2634 a_state->sam_ctx = d_state->sam_ctx;
2635 a_state->access_mask = r->in.access_mask;
2636 a_state->domain_state = talloc_reference(a_state, d_state);
2637 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2638 a_state->account_sid = talloc_steal(a_state, sid);
2639 a_state->account_name = talloc_strdup(a_state, account_name);
2640 if (!a_state->account_name) {
2641 return NT_STATUS_NO_MEMORY;
2644 /* create the policy handle */
2645 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2646 if (!u_handle) {
2647 return NT_STATUS_NO_MEMORY;
2650 u_handle->data = talloc_steal(u_handle, a_state);
2652 *r->out.user_handle = u_handle->wire_handle;
2654 return NT_STATUS_OK;
2660 samr_DeleteUser
2662 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2663 struct samr_DeleteUser *r)
2665 struct dcesrv_handle *h;
2666 struct samr_account_state *a_state;
2667 int ret;
2669 *r->out.user_handle = *r->in.user_handle;
2671 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2673 a_state = h->data;
2675 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2676 if (ret != LDB_SUCCESS) {
2677 DEBUG(1, ("Failed to delete user: %s: %s\n",
2678 ldb_dn_get_linearized(a_state->account_dn),
2679 ldb_errstring(a_state->sam_ctx)));
2680 return NT_STATUS_UNSUCCESSFUL;
2683 talloc_free(h);
2684 ZERO_STRUCTP(r->out.user_handle);
2686 return NT_STATUS_OK;
2691 samr_QueryUserInfo
2693 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2694 struct samr_QueryUserInfo *r)
2696 struct dcesrv_handle *h;
2697 struct samr_account_state *a_state;
2698 struct ldb_message *msg, **res;
2699 int ret;
2700 struct ldb_context *sam_ctx;
2702 const char * const *attrs = NULL;
2703 union samr_UserInfo *info;
2705 *r->out.info = NULL;
2707 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2709 a_state = h->data;
2710 sam_ctx = a_state->sam_ctx;
2712 /* fill in the reply */
2713 switch (r->in.level) {
2714 case 1:
2716 static const char * const attrs2[] = {"sAMAccountName",
2717 "displayName",
2718 "primaryroupID",
2719 "description",
2720 "comment",
2721 NULL};
2722 attrs = attrs2;
2723 break;
2725 case 2:
2727 static const char * const attrs2[] = {"comment",
2728 "countryCode",
2729 "codePage",
2730 NULL};
2731 attrs = attrs2;
2732 break;
2734 case 3:
2736 static const char * const attrs2[] = {"sAMAccountName",
2737 "displayName",
2738 "objectSid",
2739 "primaryGroupID",
2740 "homeDirectory",
2741 "homeDrive",
2742 "scriptPath",
2743 "profilePath",
2744 "userWorkstations",
2745 "lastLogon",
2746 "lastLogoff",
2747 "pwdLastSet",
2748 "logonHours",
2749 "badPwdCount",
2750 "logonCount",
2751 "userAccountControl",
2752 NULL};
2753 attrs = attrs2;
2754 break;
2756 case 4:
2758 static const char * const attrs2[] = {"logonHours",
2759 NULL};
2760 attrs = attrs2;
2761 break;
2763 case 5:
2765 static const char * const attrs2[] = {"sAMAccountName",
2766 "displayName",
2767 "objectSid",
2768 "primaryGroupID",
2769 "homeDirectory",
2770 "homeDrive",
2771 "scriptPath",
2772 "profilePath",
2773 "description",
2774 "userWorkstations",
2775 "lastLogon",
2776 "lastLogoff",
2777 "logonHours",
2778 "badPwdCount",
2779 "logonCount",
2780 "pwdLastSet",
2781 "accountExpires",
2782 "userAccountControl",
2783 NULL};
2784 attrs = attrs2;
2785 break;
2787 case 6:
2789 static const char * const attrs2[] = {"sAMAccountName",
2790 "displayName",
2791 NULL};
2792 attrs = attrs2;
2793 break;
2795 case 7:
2797 static const char * const attrs2[] = {"sAMAccountName",
2798 NULL};
2799 attrs = attrs2;
2800 break;
2802 case 8:
2804 static const char * const attrs2[] = {"displayName",
2805 NULL};
2806 attrs = attrs2;
2807 break;
2809 case 9:
2811 static const char * const attrs2[] = {"primaryGroupID",
2812 NULL};
2813 attrs = attrs2;
2814 break;
2816 case 10:
2818 static const char * const attrs2[] = {"homeDirectory",
2819 "homeDrive",
2820 NULL};
2821 attrs = attrs2;
2822 break;
2824 case 11:
2826 static const char * const attrs2[] = {"scriptPath",
2827 NULL};
2828 attrs = attrs2;
2829 break;
2831 case 12:
2833 static const char * const attrs2[] = {"profilePath",
2834 NULL};
2835 attrs = attrs2;
2836 break;
2838 case 13:
2840 static const char * const attrs2[] = {"description",
2841 NULL};
2842 attrs = attrs2;
2843 break;
2845 case 14:
2847 static const char * const attrs2[] = {"userWorkstations",
2848 NULL};
2849 attrs = attrs2;
2850 break;
2852 case 16:
2854 static const char * const attrs2[] = {"userAccountControl",
2855 "pwdLastSet",
2856 NULL};
2857 attrs = attrs2;
2858 break;
2860 case 17:
2862 static const char * const attrs2[] = {"accountExpires",
2863 NULL};
2864 attrs = attrs2;
2865 break;
2867 case 18:
2869 return NT_STATUS_NOT_SUPPORTED;
2871 case 20:
2873 static const char * const attrs2[] = {"userParameters",
2874 NULL};
2875 attrs = attrs2;
2876 break;
2878 case 21:
2880 static const char * const attrs2[] = {"lastLogon",
2881 "lastLogoff",
2882 "pwdLastSet",
2883 "accountExpires",
2884 "sAMAccountName",
2885 "displayName",
2886 "homeDirectory",
2887 "homeDrive",
2888 "scriptPath",
2889 "profilePath",
2890 "description",
2891 "userWorkstations",
2892 "comment",
2893 "userParameters",
2894 "objectSid",
2895 "primaryGroupID",
2896 "userAccountControl",
2897 "logonHours",
2898 "badPwdCount",
2899 "logonCount",
2900 "countryCode",
2901 "codePage",
2902 NULL};
2903 attrs = attrs2;
2904 break;
2906 case 23:
2907 case 24:
2908 case 25:
2909 case 26:
2911 return NT_STATUS_NOT_SUPPORTED;
2913 default:
2915 return NT_STATUS_INVALID_INFO_CLASS;
2919 /* pull all the user attributes */
2920 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2921 a_state->account_dn, &res, attrs);
2922 if (ret == 0) {
2923 return NT_STATUS_NO_SUCH_USER;
2925 if (ret != 1) {
2926 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2928 msg = res[0];
2930 /* allocate the info structure */
2931 info = talloc_zero(mem_ctx, union samr_UserInfo);
2932 if (info == NULL) {
2933 return NT_STATUS_NO_MEMORY;
2936 /* fill in the reply */
2937 switch (r->in.level) {
2938 case 1:
2939 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2940 QUERY_STRING(msg, info1.full_name, "displayName");
2941 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2942 QUERY_STRING(msg, info1.description, "description");
2943 QUERY_STRING(msg, info1.comment, "comment");
2944 break;
2946 case 2:
2947 QUERY_STRING(msg, info2.comment, "comment");
2948 QUERY_UINT (msg, info2.country_code, "countryCode");
2949 QUERY_UINT (msg, info2.code_page, "codePage");
2950 break;
2952 case 3:
2953 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2954 QUERY_STRING(msg, info3.full_name, "displayName");
2955 QUERY_RID (msg, info3.rid, "objectSid");
2956 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2957 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2958 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2959 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2960 QUERY_STRING(msg, info3.profile_path, "profilePath");
2961 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2962 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2963 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2964 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2965 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2966 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2967 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2968 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2969 QUERY_UINT (msg, info3.logon_count, "logonCount");
2970 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
2971 break;
2973 case 4:
2974 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2975 break;
2977 case 5:
2978 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2979 QUERY_STRING(msg, info5.full_name, "displayName");
2980 QUERY_RID (msg, info5.rid, "objectSid");
2981 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2982 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2983 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2984 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2985 QUERY_STRING(msg, info5.profile_path, "profilePath");
2986 QUERY_STRING(msg, info5.description, "description");
2987 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2988 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2989 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2990 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2991 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
2992 QUERY_UINT (msg, info5.logon_count, "logonCount");
2993 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2994 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
2995 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
2996 break;
2998 case 6:
2999 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3000 QUERY_STRING(msg, info6.full_name, "displayName");
3001 break;
3003 case 7:
3004 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3005 break;
3007 case 8:
3008 QUERY_STRING(msg, info8.full_name, "displayName");
3009 break;
3011 case 9:
3012 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3013 break;
3015 case 10:
3016 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3017 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3018 break;
3020 case 11:
3021 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3022 break;
3024 case 12:
3025 QUERY_STRING(msg, info12.profile_path, "profilePath");
3026 break;
3028 case 13:
3029 QUERY_STRING(msg, info13.description, "description");
3030 break;
3032 case 14:
3033 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3034 break;
3036 case 16:
3037 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3038 break;
3040 case 17:
3041 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3042 break;
3044 case 20:
3045 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3046 break;
3048 case 21:
3049 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3050 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3051 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3052 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3053 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3054 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3055 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3056 QUERY_STRING(msg, info21.full_name, "displayName");
3057 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3058 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3059 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3060 QUERY_STRING(msg, info21.profile_path, "profilePath");
3061 QUERY_STRING(msg, info21.description, "description");
3062 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3063 QUERY_STRING(msg, info21.comment, "comment");
3064 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3065 QUERY_RID (msg, info21.rid, "objectSid");
3066 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3067 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3068 info->info21.fields_present = 0x08FFFFFF;
3069 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3070 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3071 QUERY_UINT (msg, info21.logon_count, "logonCount");
3072 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3073 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3074 } else {
3075 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3077 QUERY_UINT (msg, info21.country_code, "countryCode");
3078 QUERY_UINT (msg, info21.code_page, "codePage");
3079 break;
3082 default:
3083 talloc_free(info);
3084 return NT_STATUS_INVALID_INFO_CLASS;
3087 *r->out.info = info;
3089 return NT_STATUS_OK;
3094 samr_SetUserInfo
3096 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3097 struct samr_SetUserInfo *r)
3099 struct dcesrv_handle *h;
3100 struct samr_account_state *a_state;
3101 struct ldb_message *msg;
3102 int ret;
3103 NTSTATUS status = NT_STATUS_OK;
3104 struct ldb_context *sam_ctx;
3106 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3108 a_state = h->data;
3109 sam_ctx = a_state->sam_ctx;
3111 msg = ldb_msg_new(mem_ctx);
3112 if (msg == NULL) {
3113 return NT_STATUS_NO_MEMORY;
3116 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3117 if (!msg->dn) {
3118 return NT_STATUS_NO_MEMORY;
3121 switch (r->in.level) {
3122 case 2:
3123 SET_STRING(msg, info2.comment, "comment");
3124 SET_UINT (msg, info2.country_code, "countryCode");
3125 SET_UINT (msg, info2.code_page, "codePage");
3126 break;
3128 case 4:
3129 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3130 break;
3132 case 6:
3133 SET_STRING(msg, info6.account_name, "samAccountName");
3134 SET_STRING(msg, info6.full_name, "displayName");
3135 break;
3137 case 7:
3138 SET_STRING(msg, info7.account_name, "samAccountName");
3139 break;
3141 case 8:
3142 SET_STRING(msg, info8.full_name, "displayName");
3143 break;
3145 case 9:
3146 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3147 break;
3149 case 10:
3150 SET_STRING(msg, info10.home_directory, "homeDirectory");
3151 SET_STRING(msg, info10.home_drive, "homeDrive");
3152 break;
3154 case 11:
3155 SET_STRING(msg, info11.logon_script, "scriptPath");
3156 break;
3158 case 12:
3159 SET_STRING(msg, info12.profile_path, "profilePath");
3160 break;
3162 case 13:
3163 SET_STRING(msg, info13.description, "description");
3164 break;
3166 case 14:
3167 SET_STRING(msg, info14.workstations, "userWorkstations");
3168 break;
3170 case 16:
3171 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3172 break;
3174 case 17:
3175 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3176 break;
3178 case 18:
3179 status = samr_set_password_buffers(dce_call,
3180 a_state->sam_ctx,
3181 a_state->account_dn,
3182 a_state->domain_state->domain_dn,
3183 mem_ctx,
3184 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3185 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3186 if (!NT_STATUS_IS_OK(status)) {
3187 return status;
3190 if (r->in.info->info18.password_expired > 0) {
3191 struct ldb_message_element *set_el;
3192 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3193 return NT_STATUS_NO_MEMORY;
3195 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3196 set_el->flags = LDB_FLAG_MOD_REPLACE;
3198 break;
3200 case 20:
3201 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3202 break;
3204 case 21:
3205 if (r->in.info->info21.fields_present == 0)
3206 return NT_STATUS_INVALID_PARAMETER;
3208 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3209 IFSET(SAMR_FIELD_LAST_LOGON)
3210 SET_UINT64(msg, info21.last_logon, "lastLogon");
3211 IFSET(SAMR_FIELD_LAST_LOGOFF)
3212 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3213 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3214 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3215 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3216 SET_STRING(msg, info21.account_name, "samAccountName");
3217 IFSET(SAMR_FIELD_FULL_NAME)
3218 SET_STRING(msg, info21.full_name, "displayName");
3219 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3220 SET_STRING(msg, info21.home_directory, "homeDirectory");
3221 IFSET(SAMR_FIELD_HOME_DRIVE)
3222 SET_STRING(msg, info21.home_drive, "homeDrive");
3223 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3224 SET_STRING(msg, info21.logon_script, "scriptPath");
3225 IFSET(SAMR_FIELD_PROFILE_PATH)
3226 SET_STRING(msg, info21.profile_path, "profilePath");
3227 IFSET(SAMR_FIELD_DESCRIPTION)
3228 SET_STRING(msg, info21.description, "description");
3229 IFSET(SAMR_FIELD_WORKSTATIONS)
3230 SET_STRING(msg, info21.workstations, "userWorkstations");
3231 IFSET(SAMR_FIELD_COMMENT)
3232 SET_STRING(msg, info21.comment, "comment");
3233 IFSET(SAMR_FIELD_PARAMETERS)
3234 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3235 IFSET(SAMR_FIELD_PRIMARY_GID)
3236 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3237 IFSET(SAMR_FIELD_ACCT_FLAGS)
3238 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3239 IFSET(SAMR_FIELD_LOGON_HOURS)
3240 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3241 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3242 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3243 IFSET(SAMR_FIELD_NUM_LOGONS)
3244 SET_UINT (msg, info21.logon_count, "logonCount");
3245 IFSET(SAMR_FIELD_COUNTRY_CODE)
3246 SET_UINT (msg, info21.country_code, "countryCode");
3247 IFSET(SAMR_FIELD_CODE_PAGE)
3248 SET_UINT (msg, info21.code_page, "codePage");
3250 /* password change fields */
3251 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3252 return NT_STATUS_ACCESS_DENIED;
3254 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3255 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3256 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3258 if (r->in.info->info21.lm_password_set) {
3259 if ((r->in.info->info21.lm_owf_password.length != 16)
3260 || (r->in.info->info21.lm_owf_password.size != 16)) {
3261 return NT_STATUS_INVALID_PARAMETER;
3264 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3266 if (r->in.info->info21.nt_password_set) {
3267 if ((r->in.info->info21.nt_owf_password.length != 16)
3268 || (r->in.info->info21.nt_owf_password.size != 16)) {
3269 return NT_STATUS_INVALID_PARAMETER;
3272 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3274 status = samr_set_password_buffers(dce_call,
3275 a_state->sam_ctx,
3276 a_state->account_dn,
3277 a_state->domain_state->domain_dn,
3278 mem_ctx,
3279 lm_pwd_hash,
3280 nt_pwd_hash);
3281 if (!NT_STATUS_IS_OK(status)) {
3282 return status;
3287 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3288 NTTIME t = 0;
3289 struct ldb_message_element *set_el;
3290 if (r->in.info->info21.password_expired
3291 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3292 unix_to_nt_time(&t, time(NULL));
3294 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3295 "pwdLastSet", t) != LDB_SUCCESS) {
3296 return NT_STATUS_NO_MEMORY;
3298 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3299 set_el->flags = LDB_FLAG_MOD_REPLACE;
3301 #undef IFSET
3302 break;
3304 case 23:
3305 if (r->in.info->info23.info.fields_present == 0)
3306 return NT_STATUS_INVALID_PARAMETER;
3308 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3309 IFSET(SAMR_FIELD_LAST_LOGON)
3310 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3311 IFSET(SAMR_FIELD_LAST_LOGOFF)
3312 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3313 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3314 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3315 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3316 SET_STRING(msg, info23.info.account_name, "samAccountName");
3317 IFSET(SAMR_FIELD_FULL_NAME)
3318 SET_STRING(msg, info23.info.full_name, "displayName");
3319 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3320 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3321 IFSET(SAMR_FIELD_HOME_DRIVE)
3322 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3323 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3324 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3325 IFSET(SAMR_FIELD_PROFILE_PATH)
3326 SET_STRING(msg, info23.info.profile_path, "profilePath");
3327 IFSET(SAMR_FIELD_DESCRIPTION)
3328 SET_STRING(msg, info23.info.description, "description");
3329 IFSET(SAMR_FIELD_WORKSTATIONS)
3330 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3331 IFSET(SAMR_FIELD_COMMENT)
3332 SET_STRING(msg, info23.info.comment, "comment");
3333 IFSET(SAMR_FIELD_PARAMETERS)
3334 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3335 IFSET(SAMR_FIELD_PRIMARY_GID)
3336 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3337 IFSET(SAMR_FIELD_ACCT_FLAGS)
3338 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3339 IFSET(SAMR_FIELD_LOGON_HOURS)
3340 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3341 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3342 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3343 IFSET(SAMR_FIELD_NUM_LOGONS)
3344 SET_UINT (msg, info23.info.logon_count, "logonCount");
3346 IFSET(SAMR_FIELD_COUNTRY_CODE)
3347 SET_UINT (msg, info23.info.country_code, "countryCode");
3348 IFSET(SAMR_FIELD_CODE_PAGE)
3349 SET_UINT (msg, info23.info.code_page, "codePage");
3351 /* password change fields */
3352 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3353 return NT_STATUS_ACCESS_DENIED;
3355 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3356 status = samr_set_password(dce_call,
3357 a_state->sam_ctx,
3358 a_state->account_dn,
3359 a_state->domain_state->domain_dn,
3360 mem_ctx,
3361 &r->in.info->info23.password);
3362 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3363 status = samr_set_password(dce_call,
3364 a_state->sam_ctx,
3365 a_state->account_dn,
3366 a_state->domain_state->domain_dn,
3367 mem_ctx,
3368 &r->in.info->info23.password);
3370 if (!NT_STATUS_IS_OK(status)) {
3371 return status;
3374 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3375 NTTIME t = 0;
3376 struct ldb_message_element *set_el;
3377 if (r->in.info->info23.info.password_expired
3378 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3379 unix_to_nt_time(&t, time(NULL));
3381 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3382 "pwdLastSet", t) != LDB_SUCCESS) {
3383 return NT_STATUS_NO_MEMORY;
3385 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3386 set_el->flags = LDB_FLAG_MOD_REPLACE;
3388 #undef IFSET
3389 break;
3391 /* the set password levels are handled separately */
3392 case 24:
3393 status = samr_set_password(dce_call,
3394 a_state->sam_ctx,
3395 a_state->account_dn,
3396 a_state->domain_state->domain_dn,
3397 mem_ctx,
3398 &r->in.info->info24.password);
3399 if (!NT_STATUS_IS_OK(status)) {
3400 return status;
3403 if (r->in.info->info24.password_expired > 0) {
3404 struct ldb_message_element *set_el;
3405 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3406 return NT_STATUS_NO_MEMORY;
3408 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3409 set_el->flags = LDB_FLAG_MOD_REPLACE;
3411 break;
3413 case 25:
3414 if (r->in.info->info25.info.fields_present == 0)
3415 return NT_STATUS_INVALID_PARAMETER;
3417 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3418 IFSET(SAMR_FIELD_LAST_LOGON)
3419 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3420 IFSET(SAMR_FIELD_LAST_LOGOFF)
3421 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3422 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3423 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3424 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3425 SET_STRING(msg, info25.info.account_name, "samAccountName");
3426 IFSET(SAMR_FIELD_FULL_NAME)
3427 SET_STRING(msg, info25.info.full_name, "displayName");
3428 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3429 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3430 IFSET(SAMR_FIELD_HOME_DRIVE)
3431 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3432 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3433 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3434 IFSET(SAMR_FIELD_PROFILE_PATH)
3435 SET_STRING(msg, info25.info.profile_path, "profilePath");
3436 IFSET(SAMR_FIELD_DESCRIPTION)
3437 SET_STRING(msg, info25.info.description, "description");
3438 IFSET(SAMR_FIELD_WORKSTATIONS)
3439 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3440 IFSET(SAMR_FIELD_COMMENT)
3441 SET_STRING(msg, info25.info.comment, "comment");
3442 IFSET(SAMR_FIELD_PARAMETERS)
3443 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3444 IFSET(SAMR_FIELD_PRIMARY_GID)
3445 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3446 IFSET(SAMR_FIELD_ACCT_FLAGS)
3447 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3448 IFSET(SAMR_FIELD_LOGON_HOURS)
3449 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3450 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3451 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3452 IFSET(SAMR_FIELD_NUM_LOGONS)
3453 SET_UINT (msg, info25.info.logon_count, "logonCount");
3454 IFSET(SAMR_FIELD_COUNTRY_CODE)
3455 SET_UINT (msg, info25.info.country_code, "countryCode");
3456 IFSET(SAMR_FIELD_CODE_PAGE)
3457 SET_UINT (msg, info25.info.code_page, "codePage");
3459 /* password change fields */
3460 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3461 return NT_STATUS_ACCESS_DENIED;
3463 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3464 status = samr_set_password_ex(dce_call,
3465 a_state->sam_ctx,
3466 a_state->account_dn,
3467 a_state->domain_state->domain_dn,
3468 mem_ctx,
3469 &r->in.info->info25.password);
3470 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3471 status = samr_set_password_ex(dce_call,
3472 a_state->sam_ctx,
3473 a_state->account_dn,
3474 a_state->domain_state->domain_dn,
3475 mem_ctx,
3476 &r->in.info->info25.password);
3478 if (!NT_STATUS_IS_OK(status)) {
3479 return status;
3482 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3483 NTTIME t = 0;
3484 struct ldb_message_element *set_el;
3485 if (r->in.info->info25.info.password_expired
3486 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3487 unix_to_nt_time(&t, time(NULL));
3489 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3490 "pwdLastSet", t) != LDB_SUCCESS) {
3491 return NT_STATUS_NO_MEMORY;
3493 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3494 set_el->flags = LDB_FLAG_MOD_REPLACE;
3496 #undef IFSET
3497 break;
3499 /* the set password levels are handled separately */
3500 case 26:
3501 status = samr_set_password_ex(dce_call,
3502 a_state->sam_ctx,
3503 a_state->account_dn,
3504 a_state->domain_state->domain_dn,
3505 mem_ctx,
3506 &r->in.info->info26.password);
3507 if (!NT_STATUS_IS_OK(status)) {
3508 return status;
3511 if (r->in.info->info26.password_expired > 0) {
3512 struct ldb_message_element *set_el;
3513 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3514 return NT_STATUS_NO_MEMORY;
3516 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3517 set_el->flags = LDB_FLAG_MOD_REPLACE;
3519 break;
3521 default:
3522 /* many info classes are not valid for SetUserInfo */
3523 return NT_STATUS_INVALID_INFO_CLASS;
3526 if (!NT_STATUS_IS_OK(status)) {
3527 return status;
3530 /* modify the samdb record */
3531 if (msg->num_elements > 0) {
3532 ret = ldb_modify(a_state->sam_ctx, msg);
3533 if (ret != LDB_SUCCESS) {
3534 DEBUG(1,("Failed to modify record %s: %s\n",
3535 ldb_dn_get_linearized(a_state->account_dn),
3536 ldb_errstring(a_state->sam_ctx)));
3538 /* we really need samdb.c to return NTSTATUS */
3539 return NT_STATUS_UNSUCCESSFUL;
3543 return NT_STATUS_OK;
3548 samr_GetGroupsForUser
3550 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3551 struct samr_GetGroupsForUser *r)
3553 struct dcesrv_handle *h;
3554 struct samr_account_state *a_state;
3555 struct samr_domain_state *d_state;
3556 struct ldb_message **res;
3557 const char * const attrs[2] = { "objectSid", NULL };
3558 struct samr_RidWithAttributeArray *array;
3559 int i, count;
3561 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3563 a_state = h->data;
3564 d_state = a_state->domain_state;
3566 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3567 d_state->domain_dn, &res,
3568 attrs, d_state->domain_sid,
3569 "(&(member=%s)(|(grouptype=%d)(grouptype=%d))(objectclass=group))",
3570 ldb_dn_get_linearized(a_state->account_dn),
3571 GTYPE_SECURITY_GLOBAL_GROUP,
3572 GTYPE_SECURITY_UNIVERSAL_GROUP);
3573 if (count < 0)
3574 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3576 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3577 if (array == NULL)
3578 return NT_STATUS_NO_MEMORY;
3580 array->count = 0;
3581 array->rids = NULL;
3583 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3584 count + 1);
3585 if (array->rids == NULL)
3586 return NT_STATUS_NO_MEMORY;
3588 /* Adds the primary group */
3589 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3590 ~0, a_state->account_dn,
3591 "primaryGroupID", NULL);
3592 array->rids[0].attributes = SE_GROUP_MANDATORY
3593 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3594 array->count += 1;
3596 /* Adds the additional groups */
3597 for (i = 0; i < count; i++) {
3598 struct dom_sid *group_sid;
3600 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3601 if (group_sid == NULL) {
3602 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3605 array->rids[i + 1].rid =
3606 group_sid->sub_auths[group_sid->num_auths-1];
3607 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3608 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3609 array->count += 1;
3612 *r->out.rids = array;
3614 return NT_STATUS_OK;
3619 samr_QueryDisplayInfo
3621 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3622 struct samr_QueryDisplayInfo *r)
3624 struct dcesrv_handle *h;
3625 struct samr_domain_state *d_state;
3626 struct ldb_message **res;
3627 int i, ldb_cnt;
3628 uint32_t count;
3629 const char * const attrs[] = { "objectSid", "sAMAccountName",
3630 "displayName", "description", "userAccountControl",
3631 "pwdLastSet", NULL };
3632 struct samr_DispEntryFull *entriesFull = NULL;
3633 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3634 struct samr_DispEntryAscii *entriesAscii = NULL;
3635 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3636 const char *filter;
3638 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3640 d_state = h->data;
3642 switch (r->in.level) {
3643 case 1:
3644 case 4:
3645 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3646 "(sAMAccountType=%u))",
3647 ATYPE_NORMAL_ACCOUNT);
3648 break;
3649 case 2:
3650 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3651 "(sAMAccountType=%u))",
3652 ATYPE_WORKSTATION_TRUST);
3653 break;
3654 case 3:
3655 case 5:
3656 filter = talloc_asprintf(mem_ctx,
3657 "(&(|(groupType=%d)(groupType=%d))"
3658 "(objectClass=group))",
3659 GTYPE_SECURITY_UNIVERSAL_GROUP,
3660 GTYPE_SECURITY_GLOBAL_GROUP);
3661 break;
3662 default:
3663 return NT_STATUS_INVALID_INFO_CLASS;
3666 /* search for all requested objects in this domain. This could
3667 possibly be cached and resumed based on resume_key */
3668 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3669 d_state->domain_dn, &res, attrs,
3670 d_state->domain_sid, "%s", filter);
3671 if (ldb_cnt == -1) {
3672 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3674 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3675 return NT_STATUS_OK;
3678 switch (r->in.level) {
3679 case 1:
3680 entriesGeneral = talloc_array(mem_ctx,
3681 struct samr_DispEntryGeneral,
3682 ldb_cnt);
3683 break;
3684 case 2:
3685 entriesFull = talloc_array(mem_ctx,
3686 struct samr_DispEntryFull,
3687 ldb_cnt);
3688 break;
3689 case 3:
3690 entriesFullGroup = talloc_array(mem_ctx,
3691 struct samr_DispEntryFullGroup,
3692 ldb_cnt);
3693 break;
3694 case 4:
3695 case 5:
3696 entriesAscii = talloc_array(mem_ctx,
3697 struct samr_DispEntryAscii,
3698 ldb_cnt);
3699 break;
3702 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3703 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3704 return NT_STATUS_NO_MEMORY;
3706 count = 0;
3708 for (i=0; i<ldb_cnt; i++) {
3709 struct dom_sid *objectsid;
3711 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3712 "objectSid");
3713 if (objectsid == NULL)
3714 continue;
3716 switch(r->in.level) {
3717 case 1:
3718 entriesGeneral[count].idx = count + 1;
3719 entriesGeneral[count].rid =
3720 objectsid->sub_auths[objectsid->num_auths-1];
3721 entriesGeneral[count].acct_flags =
3722 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3723 res[i],
3724 d_state->domain_dn);
3725 entriesGeneral[count].account_name.string =
3726 ldb_msg_find_attr_as_string(res[i],
3727 "sAMAccountName", "");
3728 entriesGeneral[count].full_name.string =
3729 ldb_msg_find_attr_as_string(res[i], "displayName", "");
3730 entriesGeneral[count].description.string =
3731 ldb_msg_find_attr_as_string(res[i], "description", "");
3732 break;
3733 case 2:
3734 entriesFull[count].idx = count + 1;
3735 entriesFull[count].rid =
3736 objectsid->sub_auths[objectsid->num_auths-1];
3738 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3739 entriesFull[count].acct_flags =
3740 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3741 res[i],
3742 d_state->domain_dn) | ACB_NORMAL;
3743 entriesFull[count].account_name.string =
3744 ldb_msg_find_attr_as_string(res[i], "sAMAccountName",
3745 "");
3746 entriesFull[count].description.string =
3747 ldb_msg_find_attr_as_string(res[i], "description", "");
3748 break;
3749 case 3:
3750 entriesFullGroup[count].idx = count + 1;
3751 entriesFullGroup[count].rid =
3752 objectsid->sub_auths[objectsid->num_auths-1];
3753 /* We get a "7" here for groups */
3754 entriesFullGroup[count].acct_flags
3755 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3756 entriesFullGroup[count].account_name.string =
3757 ldb_msg_find_attr_as_string(res[i], "sAMAccountName",
3758 "");
3759 entriesFullGroup[count].description.string =
3760 ldb_msg_find_attr_as_string(res[i], "description", "");
3761 break;
3762 case 4:
3763 case 5:
3764 entriesAscii[count].idx = count + 1;
3765 entriesAscii[count].account_name.string =
3766 ldb_msg_find_attr_as_string(res[i], "sAMAccountName",
3767 "");
3768 break;
3771 count += 1;
3774 *r->out.total_size = count;
3776 if (r->in.start_idx >= count) {
3777 *r->out.returned_size = 0;
3778 switch(r->in.level) {
3779 case 1:
3780 r->out.info->info1.count = *r->out.returned_size;
3781 r->out.info->info1.entries = NULL;
3782 break;
3783 case 2:
3784 r->out.info->info2.count = *r->out.returned_size;
3785 r->out.info->info2.entries = NULL;
3786 break;
3787 case 3:
3788 r->out.info->info3.count = *r->out.returned_size;
3789 r->out.info->info3.entries = NULL;
3790 break;
3791 case 4:
3792 r->out.info->info4.count = *r->out.returned_size;
3793 r->out.info->info4.entries = NULL;
3794 break;
3795 case 5:
3796 r->out.info->info5.count = *r->out.returned_size;
3797 r->out.info->info5.entries = NULL;
3798 break;
3800 } else {
3801 *r->out.returned_size = MIN(count - r->in.start_idx,
3802 r->in.max_entries);
3803 switch(r->in.level) {
3804 case 1:
3805 r->out.info->info1.count = *r->out.returned_size;
3806 r->out.info->info1.entries =
3807 &(entriesGeneral[r->in.start_idx]);
3808 break;
3809 case 2:
3810 r->out.info->info2.count = *r->out.returned_size;
3811 r->out.info->info2.entries =
3812 &(entriesFull[r->in.start_idx]);
3813 break;
3814 case 3:
3815 r->out.info->info3.count = *r->out.returned_size;
3816 r->out.info->info3.entries =
3817 &(entriesFullGroup[r->in.start_idx]);
3818 break;
3819 case 4:
3820 r->out.info->info4.count = *r->out.returned_size;
3821 r->out.info->info4.entries =
3822 &(entriesAscii[r->in.start_idx]);
3823 break;
3824 case 5:
3825 r->out.info->info5.count = *r->out.returned_size;
3826 r->out.info->info5.entries =
3827 &(entriesAscii[r->in.start_idx]);
3828 break;
3832 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3833 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3838 samr_GetDisplayEnumerationIndex
3840 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3841 struct samr_GetDisplayEnumerationIndex *r)
3843 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3848 samr_TestPrivateFunctionsDomain
3850 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3851 struct samr_TestPrivateFunctionsDomain *r)
3853 return NT_STATUS_NOT_IMPLEMENTED;
3858 samr_TestPrivateFunctionsUser
3860 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3861 struct samr_TestPrivateFunctionsUser *r)
3863 return NT_STATUS_NOT_IMPLEMENTED;
3868 samr_GetUserPwInfo
3870 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3871 struct samr_GetUserPwInfo *r)
3873 struct dcesrv_handle *h;
3874 struct samr_account_state *a_state;
3876 ZERO_STRUCTP(r->out.info);
3878 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3880 a_state = h->data;
3882 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3883 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3884 NULL);
3885 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3886 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3888 return NT_STATUS_OK;
3893 samr_RemoveMemberFromForeignDomain
3895 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3896 struct samr_RemoveMemberFromForeignDomain *r)
3898 struct dcesrv_handle *h;
3899 struct samr_domain_state *d_state;
3900 const char *memberdn;
3901 struct ldb_message **res;
3902 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3903 int i, count;
3905 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3907 d_state = h->data;
3909 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3910 "distinguishedName", "(objectSid=%s)",
3911 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3912 /* Nothing to do */
3913 if (memberdn == NULL) {
3914 return NT_STATUS_OK;
3917 /* TODO: Does this call only remove alias members, or does it do this
3918 * for domain groups as well? */
3920 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3921 d_state->domain_dn, &res, attrs,
3922 d_state->domain_sid,
3923 "(&(member=%s)(objectClass=group)"
3924 "(|(groupType=%d)(groupType=%d)))",
3925 memberdn,
3926 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3927 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3929 if (count < 0)
3930 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3932 for (i=0; i<count; i++) {
3933 struct ldb_message *mod;
3935 mod = ldb_msg_new(mem_ctx);
3936 if (mod == NULL) {
3937 return NT_STATUS_NO_MEMORY;
3940 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
3941 if (mod->dn == NULL) {
3942 talloc_free(mod);
3943 continue;
3946 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3947 "member", memberdn) != LDB_SUCCESS)
3948 return NT_STATUS_NO_MEMORY;
3950 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
3951 return NT_STATUS_UNSUCCESSFUL;
3953 talloc_free(mod);
3956 return NT_STATUS_OK;
3961 samr_QueryDomainInfo2
3963 just an alias for samr_QueryDomainInfo
3965 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3966 struct samr_QueryDomainInfo2 *r)
3968 struct samr_QueryDomainInfo r1;
3969 NTSTATUS status;
3971 ZERO_STRUCT(r1.out);
3972 r1.in.domain_handle = r->in.domain_handle;
3973 r1.in.level = r->in.level;
3974 r1.out.info = r->out.info;
3976 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3978 return status;
3983 samr_QueryUserInfo2
3985 just an alias for samr_QueryUserInfo
3987 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3988 struct samr_QueryUserInfo2 *r)
3990 struct samr_QueryUserInfo r1;
3991 NTSTATUS status;
3993 r1.in.user_handle = r->in.user_handle;
3994 r1.in.level = r->in.level;
3995 r1.out.info = r->out.info;
3997 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3999 return status;
4004 samr_QueryDisplayInfo2
4006 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4007 struct samr_QueryDisplayInfo2 *r)
4009 struct samr_QueryDisplayInfo q;
4010 NTSTATUS result;
4012 q.in.domain_handle = r->in.domain_handle;
4013 q.in.level = r->in.level;
4014 q.in.start_idx = r->in.start_idx;
4015 q.in.max_entries = r->in.max_entries;
4016 q.in.buf_size = r->in.buf_size;
4017 q.out.total_size = r->out.total_size;
4018 q.out.returned_size = r->out.returned_size;
4019 q.out.info = r->out.info;
4021 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4023 return result;
4028 samr_GetDisplayEnumerationIndex2
4030 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4031 struct samr_GetDisplayEnumerationIndex2 *r)
4033 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4038 samr_QueryDisplayInfo3
4040 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4041 struct samr_QueryDisplayInfo3 *r)
4043 struct samr_QueryDisplayInfo q;
4044 NTSTATUS result;
4046 q.in.domain_handle = r->in.domain_handle;
4047 q.in.level = r->in.level;
4048 q.in.start_idx = r->in.start_idx;
4049 q.in.max_entries = r->in.max_entries;
4050 q.in.buf_size = r->in.buf_size;
4051 q.out.total_size = r->out.total_size;
4052 q.out.returned_size = r->out.returned_size;
4053 q.out.info = r->out.info;
4055 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4057 return result;
4062 samr_AddMultipleMembersToAlias
4064 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4065 struct samr_AddMultipleMembersToAlias *r)
4067 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4072 samr_RemoveMultipleMembersFromAlias
4074 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4075 struct samr_RemoveMultipleMembersFromAlias *r)
4077 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4082 samr_GetDomPwInfo
4084 this fetches the default password properties for a domain
4086 note that w2k3 completely ignores the domain name in this call, and
4087 always returns the information for the servers primary domain
4089 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4090 struct samr_GetDomPwInfo *r)
4092 struct ldb_message **msgs;
4093 int ret;
4094 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4095 struct ldb_context *sam_ctx;
4097 ZERO_STRUCTP(r->out.info);
4099 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4100 dce_call->conn->dce_ctx->lp_ctx,
4101 dce_call->conn->auth_state.session_info, 0);
4102 if (sam_ctx == NULL) {
4103 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4106 /* The domain name in this call is ignored */
4107 ret = gendb_search_dn(sam_ctx,
4108 mem_ctx, NULL, &msgs, attrs);
4109 if (ret <= 0) {
4110 talloc_free(sam_ctx);
4112 return NT_STATUS_NO_SUCH_DOMAIN;
4114 if (ret > 1) {
4115 talloc_free(msgs);
4116 talloc_free(sam_ctx);
4118 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4121 r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4122 "minPwdLength", 0);
4123 r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4124 "pwdProperties", 1);
4126 talloc_free(msgs);
4127 talloc_unlink(mem_ctx, sam_ctx);
4129 return NT_STATUS_OK;
4134 samr_Connect2
4136 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4137 struct samr_Connect2 *r)
4139 struct samr_Connect c;
4141 c.in.system_name = NULL;
4142 c.in.access_mask = r->in.access_mask;
4143 c.out.connect_handle = r->out.connect_handle;
4145 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4150 samr_SetUserInfo2
4152 just an alias for samr_SetUserInfo
4154 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4155 struct samr_SetUserInfo2 *r)
4157 struct samr_SetUserInfo r2;
4159 r2.in.user_handle = r->in.user_handle;
4160 r2.in.level = r->in.level;
4161 r2.in.info = r->in.info;
4163 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4168 samr_SetBootKeyInformation
4170 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4171 struct samr_SetBootKeyInformation *r)
4173 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4178 samr_GetBootKeyInformation
4180 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4181 struct samr_GetBootKeyInformation *r)
4183 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4188 samr_Connect3
4190 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4191 struct samr_Connect3 *r)
4193 struct samr_Connect c;
4195 c.in.system_name = NULL;
4196 c.in.access_mask = r->in.access_mask;
4197 c.out.connect_handle = r->out.connect_handle;
4199 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4204 samr_Connect4
4206 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4207 struct samr_Connect4 *r)
4209 struct samr_Connect c;
4211 c.in.system_name = NULL;
4212 c.in.access_mask = r->in.access_mask;
4213 c.out.connect_handle = r->out.connect_handle;
4215 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4220 samr_Connect5
4222 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4223 struct samr_Connect5 *r)
4225 struct samr_Connect c;
4226 NTSTATUS status;
4228 c.in.system_name = NULL;
4229 c.in.access_mask = r->in.access_mask;
4230 c.out.connect_handle = r->out.connect_handle;
4232 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4234 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4235 r->out.info_out->info1.unknown2 = 0;
4236 *r->out.level_out = r->in.level_in;
4238 return status;
4243 samr_RidToSid
4245 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4246 struct samr_RidToSid *r)
4248 struct samr_domain_state *d_state;
4249 struct dcesrv_handle *h;
4251 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4253 d_state = h->data;
4255 /* form the users SID */
4256 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4257 if (!*r->out.sid) {
4258 return NT_STATUS_NO_MEMORY;
4261 return NT_STATUS_OK;
4266 samr_SetDsrmPassword
4268 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4269 struct samr_SetDsrmPassword *r)
4271 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4276 samr_ValidatePassword
4278 For now the call checks the password complexity (if active) and the minimum
4279 password length on level 2 and 3. Level 1 is ignored for now.
4281 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4282 TALLOC_CTX *mem_ctx,
4283 struct samr_ValidatePassword *r)
4285 struct samr_GetDomPwInfo r2;
4286 struct samr_PwInfo pwInfo;
4287 DATA_BLOB password;
4288 enum samr_ValidationStatus res;
4289 NTSTATUS status;
4291 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4293 r2.in.domain_name = NULL;
4294 r2.out.info = &pwInfo;
4295 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4296 if (!NT_STATUS_IS_OK(status)) {
4297 return status;
4300 switch (r->in.level) {
4301 case NetValidateAuthentication:
4302 /* we don't support this yet */
4303 return NT_STATUS_NOT_SUPPORTED;
4304 break;
4305 case NetValidatePasswordChange:
4306 password = data_blob_const(r->in.req->req2.password.string,
4307 r->in.req->req2.password.length);
4308 res = samdb_check_password(&password,
4309 pwInfo.password_properties,
4310 pwInfo.min_password_length);
4311 (*r->out.rep)->ctr2.status = res;
4312 break;
4313 case NetValidatePasswordReset:
4314 password = data_blob_const(r->in.req->req3.password.string,
4315 r->in.req->req3.password.length);
4316 res = samdb_check_password(&password,
4317 pwInfo.password_properties,
4318 pwInfo.min_password_length);
4319 (*r->out.rep)->ctr3.status = res;
4320 break;
4321 default:
4322 return NT_STATUS_INVALID_INFO_CLASS;
4323 break;
4326 return NT_STATUS_OK;
4330 /* include the generated boilerplate */
4331 #include "librpc/gen_ndr/ndr_samr_s.c"