s4/heimdal_build: use GetTimeOfDay macro instead of gettimeofday
[Samba/ita.git] / source4 / rpc_server / samr / dcesrv_samr.c
blobe222a41d26412049306ae9d9545b299ca9c2212f
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 = samdb_result_string(msg, attr, "");
47 #define QUERY_UINT(msg, field, attr) \
48 info->field = samdb_result_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 = samdb_result_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);
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 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
466 info->password_history_length =
467 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
468 info->password_properties =
469 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
470 info->max_password_age =
471 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
472 info->min_password_age =
473 samdb_result_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 = samdb_result_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 = samdb_result_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 samdb_result_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 = samdb_result_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 samdb_result_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 = samdb_result_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 = samdb_result_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_RidTypeArray *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_RidTypeArray);
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->types = talloc_array(array, uint32_t, num_members);
2155 if (array->types == 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->types[array->count] = 7; /* RID type of some kind, not sure what the value means. */
2172 array->count++;
2175 *r->out.rids = array;
2177 return NT_STATUS_OK;
2182 samr_SetMemberAttributesOfGroup
2184 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2185 struct samr_SetMemberAttributesOfGroup *r)
2187 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2192 samr_OpenAlias
2194 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2195 struct samr_OpenAlias *r)
2197 struct samr_domain_state *d_state;
2198 struct samr_account_state *a_state;
2199 struct dcesrv_handle *h;
2200 const char *alias_name;
2201 struct dom_sid *sid;
2202 struct ldb_message **msgs;
2203 struct dcesrv_handle *g_handle;
2204 const char * const attrs[2] = { "sAMAccountName", NULL };
2205 int ret;
2207 ZERO_STRUCTP(r->out.alias_handle);
2209 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2211 d_state = h->data;
2213 /* form the alias SID */
2214 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2215 if (sid == NULL)
2216 return NT_STATUS_NO_MEMORY;
2218 /* search for the group record */
2219 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2220 "(&(objectSid=%s)(objectclass=group)"
2221 "(|(grouptype=%d)(grouptype=%d)))",
2222 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2223 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2224 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2225 if (ret == 0) {
2226 return NT_STATUS_NO_SUCH_ALIAS;
2228 if (ret != 1) {
2229 DEBUG(0,("Found %d records matching sid %s\n",
2230 ret, dom_sid_string(mem_ctx, sid)));
2231 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2234 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2235 if (alias_name == NULL) {
2236 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2237 dom_sid_string(mem_ctx, sid)));
2238 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2241 a_state = talloc(mem_ctx, struct samr_account_state);
2242 if (!a_state) {
2243 return NT_STATUS_NO_MEMORY;
2245 a_state->sam_ctx = d_state->sam_ctx;
2246 a_state->access_mask = r->in.access_mask;
2247 a_state->domain_state = talloc_reference(a_state, d_state);
2248 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2249 a_state->account_sid = talloc_steal(a_state, sid);
2250 a_state->account_name = talloc_strdup(a_state, alias_name);
2251 if (!a_state->account_name) {
2252 return NT_STATUS_NO_MEMORY;
2255 /* create the policy handle */
2256 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2257 if (!g_handle) {
2258 return NT_STATUS_NO_MEMORY;
2261 g_handle->data = talloc_steal(g_handle, a_state);
2263 *r->out.alias_handle = g_handle->wire_handle;
2265 return NT_STATUS_OK;
2270 samr_QueryAliasInfo
2272 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2273 struct samr_QueryAliasInfo *r)
2275 struct dcesrv_handle *h;
2276 struct samr_account_state *a_state;
2277 struct ldb_message *msg, **res;
2278 const char * const attrs[4] = { "sAMAccountName", "description",
2279 "numMembers", NULL };
2280 int ret;
2281 union samr_AliasInfo *info;
2283 *r->out.info = NULL;
2285 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2287 a_state = h->data;
2289 /* pull all the alias attributes */
2290 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2291 a_state->account_dn, &res, attrs);
2292 if (ret == 0) {
2293 return NT_STATUS_NO_SUCH_ALIAS;
2295 if (ret != 1) {
2296 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2298 msg = res[0];
2300 /* allocate the info structure */
2301 info = talloc_zero(mem_ctx, union samr_AliasInfo);
2302 if (info == NULL) {
2303 return NT_STATUS_NO_MEMORY;
2306 switch(r->in.level) {
2307 case ALIASINFOALL:
2308 QUERY_STRING(msg, all.name, "sAMAccountName");
2309 QUERY_UINT (msg, all.num_members, "numMembers");
2310 QUERY_STRING(msg, all.description, "description");
2311 break;
2312 case ALIASINFONAME:
2313 QUERY_STRING(msg, name, "sAMAccountName");
2314 break;
2315 case ALIASINFODESCRIPTION:
2316 QUERY_STRING(msg, description, "description");
2317 break;
2318 default:
2319 talloc_free(info);
2320 return NT_STATUS_INVALID_INFO_CLASS;
2323 *r->out.info = info;
2325 return NT_STATUS_OK;
2330 samr_SetAliasInfo
2332 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2333 struct samr_SetAliasInfo *r)
2335 struct dcesrv_handle *h;
2336 struct samr_account_state *a_state;
2337 struct ldb_message *msg;
2338 struct ldb_context *sam_ctx;
2339 int ret;
2341 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2343 a_state = h->data;
2344 sam_ctx = a_state->sam_ctx;
2346 msg = ldb_msg_new(mem_ctx);
2347 if (msg == NULL) {
2348 return NT_STATUS_NO_MEMORY;
2351 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2352 if (!msg->dn) {
2353 return NT_STATUS_NO_MEMORY;
2356 switch (r->in.level) {
2357 case ALIASINFODESCRIPTION:
2358 SET_STRING(msg, description, "description");
2359 break;
2360 case ALIASINFONAME:
2361 /* On W2k3 this does not change the name, it changes the
2362 * sAMAccountName attribute */
2363 SET_STRING(msg, name, "sAMAccountName");
2364 break;
2365 default:
2366 return NT_STATUS_INVALID_INFO_CLASS;
2369 /* modify the samdb record */
2370 ret = ldb_modify(a_state->sam_ctx, msg);
2371 if (ret != LDB_SUCCESS) {
2372 /* we really need samdb.c to return NTSTATUS */
2373 return NT_STATUS_UNSUCCESSFUL;
2376 return NT_STATUS_OK;
2381 samr_DeleteDomAlias
2383 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2384 struct samr_DeleteDomAlias *r)
2386 struct dcesrv_handle *h;
2387 struct samr_account_state *a_state;
2388 int ret;
2390 *r->out.alias_handle = *r->in.alias_handle;
2392 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2394 a_state = h->data;
2396 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2397 if (ret != LDB_SUCCESS) {
2398 return NT_STATUS_UNSUCCESSFUL;
2401 talloc_free(h);
2402 ZERO_STRUCTP(r->out.alias_handle);
2404 return NT_STATUS_OK;
2409 samr_AddAliasMember
2411 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2412 struct samr_AddAliasMember *r)
2414 struct dcesrv_handle *h;
2415 struct samr_account_state *a_state;
2416 struct samr_domain_state *d_state;
2417 struct ldb_message *mod;
2418 struct ldb_message **msgs;
2419 const char * const attrs[] = { NULL };
2420 struct ldb_dn *memberdn = NULL;
2421 int ret;
2422 NTSTATUS status;
2424 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2426 a_state = h->data;
2427 d_state = a_state->domain_state;
2429 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2430 &msgs, attrs, "(objectsid=%s)",
2431 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2433 if (ret == 1) {
2434 memberdn = msgs[0]->dn;
2435 } else if (ret == 0) {
2436 status = samdb_create_foreign_security_principal(
2437 d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2438 if (!NT_STATUS_IS_OK(status)) {
2439 return status;
2441 } else {
2442 DEBUG(0,("Found %d records matching sid %s\n",
2443 ret, dom_sid_string(mem_ctx, r->in.sid)));
2444 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2447 if (memberdn == NULL) {
2448 DEBUG(0, ("Could not find memberdn\n"));
2449 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2452 mod = ldb_msg_new(mem_ctx);
2453 if (mod == NULL) {
2454 return NT_STATUS_NO_MEMORY;
2457 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2459 ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2460 ldb_dn_alloc_linearized(mem_ctx, memberdn));
2461 if (ret != LDB_SUCCESS) {
2462 return NT_STATUS_UNSUCCESSFUL;
2465 ret = ldb_modify(a_state->sam_ctx, mod);
2466 switch (ret) {
2467 case LDB_SUCCESS:
2468 return NT_STATUS_OK;
2469 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2470 case LDB_ERR_ENTRY_ALREADY_EXISTS:
2471 return NT_STATUS_MEMBER_IN_GROUP;
2472 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2473 return NT_STATUS_ACCESS_DENIED;
2474 default:
2475 return NT_STATUS_UNSUCCESSFUL;
2481 samr_DeleteAliasMember
2483 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2484 struct samr_DeleteAliasMember *r)
2486 struct dcesrv_handle *h;
2487 struct samr_account_state *a_state;
2488 struct samr_domain_state *d_state;
2489 struct ldb_message *mod;
2490 const char *memberdn;
2491 int ret;
2493 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2495 a_state = h->data;
2496 d_state = a_state->domain_state;
2498 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2499 "distinguishedName", "(objectSid=%s)",
2500 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2501 if (memberdn == NULL) {
2502 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2505 mod = ldb_msg_new(mem_ctx);
2506 if (mod == NULL) {
2507 return NT_STATUS_NO_MEMORY;
2510 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2512 ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2513 memberdn);
2514 if (ret != LDB_SUCCESS) {
2515 return NT_STATUS_UNSUCCESSFUL;
2518 ret = ldb_modify(a_state->sam_ctx, mod);
2519 switch (ret) {
2520 case LDB_SUCCESS:
2521 return NT_STATUS_OK;
2522 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2523 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2524 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2525 return NT_STATUS_ACCESS_DENIED;
2526 default:
2527 return NT_STATUS_UNSUCCESSFUL;
2533 samr_GetMembersInAlias
2535 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2536 struct samr_GetMembersInAlias *r)
2538 struct dcesrv_handle *h;
2539 struct samr_account_state *a_state;
2540 struct samr_domain_state *d_state;
2541 struct lsa_SidPtr *array;
2542 unsigned int i, num_members;
2543 struct dom_sid *members;
2544 NTSTATUS status;
2546 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2548 a_state = h->data;
2549 d_state = a_state->domain_state;
2551 status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2552 a_state->account_dn, &members,
2553 &num_members);
2554 if (!NT_STATUS_IS_OK(status)) {
2555 return status;
2558 if (num_members == 0) {
2559 r->out.sids->sids = NULL;
2561 return NT_STATUS_OK;
2564 array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2565 if (array == NULL) {
2566 return NT_STATUS_NO_MEMORY;
2569 for (i=0; i<num_members; i++) {
2570 array[i].sid = &members[i];
2573 r->out.sids->num_sids = num_members;
2574 r->out.sids->sids = array;
2576 return NT_STATUS_OK;
2580 samr_OpenUser
2582 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2583 struct samr_OpenUser *r)
2585 struct samr_domain_state *d_state;
2586 struct samr_account_state *a_state;
2587 struct dcesrv_handle *h;
2588 const char *account_name;
2589 struct dom_sid *sid;
2590 struct ldb_message **msgs;
2591 struct dcesrv_handle *u_handle;
2592 const char * const attrs[2] = { "sAMAccountName", NULL };
2593 int ret;
2595 ZERO_STRUCTP(r->out.user_handle);
2597 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2599 d_state = h->data;
2601 /* form the users SID */
2602 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2603 if (!sid) {
2604 return NT_STATUS_NO_MEMORY;
2607 /* search for the user record */
2608 ret = gendb_search(d_state->sam_ctx,
2609 mem_ctx, d_state->domain_dn, &msgs, attrs,
2610 "(&(objectSid=%s)(objectclass=user))",
2611 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2612 if (ret == 0) {
2613 return NT_STATUS_NO_SUCH_USER;
2615 if (ret != 1) {
2616 DEBUG(0,("Found %d records matching sid %s\n", ret,
2617 dom_sid_string(mem_ctx, sid)));
2618 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2621 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2622 if (account_name == NULL) {
2623 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2624 dom_sid_string(mem_ctx, sid)));
2625 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2628 a_state = talloc(mem_ctx, struct samr_account_state);
2629 if (!a_state) {
2630 return NT_STATUS_NO_MEMORY;
2632 a_state->sam_ctx = d_state->sam_ctx;
2633 a_state->access_mask = r->in.access_mask;
2634 a_state->domain_state = talloc_reference(a_state, d_state);
2635 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2636 a_state->account_sid = talloc_steal(a_state, sid);
2637 a_state->account_name = talloc_strdup(a_state, account_name);
2638 if (!a_state->account_name) {
2639 return NT_STATUS_NO_MEMORY;
2642 /* create the policy handle */
2643 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2644 if (!u_handle) {
2645 return NT_STATUS_NO_MEMORY;
2648 u_handle->data = talloc_steal(u_handle, a_state);
2650 *r->out.user_handle = u_handle->wire_handle;
2652 return NT_STATUS_OK;
2658 samr_DeleteUser
2660 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2661 struct samr_DeleteUser *r)
2663 struct dcesrv_handle *h;
2664 struct samr_account_state *a_state;
2665 int ret;
2667 *r->out.user_handle = *r->in.user_handle;
2669 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2671 a_state = h->data;
2673 ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2674 if (ret != LDB_SUCCESS) {
2675 DEBUG(1, ("Failed to delete user: %s: %s\n",
2676 ldb_dn_get_linearized(a_state->account_dn),
2677 ldb_errstring(a_state->sam_ctx)));
2678 return NT_STATUS_UNSUCCESSFUL;
2681 talloc_free(h);
2682 ZERO_STRUCTP(r->out.user_handle);
2684 return NT_STATUS_OK;
2689 samr_QueryUserInfo
2691 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2692 struct samr_QueryUserInfo *r)
2694 struct dcesrv_handle *h;
2695 struct samr_account_state *a_state;
2696 struct ldb_message *msg, **res;
2697 int ret;
2698 struct ldb_context *sam_ctx;
2700 const char * const *attrs = NULL;
2701 union samr_UserInfo *info;
2703 *r->out.info = NULL;
2705 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2707 a_state = h->data;
2708 sam_ctx = a_state->sam_ctx;
2710 /* fill in the reply */
2711 switch (r->in.level) {
2712 case 1:
2714 static const char * const attrs2[] = {"sAMAccountName",
2715 "displayName",
2716 "primaryroupID",
2717 "description",
2718 "comment",
2719 NULL};
2720 attrs = attrs2;
2721 break;
2723 case 2:
2725 static const char * const attrs2[] = {"comment",
2726 "countryCode",
2727 "codePage",
2728 NULL};
2729 attrs = attrs2;
2730 break;
2732 case 3:
2734 static const char * const attrs2[] = {"sAMAccountName",
2735 "displayName",
2736 "objectSid",
2737 "primaryGroupID",
2738 "homeDirectory",
2739 "homeDrive",
2740 "scriptPath",
2741 "profilePath",
2742 "userWorkstations",
2743 "lastLogon",
2744 "lastLogoff",
2745 "pwdLastSet",
2746 "logonHours",
2747 "badPwdCount",
2748 "logonCount",
2749 "userAccountControl",
2750 NULL};
2751 attrs = attrs2;
2752 break;
2754 case 4:
2756 static const char * const attrs2[] = {"logonHours",
2757 NULL};
2758 attrs = attrs2;
2759 break;
2761 case 5:
2763 static const char * const attrs2[] = {"sAMAccountName",
2764 "displayName",
2765 "objectSid",
2766 "primaryGroupID",
2767 "homeDirectory",
2768 "homeDrive",
2769 "scriptPath",
2770 "profilePath",
2771 "description",
2772 "userWorkstations",
2773 "lastLogon",
2774 "lastLogoff",
2775 "logonHours",
2776 "badPwdCount",
2777 "logonCount",
2778 "pwdLastSet",
2779 "accountExpires",
2780 "userAccountControl",
2781 NULL};
2782 attrs = attrs2;
2783 break;
2785 case 6:
2787 static const char * const attrs2[] = {"sAMAccountName",
2788 "displayName",
2789 NULL};
2790 attrs = attrs2;
2791 break;
2793 case 7:
2795 static const char * const attrs2[] = {"sAMAccountName",
2796 NULL};
2797 attrs = attrs2;
2798 break;
2800 case 8:
2802 static const char * const attrs2[] = {"displayName",
2803 NULL};
2804 attrs = attrs2;
2805 break;
2807 case 9:
2809 static const char * const attrs2[] = {"primaryGroupID",
2810 NULL};
2811 attrs = attrs2;
2812 break;
2814 case 10:
2816 static const char * const attrs2[] = {"homeDirectory",
2817 "homeDrive",
2818 NULL};
2819 attrs = attrs2;
2820 break;
2822 case 11:
2824 static const char * const attrs2[] = {"scriptPath",
2825 NULL};
2826 attrs = attrs2;
2827 break;
2829 case 12:
2831 static const char * const attrs2[] = {"profilePath",
2832 NULL};
2833 attrs = attrs2;
2834 break;
2836 case 13:
2838 static const char * const attrs2[] = {"description",
2839 NULL};
2840 attrs = attrs2;
2841 break;
2843 case 14:
2845 static const char * const attrs2[] = {"userWorkstations",
2846 NULL};
2847 attrs = attrs2;
2848 break;
2850 case 16:
2852 static const char * const attrs2[] = {"userAccountControl",
2853 "pwdLastSet",
2854 NULL};
2855 attrs = attrs2;
2856 break;
2858 case 17:
2860 static const char * const attrs2[] = {"accountExpires",
2861 NULL};
2862 attrs = attrs2;
2863 break;
2865 case 18:
2867 return NT_STATUS_NOT_SUPPORTED;
2869 case 20:
2871 static const char * const attrs2[] = {"userParameters",
2872 NULL};
2873 attrs = attrs2;
2874 break;
2876 case 21:
2878 static const char * const attrs2[] = {"lastLogon",
2879 "lastLogoff",
2880 "pwdLastSet",
2881 "accountExpires",
2882 "sAMAccountName",
2883 "displayName",
2884 "homeDirectory",
2885 "homeDrive",
2886 "scriptPath",
2887 "profilePath",
2888 "description",
2889 "userWorkstations",
2890 "comment",
2891 "userParameters",
2892 "objectSid",
2893 "primaryGroupID",
2894 "userAccountControl",
2895 "logonHours",
2896 "badPwdCount",
2897 "logonCount",
2898 "countryCode",
2899 "codePage",
2900 NULL};
2901 attrs = attrs2;
2902 break;
2904 case 23:
2905 case 24:
2906 case 25:
2907 case 26:
2909 return NT_STATUS_NOT_SUPPORTED;
2911 default:
2913 return NT_STATUS_INVALID_INFO_CLASS;
2917 /* pull all the user attributes */
2918 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2919 a_state->account_dn, &res, attrs);
2920 if (ret == 0) {
2921 return NT_STATUS_NO_SUCH_USER;
2923 if (ret != 1) {
2924 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2926 msg = res[0];
2928 /* allocate the info structure */
2929 info = talloc_zero(mem_ctx, union samr_UserInfo);
2930 if (info == NULL) {
2931 return NT_STATUS_NO_MEMORY;
2934 /* fill in the reply */
2935 switch (r->in.level) {
2936 case 1:
2937 QUERY_STRING(msg, info1.account_name, "sAMAccountName");
2938 QUERY_STRING(msg, info1.full_name, "displayName");
2939 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2940 QUERY_STRING(msg, info1.description, "description");
2941 QUERY_STRING(msg, info1.comment, "comment");
2942 break;
2944 case 2:
2945 QUERY_STRING(msg, info2.comment, "comment");
2946 QUERY_UINT (msg, info2.country_code, "countryCode");
2947 QUERY_UINT (msg, info2.code_page, "codePage");
2948 break;
2950 case 3:
2951 QUERY_STRING(msg, info3.account_name, "sAMAccountName");
2952 QUERY_STRING(msg, info3.full_name, "displayName");
2953 QUERY_RID (msg, info3.rid, "objectSid");
2954 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2955 QUERY_STRING(msg, info3.home_directory, "homeDirectory");
2956 QUERY_STRING(msg, info3.home_drive, "homeDrive");
2957 QUERY_STRING(msg, info3.logon_script, "scriptPath");
2958 QUERY_STRING(msg, info3.profile_path, "profilePath");
2959 QUERY_STRING(msg, info3.workstations, "userWorkstations");
2960 QUERY_UINT64(msg, info3.last_logon, "lastLogon");
2961 QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
2962 QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
2963 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2964 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2965 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2966 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2967 QUERY_UINT (msg, info3.logon_count, "logonCount");
2968 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
2969 break;
2971 case 4:
2972 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2973 break;
2975 case 5:
2976 QUERY_STRING(msg, info5.account_name, "sAMAccountName");
2977 QUERY_STRING(msg, info5.full_name, "displayName");
2978 QUERY_RID (msg, info5.rid, "objectSid");
2979 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2980 QUERY_STRING(msg, info5.home_directory, "homeDirectory");
2981 QUERY_STRING(msg, info5.home_drive, "homeDrive");
2982 QUERY_STRING(msg, info5.logon_script, "scriptPath");
2983 QUERY_STRING(msg, info5.profile_path, "profilePath");
2984 QUERY_STRING(msg, info5.description, "description");
2985 QUERY_STRING(msg, info5.workstations, "userWorkstations");
2986 QUERY_UINT64(msg, info5.last_logon, "lastLogon");
2987 QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
2988 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2989 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
2990 QUERY_UINT (msg, info5.logon_count, "logonCount");
2991 QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
2992 QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
2993 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
2994 break;
2996 case 6:
2997 QUERY_STRING(msg, info6.account_name, "sAMAccountName");
2998 QUERY_STRING(msg, info6.full_name, "displayName");
2999 break;
3001 case 7:
3002 QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3003 break;
3005 case 8:
3006 QUERY_STRING(msg, info8.full_name, "displayName");
3007 break;
3009 case 9:
3010 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3011 break;
3013 case 10:
3014 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3015 QUERY_STRING(msg, info10.home_drive, "homeDrive");
3016 break;
3018 case 11:
3019 QUERY_STRING(msg, info11.logon_script, "scriptPath");
3020 break;
3022 case 12:
3023 QUERY_STRING(msg, info12.profile_path, "profilePath");
3024 break;
3026 case 13:
3027 QUERY_STRING(msg, info13.description, "description");
3028 break;
3030 case 14:
3031 QUERY_STRING(msg, info14.workstations, "userWorkstations");
3032 break;
3034 case 16:
3035 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3036 break;
3038 case 17:
3039 QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3040 break;
3042 case 20:
3043 QUERY_PARAMETERS(msg, info20.parameters, "userParameters");
3044 break;
3046 case 21:
3047 QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3048 QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3049 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3050 QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3051 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3052 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3053 QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3054 QUERY_STRING(msg, info21.full_name, "displayName");
3055 QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3056 QUERY_STRING(msg, info21.home_drive, "homeDrive");
3057 QUERY_STRING(msg, info21.logon_script, "scriptPath");
3058 QUERY_STRING(msg, info21.profile_path, "profilePath");
3059 QUERY_STRING(msg, info21.description, "description");
3060 QUERY_STRING(msg, info21.workstations, "userWorkstations");
3061 QUERY_STRING(msg, info21.comment, "comment");
3062 QUERY_PARAMETERS(msg, info21.parameters, "userParameters");
3063 QUERY_RID (msg, info21.rid, "objectSid");
3064 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3065 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3066 info->info21.fields_present = 0x08FFFFFF;
3067 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3068 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3069 QUERY_UINT (msg, info21.logon_count, "logonCount");
3070 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3071 info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3072 } else {
3073 info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3075 QUERY_UINT (msg, info21.country_code, "countryCode");
3076 QUERY_UINT (msg, info21.code_page, "codePage");
3077 break;
3080 default:
3081 talloc_free(info);
3082 return NT_STATUS_INVALID_INFO_CLASS;
3085 *r->out.info = info;
3087 return NT_STATUS_OK;
3092 samr_SetUserInfo
3094 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3095 struct samr_SetUserInfo *r)
3097 struct dcesrv_handle *h;
3098 struct samr_account_state *a_state;
3099 struct ldb_message *msg;
3100 int ret;
3101 NTSTATUS status = NT_STATUS_OK;
3102 struct ldb_context *sam_ctx;
3104 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3106 a_state = h->data;
3107 sam_ctx = a_state->sam_ctx;
3109 msg = ldb_msg_new(mem_ctx);
3110 if (msg == NULL) {
3111 return NT_STATUS_NO_MEMORY;
3114 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3115 if (!msg->dn) {
3116 return NT_STATUS_NO_MEMORY;
3119 switch (r->in.level) {
3120 case 2:
3121 SET_STRING(msg, info2.comment, "comment");
3122 SET_UINT (msg, info2.country_code, "countryCode");
3123 SET_UINT (msg, info2.code_page, "codePage");
3124 break;
3126 case 4:
3127 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3128 break;
3130 case 6:
3131 SET_STRING(msg, info6.account_name, "samAccountName");
3132 SET_STRING(msg, info6.full_name, "displayName");
3133 break;
3135 case 7:
3136 SET_STRING(msg, info7.account_name, "samAccountName");
3137 break;
3139 case 8:
3140 SET_STRING(msg, info8.full_name, "displayName");
3141 break;
3143 case 9:
3144 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3145 break;
3147 case 10:
3148 SET_STRING(msg, info10.home_directory, "homeDirectory");
3149 SET_STRING(msg, info10.home_drive, "homeDrive");
3150 break;
3152 case 11:
3153 SET_STRING(msg, info11.logon_script, "scriptPath");
3154 break;
3156 case 12:
3157 SET_STRING(msg, info12.profile_path, "profilePath");
3158 break;
3160 case 13:
3161 SET_STRING(msg, info13.description, "description");
3162 break;
3164 case 14:
3165 SET_STRING(msg, info14.workstations, "userWorkstations");
3166 break;
3168 case 16:
3169 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3170 break;
3172 case 17:
3173 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3174 break;
3176 case 18:
3177 status = samr_set_password_buffers(dce_call,
3178 a_state->sam_ctx,
3179 a_state->account_dn,
3180 a_state->domain_state->domain_dn,
3181 mem_ctx,
3182 r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3183 r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3184 if (!NT_STATUS_IS_OK(status)) {
3185 return status;
3188 if (r->in.info->info18.password_expired > 0) {
3189 struct ldb_message_element *set_el;
3190 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3191 return NT_STATUS_NO_MEMORY;
3193 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3194 set_el->flags = LDB_FLAG_MOD_REPLACE;
3196 break;
3198 case 20:
3199 SET_PARAMETERS(msg, info20.parameters, "userParameters");
3200 break;
3202 case 21:
3203 if (r->in.info->info21.fields_present == 0)
3204 return NT_STATUS_INVALID_PARAMETER;
3206 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3207 IFSET(SAMR_FIELD_LAST_LOGON)
3208 SET_UINT64(msg, info21.last_logon, "lastLogon");
3209 IFSET(SAMR_FIELD_LAST_LOGOFF)
3210 SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3211 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3212 SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3213 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3214 SET_STRING(msg, info21.account_name, "samAccountName");
3215 IFSET(SAMR_FIELD_FULL_NAME)
3216 SET_STRING(msg, info21.full_name, "displayName");
3217 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3218 SET_STRING(msg, info21.home_directory, "homeDirectory");
3219 IFSET(SAMR_FIELD_HOME_DRIVE)
3220 SET_STRING(msg, info21.home_drive, "homeDrive");
3221 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3222 SET_STRING(msg, info21.logon_script, "scriptPath");
3223 IFSET(SAMR_FIELD_PROFILE_PATH)
3224 SET_STRING(msg, info21.profile_path, "profilePath");
3225 IFSET(SAMR_FIELD_DESCRIPTION)
3226 SET_STRING(msg, info21.description, "description");
3227 IFSET(SAMR_FIELD_WORKSTATIONS)
3228 SET_STRING(msg, info21.workstations, "userWorkstations");
3229 IFSET(SAMR_FIELD_COMMENT)
3230 SET_STRING(msg, info21.comment, "comment");
3231 IFSET(SAMR_FIELD_PARAMETERS)
3232 SET_PARAMETERS(msg, info21.parameters, "userParameters");
3233 IFSET(SAMR_FIELD_PRIMARY_GID)
3234 SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3235 IFSET(SAMR_FIELD_ACCT_FLAGS)
3236 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3237 IFSET(SAMR_FIELD_LOGON_HOURS)
3238 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3239 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3240 SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3241 IFSET(SAMR_FIELD_NUM_LOGONS)
3242 SET_UINT (msg, info21.logon_count, "logonCount");
3243 IFSET(SAMR_FIELD_COUNTRY_CODE)
3244 SET_UINT (msg, info21.country_code, "countryCode");
3245 IFSET(SAMR_FIELD_CODE_PAGE)
3246 SET_UINT (msg, info21.code_page, "codePage");
3248 /* password change fields */
3249 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3250 return NT_STATUS_ACCESS_DENIED;
3252 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3253 | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3254 uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3256 if (r->in.info->info21.lm_password_set) {
3257 if ((r->in.info->info21.lm_owf_password.length != 16)
3258 || (r->in.info->info21.lm_owf_password.size != 16)) {
3259 return NT_STATUS_INVALID_PARAMETER;
3262 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3264 if (r->in.info->info21.nt_password_set) {
3265 if ((r->in.info->info21.nt_owf_password.length != 16)
3266 || (r->in.info->info21.nt_owf_password.size != 16)) {
3267 return NT_STATUS_INVALID_PARAMETER;
3270 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3272 status = samr_set_password_buffers(dce_call,
3273 a_state->sam_ctx,
3274 a_state->account_dn,
3275 a_state->domain_state->domain_dn,
3276 mem_ctx,
3277 lm_pwd_hash,
3278 nt_pwd_hash);
3279 if (!NT_STATUS_IS_OK(status)) {
3280 return status;
3285 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3286 NTTIME t = 0;
3287 struct ldb_message_element *set_el;
3288 if (r->in.info->info21.password_expired
3289 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3290 unix_to_nt_time(&t, time(NULL));
3292 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3293 "pwdLastSet", t) != LDB_SUCCESS) {
3294 return NT_STATUS_NO_MEMORY;
3296 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3297 set_el->flags = LDB_FLAG_MOD_REPLACE;
3299 #undef IFSET
3300 break;
3302 case 23:
3303 if (r->in.info->info23.info.fields_present == 0)
3304 return NT_STATUS_INVALID_PARAMETER;
3306 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3307 IFSET(SAMR_FIELD_LAST_LOGON)
3308 SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3309 IFSET(SAMR_FIELD_LAST_LOGOFF)
3310 SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3311 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3312 SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3313 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3314 SET_STRING(msg, info23.info.account_name, "samAccountName");
3315 IFSET(SAMR_FIELD_FULL_NAME)
3316 SET_STRING(msg, info23.info.full_name, "displayName");
3317 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3318 SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3319 IFSET(SAMR_FIELD_HOME_DRIVE)
3320 SET_STRING(msg, info23.info.home_drive, "homeDrive");
3321 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3322 SET_STRING(msg, info23.info.logon_script, "scriptPath");
3323 IFSET(SAMR_FIELD_PROFILE_PATH)
3324 SET_STRING(msg, info23.info.profile_path, "profilePath");
3325 IFSET(SAMR_FIELD_DESCRIPTION)
3326 SET_STRING(msg, info23.info.description, "description");
3327 IFSET(SAMR_FIELD_WORKSTATIONS)
3328 SET_STRING(msg, info23.info.workstations, "userWorkstations");
3329 IFSET(SAMR_FIELD_COMMENT)
3330 SET_STRING(msg, info23.info.comment, "comment");
3331 IFSET(SAMR_FIELD_PARAMETERS)
3332 SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3333 IFSET(SAMR_FIELD_PRIMARY_GID)
3334 SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3335 IFSET(SAMR_FIELD_ACCT_FLAGS)
3336 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3337 IFSET(SAMR_FIELD_LOGON_HOURS)
3338 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3339 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3340 SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3341 IFSET(SAMR_FIELD_NUM_LOGONS)
3342 SET_UINT (msg, info23.info.logon_count, "logonCount");
3344 IFSET(SAMR_FIELD_COUNTRY_CODE)
3345 SET_UINT (msg, info23.info.country_code, "countryCode");
3346 IFSET(SAMR_FIELD_CODE_PAGE)
3347 SET_UINT (msg, info23.info.code_page, "codePage");
3349 /* password change fields */
3350 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3351 return NT_STATUS_ACCESS_DENIED;
3353 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3354 status = samr_set_password(dce_call,
3355 a_state->sam_ctx,
3356 a_state->account_dn,
3357 a_state->domain_state->domain_dn,
3358 mem_ctx,
3359 &r->in.info->info23.password);
3360 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3361 status = samr_set_password(dce_call,
3362 a_state->sam_ctx,
3363 a_state->account_dn,
3364 a_state->domain_state->domain_dn,
3365 mem_ctx,
3366 &r->in.info->info23.password);
3368 if (!NT_STATUS_IS_OK(status)) {
3369 return status;
3372 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3373 NTTIME t = 0;
3374 struct ldb_message_element *set_el;
3375 if (r->in.info->info23.info.password_expired
3376 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3377 unix_to_nt_time(&t, time(NULL));
3379 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3380 "pwdLastSet", t) != LDB_SUCCESS) {
3381 return NT_STATUS_NO_MEMORY;
3383 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3384 set_el->flags = LDB_FLAG_MOD_REPLACE;
3386 #undef IFSET
3387 break;
3389 /* the set password levels are handled separately */
3390 case 24:
3391 status = samr_set_password(dce_call,
3392 a_state->sam_ctx,
3393 a_state->account_dn,
3394 a_state->domain_state->domain_dn,
3395 mem_ctx,
3396 &r->in.info->info24.password);
3397 if (!NT_STATUS_IS_OK(status)) {
3398 return status;
3401 if (r->in.info->info24.password_expired > 0) {
3402 struct ldb_message_element *set_el;
3403 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3404 return NT_STATUS_NO_MEMORY;
3406 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3407 set_el->flags = LDB_FLAG_MOD_REPLACE;
3409 break;
3411 case 25:
3412 if (r->in.info->info25.info.fields_present == 0)
3413 return NT_STATUS_INVALID_PARAMETER;
3415 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3416 IFSET(SAMR_FIELD_LAST_LOGON)
3417 SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3418 IFSET(SAMR_FIELD_LAST_LOGOFF)
3419 SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3420 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3421 SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3422 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3423 SET_STRING(msg, info25.info.account_name, "samAccountName");
3424 IFSET(SAMR_FIELD_FULL_NAME)
3425 SET_STRING(msg, info25.info.full_name, "displayName");
3426 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3427 SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3428 IFSET(SAMR_FIELD_HOME_DRIVE)
3429 SET_STRING(msg, info25.info.home_drive, "homeDrive");
3430 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3431 SET_STRING(msg, info25.info.logon_script, "scriptPath");
3432 IFSET(SAMR_FIELD_PROFILE_PATH)
3433 SET_STRING(msg, info25.info.profile_path, "profilePath");
3434 IFSET(SAMR_FIELD_DESCRIPTION)
3435 SET_STRING(msg, info25.info.description, "description");
3436 IFSET(SAMR_FIELD_WORKSTATIONS)
3437 SET_STRING(msg, info25.info.workstations, "userWorkstations");
3438 IFSET(SAMR_FIELD_COMMENT)
3439 SET_STRING(msg, info25.info.comment, "comment");
3440 IFSET(SAMR_FIELD_PARAMETERS)
3441 SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3442 IFSET(SAMR_FIELD_PRIMARY_GID)
3443 SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
3444 IFSET(SAMR_FIELD_ACCT_FLAGS)
3445 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3446 IFSET(SAMR_FIELD_LOGON_HOURS)
3447 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3448 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3449 SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
3450 IFSET(SAMR_FIELD_NUM_LOGONS)
3451 SET_UINT (msg, info25.info.logon_count, "logonCount");
3452 IFSET(SAMR_FIELD_COUNTRY_CODE)
3453 SET_UINT (msg, info25.info.country_code, "countryCode");
3454 IFSET(SAMR_FIELD_CODE_PAGE)
3455 SET_UINT (msg, info25.info.code_page, "codePage");
3457 /* password change fields */
3458 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3459 return NT_STATUS_ACCESS_DENIED;
3461 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3462 status = samr_set_password_ex(dce_call,
3463 a_state->sam_ctx,
3464 a_state->account_dn,
3465 a_state->domain_state->domain_dn,
3466 mem_ctx,
3467 &r->in.info->info25.password);
3468 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3469 status = samr_set_password_ex(dce_call,
3470 a_state->sam_ctx,
3471 a_state->account_dn,
3472 a_state->domain_state->domain_dn,
3473 mem_ctx,
3474 &r->in.info->info25.password);
3476 if (!NT_STATUS_IS_OK(status)) {
3477 return status;
3480 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3481 NTTIME t = 0;
3482 struct ldb_message_element *set_el;
3483 if (r->in.info->info25.info.password_expired
3484 == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3485 unix_to_nt_time(&t, time(NULL));
3487 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3488 "pwdLastSet", t) != LDB_SUCCESS) {
3489 return NT_STATUS_NO_MEMORY;
3491 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3492 set_el->flags = LDB_FLAG_MOD_REPLACE;
3494 #undef IFSET
3495 break;
3497 /* the set password levels are handled separately */
3498 case 26:
3499 status = samr_set_password_ex(dce_call,
3500 a_state->sam_ctx,
3501 a_state->account_dn,
3502 a_state->domain_state->domain_dn,
3503 mem_ctx,
3504 &r->in.info->info26.password);
3505 if (!NT_STATUS_IS_OK(status)) {
3506 return status;
3509 if (r->in.info->info26.password_expired > 0) {
3510 struct ldb_message_element *set_el;
3511 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3512 return NT_STATUS_NO_MEMORY;
3514 set_el = ldb_msg_find_element(msg, "pwdLastSet");
3515 set_el->flags = LDB_FLAG_MOD_REPLACE;
3517 break;
3519 default:
3520 /* many info classes are not valid for SetUserInfo */
3521 return NT_STATUS_INVALID_INFO_CLASS;
3524 if (!NT_STATUS_IS_OK(status)) {
3525 return status;
3528 /* modify the samdb record */
3529 if (msg->num_elements > 0) {
3530 ret = ldb_modify(a_state->sam_ctx, msg);
3531 if (ret != LDB_SUCCESS) {
3532 DEBUG(1,("Failed to modify record %s: %s\n",
3533 ldb_dn_get_linearized(a_state->account_dn),
3534 ldb_errstring(a_state->sam_ctx)));
3536 /* we really need samdb.c to return NTSTATUS */
3537 return NT_STATUS_UNSUCCESSFUL;
3541 return NT_STATUS_OK;
3546 samr_GetGroupsForUser
3548 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3549 struct samr_GetGroupsForUser *r)
3551 struct dcesrv_handle *h;
3552 struct samr_account_state *a_state;
3553 struct samr_domain_state *d_state;
3554 struct ldb_message **res;
3555 const char * const attrs[2] = { "objectSid", NULL };
3556 struct samr_RidWithAttributeArray *array;
3557 int i, count;
3559 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3561 a_state = h->data;
3562 d_state = a_state->domain_state;
3564 count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3565 d_state->domain_dn, &res,
3566 attrs, d_state->domain_sid,
3567 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3568 ldb_dn_get_linearized(a_state->account_dn),
3569 GTYPE_SECURITY_GLOBAL_GROUP);
3570 if (count < 0)
3571 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3573 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3574 if (array == NULL)
3575 return NT_STATUS_NO_MEMORY;
3577 array->count = 0;
3578 array->rids = NULL;
3580 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3581 count + 1);
3582 if (array->rids == NULL)
3583 return NT_STATUS_NO_MEMORY;
3585 /* Adds the primary group */
3586 array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3587 ~0, a_state->account_dn,
3588 "primaryGroupID", NULL);
3589 array->rids[0].attributes = SE_GROUP_MANDATORY
3590 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3591 array->count += 1;
3593 /* Adds the additional groups */
3594 for (i = 0; i < count; i++) {
3595 struct dom_sid *group_sid;
3597 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3598 if (group_sid == NULL) {
3599 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3602 array->rids[i + 1].rid =
3603 group_sid->sub_auths[group_sid->num_auths-1];
3604 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3605 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3606 array->count += 1;
3609 *r->out.rids = array;
3611 return NT_STATUS_OK;
3616 samr_QueryDisplayInfo
3618 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3619 struct samr_QueryDisplayInfo *r)
3621 struct dcesrv_handle *h;
3622 struct samr_domain_state *d_state;
3623 struct ldb_message **res;
3624 int i, ldb_cnt;
3625 uint32_t count;
3626 const char * const attrs[] = { "objectSid", "sAMAccountName",
3627 "displayName", "description", "userAccountControl",
3628 "pwdLastSet", NULL };
3629 struct samr_DispEntryFull *entriesFull = NULL;
3630 struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3631 struct samr_DispEntryAscii *entriesAscii = NULL;
3632 struct samr_DispEntryGeneral *entriesGeneral = NULL;
3633 const char *filter;
3635 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3637 d_state = h->data;
3639 switch (r->in.level) {
3640 case 1:
3641 case 4:
3642 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3643 "(sAMAccountType=%u))",
3644 ATYPE_NORMAL_ACCOUNT);
3645 break;
3646 case 2:
3647 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3648 "(sAMAccountType=%u))",
3649 ATYPE_WORKSTATION_TRUST);
3650 break;
3651 case 3:
3652 case 5:
3653 filter = talloc_asprintf(mem_ctx,
3654 "(&(|(groupType=%d)(groupType=%d))"
3655 "(objectClass=group))",
3656 GTYPE_SECURITY_UNIVERSAL_GROUP,
3657 GTYPE_SECURITY_GLOBAL_GROUP);
3658 break;
3659 default:
3660 return NT_STATUS_INVALID_INFO_CLASS;
3663 /* search for all requested objects in this domain. This could
3664 possibly be cached and resumed based on resume_key */
3665 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3666 d_state->domain_dn, &res, attrs,
3667 d_state->domain_sid, "%s", filter);
3668 if (ldb_cnt == -1) {
3669 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3671 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3672 return NT_STATUS_OK;
3675 switch (r->in.level) {
3676 case 1:
3677 entriesGeneral = talloc_array(mem_ctx,
3678 struct samr_DispEntryGeneral,
3679 ldb_cnt);
3680 break;
3681 case 2:
3682 entriesFull = talloc_array(mem_ctx,
3683 struct samr_DispEntryFull,
3684 ldb_cnt);
3685 break;
3686 case 3:
3687 entriesFullGroup = talloc_array(mem_ctx,
3688 struct samr_DispEntryFullGroup,
3689 ldb_cnt);
3690 break;
3691 case 4:
3692 case 5:
3693 entriesAscii = talloc_array(mem_ctx,
3694 struct samr_DispEntryAscii,
3695 ldb_cnt);
3696 break;
3699 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3700 (entriesAscii == NULL) && (entriesFullGroup == NULL))
3701 return NT_STATUS_NO_MEMORY;
3703 count = 0;
3705 for (i=0; i<ldb_cnt; i++) {
3706 struct dom_sid *objectsid;
3708 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3709 "objectSid");
3710 if (objectsid == NULL)
3711 continue;
3713 switch(r->in.level) {
3714 case 1:
3715 entriesGeneral[count].idx = count + 1;
3716 entriesGeneral[count].rid =
3717 objectsid->sub_auths[objectsid->num_auths-1];
3718 entriesGeneral[count].acct_flags =
3719 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3720 res[i],
3721 d_state->domain_dn);
3722 entriesGeneral[count].account_name.string =
3723 samdb_result_string(res[i],
3724 "sAMAccountName", "");
3725 entriesGeneral[count].full_name.string =
3726 samdb_result_string(res[i], "displayName", "");
3727 entriesGeneral[count].description.string =
3728 samdb_result_string(res[i], "description", "");
3729 break;
3730 case 2:
3731 entriesFull[count].idx = count + 1;
3732 entriesFull[count].rid =
3733 objectsid->sub_auths[objectsid->num_auths-1];
3735 /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3736 entriesFull[count].acct_flags =
3737 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3738 res[i],
3739 d_state->domain_dn) | ACB_NORMAL;
3740 entriesFull[count].account_name.string =
3741 samdb_result_string(res[i], "sAMAccountName",
3742 "");
3743 entriesFull[count].description.string =
3744 samdb_result_string(res[i], "description", "");
3745 break;
3746 case 3:
3747 entriesFullGroup[count].idx = count + 1;
3748 entriesFullGroup[count].rid =
3749 objectsid->sub_auths[objectsid->num_auths-1];
3750 /* We get a "7" here for groups */
3751 entriesFullGroup[count].acct_flags
3752 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3753 entriesFullGroup[count].account_name.string =
3754 samdb_result_string(res[i], "sAMAccountName",
3755 "");
3756 entriesFullGroup[count].description.string =
3757 samdb_result_string(res[i], "description", "");
3758 break;
3759 case 4:
3760 case 5:
3761 entriesAscii[count].idx = count + 1;
3762 entriesAscii[count].account_name.string =
3763 samdb_result_string(res[i], "sAMAccountName",
3764 "");
3765 break;
3768 count += 1;
3771 *r->out.total_size = count;
3773 if (r->in.start_idx >= count) {
3774 *r->out.returned_size = 0;
3775 switch(r->in.level) {
3776 case 1:
3777 r->out.info->info1.count = *r->out.returned_size;
3778 r->out.info->info1.entries = NULL;
3779 break;
3780 case 2:
3781 r->out.info->info2.count = *r->out.returned_size;
3782 r->out.info->info2.entries = NULL;
3783 break;
3784 case 3:
3785 r->out.info->info3.count = *r->out.returned_size;
3786 r->out.info->info3.entries = NULL;
3787 break;
3788 case 4:
3789 r->out.info->info4.count = *r->out.returned_size;
3790 r->out.info->info4.entries = NULL;
3791 break;
3792 case 5:
3793 r->out.info->info5.count = *r->out.returned_size;
3794 r->out.info->info5.entries = NULL;
3795 break;
3797 } else {
3798 *r->out.returned_size = MIN(count - r->in.start_idx,
3799 r->in.max_entries);
3800 switch(r->in.level) {
3801 case 1:
3802 r->out.info->info1.count = *r->out.returned_size;
3803 r->out.info->info1.entries =
3804 &(entriesGeneral[r->in.start_idx]);
3805 break;
3806 case 2:
3807 r->out.info->info2.count = *r->out.returned_size;
3808 r->out.info->info2.entries =
3809 &(entriesFull[r->in.start_idx]);
3810 break;
3811 case 3:
3812 r->out.info->info3.count = *r->out.returned_size;
3813 r->out.info->info3.entries =
3814 &(entriesFullGroup[r->in.start_idx]);
3815 break;
3816 case 4:
3817 r->out.info->info4.count = *r->out.returned_size;
3818 r->out.info->info4.entries =
3819 &(entriesAscii[r->in.start_idx]);
3820 break;
3821 case 5:
3822 r->out.info->info5.count = *r->out.returned_size;
3823 r->out.info->info5.entries =
3824 &(entriesAscii[r->in.start_idx]);
3825 break;
3829 return (*r->out.returned_size < (count - r->in.start_idx)) ?
3830 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3835 samr_GetDisplayEnumerationIndex
3837 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3838 struct samr_GetDisplayEnumerationIndex *r)
3840 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3845 samr_TestPrivateFunctionsDomain
3847 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3848 struct samr_TestPrivateFunctionsDomain *r)
3850 return NT_STATUS_NOT_IMPLEMENTED;
3855 samr_TestPrivateFunctionsUser
3857 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3858 struct samr_TestPrivateFunctionsUser *r)
3860 return NT_STATUS_NOT_IMPLEMENTED;
3865 samr_GetUserPwInfo
3867 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3868 struct samr_GetUserPwInfo *r)
3870 struct dcesrv_handle *h;
3871 struct samr_account_state *a_state;
3873 ZERO_STRUCTP(r->out.info);
3875 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3877 a_state = h->data;
3879 r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3880 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3881 NULL);
3882 r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3883 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3885 return NT_STATUS_OK;
3890 samr_RemoveMemberFromForeignDomain
3892 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3893 struct samr_RemoveMemberFromForeignDomain *r)
3895 struct dcesrv_handle *h;
3896 struct samr_domain_state *d_state;
3897 const char *memberdn;
3898 struct ldb_message **res;
3899 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3900 int i, count;
3902 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3904 d_state = h->data;
3906 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3907 "distinguishedName", "(objectSid=%s)",
3908 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3909 /* Nothing to do */
3910 if (memberdn == NULL) {
3911 return NT_STATUS_OK;
3914 /* TODO: Does this call only remove alias members, or does it do this
3915 * for domain groups as well? */
3917 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3918 d_state->domain_dn, &res, attrs,
3919 d_state->domain_sid,
3920 "(&(member=%s)(objectClass=group)"
3921 "(|(groupType=%d)(groupType=%d)))",
3922 memberdn,
3923 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3924 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3926 if (count < 0)
3927 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3929 for (i=0; i<count; i++) {
3930 struct ldb_message *mod;
3932 mod = ldb_msg_new(mem_ctx);
3933 if (mod == NULL) {
3934 return NT_STATUS_NO_MEMORY;
3937 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
3938 if (mod->dn == NULL) {
3939 talloc_free(mod);
3940 continue;
3943 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3944 "member", memberdn) != LDB_SUCCESS)
3945 return NT_STATUS_NO_MEMORY;
3947 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
3948 return NT_STATUS_UNSUCCESSFUL;
3950 talloc_free(mod);
3953 return NT_STATUS_OK;
3958 samr_QueryDomainInfo2
3960 just an alias for samr_QueryDomainInfo
3962 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3963 struct samr_QueryDomainInfo2 *r)
3965 struct samr_QueryDomainInfo r1;
3966 NTSTATUS status;
3968 ZERO_STRUCT(r1.out);
3969 r1.in.domain_handle = r->in.domain_handle;
3970 r1.in.level = r->in.level;
3971 r1.out.info = r->out.info;
3973 status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3975 return status;
3980 samr_QueryUserInfo2
3982 just an alias for samr_QueryUserInfo
3984 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3985 struct samr_QueryUserInfo2 *r)
3987 struct samr_QueryUserInfo r1;
3988 NTSTATUS status;
3990 r1.in.user_handle = r->in.user_handle;
3991 r1.in.level = r->in.level;
3992 r1.out.info = r->out.info;
3994 status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3996 return status;
4001 samr_QueryDisplayInfo2
4003 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4004 struct samr_QueryDisplayInfo2 *r)
4006 struct samr_QueryDisplayInfo q;
4007 NTSTATUS result;
4009 q.in.domain_handle = r->in.domain_handle;
4010 q.in.level = r->in.level;
4011 q.in.start_idx = r->in.start_idx;
4012 q.in.max_entries = r->in.max_entries;
4013 q.in.buf_size = r->in.buf_size;
4014 q.out.total_size = r->out.total_size;
4015 q.out.returned_size = r->out.returned_size;
4016 q.out.info = r->out.info;
4018 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4020 return result;
4025 samr_GetDisplayEnumerationIndex2
4027 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4028 struct samr_GetDisplayEnumerationIndex2 *r)
4030 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4035 samr_QueryDisplayInfo3
4037 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4038 struct samr_QueryDisplayInfo3 *r)
4040 struct samr_QueryDisplayInfo q;
4041 NTSTATUS result;
4043 q.in.domain_handle = r->in.domain_handle;
4044 q.in.level = r->in.level;
4045 q.in.start_idx = r->in.start_idx;
4046 q.in.max_entries = r->in.max_entries;
4047 q.in.buf_size = r->in.buf_size;
4048 q.out.total_size = r->out.total_size;
4049 q.out.returned_size = r->out.returned_size;
4050 q.out.info = r->out.info;
4052 result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4054 return result;
4059 samr_AddMultipleMembersToAlias
4061 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4062 struct samr_AddMultipleMembersToAlias *r)
4064 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4069 samr_RemoveMultipleMembersFromAlias
4071 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4072 struct samr_RemoveMultipleMembersFromAlias *r)
4074 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4079 samr_GetDomPwInfo
4081 this fetches the default password properties for a domain
4083 note that w2k3 completely ignores the domain name in this call, and
4084 always returns the information for the servers primary domain
4086 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4087 struct samr_GetDomPwInfo *r)
4089 struct ldb_message **msgs;
4090 int ret;
4091 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4092 struct ldb_context *sam_ctx;
4094 ZERO_STRUCTP(r->out.info);
4096 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4097 dce_call->conn->dce_ctx->lp_ctx,
4098 dce_call->conn->auth_state.session_info);
4099 if (sam_ctx == NULL) {
4100 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4103 /* The domain name in this call is ignored */
4104 ret = gendb_search_dn(sam_ctx,
4105 mem_ctx, NULL, &msgs, attrs);
4106 if (ret <= 0) {
4107 talloc_free(sam_ctx);
4109 return NT_STATUS_NO_SUCH_DOMAIN;
4111 if (ret > 1) {
4112 talloc_free(msgs);
4113 talloc_free(sam_ctx);
4115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4118 r->out.info->min_password_length = samdb_result_uint(msgs[0],
4119 "minPwdLength", 0);
4120 r->out.info->password_properties = samdb_result_uint(msgs[0],
4121 "pwdProperties", 1);
4123 talloc_free(msgs);
4124 talloc_unlink(mem_ctx, sam_ctx);
4126 return NT_STATUS_OK;
4131 samr_Connect2
4133 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4134 struct samr_Connect2 *r)
4136 struct samr_Connect c;
4138 c.in.system_name = NULL;
4139 c.in.access_mask = r->in.access_mask;
4140 c.out.connect_handle = r->out.connect_handle;
4142 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4147 samr_SetUserInfo2
4149 just an alias for samr_SetUserInfo
4151 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4152 struct samr_SetUserInfo2 *r)
4154 struct samr_SetUserInfo r2;
4156 r2.in.user_handle = r->in.user_handle;
4157 r2.in.level = r->in.level;
4158 r2.in.info = r->in.info;
4160 return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4165 samr_SetBootKeyInformation
4167 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4168 struct samr_SetBootKeyInformation *r)
4170 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4175 samr_GetBootKeyInformation
4177 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4178 struct samr_GetBootKeyInformation *r)
4180 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4185 samr_Connect3
4187 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4188 struct samr_Connect3 *r)
4190 struct samr_Connect c;
4192 c.in.system_name = NULL;
4193 c.in.access_mask = r->in.access_mask;
4194 c.out.connect_handle = r->out.connect_handle;
4196 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4201 samr_Connect4
4203 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4204 struct samr_Connect4 *r)
4206 struct samr_Connect c;
4208 c.in.system_name = NULL;
4209 c.in.access_mask = r->in.access_mask;
4210 c.out.connect_handle = r->out.connect_handle;
4212 return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4217 samr_Connect5
4219 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4220 struct samr_Connect5 *r)
4222 struct samr_Connect c;
4223 NTSTATUS status;
4225 c.in.system_name = NULL;
4226 c.in.access_mask = r->in.access_mask;
4227 c.out.connect_handle = r->out.connect_handle;
4229 status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4231 r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4232 r->out.info_out->info1.unknown2 = 0;
4233 *r->out.level_out = r->in.level_in;
4235 return status;
4240 samr_RidToSid
4242 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4243 struct samr_RidToSid *r)
4245 struct samr_domain_state *d_state;
4246 struct dcesrv_handle *h;
4248 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4250 d_state = h->data;
4252 /* form the users SID */
4253 *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4254 if (!*r->out.sid) {
4255 return NT_STATUS_NO_MEMORY;
4258 return NT_STATUS_OK;
4263 samr_SetDsrmPassword
4265 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4266 struct samr_SetDsrmPassword *r)
4268 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4273 samr_ValidatePassword
4275 For now the call checks the password complexity (if active) and the minimum
4276 password length on level 2 and 3. Level 1 is ignored for now.
4278 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4279 TALLOC_CTX *mem_ctx,
4280 struct samr_ValidatePassword *r)
4282 struct samr_GetDomPwInfo r2;
4283 struct samr_PwInfo pwInfo;
4284 DATA_BLOB password;
4285 enum samr_ValidationStatus res;
4286 NTSTATUS status;
4288 (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4290 r2.in.domain_name = NULL;
4291 r2.out.info = &pwInfo;
4292 status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4293 if (!NT_STATUS_IS_OK(status)) {
4294 return status;
4297 switch (r->in.level) {
4298 case NetValidateAuthentication:
4299 /* we don't support this yet */
4300 return NT_STATUS_NOT_SUPPORTED;
4301 break;
4302 case NetValidatePasswordChange:
4303 password = data_blob_const(r->in.req->req2.password.string,
4304 r->in.req->req2.password.length);
4305 res = samdb_check_password(&password,
4306 pwInfo.password_properties,
4307 pwInfo.min_password_length);
4308 (*r->out.rep)->ctr2.status = res;
4309 break;
4310 case NetValidatePasswordReset:
4311 password = data_blob_const(r->in.req->req3.password.string,
4312 r->in.req->req3.password.length);
4313 res = samdb_check_password(&password,
4314 pwInfo.password_properties,
4315 pwInfo.min_password_length);
4316 (*r->out.rep)->ctr3.status = res;
4317 break;
4318 default:
4319 return NT_STATUS_INVALID_INFO_CLASS;
4320 break;
4323 return NT_STATUS_OK;
4327 /* include the generated boilerplate */
4328 #include "librpc/gen_ndr/ndr_samr_s.c"