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"
27 this type allows us to distinguish handle types
39 state asscoiated with a samr_Connect*() operation
41 struct samr_connect_state {
49 state associated with a samr_OpenDomain() operation
51 struct samr_domain_state {
52 struct samr_connect_state *connect_state;
57 const char *domain_sid;
58 const char *domain_name;
59 const char *domain_dn;
63 state associated with a open account handle
65 struct samr_account_state {
66 struct samr_domain_state *domain_state;
70 const char *account_sid;
71 const char *account_name;
72 const char *account_dn;
77 destroy connection state
79 static void samr_Connect_close(struct samr_connect_state *c_state)
81 c_state->reference_count--;
82 if (c_state->reference_count == 0) {
83 samdb_close(c_state->sam_ctx);
84 talloc_destroy(c_state->mem_ctx);
89 destroy an open connection. This closes the database connection
91 static void samr_Connect_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
93 struct samr_connect_state *c_state = h->data;
94 samr_Connect_close(c_state);
100 create a connection to the SAM database
102 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
103 struct samr_Connect *r)
105 struct samr_connect_state *c_state;
106 struct dcesrv_handle *handle;
107 TALLOC_CTX *connect_mem_ctx;
109 ZERO_STRUCTP(r->out.handle);
111 connect_mem_ctx = talloc_init("samr_Connect");
112 if (!connect_mem_ctx) {
113 return NT_STATUS_NO_MEMORY;
116 c_state = talloc_p(connect_mem_ctx, struct samr_connect_state);
118 return NT_STATUS_NO_MEMORY;
120 c_state->mem_ctx = connect_mem_ctx;
122 /* make sure the sam database is accessible */
123 c_state->sam_ctx = samdb_connect();
124 if (c_state->sam_ctx == NULL) {
125 talloc_destroy(c_state->mem_ctx);
126 return NT_STATUS_INVALID_SYSTEM_SERVICE;
129 handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_CONNECT);
131 talloc_destroy(c_state->mem_ctx);
132 return NT_STATUS_NO_MEMORY;
135 handle->data = c_state;
136 handle->destroy = samr_Connect_destroy;
138 c_state->reference_count = 1;
139 c_state->access_mask = r->in.access_mask;
140 *r->out.handle = handle->wire_handle;
149 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
150 struct samr_Close *r)
152 struct dcesrv_handle *h;
154 *r->out.handle = *r->in.handle;
156 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
158 /* this causes the callback samr_XXX_destroy() to be called by
159 the handle destroy code which destroys the state associated
161 dcesrv_handle_destroy(dce_call->conn, h);
163 ZERO_STRUCTP(r->out.handle);
172 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
173 struct samr_SetSecurity *r)
175 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
182 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
183 struct samr_QuerySecurity *r)
185 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
192 we refuse this operation completely. If a admin wants to shutdown samr
193 in Samba then they should use the samba admin tools to disable the samr pipe
195 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
196 struct samr_Shutdown *r)
198 return NT_STATUS_ACCESS_DENIED;
205 this maps from a domain name to a SID
207 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
208 struct samr_LookupDomain *r)
210 struct samr_connect_state *c_state;
211 struct dcesrv_handle *h;
212 struct dom_sid2 *sid;
217 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
221 if (r->in.domain->name == NULL) {
222 return NT_STATUS_INVALID_PARAMETER;
225 sidstr = samdb_search_string(c_state->sam_ctx,
226 mem_ctx, NULL, "objectSid",
227 "(&(name=%s)(objectclass=domain))",
229 if (sidstr == NULL) {
230 return NT_STATUS_NO_SUCH_DOMAIN;
233 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
235 DEBUG(1,("samdb: Invalid sid '%s' for domain %s\n",
236 sidstr, r->in.domain->name));
237 return NT_STATUS_INTERNAL_DB_CORRUPTION;
249 list the domains in the SAM
251 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
252 struct samr_EnumDomains *r)
254 struct samr_connect_state *c_state;
255 struct dcesrv_handle *h;
256 struct samr_SamArray *array;
257 const char **domains;
258 int count, i, start_i;
260 *r->out.resume_handle = 0;
262 r->out.num_entries = 0;
264 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
268 count = samdb_search_string_multiple(c_state->sam_ctx,
269 mem_ctx, NULL, &domains,
270 "name", "(objectclass=domain)");
272 DEBUG(1,("samdb: no domains found in EnumDomains\n"));
273 return NT_STATUS_INTERNAL_DB_CORRUPTION;
276 *r->out.resume_handle = count;
278 start_i = *r->in.resume_handle;
280 if (start_i >= count) {
281 /* search past end of list is not an error for this call */
285 array = talloc_p(mem_ctx, struct samr_SamArray);
287 return NT_STATUS_NO_MEMORY;
291 array->entries = NULL;
293 array->entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count - start_i);
294 if (array->entries == NULL) {
295 return NT_STATUS_NO_MEMORY;
298 for (i=0;i<count-start_i;i++) {
299 array->entries[i].idx = start_i + i;
300 array->entries[i].name.name = domains[start_i+i];
304 r->out.num_entries = i - start_i;
305 array->count = r->out.num_entries;
312 close an open domain context
314 static void samr_Domain_close(struct dcesrv_connection *conn,
315 struct samr_domain_state *d_state)
317 d_state->reference_count--;
318 if (d_state->reference_count == 0) {
319 samr_Connect_close(d_state->connect_state);
320 talloc_destroy(d_state->mem_ctx);
325 destroy an open domain context
327 static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
329 struct samr_domain_state *d_state = h->data;
330 samr_Domain_close(conn, d_state);
336 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
337 struct samr_OpenDomain *r)
339 struct dcesrv_handle *h_conn, *h_domain;
340 const char *sidstr, *domain_name;
341 struct samr_connect_state *c_state;
342 struct samr_domain_state *d_state;
343 TALLOC_CTX *mem_ctx2;
344 const char * const attrs[2] = { "name", NULL};
345 struct ldb_message **msgs;
348 ZERO_STRUCTP(r->out.domain_handle);
350 DCESRV_PULL_HANDLE(h_conn, r->in.handle, SAMR_HANDLE_CONNECT);
352 c_state = h_conn->data;
354 if (r->in.sid == NULL) {
355 return NT_STATUS_INVALID_PARAMETER;
358 sidstr = dom_sid_string(mem_ctx, r->in.sid);
359 if (sidstr == NULL) {
360 return NT_STATUS_INVALID_PARAMETER;
363 ret = samdb_search(c_state->sam_ctx,
364 mem_ctx, NULL, &msgs, attrs,
365 "(&(objectSid=%s)(objectclass=domain))",
368 return NT_STATUS_NO_SUCH_DOMAIN;
371 domain_name = ldb_msg_find_string(msgs[0], "name", NULL);
372 if (domain_name == NULL) {
373 return NT_STATUS_NO_SUCH_DOMAIN;
376 mem_ctx2 = talloc_init("OpenDomain(%s)\n", domain_name);
378 return NT_STATUS_NO_MEMORY;
381 d_state = talloc_p(mem_ctx2, struct samr_domain_state);
383 talloc_destroy(mem_ctx2);
384 return NT_STATUS_NO_MEMORY;
387 d_state->reference_count = 1;
388 d_state->connect_state = c_state;
389 d_state->sam_ctx = c_state->sam_ctx;
390 d_state->mem_ctx = mem_ctx2;
391 d_state->domain_sid = talloc_strdup(mem_ctx2, sidstr);
392 d_state->domain_name = talloc_strdup(mem_ctx2, domain_name);
393 d_state->domain_dn = talloc_strdup(mem_ctx2, msgs[0]->dn);
394 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
395 talloc_destroy(mem_ctx2);
396 return NT_STATUS_NO_MEMORY;
398 d_state->access_mask = r->in.access_mask;
400 h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN);
402 talloc_destroy(mem_ctx2);
403 return NT_STATUS_NO_MEMORY;
406 c_state->reference_count++;
407 h_domain->data = d_state;
408 h_domain->destroy = samr_Domain_destroy;
409 *r->out.domain_handle = h_domain->wire_handle;
418 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
419 struct samr_QueryDomainInfo *r)
421 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
428 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
429 struct samr_SetDomainInfo *r)
431 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
435 destroy an open account context
437 static void samr_Account_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
439 struct samr_account_state *a_state = h->data;
440 samr_Domain_close(conn, a_state->domain_state);
441 talloc_destroy(a_state->mem_ctx);
445 samr_CreateDomainGroup
447 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
448 struct samr_CreateDomainGroup *r)
450 struct samr_domain_state *d_state;
451 struct samr_account_state *a_state;
452 struct dcesrv_handle *h;
454 struct ldb_message msg;
456 const char *groupname, *sidstr;
457 time_t now = time(NULL);
458 TALLOC_CTX *mem_ctx2;
459 struct dcesrv_handle *g_handle;
463 ZERO_STRUCTP(r->out.group_handle);
466 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
470 groupname = r->in.name->name;
472 if (groupname == NULL) {
473 return NT_STATUS_INVALID_PARAMETER;
476 /* check if the group already exists */
477 name = samdb_search_string(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
479 "(&(sAMAccountName=%s)(objectclass=group))",
482 return NT_STATUS_GROUP_EXISTS;
487 /* pull in all the template attributes */
488 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
489 "(&(name=TemplateGroup)(objectclass=groupTemplate))");
491 DEBUG(1,("Failed to load TemplateGroup from samdb\n"));
492 return NT_STATUS_INTERNAL_DB_CORRUPTION;
496 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
497 d_state->domain_dn, "nextRid", &rid);
498 if (!NT_STATUS_IS_OK(status)) {
502 /* and the group SID */
503 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
505 return NT_STATUS_NO_MEMORY;
508 /* add core elements to the ldb_message for the user */
509 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", groupname,
512 return NT_STATUS_NO_MEMORY;
514 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
516 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
518 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
519 "sAMAccountName", groupname);
520 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
521 "objectClass", "group");
522 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
523 "objectSid", sidstr);
524 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
526 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
529 /* create the group */
530 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
532 DEBUG(1,("Failed to create group record %s\n", msg.dn));
533 return NT_STATUS_INTERNAL_DB_CORRUPTION;
536 /* create group state and new policy handle */
537 mem_ctx2 = talloc_init("CreateDomainGroup(%s)", groupname);
539 return NT_STATUS_NO_MEMORY;
542 a_state = talloc_p(mem_ctx2, struct samr_account_state);
544 return NT_STATUS_NO_MEMORY;
546 a_state->mem_ctx = mem_ctx2;
547 a_state->sam_ctx = d_state->sam_ctx;
548 a_state->access_mask = r->in.access_mask;
549 a_state->domain_state = d_state;
550 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
551 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
552 a_state->account_name = talloc_strdup(mem_ctx2, groupname);
553 if (!a_state->account_name || !a_state->account_sid) {
554 return NT_STATUS_NO_MEMORY;
557 /* create the policy handle */
558 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
560 return NT_STATUS_NO_MEMORY;
563 g_handle->data = a_state;
564 g_handle->destroy = samr_Account_destroy;
566 /* the domain state is in use one more time */
567 d_state->reference_count++;
569 *r->out.group_handle = g_handle->wire_handle;
577 samr_EnumDomainGroups
579 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
580 struct samr_EnumDomainGroups *r)
582 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
589 TODO: This should do some form of locking, especially around the rid allocation
591 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
592 struct samr_CreateUser2 *r)
594 struct samr_domain_state *d_state;
595 struct samr_account_state *a_state;
596 struct dcesrv_handle *h;
598 struct ldb_message msg;
600 const char *username, *sidstr;
601 time_t now = time(NULL);
602 TALLOC_CTX *mem_ctx2;
603 struct dcesrv_handle *u_handle;
606 const char *container;
608 ZERO_STRUCTP(r->out.acct_handle);
609 *r->out.access_granted = 0;
612 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
616 username = r->in.username->name;
618 if (username == NULL) {
619 return NT_STATUS_INVALID_PARAMETER;
622 /* check if the user already exists */
623 name = samdb_search_string(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
625 "(&(sAMAccountName=%s)(objectclass=user))", username);
627 return NT_STATUS_USER_EXISTS;
632 /* This must be one of these values *only* */
633 if (r->in.acct_flags == ACB_NORMAL) {
634 /* pull in all the template attributes */
635 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
636 "(&(name=TemplateUser)(objectclass=userTemplate))");
638 DEBUG(1,("Failed to load TemplateUser from samdb\n"));
639 return NT_STATUS_INTERNAL_DB_CORRUPTION;
644 } else if (r->in.acct_flags == ACB_WSTRUST) {
645 /* pull in all the template attributes */
646 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
647 "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
649 DEBUG(1,("Failed to load TemplateMemberServer from samdb\n"));
650 return NT_STATUS_INTERNAL_DB_CORRUPTION;
653 container = "Computers";
655 } else if (r->in.acct_flags == ACB_SVRTRUST) {
656 /* pull in all the template attributes */
657 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
658 "(&(name=TemplateDomainController)(objectclass=userTemplate))");
660 DEBUG(1,("Failed to load TemplateDomainController from samdb\n"));
661 return NT_STATUS_INTERNAL_DB_CORRUPTION;
664 container = "DomainControllers";
666 } else if (r->in.acct_flags == ACB_DOMTRUST) {
667 /* pull in all the template attributes */
668 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
669 "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
671 DEBUG(1,("Failed to load TemplateTrustingDomain from samdb\n"));
672 return NT_STATUS_INTERNAL_DB_CORRUPTION;
675 container = "ForeignDomains"; /* FIXME: Is this correct?*/
678 return NT_STATUS_INVALID_PARAMETER;
682 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
683 d_state->domain_dn, "nextRid", &rid);
684 if (!NT_STATUS_IS_OK(status)) {
688 /* and the users SID */
689 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
691 return NT_STATUS_NO_MEMORY;
694 /* add core elements to the ldb_message for the user */
695 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", username, container, d_state->domain_dn);
697 return NT_STATUS_NO_MEMORY;
699 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", username);
700 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", username);
701 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", username);
702 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
703 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
704 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
705 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
707 /* create the user */
708 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
710 DEBUG(1,("Failed to create user record %s\n", msg.dn));
711 return NT_STATUS_INTERNAL_DB_CORRUPTION;
714 /* create user state and new policy handle */
715 mem_ctx2 = talloc_init("CreateUser(%s)", username);
717 return NT_STATUS_NO_MEMORY;
720 a_state = talloc_p(mem_ctx2, struct samr_account_state);
722 return NT_STATUS_NO_MEMORY;
724 a_state->mem_ctx = mem_ctx2;
725 a_state->sam_ctx = d_state->sam_ctx;
726 a_state->access_mask = r->in.access_mask;
727 a_state->domain_state = d_state;
728 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
729 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
730 a_state->account_name = talloc_strdup(mem_ctx2, username);
731 if (!a_state->account_name || !a_state->account_sid) {
732 return NT_STATUS_NO_MEMORY;
735 /* create the policy handle */
736 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
738 return NT_STATUS_NO_MEMORY;
741 u_handle->data = a_state;
742 u_handle->destroy = samr_Account_destroy;
744 /* the domain state is in use one more time */
745 d_state->reference_count++;
747 *r->out.acct_handle = u_handle->wire_handle;
748 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
758 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
759 struct samr_CreateUser *r)
761 struct samr_CreateUser2 r2;
762 uint32 access_granted;
765 /* a simple wrapper around samr_CreateUser2 works nicely */
766 r2.in.handle = r->in.handle;
767 r2.in.username = r->in.username;
768 r2.in.acct_flags = ACB_NORMAL;
769 r2.in.access_mask = r->in.access_mask;
770 r2.out.acct_handle = r->out.acct_handle;
771 r2.out.access_granted = &access_granted;
772 r2.out.rid = r->out.rid;
774 return samr_CreateUser2(dce_call, mem_ctx, &r2);
778 comparison function for sorting SamEntry array
780 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
782 return e1->idx - e2->idx;
788 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
789 struct samr_EnumDomainUsers *r)
791 struct dcesrv_handle *h;
792 struct samr_domain_state *d_state;
793 struct ldb_message **res;
795 struct samr_SamEntry *entries;
796 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
798 *r->out.resume_handle = 0;
800 r->out.num_entries = 0;
802 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
806 /* search for all users in this domain. This could possibly be cached and
807 resumed based on resume_key */
808 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
811 return NT_STATUS_INTERNAL_DB_CORRUPTION;
813 if (count == 0 || r->in.max_size == 0) {
817 /* convert to SamEntry format */
818 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
820 return NT_STATUS_NO_MEMORY;
822 for (i=0;i<count;i++) {
823 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
824 entries[i].name.name = samdb_result_string(res[i], "sAMAccountName", "");
827 /* sort the results by rid */
828 qsort(entries, count, sizeof(struct samr_SamEntry),
829 (comparison_fn_t)compare_SamEntry);
831 /* find the first entry to return */
833 first<count && entries[first].idx <= *r->in.resume_handle;
836 if (first == count) {
840 /* return the rest, limit by max_size. Note that we
841 use the w2k3 element size value of 54 */
842 r->out.num_entries = count - first;
843 r->out.num_entries = MIN(r->out.num_entries,
844 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
846 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
848 return NT_STATUS_NO_MEMORY;
851 r->out.sam->entries = entries+first;
852 r->out.sam->count = r->out.num_entries;
854 if (r->out.num_entries < count - first) {
855 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
856 return STATUS_MORE_ENTRIES;
866 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
867 struct samr_CreateDomAlias *r)
869 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
874 samr_EnumDomainAliases
876 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
877 struct samr_EnumDomainAliases *r)
879 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
884 samr_GetAliasMembership
886 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
887 struct samr_GetAliasMembership *r)
889 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
896 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
897 struct samr_LookupNames *r)
899 struct dcesrv_handle *h;
900 struct samr_domain_state *d_state;
902 NTSTATUS status = NT_STATUS_OK;
903 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
906 ZERO_STRUCT(r->out.rids);
907 ZERO_STRUCT(r->out.types);
909 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
913 if (r->in.num_names == 0) {
917 r->out.rids.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names);
918 r->out.types.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names);
919 if (!r->out.rids.ids || !r->out.types.ids) {
920 return NT_STATUS_NO_MEMORY;
922 r->out.rids.count = r->in.num_names;
923 r->out.types.count = r->in.num_names;
925 for (i=0;i<r->in.num_names;i++) {
926 struct ldb_message **res;
927 struct dom_sid2 *sid;
931 r->out.rids.ids[i] = 0;
932 r->out.types.ids[i] = SID_NAME_UNKNOWN;
934 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
935 "sAMAccountName=%s", r->in.names[i].name);
937 status = STATUS_SOME_UNMAPPED;
941 sidstr = samdb_result_string(res[0], "objectSid", NULL);
942 if (sidstr == NULL) {
943 status = STATUS_SOME_UNMAPPED;
947 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
949 status = STATUS_SOME_UNMAPPED;
953 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
955 status = STATUS_SOME_UNMAPPED;
959 rtype = samdb_atype_map(atype);
961 if (rtype == SID_NAME_UNKNOWN) {
962 status = STATUS_SOME_UNMAPPED;
966 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
967 r->out.types.ids[i] = rtype;
978 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
979 struct samr_LookupRids *r)
981 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
988 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
989 struct samr_OpenGroup *r)
991 struct samr_domain_state *d_state;
992 struct samr_account_state *a_state;
993 struct dcesrv_handle *h;
994 const char *groupname, *sidstr;
995 TALLOC_CTX *mem_ctx2;
996 struct ldb_message **msgs;
997 struct dcesrv_handle *g_handle;
998 const char * const attrs[2] = { "sAMAccountName", NULL };
1001 ZERO_STRUCTP(r->out.acct_handle);
1003 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1007 /* form the group SID */
1008 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1010 return NT_STATUS_NO_MEMORY;
1013 /* search for the group record */
1014 ret = samdb_search(d_state->sam_ctx,
1015 mem_ctx, d_state->domain_dn, &msgs, attrs,
1016 "(&(objectSid=%s)(objectclass=group))",
1019 return NT_STATUS_NO_SUCH_GROUP;
1022 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
1023 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1026 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1027 if (groupname == NULL) {
1028 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
1029 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1032 /* create group state and new policy handle */
1033 mem_ctx2 = talloc_init("OpenGroup(%u)", r->in.rid);
1035 return NT_STATUS_NO_MEMORY;
1038 a_state = talloc_p(mem_ctx2, struct samr_account_state);
1040 return NT_STATUS_NO_MEMORY;
1042 a_state->mem_ctx = mem_ctx2;
1043 a_state->sam_ctx = d_state->sam_ctx;
1044 a_state->access_mask = r->in.access_mask;
1045 a_state->domain_state = d_state;
1046 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1047 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1048 a_state->account_name = talloc_strdup(mem_ctx2, groupname);
1049 if (!a_state->account_name || !a_state->account_sid) {
1050 return NT_STATUS_NO_MEMORY;
1053 /* create the policy handle */
1054 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1056 return NT_STATUS_NO_MEMORY;
1059 g_handle->data = a_state;
1060 g_handle->destroy = samr_Account_destroy;
1062 /* the domain state is in use one more time */
1063 d_state->reference_count++;
1065 *r->out.acct_handle = g_handle->wire_handle;
1067 return NT_STATUS_OK;
1070 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1072 #define QUERY_STRING(msg, field, attr) \
1073 r->out.info->field = samdb_result_string(msg, attr, "");
1074 #define QUERY_UINT(msg, field, attr) \
1075 r->out.info->field = samdb_result_uint(msg, attr, 0);
1076 #define QUERY_RID(msg, field, attr) \
1077 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1078 #define QUERY_NTTIME(msg, field, attr) \
1079 r->out.info->field = samdb_result_nttime(msg, attr, 0);
1080 #define QUERY_APASSC(msg, field, attr) \
1081 r->out.info->field = samdb_result_allow_pwd_change(a_state->sam_ctx, mem_ctx, \
1082 a_state->domain_state->domain_dn, msg, attr);
1083 #define QUERY_FPASSC(msg, field, attr) \
1084 r->out.info->field = samdb_result_force_pwd_change(a_state->sam_ctx, mem_ctx, \
1085 a_state->domain_state->domain_dn, msg, attr);
1086 #define QUERY_LHOURS(msg, field, attr) \
1087 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1088 #define QUERY_AFLAGS(msg, field, attr) \
1089 r->out.info->field = samdb_result_acct_flags(msg, attr);
1092 /* these are used to make the Set[User|Group]Info code easier to follow */
1094 #define SET_STRING(mod, field, attr) do { \
1095 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1096 if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1097 return NT_STATUS_NO_MEMORY; \
1101 #define SET_UINT(mod, field, attr) do { \
1102 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1103 return NT_STATUS_NO_MEMORY; \
1107 #define SET_AFLAGS(msg, field, attr) do { \
1108 if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1109 return NT_STATUS_NO_MEMORY; \
1113 #define SET_LHOURS(msg, field, attr) do { \
1114 if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1115 return NT_STATUS_NO_MEMORY; \
1122 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1123 struct samr_QueryGroupInfo *r)
1125 struct dcesrv_handle *h;
1126 struct samr_account_state *a_state;
1127 struct ldb_message *msg, **res;
1128 const char * const attrs[4] = { "sAMAccountName", "description",
1129 "numMembers", NULL };
1134 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1138 /* pull all the group attributes */
1139 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1140 "dn=%s", a_state->account_dn);
1142 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1146 /* allocate the info structure */
1147 r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1148 if (r->out.info == NULL) {
1149 return NT_STATUS_NO_MEMORY;
1151 ZERO_STRUCTP(r->out.info);
1153 /* Fill in the level */
1154 switch (r->in.level) {
1156 QUERY_STRING(msg, all.name.name, "sAMAccountName");
1157 r->out.info->all.unknown = 7; /* Do like w2k3 */
1158 QUERY_UINT (msg, all.num_members, "numMembers")
1159 QUERY_STRING(msg, all.description.name, "description");
1162 QUERY_STRING(msg, name.name, "sAMAccountName");
1165 r->out.info->unknown.unknown = 7;
1167 case GroupInfoDescription:
1168 QUERY_STRING(msg, description.name, "description");
1172 return NT_STATUS_INVALID_INFO_CLASS;
1175 return NT_STATUS_OK;
1182 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1183 struct samr_SetGroupInfo *r)
1185 struct dcesrv_handle *h;
1186 struct samr_account_state *a_state;
1187 struct ldb_message mod, *msg = &mod;
1190 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1195 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1197 return NT_STATUS_NO_MEMORY;
1200 switch (r->in.level) {
1201 case GroupInfoDescription:
1202 SET_STRING(msg, description.name, "description");
1205 /* On W2k3 this does not change the name, it changes the
1206 * sAMAccountName attribute */
1207 SET_STRING(msg, name.name, "sAMAccountName");
1210 /* This does not do anything obviously visible in W2k3 LDAP */
1213 return NT_STATUS_INVALID_INFO_CLASS;
1216 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1217 for (i=0;i<mod.num_elements;i++) {
1218 mod.elements[i].flags = LDB_FLAG_MOD_REPLACE;
1221 /* modify the samdb record */
1222 ret = samdb_modify(a_state->sam_ctx, mem_ctx, &mod);
1224 /* we really need samdb.c to return NTSTATUS */
1225 return NT_STATUS_UNSUCCESSFUL;
1228 return NT_STATUS_OK;
1235 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1236 struct samr_AddGroupMember *r)
1238 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1243 samr_DeleteDomainGroup
1245 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1246 struct samr_DeleteDomainGroup *r)
1248 struct dcesrv_handle *h;
1249 struct samr_account_state *a_state;
1252 *r->out.handle = *r->in.handle;
1254 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1258 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1260 return NT_STATUS_UNSUCCESSFUL;
1263 ZERO_STRUCTP(r->out.handle);
1265 return NT_STATUS_OK;
1270 samr_DeleteGroupMember
1272 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1273 struct samr_DeleteGroupMember *r)
1275 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1280 samr_QueryGroupMember
1282 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1283 struct samr_QueryGroupMember *r)
1285 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1290 samr_SetMemberAttributesOfGroup
1292 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1293 struct samr_SetMemberAttributesOfGroup *r)
1295 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1302 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1303 struct samr_OpenAlias *r)
1305 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1312 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1313 struct samr_QueryAliasInfo *r)
1315 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1322 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1323 struct samr_SetAliasInfo *r)
1325 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1332 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1333 struct samr_DeleteDomAlias *r)
1335 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1342 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1343 struct samr_AddAliasMember *r)
1345 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1350 samr_DeleteAliasMember
1352 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1353 struct samr_DeleteAliasMember *r)
1355 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1360 samr_GetMembersInAlias
1362 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1363 struct samr_GetMembersInAlias *r)
1365 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1372 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1373 struct samr_OpenUser *r)
1375 struct samr_domain_state *d_state;
1376 struct samr_account_state *a_state;
1377 struct dcesrv_handle *h;
1378 const char *username, *sidstr;
1379 TALLOC_CTX *mem_ctx2;
1380 struct ldb_message **msgs;
1381 struct dcesrv_handle *u_handle;
1382 const char * const attrs[2] = { "sAMAccountName", NULL };
1385 ZERO_STRUCTP(r->out.acct_handle);
1387 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1391 /* form the users SID */
1392 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1394 return NT_STATUS_NO_MEMORY;
1397 /* search for the user record */
1398 ret = samdb_search(d_state->sam_ctx,
1399 mem_ctx, d_state->domain_dn, &msgs, attrs,
1400 "(&(objectSid=%s)(objectclass=user))",
1403 return NT_STATUS_NO_SUCH_USER;
1406 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
1407 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1410 username = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1411 if (username == NULL) {
1412 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
1413 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1416 /* create user state and new policy handle */
1417 mem_ctx2 = talloc_init("OpenUser(%u)", r->in.rid);
1419 return NT_STATUS_NO_MEMORY;
1422 a_state = talloc_p(mem_ctx2, struct samr_account_state);
1424 return NT_STATUS_NO_MEMORY;
1426 a_state->mem_ctx = mem_ctx2;
1427 a_state->sam_ctx = d_state->sam_ctx;
1428 a_state->access_mask = r->in.access_mask;
1429 a_state->domain_state = d_state;
1430 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1431 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1432 a_state->account_name = talloc_strdup(mem_ctx2, username);
1433 if (!a_state->account_name || !a_state->account_sid) {
1434 return NT_STATUS_NO_MEMORY;
1437 /* create the policy handle */
1438 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1440 return NT_STATUS_NO_MEMORY;
1443 u_handle->data = a_state;
1444 u_handle->destroy = samr_Account_destroy;
1446 /* the domain state is in use one more time */
1447 d_state->reference_count++;
1449 *r->out.acct_handle = u_handle->wire_handle;
1451 return NT_STATUS_OK;
1459 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1460 struct samr_DeleteUser *r)
1462 struct dcesrv_handle *h;
1463 struct samr_account_state *a_state;
1466 *r->out.handle = *r->in.handle;
1468 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1472 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1474 return NT_STATUS_UNSUCCESSFUL;
1477 ZERO_STRUCTP(r->out.handle);
1479 return NT_STATUS_OK;
1486 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1487 struct samr_QueryUserInfo *r)
1489 struct dcesrv_handle *h;
1490 struct samr_account_state *a_state;
1491 struct ldb_message *msg, **res;
1496 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1500 /* pull all the user attributes */
1501 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
1502 "dn=%s", a_state->account_dn);
1504 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1508 /* allocate the info structure */
1509 r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1510 if (r->out.info == NULL) {
1511 return NT_STATUS_NO_MEMORY;
1513 ZERO_STRUCTP(r->out.info);
1515 /* fill in the reply */
1516 switch (r->in.level) {
1518 QUERY_STRING(msg, info1.username.name, "sAMAccountName");
1519 QUERY_STRING(msg, info1.full_name.name, "displayName");
1520 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
1521 QUERY_STRING(msg, info1.description.name, "description");
1522 QUERY_STRING(msg, info1.comment.name, "comment");
1526 QUERY_STRING(msg, info2.comment.name, "comment");
1527 QUERY_UINT (msg, info2.country_code, "countryCode");
1528 QUERY_UINT (msg, info2.code_page, "codePage");
1532 QUERY_STRING(msg, info3.username.name, "sAMAccountName");
1533 QUERY_STRING(msg, info3.full_name.name, "displayName");
1534 QUERY_RID (msg, info3.rid, "objectSid");
1535 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
1536 QUERY_STRING(msg, info3.home_directory.name, "homeDirectory");
1537 QUERY_STRING(msg, info3.home_drive.name, "homeDrive");
1538 QUERY_STRING(msg, info3.logon_script.name, "scriptPath");
1539 QUERY_STRING(msg, info3.profile.name, "profilePath");
1540 QUERY_STRING(msg, info3.workstations.name, "userWorkstations");
1541 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
1542 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
1543 QUERY_NTTIME(msg, info3.last_pwd_change, "pwdLastSet");
1544 QUERY_APASSC(msg, info3.allow_pwd_change, "pwdLastSet");
1545 QUERY_FPASSC(msg, info3.force_pwd_change, "pwdLastSet");
1546 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
1547 QUERY_UINT (msg, info3.bad_pwd_count, "badPwdCount");
1548 QUERY_UINT (msg, info3.num_logons, "logonCount");
1549 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
1553 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
1557 QUERY_STRING(msg, info5.username.name, "sAMAccountName");
1558 QUERY_STRING(msg, info5.full_name.name, "displayName");
1559 QUERY_RID (msg, info5.rid, "objectSid");
1560 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
1561 QUERY_STRING(msg, info5.home_directory.name, "homeDirectory");
1562 QUERY_STRING(msg, info5.home_drive.name, "homeDrive");
1563 QUERY_STRING(msg, info5.logon_script.name, "scriptPath");
1564 QUERY_STRING(msg, info5.profile.name, "profilePath");
1565 QUERY_STRING(msg, info5.description.name, "description");
1566 QUERY_STRING(msg, info5.workstations.name, "userWorkstations");
1567 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
1568 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
1569 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
1570 QUERY_UINT (msg, info5.bad_pwd_count, "badPwdCount");
1571 QUERY_UINT (msg, info5.num_logons, "logonCount");
1572 QUERY_NTTIME(msg, info5.last_pwd_change, "pwdLastSet");
1573 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
1574 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
1578 QUERY_STRING(msg, info6.username.name, "sAMAccountName");
1579 QUERY_STRING(msg, info6.full_name.name, "displayName");
1583 QUERY_STRING(msg, info7.username.name, "sAMAccountName");
1587 QUERY_STRING(msg, info8.full_name.name, "displayName");
1591 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
1595 QUERY_STRING(msg, info10.home_directory.name, "homeDirectory");
1596 QUERY_STRING(msg, info10.home_drive.name, "homeDrive");
1600 QUERY_STRING(msg, info11.logon_script.name, "scriptPath");
1604 QUERY_STRING(msg, info12.profile.name, "profilePath");
1608 QUERY_STRING(msg, info13.description.name, "description");
1612 QUERY_STRING(msg, info14.workstations.name, "userWorkstations");
1616 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1620 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
1623 QUERY_STRING(msg, info20.callback.name, "userParameters");
1627 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
1628 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
1629 QUERY_NTTIME(msg, info21.last_pwd_change, "pwdLastSet");
1630 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
1631 QUERY_APASSC(msg, info21.allow_pwd_change, "pwdLastSet");
1632 QUERY_FPASSC(msg, info21.force_pwd_change, "pwdLastSet");
1633 QUERY_STRING(msg, info21.username.name, "sAMAccountName");
1634 QUERY_STRING(msg, info21.full_name.name, "displayName");
1635 QUERY_STRING(msg, info21.home_directory.name, "homeDirectory");
1636 QUERY_STRING(msg, info21.home_drive.name, "homeDrive");
1637 QUERY_STRING(msg, info21.logon_script.name, "scriptPath");
1638 QUERY_STRING(msg, info21.profile.name, "profilePath");
1639 QUERY_STRING(msg, info21.description.name, "description");
1640 QUERY_STRING(msg, info21.workstations.name, "userWorkstations");
1641 QUERY_STRING(msg, info21.comment.name, "comment");
1642 QUERY_STRING(msg, info21.callback.name, "userParameters");
1643 QUERY_RID (msg, info21.rid, "objectSid");
1644 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
1645 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
1646 r->out.info->info21.fields_present = 0x00FFFFFF;
1647 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
1648 QUERY_UINT (msg, info21.bad_pwd_count, "badPwdCount");
1649 QUERY_UINT (msg, info21.num_logons, "logonCount");
1650 QUERY_UINT (msg, info21.country_code, "countryCode");
1651 QUERY_UINT (msg, info21.code_page, "codePage");
1657 return NT_STATUS_INVALID_INFO_CLASS;
1660 return NT_STATUS_OK;
1665 set password via a samr_CryptPassword buffer
1666 this will in the 'msg' with modify operations that will update the user
1667 password when applied
1669 static NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
1670 struct samr_account_state *a_state, TALLOC_CTX *mem_ctx,
1671 struct ldb_message *msg,
1672 struct samr_CryptPassword *pwbuf)
1675 uint32 new_pass_len;
1676 DATA_BLOB session_key = dce_call->conn->session_key;
1678 SamOEMhashBlob(pwbuf->data, 516, &session_key);
1680 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
1681 &new_pass_len, STR_UNICODE)) {
1682 DEBUG(3,("samr: failed to decode password buffer\n"));
1683 return NT_STATUS_WRONG_PASSWORD;
1686 /* set the password - samdb needs to know both the domain and user DNs,
1687 so the domain password policy can be used */
1688 return samdb_set_password(a_state->sam_ctx, mem_ctx,
1689 a_state->account_dn, a_state->domain_state->domain_dn,
1692 False /* This is a password set, not change */);
1698 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1699 struct samr_SetUserInfo *r)
1701 struct dcesrv_handle *h;
1702 struct samr_account_state *a_state;
1703 struct ldb_message mod, *msg = &mod;
1705 NTSTATUS status = NT_STATUS_OK;
1707 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1712 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1714 return NT_STATUS_NO_MEMORY;
1717 switch (r->in.level) {
1719 SET_STRING(msg, info2.comment.name, "comment");
1720 SET_UINT (msg, info2.country_code, "countryCode");
1721 SET_UINT (msg, info2.code_page, "codePage");
1725 SET_LHOURS(msg, info4.logon_hours, "logonHours");
1729 SET_STRING(msg, info6.full_name.name, "displayName");
1733 SET_STRING(msg, info8.full_name.name, "displayName");
1737 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
1741 SET_STRING(msg, info10.home_directory.name, "homeDirectory");
1742 SET_STRING(msg, info10.home_drive.name, "homeDrive");
1746 SET_STRING(msg, info11.logon_script.name, "scriptPath");
1750 SET_STRING(msg, info12.profile.name, "profilePath");
1754 SET_STRING(msg, info13.description.name, "description");
1758 SET_STRING(msg, info14.workstations.name, "userWorkstations");
1762 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1766 SET_STRING(msg, info20.callback.name, "userParameters");
1770 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1771 IFSET(SAMR_FIELD_NAME)
1772 SET_STRING(msg, info21.full_name.name, "displayName");
1773 IFSET(SAMR_FIELD_DESCRIPTION)
1774 SET_STRING(msg, info21.description.name, "description");
1775 IFSET(SAMR_FIELD_COMMENT)
1776 SET_STRING(msg, info21.comment.name, "comment");
1777 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1778 SET_STRING(msg, info21.logon_script.name, "scriptPath");
1779 IFSET(SAMR_FIELD_PROFILE)
1780 SET_STRING(msg, info21.profile.name, "profilePath");
1781 IFSET(SAMR_FIELD_WORKSTATION)
1782 SET_STRING(msg, info21.workstations.name, "userWorkstations");
1783 IFSET(SAMR_FIELD_LOGON_HOURS)
1784 SET_LHOURS(msg, info21.logon_hours, "logonHours");
1785 IFSET(SAMR_FIELD_CALLBACK)
1786 SET_STRING(msg, info21.callback.name, "userParameters");
1787 IFSET(SAMR_FIELD_COUNTRY_CODE)
1788 SET_UINT (msg, info21.country_code, "countryCode");
1789 IFSET(SAMR_FIELD_CODE_PAGE)
1790 SET_UINT (msg, info21.code_page, "codePage");
1793 /* the set password levels are handled separately */
1795 status = samr_set_password(dce_call, a_state, mem_ctx, msg,
1796 &r->in.info->info24.password);
1801 /* many info classes are not valid for SetUserInfo */
1802 return NT_STATUS_INVALID_INFO_CLASS;
1805 if (!NT_STATUS_IS_OK(status)) {
1809 /* mark all the message elements as LDB_FLAG_MOD_REPLACE,
1810 unless they are already marked with some other flag */
1811 for (i=0;i<mod.num_elements;i++) {
1812 if (mod.elements[i].flags == 0) {
1813 mod.elements[i].flags = LDB_FLAG_MOD_REPLACE;
1817 /* modify the samdb record */
1818 ret = samdb_modify(a_state->sam_ctx, mem_ctx, msg);
1820 /* we really need samdb.c to return NTSTATUS */
1821 return NT_STATUS_UNSUCCESSFUL;
1824 return NT_STATUS_OK;
1829 samr_ChangePasswordUser
1831 static NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1832 struct samr_ChangePasswordUser *r)
1834 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1839 samr_GetGroupsForUser
1841 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1842 struct samr_GetGroupsForUser *r)
1844 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1849 samr_QueryDisplayInfo
1851 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1852 struct samr_QueryDisplayInfo *r)
1854 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1859 samr_GetDisplayEnumerationIndex
1861 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1862 struct samr_GetDisplayEnumerationIndex *r)
1864 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1869 samr_TestPrivateFunctionsDomain
1871 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1872 struct samr_TestPrivateFunctionsDomain *r)
1874 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1879 samr_TestPrivateFunctionsUser
1881 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1882 struct samr_TestPrivateFunctionsUser *r)
1884 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1891 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1892 struct samr_GetUserPwInfo *r)
1894 struct dcesrv_handle *h;
1895 struct samr_account_state *a_state;
1897 ZERO_STRUCT(r->out.info);
1899 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1903 r->out.info.min_pwd_len = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength",
1904 "dn=%s", a_state->domain_state->domain_dn);
1905 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties",
1906 "dn=%s", a_state->account_dn);
1907 return NT_STATUS_OK;
1912 samr_RemoveMemberFromForeignDomain
1914 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1915 struct samr_RemoveMemberFromForeignDomain *r)
1917 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1922 samr_QueryDomainInfo2
1924 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1925 struct samr_QueryDomainInfo2 *r)
1927 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1934 just an alias for samr_QueryUserInfo
1936 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1937 struct samr_QueryUserInfo2 *r)
1939 struct samr_QueryUserInfo r1;
1942 r1.in.handle = r->in.handle;
1943 r1.in.level = r->in.level;
1945 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
1947 r->out.info = r1.out.info;
1954 samr_QueryDisplayInfo2
1956 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1957 struct samr_QueryDisplayInfo2 *r)
1959 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1964 samr_GetDisplayEnumerationIndex2
1966 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1967 struct samr_GetDisplayEnumerationIndex2 *r)
1969 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1974 samr_QueryDisplayInfo3
1976 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1977 struct samr_QueryDisplayInfo3 *r)
1979 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1984 samr_AddMultipleMembersToAlias
1986 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1987 struct samr_AddMultipleMembersToAlias *r)
1989 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1994 samr_RemoveMultipleMembersFromAlias
1996 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1997 struct samr_RemoveMultipleMembersFromAlias *r)
1999 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2004 samr_OemChangePasswordUser2
2006 static NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2007 struct samr_OemChangePasswordUser2 *r)
2009 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2014 samr_ChangePasswordUser2
2016 static NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2017 struct samr_ChangePasswordUser2 *r)
2019 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2026 this fetches the default password properties for a domain
2028 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2029 struct samr_GetDomPwInfo *r)
2031 struct ldb_message **msgs;
2033 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2036 if (r->in.name == NULL || r->in.name->name == NULL) {
2037 return NT_STATUS_NO_SUCH_DOMAIN;
2040 sam_ctx = samdb_connect();
2041 if (sam_ctx == NULL) {
2042 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2045 ret = samdb_search(sam_ctx,
2046 mem_ctx, NULL, &msgs, attrs,
2047 "(&(name=%s)(objectclass=domain))",
2050 samdb_close(sam_ctx);
2051 return NT_STATUS_NO_SUCH_DOMAIN;
2054 samdb_search_free(sam_ctx, mem_ctx, msgs);
2055 samdb_close(sam_ctx);
2056 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2059 r->out.info.min_pwd_len = samdb_result_uint(msgs[0], "minPwdLength", 0);
2060 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2062 samdb_search_free(sam_ctx, mem_ctx, msgs);
2064 samdb_close(sam_ctx);
2065 return NT_STATUS_OK;
2072 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2073 struct samr_Connect2 *r)
2075 struct samr_Connect c;
2077 c.in.system_name = NULL;
2078 c.in.access_mask = r->in.access_mask;
2079 c.out.handle = r->out.handle;
2081 return samr_Connect(dce_call, mem_ctx, &c);
2088 just an alias for samr_SetUserInfo
2090 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2091 struct samr_SetUserInfo2 *r)
2093 struct samr_SetUserInfo r2;
2095 r2.in.handle = r->in.handle;
2096 r2.in.level = r->in.level;
2097 r2.in.info = r->in.info;
2099 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2104 samr_SetBootKeyInformation
2106 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2107 struct samr_SetBootKeyInformation *r)
2109 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2114 samr_GetBootKeyInformation
2116 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2117 struct samr_GetBootKeyInformation *r)
2119 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2126 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2127 struct samr_Connect3 *r)
2129 struct samr_Connect c;
2131 c.in.system_name = NULL;
2132 c.in.access_mask = r->in.access_mask;
2133 c.out.handle = r->out.handle;
2135 return samr_Connect(dce_call, mem_ctx, &c);
2142 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2143 struct samr_Connect4 *r)
2145 struct samr_Connect c;
2147 c.in.system_name = NULL;
2148 c.in.access_mask = r->in.access_mask;
2149 c.out.handle = r->out.handle;
2151 return samr_Connect(dce_call, mem_ctx, &c);
2156 samr_ChangePasswordUser3
2158 static NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2159 struct samr_ChangePasswordUser3 *r)
2161 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2168 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2169 struct samr_Connect5 *r)
2171 struct samr_Connect c;
2174 c.in.system_name = NULL;
2175 c.in.access_mask = r->in.access_mask;
2176 c.out.handle = r->out.handle;
2178 status = samr_Connect(dce_call, mem_ctx, &c);
2180 r->out.info->info1.unknown1 = 3;
2181 r->out.info->info1.unknown2 = 0;
2182 r->out.level = r->in.level;
2191 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2192 struct samr_RidToSid *r)
2194 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2199 samr_SetDsrmPassword
2201 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2202 struct samr_SetDsrmPassword *r)
2204 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2209 samr_ValidatePassword
2211 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2212 struct samr_ValidatePassword *r)
2214 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2218 /* include the generated boilerplate */
2219 #include "librpc/gen_ndr/ndr_samr_s.c"