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 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
145 we refuse this operation completely. If a admin wants to shutdown samr
146 in Samba then they should use the samba admin tools to disable the samr pipe
148 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
149 struct samr_Shutdown *r)
151 return NT_STATUS_ACCESS_DENIED;
158 this maps from a domain name to a SID
160 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
161 struct samr_LookupDomain *r)
163 struct samr_connect_state *c_state;
164 struct dcesrv_handle *h;
165 struct dom_sid2 *sid;
170 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
174 if (r->in.domain->name == NULL) {
175 return NT_STATUS_INVALID_PARAMETER;
178 sidstr = samdb_search_string(c_state->sam_ctx,
179 mem_ctx, NULL, "objectSid",
180 "(&(name=%s)(objectclass=domain))",
182 if (sidstr == NULL) {
183 return NT_STATUS_NO_SUCH_DOMAIN;
186 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
188 DEBUG(1,("samdb: Invalid sid '%s' for domain %s\n",
189 sidstr, r->in.domain->name));
190 return NT_STATUS_INTERNAL_DB_CORRUPTION;
202 list the domains in the SAM
204 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
205 struct samr_EnumDomains *r)
207 struct samr_connect_state *c_state;
208 struct dcesrv_handle *h;
209 struct samr_SamArray *array;
210 const char **domains;
211 int count, i, start_i;
213 *r->out.resume_handle = 0;
215 r->out.num_entries = 0;
217 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
221 count = samdb_search_string_multiple(c_state->sam_ctx,
222 mem_ctx, NULL, &domains,
223 "name", "(objectclass=domain)");
225 DEBUG(1,("samdb: no domains found in EnumDomains\n"));
226 return NT_STATUS_INTERNAL_DB_CORRUPTION;
229 *r->out.resume_handle = count;
231 start_i = *r->in.resume_handle;
233 if (start_i >= count) {
234 /* search past end of list is not an error for this call */
238 array = talloc_p(mem_ctx, struct samr_SamArray);
240 return NT_STATUS_NO_MEMORY;
244 array->entries = NULL;
246 array->entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count - start_i);
247 if (array->entries == NULL) {
248 return NT_STATUS_NO_MEMORY;
251 for (i=0;i<count-start_i;i++) {
252 array->entries[i].idx = start_i + i;
253 array->entries[i].name.name = domains[start_i+i];
257 r->out.num_entries = i;
258 array->count = r->out.num_entries;
265 close an open domain context
267 static void samr_Domain_close(struct dcesrv_connection *conn,
268 struct samr_domain_state *d_state)
270 d_state->reference_count--;
271 if (d_state->reference_count == 0) {
272 samr_Connect_close(d_state->connect_state);
273 talloc_destroy(d_state->mem_ctx);
278 destroy an open domain context
280 static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
282 struct samr_domain_state *d_state = h->data;
283 samr_Domain_close(conn, d_state);
289 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
290 struct samr_OpenDomain *r)
292 struct dcesrv_handle *h_conn, *h_domain;
293 const char *sidstr, *domain_name;
294 struct samr_connect_state *c_state;
295 struct samr_domain_state *d_state;
296 TALLOC_CTX *mem_ctx2;
297 const char * const attrs[2] = { "name", NULL};
298 struct ldb_message **msgs;
301 ZERO_STRUCTP(r->out.domain_handle);
303 DCESRV_PULL_HANDLE(h_conn, r->in.handle, SAMR_HANDLE_CONNECT);
305 c_state = h_conn->data;
307 if (r->in.sid == NULL) {
308 return NT_STATUS_INVALID_PARAMETER;
311 sidstr = dom_sid_string(mem_ctx, r->in.sid);
312 if (sidstr == NULL) {
313 return NT_STATUS_INVALID_PARAMETER;
316 ret = samdb_search(c_state->sam_ctx,
317 mem_ctx, NULL, &msgs, attrs,
318 "(&(objectSid=%s)(objectclass=domain))",
321 return NT_STATUS_NO_SUCH_DOMAIN;
324 domain_name = ldb_msg_find_string(msgs[0], "name", NULL);
325 if (domain_name == NULL) {
326 return NT_STATUS_NO_SUCH_DOMAIN;
329 mem_ctx2 = talloc_init("OpenDomain(%s)\n", domain_name);
331 return NT_STATUS_NO_MEMORY;
334 d_state = talloc_p(mem_ctx2, struct samr_domain_state);
336 talloc_destroy(mem_ctx2);
337 return NT_STATUS_NO_MEMORY;
340 d_state->reference_count = 1;
341 d_state->connect_state = c_state;
342 d_state->sam_ctx = c_state->sam_ctx;
343 d_state->mem_ctx = mem_ctx2;
344 d_state->domain_sid = talloc_strdup(mem_ctx2, sidstr);
345 d_state->domain_name = talloc_strdup(mem_ctx2, domain_name);
346 d_state->domain_dn = talloc_strdup(mem_ctx2, msgs[0]->dn);
347 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
348 talloc_destroy(mem_ctx2);
349 return NT_STATUS_NO_MEMORY;
351 d_state->access_mask = r->in.access_mask;
353 h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN);
355 talloc_destroy(mem_ctx2);
356 return NT_STATUS_NO_MEMORY;
359 c_state->reference_count++;
360 h_domain->data = d_state;
361 h_domain->destroy = samr_Domain_destroy;
362 *r->out.domain_handle = h_domain->wire_handle;
371 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
372 struct samr_QueryDomainInfo *r)
374 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
381 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
382 struct samr_SetDomainInfo *r)
384 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
388 destroy an open account context
390 static void samr_Account_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
392 struct samr_account_state *a_state = h->data;
393 samr_Domain_close(conn, a_state->domain_state);
394 talloc_destroy(a_state->mem_ctx);
398 samr_CreateDomainGroup
400 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
401 struct samr_CreateDomainGroup *r)
403 struct samr_domain_state *d_state;
404 struct samr_account_state *a_state;
405 struct dcesrv_handle *h;
407 struct ldb_message msg;
409 const char *groupname, *sidstr;
410 time_t now = time(NULL);
411 TALLOC_CTX *mem_ctx2;
412 struct dcesrv_handle *g_handle;
416 ZERO_STRUCTP(r->out.group_handle);
419 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
423 groupname = r->in.name->name;
425 if (groupname == NULL) {
426 return NT_STATUS_INVALID_PARAMETER;
429 /* check if the group already exists */
430 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
432 "(&(sAMAccountName=%s)(objectclass=group))",
435 return NT_STATUS_GROUP_EXISTS;
440 /* pull in all the template attributes */
441 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
442 "(&(name=TemplateGroup)(objectclass=groupTemplate))");
444 DEBUG(1,("Failed to load TemplateGroup from samdb\n"));
445 return NT_STATUS_INTERNAL_DB_CORRUPTION;
449 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
450 d_state->domain_dn, "nextRid", &rid);
451 if (!NT_STATUS_IS_OK(status)) {
455 /* and the group SID */
456 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
458 return NT_STATUS_NO_MEMORY;
461 /* add core elements to the ldb_message for the user */
462 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", groupname,
465 return NT_STATUS_NO_MEMORY;
467 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
469 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
471 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
472 "sAMAccountName", groupname);
473 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
474 "objectClass", "group");
475 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
476 "objectSid", sidstr);
477 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
479 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
482 /* create the group */
483 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
485 DEBUG(1,("Failed to create group record %s\n", msg.dn));
486 return NT_STATUS_INTERNAL_DB_CORRUPTION;
489 /* create group state and new policy handle */
490 mem_ctx2 = talloc_init("CreateDomainGroup(%s)", groupname);
492 return NT_STATUS_NO_MEMORY;
495 a_state = talloc_p(mem_ctx2, struct samr_account_state);
497 return NT_STATUS_NO_MEMORY;
499 a_state->mem_ctx = mem_ctx2;
500 a_state->sam_ctx = d_state->sam_ctx;
501 a_state->access_mask = r->in.access_mask;
502 a_state->domain_state = d_state;
503 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
504 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
505 a_state->account_name = talloc_strdup(mem_ctx2, groupname);
506 if (!a_state->account_name || !a_state->account_sid) {
507 return NT_STATUS_NO_MEMORY;
510 /* create the policy handle */
511 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
513 return NT_STATUS_NO_MEMORY;
516 g_handle->data = a_state;
517 g_handle->destroy = samr_Account_destroy;
519 /* the domain state is in use one more time */
520 d_state->reference_count++;
522 *r->out.group_handle = g_handle->wire_handle;
530 samr_EnumDomainGroups
532 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
533 struct samr_EnumDomainGroups *r)
535 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
542 TODO: This should do some form of locking, especially around the rid allocation
544 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
545 struct samr_CreateUser2 *r)
547 struct samr_domain_state *d_state;
548 struct samr_account_state *a_state;
549 struct dcesrv_handle *h;
551 struct ldb_message msg;
553 const char *username, *sidstr;
554 time_t now = time(NULL);
555 TALLOC_CTX *mem_ctx2;
556 struct dcesrv_handle *u_handle;
559 const char *container, *additional_class=NULL;
561 ZERO_STRUCTP(r->out.acct_handle);
562 *r->out.access_granted = 0;
565 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
569 username = r->in.username->name;
571 if (username == NULL) {
572 return NT_STATUS_INVALID_PARAMETER;
575 /* check if the user already exists */
576 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
578 "(&(sAMAccountName=%s)(objectclass=user))", username);
580 return NT_STATUS_USER_EXISTS;
585 /* This must be one of these values *only* */
586 if (r->in.acct_flags == ACB_NORMAL) {
587 /* pull in all the template attributes */
588 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
589 "(&(name=TemplateUser)(objectclass=userTemplate))");
591 DEBUG(1,("Failed to load TemplateUser from samdb\n"));
592 return NT_STATUS_INTERNAL_DB_CORRUPTION;
597 } else if (r->in.acct_flags == ACB_WSTRUST) {
598 /* pull in all the template attributes */
599 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
600 "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
602 DEBUG(1,("Failed to load TemplateMemberServer from samdb\n"));
603 return NT_STATUS_INTERNAL_DB_CORRUPTION;
606 container = "Computers";
607 additional_class = "computer";
609 } else if (r->in.acct_flags == ACB_SVRTRUST) {
610 /* pull in all the template attributes */
611 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
612 "(&(name=TemplateDomainController)(objectclass=userTemplate))");
614 DEBUG(1,("Failed to load TemplateDomainController from samdb\n"));
615 return NT_STATUS_INTERNAL_DB_CORRUPTION;
618 container = "DomainControllers";
619 additional_class = "computer";
621 } else if (r->in.acct_flags == ACB_DOMTRUST) {
622 /* pull in all the template attributes */
623 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg,
624 "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
626 DEBUG(1,("Failed to load TemplateTrustingDomain from samdb\n"));
627 return NT_STATUS_INTERNAL_DB_CORRUPTION;
630 container = "ForeignDomains"; /* FIXME: Is this correct?*/
631 additional_class = "computer";
634 return NT_STATUS_INVALID_PARAMETER;
638 status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx,
639 d_state->domain_dn, "nextRid", &rid);
640 if (!NT_STATUS_IS_OK(status)) {
644 /* and the users SID */
645 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
647 return NT_STATUS_NO_MEMORY;
650 /* add core elements to the ldb_message for the user */
651 msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", username, container, d_state->domain_dn);
653 return NT_STATUS_NO_MEMORY;
655 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", username);
656 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", username);
657 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", username);
658 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
659 if (additional_class) {
660 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class);
662 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
663 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
664 samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
666 /* create the user */
667 ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
669 DEBUG(1,("Failed to create user record %s\n", msg.dn));
670 return NT_STATUS_INTERNAL_DB_CORRUPTION;
673 /* create user state and new policy handle */
674 mem_ctx2 = talloc_init("CreateUser(%s)", username);
676 return NT_STATUS_NO_MEMORY;
679 a_state = talloc_p(mem_ctx2, struct samr_account_state);
681 return NT_STATUS_NO_MEMORY;
683 a_state->mem_ctx = mem_ctx2;
684 a_state->sam_ctx = d_state->sam_ctx;
685 a_state->access_mask = r->in.access_mask;
686 a_state->domain_state = d_state;
687 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
688 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
689 a_state->account_name = talloc_strdup(mem_ctx2, username);
690 if (!a_state->account_name || !a_state->account_sid) {
691 return NT_STATUS_NO_MEMORY;
694 /* create the policy handle */
695 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
697 return NT_STATUS_NO_MEMORY;
700 u_handle->data = a_state;
701 u_handle->destroy = samr_Account_destroy;
703 /* the domain state is in use one more time */
704 d_state->reference_count++;
706 *r->out.acct_handle = u_handle->wire_handle;
707 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
717 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
718 struct samr_CreateUser *r)
720 struct samr_CreateUser2 r2;
721 uint32_t access_granted;
724 /* a simple wrapper around samr_CreateUser2 works nicely */
725 r2.in.handle = r->in.handle;
726 r2.in.username = r->in.username;
727 r2.in.acct_flags = ACB_NORMAL;
728 r2.in.access_mask = r->in.access_mask;
729 r2.out.acct_handle = r->out.acct_handle;
730 r2.out.access_granted = &access_granted;
731 r2.out.rid = r->out.rid;
733 return samr_CreateUser2(dce_call, mem_ctx, &r2);
737 comparison function for sorting SamEntry array
739 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
741 return e1->idx - e2->idx;
747 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
748 struct samr_EnumDomainUsers *r)
750 struct dcesrv_handle *h;
751 struct samr_domain_state *d_state;
752 struct ldb_message **res;
754 struct samr_SamEntry *entries;
755 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
757 *r->out.resume_handle = 0;
759 r->out.num_entries = 0;
761 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
765 /* search for all users in this domain. This could possibly be cached and
766 resumed based on resume_key */
767 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
770 return NT_STATUS_INTERNAL_DB_CORRUPTION;
772 if (count == 0 || r->in.max_size == 0) {
776 /* convert to SamEntry format */
777 entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
779 return NT_STATUS_NO_MEMORY;
781 for (i=0;i<count;i++) {
782 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
783 entries[i].name.name = samdb_result_string(res[i], "sAMAccountName", "");
786 /* sort the results by rid */
787 qsort(entries, count, sizeof(struct samr_SamEntry),
788 (comparison_fn_t)compare_SamEntry);
790 /* find the first entry to return */
792 first<count && entries[first].idx <= *r->in.resume_handle;
795 if (first == count) {
799 /* return the rest, limit by max_size. Note that we
800 use the w2k3 element size value of 54 */
801 r->out.num_entries = count - first;
802 r->out.num_entries = MIN(r->out.num_entries,
803 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
805 r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
807 return NT_STATUS_NO_MEMORY;
810 r->out.sam->entries = entries+first;
811 r->out.sam->count = r->out.num_entries;
813 if (r->out.num_entries < count - first) {
814 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
815 return STATUS_MORE_ENTRIES;
825 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
826 struct samr_CreateDomAlias *r)
828 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
833 samr_EnumDomainAliases
835 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
836 struct samr_EnumDomainAliases *r)
838 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
843 samr_GetAliasMembership
845 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
846 struct samr_GetAliasMembership *r)
848 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
855 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
856 struct samr_LookupNames *r)
858 struct dcesrv_handle *h;
859 struct samr_domain_state *d_state;
861 NTSTATUS status = NT_STATUS_OK;
862 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
865 ZERO_STRUCT(r->out.rids);
866 ZERO_STRUCT(r->out.types);
868 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
872 if (r->in.num_names == 0) {
876 r->out.rids.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
877 r->out.types.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
878 if (!r->out.rids.ids || !r->out.types.ids) {
879 return NT_STATUS_NO_MEMORY;
881 r->out.rids.count = r->in.num_names;
882 r->out.types.count = r->in.num_names;
884 for (i=0;i<r->in.num_names;i++) {
885 struct ldb_message **res;
886 struct dom_sid2 *sid;
888 uint32_t atype, rtype;
890 r->out.rids.ids[i] = 0;
891 r->out.types.ids[i] = SID_NAME_UNKNOWN;
893 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
894 "sAMAccountName=%s", r->in.names[i].name);
896 status = STATUS_SOME_UNMAPPED;
900 sidstr = samdb_result_string(res[0], "objectSid", NULL);
901 if (sidstr == NULL) {
902 status = STATUS_SOME_UNMAPPED;
906 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
908 status = STATUS_SOME_UNMAPPED;
912 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
914 status = STATUS_SOME_UNMAPPED;
918 rtype = samdb_atype_map(atype);
920 if (rtype == SID_NAME_UNKNOWN) {
921 status = STATUS_SOME_UNMAPPED;
925 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
926 r->out.types.ids[i] = rtype;
937 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
938 struct samr_LookupRids *r)
940 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
947 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
948 struct samr_OpenGroup *r)
950 struct samr_domain_state *d_state;
951 struct samr_account_state *a_state;
952 struct dcesrv_handle *h;
953 const char *groupname, *sidstr;
954 TALLOC_CTX *mem_ctx2;
955 struct ldb_message **msgs;
956 struct dcesrv_handle *g_handle;
957 const char * const attrs[2] = { "sAMAccountName", NULL };
960 ZERO_STRUCTP(r->out.acct_handle);
962 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
966 /* form the group SID */
967 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
969 return NT_STATUS_NO_MEMORY;
972 /* search for the group record */
973 ret = samdb_search(d_state->sam_ctx,
974 mem_ctx, d_state->domain_dn, &msgs, attrs,
975 "(&(objectSid=%s)(objectclass=group))",
978 return NT_STATUS_NO_SUCH_GROUP;
981 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
982 return NT_STATUS_INTERNAL_DB_CORRUPTION;
985 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
986 if (groupname == NULL) {
987 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
988 return NT_STATUS_INTERNAL_DB_CORRUPTION;
991 /* create group state and new policy handle */
992 mem_ctx2 = talloc_init("OpenGroup(%u)", r->in.rid);
994 return NT_STATUS_NO_MEMORY;
997 a_state = talloc_p(mem_ctx2, struct samr_account_state);
999 return NT_STATUS_NO_MEMORY;
1001 a_state->mem_ctx = mem_ctx2;
1002 a_state->sam_ctx = d_state->sam_ctx;
1003 a_state->access_mask = r->in.access_mask;
1004 a_state->domain_state = d_state;
1005 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1006 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1007 a_state->account_name = talloc_strdup(mem_ctx2, groupname);
1008 if (!a_state->account_name || !a_state->account_sid) {
1009 return NT_STATUS_NO_MEMORY;
1012 /* create the policy handle */
1013 g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1015 return NT_STATUS_NO_MEMORY;
1018 g_handle->data = a_state;
1019 g_handle->destroy = samr_Account_destroy;
1021 /* the domain state is in use one more time */
1022 d_state->reference_count++;
1024 *r->out.acct_handle = g_handle->wire_handle;
1026 return NT_STATUS_OK;
1029 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1031 #define QUERY_STRING(msg, field, attr) \
1032 r->out.info->field = samdb_result_string(msg, attr, "");
1033 #define QUERY_UINT(msg, field, attr) \
1034 r->out.info->field = samdb_result_uint(msg, attr, 0);
1035 #define QUERY_RID(msg, field, attr) \
1036 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1037 #define QUERY_NTTIME(msg, field, attr) \
1038 r->out.info->field = samdb_result_nttime(msg, attr, 0);
1039 #define QUERY_APASSC(msg, field, attr) \
1040 r->out.info->field = samdb_result_allow_pwd_change(a_state->sam_ctx, mem_ctx, \
1041 a_state->domain_state->domain_dn, msg, attr);
1042 #define QUERY_FPASSC(msg, field, attr) \
1043 r->out.info->field = samdb_result_force_pwd_change(a_state->sam_ctx, mem_ctx, \
1044 a_state->domain_state->domain_dn, msg, attr);
1045 #define QUERY_LHOURS(msg, field, attr) \
1046 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1047 #define QUERY_AFLAGS(msg, field, attr) \
1048 r->out.info->field = samdb_result_acct_flags(msg, attr);
1051 /* these are used to make the Set[User|Group]Info code easier to follow */
1053 #define SET_STRING(mod, field, attr) do { \
1054 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1055 if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1056 return NT_STATUS_NO_MEMORY; \
1060 #define SET_UINT(mod, field, attr) do { \
1061 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1062 return NT_STATUS_NO_MEMORY; \
1066 #define SET_AFLAGS(msg, field, attr) do { \
1067 if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1068 return NT_STATUS_NO_MEMORY; \
1072 #define SET_LHOURS(msg, field, attr) do { \
1073 if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1074 return NT_STATUS_NO_MEMORY; \
1081 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1082 struct samr_QueryGroupInfo *r)
1084 struct dcesrv_handle *h;
1085 struct samr_account_state *a_state;
1086 struct ldb_message *msg, **res;
1087 const char * const attrs[4] = { "sAMAccountName", "description",
1088 "numMembers", NULL };
1093 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1097 /* pull all the group attributes */
1098 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1099 "dn=%s", a_state->account_dn);
1101 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1105 /* allocate the info structure */
1106 r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1107 if (r->out.info == NULL) {
1108 return NT_STATUS_NO_MEMORY;
1110 ZERO_STRUCTP(r->out.info);
1112 /* Fill in the level */
1113 switch (r->in.level) {
1115 QUERY_STRING(msg, all.name.name, "sAMAccountName");
1116 r->out.info->all.unknown = 7; /* Do like w2k3 */
1117 QUERY_UINT (msg, all.num_members, "numMembers")
1118 QUERY_STRING(msg, all.description.name, "description");
1121 QUERY_STRING(msg, name.name, "sAMAccountName");
1124 r->out.info->unknown.unknown = 7;
1126 case GroupInfoDescription:
1127 QUERY_STRING(msg, description.name, "description");
1131 return NT_STATUS_INVALID_INFO_CLASS;
1134 return NT_STATUS_OK;
1141 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1142 struct samr_SetGroupInfo *r)
1144 struct dcesrv_handle *h;
1145 struct samr_account_state *a_state;
1146 struct ldb_message mod, *msg = &mod;
1149 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1154 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1156 return NT_STATUS_NO_MEMORY;
1159 switch (r->in.level) {
1160 case GroupInfoDescription:
1161 SET_STRING(msg, description.name, "description");
1164 /* On W2k3 this does not change the name, it changes the
1165 * sAMAccountName attribute */
1166 SET_STRING(msg, name.name, "sAMAccountName");
1169 /* This does not do anything obviously visible in W2k3 LDAP */
1172 return NT_STATUS_INVALID_INFO_CLASS;
1175 /* modify the samdb record */
1176 ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
1178 /* we really need samdb.c to return NTSTATUS */
1179 return NT_STATUS_UNSUCCESSFUL;
1182 return NT_STATUS_OK;
1189 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1190 struct samr_AddGroupMember *r)
1192 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1197 samr_DeleteDomainGroup
1199 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1200 struct samr_DeleteDomainGroup *r)
1202 struct dcesrv_handle *h;
1203 struct samr_account_state *a_state;
1206 *r->out.handle = *r->in.handle;
1208 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1212 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1214 return NT_STATUS_UNSUCCESSFUL;
1217 ZERO_STRUCTP(r->out.handle);
1219 return NT_STATUS_OK;
1224 samr_DeleteGroupMember
1226 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1227 struct samr_DeleteGroupMember *r)
1229 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1234 samr_QueryGroupMember
1236 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1237 struct samr_QueryGroupMember *r)
1239 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1244 samr_SetMemberAttributesOfGroup
1246 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1247 struct samr_SetMemberAttributesOfGroup *r)
1249 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1256 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1257 struct samr_OpenAlias *r)
1259 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1266 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1267 struct samr_QueryAliasInfo *r)
1269 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1276 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1277 struct samr_SetAliasInfo *r)
1279 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1286 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1287 struct samr_DeleteDomAlias *r)
1289 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1296 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1297 struct samr_AddAliasMember *r)
1299 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1304 samr_DeleteAliasMember
1306 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1307 struct samr_DeleteAliasMember *r)
1309 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1314 samr_GetMembersInAlias
1316 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1317 struct samr_GetMembersInAlias *r)
1319 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1326 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1327 struct samr_OpenUser *r)
1329 struct samr_domain_state *d_state;
1330 struct samr_account_state *a_state;
1331 struct dcesrv_handle *h;
1332 const char *username, *sidstr;
1333 TALLOC_CTX *mem_ctx2;
1334 struct ldb_message **msgs;
1335 struct dcesrv_handle *u_handle;
1336 const char * const attrs[2] = { "sAMAccountName", NULL };
1339 ZERO_STRUCTP(r->out.acct_handle);
1341 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1345 /* form the users SID */
1346 sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1348 return NT_STATUS_NO_MEMORY;
1351 /* search for the user record */
1352 ret = samdb_search(d_state->sam_ctx,
1353 mem_ctx, d_state->domain_dn, &msgs, attrs,
1354 "(&(objectSid=%s)(objectclass=user))",
1357 return NT_STATUS_NO_SUCH_USER;
1360 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
1361 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1364 username = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1365 if (username == NULL) {
1366 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
1367 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1370 /* create user state and new policy handle */
1371 mem_ctx2 = talloc_init("OpenUser(%u)", r->in.rid);
1373 return NT_STATUS_NO_MEMORY;
1376 a_state = talloc_p(mem_ctx2, struct samr_account_state);
1378 return NT_STATUS_NO_MEMORY;
1380 a_state->mem_ctx = mem_ctx2;
1381 a_state->sam_ctx = d_state->sam_ctx;
1382 a_state->access_mask = r->in.access_mask;
1383 a_state->domain_state = d_state;
1384 a_state->account_dn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1385 a_state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1386 a_state->account_name = talloc_strdup(mem_ctx2, username);
1387 if (!a_state->account_name || !a_state->account_sid) {
1388 return NT_STATUS_NO_MEMORY;
1391 /* create the policy handle */
1392 u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1394 return NT_STATUS_NO_MEMORY;
1397 u_handle->data = a_state;
1398 u_handle->destroy = samr_Account_destroy;
1400 /* the domain state is in use one more time */
1401 d_state->reference_count++;
1403 *r->out.acct_handle = u_handle->wire_handle;
1405 return NT_STATUS_OK;
1413 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1414 struct samr_DeleteUser *r)
1416 struct dcesrv_handle *h;
1417 struct samr_account_state *a_state;
1420 *r->out.handle = *r->in.handle;
1422 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1426 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1428 return NT_STATUS_UNSUCCESSFUL;
1431 ZERO_STRUCTP(r->out.handle);
1433 return NT_STATUS_OK;
1440 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1441 struct samr_QueryUserInfo *r)
1443 struct dcesrv_handle *h;
1444 struct samr_account_state *a_state;
1445 struct ldb_message *msg, **res;
1450 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1454 /* pull all the user attributes */
1455 ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
1456 "dn=%s", a_state->account_dn);
1458 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1462 /* allocate the info structure */
1463 r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1464 if (r->out.info == NULL) {
1465 return NT_STATUS_NO_MEMORY;
1467 ZERO_STRUCTP(r->out.info);
1469 /* fill in the reply */
1470 switch (r->in.level) {
1472 QUERY_STRING(msg, info1.username.name, "sAMAccountName");
1473 QUERY_STRING(msg, info1.full_name.name, "displayName");
1474 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
1475 QUERY_STRING(msg, info1.description.name, "description");
1476 QUERY_STRING(msg, info1.comment.name, "comment");
1480 QUERY_STRING(msg, info2.comment.name, "comment");
1481 QUERY_UINT (msg, info2.country_code, "countryCode");
1482 QUERY_UINT (msg, info2.code_page, "codePage");
1486 QUERY_STRING(msg, info3.username.name, "sAMAccountName");
1487 QUERY_STRING(msg, info3.full_name.name, "displayName");
1488 QUERY_RID (msg, info3.rid, "objectSid");
1489 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
1490 QUERY_STRING(msg, info3.home_directory.name, "homeDirectory");
1491 QUERY_STRING(msg, info3.home_drive.name, "homeDrive");
1492 QUERY_STRING(msg, info3.logon_script.name, "scriptPath");
1493 QUERY_STRING(msg, info3.profile.name, "profilePath");
1494 QUERY_STRING(msg, info3.workstations.name, "userWorkstations");
1495 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
1496 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
1497 QUERY_NTTIME(msg, info3.last_pwd_change, "pwdLastSet");
1498 QUERY_APASSC(msg, info3.allow_pwd_change, "pwdLastSet");
1499 QUERY_FPASSC(msg, info3.force_pwd_change, "pwdLastSet");
1500 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
1501 QUERY_UINT (msg, info3.bad_pwd_count, "badPwdCount");
1502 QUERY_UINT (msg, info3.num_logons, "logonCount");
1503 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
1507 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
1511 QUERY_STRING(msg, info5.username.name, "sAMAccountName");
1512 QUERY_STRING(msg, info5.full_name.name, "displayName");
1513 QUERY_RID (msg, info5.rid, "objectSid");
1514 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
1515 QUERY_STRING(msg, info5.home_directory.name, "homeDirectory");
1516 QUERY_STRING(msg, info5.home_drive.name, "homeDrive");
1517 QUERY_STRING(msg, info5.logon_script.name, "scriptPath");
1518 QUERY_STRING(msg, info5.profile.name, "profilePath");
1519 QUERY_STRING(msg, info5.description.name, "description");
1520 QUERY_STRING(msg, info5.workstations.name, "userWorkstations");
1521 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
1522 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
1523 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
1524 QUERY_UINT (msg, info5.bad_pwd_count, "badPwdCount");
1525 QUERY_UINT (msg, info5.num_logons, "logonCount");
1526 QUERY_NTTIME(msg, info5.last_pwd_change, "pwdLastSet");
1527 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
1528 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
1532 QUERY_STRING(msg, info6.username.name, "sAMAccountName");
1533 QUERY_STRING(msg, info6.full_name.name, "displayName");
1537 QUERY_STRING(msg, info7.username.name, "sAMAccountName");
1541 QUERY_STRING(msg, info8.full_name.name, "displayName");
1545 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
1549 QUERY_STRING(msg, info10.home_directory.name, "homeDirectory");
1550 QUERY_STRING(msg, info10.home_drive.name, "homeDrive");
1554 QUERY_STRING(msg, info11.logon_script.name, "scriptPath");
1558 QUERY_STRING(msg, info12.profile.name, "profilePath");
1562 QUERY_STRING(msg, info13.description.name, "description");
1566 QUERY_STRING(msg, info14.workstations.name, "userWorkstations");
1570 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1574 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
1577 QUERY_STRING(msg, info20.callback.name, "userParameters");
1581 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
1582 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
1583 QUERY_NTTIME(msg, info21.last_pwd_change, "pwdLastSet");
1584 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
1585 QUERY_APASSC(msg, info21.allow_pwd_change, "pwdLastSet");
1586 QUERY_FPASSC(msg, info21.force_pwd_change, "pwdLastSet");
1587 QUERY_STRING(msg, info21.username.name, "sAMAccountName");
1588 QUERY_STRING(msg, info21.full_name.name, "displayName");
1589 QUERY_STRING(msg, info21.home_directory.name, "homeDirectory");
1590 QUERY_STRING(msg, info21.home_drive.name, "homeDrive");
1591 QUERY_STRING(msg, info21.logon_script.name, "scriptPath");
1592 QUERY_STRING(msg, info21.profile.name, "profilePath");
1593 QUERY_STRING(msg, info21.description.name, "description");
1594 QUERY_STRING(msg, info21.workstations.name, "userWorkstations");
1595 QUERY_STRING(msg, info21.comment.name, "comment");
1596 QUERY_STRING(msg, info21.callback.name, "userParameters");
1597 QUERY_RID (msg, info21.rid, "objectSid");
1598 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
1599 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
1600 r->out.info->info21.fields_present = 0x00FFFFFF;
1601 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
1602 QUERY_UINT (msg, info21.bad_pwd_count, "badPwdCount");
1603 QUERY_UINT (msg, info21.num_logons, "logonCount");
1604 QUERY_UINT (msg, info21.country_code, "countryCode");
1605 QUERY_UINT (msg, info21.code_page, "codePage");
1611 return NT_STATUS_INVALID_INFO_CLASS;
1614 return NT_STATUS_OK;
1621 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1622 struct samr_SetUserInfo *r)
1624 struct dcesrv_handle *h;
1625 struct samr_account_state *a_state;
1626 struct ldb_message mod, *msg = &mod;
1628 NTSTATUS status = NT_STATUS_OK;
1630 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1635 mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1637 return NT_STATUS_NO_MEMORY;
1640 switch (r->in.level) {
1642 SET_STRING(msg, info2.comment.name, "comment");
1643 SET_UINT (msg, info2.country_code, "countryCode");
1644 SET_UINT (msg, info2.code_page, "codePage");
1648 SET_LHOURS(msg, info4.logon_hours, "logonHours");
1652 SET_STRING(msg, info6.full_name.name, "displayName");
1656 SET_STRING(msg, info8.full_name.name, "displayName");
1660 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
1664 SET_STRING(msg, info10.home_directory.name, "homeDirectory");
1665 SET_STRING(msg, info10.home_drive.name, "homeDrive");
1669 SET_STRING(msg, info11.logon_script.name, "scriptPath");
1673 SET_STRING(msg, info12.profile.name, "profilePath");
1677 SET_STRING(msg, info13.description.name, "description");
1681 SET_STRING(msg, info14.workstations.name, "userWorkstations");
1685 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
1689 SET_STRING(msg, info20.callback.name, "userParameters");
1693 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1694 IFSET(SAMR_FIELD_NAME)
1695 SET_STRING(msg, info21.full_name.name, "displayName");
1696 IFSET(SAMR_FIELD_DESCRIPTION)
1697 SET_STRING(msg, info21.description.name, "description");
1698 IFSET(SAMR_FIELD_COMMENT)
1699 SET_STRING(msg, info21.comment.name, "comment");
1700 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1701 SET_STRING(msg, info21.logon_script.name, "scriptPath");
1702 IFSET(SAMR_FIELD_PROFILE)
1703 SET_STRING(msg, info21.profile.name, "profilePath");
1704 IFSET(SAMR_FIELD_WORKSTATION)
1705 SET_STRING(msg, info21.workstations.name, "userWorkstations");
1706 IFSET(SAMR_FIELD_LOGON_HOURS)
1707 SET_LHOURS(msg, info21.logon_hours, "logonHours");
1708 IFSET(SAMR_FIELD_CALLBACK)
1709 SET_STRING(msg, info21.callback.name, "userParameters");
1710 IFSET(SAMR_FIELD_COUNTRY_CODE)
1711 SET_UINT (msg, info21.country_code, "countryCode");
1712 IFSET(SAMR_FIELD_CODE_PAGE)
1713 SET_UINT (msg, info21.code_page, "codePage");
1718 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
1719 IFSET(SAMR_FIELD_NAME)
1720 SET_STRING(msg, info23.info.full_name.name, "displayName");
1721 IFSET(SAMR_FIELD_DESCRIPTION)
1722 SET_STRING(msg, info23.info.description.name, "description");
1723 IFSET(SAMR_FIELD_COMMENT)
1724 SET_STRING(msg, info23.info.comment.name, "comment");
1725 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1726 SET_STRING(msg, info23.info.logon_script.name, "scriptPath");
1727 IFSET(SAMR_FIELD_PROFILE)
1728 SET_STRING(msg, info23.info.profile.name, "profilePath");
1729 IFSET(SAMR_FIELD_WORKSTATION)
1730 SET_STRING(msg, info23.info.workstations.name, "userWorkstations");
1731 IFSET(SAMR_FIELD_LOGON_HOURS)
1732 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
1733 IFSET(SAMR_FIELD_CALLBACK)
1734 SET_STRING(msg, info23.info.callback.name, "userParameters");
1735 IFSET(SAMR_FIELD_COUNTRY_CODE)
1736 SET_UINT (msg, info23.info.country_code, "countryCode");
1737 IFSET(SAMR_FIELD_CODE_PAGE)
1738 SET_UINT (msg, info23.info.code_page, "codePage");
1739 IFSET(SAMR_FIELD_PASSWORD) {
1740 status = samr_set_password(dce_call,
1742 a_state->account_dn,
1743 a_state->domain_state->domain_dn,
1745 &r->in.info->info23.password);
1750 /* the set password levels are handled separately */
1752 status = samr_set_password(dce_call,
1754 a_state->account_dn,
1755 a_state->domain_state->domain_dn,
1757 &r->in.info->info24.password);
1761 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
1762 IFSET(SAMR_FIELD_NAME)
1763 SET_STRING(msg, info25.info.full_name.name, "displayName");
1764 IFSET(SAMR_FIELD_DESCRIPTION)
1765 SET_STRING(msg, info25.info.description.name, "description");
1766 IFSET(SAMR_FIELD_COMMENT)
1767 SET_STRING(msg, info25.info.comment.name, "comment");
1768 IFSET(SAMR_FIELD_LOGON_SCRIPT)
1769 SET_STRING(msg, info25.info.logon_script.name, "scriptPath");
1770 IFSET(SAMR_FIELD_PROFILE)
1771 SET_STRING(msg, info25.info.profile.name, "profilePath");
1772 IFSET(SAMR_FIELD_WORKSTATION)
1773 SET_STRING(msg, info25.info.workstations.name, "userWorkstations");
1774 IFSET(SAMR_FIELD_LOGON_HOURS)
1775 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
1776 IFSET(SAMR_FIELD_CALLBACK)
1777 SET_STRING(msg, info25.info.callback.name, "userParameters");
1778 IFSET(SAMR_FIELD_COUNTRY_CODE)
1779 SET_UINT (msg, info25.info.country_code, "countryCode");
1780 IFSET(SAMR_FIELD_CODE_PAGE)
1781 SET_UINT (msg, info25.info.code_page, "codePage");
1782 IFSET(SAMR_FIELD_PASSWORD) {
1783 status = samr_set_password_ex(dce_call,
1785 a_state->account_dn,
1786 a_state->domain_state->domain_dn,
1788 &r->in.info->info25.password);
1793 /* the set password levels are handled separately */
1795 status = samr_set_password_ex(dce_call,
1797 a_state->account_dn,
1798 a_state->domain_state->domain_dn,
1800 &r->in.info->info26.password);
1805 /* many info classes are not valid for SetUserInfo */
1806 return NT_STATUS_INVALID_INFO_CLASS;
1809 if (!NT_STATUS_IS_OK(status)) {
1813 /* modify the samdb record */
1814 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1816 /* we really need samdb.c to return NTSTATUS */
1817 return NT_STATUS_UNSUCCESSFUL;
1820 return NT_STATUS_OK;
1825 samr_GetGroupsForUser
1827 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1828 struct samr_GetGroupsForUser *r)
1830 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1835 samr_QueryDisplayInfo
1837 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1838 struct samr_QueryDisplayInfo *r)
1840 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1845 samr_GetDisplayEnumerationIndex
1847 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1848 struct samr_GetDisplayEnumerationIndex *r)
1850 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1855 samr_TestPrivateFunctionsDomain
1857 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1858 struct samr_TestPrivateFunctionsDomain *r)
1860 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1865 samr_TestPrivateFunctionsUser
1867 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1868 struct samr_TestPrivateFunctionsUser *r)
1870 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1877 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1878 struct samr_GetUserPwInfo *r)
1880 struct dcesrv_handle *h;
1881 struct samr_account_state *a_state;
1883 ZERO_STRUCT(r->out.info);
1885 DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1889 r->out.info.min_pwd_len = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength",
1890 "dn=%s", a_state->domain_state->domain_dn);
1891 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties",
1892 "dn=%s", a_state->account_dn);
1893 return NT_STATUS_OK;
1898 samr_RemoveMemberFromForeignDomain
1900 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1901 struct samr_RemoveMemberFromForeignDomain *r)
1903 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1908 samr_QueryDomainInfo2
1910 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1911 struct samr_QueryDomainInfo2 *r)
1913 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1920 just an alias for samr_QueryUserInfo
1922 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1923 struct samr_QueryUserInfo2 *r)
1925 struct samr_QueryUserInfo r1;
1928 r1.in.handle = r->in.handle;
1929 r1.in.level = r->in.level;
1931 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
1933 r->out.info = r1.out.info;
1940 samr_QueryDisplayInfo2
1942 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1943 struct samr_QueryDisplayInfo2 *r)
1945 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1950 samr_GetDisplayEnumerationIndex2
1952 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1953 struct samr_GetDisplayEnumerationIndex2 *r)
1955 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1960 samr_QueryDisplayInfo3
1962 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1963 struct samr_QueryDisplayInfo3 *r)
1965 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1970 samr_AddMultipleMembersToAlias
1972 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1973 struct samr_AddMultipleMembersToAlias *r)
1975 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1980 samr_RemoveMultipleMembersFromAlias
1982 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1983 struct samr_RemoveMultipleMembersFromAlias *r)
1985 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1992 this fetches the default password properties for a domain
1994 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1995 struct samr_GetDomPwInfo *r)
1997 struct ldb_message **msgs;
1999 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2002 if (r->in.name == NULL || r->in.name->name == NULL) {
2003 return NT_STATUS_NO_SUCH_DOMAIN;
2006 sam_ctx = samdb_connect();
2007 if (sam_ctx == NULL) {
2008 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2011 ret = samdb_search(sam_ctx,
2012 mem_ctx, NULL, &msgs, attrs,
2013 "(&(name=%s)(objectclass=domain))",
2016 samdb_close(sam_ctx);
2017 return NT_STATUS_NO_SUCH_DOMAIN;
2020 samdb_search_free(sam_ctx, mem_ctx, msgs);
2021 samdb_close(sam_ctx);
2022 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2025 r->out.info.min_pwd_len = samdb_result_uint(msgs[0], "minPwdLength", 0);
2026 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2028 samdb_search_free(sam_ctx, mem_ctx, msgs);
2030 samdb_close(sam_ctx);
2031 return NT_STATUS_OK;
2038 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2039 struct samr_Connect2 *r)
2041 struct samr_Connect c;
2043 c.in.system_name = NULL;
2044 c.in.access_mask = r->in.access_mask;
2045 c.out.handle = r->out.handle;
2047 return samr_Connect(dce_call, mem_ctx, &c);
2054 just an alias for samr_SetUserInfo
2056 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2057 struct samr_SetUserInfo2 *r)
2059 struct samr_SetUserInfo r2;
2061 r2.in.handle = r->in.handle;
2062 r2.in.level = r->in.level;
2063 r2.in.info = r->in.info;
2065 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2070 samr_SetBootKeyInformation
2072 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2073 struct samr_SetBootKeyInformation *r)
2075 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2080 samr_GetBootKeyInformation
2082 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2083 struct samr_GetBootKeyInformation *r)
2085 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2092 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2093 struct samr_Connect3 *r)
2095 struct samr_Connect c;
2097 c.in.system_name = NULL;
2098 c.in.access_mask = r->in.access_mask;
2099 c.out.handle = r->out.handle;
2101 return samr_Connect(dce_call, mem_ctx, &c);
2108 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2109 struct samr_Connect4 *r)
2111 struct samr_Connect c;
2113 c.in.system_name = NULL;
2114 c.in.access_mask = r->in.access_mask;
2115 c.out.handle = r->out.handle;
2117 return samr_Connect(dce_call, mem_ctx, &c);
2124 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2125 struct samr_Connect5 *r)
2127 struct samr_Connect c;
2130 c.in.system_name = NULL;
2131 c.in.access_mask = r->in.access_mask;
2132 c.out.handle = r->out.handle;
2134 status = samr_Connect(dce_call, mem_ctx, &c);
2136 r->out.info->info1.unknown1 = 3;
2137 r->out.info->info1.unknown2 = 0;
2138 r->out.level = r->in.level;
2147 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2148 struct samr_RidToSid *r)
2150 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2155 samr_SetDsrmPassword
2157 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2158 struct samr_SetDsrmPassword *r)
2160 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2165 samr_ValidatePassword
2167 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2168 struct samr_ValidatePassword *r)
2170 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2174 /* include the generated boilerplate */
2175 #include "librpc/gen_ndr/ndr_samr_s.c"