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 connection state
32 static void samr_Connect_close(struct samr_connect_state *c_state)
34 c_state->reference_count--;
35 if (c_state->reference_count == 0) {
36 samdb_close(c_state->sam_ctx);
37 talloc_destroy(c_state->mem_ctx);
42 destroy an open connection. This closes the database connection
44 static void samr_Connect_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
46 struct samr_connect_state *c_state = h->data;
47 samr_Connect_close(c_state);
53 create a connection to the SAM database
55 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
56 struct samr_Connect *r)
58 struct samr_connect_state *c_state;
59 struct dcesrv_handle *handle;
60 TALLOC_CTX *connect_mem_ctx;
62 ZERO_STRUCTP(r->out.handle);
64 connect_mem_ctx = talloc_init("samr_Connect");
65 if (!connect_mem_ctx) {
66 return NT_STATUS_NO_MEMORY;
69 c_state = talloc_p(connect_mem_ctx, struct samr_connect_state);
71 return NT_STATUS_NO_MEMORY;
73 c_state->mem_ctx = connect_mem_ctx;
75 /* make sure the sam database is accessible */
76 c_state->sam_ctx = samdb_connect();
77 if (c_state->sam_ctx == NULL) {
78 talloc_destroy(c_state->mem_ctx);
79 return NT_STATUS_INVALID_SYSTEM_SERVICE;
82 handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_CONNECT);
84 talloc_destroy(c_state->mem_ctx);
85 return NT_STATUS_NO_MEMORY;
88 handle->data = c_state;
89 handle->destroy = samr_Connect_destroy;
91 c_state->reference_count = 1;
92 c_state->access_mask = r->in.access_mask;
93 *r->out.handle = handle->wire_handle;
102 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
103 struct samr_Close *r)
105 struct dcesrv_handle *h;
107 *r->out.handle = *r->in.handle;
109 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
111 /* this causes the callback samr_XXX_destroy() to be called by
112 the handle destroy code which destroys the state associated
114 dcesrv_handle_destroy(dce_call->conn, h);
116 ZERO_STRUCTP(r->out.handle);
125 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
126 struct samr_SetSecurity *r)
128 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
135 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
136 struct samr_QuerySecurity *r)
138 struct dcesrv_handle *h;
139 struct samr_SdBuf *sd;
143 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
145 sd = talloc_p(mem_ctx, struct samr_SdBuf);
147 return NT_STATUS_NO_MEMORY;
150 sd->sd = samdb_default_security_descriptor(mem_ctx);
161 we refuse this operation completely. If a admin wants to shutdown samr
162 in Samba then they should use the samba admin tools to disable the samr pipe
164 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
165 struct samr_Shutdown *r)
167 return NT_STATUS_ACCESS_DENIED;
174 this maps from a domain name to a SID
176 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
177 struct samr_LookupDomain *r)
179 struct samr_connect_state *c_state;
180 struct dcesrv_handle *h;
181 struct dom_sid2 *sid;
186 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
190 if (r->in.domain->name == NULL) {
191 return NT_STATUS_INVALID_PARAMETER;
194 sidstr = samdb_search_string(c_state->sam_ctx,
195 mem_ctx, NULL, "objectSid",
196 "(&(name=%s)(objectclass=domain))",
198 if (sidstr == NULL) {
199 return NT_STATUS_NO_SUCH_DOMAIN;
202 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
204 DEBUG(1,("samdb: Invalid sid '%s' for domain %s\n",
205 sidstr, r->in.domain->name));
206 return NT_STATUS_INTERNAL_DB_CORRUPTION;
218 list the domains in the SAM
220 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
221 struct samr_EnumDomains *r)
223 struct samr_connect_state *c_state;
224 struct dcesrv_handle *h;
225 struct samr_SamArray *array;
226 const char **domains;
227 int count, i, start_i;
229 *r->out.resume_handle = 0;
231 r->out.num_entries = 0;
233 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
237 count = samdb_search_string_multiple(c_state->sam_ctx,
238 mem_ctx, NULL, &domains,
239 "name", "(objectclass=domain)");
241 DEBUG(1,("samdb: no domains found in EnumDomains\n"));
242 return NT_STATUS_INTERNAL_DB_CORRUPTION;
245 *r->out.resume_handle = count;
247 start_i = *r->in.resume_handle;
249 if (start_i >= count) {
250 /* search past end of list is not an error for this call */
254 array = talloc_p(mem_ctx, struct samr_SamArray);
256 return NT_STATUS_NO_MEMORY;
260 array->entries = NULL;
262 array->entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count - start_i);
263 if (array->entries == NULL) {
264 return NT_STATUS_NO_MEMORY;
267 for (i=0;i<count-start_i;i++) {
268 array->entries[i].idx = start_i + i;
269 array->entries[i].name.name = domains[start_i+i];
273 r->out.num_entries = i;
274 array->count = r->out.num_entries;
281 close an open domain context
283 static void samr_Domain_close(struct dcesrv_connection *conn,
284 struct samr_domain_state *d_state)
286 d_state->reference_count--;
287 if (d_state->reference_count == 0) {
288 samr_Connect_close(d_state->connect_state);
289 talloc_destroy(d_state->mem_ctx);
294 destroy an open domain context
296 static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
298 struct samr_domain_state *d_state = h->data;
299 samr_Domain_close(conn, d_state);
305 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
306 struct samr_OpenDomain *r)
308 struct dcesrv_handle *h_conn, *h_domain;
309 const char *sidstr, *domain_name;
310 struct samr_connect_state *c_state;
311 struct samr_domain_state *d_state;
312 TALLOC_CTX *mem_ctx2;
313 const char * const attrs[2] = { "name", NULL};
314 struct ldb_message **msgs;
317 ZERO_STRUCTP(r->out.domain_handle);
319 DCESRV_PULL_HANDLE(h_conn, r->in.handle, SAMR_HANDLE_CONNECT);
321 c_state = h_conn->data;
323 if (r->in.sid == NULL) {
324 return NT_STATUS_INVALID_PARAMETER;
327 sidstr = dom_sid_string(mem_ctx, r->in.sid);
328 if (sidstr == NULL) {
329 return NT_STATUS_INVALID_PARAMETER;
332 ret = samdb_search(c_state->sam_ctx,
333 mem_ctx, NULL, &msgs, attrs,
334 "(&(objectSid=%s)(objectclass=domain))",
337 return NT_STATUS_NO_SUCH_DOMAIN;
340 domain_name = ldb_msg_find_string(msgs[0], "name", NULL);
341 if (domain_name == NULL) {
342 return NT_STATUS_NO_SUCH_DOMAIN;
345 mem_ctx2 = talloc_init("OpenDomain(%s)\n", domain_name);
347 return NT_STATUS_NO_MEMORY;
350 d_state = talloc_p(mem_ctx2, struct samr_domain_state);
352 talloc_destroy(mem_ctx2);
353 return NT_STATUS_NO_MEMORY;
356 d_state->reference_count = 1;
357 d_state->connect_state = c_state;
358 d_state->sam_ctx = c_state->sam_ctx;
359 d_state->mem_ctx = mem_ctx2;
360 d_state->domain_sid = talloc_strdup(mem_ctx2, sidstr);
361 d_state->domain_name = talloc_strdup(mem_ctx2, domain_name);
362 d_state->domain_dn = talloc_strdup(mem_ctx2, msgs[0]->dn);
363 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
364 talloc_destroy(mem_ctx2);
365 return NT_STATUS_NO_MEMORY;
367 d_state->access_mask = r->in.access_mask;
369 h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN);
371 talloc_destroy(mem_ctx2);
372 return NT_STATUS_NO_MEMORY;
375 c_state->reference_count++;
376 h_domain->data = d_state;
377 h_domain->destroy = samr_Domain_destroy;
378 *r->out.domain_handle = h_domain->wire_handle;
386 static NTSTATUS samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
387 struct samr_DomInfo2 *info)
389 const char * const attrs[] = { "comment", "name", NULL };
391 struct ldb_message **res;
393 ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, attrs,
394 "dn=%s", state->domain_dn);
396 return NT_STATUS_INTERNAL_DB_CORRUPTION;
399 /* where is this supposed to come from? is it settable? */
400 info->force_logoff_time = 0x8000000000000000LL;
402 info->comment.name = samdb_result_string(res[0], "comment", NULL);
403 info->domain.name = samdb_result_string(res[0], "name", NULL);
405 info->primary.name = lp_netbios_name();
406 info->sequence_num = 0;
407 info->role = ROLE_DOMAIN_PDC;
408 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, NULL, "(objectClass=user)");
409 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
410 "(&(objectClass=group)(sAMAccountType=%u))",
412 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
413 "(&(objectClass=group)(sAMAccountType=%u))",
422 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
423 struct samr_QueryDomainInfo *r)
425 struct dcesrv_handle *h;
426 struct samr_domain_state *d_state;
430 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
434 r->out.info = talloc_p(mem_ctx, union samr_DomainInfo);
436 return NT_STATUS_NO_MEMORY;
439 ZERO_STRUCTP(r->out.info);
441 switch (r->in.level) {
443 return samr_info_DomInfo2(d_state, mem_ctx, &r->out.info->info2);
446 return NT_STATUS_INVALID_INFO_CLASS;
453 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
454 struct samr_SetDomainInfo *r)
456 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
460 destroy an open account context
462 static void samr_Account_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
464 struct samr_account_state *a_state = h->data;
465 samr_Domain_close(conn, a_state->domain_state);
466 talloc_destroy(a_state->mem_ctx);
470 samr_CreateDomainGroup
472 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
473 struct samr_CreateDomainGroup *r)
475 struct samr_domain_state *d_state;
476 struct samr_account_state *a_state;
477 struct dcesrv_handle *h;
479 struct ldb_message msg;
481 const char *groupname, *sidstr;
482 time_t now = time(NULL);
483 TALLOC_CTX *mem_ctx2;
484 struct dcesrv_handle *g_handle;
488 ZERO_STRUCTP(r->out.group_handle);
491 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
495 groupname = r->in.name->name;
497 if (groupname == NULL) {
498 return NT_STATUS_INVALID_PARAMETER;
501 /* check if the group already exists */
502 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
504 "(&(sAMAccountName=%s)(objectclass=group))",
507 return NT_STATUS_GROUP_EXISTS;
512 /* pull in all the template attributes */
513 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
514 "(&(name=TemplateGroup)(objectclass=groupTemplate))");
516 DEBUG(1,("Failed to load TemplateGroup from samdb\n"));
517 return NT_STATUS_INTERNAL_DB_CORRUPTION;
521 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
522 d_state->domain_dn, "nextRid", &rid);
523 if (!NT_STATUS_IS_OK(status)) {
527 /* and the group SID */
528 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
530 return NT_STATUS_NO_MEMORY;
533 /* add core elements to the ldb_message for the user */
534 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", groupname,
537 return NT_STATUS_NO_MEMORY;
539 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
541 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
543 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
544 "sAMAccountName", groupname);
545 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
546 "objectClass", "group");
547 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
548 "objectSid", sidstr);
549 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
551 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
554 /* create the group */
555 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
557 DEBUG(1,("Failed to create group record %s\n", msg.dn));
558 return NT_STATUS_INTERNAL_DB_CORRUPTION;
561 /* create group state and new policy handle */
562 mem_ctx2 = talloc_init("CreateDomainGroup(%s)", groupname);
564 return NT_STATUS_NO_MEMORY;
567 a_state = talloc_p(mem_ctx2, struct samr_account_state);
569 return NT_STATUS_NO_MEMORY;
571 a_state->mem_ctx = mem_ctx2;
572 a_state->sam_ctx = d_state->sam_ctx;
573 a_state->access_mask = r->in.access_mask;
574 a_state->domain_state = d_state;
575 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
576 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
577 a_state->account_name = talloc_strdup(mem_ctx2, groupname);
578 if (!a_state->account_name || !a_state->account_sid) {
579 return NT_STATUS_NO_MEMORY;
582 /* create the policy handle */
583 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
585 return NT_STATUS_NO_MEMORY;
588 g_handle->data = a_state;
589 g_handle->destroy = samr_Account_destroy;
591 /* the domain state is in use one more time */
592 d_state->reference_count++;
594 *r->out.group_handle = g_handle->wire_handle;
602 samr_EnumDomainGroups
604 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
605 struct samr_EnumDomainGroups *r)
607 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
614 TODO: This should do some form of locking, especially around the rid allocation
616 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
617 struct samr_CreateUser2 *r)
619 struct samr_domain_state *d_state;
620 struct samr_account_state *a_state;
621 struct dcesrv_handle *h;
623 struct ldb_message msg;
625 const char *username, *sidstr;
626 time_t now = time(NULL);
627 TALLOC_CTX *mem_ctx2;
628 struct dcesrv_handle *u_handle;
631 const char *container, *additional_class=NULL;
633 ZERO_STRUCTP(r->out.acct_handle);
634 *r->out.access_granted = 0;
637 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
641 username = r->in.username->name;
643 if (username == NULL) {
644 return NT_STATUS_INVALID_PARAMETER;
647 /* check if the user already exists */
648 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
650 "(&(sAMAccountName=%s)(objectclass=user))", username);
652 return NT_STATUS_USER_EXISTS;
657 /* This must be one of these values *only* */
658 if (r->in.acct_flags == ACB_NORMAL) {
659 /* pull in all the template attributes */
660 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
661 "(&(name=TemplateUser)(objectclass=userTemplate))");
663 DEBUG(1,("Failed to load TemplateUser from samdb\n"));
664 return NT_STATUS_INTERNAL_DB_CORRUPTION;
669 } else if (r->in.acct_flags == ACB_WSTRUST) {
670 /* pull in all the template attributes */
671 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
672 "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
674 DEBUG(1,("Failed to load TemplateMemberServer from samdb\n"));
675 return NT_STATUS_INTERNAL_DB_CORRUPTION;
678 container = "Computers";
679 additional_class = "computer";
681 } else if (r->in.acct_flags == ACB_SVRTRUST) {
682 /* pull in all the template attributes */
683 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
684 "(&(name=TemplateDomainController)(objectclass=userTemplate))");
686 DEBUG(1,("Failed to load TemplateDomainController from samdb\n"));
687 return NT_STATUS_INTERNAL_DB_CORRUPTION;
690 container = "DomainControllers";
691 additional_class = "computer";
693 } else if (r->in.acct_flags == ACB_DOMTRUST) {
694 /* pull in all the template attributes */
695 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
696 "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
698 DEBUG(1,("Failed to load TemplateTrustingDomain from samdb\n"));
699 return NT_STATUS_INTERNAL_DB_CORRUPTION;
702 container = "ForeignDomains"; /* FIXME: Is this correct?*/
703 additional_class = "computer";
706 return NT_STATUS_INVALID_PARAMETER;
710 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
711 d_state->domain_dn, "nextRid", &rid);
712 if (!NT_STATUS_IS_OK(status)) {
716 /* and the users SID */
717 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
719 return NT_STATUS_NO_MEMORY;
722 /* add core elements to the ldb_message for the user */
723 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", username, container, d_state->domain_dn);
725 return NT_STATUS_NO_MEMORY;
727 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", username);
728 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", username);
729 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", username);
730 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
731 if (additional_class) {
732 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class);
734 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
735 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
736 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
738 /* create the user */
739 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
741 DEBUG(1,("Failed to create user record %s\n", msg.dn));
742 return NT_STATUS_INTERNAL_DB_CORRUPTION;
745 /* create user state and new policy handle */
746 mem_ctx2 = talloc_init("CreateUser(%s)", username);
748 return NT_STATUS_NO_MEMORY;
751 a_state = talloc_p(mem_ctx2, struct samr_account_state);
753 return NT_STATUS_NO_MEMORY;
755 a_state->mem_ctx = mem_ctx2;
756 a_state->sam_ctx = d_state->sam_ctx;
757 a_state->access_mask = r->in.access_mask;
758 a_state->domain_state = d_state;
759 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
760 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
761 a_state->account_name = talloc_strdup(mem_ctx2, username);
762 if (!a_state->account_name || !a_state->account_sid) {
763 return NT_STATUS_NO_MEMORY;
766 /* create the policy handle */
767 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
769 return NT_STATUS_NO_MEMORY;
772 u_handle->data = a_state;
773 u_handle->destroy = samr_Account_destroy;
775 /* the domain state is in use one more time */
776 d_state->reference_count++;
778 *r->out.acct_handle = u_handle->wire_handle;
779 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
789 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
790 struct samr_CreateUser *r)
792 struct samr_CreateUser2 r2;
793 uint32_t access_granted;
796 /* a simple wrapper around samr_CreateUser2 works nicely */
797 r2.in.handle = r->in.handle;
798 r2.in.username = r->in.username;
799 r2.in.acct_flags = ACB_NORMAL;
800 r2.in.access_mask = r->in.access_mask;
801 r2.out.acct_handle = r->out.acct_handle;
802 r2.out.access_granted = &access_granted;
803 r2.out.rid = r->out.rid;
805 return samr_CreateUser2(dce_call, mem_ctx, &r2);
809 comparison function for sorting SamEntry array
811 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
813 return e1->idx - e2->idx;
819 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
820 struct samr_EnumDomainUsers *r)
822 struct dcesrv_handle *h;
823 struct samr_domain_state *d_state;
824 struct ldb_message **res;
826 struct samr_SamEntry *entries;
827 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
829 *r->out.resume_handle = 0;
831 r->out.num_entries = 0;
833 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
837 /* search for all users in this domain. This could possibly be cached and
838 resumed based on resume_key */
839 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
842 return NT_STATUS_INTERNAL_DB_CORRUPTION;
844 if (count == 0 || r->in.max_size == 0) {
848 /* convert to SamEntry format */
849 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
851 return NT_STATUS_NO_MEMORY;
853 for (i=0;i<count;i++) {
854 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
855 entries[i].name.name = samdb_result_string(res[i], "sAMAccountName", "");
858 /* sort the results by rid */
859 qsort(entries, count, sizeof(struct samr_SamEntry),
860 (comparison_fn_t)compare_SamEntry);
862 /* find the first entry to return */
864 first<count && entries[first].idx <= *r->in.resume_handle;
867 if (first == count) {
871 /* return the rest, limit by max_size. Note that we
872 use the w2k3 element size value of 54 */
873 r->out.num_entries = count - first;
874 r->out.num_entries = MIN(r->out.num_entries,
875 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
877 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
879 return NT_STATUS_NO_MEMORY;
882 r->out.sam->entries = entries+first;
883 r->out.sam->count = r->out.num_entries;
885 if (r->out.num_entries < count - first) {
886 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
887 return STATUS_MORE_ENTRIES;
897 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
898 struct samr_CreateDomAlias *r)
900 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
905 samr_EnumDomainAliases
907 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
908 struct samr_EnumDomainAliases *r)
910 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
915 samr_GetAliasMembership
917 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
918 struct samr_GetAliasMembership *r)
920 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
927 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
928 struct samr_LookupNames *r)
930 struct dcesrv_handle *h;
931 struct samr_domain_state *d_state;
933 NTSTATUS status = NT_STATUS_OK;
934 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
937 ZERO_STRUCT(r->out.rids);
938 ZERO_STRUCT(r->out.types);
940 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
944 if (r->in.num_names == 0) {
948 r->out.rids.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
949 r->out.types.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
950 if (!r->out.rids.ids || !r->out.types.ids) {
951 return NT_STATUS_NO_MEMORY;
953 r->out.rids.count = r->in.num_names;
954 r->out.types.count = r->in.num_names;
956 for (i=0;i<r->in.num_names;i++) {
957 struct ldb_message **res;
958 struct dom_sid2 *sid;
960 uint32_t atype, rtype;
962 r->out.rids.ids[i] = 0;
963 r->out.types.ids[i] = SID_NAME_UNKNOWN;
965 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
966 "sAMAccountName=%s", r->in.names[i].name);
968 status = STATUS_SOME_UNMAPPED;
972 sidstr = samdb_result_string(res[0], "objectSid", NULL);
973 if (sidstr == NULL) {
974 status = STATUS_SOME_UNMAPPED;
978 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
980 status = STATUS_SOME_UNMAPPED;
984 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
986 status = STATUS_SOME_UNMAPPED;
990 rtype = samdb_atype_map(atype);
992 if (rtype == SID_NAME_UNKNOWN) {
993 status = STATUS_SOME_UNMAPPED;
997 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
998 r->out.types.ids[i] = rtype;
1009 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1010 struct samr_LookupRids *r)
1012 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1019 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1020 struct samr_OpenGroup *r)
1022 struct samr_domain_state *d_state;
1023 struct samr_account_state *a_state;
1024 struct dcesrv_handle *h;
1025 const char *groupname, *sidstr;
1026 TALLOC_CTX *mem_ctx2;
1027 struct ldb_message **msgs;
1028 struct dcesrv_handle *g_handle;
1029 const char * const attrs[2] = { "sAMAccountName", NULL };
1032 ZERO_STRUCTP(r->out.acct_handle);
1034 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1038 /* form the group SID */
1039 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1041 return NT_STATUS_NO_MEMORY;
1044 /* search for the group record */
1045 ret = samdb_search(d_state->sam_ctx,
1046 mem_ctx, d_state->domain_dn, &msgs, attrs,
1047 "(&(objectSid=%s)(objectclass=group))",
1050 return NT_STATUS_NO_SUCH_GROUP;
1053 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
1054 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1057 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1058 if (groupname == NULL) {
1059 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
1060 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1063 /* create group state and new policy handle */
1064 mem_ctx2 = talloc_init("OpenGroup(%u)", r->in.rid);
1066 return NT_STATUS_NO_MEMORY;
1069 a_state = talloc_p(mem_ctx2, struct samr_account_state);
1071 return NT_STATUS_NO_MEMORY;
1073 a_state->mem_ctx = mem_ctx2;
1074 a_state->sam_ctx = d_state->sam_ctx;
1075 a_state->access_mask = r->in.access_mask;
1076 a_state->domain_state = d_state;
1077 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1078 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1079 a_state->account_name = talloc_strdup(mem_ctx2, groupname);
1080 if (!a_state->account_name || !a_state->account_sid) {
1081 return NT_STATUS_NO_MEMORY;
1084 /* create the policy handle */
1085 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1087 return NT_STATUS_NO_MEMORY;
1090 g_handle->data = a_state;
1091 g_handle->destroy = samr_Account_destroy;
1093 /* the domain state is in use one more time */
1094 d_state->reference_count++;
1096 *r->out.acct_handle = g_handle->wire_handle;
1098 return NT_STATUS_OK;
1101 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1103 #define QUERY_STRING(msg, field, attr) \
1104 r->out.info->field = samdb_result_string(msg, attr, "");
1105 #define QUERY_UINT(msg, field, attr) \
1106 r->out.info->field = samdb_result_uint(msg, attr, 0);
1107 #define QUERY_RID(msg, field, attr) \
1108 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1109 #define QUERY_NTTIME(msg, field, attr) \
1110 r->out.info->field = samdb_result_nttime(msg, attr, 0);
1111 #define QUERY_APASSC(msg, field, attr) \
1112 r->out.info->field = samdb_result_allow_pwd_change(a_state->sam_ctx, mem_ctx, \
1113 a_state->domain_state->domain_dn, msg, attr);
1114 #define QUERY_FPASSC(msg, field, attr) \
1115 r->out.info->field = samdb_result_force_pwd_change(a_state->sam_ctx, mem_ctx, \
1116 a_state->domain_state->domain_dn, msg, attr);
1117 #define QUERY_LHOURS(msg, field, attr) \
1118 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1119 #define QUERY_AFLAGS(msg, field, attr) \
1120 r->out.info->field = samdb_result_acct_flags(msg, attr);
1123 /* these are used to make the Set[User|Group]Info code easier to follow */
1125 #define SET_STRING(mod, field, attr) do { \
1126 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1127 if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1128 return NT_STATUS_NO_MEMORY; \
1132 #define SET_UINT(mod, field, attr) do { \
1133 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1134 return NT_STATUS_NO_MEMORY; \
1138 #define SET_AFLAGS(msg, field, attr) do { \
1139 if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1140 return NT_STATUS_NO_MEMORY; \
1144 #define SET_LHOURS(msg, field, attr) do { \
1145 if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1146 return NT_STATUS_NO_MEMORY; \
1153 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1154 struct samr_QueryGroupInfo *r)
1156 struct dcesrv_handle *h;
1157 struct samr_account_state *a_state;
1158 struct ldb_message *msg, **res;
1159 const char * const attrs[4] = { "sAMAccountName", "description",
1160 "numMembers", NULL };
1165 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1169 /* pull all the group attributes */
1170 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1171 "dn=%s", a_state->account_dn);
1173 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1177 /* allocate the info structure */
1178 r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1179 if (r->out.info == NULL) {
1180 return NT_STATUS_NO_MEMORY;
1182 ZERO_STRUCTP(r->out.info);
1184 /* Fill in the level */
1185 switch (r->in.level) {
1187 QUERY_STRING(msg, all.name.name, "sAMAccountName");
1188 r->out.info->all.unknown = 7; /* Do like w2k3 */
1189 QUERY_UINT (msg, all.num_members, "numMembers")
1190 QUERY_STRING(msg, all.description.name, "description");
1193 QUERY_STRING(msg, name.name, "sAMAccountName");
1196 r->out.info->unknown.unknown = 7;
1198 case GroupInfoDescription:
1199 QUERY_STRING(msg, description.name, "description");
1203 return NT_STATUS_INVALID_INFO_CLASS;
1206 return NT_STATUS_OK;
1213 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1214 struct samr_SetGroupInfo *r)
1216 struct dcesrv_handle *h;
1217 struct samr_account_state *a_state;
1218 struct ldb_message mod, *msg = &mod;
1221 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1226 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1228 return NT_STATUS_NO_MEMORY;
1231 switch (r->in.level) {
1232 case GroupInfoDescription:
1233 SET_STRING(msg, description.name, "description");
1236 /* On W2k3 this does not change the name, it changes the
1237 * sAMAccountName attribute */
1238 SET_STRING(msg, name.name, "sAMAccountName");
1241 /* This does not do anything obviously visible in W2k3 LDAP */
1244 return NT_STATUS_INVALID_INFO_CLASS;
1247 /* modify the samdb record */
1248 ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
1250 /* we really need samdb.c to return NTSTATUS */
1251 return NT_STATUS_UNSUCCESSFUL;
1254 return NT_STATUS_OK;
1261 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1262 struct samr_AddGroupMember *r)
1264 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1269 samr_DeleteDomainGroup
1271 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1272 struct samr_DeleteDomainGroup *r)
1274 struct dcesrv_handle *h;
1275 struct samr_account_state *a_state;
1278 *r->out.handle = *r->in.handle;
1280 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1284 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1286 return NT_STATUS_UNSUCCESSFUL;
1289 ZERO_STRUCTP(r->out.handle);
1291 return NT_STATUS_OK;
1296 samr_DeleteGroupMember
1298 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1299 struct samr_DeleteGroupMember *r)
1301 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1306 samr_QueryGroupMember
1308 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1309 struct samr_QueryGroupMember *r)
1311 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1316 samr_SetMemberAttributesOfGroup
1318 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1319 struct samr_SetMemberAttributesOfGroup *r)
1321 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1328 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1329 struct samr_OpenAlias *r)
1331 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1338 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1339 struct samr_QueryAliasInfo *r)
1341 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1348 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1349 struct samr_SetAliasInfo *r)
1351 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1358 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1359 struct samr_DeleteDomAlias *r)
1361 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1368 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1369 struct samr_AddAliasMember *r)
1371 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1376 samr_DeleteAliasMember
1378 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1379 struct samr_DeleteAliasMember *r)
1381 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1386 samr_GetMembersInAlias
1388 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1389 struct samr_GetMembersInAlias *r)
1391 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1398 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1399 struct samr_OpenUser *r)
1401 struct samr_domain_state *d_state;
1402 struct samr_account_state *a_state;
1403 struct dcesrv_handle *h;
1404 const char *username, *sidstr;
1405 TALLOC_CTX *mem_ctx2;
1406 struct ldb_message **msgs;
1407 struct dcesrv_handle *u_handle;
1408 const char * const attrs[2] = { "sAMAccountName", NULL };
1411 ZERO_STRUCTP(r->out.acct_handle);
1413 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1417 /* form the users SID */
1418 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1420 return NT_STATUS_NO_MEMORY;
1423 /* search for the user record */
1424 ret = samdb_search(d_state->sam_ctx,
1425 mem_ctx, d_state->domain_dn, &msgs, attrs,
1426 "(&(objectSid=%s)(objectclass=user))",
1429 return NT_STATUS_NO_SUCH_USER;
1432 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
1433 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1436 username = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1437 if (username == NULL) {
1438 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
1439 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1442 /* create user state and new policy handle */
1443 mem_ctx2 = talloc_init("OpenUser(%u)", r->in.rid);
1445 return NT_STATUS_NO_MEMORY;
1448 a_state = talloc_p(mem_ctx2, struct samr_account_state);
1450 return NT_STATUS_NO_MEMORY;
1452 a_state->mem_ctx = mem_ctx2;
1453 a_state->sam_ctx = d_state->sam_ctx;
1454 a_state->access_mask = r->in.access_mask;
1455 a_state->domain_state = d_state;
1456 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1457 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1458 a_state->account_name = talloc_strdup(mem_ctx2, username);
1459 if (!a_state->account_name || !a_state->account_sid) {
1460 return NT_STATUS_NO_MEMORY;
1463 /* create the policy handle */
1464 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1466 return NT_STATUS_NO_MEMORY;
1469 u_handle->data = a_state;
1470 u_handle->destroy = samr_Account_destroy;
1472 /* the domain state is in use one more time */
1473 d_state->reference_count++;
1475 *r->out.acct_handle = u_handle->wire_handle;
1477 return NT_STATUS_OK;
1485 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1486 struct samr_DeleteUser *r)
1488 struct dcesrv_handle *h;
1489 struct samr_account_state *a_state;
1492 *r->out.handle = *r->in.handle;
1494 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1498 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1500 return NT_STATUS_UNSUCCESSFUL;
1503 ZERO_STRUCTP(r->out.handle);
1505 return NT_STATUS_OK;
1512 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1513 struct samr_QueryUserInfo *r)
1515 struct dcesrv_handle *h;
1516 struct samr_account_state *a_state;
1517 struct ldb_message *msg, **res;
1522 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1526 /* pull all the user attributes */
1527 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
1528 "dn=%s", a_state->account_dn);
1530 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1534 /* allocate the info structure */
1535 r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1536 if (r->out.info == NULL) {
1537 return NT_STATUS_NO_MEMORY;
1539 ZERO_STRUCTP(r->out.info);
1541 /* fill in the reply */
1542 switch (r->in.level) {
1544 QUERY_STRING(msg, info1.username.name, "sAMAccountName");
1545 QUERY_STRING(msg, info1.full_name.name, "displayName");
1546 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
1547 QUERY_STRING(msg, info1.description.name, "description");
1548 QUERY_STRING(msg, info1.comment.name, "comment");
1552 QUERY_STRING(msg, info2.comment.name, "comment");
1553 QUERY_UINT (msg, info2.country_code, "countryCode");
1554 QUERY_UINT (msg, info2.code_page, "codePage");
1558 QUERY_STRING(msg, info3.username.name, "sAMAccountName");
1559 QUERY_STRING(msg, info3.full_name.name, "displayName");
1560 QUERY_RID (msg, info3.rid, "objectSid");
1561 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
1562 QUERY_STRING(msg, info3.home_directory.name, "homeDirectory");
1563 QUERY_STRING(msg, info3.home_drive.name, "homeDrive");
1564 QUERY_STRING(msg, info3.logon_script.name, "scriptPath");
1565 QUERY_STRING(msg, info3.profile.name, "profilePath");
1566 QUERY_STRING(msg, info3.workstations.name, "userWorkstations");
1567 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
1568 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
1569 QUERY_NTTIME(msg, info3.last_pwd_change, "pwdLastSet");
1570 QUERY_APASSC(msg, info3.allow_pwd_change, "pwdLastSet");
1571 QUERY_FPASSC(msg, info3.force_pwd_change, "pwdLastSet");
1572 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
1573 QUERY_UINT (msg, info3.bad_pwd_count, "badPwdCount");
1574 QUERY_UINT (msg, info3.num_logons, "logonCount");
1575 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
1579 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
1583 QUERY_STRING(msg, info5.username.name, "sAMAccountName");
1584 QUERY_STRING(msg, info5.full_name.name, "displayName");
1585 QUERY_RID (msg, info5.rid, "objectSid");
1586 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
1587 QUERY_STRING(msg, info5.home_directory.name, "homeDirectory");
1588 QUERY_STRING(msg, info5.home_drive.name, "homeDrive");
1589 QUERY_STRING(msg, info5.logon_script.name, "scriptPath");
1590 QUERY_STRING(msg, info5.profile.name, "profilePath");
1591 QUERY_STRING(msg, info5.description.name, "description");
1592 QUERY_STRING(msg, info5.workstations.name, "userWorkstations");
1593 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
1594 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
1595 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
1596 QUERY_UINT (msg, info5.bad_pwd_count, "badPwdCount");
1597 QUERY_UINT (msg, info5.num_logons, "logonCount");
1598 QUERY_NTTIME(msg, info5.last_pwd_change, "pwdLastSet");
1599 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
1600 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
1604 QUERY_STRING(msg, info6.username.name, "sAMAccountName");
1605 QUERY_STRING(msg, info6.full_name.name, "displayName");
1609 QUERY_STRING(msg, info7.username.name, "sAMAccountName");
1613 QUERY_STRING(msg, info8.full_name.name, "displayName");
1617 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
1621 QUERY_STRING(msg, info10.home_directory.name, "homeDirectory");
1622 QUERY_STRING(msg, info10.home_drive.name, "homeDrive");
1626 QUERY_STRING(msg, info11.logon_script.name, "scriptPath");
1630 QUERY_STRING(msg, info12.profile.name, "profilePath");
1634 QUERY_STRING(msg, info13.description.name, "description");
1638 QUERY_STRING(msg, info14.workstations.name, "userWorkstations");
1642 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1646 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
1649 QUERY_STRING(msg, info20.callback.name, "userParameters");
1653 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
1654 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
1655 QUERY_NTTIME(msg, info21.last_pwd_change, "pwdLastSet");
1656 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
1657 QUERY_APASSC(msg, info21.allow_pwd_change, "pwdLastSet");
1658 QUERY_FPASSC(msg, info21.force_pwd_change, "pwdLastSet");
1659 QUERY_STRING(msg, info21.username.name, "sAMAccountName");
1660 QUERY_STRING(msg, info21.full_name.name, "displayName");
1661 QUERY_STRING(msg, info21.home_directory.name, "homeDirectory");
1662 QUERY_STRING(msg, info21.home_drive.name, "homeDrive");
1663 QUERY_STRING(msg, info21.logon_script.name, "scriptPath");
1664 QUERY_STRING(msg, info21.profile.name, "profilePath");
1665 QUERY_STRING(msg, info21.description.name, "description");
1666 QUERY_STRING(msg, info21.workstations.name, "userWorkstations");
1667 QUERY_STRING(msg, info21.comment.name, "comment");
1668 QUERY_STRING(msg, info21.callback.name, "userParameters");
1669 QUERY_RID (msg, info21.rid, "objectSid");
1670 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
1671 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
1672 r->out.info->info21.fields_present = 0x00FFFFFF;
1673 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
1674 QUERY_UINT (msg, info21.bad_pwd_count, "badPwdCount");
1675 QUERY_UINT (msg, info21.num_logons, "logonCount");
1676 QUERY_UINT (msg, info21.country_code, "countryCode");
1677 QUERY_UINT (msg, info21.code_page, "codePage");
1683 return NT_STATUS_INVALID_INFO_CLASS;
1686 return NT_STATUS_OK;
1693 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1694 struct samr_SetUserInfo *r)
1696 struct dcesrv_handle *h;
1697 struct samr_account_state *a_state;
1698 struct ldb_message mod, *msg = &mod;
1700 NTSTATUS status = NT_STATUS_OK;
1702 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1707 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1709 return NT_STATUS_NO_MEMORY;
1712 switch (r->in.level) {
1714 SET_STRING(msg, info2.comment.name, "comment");
1715 SET_UINT (msg, info2.country_code, "countryCode");
1716 SET_UINT (msg, info2.code_page, "codePage");
1720 SET_LHOURS(msg, info4.logon_hours, "logonHours");
1724 SET_STRING(msg, info6.full_name.name, "displayName");
1728 SET_STRING(msg, info8.full_name.name, "displayName");
1732 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
1736 SET_STRING(msg, info10.home_directory.name, "homeDirectory");
1737 SET_STRING(msg, info10.home_drive.name, "homeDrive");
1741 SET_STRING(msg, info11.logon_script.name, "scriptPath");
1745 SET_STRING(msg, info12.profile.name, "profilePath");
1749 SET_STRING(msg, info13.description.name, "description");
1753 SET_STRING(msg, info14.workstations.name, "userWorkstations");
1757 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1761 SET_STRING(msg, info20.callback.name, "userParameters");
1765 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1766 IFSET(SAMR_FIELD_NAME)
1767 SET_STRING(msg, info21.full_name.name, "displayName");
1768 IFSET(SAMR_FIELD_DESCRIPTION)
1769 SET_STRING(msg, info21.description.name, "description");
1770 IFSET(SAMR_FIELD_COMMENT)
1771 SET_STRING(msg, info21.comment.name, "comment");
1772 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1773 SET_STRING(msg, info21.logon_script.name, "scriptPath");
1774 IFSET(SAMR_FIELD_PROFILE)
1775 SET_STRING(msg, info21.profile.name, "profilePath");
1776 IFSET(SAMR_FIELD_WORKSTATION)
1777 SET_STRING(msg, info21.workstations.name, "userWorkstations");
1778 IFSET(SAMR_FIELD_LOGON_HOURS)
1779 SET_LHOURS(msg, info21.logon_hours, "logonHours");
1780 IFSET(SAMR_FIELD_CALLBACK)
1781 SET_STRING(msg, info21.callback.name, "userParameters");
1782 IFSET(SAMR_FIELD_COUNTRY_CODE)
1783 SET_UINT (msg, info21.country_code, "countryCode");
1784 IFSET(SAMR_FIELD_CODE_PAGE)
1785 SET_UINT (msg, info21.code_page, "codePage");
1790 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
1791 IFSET(SAMR_FIELD_NAME)
1792 SET_STRING(msg, info23.info.full_name.name, "displayName");
1793 IFSET(SAMR_FIELD_DESCRIPTION)
1794 SET_STRING(msg, info23.info.description.name, "description");
1795 IFSET(SAMR_FIELD_COMMENT)
1796 SET_STRING(msg, info23.info.comment.name, "comment");
1797 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1798 SET_STRING(msg, info23.info.logon_script.name, "scriptPath");
1799 IFSET(SAMR_FIELD_PROFILE)
1800 SET_STRING(msg, info23.info.profile.name, "profilePath");
1801 IFSET(SAMR_FIELD_WORKSTATION)
1802 SET_STRING(msg, info23.info.workstations.name, "userWorkstations");
1803 IFSET(SAMR_FIELD_LOGON_HOURS)
1804 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
1805 IFSET(SAMR_FIELD_CALLBACK)
1806 SET_STRING(msg, info23.info.callback.name, "userParameters");
1807 IFSET(SAMR_FIELD_COUNTRY_CODE)
1808 SET_UINT (msg, info23.info.country_code, "countryCode");
1809 IFSET(SAMR_FIELD_CODE_PAGE)
1810 SET_UINT (msg, info23.info.code_page, "codePage");
1811 IFSET(SAMR_FIELD_PASSWORD) {
1812 status = samr_set_password(dce_call,
1814 a_state->account_dn,
1815 a_state->domain_state->domain_dn,
1817 &r->in.info->info23.password);
1822 /* the set password levels are handled separately */
1824 status = samr_set_password(dce_call,
1826 a_state->account_dn,
1827 a_state->domain_state->domain_dn,
1829 &r->in.info->info24.password);
1833 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
1834 IFSET(SAMR_FIELD_NAME)
1835 SET_STRING(msg, info25.info.full_name.name, "displayName");
1836 IFSET(SAMR_FIELD_DESCRIPTION)
1837 SET_STRING(msg, info25.info.description.name, "description");
1838 IFSET(SAMR_FIELD_COMMENT)
1839 SET_STRING(msg, info25.info.comment.name, "comment");
1840 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1841 SET_STRING(msg, info25.info.logon_script.name, "scriptPath");
1842 IFSET(SAMR_FIELD_PROFILE)
1843 SET_STRING(msg, info25.info.profile.name, "profilePath");
1844 IFSET(SAMR_FIELD_WORKSTATION)
1845 SET_STRING(msg, info25.info.workstations.name, "userWorkstations");
1846 IFSET(SAMR_FIELD_LOGON_HOURS)
1847 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
1848 IFSET(SAMR_FIELD_CALLBACK)
1849 SET_STRING(msg, info25.info.callback.name, "userParameters");
1850 IFSET(SAMR_FIELD_COUNTRY_CODE)
1851 SET_UINT (msg, info25.info.country_code, "countryCode");
1852 IFSET(SAMR_FIELD_CODE_PAGE)
1853 SET_UINT (msg, info25.info.code_page, "codePage");
1854 IFSET(SAMR_FIELD_PASSWORD) {
1855 status = samr_set_password_ex(dce_call,
1857 a_state->account_dn,
1858 a_state->domain_state->domain_dn,
1860 &r->in.info->info25.password);
1865 /* the set password levels are handled separately */
1867 status = samr_set_password_ex(dce_call,
1869 a_state->account_dn,
1870 a_state->domain_state->domain_dn,
1872 &r->in.info->info26.password);
1877 /* many info classes are not valid for SetUserInfo */
1878 return NT_STATUS_INVALID_INFO_CLASS;
1881 if (!NT_STATUS_IS_OK(status)) {
1885 /* modify the samdb record */
1886 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1888 /* we really need samdb.c to return NTSTATUS */
1889 return NT_STATUS_UNSUCCESSFUL;
1892 return NT_STATUS_OK;
1897 samr_GetGroupsForUser
1899 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1900 struct samr_GetGroupsForUser *r)
1902 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1907 samr_QueryDisplayInfo
1909 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1910 struct samr_QueryDisplayInfo *r)
1912 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1917 samr_GetDisplayEnumerationIndex
1919 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1920 struct samr_GetDisplayEnumerationIndex *r)
1922 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1927 samr_TestPrivateFunctionsDomain
1929 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1930 struct samr_TestPrivateFunctionsDomain *r)
1932 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1937 samr_TestPrivateFunctionsUser
1939 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1940 struct samr_TestPrivateFunctionsUser *r)
1942 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1949 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1950 struct samr_GetUserPwInfo *r)
1952 struct dcesrv_handle *h;
1953 struct samr_account_state *a_state;
1955 ZERO_STRUCT(r->out.info);
1957 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1961 r->out.info.min_pwd_len = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength",
1962 "dn=%s", a_state->domain_state->domain_dn);
1963 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties",
1964 "dn=%s", a_state->account_dn);
1965 return NT_STATUS_OK;
1970 samr_RemoveMemberFromForeignDomain
1972 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1973 struct samr_RemoveMemberFromForeignDomain *r)
1975 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1980 samr_QueryDomainInfo2
1982 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1983 struct samr_QueryDomainInfo2 *r)
1985 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1992 just an alias for samr_QueryUserInfo
1994 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1995 struct samr_QueryUserInfo2 *r)
1997 struct samr_QueryUserInfo r1;
2000 r1.in.handle = r->in.handle;
2001 r1.in.level = r->in.level;
2003 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
2005 r->out.info = r1.out.info;
2012 samr_QueryDisplayInfo2
2014 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2015 struct samr_QueryDisplayInfo2 *r)
2017 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2022 samr_GetDisplayEnumerationIndex2
2024 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2025 struct samr_GetDisplayEnumerationIndex2 *r)
2027 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2032 samr_QueryDisplayInfo3
2034 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2035 struct samr_QueryDisplayInfo3 *r)
2037 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2042 samr_AddMultipleMembersToAlias
2044 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2045 struct samr_AddMultipleMembersToAlias *r)
2047 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2052 samr_RemoveMultipleMembersFromAlias
2054 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2055 struct samr_RemoveMultipleMembersFromAlias *r)
2057 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2064 this fetches the default password properties for a domain
2066 note that w2k3 completely ignores the domain name in this call, and
2067 always returns the information for the servers primary domain
2069 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2070 struct samr_GetDomPwInfo *r)
2072 struct ldb_message **msgs;
2074 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2077 sam_ctx = samdb_connect();
2078 if (sam_ctx == NULL) {
2079 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2082 ret = samdb_search(sam_ctx,
2083 mem_ctx, NULL, &msgs, attrs,
2084 "(&(name=%s)(objectclass=domain))",
2087 samdb_close(sam_ctx);
2088 return NT_STATUS_NO_SUCH_DOMAIN;
2091 samdb_search_free(sam_ctx, mem_ctx, msgs);
2092 samdb_close(sam_ctx);
2093 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2096 r->out.info.min_pwd_len = samdb_result_uint(msgs[0], "minPwdLength", 0);
2097 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2099 samdb_search_free(sam_ctx, mem_ctx, msgs);
2101 samdb_close(sam_ctx);
2102 return NT_STATUS_OK;
2109 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2110 struct samr_Connect2 *r)
2112 struct samr_Connect c;
2114 c.in.system_name = NULL;
2115 c.in.access_mask = r->in.access_mask;
2116 c.out.handle = r->out.handle;
2118 return samr_Connect(dce_call, mem_ctx, &c);
2125 just an alias for samr_SetUserInfo
2127 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2128 struct samr_SetUserInfo2 *r)
2130 struct samr_SetUserInfo r2;
2132 r2.in.handle = r->in.handle;
2133 r2.in.level = r->in.level;
2134 r2.in.info = r->in.info;
2136 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2141 samr_SetBootKeyInformation
2143 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2144 struct samr_SetBootKeyInformation *r)
2146 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2151 samr_GetBootKeyInformation
2153 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2154 struct samr_GetBootKeyInformation *r)
2156 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2163 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2164 struct samr_Connect3 *r)
2166 struct samr_Connect c;
2168 c.in.system_name = NULL;
2169 c.in.access_mask = r->in.access_mask;
2170 c.out.handle = r->out.handle;
2172 return samr_Connect(dce_call, mem_ctx, &c);
2179 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2180 struct samr_Connect4 *r)
2182 struct samr_Connect c;
2184 c.in.system_name = NULL;
2185 c.in.access_mask = r->in.access_mask;
2186 c.out.handle = r->out.handle;
2188 return samr_Connect(dce_call, mem_ctx, &c);
2195 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2196 struct samr_Connect5 *r)
2198 struct samr_Connect c;
2201 c.in.system_name = NULL;
2202 c.in.access_mask = r->in.access_mask;
2203 c.out.handle = r->out.handle;
2205 status = samr_Connect(dce_call, mem_ctx, &c);
2207 r->out.info->info1.unknown1 = 3;
2208 r->out.info->info1.unknown2 = 0;
2209 r->out.level = r->in.level;
2218 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2219 struct samr_RidToSid *r)
2221 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2226 samr_SetDsrmPassword
2228 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2229 struct samr_SetDsrmPassword *r)
2231 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2236 samr_ValidatePassword
2238 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2239 struct samr_ValidatePassword *r)
2241 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2245 /* include the generated boilerplate */
2246 #include "librpc/gen_ndr/ndr_samr_s.c"