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;
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;
77 destroy connection state
79 static void samr_Connect_close(struct samr_connect_state *state)
81 state->reference_count--;
82 if (state->reference_count == 0) {
83 samdb_close(state->sam_ctx);
84 talloc_destroy(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 *state = h->data;
94 samr_Connect_close(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 *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 state = talloc_p(connect_mem_ctx, struct samr_connect_state);
118 return NT_STATUS_NO_MEMORY;
120 state->mem_ctx = connect_mem_ctx;
122 /* make sure the sam database is accessible */
123 state->sam_ctx = samdb_connect();
124 if (state->sam_ctx == NULL) {
125 talloc_destroy(state->mem_ctx);
126 return NT_STATUS_INVALID_SYSTEM_SERVICE;
129 handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_CONNECT);
131 talloc_destroy(state->mem_ctx);
132 return NT_STATUS_NO_MEMORY;
135 handle->data = state;
136 handle->destroy = samr_Connect_destroy;
138 state->reference_count = 1;
139 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 *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(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 *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(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 *state)
317 state->reference_count--;
318 if (state->reference_count == 0) {
319 samr_Connect_close(state->connect_state);
320 talloc_destroy(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 *state = h->data;
330 samr_Domain_close(conn, 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 *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 state = talloc_p(mem_ctx2, struct samr_domain_state);
383 talloc_destroy(mem_ctx2);
384 return NT_STATUS_NO_MEMORY;
387 state->reference_count = 1;
388 state->connect_state = c_state;
389 state->sam_ctx = c_state->sam_ctx;
390 state->mem_ctx = mem_ctx2;
391 state->domain_sid = talloc_strdup(mem_ctx2, sidstr);
392 state->domain_name = talloc_strdup(mem_ctx2, domain_name);
393 state->basedn = talloc_strdup(mem_ctx2, msgs[0]->dn);
394 if (!state->domain_sid || !state->domain_name || !state->basedn) {
395 talloc_destroy(mem_ctx2);
396 return NT_STATUS_NO_MEMORY;
398 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 = 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 *state = h->data;
440 samr_Domain_close(conn, state->domain_state);
441 talloc_destroy(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 *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->basedn,
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->basedn, "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 state = talloc_p(mem_ctx2, struct samr_account_state);
544 return NT_STATUS_NO_MEMORY;
546 state->mem_ctx = mem_ctx2;
547 state->sam_ctx = d_state->sam_ctx;
548 state->access_mask = r->in.access_mask;
549 state->domain_state = d_state;
550 state->basedn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
551 state->account_sid = talloc_strdup(mem_ctx2, sidstr);
552 state->account_name = talloc_strdup(mem_ctx2, groupname);
553 if (!state->account_name || !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 = 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 *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;
607 ZERO_STRUCTP(r->out.acct_handle);
608 *r->out.access_granted = 0;
611 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
615 username = r->in.username->name;
617 if (username == NULL) {
618 return NT_STATUS_INVALID_PARAMETER;
621 /* check if the user already exists */
622 name = samdb_search_string(d_state->sam_ctx, mem_ctx, d_state->basedn,
624 "(&(sAMAccountName=%s)(objectclass=user))", username);
626 return NT_STATUS_USER_EXISTS;
631 /* pull in all the template attributes */
632 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
633 "(&(name=TemplateUser)(objectclass=userTemplate))");
635 DEBUG(1,("Failed to load TemplateUser from samdb\n"));
636 return NT_STATUS_INTERNAL_DB_CORRUPTION;
640 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
641 d_state->basedn, "nextRid", &rid);
642 if (!NT_STATUS_IS_OK(status)) {
646 /* and the users SID */
647 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
649 return NT_STATUS_NO_MEMORY;
652 /* add core elements to the ldb_message for the user */
653 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", username, d_state->basedn);
655 return NT_STATUS_NO_MEMORY;
657 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", username);
658 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", username);
659 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", username);
660 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
661 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
662 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
663 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
665 /* create the user */
666 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
668 DEBUG(1,("Failed to create user record %s\n", msg.dn));
669 return NT_STATUS_INTERNAL_DB_CORRUPTION;
672 /* create user state and new policy handle */
673 mem_ctx2 = talloc_init("CreateUser(%s)", username);
675 return NT_STATUS_NO_MEMORY;
678 state = talloc_p(mem_ctx2, struct samr_account_state);
680 return NT_STATUS_NO_MEMORY;
682 state->mem_ctx = mem_ctx2;
683 state->sam_ctx = d_state->sam_ctx;
684 state->access_mask = r->in.access_mask;
685 state->domain_state = d_state;
686 state->basedn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
687 state->account_sid = talloc_strdup(mem_ctx2, sidstr);
688 state->account_name = talloc_strdup(mem_ctx2, username);
689 if (!state->account_name || !state->account_sid) {
690 return NT_STATUS_NO_MEMORY;
693 /* create the policy handle */
694 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
696 return NT_STATUS_NO_MEMORY;
699 u_handle->data = state;
700 u_handle->destroy = samr_Account_destroy;
702 /* the domain state is in use one more time */
703 d_state->reference_count++;
705 *r->out.acct_handle = u_handle->wire_handle;
706 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
716 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
717 struct samr_CreateUser *r)
719 struct samr_CreateUser2 r2;
720 uint32 access_granted;
723 /* a simple wrapper around samr_CreateUser2 works nicely */
724 r2.in.handle = r->in.handle;
725 r2.in.username = r->in.username;
726 r2.in.acct_flags = 1234;
727 r2.in.access_mask = r->in.access_mask;
728 r2.out.acct_handle = r->out.acct_handle;
729 r2.out.access_granted = &access_granted;
730 r2.out.rid = r->out.rid;
732 return samr_CreateUser2(dce_call, mem_ctx, &r2);
736 comparison function for sorting SamEntry array
738 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
740 return e1->idx - e2->idx;
746 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
747 struct samr_EnumDomainUsers *r)
749 struct dcesrv_handle *h;
750 struct samr_domain_state *state;
751 struct ldb_message **res;
753 struct samr_SamEntry *entries;
754 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
756 *r->out.resume_handle = 0;
758 r->out.num_entries = 0;
760 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
764 /* search for all users in this domain. This could possibly be cached and
765 resumed based on resume_key */
766 count = samdb_search(state->sam_ctx, mem_ctx, state->basedn, &res, attrs,
769 return NT_STATUS_INTERNAL_DB_CORRUPTION;
771 if (count == 0 || r->in.max_size == 0) {
775 /* convert to SamEntry format */
776 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
778 return NT_STATUS_NO_MEMORY;
780 for (i=0;i<count;i++) {
781 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
782 entries[i].name.name = samdb_result_string(res[i], "sAMAccountName", "");
785 /* sort the results by rid */
786 qsort(entries, count, sizeof(struct samr_SamEntry),
787 (comparison_fn_t)compare_SamEntry);
789 /* find the first entry to return */
791 first<count && entries[first].idx <= *r->in.resume_handle;
794 if (first == count) {
798 /* return the rest, limit by max_size. Note that we
799 use the w2k3 element size value of 54 */
800 r->out.num_entries = count - first;
801 r->out.num_entries = MIN(r->out.num_entries,
802 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
804 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
806 return NT_STATUS_NO_MEMORY;
809 r->out.sam->entries = entries+first;
810 r->out.sam->count = r->out.num_entries;
812 if (r->out.num_entries < count - first) {
813 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
814 return STATUS_MORE_ENTRIES;
824 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
825 struct samr_CreateDomAlias *r)
827 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
832 samr_EnumDomainAliases
834 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
835 struct samr_EnumDomainAliases *r)
837 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
842 samr_GetAliasMembership
844 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
845 struct samr_GetAliasMembership *r)
847 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
854 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
855 struct samr_LookupNames *r)
857 struct dcesrv_handle *h;
858 struct samr_domain_state *state;
860 NTSTATUS status = NT_STATUS_OK;
861 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
864 ZERO_STRUCT(r->out.rids);
865 ZERO_STRUCT(r->out.types);
867 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
871 if (r->in.num_names == 0) {
875 r->out.rids.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names);
876 r->out.types.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names);
877 if (!r->out.rids.ids || !r->out.types.ids) {
878 return NT_STATUS_NO_MEMORY;
880 r->out.rids.count = r->in.num_names;
881 r->out.types.count = r->in.num_names;
883 for (i=0;i<r->in.num_names;i++) {
884 struct ldb_message **res;
885 struct dom_sid2 *sid;
889 r->out.rids.ids[i] = 0;
890 r->out.types.ids[i] = SID_NAME_UNKNOWN;
892 count = samdb_search(state->sam_ctx, mem_ctx, state->basedn, &res, attrs,
893 "sAMAccountName=%s", r->in.names[i].name);
895 status = STATUS_SOME_UNMAPPED;
899 sidstr = samdb_result_string(res[0], "objectSid", NULL);
900 if (sidstr == NULL) {
901 status = STATUS_SOME_UNMAPPED;
905 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
907 status = STATUS_SOME_UNMAPPED;
911 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
913 status = STATUS_SOME_UNMAPPED;
917 switch (atype & 0xF0000000) {
919 rtype = SID_NAME_USER;
921 case ATYPE_GLOBAL_GROUP:
922 rtype = SID_NAME_DOM_GRP;
924 case ATYPE_LOCAL_GROUP:
925 rtype = SID_NAME_ALIAS;
928 DEBUG(1,("Unknown sAMAccountType 0x%08x\n", atype));
929 status = STATUS_SOME_UNMAPPED;
933 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
934 r->out.types.ids[i] = rtype;
945 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
946 struct samr_LookupRids *r)
948 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
955 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
956 struct samr_OpenGroup *r)
958 struct samr_domain_state *d_state;
959 struct samr_account_state *state;
960 struct dcesrv_handle *h;
961 const char *groupname, *sidstr;
962 TALLOC_CTX *mem_ctx2;
963 struct ldb_message **msgs;
964 struct dcesrv_handle *g_handle;
965 const char * const attrs[2] = { "sAMAccountName", NULL };
968 ZERO_STRUCTP(r->out.acct_handle);
970 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
974 /* form the group SID */
975 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
977 return NT_STATUS_NO_MEMORY;
980 /* search for the group record */
981 ret = samdb_search(d_state->sam_ctx,
982 mem_ctx, d_state->basedn, &msgs, attrs,
983 "(&(objectSid=%s)(objectclass=group))",
986 return NT_STATUS_NO_SUCH_GROUP;
989 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
990 return NT_STATUS_INTERNAL_DB_CORRUPTION;
993 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
994 if (groupname == NULL) {
995 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
996 return NT_STATUS_INTERNAL_DB_CORRUPTION;
999 /* create group state and new policy handle */
1000 mem_ctx2 = talloc_init("OpenGroup(%u)", r->in.rid);
1002 return NT_STATUS_NO_MEMORY;
1005 state = talloc_p(mem_ctx2, struct samr_account_state);
1007 return NT_STATUS_NO_MEMORY;
1009 state->mem_ctx = mem_ctx2;
1010 state->sam_ctx = d_state->sam_ctx;
1011 state->access_mask = r->in.access_mask;
1012 state->domain_state = d_state;
1013 state->basedn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1014 state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1015 state->account_name = talloc_strdup(mem_ctx2, groupname);
1016 if (!state->account_name || !state->account_sid) {
1017 return NT_STATUS_NO_MEMORY;
1020 /* create the policy handle */
1021 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1023 return NT_STATUS_NO_MEMORY;
1026 g_handle->data = state;
1027 g_handle->destroy = samr_Account_destroy;
1029 /* the domain state is in use one more time */
1030 d_state->reference_count++;
1032 *r->out.acct_handle = g_handle->wire_handle;
1034 return NT_STATUS_OK;
1037 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1039 #define QUERY_STRING(msg, field, attr) \
1040 r->out.info->field = samdb_result_string(msg, attr, "");
1041 #define QUERY_UINT(msg, field, attr) \
1042 r->out.info->field = samdb_result_uint(msg, attr, 0);
1043 #define QUERY_RID(msg, field, attr) \
1044 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1045 #define QUERY_NTTIME(msg, field, attr) \
1046 r->out.info->field = samdb_result_nttime(msg, attr, 0);
1047 #define QUERY_APASSC(msg, field, attr) \
1048 r->out.info->field = samdb_result_allow_pwd_change(state->sam_ctx, mem_ctx, \
1049 state->domain_state->basedn, msg, attr);
1050 #define QUERY_FPASSC(msg, field, attr) \
1051 r->out.info->field = samdb_result_force_pwd_change(state->sam_ctx, mem_ctx, \
1052 state->domain_state->basedn, msg, attr);
1053 #define QUERY_LHOURS(msg, field, attr) \
1054 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1055 #define QUERY_AFLAGS(msg, field, attr) \
1056 r->out.info->field = samdb_result_acct_flags(msg, attr);
1059 /* these are used to make the Set[User|Group]Info code easier to follow */
1061 #define SET_STRING(mod, field, attr) do { \
1062 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1063 if (samdb_msg_add_string(state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1064 return NT_STATUS_NO_MEMORY; \
1068 #define SET_UINT(mod, field, attr) do { \
1069 if (samdb_msg_add_uint(state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1070 return NT_STATUS_NO_MEMORY; \
1074 #define SET_AFLAGS(msg, field, attr) do { \
1075 if (samdb_msg_add_acct_flags(state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1076 return NT_STATUS_NO_MEMORY; \
1080 #define SET_LHOURS(msg, field, attr) do { \
1081 if (samdb_msg_add_logon_hours(state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1082 return NT_STATUS_NO_MEMORY; \
1089 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1090 struct samr_QueryGroupInfo *r)
1092 struct dcesrv_handle *h;
1093 struct samr_account_state *state;
1094 struct ldb_message *msg, **res;
1095 const char * const attrs[4] = { "sAMAccountName", "description",
1096 "numMembers", NULL };
1101 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1105 /* pull all the group attributes */
1106 ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, attrs,
1107 "dn=%s", state->basedn);
1109 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1113 /* allocate the info structure */
1114 r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1115 if (r->out.info == NULL) {
1116 return NT_STATUS_NO_MEMORY;
1118 ZERO_STRUCTP(r->out.info);
1120 /* Fill in the level */
1121 switch (r->in.level) {
1123 QUERY_STRING(msg, all.name.name, "sAMAccountName");
1124 r->out.info->all.unknown = 7; /* Do like w2k3 */
1125 QUERY_UINT (msg, all.num_members, "numMembers")
1126 QUERY_STRING(msg, all.description.name, "description");
1129 QUERY_STRING(msg, name.name, "sAMAccountName");
1132 r->out.info->unknown.unknown = 7;
1134 case GroupInfoDescription:
1135 QUERY_STRING(msg, description.name, "description");
1139 return NT_STATUS_INVALID_INFO_CLASS;
1142 return NT_STATUS_OK;
1149 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1150 struct samr_SetGroupInfo *r)
1152 struct dcesrv_handle *h;
1153 struct samr_account_state *state;
1154 struct ldb_message mod, *msg = &mod;
1157 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1162 mod.dn = talloc_strdup(mem_ctx, state->basedn);
1164 return NT_STATUS_NO_MEMORY;
1167 switch (r->in.level) {
1168 case GroupInfoDescription:
1169 SET_STRING(msg, description.name, "description");
1172 /* On W2k3 this does not change the name, it changes the
1173 * sAMAccountName attribute */
1174 SET_STRING(msg, name.name, "sAMAccountName");
1177 /* This does not do anything obviously visible in W2k3 LDAP */
1180 return NT_STATUS_INVALID_INFO_CLASS;
1183 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1184 for (i=0;i<mod.num_elements;i++) {
1185 mod.elements[i].flags = LDB_FLAG_MOD_REPLACE;
1188 /* modify the samdb record */
1189 ret = samdb_modify(state->sam_ctx, mem_ctx, &mod);
1191 /* we really need samdb.c to return NTSTATUS */
1192 return NT_STATUS_UNSUCCESSFUL;
1195 return NT_STATUS_OK;
1202 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1203 struct samr_AddGroupMember *r)
1205 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1210 samr_DeleteDomainGroup
1212 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1213 struct samr_DeleteDomainGroup *r)
1215 struct dcesrv_handle *h;
1216 struct samr_account_state *state;
1219 *r->out.handle = *r->in.handle;
1221 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1225 ret = samdb_delete(state->sam_ctx, mem_ctx, state->basedn);
1227 return NT_STATUS_UNSUCCESSFUL;
1230 ZERO_STRUCTP(r->out.handle);
1232 return NT_STATUS_OK;
1237 samr_DeleteGroupMember
1239 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1240 struct samr_DeleteGroupMember *r)
1242 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1247 samr_QueryGroupMember
1249 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1250 struct samr_QueryGroupMember *r)
1252 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1257 samr_SetMemberAttributesOfGroup
1259 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1260 struct samr_SetMemberAttributesOfGroup *r)
1262 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1269 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1270 struct samr_OpenAlias *r)
1272 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1279 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1280 struct samr_QueryAliasInfo *r)
1282 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1289 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1290 struct samr_SetAliasInfo *r)
1292 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1299 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1300 struct samr_DeleteDomAlias *r)
1302 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1309 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1310 struct samr_AddAliasMember *r)
1312 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1317 samr_DeleteAliasMember
1319 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1320 struct samr_DeleteAliasMember *r)
1322 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1327 samr_GetMembersInAlias
1329 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1330 struct samr_GetMembersInAlias *r)
1332 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1339 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1340 struct samr_OpenUser *r)
1342 struct samr_domain_state *d_state;
1343 struct samr_account_state *state;
1344 struct dcesrv_handle *h;
1345 const char *username, *sidstr;
1346 TALLOC_CTX *mem_ctx2;
1347 struct ldb_message **msgs;
1348 struct dcesrv_handle *u_handle;
1349 const char * const attrs[2] = { "sAMAccountName", NULL };
1352 ZERO_STRUCTP(r->out.acct_handle);
1354 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1358 /* form the users SID */
1359 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1361 return NT_STATUS_NO_MEMORY;
1364 /* search for the user record */
1365 ret = samdb_search(d_state->sam_ctx,
1366 mem_ctx, d_state->basedn, &msgs, attrs,
1367 "(&(objectSid=%s)(objectclass=user))",
1370 return NT_STATUS_NO_SUCH_USER;
1373 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
1374 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1377 username = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1378 if (username == NULL) {
1379 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
1380 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1383 /* create user state and new policy handle */
1384 mem_ctx2 = talloc_init("OpenUser(%u)", r->in.rid);
1386 return NT_STATUS_NO_MEMORY;
1389 state = talloc_p(mem_ctx2, struct samr_account_state);
1391 return NT_STATUS_NO_MEMORY;
1393 state->mem_ctx = mem_ctx2;
1394 state->sam_ctx = d_state->sam_ctx;
1395 state->access_mask = r->in.access_mask;
1396 state->domain_state = d_state;
1397 state->basedn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1398 state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1399 state->account_name = talloc_strdup(mem_ctx2, username);
1400 if (!state->account_name || !state->account_sid) {
1401 return NT_STATUS_NO_MEMORY;
1404 /* create the policy handle */
1405 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1407 return NT_STATUS_NO_MEMORY;
1410 u_handle->data = state;
1411 u_handle->destroy = samr_Account_destroy;
1413 /* the domain state is in use one more time */
1414 d_state->reference_count++;
1416 *r->out.acct_handle = u_handle->wire_handle;
1418 return NT_STATUS_OK;
1426 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1427 struct samr_DeleteUser *r)
1429 struct dcesrv_handle *h;
1430 struct samr_account_state *state;
1433 *r->out.handle = *r->in.handle;
1435 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1439 ret = samdb_delete(state->sam_ctx, mem_ctx, state->basedn);
1441 return NT_STATUS_UNSUCCESSFUL;
1444 ZERO_STRUCTP(r->out.handle);
1446 return NT_STATUS_OK;
1453 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1454 struct samr_QueryUserInfo *r)
1456 struct dcesrv_handle *h;
1457 struct samr_account_state *state;
1458 struct ldb_message *msg, **res;
1463 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1467 /* pull all the user attributes */
1468 ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, NULL,
1469 "dn=%s", state->basedn);
1471 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1475 /* allocate the info structure */
1476 r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1477 if (r->out.info == NULL) {
1478 return NT_STATUS_NO_MEMORY;
1480 ZERO_STRUCTP(r->out.info);
1482 /* fill in the reply */
1483 switch (r->in.level) {
1485 QUERY_STRING(msg, info1.username.name, "sAMAccountName");
1486 QUERY_STRING(msg, info1.full_name.name, "displayName");
1487 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
1488 QUERY_STRING(msg, info1.description.name, "description");
1489 QUERY_STRING(msg, info1.comment.name, "comment");
1493 QUERY_STRING(msg, info2.comment.name, "comment");
1494 QUERY_UINT (msg, info2.country_code, "countryCode");
1495 QUERY_UINT (msg, info2.code_page, "codePage");
1499 QUERY_STRING(msg, info3.username.name, "sAMAccountName");
1500 QUERY_STRING(msg, info3.full_name.name, "displayName");
1501 QUERY_RID (msg, info3.rid, "objectSid");
1502 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
1503 QUERY_STRING(msg, info3.home_directory.name, "homeDirectory");
1504 QUERY_STRING(msg, info3.home_drive.name, "homeDrive");
1505 QUERY_STRING(msg, info3.logon_script.name, "scriptPath");
1506 QUERY_STRING(msg, info3.profile.name, "profilePath");
1507 QUERY_STRING(msg, info3.workstations.name, "userWorkstations");
1508 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
1509 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
1510 QUERY_NTTIME(msg, info3.last_pwd_change, "pwdLastSet");
1511 QUERY_APASSC(msg, info3.allow_pwd_change, "pwdLastSet");
1512 QUERY_FPASSC(msg, info3.force_pwd_change, "pwdLastSet");
1513 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
1514 QUERY_UINT (msg, info3.bad_pwd_count, "badPwdCount");
1515 QUERY_UINT (msg, info3.num_logons, "logonCount");
1516 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
1520 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
1524 QUERY_STRING(msg, info5.username.name, "sAMAccountName");
1525 QUERY_STRING(msg, info5.full_name.name, "displayName");
1526 QUERY_RID (msg, info5.rid, "objectSid");
1527 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
1528 QUERY_STRING(msg, info5.home_directory.name, "homeDirectory");
1529 QUERY_STRING(msg, info5.home_drive.name, "homeDrive");
1530 QUERY_STRING(msg, info5.logon_script.name, "scriptPath");
1531 QUERY_STRING(msg, info5.profile.name, "profilePath");
1532 QUERY_STRING(msg, info5.description.name, "description");
1533 QUERY_STRING(msg, info5.workstations.name, "userWorkstations");
1534 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
1535 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
1536 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
1537 QUERY_UINT (msg, info5.bad_pwd_count, "badPwdCount");
1538 QUERY_UINT (msg, info5.num_logons, "logonCount");
1539 QUERY_NTTIME(msg, info5.last_pwd_change, "pwdLastSet");
1540 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
1541 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
1545 QUERY_STRING(msg, info6.username.name, "sAMAccountName");
1546 QUERY_STRING(msg, info6.full_name.name, "displayName");
1550 QUERY_STRING(msg, info7.username.name, "sAMAccountName");
1554 QUERY_STRING(msg, info8.full_name.name, "displayName");
1558 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
1562 QUERY_STRING(msg, info10.home_directory.name, "homeDirectory");
1563 QUERY_STRING(msg, info10.home_drive.name, "homeDrive");
1567 QUERY_STRING(msg, info11.logon_script.name, "scriptPath");
1571 QUERY_STRING(msg, info12.profile.name, "profilePath");
1575 QUERY_STRING(msg, info13.description.name, "description");
1579 QUERY_STRING(msg, info14.workstations.name, "userWorkstations");
1583 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1587 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
1590 QUERY_STRING(msg, info20.callback.name, "userParameters");
1594 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
1595 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
1596 QUERY_NTTIME(msg, info21.last_pwd_change, "pwdLastSet");
1597 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
1598 QUERY_APASSC(msg, info21.allow_pwd_change, "pwdLastSet");
1599 QUERY_FPASSC(msg, info21.force_pwd_change, "pwdLastSet");
1600 QUERY_STRING(msg, info21.username.name, "sAMAccountName");
1601 QUERY_STRING(msg, info21.full_name.name, "displayName");
1602 QUERY_STRING(msg, info21.home_directory.name, "homeDirectory");
1603 QUERY_STRING(msg, info21.home_drive.name, "homeDrive");
1604 QUERY_STRING(msg, info21.logon_script.name, "scriptPath");
1605 QUERY_STRING(msg, info21.profile.name, "profilePath");
1606 QUERY_STRING(msg, info21.description.name, "description");
1607 QUERY_STRING(msg, info21.workstations.name, "userWorkstations");
1608 QUERY_STRING(msg, info21.comment.name, "comment");
1609 QUERY_STRING(msg, info21.callback.name, "userParameters");
1610 QUERY_RID (msg, info21.rid, "objectSid");
1611 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
1612 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
1613 r->out.info->info21.fields_present = 0x00FFFFFF;
1614 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
1615 QUERY_UINT (msg, info21.bad_pwd_count, "badPwdCount");
1616 QUERY_UINT (msg, info21.num_logons, "logonCount");
1617 QUERY_UINT (msg, info21.country_code, "countryCode");
1618 QUERY_UINT (msg, info21.code_page, "codePage");
1624 return NT_STATUS_INVALID_INFO_CLASS;
1627 return NT_STATUS_OK;
1632 set password via a samr_CryptPassword buffer
1633 this will in the 'msg' with modify operations that will update the user
1634 password when applied
1636 static NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
1637 struct samr_account_state *state, TALLOC_CTX *mem_ctx,
1638 struct ldb_message *msg,
1639 struct samr_CryptPassword *pwbuf)
1642 uint32 new_pass_len;
1643 DATA_BLOB session_key = dce_call->conn->session_key;
1645 SamOEMhashBlob(pwbuf->data, 516, &session_key);
1647 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
1648 &new_pass_len, STR_UNICODE)) {
1649 DEBUG(3,("samr: failed to decode password buffer\n"));
1650 return NT_STATUS_WRONG_PASSWORD;
1653 /* set the password - samdb needs to know both the domain and user DNs,
1654 so the domain password policy can be used */
1655 return samdb_set_password(state->sam_ctx, mem_ctx,
1656 state->basedn, state->domain_state->basedn,
1663 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1664 struct samr_SetUserInfo *r)
1666 struct dcesrv_handle *h;
1667 struct samr_account_state *state;
1668 struct ldb_message mod, *msg = &mod;
1670 NTSTATUS status = NT_STATUS_OK;
1672 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1677 mod.dn = talloc_strdup(mem_ctx, state->basedn);
1679 return NT_STATUS_NO_MEMORY;
1682 switch (r->in.level) {
1684 SET_STRING(msg, info2.comment.name, "comment");
1685 SET_UINT (msg, info2.country_code, "countryCode");
1686 SET_UINT (msg, info2.code_page, "codePage");
1690 SET_LHOURS(msg, info4.logon_hours, "logonHours");
1694 SET_STRING(msg, info6.full_name.name, "displayName");
1698 SET_STRING(msg, info8.full_name.name, "displayName");
1702 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
1706 SET_STRING(msg, info10.home_directory.name, "homeDirectory");
1707 SET_STRING(msg, info10.home_drive.name, "homeDrive");
1711 SET_STRING(msg, info11.logon_script.name, "scriptPath");
1715 SET_STRING(msg, info12.profile.name, "profilePath");
1719 SET_STRING(msg, info13.description.name, "description");
1723 SET_STRING(msg, info14.workstations.name, "userWorkstations");
1727 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1731 SET_STRING(msg, info20.callback.name, "userParameters");
1735 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1736 IFSET(SAMR_FIELD_NAME)
1737 SET_STRING(msg, info21.full_name.name, "displayName");
1738 IFSET(SAMR_FIELD_DESCRIPTION)
1739 SET_STRING(msg, info21.description.name, "description");
1740 IFSET(SAMR_FIELD_COMMENT)
1741 SET_STRING(msg, info21.comment.name, "comment");
1742 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1743 SET_STRING(msg, info21.logon_script.name, "scriptPath");
1744 IFSET(SAMR_FIELD_PROFILE)
1745 SET_STRING(msg, info21.profile.name, "profilePath");
1746 IFSET(SAMR_FIELD_WORKSTATION)
1747 SET_STRING(msg, info21.workstations.name, "userWorkstations");
1748 IFSET(SAMR_FIELD_LOGON_HOURS)
1749 SET_LHOURS(msg, info21.logon_hours, "logonHours");
1750 IFSET(SAMR_FIELD_CALLBACK)
1751 SET_STRING(msg, info21.callback.name, "userParameters");
1752 IFSET(SAMR_FIELD_COUNTRY_CODE)
1753 SET_UINT (msg, info21.country_code, "countryCode");
1754 IFSET(SAMR_FIELD_CODE_PAGE)
1755 SET_UINT (msg, info21.code_page, "codePage");
1758 /* the set password levels are handled separately */
1760 status = samr_set_password(dce_call, state, mem_ctx, msg,
1761 &r->in.info->info24.password);
1766 /* many info classes are not valid for SetUserInfo */
1767 return NT_STATUS_INVALID_INFO_CLASS;
1770 if (!NT_STATUS_IS_OK(status)) {
1774 /* mark all the message elements as LDB_FLAG_MOD_REPLACE,
1775 unless they are already marked with some other flag */
1776 for (i=0;i<mod.num_elements;i++) {
1777 if (mod.elements[i].flags == 0) {
1778 mod.elements[i].flags = LDB_FLAG_MOD_REPLACE;
1782 /* modify the samdb record */
1783 ret = samdb_modify(state->sam_ctx, mem_ctx, msg);
1785 /* we really need samdb.c to return NTSTATUS */
1786 return NT_STATUS_UNSUCCESSFUL;
1789 return NT_STATUS_OK;
1794 samr_ChangePasswordUser
1796 static NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1797 struct samr_ChangePasswordUser *r)
1799 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1804 samr_GetGroupsForUser
1806 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1807 struct samr_GetGroupsForUser *r)
1809 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1814 samr_QueryDisplayInfo
1816 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1817 struct samr_QueryDisplayInfo *r)
1819 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1824 samr_GetDisplayEnumerationIndex
1826 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1827 struct samr_GetDisplayEnumerationIndex *r)
1829 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1834 samr_TestPrivateFunctionsDomain
1836 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1837 struct samr_TestPrivateFunctionsDomain *r)
1839 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1844 samr_TestPrivateFunctionsUser
1846 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1847 struct samr_TestPrivateFunctionsUser *r)
1849 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1856 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1857 struct samr_GetUserPwInfo *r)
1859 struct dcesrv_handle *h;
1860 struct samr_account_state *state;
1862 ZERO_STRUCT(r->out.info);
1864 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1868 r->out.info.min_pwd_len = samdb_search_uint(state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength",
1869 "dn=%s", state->domain_state->basedn);
1870 r->out.info.password_properties = samdb_search_uint(state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties",
1871 "dn=%s", state->basedn);
1872 return NT_STATUS_OK;
1877 samr_RemoveMemberFromForeignDomain
1879 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1880 struct samr_RemoveMemberFromForeignDomain *r)
1882 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1887 samr_QueryDomainInfo2
1889 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1890 struct samr_QueryDomainInfo2 *r)
1892 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1899 just an alias for samr_QueryUserInfo
1901 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1902 struct samr_QueryUserInfo2 *r)
1904 struct samr_QueryUserInfo r1;
1907 r1.in.handle = r->in.handle;
1908 r1.in.level = r->in.level;
1910 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
1912 r->out.info = r1.out.info;
1919 samr_QueryDisplayInfo2
1921 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1922 struct samr_QueryDisplayInfo2 *r)
1924 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1929 samr_GetDisplayEnumerationIndex2
1931 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1932 struct samr_GetDisplayEnumerationIndex2 *r)
1934 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1939 samr_QueryDisplayInfo3
1941 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1942 struct samr_QueryDisplayInfo3 *r)
1944 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1949 samr_AddMultipleMembersToAlias
1951 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1952 struct samr_AddMultipleMembersToAlias *r)
1954 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1959 samr_RemoveMultipleMembersFromAlias
1961 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1962 struct samr_RemoveMultipleMembersFromAlias *r)
1964 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1969 samr_OemChangePasswordUser2
1971 static NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1972 struct samr_OemChangePasswordUser2 *r)
1974 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1979 samr_ChangePasswordUser2
1981 static NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1982 struct samr_ChangePasswordUser2 *r)
1984 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1991 this fetches the default password properties for a domain
1993 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1994 struct samr_GetDomPwInfo *r)
1996 struct ldb_message **msgs;
1998 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2001 if (r->in.name == NULL || r->in.name->name == NULL) {
2002 return NT_STATUS_NO_SUCH_DOMAIN;
2005 sam_ctx = samdb_connect();
2006 if (sam_ctx == NULL) {
2007 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2010 ret = samdb_search(sam_ctx,
2011 mem_ctx, NULL, &msgs, attrs,
2012 "(&(name=%s)(objectclass=domain))",
2015 samdb_close(sam_ctx);
2016 return NT_STATUS_NO_SUCH_DOMAIN;
2019 samdb_search_free(sam_ctx, mem_ctx, msgs);
2020 samdb_close(sam_ctx);
2021 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2024 r->out.info.min_pwd_len = samdb_result_uint(msgs[0], "minPwdLength", 0);
2025 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2027 samdb_search_free(sam_ctx, mem_ctx, msgs);
2029 samdb_close(sam_ctx);
2030 return NT_STATUS_OK;
2037 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2038 struct samr_Connect2 *r)
2040 struct samr_Connect c;
2042 c.in.system_name = NULL;
2043 c.in.access_mask = r->in.access_mask;
2044 c.out.handle = r->out.handle;
2046 return samr_Connect(dce_call, mem_ctx, &c);
2053 just an alias for samr_SetUserInfo
2055 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2056 struct samr_SetUserInfo2 *r)
2058 struct samr_SetUserInfo r2;
2060 r2.in.handle = r->in.handle;
2061 r2.in.level = r->in.level;
2062 r2.in.info = r->in.info;
2064 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2069 samr_SetBootKeyInformation
2071 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2072 struct samr_SetBootKeyInformation *r)
2074 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2079 samr_GetBootKeyInformation
2081 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2082 struct samr_GetBootKeyInformation *r)
2084 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2091 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2092 struct samr_Connect3 *r)
2094 struct samr_Connect c;
2096 c.in.system_name = NULL;
2097 c.in.access_mask = r->in.access_mask;
2098 c.out.handle = r->out.handle;
2100 return samr_Connect(dce_call, mem_ctx, &c);
2107 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2108 struct samr_Connect4 *r)
2110 struct samr_Connect c;
2112 c.in.system_name = NULL;
2113 c.in.access_mask = r->in.access_mask;
2114 c.out.handle = r->out.handle;
2116 return samr_Connect(dce_call, mem_ctx, &c);
2121 samr_ChangePasswordUser3
2123 static NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2124 struct samr_ChangePasswordUser3 *r)
2126 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2133 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2134 struct samr_Connect5 *r)
2136 struct samr_Connect c;
2139 c.in.system_name = NULL;
2140 c.in.access_mask = r->in.access_mask;
2141 c.out.handle = r->out.handle;
2143 status = samr_Connect(dce_call, mem_ctx, &c);
2145 r->out.info->info1.unknown1 = 3;
2146 r->out.info->info1.unknown2 = 0;
2147 r->out.level = r->in.level;
2156 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2157 struct samr_RidToSid *r)
2159 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2164 samr_SetDsrmPassword
2166 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2167 struct samr_SetDsrmPassword *r)
2169 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2174 samr_ValidatePassword
2176 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2177 struct samr_ValidatePassword *r)
2179 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2183 /* include the generated boilerplate */
2184 #include "librpc/gen_ndr/ndr_samr_s.c"