2 Unix SMB/CIFS implementation.
4 endpoint server for the samr pipe
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "rpc_server/common/common.h"
25 #include "rpc_server/samr/dcesrv_samr.h"
30 destroy a general handle. This relies on the talloc destructor being set up correctly
32 static void samr_handle_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
40 create a connection to the SAM database
42 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
43 struct samr_Connect *r)
45 struct samr_connect_state *c_state;
46 struct dcesrv_handle *handle;
48 ZERO_STRUCTP(r->out.handle);
50 c_state = talloc_p(NULL, struct samr_connect_state);
52 return NT_STATUS_NO_MEMORY;
55 /* make sure the sam database is accessible */
56 c_state->sam_ctx = samdb_connect(mem_ctx);
57 if (c_state->sam_ctx == NULL) {
58 talloc_destroy(c_state);
59 return NT_STATUS_INVALID_SYSTEM_SERVICE;
62 handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_CONNECT);
65 return NT_STATUS_NO_MEMORY;
68 handle->data = c_state;
69 handle->destroy = samr_handle_destroy;
71 c_state->access_mask = r->in.access_mask;
72 *r->out.handle = handle->wire_handle;
81 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
84 struct dcesrv_handle *h;
86 *r->out.handle = *r->in.handle;
88 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
90 /* this causes the callback samr_XXX_destroy() to be called by
91 the handle destroy code which destroys the state associated
93 dcesrv_handle_destroy(dce_call->conn, h);
95 ZERO_STRUCTP(r->out.handle);
104 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
105 struct samr_SetSecurity *r)
107 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
114 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
115 struct samr_QuerySecurity *r)
117 struct dcesrv_handle *h;
118 struct samr_SdBuf *sd;
122 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
124 sd = talloc_p(mem_ctx, struct samr_SdBuf);
126 return NT_STATUS_NO_MEMORY;
129 sd->sd = samdb_default_security_descriptor(mem_ctx);
140 we refuse this operation completely. If a admin wants to shutdown samr
141 in Samba then they should use the samba admin tools to disable the samr pipe
143 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
144 struct samr_Shutdown *r)
146 return NT_STATUS_ACCESS_DENIED;
153 this maps from a domain name to a SID
155 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
156 struct samr_LookupDomain *r)
158 struct samr_connect_state *c_state;
159 struct dcesrv_handle *h;
160 struct dom_sid2 *sid;
165 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
169 if (r->in.domain->name == NULL) {
170 return NT_STATUS_INVALID_PARAMETER;
173 sidstr = samdb_search_string(c_state->sam_ctx,
174 mem_ctx, NULL, "objectSid",
175 "(&(name=%s)(objectclass=domain))",
177 if (sidstr == NULL) {
178 return NT_STATUS_NO_SUCH_DOMAIN;
181 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
183 DEBUG(0,("samdb: Invalid sid '%s' for domain %s\n",
184 sidstr, r->in.domain->name));
185 return NT_STATUS_INTERNAL_DB_CORRUPTION;
197 list the domains in the SAM
199 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
200 struct samr_EnumDomains *r)
202 struct samr_connect_state *c_state;
203 struct dcesrv_handle *h;
204 struct samr_SamArray *array;
205 const char **domains;
206 int count, i, start_i;
208 *r->out.resume_handle = 0;
210 r->out.num_entries = 0;
212 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
216 count = samdb_search_string_multiple(c_state->sam_ctx,
217 mem_ctx, NULL, &domains,
218 "name", "(objectclass=domain)");
220 DEBUG(0,("samdb: no domains found in EnumDomains\n"));
221 return NT_STATUS_INTERNAL_DB_CORRUPTION;
224 *r->out.resume_handle = count;
226 start_i = *r->in.resume_handle;
228 if (start_i >= count) {
229 /* search past end of list is not an error for this call */
233 array = talloc_p(mem_ctx, struct samr_SamArray);
235 return NT_STATUS_NO_MEMORY;
239 array->entries = NULL;
241 array->entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count - start_i);
242 if (array->entries == NULL) {
243 return NT_STATUS_NO_MEMORY;
246 for (i=0;i<count-start_i;i++) {
247 array->entries[i].idx = start_i + i;
248 array->entries[i].name.name = domains[start_i+i];
252 r->out.num_entries = i;
253 array->count = r->out.num_entries;
260 close an open domain context
262 static int samr_Domain_destructor(void *ptr)
264 struct samr_domain_state *d_state = ptr;
265 /* we need to explicitly free the connect state to lower the
267 talloc_free(d_state->connect_state);
274 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
275 struct samr_OpenDomain *r)
277 struct dcesrv_handle *h_conn, *h_domain;
278 const char *sidstr, *domain_name;
279 struct samr_connect_state *c_state;
280 struct samr_domain_state *d_state;
281 const char * const attrs[2] = { "name", NULL};
282 struct ldb_message **msgs;
285 ZERO_STRUCTP(r->out.domain_handle);
287 DCESRV_PULL_HANDLE(h_conn, r->in.handle, SAMR_HANDLE_CONNECT);
289 c_state = h_conn->data;
291 if (r->in.sid == NULL) {
292 return NT_STATUS_INVALID_PARAMETER;
295 sidstr = dom_sid_string(mem_ctx, r->in.sid);
296 if (sidstr == NULL) {
297 return NT_STATUS_INVALID_PARAMETER;
300 ret = samdb_search(c_state->sam_ctx,
301 mem_ctx, NULL, &msgs, attrs,
302 "(&(objectSid=%s)(objectclass=domain))",
305 return NT_STATUS_NO_SUCH_DOMAIN;
308 domain_name = ldb_msg_find_string(msgs[0], "name", NULL);
309 if (domain_name == NULL) {
310 return NT_STATUS_NO_SUCH_DOMAIN;
313 d_state = talloc_p(c_state, struct samr_domain_state);
315 return NT_STATUS_NO_MEMORY;
318 d_state->connect_state = c_state;
319 d_state->sam_ctx = c_state->sam_ctx;
320 d_state->domain_sid = talloc_strdup(d_state, sidstr);
321 d_state->domain_name = talloc_strdup(d_state, domain_name);
322 d_state->domain_dn = talloc_strdup(d_state, msgs[0]->dn);
323 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
324 talloc_free(d_state);
325 return NT_STATUS_NO_MEMORY;
327 d_state->access_mask = r->in.access_mask;
329 h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN);
331 talloc_free(d_state);
332 return NT_STATUS_NO_MEMORY;
334 talloc_set_destructor(d_state, samr_Domain_destructor);
335 talloc_increase_ref_count(c_state);
337 h_domain->data = d_state;
338 h_domain->destroy = samr_handle_destroy;
339 *r->out.domain_handle = h_domain->wire_handle;
347 static NTSTATUS samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
348 struct samr_DomInfo2 *info)
350 const char * const attrs[] = { "comment", "name", NULL };
352 struct ldb_message **res;
354 ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, attrs,
355 "dn=%s", state->domain_dn);
357 return NT_STATUS_INTERNAL_DB_CORRUPTION;
360 /* where is this supposed to come from? is it settable? */
361 info->force_logoff_time = 0x8000000000000000LL;
363 info->comment.name = samdb_result_string(res[0], "comment", NULL);
364 info->domain.name = samdb_result_string(res[0], "name", NULL);
366 info->primary.name = lp_netbios_name();
367 info->sequence_num = 0;
368 info->role = ROLE_DOMAIN_PDC;
369 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, NULL, "(objectClass=user)");
370 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
371 "(&(objectClass=group)(sAMAccountType=%u))",
373 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
374 "(&(objectClass=group)(sAMAccountType=%u))",
383 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
384 struct samr_QueryDomainInfo *r)
386 struct dcesrv_handle *h;
387 struct samr_domain_state *d_state;
391 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
395 r->out.info = talloc_p(mem_ctx, union samr_DomainInfo);
397 return NT_STATUS_NO_MEMORY;
400 ZERO_STRUCTP(r->out.info);
402 switch (r->in.level) {
404 return samr_info_DomInfo2(d_state, mem_ctx, &r->out.info->info2);
407 return NT_STATUS_INVALID_INFO_CLASS;
414 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
415 struct samr_SetDomainInfo *r)
417 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
421 close an open domain context
423 static int samr_Account_destructor(void *ptr)
425 struct samr_account_state *a_state = ptr;
426 /* we need to explicitly free the domain state to lower the
428 talloc_free(a_state->domain_state);
433 samr_CreateDomainGroup
435 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
436 struct samr_CreateDomainGroup *r)
438 struct samr_domain_state *d_state;
439 struct samr_account_state *a_state;
440 struct dcesrv_handle *h;
442 struct ldb_message msg;
444 const char *groupname, *sidstr;
445 time_t now = time(NULL);
446 struct dcesrv_handle *g_handle;
450 ZERO_STRUCTP(r->out.group_handle);
453 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
457 groupname = r->in.name->name;
459 if (groupname == NULL) {
460 return NT_STATUS_INVALID_PARAMETER;
463 /* check if the group already exists */
464 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
466 "(&(sAMAccountName=%s)(objectclass=group))",
469 return NT_STATUS_GROUP_EXISTS;
474 /* pull in all the template attributes */
475 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
476 "(&(name=TemplateGroup)(objectclass=groupTemplate))");
478 DEBUG(0,("Failed to load TemplateGroup from samdb\n"));
479 return NT_STATUS_INTERNAL_DB_CORRUPTION;
483 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
484 d_state->domain_dn, "nextRid", &rid);
485 if (!NT_STATUS_IS_OK(status)) {
489 /* and the group SID */
490 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
492 return NT_STATUS_NO_MEMORY;
495 /* add core elements to the ldb_message for the user */
496 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", groupname,
499 return NT_STATUS_NO_MEMORY;
501 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
503 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
505 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
506 "sAMAccountName", groupname);
507 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
508 "objectClass", "group");
509 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
510 "objectSid", sidstr);
511 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
513 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
516 /* create the group */
517 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
519 DEBUG(0,("Failed to create group record %s\n", msg.dn));
520 return NT_STATUS_INTERNAL_DB_CORRUPTION;
523 a_state = talloc_p(d_state, struct samr_account_state);
525 return NT_STATUS_NO_MEMORY;
527 a_state->sam_ctx = d_state->sam_ctx;
528 a_state->access_mask = r->in.access_mask;
529 a_state->domain_state = d_state;
530 a_state->account_dn = talloc_steal(d_state, msg.dn);
531 a_state->account_sid = talloc_strdup(d_state, sidstr);
532 a_state->account_name = talloc_strdup(d_state, groupname);
533 if (!a_state->account_name || !a_state->account_sid) {
534 return NT_STATUS_NO_MEMORY;
537 /* create the policy handle */
538 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
540 return NT_STATUS_NO_MEMORY;
543 g_handle->data = a_state;
544 g_handle->destroy = samr_handle_destroy;
546 /* the domain state is in use one more time */
547 talloc_increase_ref_count(d_state);
548 talloc_set_destructor(a_state, samr_Account_destructor);
550 *r->out.group_handle = g_handle->wire_handle;
558 samr_EnumDomainGroups
560 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
561 struct samr_EnumDomainGroups *r)
563 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
570 TODO: This should do some form of locking, especially around the rid allocation
572 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
573 struct samr_CreateUser2 *r)
575 struct samr_domain_state *d_state;
576 struct samr_account_state *a_state;
577 struct dcesrv_handle *h;
579 struct ldb_message msg;
581 const char *account_name, *sidstr;
582 time_t now = time(NULL);
583 struct dcesrv_handle *u_handle;
586 const char *container, *additional_class=NULL;
588 ZERO_STRUCTP(r->out.acct_handle);
589 *r->out.access_granted = 0;
592 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
596 account_name = r->in.account_name->name;
598 if (account_name == NULL) {
599 return NT_STATUS_INVALID_PARAMETER;
602 /* check if the user already exists */
603 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
605 "(&(sAMAccountName=%s)(objectclass=user))", account_name);
607 return NT_STATUS_USER_EXISTS;
612 /* This must be one of these values *only* */
613 if (r->in.acct_flags == ACB_NORMAL) {
614 /* pull in all the template attributes */
615 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
616 "(&(name=TemplateUser)(objectclass=userTemplate))");
618 DEBUG(0,("Failed to load TemplateUser from samdb\n"));
619 return NT_STATUS_INTERNAL_DB_CORRUPTION;
624 } else if (r->in.acct_flags == ACB_WSTRUST) {
625 /* pull in all the template attributes */
626 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
627 "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
629 DEBUG(0,("Failed to load TemplateMemberServer from samdb\n"));
630 return NT_STATUS_INTERNAL_DB_CORRUPTION;
633 container = "Computers";
634 additional_class = "computer";
636 } else if (r->in.acct_flags == ACB_SVRTRUST) {
637 /* pull in all the template attributes */
638 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
639 "(&(name=TemplateDomainController)(objectclass=userTemplate))");
641 DEBUG(0,("Failed to load TemplateDomainController from samdb\n"));
642 return NT_STATUS_INTERNAL_DB_CORRUPTION;
645 container = "DomainControllers";
646 additional_class = "computer";
648 } else if (r->in.acct_flags == ACB_DOMTRUST) {
649 /* pull in all the template attributes */
650 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
651 "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
653 DEBUG(0,("Failed to load TemplateTrustingDomain from samdb\n"));
654 return NT_STATUS_INTERNAL_DB_CORRUPTION;
657 container = "ForeignDomains"; /* FIXME: Is this correct?*/
658 additional_class = "computer";
661 return NT_STATUS_INVALID_PARAMETER;
665 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
666 d_state->domain_dn, "nextRid", &rid);
667 if (!NT_STATUS_IS_OK(status)) {
671 /* and the users SID */
672 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
674 return NT_STATUS_NO_MEMORY;
677 /* add core elements to the ldb_message for the user */
678 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", account_name, container, d_state->domain_dn);
680 return NT_STATUS_NO_MEMORY;
682 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", account_name);
683 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", account_name);
684 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", account_name);
685 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
686 if (additional_class) {
687 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class);
689 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
690 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
691 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
693 /* create the user */
694 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
696 DEBUG(0,("Failed to create user record %s\n", msg.dn));
697 return NT_STATUS_INTERNAL_DB_CORRUPTION;
700 a_state = talloc_p(d_state, struct samr_account_state);
702 return NT_STATUS_NO_MEMORY;
704 a_state->sam_ctx = d_state->sam_ctx;
705 a_state->access_mask = r->in.access_mask;
706 a_state->domain_state = d_state;
707 a_state->account_dn = talloc_steal(d_state, msg.dn);
708 a_state->account_sid = talloc_strdup(d_state, sidstr);
709 a_state->account_name = talloc_strdup(d_state, account_name);
710 if (!a_state->account_name || !a_state->account_sid) {
711 return NT_STATUS_NO_MEMORY;
714 /* create the policy handle */
715 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
717 return NT_STATUS_NO_MEMORY;
720 u_handle->data = a_state;
721 u_handle->destroy = samr_handle_destroy;
723 /* the domain state is in use one more time */
724 talloc_increase_ref_count(d_state);
725 talloc_set_destructor(a_state, samr_Account_destructor);
727 *r->out.acct_handle = u_handle->wire_handle;
728 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
738 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
739 struct samr_CreateUser *r)
741 struct samr_CreateUser2 r2;
742 uint32_t access_granted = 0;
745 /* a simple wrapper around samr_CreateUser2 works nicely */
746 r2.in.handle = r->in.handle;
747 r2.in.account_name = r->in.account_name;
748 r2.in.acct_flags = ACB_NORMAL;
749 r2.in.access_mask = r->in.access_mask;
750 r2.out.acct_handle = r->out.acct_handle;
751 r2.out.access_granted = &access_granted;
752 r2.out.rid = r->out.rid;
754 return samr_CreateUser2(dce_call, mem_ctx, &r2);
758 comparison function for sorting SamEntry array
760 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
762 return e1->idx - e2->idx;
768 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
769 struct samr_EnumDomainUsers *r)
771 struct dcesrv_handle *h;
772 struct samr_domain_state *d_state;
773 struct ldb_message **res;
775 struct samr_SamEntry *entries;
776 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
778 *r->out.resume_handle = 0;
780 r->out.num_entries = 0;
782 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
786 /* search for all users in this domain. This could possibly be cached and
787 resumed based on resume_key */
788 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
791 return NT_STATUS_INTERNAL_DB_CORRUPTION;
793 if (count == 0 || r->in.max_size == 0) {
797 /* convert to SamEntry format */
798 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
800 return NT_STATUS_NO_MEMORY;
802 for (i=0;i<count;i++) {
803 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
804 entries[i].name.name = samdb_result_string(res[i], "sAMAccountName", "");
807 /* sort the results by rid */
808 qsort(entries, count, sizeof(struct samr_SamEntry),
809 (comparison_fn_t)compare_SamEntry);
811 /* find the first entry to return */
813 first<count && entries[first].idx <= *r->in.resume_handle;
816 if (first == count) {
820 /* return the rest, limit by max_size. Note that we
821 use the w2k3 element size value of 54 */
822 r->out.num_entries = count - first;
823 r->out.num_entries = MIN(r->out.num_entries,
824 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
826 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
828 return NT_STATUS_NO_MEMORY;
831 r->out.sam->entries = entries+first;
832 r->out.sam->count = r->out.num_entries;
834 if (r->out.num_entries < count - first) {
835 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
836 return STATUS_MORE_ENTRIES;
846 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
847 struct samr_CreateDomAlias *r)
849 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
854 samr_EnumDomainAliases
856 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
857 struct samr_EnumDomainAliases *r)
859 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
864 samr_GetAliasMembership
866 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
867 struct samr_GetAliasMembership *r)
869 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
876 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
877 struct samr_LookupNames *r)
879 struct dcesrv_handle *h;
880 struct samr_domain_state *d_state;
882 NTSTATUS status = NT_STATUS_OK;
883 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
886 ZERO_STRUCT(r->out.rids);
887 ZERO_STRUCT(r->out.types);
889 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
893 if (r->in.num_names == 0) {
897 r->out.rids.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
898 r->out.types.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
899 if (!r->out.rids.ids || !r->out.types.ids) {
900 return NT_STATUS_NO_MEMORY;
902 r->out.rids.count = r->in.num_names;
903 r->out.types.count = r->in.num_names;
905 for (i=0;i<r->in.num_names;i++) {
906 struct ldb_message **res;
907 struct dom_sid2 *sid;
909 uint32_t atype, rtype;
911 r->out.rids.ids[i] = 0;
912 r->out.types.ids[i] = SID_NAME_UNKNOWN;
914 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
915 "sAMAccountName=%s", r->in.names[i].name);
917 status = STATUS_SOME_UNMAPPED;
921 sidstr = samdb_result_string(res[0], "objectSid", NULL);
922 if (sidstr == NULL) {
923 status = STATUS_SOME_UNMAPPED;
927 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
929 status = STATUS_SOME_UNMAPPED;
933 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
935 status = STATUS_SOME_UNMAPPED;
939 rtype = samdb_atype_map(atype);
941 if (rtype == SID_NAME_UNKNOWN) {
942 status = STATUS_SOME_UNMAPPED;
946 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
947 r->out.types.ids[i] = rtype;
958 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
959 struct samr_LookupRids *r)
961 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
968 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
969 struct samr_OpenGroup *r)
971 struct samr_domain_state *d_state;
972 struct samr_account_state *a_state;
973 struct dcesrv_handle *h;
974 const char *groupname, *sidstr;
975 struct ldb_message **msgs;
976 struct dcesrv_handle *g_handle;
977 const char * const attrs[2] = { "sAMAccountName", NULL };
980 ZERO_STRUCTP(r->out.acct_handle);
982 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
986 /* form the group SID */
987 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
989 return NT_STATUS_NO_MEMORY;
992 /* search for the group record */
993 ret = samdb_search(d_state->sam_ctx,
994 mem_ctx, d_state->domain_dn, &msgs, attrs,
995 "(&(objectSid=%s)(objectclass=group))",
998 return NT_STATUS_NO_SUCH_GROUP;
1001 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1002 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1005 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1006 if (groupname == NULL) {
1007 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1008 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1011 a_state = talloc_p(d_state, struct samr_account_state);
1013 return NT_STATUS_NO_MEMORY;
1015 a_state->sam_ctx = d_state->sam_ctx;
1016 a_state->access_mask = r->in.access_mask;
1017 a_state->domain_state = d_state;
1018 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1019 a_state->account_sid = talloc_strdup(a_state, sidstr);
1020 a_state->account_name = talloc_strdup(a_state, groupname);
1021 if (!a_state->account_name || !a_state->account_sid) {
1022 return NT_STATUS_NO_MEMORY;
1025 /* create the policy handle */
1026 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1028 return NT_STATUS_NO_MEMORY;
1031 g_handle->data = a_state;
1032 g_handle->destroy = samr_handle_destroy;
1034 /* the domain state is in use one more time */
1035 talloc_increase_ref_count(d_state);
1036 talloc_set_destructor(a_state, samr_Account_destructor);
1038 *r->out.acct_handle = g_handle->wire_handle;
1040 return NT_STATUS_OK;
1043 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1045 #define QUERY_STRING(msg, field, attr) \
1046 r->out.info->field = samdb_result_string(msg, attr, "");
1047 #define QUERY_UINT(msg, field, attr) \
1048 r->out.info->field = samdb_result_uint(msg, attr, 0);
1049 #define QUERY_RID(msg, field, attr) \
1050 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1051 #define QUERY_NTTIME(msg, field, attr) \
1052 r->out.info->field = samdb_result_nttime(msg, attr, 0);
1053 #define QUERY_APASSC(msg, field, attr) \
1054 r->out.info->field = samdb_result_allow_password_change(a_state->sam_ctx, mem_ctx, \
1055 a_state->domain_state->domain_dn, msg, attr);
1056 #define QUERY_FPASSC(msg, field, attr) \
1057 r->out.info->field = samdb_result_force_password_change(a_state->sam_ctx, mem_ctx, \
1058 a_state->domain_state->domain_dn, msg, attr);
1059 #define QUERY_LHOURS(msg, field, attr) \
1060 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1061 #define QUERY_AFLAGS(msg, field, attr) \
1062 r->out.info->field = samdb_result_acct_flags(msg, attr);
1065 /* these are used to make the Set[User|Group]Info code easier to follow */
1067 #define SET_STRING(mod, field, attr) do { \
1068 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1069 if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1070 return NT_STATUS_NO_MEMORY; \
1074 #define SET_UINT(mod, field, attr) do { \
1075 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1076 return NT_STATUS_NO_MEMORY; \
1080 #define SET_AFLAGS(msg, field, attr) do { \
1081 if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1082 return NT_STATUS_NO_MEMORY; \
1086 #define SET_LHOURS(msg, field, attr) do { \
1087 if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1088 return NT_STATUS_NO_MEMORY; \
1095 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1096 struct samr_QueryGroupInfo *r)
1098 struct dcesrv_handle *h;
1099 struct samr_account_state *a_state;
1100 struct ldb_message *msg, **res;
1101 const char * const attrs[4] = { "sAMAccountName", "description",
1102 "numMembers", NULL };
1107 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1111 /* pull all the group attributes */
1112 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1113 "dn=%s", a_state->account_dn);
1115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1119 /* allocate the info structure */
1120 r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1121 if (r->out.info == NULL) {
1122 return NT_STATUS_NO_MEMORY;
1124 ZERO_STRUCTP(r->out.info);
1126 /* Fill in the level */
1127 switch (r->in.level) {
1129 QUERY_STRING(msg, all.name.name, "sAMAccountName");
1130 r->out.info->all.unknown = 7; /* Do like w2k3 */
1131 QUERY_UINT (msg, all.num_members, "numMembers")
1132 QUERY_STRING(msg, all.description.name, "description");
1135 QUERY_STRING(msg, name.name, "sAMAccountName");
1138 r->out.info->unknown.unknown = 7;
1140 case GroupInfoDescription:
1141 QUERY_STRING(msg, description.name, "description");
1145 return NT_STATUS_INVALID_INFO_CLASS;
1148 return NT_STATUS_OK;
1155 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1156 struct samr_SetGroupInfo *r)
1158 struct dcesrv_handle *h;
1159 struct samr_account_state *a_state;
1160 struct ldb_message mod, *msg = &mod;
1163 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1168 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1170 return NT_STATUS_NO_MEMORY;
1173 switch (r->in.level) {
1174 case GroupInfoDescription:
1175 SET_STRING(msg, description.name, "description");
1178 /* On W2k3 this does not change the name, it changes the
1179 * sAMAccountName attribute */
1180 SET_STRING(msg, name.name, "sAMAccountName");
1183 /* This does not do anything obviously visible in W2k3 LDAP */
1186 return NT_STATUS_INVALID_INFO_CLASS;
1189 /* modify the samdb record */
1190 ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
1192 /* we really need samdb.c to return NTSTATUS */
1193 return NT_STATUS_UNSUCCESSFUL;
1196 return NT_STATUS_OK;
1203 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1204 struct samr_AddGroupMember *r)
1206 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1211 samr_DeleteDomainGroup
1213 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1214 struct samr_DeleteDomainGroup *r)
1216 struct dcesrv_handle *h;
1217 struct samr_account_state *a_state;
1220 *r->out.handle = *r->in.handle;
1222 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1226 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1228 return NT_STATUS_UNSUCCESSFUL;
1231 ZERO_STRUCTP(r->out.handle);
1233 return NT_STATUS_OK;
1238 samr_DeleteGroupMember
1240 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1241 struct samr_DeleteGroupMember *r)
1243 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1248 samr_QueryGroupMember
1250 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1251 struct samr_QueryGroupMember *r)
1253 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1258 samr_SetMemberAttributesOfGroup
1260 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1261 struct samr_SetMemberAttributesOfGroup *r)
1263 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1270 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1271 struct samr_OpenAlias *r)
1273 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1280 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1281 struct samr_QueryAliasInfo *r)
1283 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1290 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1291 struct samr_SetAliasInfo *r)
1293 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1300 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1301 struct samr_DeleteDomAlias *r)
1303 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1310 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1311 struct samr_AddAliasMember *r)
1313 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1318 samr_DeleteAliasMember
1320 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1321 struct samr_DeleteAliasMember *r)
1323 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1328 samr_GetMembersInAlias
1330 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1331 struct samr_GetMembersInAlias *r)
1333 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1340 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1341 struct samr_OpenUser *r)
1343 struct samr_domain_state *d_state;
1344 struct samr_account_state *a_state;
1345 struct dcesrv_handle *h;
1346 const char *account_name, *sidstr;
1347 struct ldb_message **msgs;
1348 struct dcesrv_handle *u_handle;
1349 const char * const attrs[2] = { "sAMAccountName", NULL };
1352 ZERO_STRUCTP(r->out.acct_handle);
1354 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1358 /* form the users SID */
1359 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1361 return NT_STATUS_NO_MEMORY;
1364 /* search for the user record */
1365 ret = samdb_search(d_state->sam_ctx,
1366 mem_ctx, d_state->domain_dn, &msgs, attrs,
1367 "(&(objectSid=%s)(objectclass=user))",
1370 return NT_STATUS_NO_SUCH_USER;
1373 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1374 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1377 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1378 if (account_name == NULL) {
1379 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1380 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1383 a_state = talloc_p(d_state, struct samr_account_state);
1385 return NT_STATUS_NO_MEMORY;
1387 a_state->sam_ctx = d_state->sam_ctx;
1388 a_state->access_mask = r->in.access_mask;
1389 a_state->domain_state = d_state;
1390 a_state->account_dn = talloc_steal(d_state, msgs[0]->dn);
1391 a_state->account_sid = talloc_strdup(d_state, sidstr);
1392 a_state->account_name = talloc_strdup(d_state, account_name);
1393 if (!a_state->account_name || !a_state->account_sid) {
1394 return NT_STATUS_NO_MEMORY;
1397 /* create the policy handle */
1398 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1400 return NT_STATUS_NO_MEMORY;
1403 u_handle->data = a_state;
1404 u_handle->destroy = samr_handle_destroy;
1406 /* the domain state is in use one more time */
1407 talloc_increase_ref_count(d_state);
1408 talloc_set_destructor(a_state, samr_Account_destructor);
1410 *r->out.acct_handle = u_handle->wire_handle;
1412 return NT_STATUS_OK;
1420 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1421 struct samr_DeleteUser *r)
1423 struct dcesrv_handle *h;
1424 struct samr_account_state *a_state;
1427 *r->out.handle = *r->in.handle;
1429 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1433 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1435 return NT_STATUS_UNSUCCESSFUL;
1438 ZERO_STRUCTP(r->out.handle);
1440 return NT_STATUS_OK;
1447 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1448 struct samr_QueryUserInfo *r)
1450 struct dcesrv_handle *h;
1451 struct samr_account_state *a_state;
1452 struct ldb_message *msg, **res;
1457 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1461 /* pull all the user attributes */
1462 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
1463 "dn=%s", a_state->account_dn);
1465 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1469 /* allocate the info structure */
1470 r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1471 if (r->out.info == NULL) {
1472 return NT_STATUS_NO_MEMORY;
1474 ZERO_STRUCTP(r->out.info);
1476 /* fill in the reply */
1477 switch (r->in.level) {
1479 QUERY_STRING(msg, info1.account_name.name,"sAMAccountName");
1480 QUERY_STRING(msg, info1.full_name.name, "displayName");
1481 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
1482 QUERY_STRING(msg, info1.description.name, "description");
1483 QUERY_STRING(msg, info1.comment.name, "comment");
1487 QUERY_STRING(msg, info2.comment.name, "comment");
1488 QUERY_UINT (msg, info2.country_code, "countryCode");
1489 QUERY_UINT (msg, info2.code_page, "codePage");
1493 QUERY_STRING(msg, info3.account_name.name, "sAMAccountName");
1494 QUERY_STRING(msg, info3.full_name.name, "displayName");
1495 QUERY_RID (msg, info3.rid, "objectSid");
1496 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
1497 QUERY_STRING(msg, info3.home_directory.name, "homeDirectory");
1498 QUERY_STRING(msg, info3.home_drive.name, "homeDrive");
1499 QUERY_STRING(msg, info3.logon_script.name, "scriptPath");
1500 QUERY_STRING(msg, info3.profile_path.name, "profilePath");
1501 QUERY_STRING(msg, info3.workstations.name, "userWorkstations");
1502 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
1503 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
1504 QUERY_NTTIME(msg, info3.last_password_change,"pwdLastSet");
1505 QUERY_APASSC(msg, info3.allow_password_change,"pwdLastSet");
1506 QUERY_FPASSC(msg, info3.force_password_change,"pwdLastSet");
1507 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
1508 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
1509 QUERY_UINT (msg, info3.num_logons, "logonCount");
1510 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
1514 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
1518 QUERY_STRING(msg, info5.account_name.name, "sAMAccountName");
1519 QUERY_STRING(msg, info5.full_name.name, "displayName");
1520 QUERY_RID (msg, info5.rid, "objectSid");
1521 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
1522 QUERY_STRING(msg, info5.home_directory.name, "homeDirectory");
1523 QUERY_STRING(msg, info5.home_drive.name, "homeDrive");
1524 QUERY_STRING(msg, info5.logon_script.name, "scriptPath");
1525 QUERY_STRING(msg, info5.profile_path.name, "profilePath");
1526 QUERY_STRING(msg, info5.description.name, "description");
1527 QUERY_STRING(msg, info5.workstations.name, "userWorkstations");
1528 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
1529 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
1530 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
1531 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
1532 QUERY_UINT (msg, info5.num_logons, "logonCount");
1533 QUERY_NTTIME(msg, info5.last_password_change,"pwdLastSet");
1534 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
1535 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
1539 QUERY_STRING(msg, info6.account_name.name, "sAMAccountName");
1540 QUERY_STRING(msg, info6.full_name.name, "displayName");
1544 QUERY_STRING(msg, info7.account_name.name, "sAMAccountName");
1548 QUERY_STRING(msg, info8.full_name.name, "displayName");
1552 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
1556 QUERY_STRING(msg, info10.home_directory.name, "homeDirectory");
1557 QUERY_STRING(msg, info10.home_drive.name, "homeDrive");
1561 QUERY_STRING(msg, info11.logon_script.name, "scriptPath");
1565 QUERY_STRING(msg, info12.profile_path.name, "profilePath");
1569 QUERY_STRING(msg, info13.description.name, "description");
1573 QUERY_STRING(msg, info14.workstations.name, "userWorkstations");
1577 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1581 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
1584 QUERY_STRING(msg, info20.callback.name, "userParameters");
1588 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
1589 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
1590 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
1591 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
1592 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
1593 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
1594 QUERY_STRING(msg, info21.account_name.name, "sAMAccountName");
1595 QUERY_STRING(msg, info21.full_name.name, "displayName");
1596 QUERY_STRING(msg, info21.home_directory.name, "homeDirectory");
1597 QUERY_STRING(msg, info21.home_drive.name, "homeDrive");
1598 QUERY_STRING(msg, info21.logon_script.name, "scriptPath");
1599 QUERY_STRING(msg, info21.profile_path.name, "profilePath");
1600 QUERY_STRING(msg, info21.description.name, "description");
1601 QUERY_STRING(msg, info21.workstations.name, "userWorkstations");
1602 QUERY_STRING(msg, info21.comment.name, "comment");
1603 QUERY_STRING(msg, info21.callback.name, "userParameters");
1604 QUERY_RID (msg, info21.rid, "objectSid");
1605 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
1606 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
1607 r->out.info->info21.fields_present = 0x00FFFFFF;
1608 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
1609 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
1610 QUERY_UINT (msg, info21.num_logons, "logonCount");
1611 QUERY_UINT (msg, info21.country_code, "countryCode");
1612 QUERY_UINT (msg, info21.code_page, "codePage");
1618 return NT_STATUS_INVALID_INFO_CLASS;
1621 return NT_STATUS_OK;
1628 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1629 struct samr_SetUserInfo *r)
1631 struct dcesrv_handle *h;
1632 struct samr_account_state *a_state;
1633 struct ldb_message mod, *msg = &mod;
1635 NTSTATUS status = NT_STATUS_OK;
1637 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1642 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1644 return NT_STATUS_NO_MEMORY;
1647 switch (r->in.level) {
1649 SET_STRING(msg, info2.comment.name, "comment");
1650 SET_UINT (msg, info2.country_code, "countryCode");
1651 SET_UINT (msg, info2.code_page, "codePage");
1655 SET_LHOURS(msg, info4.logon_hours, "logonHours");
1659 SET_STRING(msg, info6.full_name.name, "displayName");
1663 SET_STRING(msg, info8.full_name.name, "displayName");
1667 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
1671 SET_STRING(msg, info10.home_directory.name, "homeDirectory");
1672 SET_STRING(msg, info10.home_drive.name, "homeDrive");
1676 SET_STRING(msg, info11.logon_script.name, "scriptPath");
1680 SET_STRING(msg, info12.profile_path.name, "profilePath");
1684 SET_STRING(msg, info13.description.name, "description");
1688 SET_STRING(msg, info14.workstations.name, "userWorkstations");
1692 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1696 SET_STRING(msg, info20.callback.name, "userParameters");
1700 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1701 IFSET(SAMR_FIELD_NAME)
1702 SET_STRING(msg, info21.full_name.name, "displayName");
1703 IFSET(SAMR_FIELD_DESCRIPTION)
1704 SET_STRING(msg, info21.description.name, "description");
1705 IFSET(SAMR_FIELD_COMMENT)
1706 SET_STRING(msg, info21.comment.name, "comment");
1707 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1708 SET_STRING(msg, info21.logon_script.name, "scriptPath");
1709 IFSET(SAMR_FIELD_PROFILE_PATH)
1710 SET_STRING(msg, info21.profile_path.name, "profilePath");
1711 IFSET(SAMR_FIELD_WORKSTATION)
1712 SET_STRING(msg, info21.workstations.name, "userWorkstations");
1713 IFSET(SAMR_FIELD_LOGON_HOURS)
1714 SET_LHOURS(msg, info21.logon_hours, "logonHours");
1715 IFSET(SAMR_FIELD_CALLBACK)
1716 SET_STRING(msg, info21.callback.name, "userParameters");
1717 IFSET(SAMR_FIELD_COUNTRY_CODE)
1718 SET_UINT (msg, info21.country_code, "countryCode");
1719 IFSET(SAMR_FIELD_CODE_PAGE)
1720 SET_UINT (msg, info21.code_page, "codePage");
1725 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
1726 IFSET(SAMR_FIELD_NAME)
1727 SET_STRING(msg, info23.info.full_name.name, "displayName");
1728 IFSET(SAMR_FIELD_DESCRIPTION)
1729 SET_STRING(msg, info23.info.description.name, "description");
1730 IFSET(SAMR_FIELD_COMMENT)
1731 SET_STRING(msg, info23.info.comment.name, "comment");
1732 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1733 SET_STRING(msg, info23.info.logon_script.name, "scriptPath");
1734 IFSET(SAMR_FIELD_PROFILE_PATH)
1735 SET_STRING(msg, info23.info.profile_path.name, "profilePath");
1736 IFSET(SAMR_FIELD_WORKSTATION)
1737 SET_STRING(msg, info23.info.workstations.name, "userWorkstations");
1738 IFSET(SAMR_FIELD_LOGON_HOURS)
1739 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
1740 IFSET(SAMR_FIELD_CALLBACK)
1741 SET_STRING(msg, info23.info.callback.name, "userParameters");
1742 IFSET(SAMR_FIELD_COUNTRY_CODE)
1743 SET_UINT (msg, info23.info.country_code, "countryCode");
1744 IFSET(SAMR_FIELD_CODE_PAGE)
1745 SET_UINT (msg, info23.info.code_page, "codePage");
1746 IFSET(SAMR_FIELD_PASSWORD) {
1747 status = samr_set_password(dce_call,
1749 a_state->account_dn,
1750 a_state->domain_state->domain_dn,
1752 &r->in.info->info23.password);
1757 /* the set password levels are handled separately */
1759 status = samr_set_password(dce_call,
1761 a_state->account_dn,
1762 a_state->domain_state->domain_dn,
1764 &r->in.info->info24.password);
1768 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
1769 IFSET(SAMR_FIELD_NAME)
1770 SET_STRING(msg, info25.info.full_name.name, "displayName");
1771 IFSET(SAMR_FIELD_DESCRIPTION)
1772 SET_STRING(msg, info25.info.description.name, "description");
1773 IFSET(SAMR_FIELD_COMMENT)
1774 SET_STRING(msg, info25.info.comment.name, "comment");
1775 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1776 SET_STRING(msg, info25.info.logon_script.name, "scriptPath");
1777 IFSET(SAMR_FIELD_PROFILE_PATH)
1778 SET_STRING(msg, info25.info.profile_path.name, "profilePath");
1779 IFSET(SAMR_FIELD_WORKSTATION)
1780 SET_STRING(msg, info25.info.workstations.name, "userWorkstations");
1781 IFSET(SAMR_FIELD_LOGON_HOURS)
1782 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
1783 IFSET(SAMR_FIELD_CALLBACK)
1784 SET_STRING(msg, info25.info.callback.name, "userParameters");
1785 IFSET(SAMR_FIELD_COUNTRY_CODE)
1786 SET_UINT (msg, info25.info.country_code, "countryCode");
1787 IFSET(SAMR_FIELD_CODE_PAGE)
1788 SET_UINT (msg, info25.info.code_page, "codePage");
1789 IFSET(SAMR_FIELD_PASSWORD) {
1790 status = samr_set_password_ex(dce_call,
1792 a_state->account_dn,
1793 a_state->domain_state->domain_dn,
1795 &r->in.info->info25.password);
1800 /* the set password levels are handled separately */
1802 status = samr_set_password_ex(dce_call,
1804 a_state->account_dn,
1805 a_state->domain_state->domain_dn,
1807 &r->in.info->info26.password);
1812 /* many info classes are not valid for SetUserInfo */
1813 return NT_STATUS_INVALID_INFO_CLASS;
1816 if (!NT_STATUS_IS_OK(status)) {
1820 /* modify the samdb record */
1821 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1823 /* we really need samdb.c to return NTSTATUS */
1824 return NT_STATUS_UNSUCCESSFUL;
1827 return NT_STATUS_OK;
1832 samr_GetGroupsForUser
1834 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1835 struct samr_GetGroupsForUser *r)
1837 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1842 samr_QueryDisplayInfo
1844 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1845 struct samr_QueryDisplayInfo *r)
1847 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1852 samr_GetDisplayEnumerationIndex
1854 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1855 struct samr_GetDisplayEnumerationIndex *r)
1857 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1862 samr_TestPrivateFunctionsDomain
1864 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1865 struct samr_TestPrivateFunctionsDomain *r)
1867 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1872 samr_TestPrivateFunctionsUser
1874 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1875 struct samr_TestPrivateFunctionsUser *r)
1877 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1884 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1885 struct samr_GetUserPwInfo *r)
1887 struct dcesrv_handle *h;
1888 struct samr_account_state *a_state;
1890 ZERO_STRUCT(r->out.info);
1892 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1896 r->out.info.min_password_len = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength",
1897 "dn=%s", a_state->domain_state->domain_dn);
1898 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties",
1899 "dn=%s", a_state->account_dn);
1900 return NT_STATUS_OK;
1905 samr_RemoveMemberFromForeignDomain
1907 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1908 struct samr_RemoveMemberFromForeignDomain *r)
1910 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1915 samr_QueryDomainInfo2
1917 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1918 struct samr_QueryDomainInfo2 *r)
1920 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1927 just an alias for samr_QueryUserInfo
1929 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1930 struct samr_QueryUserInfo2 *r)
1932 struct samr_QueryUserInfo r1;
1935 r1.in.handle = r->in.handle;
1936 r1.in.level = r->in.level;
1938 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
1940 r->out.info = r1.out.info;
1947 samr_QueryDisplayInfo2
1949 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1950 struct samr_QueryDisplayInfo2 *r)
1952 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1957 samr_GetDisplayEnumerationIndex2
1959 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1960 struct samr_GetDisplayEnumerationIndex2 *r)
1962 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1967 samr_QueryDisplayInfo3
1969 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1970 struct samr_QueryDisplayInfo3 *r)
1972 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1977 samr_AddMultipleMembersToAlias
1979 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1980 struct samr_AddMultipleMembersToAlias *r)
1982 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1987 samr_RemoveMultipleMembersFromAlias
1989 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1990 struct samr_RemoveMultipleMembersFromAlias *r)
1992 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1999 this fetches the default password properties for a domain
2001 note that w2k3 completely ignores the domain name in this call, and
2002 always returns the information for the servers primary domain
2004 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2005 struct samr_GetDomPwInfo *r)
2007 struct ldb_message **msgs;
2009 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2012 ZERO_STRUCT(r->out.info);
2014 sam_ctx = samdb_connect(mem_ctx);
2015 if (sam_ctx == NULL) {
2016 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2019 ret = samdb_search(sam_ctx,
2020 mem_ctx, NULL, &msgs, attrs,
2021 "(&(name=%s)(objectclass=domain))",
2024 return NT_STATUS_NO_SUCH_DOMAIN;
2027 samdb_search_free(sam_ctx, mem_ctx, msgs);
2028 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2031 r->out.info.min_password_len = samdb_result_uint(msgs[0], "minPwdLength", 0);
2032 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2034 samdb_search_free(sam_ctx, mem_ctx, msgs);
2036 talloc_free(sam_ctx);
2037 return NT_STATUS_OK;
2044 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2045 struct samr_Connect2 *r)
2047 struct samr_Connect c;
2049 c.in.system_name = NULL;
2050 c.in.access_mask = r->in.access_mask;
2051 c.out.handle = r->out.handle;
2053 return samr_Connect(dce_call, mem_ctx, &c);
2060 just an alias for samr_SetUserInfo
2062 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2063 struct samr_SetUserInfo2 *r)
2065 struct samr_SetUserInfo r2;
2067 r2.in.handle = r->in.handle;
2068 r2.in.level = r->in.level;
2069 r2.in.info = r->in.info;
2071 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2076 samr_SetBootKeyInformation
2078 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2079 struct samr_SetBootKeyInformation *r)
2081 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2086 samr_GetBootKeyInformation
2088 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2089 struct samr_GetBootKeyInformation *r)
2091 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2098 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2099 struct samr_Connect3 *r)
2101 struct samr_Connect c;
2103 c.in.system_name = NULL;
2104 c.in.access_mask = r->in.access_mask;
2105 c.out.handle = r->out.handle;
2107 return samr_Connect(dce_call, mem_ctx, &c);
2114 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2115 struct samr_Connect4 *r)
2117 struct samr_Connect c;
2119 c.in.system_name = NULL;
2120 c.in.access_mask = r->in.access_mask;
2121 c.out.handle = r->out.handle;
2123 return samr_Connect(dce_call, mem_ctx, &c);
2130 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2131 struct samr_Connect5 *r)
2133 struct samr_Connect c;
2136 c.in.system_name = NULL;
2137 c.in.access_mask = r->in.access_mask;
2138 c.out.handle = r->out.handle;
2140 status = samr_Connect(dce_call, mem_ctx, &c);
2142 r->out.info->info1.unknown1 = 3;
2143 r->out.info->info1.unknown2 = 0;
2144 r->out.level = r->in.level;
2153 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2154 struct samr_RidToSid *r)
2156 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2161 samr_SetDsrmPassword
2163 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2164 struct samr_SetDsrmPassword *r)
2166 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2171 samr_ValidatePassword
2173 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2174 struct samr_ValidatePassword *r)
2176 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2180 /* include the generated boilerplate */
2181 #include "librpc/gen_ndr/ndr_samr_s.c"