2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "librpc/gen_ndr/ndr_samr.h"
26 #include "rpc_server/dcerpc_server.h"
27 #include "rpc_server/common/common.h"
28 #include "rpc_server/samr/dcesrv_samr.h"
29 #include "system/time.h"
30 #include "lib/ldb/include/ldb.h"
34 destroy a general handle.
36 static void samr_handle_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
42 This is a bad temporary hack until we have at least some kind of schema
45 static char *ldb_hexstr(TALLOC_CTX *mem_ctx, uint32 val)
47 return talloc_asprintf(mem_ctx, "0x%.8x", val);
53 create a connection to the SAM database
55 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
56 struct samr_Connect *r)
58 struct samr_connect_state *c_state;
59 struct dcesrv_handle *handle;
61 ZERO_STRUCTP(r->out.connect_handle);
63 c_state = talloc_p(dce_call->conn, struct samr_connect_state);
65 return NT_STATUS_NO_MEMORY;
68 /* make sure the sam database is accessible */
69 c_state->sam_ctx = samdb_connect(c_state);
70 if (c_state->sam_ctx == NULL) {
72 return NT_STATUS_INVALID_SYSTEM_SERVICE;
75 handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_CONNECT);
78 return NT_STATUS_NO_MEMORY;
81 handle->data = c_state;
82 handle->destroy = samr_handle_destroy;
84 c_state->access_mask = r->in.access_mask;
85 *r->out.connect_handle = handle->wire_handle;
94 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
97 struct dcesrv_handle *h;
99 *r->out.handle = *r->in.handle;
101 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
103 /* this causes the parameters samr_XXX_destroy() to be called by
104 the handle destroy code which destroys the state associated
106 dcesrv_handle_destroy(dce_call->conn, h);
108 ZERO_STRUCTP(r->out.handle);
117 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
118 struct samr_SetSecurity *r)
120 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
127 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
128 struct samr_QuerySecurity *r)
130 struct dcesrv_handle *h;
131 struct sec_desc_buf *sd;
135 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
137 sd = talloc_p(mem_ctx, struct sec_desc_buf);
139 return NT_STATUS_NO_MEMORY;
142 sd->sd = samdb_default_security_descriptor(mem_ctx);
153 we refuse this operation completely. If a admin wants to shutdown samr
154 in Samba then they should use the samba admin tools to disable the samr pipe
156 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
157 struct samr_Shutdown *r)
159 return NT_STATUS_ACCESS_DENIED;
166 this maps from a domain name to a SID
168 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
169 struct samr_LookupDomain *r)
171 struct samr_connect_state *c_state;
172 struct dcesrv_handle *h;
173 struct dom_sid2 *sid;
178 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
182 if (r->in.domain->string == NULL) {
183 return NT_STATUS_INVALID_PARAMETER;
186 sidstr = samdb_search_string(c_state->sam_ctx,
187 mem_ctx, NULL, "objectSid",
188 "(&(name=%s)(objectclass=domain))",
189 r->in.domain->string);
190 if (sidstr == NULL) {
191 return NT_STATUS_NO_SUCH_DOMAIN;
194 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
196 DEBUG(0,("samdb: Invalid sid '%s' for domain %s\n",
197 sidstr, r->in.domain->string));
198 return NT_STATUS_INTERNAL_DB_CORRUPTION;
210 list the domains in the SAM
212 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
213 struct samr_EnumDomains *r)
215 struct samr_connect_state *c_state;
216 struct dcesrv_handle *h;
217 struct samr_SamArray *array;
218 const char **domains;
219 int count, i, start_i;
221 *r->out.resume_handle = 0;
223 r->out.num_entries = 0;
225 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
229 count = samdb_search_string_multiple(c_state->sam_ctx,
230 mem_ctx, NULL, &domains,
231 "name", "(objectclass=domain)");
233 DEBUG(0,("samdb: no domains found in EnumDomains\n"));
234 return NT_STATUS_INTERNAL_DB_CORRUPTION;
237 *r->out.resume_handle = count;
239 start_i = *r->in.resume_handle;
241 if (start_i >= count) {
242 /* search past end of list is not an error for this call */
246 array = talloc_p(mem_ctx, struct samr_SamArray);
248 return NT_STATUS_NO_MEMORY;
252 array->entries = NULL;
254 array->entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count - start_i);
255 if (array->entries == NULL) {
256 return NT_STATUS_NO_MEMORY;
259 for (i=0;i<count-start_i;i++) {
260 array->entries[i].idx = start_i + i;
261 array->entries[i].name.string = domains[start_i+i];
265 r->out.num_entries = i;
266 array->count = r->out.num_entries;
275 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
276 struct samr_OpenDomain *r)
278 struct dcesrv_handle *h_conn, *h_domain;
279 const char *sidstr, *domain_name;
280 struct samr_connect_state *c_state;
281 struct samr_domain_state *d_state;
282 const char * const attrs[2] = { "name", NULL};
283 struct ldb_message **msgs;
286 ZERO_STRUCTP(r->out.domain_handle);
288 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
290 c_state = h_conn->data;
292 if (r->in.sid == NULL) {
293 return NT_STATUS_INVALID_PARAMETER;
296 sidstr = dom_sid_string(mem_ctx, r->in.sid);
297 if (sidstr == NULL) {
298 return NT_STATUS_INVALID_PARAMETER;
301 ret = samdb_search(c_state->sam_ctx,
302 mem_ctx, NULL, &msgs, attrs,
303 "(&(objectSid=%s)(objectclass=domain))",
306 return NT_STATUS_NO_SUCH_DOMAIN;
309 domain_name = ldb_msg_find_string(msgs[0], "name", NULL);
310 if (domain_name == NULL) {
311 return NT_STATUS_NO_SUCH_DOMAIN;
314 d_state = talloc_p(c_state, struct samr_domain_state);
316 return NT_STATUS_NO_MEMORY;
319 d_state->connect_state = talloc_reference(d_state, c_state);
320 d_state->sam_ctx = c_state->sam_ctx;
321 d_state->domain_sid = talloc_strdup(d_state, sidstr);
322 d_state->domain_name = talloc_strdup(d_state, domain_name);
323 d_state->domain_dn = talloc_strdup(d_state, msgs[0]->dn);
324 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
325 talloc_free(d_state);
326 return NT_STATUS_NO_MEMORY;
328 d_state->access_mask = r->in.access_mask;
330 h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN);
332 talloc_free(d_state);
333 return NT_STATUS_NO_MEMORY;
336 h_domain->data = d_state;
337 h_domain->destroy = samr_handle_destroy;
338 *r->out.domain_handle = h_domain->wire_handle;
346 static NTSTATUS samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
347 struct samr_DomInfo2 *info)
349 const char * const attrs[] = { "comment", "name", NULL };
351 struct ldb_message **res;
353 ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, attrs,
354 "dn=%s", state->domain_dn);
356 return NT_STATUS_INTERNAL_DB_CORRUPTION;
359 /* where is this supposed to come from? is it settable? */
360 info->force_logoff_time = 0x8000000000000000LL;
362 info->comment.string = samdb_result_string(res[0], "comment", NULL);
363 info->domain.string = samdb_result_string(res[0], "name", NULL);
365 info->primary.string = lp_netbios_name();
366 info->sequence_num = 0;
367 info->role = ROLE_DOMAIN_PDC;
368 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, NULL, "(objectClass=user)");
369 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
370 "(&(objectClass=group)(sAMAccountType=%u))",
372 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
373 "(&(objectClass=group)(sAMAccountType=%u))",
382 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
383 struct samr_QueryDomainInfo *r)
385 struct dcesrv_handle *h;
386 struct samr_domain_state *d_state;
390 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
394 r->out.info = talloc_p(mem_ctx, union samr_DomainInfo);
396 return NT_STATUS_NO_MEMORY;
399 ZERO_STRUCTP(r->out.info);
401 switch (r->in.level) {
403 return samr_info_DomInfo2(d_state, mem_ctx, &r->out.info->info2);
406 return NT_STATUS_INVALID_INFO_CLASS;
413 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
414 struct samr_SetDomainInfo *r)
416 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
420 samr_CreateDomainGroup
422 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
423 struct samr_CreateDomainGroup *r)
425 struct samr_domain_state *d_state;
426 struct samr_account_state *a_state;
427 struct dcesrv_handle *h;
429 struct ldb_message msg;
431 const char *groupname, *sidstr, *guidstr;
433 time_t now = time(NULL);
434 struct dcesrv_handle *g_handle;
438 ZERO_STRUCTP(r->out.group_handle);
441 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
445 groupname = r->in.name->string;
447 if (groupname == NULL) {
448 return NT_STATUS_INVALID_PARAMETER;
451 /* check if the group already exists */
452 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
454 "(&(sAMAccountName=%s)(objectclass=group))",
457 return NT_STATUS_GROUP_EXISTS;
462 /* pull in all the template attributes */
463 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
464 "(&(name=TemplateGroup)(objectclass=groupTemplate))");
466 DEBUG(0,("Failed to load TemplateGroup from samdb\n"));
467 return NT_STATUS_INTERNAL_DB_CORRUPTION;
471 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
472 d_state->domain_dn, "nextRid", &rid);
473 if (!NT_STATUS_IS_OK(status)) {
477 /* and the group SID */
478 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
480 return NT_STATUS_NO_MEMORY;
484 guid = GUID_random();
485 guidstr = GUID_string(mem_ctx, &guid);
487 return NT_STATUS_NO_MEMORY;
490 /* add core elements to the ldb_message for the user */
491 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", groupname,
494 return NT_STATUS_NO_MEMORY;
496 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", groupname);
497 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", groupname);
498 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", groupname);
499 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "group");
500 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
501 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
502 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
503 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
505 /* create the group */
506 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
508 DEBUG(0,("Failed to create group record %s\n", msg.dn));
509 return NT_STATUS_INTERNAL_DB_CORRUPTION;
512 a_state = talloc_p(d_state, struct samr_account_state);
514 return NT_STATUS_NO_MEMORY;
516 a_state->sam_ctx = d_state->sam_ctx;
517 a_state->access_mask = r->in.access_mask;
518 a_state->domain_state = talloc_reference(a_state, d_state);
519 a_state->account_dn = talloc_steal(a_state, msg.dn);
520 a_state->account_sid = talloc_steal(a_state, sidstr);
521 a_state->account_name = talloc_strdup(a_state, groupname);
522 if (!a_state->account_name) {
523 return NT_STATUS_NO_MEMORY;
526 /* create the policy handle */
527 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
529 return NT_STATUS_NO_MEMORY;
532 g_handle->data = a_state;
533 g_handle->destroy = samr_handle_destroy;
535 *r->out.group_handle = g_handle->wire_handle;
543 comparison function for sorting SamEntry array
545 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
547 return e1->idx - e2->idx;
551 samr_EnumDomainGroups
553 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
554 struct samr_EnumDomainGroups *r)
556 struct dcesrv_handle *h;
557 struct samr_domain_state *d_state;
558 struct ldb_message **res;
559 int ldb_cnt, count, i, first;
560 struct samr_SamEntry *entries;
561 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
562 struct dom_sid *domain_sid;
564 *r->out.resume_handle = 0;
566 r->out.num_entries = 0;
568 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
572 /* search for all domain groups in this domain. This could possibly be
573 cached and resumed based on resume_key */
574 ldb_cnt = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
576 "(&(grouptype=%s)(objectclass=group))",
578 GTYPE_SECURITY_GLOBAL_GROUP));
580 return NT_STATUS_INTERNAL_DB_CORRUPTION;
582 if (ldb_cnt == 0 || r->in.max_size == 0) {
586 /* convert to SamEntry format */
587 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, ldb_cnt);
589 return NT_STATUS_NO_MEMORY;
593 domain_sid = dom_sid_parse_talloc(mem_ctx, d_state->domain_sid);
595 for (i=0;i<ldb_cnt;i++) {
596 struct dom_sid *alias_sid;
598 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
601 if (alias_sid == NULL)
604 if (!dom_sid_in_domain(domain_sid, alias_sid))
608 alias_sid->sub_auths[alias_sid->num_auths-1];
609 entries[count].name.string =
610 samdb_result_string(res[i], "sAMAccountName", "");
614 /* sort the results by rid */
615 qsort(entries, count, sizeof(struct samr_SamEntry),
616 (comparison_fn_t)compare_SamEntry);
618 /* find the first entry to return */
620 first<count && entries[first].idx <= *r->in.resume_handle;
623 if (first == count) {
627 /* return the rest, limit by max_size. Note that we
628 use the w2k3 element size value of 54 */
629 r->out.num_entries = count - first;
630 r->out.num_entries = MIN(r->out.num_entries,
631 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
633 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
635 return NT_STATUS_NO_MEMORY;
638 r->out.sam->entries = entries+first;
639 r->out.sam->count = r->out.num_entries;
641 if (r->out.num_entries < count - first) {
642 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
643 return STATUS_MORE_ENTRIES;
653 TODO: This should do some form of locking, especially around the rid allocation
655 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
656 struct samr_CreateUser2 *r)
658 struct samr_domain_state *d_state;
659 struct samr_account_state *a_state;
660 struct dcesrv_handle *h;
662 struct ldb_message msg;
664 const char *account_name, *sidstr, *guidstr;
666 time_t now = time(NULL);
667 struct dcesrv_handle *u_handle;
670 const char *container, *additional_class=NULL;
672 ZERO_STRUCTP(r->out.user_handle);
673 *r->out.access_granted = 0;
676 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
680 account_name = r->in.account_name->string;
682 if (account_name == NULL) {
683 return NT_STATUS_INVALID_PARAMETER;
686 /* check if the user already exists */
687 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
689 "(&(sAMAccountName=%s)(objectclass=user))", account_name);
691 return NT_STATUS_USER_EXISTS;
696 /* This must be one of these values *only* */
697 if (r->in.acct_flags == ACB_NORMAL) {
698 /* pull in all the template attributes */
699 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
700 "(&(name=TemplateUser)(objectclass=userTemplate))");
702 DEBUG(0,("Failed to load TemplateUser from samdb\n"));
703 return NT_STATUS_INTERNAL_DB_CORRUPTION;
708 } else if (r->in.acct_flags == ACB_WSTRUST) {
709 /* pull in all the template attributes */
710 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
711 "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
713 DEBUG(0,("Failed to load TemplateMemberServer from samdb\n"));
714 return NT_STATUS_INTERNAL_DB_CORRUPTION;
717 container = "Computers";
718 additional_class = "computer";
720 } else if (r->in.acct_flags == ACB_SVRTRUST) {
721 /* pull in all the template attributes */
722 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
723 "(&(name=TemplateDomainController)(objectclass=userTemplate))");
725 DEBUG(0,("Failed to load TemplateDomainController from samdb\n"));
726 return NT_STATUS_INTERNAL_DB_CORRUPTION;
729 container = "Domain Controllers";
730 additional_class = "computer";
732 } else if (r->in.acct_flags == ACB_DOMTRUST) {
733 /* pull in all the template attributes */
734 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
735 "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
737 DEBUG(0,("Failed to load TemplateTrustingDomain from samdb\n"));
738 return NT_STATUS_INTERNAL_DB_CORRUPTION;
742 additional_class = "computer";
745 return NT_STATUS_INVALID_PARAMETER;
749 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
750 d_state->domain_dn, "nextRid", &rid);
751 if (!NT_STATUS_IS_OK(status)) {
755 /* and the users SID */
756 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
758 return NT_STATUS_NO_MEMORY;
762 guid = GUID_random();
763 guidstr = GUID_string(mem_ctx, &guid);
765 return NT_STATUS_NO_MEMORY;
768 /* add core elements to the ldb_message for the user */
769 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", account_name, container, d_state->domain_dn);
771 return NT_STATUS_NO_MEMORY;
773 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", account_name);
774 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", account_name);
775 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", account_name);
776 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
777 if (additional_class) {
778 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class);
780 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
781 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
782 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
783 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
785 /* create the user */
786 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
788 DEBUG(0,("Failed to create user record %s\n", msg.dn));
789 return NT_STATUS_INTERNAL_DB_CORRUPTION;
792 a_state = talloc_p(d_state, struct samr_account_state);
794 return NT_STATUS_NO_MEMORY;
796 a_state->sam_ctx = d_state->sam_ctx;
797 a_state->access_mask = r->in.access_mask;
798 a_state->domain_state = talloc_reference(a_state, d_state);
799 a_state->account_dn = talloc_steal(a_state, msg.dn);
800 a_state->account_sid = talloc_steal(a_state, sidstr);
801 a_state->account_name = talloc_strdup(a_state, account_name);
802 if (!a_state->account_name) {
803 return NT_STATUS_NO_MEMORY;
806 /* create the policy handle */
807 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
809 return NT_STATUS_NO_MEMORY;
812 u_handle->data = a_state;
813 u_handle->destroy = samr_handle_destroy;
815 /* the domain state is in use one more time */
818 *r->out.user_handle = u_handle->wire_handle;
819 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
829 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
830 struct samr_CreateUser *r)
832 struct samr_CreateUser2 r2;
833 uint32_t access_granted = 0;
836 /* a simple wrapper around samr_CreateUser2 works nicely */
837 r2.in.domain_handle = r->in.domain_handle;
838 r2.in.account_name = r->in.account_name;
839 r2.in.acct_flags = ACB_NORMAL;
840 r2.in.access_mask = r->in.access_mask;
841 r2.out.user_handle = r->out.user_handle;
842 r2.out.access_granted = &access_granted;
843 r2.out.rid = r->out.rid;
845 return samr_CreateUser2(dce_call, mem_ctx, &r2);
851 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
852 struct samr_EnumDomainUsers *r)
854 struct dcesrv_handle *h;
855 struct samr_domain_state *d_state;
856 struct ldb_message **res;
858 struct samr_SamEntry *entries;
859 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
861 *r->out.resume_handle = 0;
863 r->out.num_entries = 0;
865 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
869 /* search for all users in this domain. This could possibly be cached and
870 resumed based on resume_key */
871 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
874 return NT_STATUS_INTERNAL_DB_CORRUPTION;
876 if (count == 0 || r->in.max_size == 0) {
880 /* convert to SamEntry format */
881 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
883 return NT_STATUS_NO_MEMORY;
885 for (i=0;i<count;i++) {
886 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
887 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
890 /* sort the results by rid */
891 qsort(entries, count, sizeof(struct samr_SamEntry),
892 (comparison_fn_t)compare_SamEntry);
894 /* find the first entry to return */
896 first<count && entries[first].idx <= *r->in.resume_handle;
899 if (first == count) {
903 /* return the rest, limit by max_size. Note that we
904 use the w2k3 element size value of 54 */
905 r->out.num_entries = count - first;
906 r->out.num_entries = MIN(r->out.num_entries,
907 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
909 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
911 return NT_STATUS_NO_MEMORY;
914 r->out.sam->entries = entries+first;
915 r->out.sam->count = r->out.num_entries;
917 if (r->out.num_entries < count - first) {
918 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
919 return STATUS_MORE_ENTRIES;
929 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
930 struct samr_CreateDomAlias *r)
932 struct samr_domain_state *d_state;
933 struct samr_account_state *a_state;
934 struct dcesrv_handle *h;
935 const char *aliasname, *name, *sidstr, *guidstr;
937 time_t now = time(NULL);
938 struct ldb_message msg;
940 struct dcesrv_handle *a_handle;
944 ZERO_STRUCTP(r->out.alias_handle);
947 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
951 aliasname = r->in.aliasname->string;
953 if (aliasname == NULL) {
954 return NT_STATUS_INVALID_PARAMETER;
957 /* Check if alias already exists */
958 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
960 "(&(sAMAccountName=%s)(objectclass=group))",
964 return NT_STATUS_ALIAS_EXISTS;
969 /* pull in all the template attributes */
970 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
971 "(&(name=TemplateAlias)"
972 "(objectclass=aliasTemplate))");
974 DEBUG(0,("Failed to load TemplateAlias from samdb\n"));
975 return NT_STATUS_INTERNAL_DB_CORRUPTION;
979 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
980 d_state->domain_dn, "nextRid", &rid);
981 if (!NT_STATUS_IS_OK(status)) {
985 /* and the group SID */
986 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
988 return NT_STATUS_NO_MEMORY;
992 guid = GUID_random();
993 guidstr = GUID_string(mem_ctx, &guid);
995 return NT_STATUS_NO_MEMORY;
998 /* add core elements to the ldb_message for the alias */
999 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", aliasname,
1000 d_state->domain_dn);
1002 return NT_STATUS_NO_MEMORY;
1005 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", aliasname);
1006 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", aliasname);
1007 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", aliasname);
1008 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "group");
1009 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
1010 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
1011 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
1012 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
1014 /* create the alias */
1015 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
1017 DEBUG(0,("Failed to create alias record %s\n", msg.dn));
1018 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1021 a_state = talloc_p(d_state, struct samr_account_state);
1023 return NT_STATUS_NO_MEMORY;
1026 a_state->sam_ctx = d_state->sam_ctx;
1027 a_state->access_mask = r->in.access_mask;
1028 a_state->domain_state = talloc_reference(a_state, d_state);
1029 a_state->account_dn = talloc_steal(a_state, msg.dn);
1030 a_state->account_sid = talloc_steal(a_state, sidstr);
1031 a_state->account_name = talloc_strdup(a_state, aliasname);
1032 if (!a_state->account_name) {
1033 return NT_STATUS_NO_MEMORY;
1036 /* create the policy handle */
1037 a_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_ALIAS);
1038 if (a_handle == NULL)
1039 return NT_STATUS_NO_MEMORY;
1041 a_handle->data = a_state;
1042 a_handle->destroy = samr_handle_destroy;
1044 *r->out.alias_handle = a_handle->wire_handle;
1047 return NT_STATUS_OK;
1052 samr_EnumDomainAliases
1054 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1055 struct samr_EnumDomainAliases *r)
1057 struct dcesrv_handle *h;
1058 struct samr_domain_state *d_state;
1059 struct ldb_message **res;
1060 int ldb_cnt, count, i, first;
1061 struct samr_SamEntry *entries;
1062 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1063 struct dom_sid *domain_sid;
1065 *r->out.resume_handle = 0;
1067 r->out.num_entries = 0;
1069 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1073 /* search for all domain groups in this domain. This could possibly be
1074 cached and resumed based on resume_key */
1075 ldb_cnt = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1077 "(&(|(grouptype=%s)(grouptype=%s)))"
1078 "(objectclass=group))",
1080 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1082 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1083 if (ldb_cnt == -1) {
1084 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1087 return NT_STATUS_OK;
1090 /* convert to SamEntry format */
1091 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, ldb_cnt);
1093 return NT_STATUS_NO_MEMORY;
1097 domain_sid = dom_sid_parse_talloc(mem_ctx, d_state->domain_sid);
1099 for (i=0;i<ldb_cnt;i++) {
1100 struct dom_sid *alias_sid;
1102 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1105 if (alias_sid == NULL)
1108 if (!dom_sid_in_domain(domain_sid, alias_sid))
1111 entries[count].idx =
1112 alias_sid->sub_auths[alias_sid->num_auths-1];
1113 entries[count].name.string =
1114 samdb_result_string(res[i], "sAMAccountName", "");
1118 /* sort the results by rid */
1119 qsort(entries, count, sizeof(struct samr_SamEntry),
1120 (comparison_fn_t)compare_SamEntry);
1122 /* find the first entry to return */
1124 first<count && entries[first].idx <= *r->in.resume_handle;
1127 if (first == count) {
1128 return NT_STATUS_OK;
1131 r->out.num_entries = count - first;
1132 r->out.num_entries = MIN(r->out.num_entries, 1000);
1134 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
1136 return NT_STATUS_NO_MEMORY;
1139 r->out.sam->entries = entries+first;
1140 r->out.sam->count = r->out.num_entries;
1142 if (r->out.num_entries < count - first) {
1143 *r->out.resume_handle =
1144 entries[first+r->out.num_entries-1].idx;
1145 return STATUS_MORE_ENTRIES;
1148 return NT_STATUS_OK;
1153 samr_GetAliasMembership
1155 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1156 struct samr_GetAliasMembership *r)
1158 struct dcesrv_handle *h;
1159 struct samr_domain_state *d_state;
1160 struct ldb_message **res;
1161 struct dom_sid *domain_sid;
1164 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1168 if (r->in.sids->num_sids > 0) {
1170 const char * const attrs[2] = { "objectSid", NULL };
1172 filter = talloc_asprintf(mem_ctx,
1173 "(&(|(grouptype=%s)(grouptype=%s))"
1174 "(objectclass=group)(|",
1176 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1178 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1180 return NT_STATUS_NO_MEMORY;
1182 for (i=0; i<r->in.sids->num_sids; i++) {
1183 const char *sidstr, *memberdn;
1185 sidstr = dom_sid_string(mem_ctx,
1186 r->in.sids->sids[i].sid);
1188 return NT_STATUS_NO_MEMORY;
1190 memberdn = samdb_search_string(d_state->sam_ctx,
1191 mem_ctx, NULL, "dn",
1195 if (memberdn == NULL)
1198 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1201 return NT_STATUS_NO_MEMORY;
1204 count = samdb_search(d_state->sam_ctx, mem_ctx,
1205 d_state->domain_dn, &res, attrs,
1208 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1211 r->out.rids->count = 0;
1212 r->out.rids->ids = talloc_array_p(mem_ctx, uint32_t, count);
1213 if (r->out.rids->ids == NULL)
1214 return NT_STATUS_NO_MEMORY;
1216 domain_sid = dom_sid_parse_talloc(mem_ctx, d_state->domain_sid);
1217 if (domain_sid == NULL)
1218 return NT_STATUS_NO_MEMORY;
1220 for (i=0; i<count; i++) {
1221 struct dom_sid *alias_sid;
1223 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1225 if (alias_sid == NULL) {
1226 DEBUG(0, ("Could not find objectSid\n"));
1230 if (!dom_sid_in_domain(domain_sid, alias_sid))
1233 r->out.rids->ids[r->out.rids->count] =
1234 alias_sid->sub_auths[alias_sid->num_auths-1];
1235 r->out.rids->count += 1;
1238 return NT_STATUS_OK;
1245 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1246 struct samr_LookupNames *r)
1248 struct dcesrv_handle *h;
1249 struct samr_domain_state *d_state;
1251 NTSTATUS status = NT_STATUS_OK;
1252 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1255 ZERO_STRUCT(r->out.rids);
1256 ZERO_STRUCT(r->out.types);
1258 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1262 if (r->in.num_names == 0) {
1263 return NT_STATUS_OK;
1266 r->out.rids.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
1267 r->out.types.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
1268 if (!r->out.rids.ids || !r->out.types.ids) {
1269 return NT_STATUS_NO_MEMORY;
1271 r->out.rids.count = r->in.num_names;
1272 r->out.types.count = r->in.num_names;
1274 for (i=0;i<r->in.num_names;i++) {
1275 struct ldb_message **res;
1276 struct dom_sid2 *sid;
1278 uint32_t atype, rtype;
1280 r->out.rids.ids[i] = 0;
1281 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1283 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1284 "sAMAccountName=%s", r->in.names[i].string);
1286 status = STATUS_SOME_UNMAPPED;
1290 sidstr = samdb_result_string(res[0], "objectSid", NULL);
1291 if (sidstr == NULL) {
1292 status = STATUS_SOME_UNMAPPED;
1296 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
1298 status = STATUS_SOME_UNMAPPED;
1302 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1304 status = STATUS_SOME_UNMAPPED;
1308 rtype = samdb_atype_map(atype);
1310 if (rtype == SID_NAME_UNKNOWN) {
1311 status = STATUS_SOME_UNMAPPED;
1315 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1316 r->out.types.ids[i] = rtype;
1327 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1328 struct samr_LookupRids *r)
1330 struct dcesrv_handle *h;
1331 struct samr_domain_state *d_state;
1333 NTSTATUS status = NT_STATUS_OK;
1334 struct samr_String *names;
1337 ZERO_STRUCT(r->out.names);
1338 ZERO_STRUCT(r->out.types);
1340 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1344 if (r->in.num_rids == 0)
1345 return NT_STATUS_OK;
1347 names = talloc_array_p(mem_ctx, struct samr_String, r->in.num_rids);
1348 ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_rids);
1350 if ((names == NULL) || (ids == NULL))
1351 return NT_STATUS_NO_MEMORY;
1353 for (i=0; i<r->in.num_rids; i++) {
1354 struct ldb_message **res;
1356 const char * const attrs[] = { "sAMAccountType",
1357 "sAMAccountName", NULL };
1360 ids[i] = SID_NAME_UNKNOWN;
1362 count = samdb_search(d_state->sam_ctx, mem_ctx,
1363 d_state->domain_dn, &res, attrs,
1364 "(objectSid=%s-%u)", d_state->domain_sid,
1367 status = STATUS_SOME_UNMAPPED;
1371 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1374 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1376 status = STATUS_SOME_UNMAPPED;
1380 ids[i] = samdb_atype_map(atype);
1382 if (ids[i] == SID_NAME_UNKNOWN) {
1383 status = STATUS_SOME_UNMAPPED;
1388 r->out.names.names = names;
1389 r->out.names.count = r->in.num_rids;
1391 r->out.types.ids = ids;
1392 r->out.types.count = r->in.num_rids;
1401 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1402 struct samr_OpenGroup *r)
1404 struct samr_domain_state *d_state;
1405 struct samr_account_state *a_state;
1406 struct dcesrv_handle *h;
1407 const char *groupname, *sidstr;
1408 struct ldb_message **msgs;
1409 struct dcesrv_handle *g_handle;
1410 const char * const attrs[2] = { "sAMAccountName", NULL };
1413 ZERO_STRUCTP(r->out.group_handle);
1415 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1419 /* form the group SID */
1420 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1422 return NT_STATUS_NO_MEMORY;
1425 /* search for the group record */
1426 ret = samdb_search(d_state->sam_ctx,
1427 mem_ctx, d_state->domain_dn, &msgs, attrs,
1428 "(&(objectSid=%s)(objectclass=group)"
1430 sidstr, ldb_hexstr(mem_ctx,
1431 GTYPE_SECURITY_GLOBAL_GROUP));
1433 return NT_STATUS_NO_SUCH_GROUP;
1436 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1437 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1440 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1441 if (groupname == NULL) {
1442 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1443 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1446 a_state = talloc_p(d_state, struct samr_account_state);
1448 return NT_STATUS_NO_MEMORY;
1450 a_state->sam_ctx = d_state->sam_ctx;
1451 a_state->access_mask = r->in.access_mask;
1452 a_state->domain_state = talloc_reference(a_state, d_state);
1453 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1454 a_state->account_sid = talloc_steal(a_state, sidstr);
1455 a_state->account_name = talloc_strdup(a_state, groupname);
1456 if (!a_state->account_name) {
1457 return NT_STATUS_NO_MEMORY;
1460 /* create the policy handle */
1461 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1463 return NT_STATUS_NO_MEMORY;
1466 g_handle->data = a_state;
1467 g_handle->destroy = samr_handle_destroy;
1469 *r->out.group_handle = g_handle->wire_handle;
1471 return NT_STATUS_OK;
1474 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1476 #define QUERY_STRING(msg, field, attr) \
1477 r->out.info->field = samdb_result_string(msg, attr, "");
1478 #define QUERY_UINT(msg, field, attr) \
1479 r->out.info->field = samdb_result_uint(msg, attr, 0);
1480 #define QUERY_RID(msg, field, attr) \
1481 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1482 #define QUERY_NTTIME(msg, field, attr) \
1483 r->out.info->field = samdb_result_nttime(msg, attr, 0);
1484 #define QUERY_APASSC(msg, field, attr) \
1485 r->out.info->field = samdb_result_allow_password_change(a_state->sam_ctx, mem_ctx, \
1486 a_state->domain_state->domain_dn, msg, attr);
1487 #define QUERY_FPASSC(msg, field, attr) \
1488 r->out.info->field = samdb_result_force_password_change(a_state->sam_ctx, mem_ctx, \
1489 a_state->domain_state->domain_dn, msg, attr);
1490 #define QUERY_LHOURS(msg, field, attr) \
1491 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1492 #define QUERY_AFLAGS(msg, field, attr) \
1493 r->out.info->field = samdb_result_acct_flags(msg, attr);
1496 /* these are used to make the Set[User|Group]Info code easier to follow */
1498 #define SET_STRING(mod, field, attr) do { \
1499 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1500 if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1501 return NT_STATUS_NO_MEMORY; \
1505 #define SET_UINT(mod, field, attr) do { \
1506 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1507 return NT_STATUS_NO_MEMORY; \
1511 #define SET_AFLAGS(msg, field, attr) do { \
1512 if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1513 return NT_STATUS_NO_MEMORY; \
1517 #define SET_LHOURS(msg, field, attr) do { \
1518 if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
1519 return NT_STATUS_NO_MEMORY; \
1526 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1527 struct samr_QueryGroupInfo *r)
1529 struct dcesrv_handle *h;
1530 struct samr_account_state *a_state;
1531 struct ldb_message *msg, **res;
1532 const char * const attrs[4] = { "sAMAccountName", "description",
1533 "numMembers", NULL };
1538 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1542 /* pull all the group attributes */
1543 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1544 "dn=%s", a_state->account_dn);
1546 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1550 /* allocate the info structure */
1551 r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1552 if (r->out.info == NULL) {
1553 return NT_STATUS_NO_MEMORY;
1555 ZERO_STRUCTP(r->out.info);
1557 /* Fill in the level */
1558 switch (r->in.level) {
1560 QUERY_STRING(msg, all.name.string, "sAMAccountName");
1561 r->out.info->all.attributes = 7; /* Do like w2k3 */
1562 QUERY_UINT (msg, all.num_members, "numMembers")
1563 QUERY_STRING(msg, all.description.string, "description");
1566 QUERY_STRING(msg, name.string, "sAMAccountName");
1569 r->out.info->unknown.unknown = 7;
1571 case GroupInfoDescription:
1572 QUERY_STRING(msg, description.string, "description");
1576 return NT_STATUS_INVALID_INFO_CLASS;
1579 return NT_STATUS_OK;
1586 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1587 struct samr_SetGroupInfo *r)
1589 struct dcesrv_handle *h;
1590 struct samr_account_state *a_state;
1591 struct ldb_message mod, *msg = &mod;
1594 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1599 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1601 return NT_STATUS_NO_MEMORY;
1604 switch (r->in.level) {
1605 case GroupInfoDescription:
1606 SET_STRING(msg, description.string, "description");
1609 /* On W2k3 this does not change the name, it changes the
1610 * sAMAccountName attribute */
1611 SET_STRING(msg, name.string, "sAMAccountName");
1614 /* This does not do anything obviously visible in W2k3 LDAP */
1617 return NT_STATUS_INVALID_INFO_CLASS;
1620 /* modify the samdb record */
1621 ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
1623 /* we really need samdb.c to return NTSTATUS */
1624 return NT_STATUS_UNSUCCESSFUL;
1627 return NT_STATUS_OK;
1634 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1635 struct samr_AddGroupMember *r)
1637 struct dcesrv_handle *h;
1638 struct samr_account_state *a_state;
1639 struct samr_domain_state *d_state;
1640 struct ldb_message mod;
1642 const char *memberdn;
1643 struct ldb_message **msgs;
1644 const char * const attrs[2] = { "dn", NULL };
1647 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1650 d_state = a_state->domain_state;
1652 membersidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid,
1654 if (membersidstr == NULL)
1655 return NT_STATUS_NO_MEMORY;
1657 /* In native mode, AD can also nest domain groups. Not sure yet
1658 * whether this is also available via RPC. */
1659 ret = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1660 &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1664 return NT_STATUS_NO_SUCH_USER;
1667 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1669 memberdn = samdb_result_string(msgs[0], "dn", NULL);
1671 if (memberdn == NULL)
1672 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1675 mod.dn = talloc_reference(mem_ctx, a_state->account_dn);
1677 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, &mod, "member",
1679 return NT_STATUS_UNSUCCESSFUL;
1681 if (samdb_modify(a_state->sam_ctx, mem_ctx, &mod) != 0)
1682 return NT_STATUS_UNSUCCESSFUL;
1684 return NT_STATUS_OK;
1689 samr_DeleteDomainGroup
1691 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1692 struct samr_DeleteDomainGroup *r)
1694 struct dcesrv_handle *h;
1695 struct samr_account_state *a_state;
1698 *r->out.group_handle = *r->in.group_handle;
1700 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1704 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1706 return NT_STATUS_UNSUCCESSFUL;
1709 ZERO_STRUCTP(r->out.group_handle);
1711 return NT_STATUS_OK;
1716 samr_DeleteGroupMember
1718 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1719 struct samr_DeleteGroupMember *r)
1721 struct dcesrv_handle *h;
1722 struct samr_account_state *a_state;
1723 struct samr_domain_state *d_state;
1724 struct ldb_message mod;
1726 const char *memberdn;
1727 struct ldb_message **msgs;
1728 const char * const attrs[2] = { "dn", NULL };
1731 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1734 d_state = a_state->domain_state;
1736 membersidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid,
1738 if (membersidstr == NULL)
1739 return NT_STATUS_NO_MEMORY;
1741 /* In native mode, AD can also nest domain groups. Not sure yet
1742 * whether this is also available via RPC. */
1743 ret = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1744 &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1748 return NT_STATUS_NO_SUCH_USER;
1751 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1753 memberdn = samdb_result_string(msgs[0], "dn", NULL);
1755 if (memberdn == NULL)
1756 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1759 mod.dn = talloc_reference(mem_ctx, a_state->account_dn);
1761 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, &mod, "member",
1763 return NT_STATUS_UNSUCCESSFUL;
1765 if (samdb_modify(a_state->sam_ctx, mem_ctx, &mod) != 0)
1766 return NT_STATUS_UNSUCCESSFUL;
1768 return NT_STATUS_OK;
1773 samr_QueryGroupMember
1775 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1776 struct samr_QueryGroupMember *r)
1778 struct dcesrv_handle *h;
1779 struct samr_account_state *a_state;
1780 struct ldb_message **res;
1781 struct ldb_message_element *el;
1782 struct samr_ridArray *array;
1783 const char * const attrs[2] = { "member", NULL };
1786 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1790 /* pull the member attribute */
1791 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1792 "dn=%s", a_state->account_dn);
1795 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1798 array = talloc_p(mem_ctx, struct samr_ridArray);
1801 return NT_STATUS_NO_MEMORY;
1803 ZERO_STRUCTP(array);
1805 el = ldb_msg_find_element(res[0], "member");
1810 array->count = el->num_values;
1812 array->rids = talloc_array_p(mem_ctx, uint32,
1814 if (array->rids == NULL)
1815 return NT_STATUS_NO_MEMORY;
1817 array->unknown = talloc_array_p(mem_ctx, uint32,
1819 if (array->unknown == NULL)
1820 return NT_STATUS_NO_MEMORY;
1822 for (i=0; i<el->num_values; i++) {
1823 struct ldb_message **res2;
1824 const char * const attrs2[2] = { "objectSid", NULL };
1825 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL,
1826 &res2, attrs2, "dn=%s",
1827 (char *)el->values[i].data);
1829 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1832 samdb_result_rid_from_sid(mem_ctx, res2[0],
1835 if (array->rids[i] == 0)
1836 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1838 array->unknown[i] = 7; /* Not sure what this is.. */
1842 r->out.rids = array;
1844 return NT_STATUS_OK;
1849 samr_SetMemberAttributesOfGroup
1851 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1852 struct samr_SetMemberAttributesOfGroup *r)
1854 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1861 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1862 struct samr_OpenAlias *r)
1864 struct samr_domain_state *d_state;
1865 struct samr_account_state *a_state;
1866 struct dcesrv_handle *h;
1867 const char *aliasname, *sidstr;
1868 struct ldb_message **msgs;
1869 struct dcesrv_handle *g_handle;
1870 const char * const attrs[2] = { "sAMAccountName", NULL };
1873 ZERO_STRUCTP(r->out.alias_handle);
1875 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1879 /* form the alias SID */
1880 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid,
1883 return NT_STATUS_NO_MEMORY;
1885 /* search for the group record */
1886 ret = samdb_search(d_state->sam_ctx,
1887 mem_ctx, d_state->domain_dn, &msgs, attrs,
1888 "(&(objectSid=%s)(objectclass=group)"
1889 "(|(grouptype=%s)(grouptype=%s)))",
1892 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1894 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1896 return NT_STATUS_NO_SUCH_ALIAS;
1899 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1900 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1903 aliasname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1904 if (aliasname == NULL) {
1905 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1906 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1909 a_state = talloc_p(d_state, struct samr_account_state);
1911 return NT_STATUS_NO_MEMORY;
1913 a_state->sam_ctx = d_state->sam_ctx;
1914 a_state->access_mask = r->in.access_mask;
1915 a_state->domain_state = talloc_reference(a_state, d_state);
1916 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1917 a_state->account_sid = talloc_steal(a_state, sidstr);
1918 a_state->account_name = talloc_strdup(a_state, aliasname);
1919 if (!a_state->account_name) {
1920 return NT_STATUS_NO_MEMORY;
1923 /* create the policy handle */
1924 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_ALIAS);
1926 return NT_STATUS_NO_MEMORY;
1929 g_handle->data = a_state;
1930 g_handle->destroy = samr_handle_destroy;
1932 *r->out.alias_handle = g_handle->wire_handle;
1934 return NT_STATUS_OK;
1941 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1942 struct samr_QueryAliasInfo *r)
1944 struct dcesrv_handle *h;
1945 struct samr_account_state *a_state;
1946 struct ldb_message *msg, **res;
1947 const char * const attrs[4] = { "sAMAccountName", "description",
1948 "numMembers", NULL };
1953 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
1957 /* pull all the alias attributes */
1958 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1959 "dn=%s", a_state->account_dn);
1961 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1965 /* allocate the info structure */
1966 r->out.info = talloc_p(mem_ctx, union samr_AliasInfo);
1967 if (r->out.info == NULL) {
1968 return NT_STATUS_NO_MEMORY;
1970 ZERO_STRUCTP(r->out.info);
1972 switch(r->in.level) {
1974 QUERY_STRING(msg, all.name.string, "sAMAccountName");
1975 QUERY_UINT (msg, all.num_members, "numMembers");
1976 QUERY_STRING(msg, all.description.string, "description");
1979 QUERY_STRING(msg, name.string, "sAMAccountName");
1981 case AliasInfoDescription:
1982 QUERY_STRING(msg, description.string, "description");
1986 return NT_STATUS_INVALID_INFO_CLASS;
1989 return NT_STATUS_OK;
1996 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1997 struct samr_SetAliasInfo *r)
1999 struct dcesrv_handle *h;
2000 struct samr_account_state *a_state;
2001 struct ldb_message mod, *msg = &mod;
2004 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2009 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
2011 return NT_STATUS_NO_MEMORY;
2014 switch (r->in.level) {
2015 case AliasInfoDescription:
2016 SET_STRING(msg, description.string, "description");
2019 /* On W2k3 this does not change the name, it changes the
2020 * sAMAccountName attribute */
2021 SET_STRING(msg, name.string, "sAMAccountName");
2024 return NT_STATUS_INVALID_INFO_CLASS;
2027 /* modify the samdb record */
2028 ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
2030 /* we really need samdb.c to return NTSTATUS */
2031 return NT_STATUS_UNSUCCESSFUL;
2034 return NT_STATUS_OK;
2041 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2042 struct samr_DeleteDomAlias *r)
2044 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2051 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2052 struct samr_AddAliasMember *r)
2054 struct dcesrv_handle *h;
2055 struct samr_account_state *a_state;
2056 struct samr_domain_state *d_state;
2058 struct ldb_message mod;
2059 struct ldb_message **msgs;
2060 const char * const attrs[2] = { "dn", NULL };
2061 const char *memberdn = NULL;
2064 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2067 d_state = a_state->domain_state;
2069 sidstr = dom_sid_string(mem_ctx, r->in.sid);
2071 return NT_STATUS_INVALID_PARAMETER;
2073 ret = samdb_search(d_state->sam_ctx, mem_ctx, NULL,
2074 &msgs, attrs, "(objectsid=%s)", sidstr);
2077 memberdn = ldb_msg_find_string(msgs[0], "dn", NULL);
2078 } else if (ret > 1) {
2079 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
2080 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2081 } else if (ret == 0) {
2082 struct ldb_message msg;
2084 const char *guidstr, *basedn;
2086 /* We might have to create a ForeignSecurityPrincipal, but
2087 * only if it's not our own domain */
2088 if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx,
2089 d_state->domain_sid),
2091 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2095 /* pull in all the template attributes */
2096 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
2097 "(&(name=TemplateForeignSecurityPrincipal)"
2098 "(objectclass=foreignSecurityPrincipalTemplate))");
2100 DEBUG(0,("Failed to load "
2101 "TemplateForeignSecurityPrincipal "
2103 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2107 guid = GUID_random();
2108 guidstr = GUID_string(mem_ctx, &guid);
2110 return NT_STATUS_NO_MEMORY;
2113 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
2114 * put the ForeignSecurityPrincipals? d_state->domain_dn does
2115 * not work, this is wrong for the Builtin domain, there's no
2116 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
2119 basedn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2121 "(&(objectClass=container)"
2122 "(cn=ForeignSecurityPrincipals))");
2124 if (basedn == NULL) {
2125 DEBUG(0, ("Failed to find DN for "
2126 "ForeignSecurityPrincipal container\n"));
2127 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2130 /* add core elements to the ldb_message for the alias */
2131 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,%s", sidstr, basedn);
2133 return NT_STATUS_NO_MEMORY;
2137 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
2139 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
2141 "foreignSecurityPrincipal");
2142 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
2143 "objectSid", sidstr);
2144 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
2145 "objectGUID", guidstr);
2147 /* create the alias */
2148 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
2150 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2151 "record %s\n", msg.dn));
2152 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2155 DEBUG(0, ("samdb_search returned %d\n", ret));
2158 if (memberdn == NULL) {
2159 DEBUG(0, ("Could not find memberdn\n"));
2160 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2164 mod.dn = talloc_reference(mem_ctx, a_state->account_dn);
2166 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, &mod, "member",
2168 return NT_STATUS_UNSUCCESSFUL;
2170 if (samdb_modify(a_state->sam_ctx, mem_ctx, &mod) != 0)
2171 return NT_STATUS_UNSUCCESSFUL;
2173 return NT_STATUS_OK;
2178 samr_DeleteAliasMember
2180 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2181 struct samr_DeleteAliasMember *r)
2183 struct dcesrv_handle *h;
2184 struct samr_account_state *a_state;
2185 struct samr_domain_state *d_state;
2187 struct ldb_message mod;
2188 const char *memberdn;
2190 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2193 d_state = a_state->domain_state;
2195 sidstr = dom_sid_string(mem_ctx, r->in.sid);
2197 return NT_STATUS_INVALID_PARAMETER;
2199 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2200 "dn", "(objectSid=%s)", sidstr);
2202 if (memberdn == NULL)
2203 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2206 mod.dn = talloc_reference(mem_ctx, a_state->account_dn);
2208 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, &mod, "member",
2210 return NT_STATUS_UNSUCCESSFUL;
2212 if (samdb_modify(a_state->sam_ctx, mem_ctx, &mod) != 0)
2213 return NT_STATUS_UNSUCCESSFUL;
2215 return NT_STATUS_OK;
2220 samr_GetMembersInAlias
2222 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2223 struct samr_GetMembersInAlias *r)
2225 struct dcesrv_handle *h;
2226 struct samr_account_state *a_state;
2227 struct samr_domain_state *d_state;
2228 struct ldb_message **msgs;
2229 struct lsa_SidPtr *sids;
2230 struct ldb_message_element *el;
2231 const char * const attrs[2] = { "member", NULL};
2234 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2237 d_state = a_state->domain_state;
2239 ret = samdb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2240 "dn=%s", a_state->account_dn);
2243 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2245 r->out.sids->num_sids = 0;
2246 r->out.sids->sids = NULL;
2248 el = ldb_msg_find_element(msgs[0], "member");
2253 sids = talloc_array_p(mem_ctx, struct lsa_SidPtr,
2257 return NT_STATUS_NO_MEMORY;
2259 for (i=0; i<el->num_values; i++) {
2260 struct ldb_message **msgs2;
2261 const char * const attrs2[2] = { "objectSid", NULL };
2262 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL,
2263 &msgs2, attrs2, "dn=%s",
2264 (char *)el->values[i].data);
2266 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2268 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2271 if (sids[i].sid == NULL)
2272 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2274 r->out.sids->num_sids = el->num_values;
2275 r->out.sids->sids = sids;
2278 return NT_STATUS_OK;
2284 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2285 struct samr_OpenUser *r)
2287 struct samr_domain_state *d_state;
2288 struct samr_account_state *a_state;
2289 struct dcesrv_handle *h;
2290 const char *account_name, *sidstr;
2291 struct ldb_message **msgs;
2292 struct dcesrv_handle *u_handle;
2293 const char * const attrs[2] = { "sAMAccountName", NULL };
2296 ZERO_STRUCTP(r->out.user_handle);
2298 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2302 /* form the users SID */
2303 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
2305 return NT_STATUS_NO_MEMORY;
2308 /* search for the user record */
2309 ret = samdb_search(d_state->sam_ctx,
2310 mem_ctx, d_state->domain_dn, &msgs, attrs,
2311 "(&(objectSid=%s)(objectclass=user))",
2314 return NT_STATUS_NO_SUCH_USER;
2317 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
2318 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2321 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2322 if (account_name == NULL) {
2323 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
2324 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2327 a_state = talloc_p(d_state, struct samr_account_state);
2329 return NT_STATUS_NO_MEMORY;
2331 a_state->sam_ctx = d_state->sam_ctx;
2332 a_state->access_mask = r->in.access_mask;
2333 a_state->domain_state = talloc_reference(a_state, d_state);
2334 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2335 a_state->account_sid = talloc_steal(a_state, sidstr);
2336 a_state->account_name = talloc_strdup(a_state, account_name);
2337 if (!a_state->account_name) {
2338 return NT_STATUS_NO_MEMORY;
2341 /* create the policy handle */
2342 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
2344 return NT_STATUS_NO_MEMORY;
2347 u_handle->data = a_state;
2348 u_handle->destroy = samr_handle_destroy;
2350 *r->out.user_handle = u_handle->wire_handle;
2352 return NT_STATUS_OK;
2360 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2361 struct samr_DeleteUser *r)
2363 struct dcesrv_handle *h;
2364 struct samr_account_state *a_state;
2367 *r->out.user_handle = *r->in.user_handle;
2369 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2373 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2375 return NT_STATUS_UNSUCCESSFUL;
2378 ZERO_STRUCTP(r->out.user_handle);
2380 return NT_STATUS_OK;
2387 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2388 struct samr_QueryUserInfo *r)
2390 struct dcesrv_handle *h;
2391 struct samr_account_state *a_state;
2392 struct ldb_message *msg, **res;
2397 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2401 /* pull all the user attributes */
2402 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
2403 "dn=%s", a_state->account_dn);
2405 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2409 /* allocate the info structure */
2410 r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
2411 if (r->out.info == NULL) {
2412 return NT_STATUS_NO_MEMORY;
2414 ZERO_STRUCTP(r->out.info);
2416 /* fill in the reply */
2417 switch (r->in.level) {
2419 QUERY_STRING(msg, info1.account_name.string, "sAMAccountName");
2420 QUERY_STRING(msg, info1.full_name.string, "displayName");
2421 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
2422 QUERY_STRING(msg, info1.description.string, "description");
2423 QUERY_STRING(msg, info1.comment.string, "comment");
2427 QUERY_STRING(msg, info2.comment.string, "comment");
2428 QUERY_UINT (msg, info2.country_code, "countryCode");
2429 QUERY_UINT (msg, info2.code_page, "codePage");
2433 QUERY_STRING(msg, info3.account_name.string, "sAMAccountName");
2434 QUERY_STRING(msg, info3.full_name.string, "displayName");
2435 QUERY_RID (msg, info3.rid, "objectSid");
2436 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
2437 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
2438 QUERY_STRING(msg, info3.home_drive.string, "homeDrive");
2439 QUERY_STRING(msg, info3.logon_script.string, "scriptPath");
2440 QUERY_STRING(msg, info3.profile_path.string, "profilePath");
2441 QUERY_STRING(msg, info3.workstations.string, "userWorkstations");
2442 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
2443 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
2444 QUERY_NTTIME(msg, info3.last_password_change, "pwdLastSet");
2445 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2446 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2447 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
2448 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
2449 QUERY_UINT (msg, info3.logon_count, "logonCount");
2450 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
2454 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
2458 QUERY_STRING(msg, info5.account_name.string, "sAMAccountName");
2459 QUERY_STRING(msg, info5.full_name.string, "displayName");
2460 QUERY_RID (msg, info5.rid, "objectSid");
2461 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
2462 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
2463 QUERY_STRING(msg, info5.home_drive.string, "homeDrive");
2464 QUERY_STRING(msg, info5.logon_script.string, "scriptPath");
2465 QUERY_STRING(msg, info5.profile_path.string, "profilePath");
2466 QUERY_STRING(msg, info5.description.string, "description");
2467 QUERY_STRING(msg, info5.workstations.string, "userWorkstations");
2468 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
2469 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
2470 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
2471 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
2472 QUERY_UINT (msg, info5.logon_count, "logonCount");
2473 QUERY_NTTIME(msg, info5.last_password_change, "pwdLastSet");
2474 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
2475 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
2479 QUERY_STRING(msg, info6.account_name.string, "sAMAccountName");
2480 QUERY_STRING(msg, info6.full_name.string, "displayName");
2484 QUERY_STRING(msg, info7.account_name.string, "sAMAccountName");
2488 QUERY_STRING(msg, info8.full_name.string, "displayName");
2492 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
2496 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
2497 QUERY_STRING(msg, info10.home_drive.string, "homeDrive");
2501 QUERY_STRING(msg, info11.logon_script.string, "scriptPath");
2505 QUERY_STRING(msg, info12.profile_path.string, "profilePath");
2509 QUERY_STRING(msg, info13.description.string, "description");
2513 QUERY_STRING(msg, info14.workstations.string, "userWorkstations");
2517 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
2521 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
2524 QUERY_STRING(msg, info20.parameters.string, "userParameters");
2528 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
2529 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
2530 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
2531 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
2532 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
2533 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
2534 QUERY_STRING(msg, info21.account_name.string, "sAMAccountName");
2535 QUERY_STRING(msg, info21.full_name.string, "displayName");
2536 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
2537 QUERY_STRING(msg, info21.home_drive.string, "homeDrive");
2538 QUERY_STRING(msg, info21.logon_script.string, "scriptPath");
2539 QUERY_STRING(msg, info21.profile_path.string, "profilePath");
2540 QUERY_STRING(msg, info21.description.string, "description");
2541 QUERY_STRING(msg, info21.workstations.string, "userWorkstations");
2542 QUERY_STRING(msg, info21.comment.string, "comment");
2543 QUERY_STRING(msg, info21.parameters.string, "userParameters");
2544 QUERY_RID (msg, info21.rid, "objectSid");
2545 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
2546 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
2547 r->out.info->info21.fields_present = 0x00FFFFFF;
2548 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
2549 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
2550 QUERY_UINT (msg, info21.logon_count, "logonCount");
2551 QUERY_UINT (msg, info21.country_code, "countryCode");
2552 QUERY_UINT (msg, info21.code_page, "codePage");
2558 return NT_STATUS_INVALID_INFO_CLASS;
2561 return NT_STATUS_OK;
2568 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2569 struct samr_SetUserInfo *r)
2571 struct dcesrv_handle *h;
2572 struct samr_account_state *a_state;
2573 struct ldb_message mod, *msg = &mod;
2575 NTSTATUS status = NT_STATUS_OK;
2577 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2582 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
2584 return NT_STATUS_NO_MEMORY;
2587 switch (r->in.level) {
2589 SET_STRING(msg, info2.comment.string, "comment");
2590 SET_UINT (msg, info2.country_code, "countryCode");
2591 SET_UINT (msg, info2.code_page, "codePage");
2595 SET_LHOURS(msg, info4.logon_hours, "logonHours");
2599 SET_STRING(msg, info6.full_name.string, "displayName");
2603 SET_STRING(msg, info8.full_name.string, "displayName");
2607 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
2611 SET_STRING(msg, info10.home_directory.string, "homeDirectory");
2612 SET_STRING(msg, info10.home_drive.string, "homeDrive");
2616 SET_STRING(msg, info11.logon_script.string, "scriptPath");
2620 SET_STRING(msg, info12.profile_path.string, "profilePath");
2624 SET_STRING(msg, info13.description.string, "description");
2628 SET_STRING(msg, info14.workstations.string, "userWorkstations");
2632 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
2636 SET_STRING(msg, info20.parameters.string, "userParameters");
2640 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
2641 IFSET(SAMR_FIELD_NAME)
2642 SET_STRING(msg, info21.full_name.string, "displayName");
2643 IFSET(SAMR_FIELD_DESCRIPTION)
2644 SET_STRING(msg, info21.description.string, "description");
2645 IFSET(SAMR_FIELD_COMMENT)
2646 SET_STRING(msg, info21.comment.string, "comment");
2647 IFSET(SAMR_FIELD_LOGON_SCRIPT)
2648 SET_STRING(msg, info21.logon_script.string, "scriptPath");
2649 IFSET(SAMR_FIELD_PROFILE_PATH)
2650 SET_STRING(msg, info21.profile_path.string, "profilePath");
2651 IFSET(SAMR_FIELD_WORKSTATION)
2652 SET_STRING(msg, info21.workstations.string, "userWorkstations");
2653 IFSET(SAMR_FIELD_LOGON_HOURS)
2654 SET_LHOURS(msg, info21.logon_hours, "logonHours");
2655 IFSET(SAMR_FIELD_ACCT_FLAGS)
2656 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
2657 IFSET(SAMR_FIELD_PARAMETERS)
2658 SET_STRING(msg, info21.parameters.string, "userParameters");
2659 IFSET(SAMR_FIELD_COUNTRY_CODE)
2660 SET_UINT (msg, info21.country_code, "countryCode");
2661 IFSET(SAMR_FIELD_CODE_PAGE)
2662 SET_UINT (msg, info21.code_page, "codePage");
2665 /* Any reason the rest of these can't be set? */
2670 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
2671 IFSET(SAMR_FIELD_NAME)
2672 SET_STRING(msg, info23.info.full_name.string, "displayName");
2673 IFSET(SAMR_FIELD_DESCRIPTION)
2674 SET_STRING(msg, info23.info.description.string, "description");
2675 IFSET(SAMR_FIELD_COMMENT)
2676 SET_STRING(msg, info23.info.comment.string, "comment");
2677 IFSET(SAMR_FIELD_LOGON_SCRIPT)
2678 SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
2679 IFSET(SAMR_FIELD_PROFILE_PATH)
2680 SET_STRING(msg, info23.info.profile_path.string, "profilePath");
2681 IFSET(SAMR_FIELD_WORKSTATION)
2682 SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
2683 IFSET(SAMR_FIELD_LOGON_HOURS)
2684 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
2685 IFSET(SAMR_FIELD_ACCT_FLAGS)
2686 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
2687 IFSET(SAMR_FIELD_PARAMETERS)
2688 SET_STRING(msg, info23.info.parameters.string, "userParameters");
2689 IFSET(SAMR_FIELD_COUNTRY_CODE)
2690 SET_UINT (msg, info23.info.country_code, "countryCode");
2691 IFSET(SAMR_FIELD_CODE_PAGE)
2692 SET_UINT (msg, info23.info.code_page, "codePage");
2693 IFSET(SAMR_FIELD_PASSWORD) {
2694 status = samr_set_password(dce_call,
2696 a_state->account_dn,
2697 a_state->domain_state->domain_dn,
2699 &r->in.info->info23.password);
2700 } else IFSET(SAMR_FIELD_PASSWORD2) {
2701 status = samr_set_password(dce_call,
2703 a_state->account_dn,
2704 a_state->domain_state->domain_dn,
2706 &r->in.info->info23.password);
2711 /* the set password levels are handled separately */
2713 status = samr_set_password(dce_call,
2715 a_state->account_dn,
2716 a_state->domain_state->domain_dn,
2718 &r->in.info->info24.password);
2722 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
2723 IFSET(SAMR_FIELD_NAME)
2724 SET_STRING(msg, info25.info.full_name.string, "displayName");
2725 IFSET(SAMR_FIELD_DESCRIPTION)
2726 SET_STRING(msg, info25.info.description.string, "description");
2727 IFSET(SAMR_FIELD_COMMENT)
2728 SET_STRING(msg, info25.info.comment.string, "comment");
2729 IFSET(SAMR_FIELD_LOGON_SCRIPT)
2730 SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
2731 IFSET(SAMR_FIELD_PROFILE_PATH)
2732 SET_STRING(msg, info25.info.profile_path.string, "profilePath");
2733 IFSET(SAMR_FIELD_WORKSTATION)
2734 SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
2735 IFSET(SAMR_FIELD_LOGON_HOURS)
2736 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
2737 IFSET(SAMR_FIELD_ACCT_FLAGS)
2738 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
2739 IFSET(SAMR_FIELD_PARAMETERS)
2740 SET_STRING(msg, info25.info.parameters.string, "userParameters");
2741 IFSET(SAMR_FIELD_COUNTRY_CODE)
2742 SET_UINT (msg, info25.info.country_code, "countryCode");
2743 IFSET(SAMR_FIELD_CODE_PAGE)
2744 SET_UINT (msg, info25.info.code_page, "codePage");
2745 IFSET(SAMR_FIELD_PASSWORD) {
2746 status = samr_set_password_ex(dce_call,
2748 a_state->account_dn,
2749 a_state->domain_state->domain_dn,
2751 &r->in.info->info25.password);
2752 } else IFSET(SAMR_FIELD_PASSWORD2) {
2753 status = samr_set_password_ex(dce_call,
2755 a_state->account_dn,
2756 a_state->domain_state->domain_dn,
2758 &r->in.info->info25.password);
2763 /* the set password levels are handled separately */
2765 status = samr_set_password_ex(dce_call,
2767 a_state->account_dn,
2768 a_state->domain_state->domain_dn,
2770 &r->in.info->info26.password);
2775 /* many info classes are not valid for SetUserInfo */
2776 return NT_STATUS_INVALID_INFO_CLASS;
2779 if (!NT_STATUS_IS_OK(status)) {
2783 /* modify the samdb record */
2784 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2786 /* we really need samdb.c to return NTSTATUS */
2787 return NT_STATUS_UNSUCCESSFUL;
2790 return NT_STATUS_OK;
2795 samr_GetGroupsForUser
2797 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2798 struct samr_GetGroupsForUser *r)
2800 struct dcesrv_handle *h;
2801 struct samr_account_state *a_state;
2802 struct samr_domain_state *d_state;
2803 struct ldb_message **res;
2804 const char * const attrs[2] = { "objectSid", NULL };
2805 struct samr_RidArray *array;
2808 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2811 d_state = a_state->domain_state;
2813 count = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
2814 "(&(member=%s)(grouptype=%s)(objectclass=group))",
2815 a_state->account_dn,
2816 ldb_hexstr(mem_ctx, GTYPE_SECURITY_GLOBAL_GROUP));
2818 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2820 array = talloc_p(mem_ctx, struct samr_RidArray);
2822 return NT_STATUS_NO_MEMORY;
2829 struct dom_sid *domain_sid;
2831 domain_sid = dom_sid_parse_talloc(mem_ctx,
2832 d_state->domain_sid);
2833 array->rid = talloc_array_p(mem_ctx, struct samr_RidType,
2836 if ((domain_sid == NULL) || (array->rid == NULL))
2837 return NT_STATUS_NO_MEMORY;
2839 for (i=0; i<count; i++) {
2840 struct dom_sid *group_sid;
2842 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
2844 if (group_sid == NULL) {
2845 DEBUG(0, ("Couldn't find objectSid attrib\n"));
2849 if (!dom_sid_in_domain(domain_sid, group_sid))
2852 array->rid[array->count].rid =
2853 group_sid->sub_auths[group_sid->num_auths-1];
2854 array->rid[array->count].type = 7;
2859 r->out.rids = array;
2861 return NT_STATUS_OK;
2866 samr_QueryDisplayInfo
2868 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2869 struct samr_QueryDisplayInfo *r)
2871 struct dcesrv_handle *h;
2872 struct samr_domain_state *d_state;
2873 struct ldb_message **res;
2874 int ldb_cnt, count, i;
2875 const char * const attrs[4] = { "objectSid", "sAMAccountName",
2876 "description", NULL };
2877 struct dom_sid *domain_sid;
2878 struct samr_DispEntryFull *entriesFull = NULL;
2879 struct samr_DispEntryAscii *entriesAscii = NULL;
2880 struct samr_DispEntryGeneral * entriesGeneral = NULL;
2883 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2887 switch (r->in.level) {
2890 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
2891 "(sAMAccountType=%s))",
2893 ATYPE_NORMAL_ACCOUNT));
2896 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
2897 "(sAMAccountType=%s))",
2899 ATYPE_WORKSTATION_TRUST));
2903 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%s)"
2904 "(objectclass=group))",
2905 ldb_hexstr(mem_ctx, GTYPE_SECURITY_GLOBAL_GROUP));
2908 return NT_STATUS_INVALID_INFO_CLASS;
2911 /* search for all domain groups in this domain. This could possibly be
2912 cached and resumed based on resume_key */
2913 ldb_cnt = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
2914 &res, attrs, "%s", filter);
2915 if (ldb_cnt == -1) {
2916 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2918 if (ldb_cnt == 0 || r->in.max_entries == 0) {
2919 return NT_STATUS_OK;
2922 switch (r->in.level) {
2924 entriesGeneral = talloc_array_p(mem_ctx,
2925 struct samr_DispEntryGeneral,
2930 entriesFull = talloc_array_p(mem_ctx,
2931 struct samr_DispEntryFull,
2936 entriesAscii = talloc_array_p(mem_ctx,
2937 struct samr_DispEntryAscii,
2942 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
2943 (entriesAscii == NULL))
2944 return NT_STATUS_NO_MEMORY;
2947 domain_sid = dom_sid_parse_talloc(mem_ctx, d_state->domain_sid);
2949 for (i=0; i<ldb_cnt; i++) {
2950 struct dom_sid *objectsid;
2952 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
2954 if (objectsid == NULL)
2957 if (!dom_sid_in_domain(domain_sid, objectsid))
2960 switch(r->in.level) {
2962 entriesGeneral[count].idx = count;
2963 entriesGeneral[count].rid =
2964 objectsid->sub_auths[objectsid->num_auths-1];
2965 entriesGeneral[count].acct_flags =
2966 samdb_result_acct_flags(res[i],
2967 "userAccountControl");
2968 entriesGeneral[count].account_name.string =
2969 samdb_result_string(res[i],
2970 "sAMAccountName", "");
2971 entriesGeneral[count].full_name.string =
2972 samdb_result_string(res[i], "displayName", "");
2973 entriesGeneral[count].description.string =
2974 samdb_result_string(res[i], "description", "");
2978 entriesFull[count].idx = count;
2979 entriesFull[count].rid =
2980 objectsid->sub_auths[objectsid->num_auths-1];
2981 entriesFull[count].acct_flags =
2982 samdb_result_acct_flags(res[i],
2983 "userAccountControl");
2984 if (r->in.level == 3) {
2985 /* We get a "7" here for groups */
2986 entriesFull[count].acct_flags = 7;
2988 entriesFull[count].account_name.string =
2989 samdb_result_string(res[i], "sAMAccountName",
2991 entriesFull[count].description.string =
2992 samdb_result_string(res[i], "description", "");
2996 entriesAscii[count].idx = count;
2997 entriesAscii[count].account_name.string =
2998 samdb_result_string(res[i], "sAMAccountName",
3006 r->out.total_size = count;
3008 if (r->in.start_idx >= count) {
3009 r->out.returned_size = 0;
3010 switch(r->in.level) {
3012 r->out.info.info1.count = r->out.returned_size;
3013 r->out.info.info1.entries = NULL;
3016 r->out.info.info2.count = r->out.returned_size;
3017 r->out.info.info2.entries = NULL;
3020 r->out.info.info3.count = r->out.returned_size;
3021 r->out.info.info3.entries = NULL;
3024 r->out.info.info4.count = r->out.returned_size;
3025 r->out.info.info4.entries = NULL;
3028 r->out.info.info5.count = r->out.returned_size;
3029 r->out.info.info5.entries = NULL;
3033 r->out.returned_size = MIN(count - r->in.start_idx,
3035 switch(r->in.level) {
3037 r->out.info.info1.count = r->out.returned_size;
3038 r->out.info.info1.entries =
3039 &(entriesGeneral[r->in.start_idx]);
3042 r->out.info.info2.count = r->out.returned_size;
3043 r->out.info.info2.entries =
3044 &(entriesFull[r->in.start_idx]);
3047 r->out.info.info3.count = r->out.returned_size;
3048 r->out.info.info3.entries =
3049 &(entriesFull[r->in.start_idx]);
3052 r->out.info.info4.count = r->out.returned_size;
3053 r->out.info.info4.entries =
3054 &(entriesAscii[r->in.start_idx]);
3057 r->out.info.info5.count = r->out.returned_size;
3058 r->out.info.info5.entries =
3059 &(entriesAscii[r->in.start_idx]);
3064 return (r->out.returned_size < (count - r->in.start_idx)) ?
3065 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3070 samr_GetDisplayEnumerationIndex
3072 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3073 struct samr_GetDisplayEnumerationIndex *r)
3075 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3080 samr_TestPrivateFunctionsDomain
3082 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3083 struct samr_TestPrivateFunctionsDomain *r)
3085 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3090 samr_TestPrivateFunctionsUser
3092 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3093 struct samr_TestPrivateFunctionsUser *r)
3095 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3102 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3103 struct samr_GetUserPwInfo *r)
3105 struct dcesrv_handle *h;
3106 struct samr_account_state *a_state;
3108 ZERO_STRUCT(r->out.info);
3110 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3114 r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength",
3115 "dn=%s", a_state->domain_state->domain_dn);
3116 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties",
3117 "dn=%s", a_state->account_dn);
3118 return NT_STATUS_OK;
3123 samr_RemoveMemberFromForeignDomain
3125 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3126 struct samr_RemoveMemberFromForeignDomain *r)
3128 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3133 samr_QueryDomainInfo2
3135 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3136 struct samr_QueryDomainInfo2 *r)
3138 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3145 just an alias for samr_QueryUserInfo
3147 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3148 struct samr_QueryUserInfo2 *r)
3150 struct samr_QueryUserInfo r1;
3153 r1.in.user_handle = r->in.user_handle;
3154 r1.in.level = r->in.level;
3156 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3158 r->out.info = r1.out.info;
3165 samr_QueryDisplayInfo2
3167 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3168 struct samr_QueryDisplayInfo2 *r)
3170 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3175 samr_GetDisplayEnumerationIndex2
3177 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3178 struct samr_GetDisplayEnumerationIndex2 *r)
3180 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3185 samr_QueryDisplayInfo3
3187 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3188 struct samr_QueryDisplayInfo3 *r)
3190 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3195 samr_AddMultipleMembersToAlias
3197 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3198 struct samr_AddMultipleMembersToAlias *r)
3200 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3205 samr_RemoveMultipleMembersFromAlias
3207 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3208 struct samr_RemoveMultipleMembersFromAlias *r)
3210 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3217 this fetches the default password properties for a domain
3219 note that w2k3 completely ignores the domain name in this call, and
3220 always returns the information for the servers primary domain
3222 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3223 struct samr_GetDomPwInfo *r)
3225 struct ldb_message **msgs;
3227 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
3230 ZERO_STRUCT(r->out.info);
3232 sam_ctx = samdb_connect(mem_ctx);
3233 if (sam_ctx == NULL) {
3234 return NT_STATUS_INVALID_SYSTEM_SERVICE;
3237 ret = samdb_search(sam_ctx,
3238 mem_ctx, NULL, &msgs, attrs,
3239 "(&(name=%s)(objectclass=domain))",
3242 return NT_STATUS_NO_SUCH_DOMAIN;
3245 samdb_search_free(sam_ctx, mem_ctx, msgs);
3246 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3249 r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
3250 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
3252 samdb_search_free(sam_ctx, mem_ctx, msgs);
3254 talloc_free(sam_ctx);
3255 return NT_STATUS_OK;
3262 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3263 struct samr_Connect2 *r)
3265 struct samr_Connect c;
3267 c.in.system_name = NULL;
3268 c.in.access_mask = r->in.access_mask;
3269 c.out.connect_handle = r->out.connect_handle;
3271 return samr_Connect(dce_call, mem_ctx, &c);
3278 just an alias for samr_SetUserInfo
3280 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3281 struct samr_SetUserInfo2 *r)
3283 struct samr_SetUserInfo r2;
3285 r2.in.user_handle = r->in.user_handle;
3286 r2.in.level = r->in.level;
3287 r2.in.info = r->in.info;
3289 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
3294 samr_SetBootKeyInformation
3296 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3297 struct samr_SetBootKeyInformation *r)
3299 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3304 samr_GetBootKeyInformation
3306 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3307 struct samr_GetBootKeyInformation *r)
3309 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3316 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3317 struct samr_Connect3 *r)
3319 struct samr_Connect c;
3321 c.in.system_name = NULL;
3322 c.in.access_mask = r->in.access_mask;
3323 c.out.connect_handle = r->out.connect_handle;
3325 return samr_Connect(dce_call, mem_ctx, &c);
3332 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3333 struct samr_Connect4 *r)
3335 struct samr_Connect c;
3337 c.in.system_name = NULL;
3338 c.in.access_mask = r->in.access_mask;
3339 c.out.connect_handle = r->out.connect_handle;
3341 return samr_Connect(dce_call, mem_ctx, &c);
3348 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3349 struct samr_Connect5 *r)
3351 struct samr_Connect c;
3354 c.in.system_name = NULL;
3355 c.in.access_mask = r->in.access_mask;
3356 c.out.connect_handle = r->out.connect_handle;
3358 status = samr_Connect(dce_call, mem_ctx, &c);
3360 r->out.info->info1.unknown1 = 3;
3361 r->out.info->info1.unknown2 = 0;
3362 r->out.level = r->in.level;
3371 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3372 struct samr_RidToSid *r)
3374 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3379 samr_SetDsrmPassword
3381 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3382 struct samr_SetDsrmPassword *r)
3384 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3389 samr_ValidatePassword
3391 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3392 struct samr_ValidatePassword *r)
3394 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3398 /* include the generated boilerplate */
3399 #include "librpc/gen_ndr/ndr_samr_s.c"