LCOV - code coverage report
Current view: top level - source4/rpc_server/samr - dcesrv_samr.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 1942 2707 71.7 %
Date: 2024-02-28 12:06:22 Functions: 74 88 84.1 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    endpoint server for the samr pipe
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2004
       7             :    Copyright (C) Volker Lendecke 2004
       8             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
       9             :    Copyright (C) Matthias Dieter Wallnöfer 2009
      10             : 
      11             :    This program is free software; you can redistribute it and/or modify
      12             :    it under the terms of the GNU General Public License as published by
      13             :    the Free Software Foundation; either version 3 of the License, or
      14             :    (at your option) any later version.
      15             : 
      16             :    This program is distributed in the hope that it will be useful,
      17             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :    GNU General Public License for more details.
      20             : 
      21             :    You should have received a copy of the GNU General Public License
      22             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "librpc/gen_ndr/ndr_samr.h"
      27             : #include "rpc_server/dcerpc_server.h"
      28             : #include "rpc_server/common/common.h"
      29             : #include "rpc_server/samr/dcesrv_samr.h"
      30             : #include "system/time.h"
      31             : #include <ldb.h>
      32             : #include <ldb_errors.h>
      33             : #include "../libds/common/flags.h"
      34             : #include "dsdb/samdb/samdb.h"
      35             : #include "dsdb/common/util.h"
      36             : #include "libcli/ldap/ldap_ndr.h"
      37             : #include "libcli/security/security.h"
      38             : #include "rpc_server/samr/proto.h"
      39             : #include "../lib/util/util_ldb.h"
      40             : #include "param/param.h"
      41             : #include "lib/util/tsort.h"
      42             : #include "libds/common/flag_mapping.h"
      43             : 
      44             : #undef strcasecmp
      45             : 
      46             : #define DCESRV_INTERFACE_SAMR_BIND(context, iface) \
      47             :        dcesrv_interface_samr_bind(context, iface)
      48        2522 : static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_connection_context *context,
      49             :                                              const struct dcesrv_interface *iface)
      50             : {
      51        2522 :         return dcesrv_interface_bind_reject_connect(context, iface);
      52             : }
      53             : 
      54             : /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
      55             : 
      56             : #define QUERY_STRING(msg, field, attr) \
      57             :         info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
      58             : #define QUERY_UINT(msg, field, attr) \
      59             :         info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
      60             : #define QUERY_RID(msg, field, attr) \
      61             :         info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
      62             : #define QUERY_UINT64(msg, field, attr) \
      63             :         info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
      64             : #define QUERY_APASSC(msg, field, attr) \
      65             :         info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
      66             :                                                          a_state->domain_state->domain_dn, msg, attr);
      67             : #define QUERY_BPWDCT(msg, field, attr) \
      68             :         info->field = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx, \
      69             :                                                          a_state->domain_state->domain_dn, msg);
      70             : #define QUERY_LHOURS(msg, field, attr) \
      71             :         info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
      72             : #define QUERY_AFLAGS(msg, field, attr) \
      73             :         info->field = samdb_result_acct_flags(msg, attr);
      74             : 
      75             : 
      76             : /* these are used to make the Set[User|Group]Info code easier to follow */
      77             : 
      78             : #define SET_STRING(msg, field, attr) do {                               \
      79             :         struct ldb_message_element *set_el;                             \
      80             :         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
      81             :         if (r->in.info->field.string[0] == '\0') {                        \
      82             :                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
      83             :                         return NT_STATUS_NO_MEMORY;                     \
      84             :                 }                                                       \
      85             :         }                                                               \
      86             :         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
      87             :                 return NT_STATUS_NO_MEMORY;                             \
      88             :         }                                                               \
      89             :         set_el = ldb_msg_find_element(msg, attr);                       \
      90             :         set_el->flags = LDB_FLAG_MOD_REPLACE;                                \
      91             : } while (0)
      92             : 
      93             : #define SET_UINT(msg, field, attr) do {                                 \
      94             :         struct ldb_message_element *set_el;                             \
      95             :         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
      96             :                 return NT_STATUS_NO_MEMORY;                             \
      97             :         }                                                               \
      98             :         set_el = ldb_msg_find_element(msg, attr);                       \
      99             :         set_el->flags = LDB_FLAG_MOD_REPLACE;                                \
     100             : } while (0)
     101             : 
     102             : #define SET_INT64(msg, field, attr) do {                                \
     103             :         struct ldb_message_element *set_el;                             \
     104             :         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
     105             :                 return NT_STATUS_NO_MEMORY;                             \
     106             :         }                                                               \
     107             :         set_el = ldb_msg_find_element(msg, attr);                       \
     108             :         set_el->flags = LDB_FLAG_MOD_REPLACE;                                \
     109             : } while (0)
     110             : 
     111             : #define SET_UINT64(msg, field, attr) do {                               \
     112             :         struct ldb_message_element *set_el;                             \
     113             :         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
     114             :                 return NT_STATUS_NO_MEMORY;                             \
     115             :         }                                                               \
     116             :         set_el = ldb_msg_find_element(msg, attr);                       \
     117             :         set_el->flags = LDB_FLAG_MOD_REPLACE;                                \
     118             : } while (0)
     119             : 
     120             : /* Set account flags, discarding flags that cannot be set with SAMR */
     121             : #define SET_AFLAGS(msg, field, attr) do {                               \
     122             :         struct ldb_message_element *set_el;                             \
     123             :         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
     124             :                 return NT_STATUS_NO_MEMORY;                             \
     125             :         }                                                               \
     126             :         set_el = ldb_msg_find_element(msg, attr);                       \
     127             :         set_el->flags = LDB_FLAG_MOD_REPLACE;                                \
     128             : } while (0)
     129             : 
     130             : #define SET_LHOURS(msg, field, attr) do {                               \
     131             :         struct ldb_message_element *set_el;                             \
     132             :         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
     133             :                 return NT_STATUS_NO_MEMORY;                             \
     134             :         }                                                               \
     135             :         set_el = ldb_msg_find_element(msg, attr);                       \
     136             :         set_el->flags = LDB_FLAG_MOD_REPLACE;                                \
     137             : } while (0)
     138             : 
     139             : #define SET_PARAMETERS(msg, field, attr) do {                           \
     140             :         struct ldb_message_element *set_el;                             \
     141             :         if (r->in.info->field.length != 0) {                              \
     142             :                 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
     143             :                         return NT_STATUS_NO_MEMORY;                     \
     144             :                 }                                                       \
     145             :                 set_el = ldb_msg_find_element(msg, attr);               \
     146             :                 set_el->flags = LDB_FLAG_MOD_REPLACE;                        \
     147             :         }                                                               \
     148             : } while (0)
     149             : 
     150             : /*
     151             :  * Clear a GUID cache
     152             :  */
     153         422 : static void clear_guid_cache(struct samr_guid_cache *cache)
     154             : {
     155         422 :         cache->handle = 0;
     156         422 :         cache->size = 0;
     157         422 :         TALLOC_FREE(cache->entries);
     158         422 : }
     159             : 
     160             : /*
     161             :  * initialize a GUID cache
     162             :  */
     163        7149 : static void initialize_guid_cache(struct samr_guid_cache *cache)
     164             : {
     165        7149 :         cache->handle = 0;
     166        7149 :         cache->size = 0;
     167        7149 :         cache->entries = NULL;
     168        6633 : }
     169             : 
     170         188 : static NTSTATUS load_guid_cache(
     171             :         struct samr_guid_cache *cache,
     172             :         struct samr_domain_state *d_state,
     173             :         unsigned int ldb_cnt,
     174             :         struct ldb_message **res)
     175             : {
     176         188 :         NTSTATUS status = NT_STATUS_OK;
     177           0 :         unsigned int i;
     178         188 :         TALLOC_CTX *frame = talloc_stackframe();
     179             : 
     180         188 :         clear_guid_cache(cache);
     181             : 
     182             :         /*
     183             :          * Store the GUID's in the cache.
     184             :          */
     185         188 :         cache->handle = 0;
     186         188 :         cache->size = ldb_cnt;
     187         188 :         cache->entries = talloc_array(d_state, struct GUID, ldb_cnt);
     188         188 :         if (cache->entries == NULL) {
     189           0 :                 clear_guid_cache(cache);
     190           0 :                 status = NT_STATUS_NO_MEMORY;
     191           0 :                 goto exit;
     192             :         }
     193             : 
     194             :         /*
     195             :          * Extract a list of the GUIDs for all the matching objects
     196             :          * we cache just the GUIDS to reduce the memory overhead of
     197             :          * the result cache.
     198             :          */
     199        3663 :         for (i = 0; i < ldb_cnt; i++) {
     200        3475 :                 cache->entries[i] = samdb_result_guid(res[i], "objectGUID");
     201             :         }
     202         188 : exit:
     203         188 :         TALLOC_FREE(frame);
     204         188 :         return status;
     205             : }
     206             : 
     207             : /*
     208             :   samr_Connect
     209             : 
     210             :   create a connection to the SAM database
     211             : */
     212        2688 : static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     213             :                              struct samr_Connect *r)
     214             : {
     215         178 :         struct samr_connect_state *c_state;
     216         178 :         struct dcesrv_handle *handle;
     217             : 
     218        2688 :         ZERO_STRUCTP(r->out.connect_handle);
     219             : 
     220        2688 :         c_state = talloc(mem_ctx, struct samr_connect_state);
     221        2688 :         if (!c_state) {
     222           0 :                 return NT_STATUS_NO_MEMORY;
     223             :         }
     224             : 
     225             :         /* make sure the sam database is accessible */
     226        2688 :         c_state->sam_ctx = dcesrv_samdb_connect_as_user(c_state, dce_call);
     227        2688 :         if (c_state->sam_ctx == NULL) {
     228           0 :                 talloc_free(c_state);
     229           0 :                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
     230             :         }
     231             : 
     232        2688 :         handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_CONNECT);
     233        2688 :         if (!handle) {
     234           0 :                 talloc_free(c_state);
     235           0 :                 return NT_STATUS_NO_MEMORY;
     236             :         }
     237             : 
     238        2688 :         handle->data = talloc_steal(handle, c_state);
     239             : 
     240        2688 :         c_state->access_mask = r->in.access_mask;
     241        2688 :         *r->out.connect_handle = handle->wire_handle;
     242             : 
     243        2688 :         return NT_STATUS_OK;
     244             : }
     245             : 
     246             : 
     247             : /*
     248             :   samr_Close
     249             : */
     250        2891 : static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     251             :                            struct samr_Close *r)
     252             : {
     253          12 :         struct dcesrv_handle *h;
     254             : 
     255        2891 :         *r->out.handle = *r->in.handle;
     256             : 
     257        2891 :         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
     258             : 
     259        2867 :         talloc_free(h);
     260             : 
     261        2867 :         ZERO_STRUCTP(r->out.handle);
     262             : 
     263        2867 :         return NT_STATUS_OK;
     264             : }
     265             : 
     266             : 
     267             : /*
     268             :   samr_SetSecurity
     269             : */
     270           0 : static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     271             :                                  struct samr_SetSecurity *r)
     272             : {
     273           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
     274             : }
     275             : 
     276             : 
     277             : /*
     278             :   samr_QuerySecurity
     279             : */
     280         322 : static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     281             :                                    struct samr_QuerySecurity *r)
     282             : {
     283           0 :         struct dcesrv_handle *h;
     284           0 :         struct sec_desc_buf *sd;
     285             : 
     286         322 :         *r->out.sdbuf = NULL;
     287             : 
     288         322 :         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
     289             : 
     290         322 :         sd = talloc(mem_ctx, struct sec_desc_buf);
     291         322 :         if (sd == NULL) {
     292           0 :                 return NT_STATUS_NO_MEMORY;
     293             :         }
     294             : 
     295         322 :         sd->sd = samdb_default_security_descriptor(mem_ctx);
     296             : 
     297         322 :         *r->out.sdbuf = sd;
     298             : 
     299         322 :         return NT_STATUS_OK;
     300             : }
     301             : 
     302             : 
     303             : /*
     304             :   samr_Shutdown
     305             : 
     306             :   we refuse this operation completely. If a admin wants to shutdown samr
     307             :   in Samba then they should use the samba admin tools to disable the samr pipe
     308             : */
     309           0 : static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     310             :                               struct samr_Shutdown *r)
     311             : {
     312           0 :         return NT_STATUS_ACCESS_DENIED;
     313             : }
     314             : 
     315             : 
     316             : /*
     317             :   samr_LookupDomain
     318             : 
     319             :   this maps from a domain name to a SID
     320             : */
     321         564 : static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     322             :                                   struct samr_LookupDomain *r)
     323             : {
     324           0 :         struct samr_connect_state *c_state;
     325           0 :         struct dcesrv_handle *h;
     326           0 :         struct dom_sid *sid;
     327         564 :         const char * const dom_attrs[] = { "objectSid", NULL};
     328           0 :         struct ldb_message **dom_msgs;
     329           0 :         int ret;
     330             : 
     331         564 :         *r->out.sid = NULL;
     332             : 
     333         564 :         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
     334             : 
     335         564 :         c_state = h->data;
     336             : 
     337         564 :         if (r->in.domain_name->string == NULL) {
     338          44 :                 return NT_STATUS_INVALID_PARAMETER;
     339             :         }
     340             : 
     341         520 :         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
     342          22 :                 ret = gendb_search(c_state->sam_ctx,
     343             :                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
     344             :                                    "(objectClass=builtinDomain)");
     345         498 :         } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
     346         454 :                 ret = gendb_search_dn(c_state->sam_ctx,
     347             :                                       mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
     348             :                                       &dom_msgs, dom_attrs);
     349             :         } else {
     350          44 :                 return NT_STATUS_NO_SUCH_DOMAIN;
     351             :         }
     352         476 :         if (ret != 1) {
     353           0 :                 return NT_STATUS_NO_SUCH_DOMAIN;
     354             :         }
     355             : 
     356         476 :         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
     357             :                                    "objectSid");
     358             : 
     359         476 :         if (sid == NULL) {
     360           0 :                 return NT_STATUS_NO_SUCH_DOMAIN;
     361             :         }
     362             : 
     363         476 :         *r->out.sid = sid;
     364             : 
     365         476 :         return NT_STATUS_OK;
     366             : }
     367             : 
     368             : 
     369             : /*
     370             :   samr_EnumDomains
     371             : 
     372             :   list the domains in the SAM
     373             : */
     374         158 : static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     375             :                                  struct samr_EnumDomains *r)
     376             : {
     377           0 :         struct dcesrv_handle *h;
     378           0 :         struct samr_SamArray *array;
     379           0 :         uint32_t i, start_i;
     380             : 
     381         158 :         *r->out.resume_handle = 0;
     382         158 :         *r->out.sam = NULL;
     383         158 :         *r->out.num_entries = 0;
     384             : 
     385         158 :         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
     386             : 
     387         158 :         *r->out.resume_handle = 2;
     388             : 
     389         158 :         start_i = *r->in.resume_handle;
     390             : 
     391         158 :         if (start_i >= 2) {
     392             :                 /* search past end of list is not an error for this call */
     393          22 :                 return NT_STATUS_OK;
     394             :         }
     395             : 
     396         136 :         array = talloc(mem_ctx, struct samr_SamArray);
     397         136 :         if (array == NULL) {
     398           0 :                 return NT_STATUS_NO_MEMORY;
     399             :         }
     400             : 
     401         136 :         array->count = 0;
     402         136 :         array->entries = NULL;
     403             : 
     404         136 :         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
     405         136 :         if (array->entries == NULL) {
     406           0 :                 return NT_STATUS_NO_MEMORY;
     407             :         }
     408             : 
     409         408 :         for (i=0;i<2-start_i;i++) {
     410         272 :                 array->entries[i].idx = start_i + i;
     411         272 :                 if (i == 0) {
     412         136 :                         array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
     413             :                 } else {
     414         136 :                         array->entries[i].name.string = "BUILTIN";
     415             :                 }
     416             :         }
     417             : 
     418         136 :         *r->out.sam = array;
     419         136 :         *r->out.num_entries = i;
     420         136 :         array->count = *r->out.num_entries;
     421             : 
     422         136 :         return NT_STATUS_OK;
     423             : }
     424             : 
     425             : 
     426             : /*
     427             :   samr_OpenDomain
     428             : */
     429        2389 : static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     430             :                                 struct samr_OpenDomain *r)
     431             : {
     432         172 :         struct dcesrv_handle *h_conn, *h_domain;
     433         172 :         struct samr_connect_state *c_state;
     434         172 :         struct samr_domain_state *d_state;
     435        2389 :         const char * const dom_attrs[] = { "cn", NULL};
     436         172 :         struct ldb_message **dom_msgs;
     437         172 :         int ret;
     438         172 :         unsigned int i;
     439             : 
     440        2389 :         ZERO_STRUCTP(r->out.domain_handle);
     441             : 
     442        2389 :         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
     443             : 
     444        2383 :         c_state = h_conn->data;
     445             : 
     446        2383 :         if (r->in.sid == NULL) {
     447           0 :                 return NT_STATUS_INVALID_PARAMETER;
     448             :         }
     449             : 
     450        2383 :         d_state = talloc(mem_ctx, struct samr_domain_state);
     451        2383 :         if (!d_state) {
     452           0 :                 return NT_STATUS_NO_MEMORY;
     453             :         }
     454             : 
     455        2383 :         d_state->domain_sid = talloc_steal(d_state, r->in.sid);
     456             : 
     457        2383 :         if (dom_sid_equal(d_state->domain_sid, &global_sid_Builtin)) {
     458         558 :                 d_state->builtin = true;
     459         558 :                 d_state->domain_name = "BUILTIN";
     460             :         } else {
     461        1825 :                 d_state->builtin = false;
     462        1825 :                 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
     463             :         }
     464             : 
     465        2383 :         ret = gendb_search(c_state->sam_ctx,
     466             :                            mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
     467             :                            "(objectSid=%s)",
     468        2383 :                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
     469             : 
     470        2383 :         if (ret == 0) {
     471           0 :                 talloc_free(d_state);
     472           0 :                 return NT_STATUS_NO_SUCH_DOMAIN;
     473        2383 :         } else if (ret > 1) {
     474           0 :                 talloc_free(d_state);
     475           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     476        2383 :         } else if (ret == -1) {
     477           0 :                 talloc_free(d_state);
     478           0 :                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
     479           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     480             :         }
     481             : 
     482        2383 :         d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
     483        2383 :         d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
     484        2383 :         d_state->connect_state = talloc_reference(d_state, c_state);
     485        2383 :         d_state->sam_ctx = c_state->sam_ctx;
     486        2383 :         d_state->access_mask = r->in.access_mask;
     487        2383 :         d_state->domain_users_cached = NULL;
     488             : 
     489        2383 :         d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
     490             : 
     491        9532 :         for (i = 0; i < SAMR_LAST_CACHE; i++) {
     492        7149 :                 initialize_guid_cache(&d_state->guid_caches[i]);
     493             :         }
     494             : 
     495        2383 :         h_domain = dcesrv_handle_create(dce_call, SAMR_HANDLE_DOMAIN);
     496        2383 :         if (!h_domain) {
     497           0 :                 talloc_free(d_state);
     498           0 :                 return NT_STATUS_NO_MEMORY;
     499             :         }
     500             : 
     501        2383 :         h_domain->data = talloc_steal(h_domain, d_state);
     502             : 
     503        2383 :         *r->out.domain_handle = h_domain->wire_handle;
     504             : 
     505        2383 :         return NT_STATUS_OK;
     506             : }
     507             : 
     508             : /*
     509             :   return DomInfo1
     510             : */
     511          59 : static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
     512             :                                           TALLOC_CTX *mem_ctx,
     513             :                                           struct ldb_message **dom_msgs,
     514             :                                           struct samr_DomInfo1 *info)
     515             : {
     516          59 :         info->min_password_length =
     517          59 :                 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
     518          59 :         info->password_history_length =
     519          59 :                 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
     520          59 :         info->password_properties =
     521          59 :                 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
     522          59 :         info->max_password_age =
     523          59 :                 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
     524          59 :         info->min_password_age =
     525          59 :                 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
     526             : 
     527          59 :         return NT_STATUS_OK;
     528             : }
     529             : 
     530             : /*
     531             :   return DomInfo2
     532             : */
     533          94 : static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
     534             :                                                        TALLOC_CTX *mem_ctx,
     535             :                                                        struct ldb_message **dom_msgs,
     536             :                                                        struct samr_DomGeneralInformation *info)
     537             : {
     538          94 :         size_t count = 0;
     539          94 :         const enum ldb_scope scope = LDB_SCOPE_SUBTREE;
     540          94 :         int ret = 0;
     541             : 
     542             :         /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
     543          94 :         info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
     544             :                                                            "domainReplica",
     545             :                                                            "");
     546             : 
     547          94 :         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
     548             :                                                             0x8000000000000000LL);
     549             : 
     550          94 :         info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
     551             :                                                                    "oEMInformation",
     552             :                                                                    "");
     553          94 :         info->domain_name.string  = state->domain_name;
     554             : 
     555          94 :         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
     556             :                                                  0);
     557          94 :         switch (state->role) {
     558          50 :         case ROLE_ACTIVE_DIRECTORY_DC:
     559             :                 /* This pulls the NetBIOS name from the
     560             :                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
     561             :                    string */
     562          50 :                 if (samdb_is_pdc(state->sam_ctx)) {
     563          38 :                         info->role = SAMR_ROLE_DOMAIN_PDC;
     564             :                 } else {
     565          12 :                         info->role = SAMR_ROLE_DOMAIN_BDC;
     566             :                 }
     567          94 :                 break;
     568           0 :         case ROLE_DOMAIN_PDC:
     569             :         case ROLE_DOMAIN_BDC:
     570             :         case ROLE_IPA_DC:
     571             :         case ROLE_AUTO:
     572           0 :                 return NT_STATUS_INTERNAL_ERROR;
     573          44 :         case ROLE_DOMAIN_MEMBER:
     574          44 :                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
     575          44 :                 break;
     576           0 :         case ROLE_STANDALONE:
     577           0 :                 info->role = SAMR_ROLE_STANDALONE;
     578           0 :                 break;
     579             :         }
     580             : 
     581             :         /*
     582             :          * Users are not meant to be in BUILTIN
     583             :          * so to speed up the query we do not filter on domain_sid
     584             :          */
     585          94 :         ret = dsdb_domain_count(
     586          94 :                 state->sam_ctx,
     587             :                 &count,
     588             :                 state->domain_dn,
     589             :                 NULL,
     590             :                 scope,
     591             :                 "(objectClass=user)");
     592          94 :         if (ret != LDB_SUCCESS || count > UINT32_MAX) {
     593           0 :                 goto error;
     594             :         }
     595          94 :         info->num_users = count;
     596             : 
     597             :         /*
     598             :          * Groups are not meant to be in BUILTIN
     599             :          * so to speed up the query we do not filter on domain_sid
     600             :          */
     601          94 :         ret = dsdb_domain_count(
     602          94 :                 state->sam_ctx,
     603             :                 &count,
     604             :                 state->domain_dn,
     605             :                 NULL,
     606             :                 scope,
     607             :                 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
     608             :                 GTYPE_SECURITY_UNIVERSAL_GROUP,
     609             :                 GTYPE_SECURITY_GLOBAL_GROUP);
     610          94 :         if (ret != LDB_SUCCESS || count > UINT32_MAX) {
     611           0 :                 goto error;
     612             :         }
     613          94 :         info->num_groups = count;
     614             : 
     615          94 :         ret = dsdb_domain_count(
     616          94 :                 state->sam_ctx,
     617             :                 &count,
     618             :                 state->domain_dn,
     619             :                 state->domain_sid,
     620             :                 scope,
     621             :                 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
     622             :                 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
     623             :                 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
     624          94 :         if (ret != LDB_SUCCESS || count > UINT32_MAX) {
     625           0 :                 goto error;
     626             :         }
     627          94 :         info->num_aliases = count;
     628             : 
     629          94 :         return NT_STATUS_OK;
     630             : 
     631           0 : error:
     632           0 :         if (count > UINT32_MAX) {
     633           0 :                 return NT_STATUS_INTEGER_OVERFLOW;
     634             :         }
     635           0 :         return dsdb_ldb_err_to_ntstatus(ret);
     636             : 
     637             : }
     638             : 
     639             : /*
     640             :   return DomInfo3
     641             : */
     642          22 : static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
     643             :                                           TALLOC_CTX *mem_ctx,
     644             :                                           struct ldb_message **dom_msgs,
     645             :                                           struct samr_DomInfo3 *info)
     646             : {
     647          22 :         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
     648             :                                                       0x8000000000000000LL);
     649             : 
     650          22 :         return NT_STATUS_OK;
     651             : }
     652             : 
     653             : /*
     654             :   return DomInfo4
     655             : */
     656          18 : static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
     657             :                                    TALLOC_CTX *mem_ctx,
     658             :                                     struct ldb_message **dom_msgs,
     659             :                                    struct samr_DomOEMInformation *info)
     660             : {
     661          18 :         info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
     662             :                                                                    "oEMInformation",
     663             :                                                                    "");
     664             : 
     665          18 :         return NT_STATUS_OK;
     666             : }
     667             : 
     668             : /*
     669             :   return DomInfo5
     670             : */
     671          19 : static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
     672             :                                           TALLOC_CTX *mem_ctx,
     673             :                                           struct ldb_message **dom_msgs,
     674             :                                           struct samr_DomInfo5 *info)
     675             : {
     676          19 :         info->domain_name.string  = state->domain_name;
     677             : 
     678          19 :         return NT_STATUS_OK;
     679             : }
     680             : 
     681             : /*
     682             :   return DomInfo6
     683             : */
     684          19 : static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
     685             :                                           TALLOC_CTX *mem_ctx,
     686             :                                           struct ldb_message **dom_msgs,
     687             :                                           struct samr_DomInfo6 *info)
     688             : {
     689             :         /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
     690          19 :         info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
     691             :                                                            "domainReplica",
     692             :                                                            "");
     693             : 
     694          19 :         return NT_STATUS_OK;
     695             : }
     696             : 
     697             : /*
     698             :   return DomInfo7
     699             : */
     700          19 : static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
     701             :                                           TALLOC_CTX *mem_ctx,
     702             :                                           struct ldb_message **dom_msgs,
     703             :                                           struct samr_DomInfo7 *info)
     704             : {
     705             : 
     706          19 :         switch (state->role) {
     707           7 :         case ROLE_ACTIVE_DIRECTORY_DC:
     708             :                 /* This pulls the NetBIOS name from the
     709             :                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
     710             :                    string */
     711           7 :                 if (samdb_is_pdc(state->sam_ctx)) {
     712           7 :                         info->role = SAMR_ROLE_DOMAIN_PDC;
     713             :                 } else {
     714           0 :                         info->role = SAMR_ROLE_DOMAIN_BDC;
     715             :                 }
     716          19 :                 break;
     717           0 :         case ROLE_DOMAIN_PDC:
     718             :         case ROLE_DOMAIN_BDC:
     719             :         case ROLE_IPA_DC:
     720             :         case ROLE_AUTO:
     721           0 :                 return NT_STATUS_INTERNAL_ERROR;
     722          12 :         case ROLE_DOMAIN_MEMBER:
     723          12 :                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
     724          12 :                 break;
     725           0 :         case ROLE_STANDALONE:
     726           0 :                 info->role = SAMR_ROLE_STANDALONE;
     727           0 :                 break;
     728             :         }
     729             : 
     730          19 :         return NT_STATUS_OK;
     731             : }
     732             : 
     733             : /*
     734             :   return DomInfo8
     735             : */
     736          21 : static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
     737             :                                           TALLOC_CTX *mem_ctx,
     738             :                                           struct ldb_message **dom_msgs,
     739             :                                           struct samr_DomInfo8 *info)
     740             : {
     741          21 :         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
     742          21 :                                                time(NULL));
     743             : 
     744          21 :         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
     745             :                                                      0x0LL);
     746             : 
     747          21 :         return NT_STATUS_OK;
     748             : }
     749             : 
     750             : /*
     751             :   return DomInfo9
     752             : */
     753          18 : static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
     754             :                                           TALLOC_CTX *mem_ctx,
     755             :                                           struct ldb_message **dom_msgs,
     756             :                                           struct samr_DomInfo9 *info)
     757             : {
     758          18 :         info->domain_server_state = DOMAIN_SERVER_ENABLED;
     759             : 
     760          18 :         return NT_STATUS_OK;
     761             : }
     762             : 
     763             : /*
     764             :   return DomInfo11
     765             : */
     766          18 : static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
     767             :                                                         TALLOC_CTX *mem_ctx,
     768             :                                                         struct ldb_message **dom_msgs,
     769             :                                                         struct samr_DomGeneralInformation2 *info)
     770             : {
     771           0 :         NTSTATUS status;
     772          18 :         status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
     773          18 :         if (!NT_STATUS_IS_OK(status)) {
     774           0 :                 return status;
     775             :         }
     776             : 
     777          18 :         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
     778             :                                                     -18000000000LL);
     779          18 :         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
     780             :                                                     -18000000000LL);
     781          18 :         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
     782             : 
     783          18 :         return NT_STATUS_OK;
     784             : }
     785             : 
     786             : /*
     787             :   return DomInfo12
     788             : */
     789          35 : static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
     790             :                                            TALLOC_CTX *mem_ctx,
     791             :                                            struct ldb_message **dom_msgs,
     792             :                                            struct samr_DomInfo12 *info)
     793             : {
     794          35 :         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
     795             :                                                     -18000000000LL);
     796          35 :         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
     797             :                                                     -18000000000LL);
     798          35 :         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
     799             : 
     800          35 :         return NT_STATUS_OK;
     801             : }
     802             : 
     803             : /*
     804             :   return DomInfo13
     805             : */
     806          18 : static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
     807             :                                            TALLOC_CTX *mem_ctx,
     808             :                                            struct ldb_message **dom_msgs,
     809             :                                            struct samr_DomInfo13 *info)
     810             : {
     811          18 :         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
     812          18 :                                                time(NULL));
     813             : 
     814          18 :         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
     815             :                                                      0x0LL);
     816             : 
     817          18 :         info->modified_count_at_last_promotion = 0;
     818             : 
     819          18 :         return NT_STATUS_OK;
     820             : }
     821             : 
     822             : /*
     823             :   samr_QueryDomainInfo
     824             : */
     825         342 : static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
     826             :                                             TALLOC_CTX *mem_ctx,
     827             :                                             struct samr_QueryDomainInfo *r)
     828             : {
     829           0 :         struct dcesrv_handle *h;
     830           0 :         struct samr_domain_state *d_state;
     831           0 :         union samr_DomainInfo *info;
     832             : 
     833           0 :         struct ldb_message **dom_msgs;
     834         342 :         const char * const *attrs = NULL;
     835             : 
     836         342 :         *r->out.info = NULL;
     837             : 
     838         342 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
     839             : 
     840         342 :         d_state = h->data;
     841             : 
     842         342 :         switch (r->in.level) {
     843          59 :         case 1:
     844             :         {
     845             :                 static const char * const attrs2[] = { "minPwdLength",
     846             :                                                        "pwdHistoryLength",
     847             :                                                        "pwdProperties",
     848             :                                                        "maxPwdAge",
     849             :                                                        "minPwdAge",
     850             :                                                        NULL };
     851          59 :                 attrs = attrs2;
     852          59 :                 break;
     853             :         }
     854          76 :         case 2:
     855             :         {
     856           0 :                 static const char * const attrs2[] = {"forceLogoff",
     857             :                                                       "oEMInformation",
     858             :                                                       "modifiedCount",
     859             :                                                       "domainReplica",
     860             :                                                       NULL};
     861          76 :                 attrs = attrs2;
     862          76 :                 break;
     863             :         }
     864          22 :         case 3:
     865             :         {
     866           0 :                 static const char * const attrs2[] = {"forceLogoff",
     867             :                                                       NULL};
     868          22 :                 attrs = attrs2;
     869          22 :                 break;
     870             :         }
     871          18 :         case 4:
     872             :         {
     873           0 :                 static const char * const attrs2[] = {"oEMInformation",
     874             :                                                       NULL};
     875          18 :                 attrs = attrs2;
     876          18 :                 break;
     877             :         }
     878          19 :         case 5:
     879             :         {
     880          19 :                 attrs = NULL;
     881          19 :                 break;
     882             :         }
     883          19 :         case 6:
     884             :         {
     885           0 :                 static const char * const attrs2[] = { "domainReplica",
     886             :                                                        NULL };
     887          19 :                 attrs = attrs2;
     888          19 :                 break;
     889             :         }
     890          19 :         case 7:
     891             :         {
     892          19 :                 attrs = NULL;
     893          19 :                 break;
     894             :         }
     895          21 :         case 8:
     896             :         {
     897           0 :                 static const char * const attrs2[] = { "modifiedCount",
     898             :                                                        "creationTime",
     899             :                                                        NULL };
     900          21 :                 attrs = attrs2;
     901          21 :                 break;
     902             :         }
     903          18 :         case 9:
     904             :         {
     905          18 :                 attrs = NULL;
     906          18 :                 break;
     907             :         }
     908          18 :         case 11:
     909             :         {
     910           0 :                 static const char * const attrs2[] = { "oEMInformation",
     911             :                                                        "forceLogoff",
     912             :                                                        "modifiedCount",
     913             :                                                        "lockoutDuration",
     914             :                                                        "lockOutObservationWindow",
     915             :                                                        "lockoutThreshold",
     916             :                                                        NULL};
     917          18 :                 attrs = attrs2;
     918          18 :                 break;
     919             :         }
     920          35 :         case 12:
     921             :         {
     922           0 :                 static const char * const attrs2[] = { "lockoutDuration",
     923             :                                                        "lockOutObservationWindow",
     924             :                                                        "lockoutThreshold",
     925             :                                                        NULL};
     926          35 :                 attrs = attrs2;
     927          35 :                 break;
     928             :         }
     929          18 :         case 13:
     930             :         {
     931           0 :                 static const char * const attrs2[] = { "modifiedCount",
     932             :                                                        "creationTime",
     933             :                                                        NULL };
     934          18 :                 attrs = attrs2;
     935          18 :                 break;
     936             :         }
     937           0 :         default:
     938             :         {
     939           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
     940             :         }
     941             :         }
     942             : 
     943             :         /* some levels don't need a search */
     944         342 :         if (attrs) {
     945           0 :                 int ret;
     946         286 :                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
     947             :                                       d_state->domain_dn, &dom_msgs, attrs);
     948         286 :                 if (ret == 0) {
     949           0 :                         return NT_STATUS_NO_SUCH_DOMAIN;
     950             :                 }
     951         286 :                 if (ret != 1) {
     952           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     953             :                 }
     954             :         }
     955             : 
     956             :         /* allocate the info structure */
     957         342 :         info = talloc_zero(mem_ctx, union samr_DomainInfo);
     958         342 :         if (info == NULL) {
     959           0 :                 return NT_STATUS_NO_MEMORY;
     960             :         }
     961             : 
     962         342 :         *r->out.info = info;
     963             : 
     964         342 :         switch (r->in.level) {
     965          59 :         case 1:
     966          59 :                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
     967             :                                                  &info->info1);
     968          76 :         case 2:
     969          76 :                 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
     970             :                                                               &info->general);
     971          22 :         case 3:
     972          22 :                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
     973             :                                                  &info->info3);
     974          18 :         case 4:
     975          18 :                 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
     976             :                                                           &info->oem);
     977          19 :         case 5:
     978          19 :                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
     979             :                                                  &info->info5);
     980          19 :         case 6:
     981          19 :                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
     982             :                                                  &info->info6);
     983          19 :         case 7:
     984          19 :                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
     985             :                                                  &info->info7);
     986          21 :         case 8:
     987          21 :                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
     988             :                                                  &info->info8);
     989          18 :         case 9:
     990          18 :                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
     991             :                                                  &info->info9);
     992          18 :         case 11:
     993          18 :                 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
     994             :                                                                &info->general2);
     995          35 :         case 12:
     996          35 :                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
     997             :                                                   &info->info12);
     998          18 :         case 13:
     999          18 :                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
    1000             :                                                   &info->info13);
    1001           0 :         default:
    1002           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
    1003             :         }
    1004             : }
    1005             : 
    1006             : 
    1007             : /*
    1008             :   samr_SetDomainInfo
    1009             : */
    1010         222 : static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    1011             :                        struct samr_SetDomainInfo *r)
    1012             : {
    1013           0 :         struct dcesrv_handle *h;
    1014           0 :         struct samr_domain_state *d_state;
    1015           0 :         struct ldb_message *msg;
    1016           0 :         int ret;
    1017           0 :         struct ldb_context *sam_ctx;
    1018             : 
    1019         222 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    1020             : 
    1021         222 :         d_state = h->data;
    1022         222 :         sam_ctx = d_state->sam_ctx;
    1023             : 
    1024         222 :         msg = ldb_msg_new(mem_ctx);
    1025         222 :         if (msg == NULL) {
    1026           0 :                 return NT_STATUS_NO_MEMORY;
    1027             :         }
    1028             : 
    1029         222 :         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
    1030         222 :         if (!msg->dn) {
    1031           0 :                 return NT_STATUS_NO_MEMORY;
    1032             :         }
    1033             : 
    1034         222 :         switch (r->in.level) {
    1035          85 :         case 1:
    1036          85 :                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
    1037          85 :                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
    1038          85 :                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
    1039          85 :                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
    1040          85 :                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
    1041          85 :                 break;
    1042           7 :         case 3:
    1043           7 :                 SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");
    1044           7 :                 break;
    1045          12 :         case 4:
    1046          12 :                 SET_STRING(msg, oem.oem_information,           "oEMInformation");
    1047          12 :                 break;
    1048             : 
    1049          18 :         case 6:
    1050             :         case 7:
    1051             :         case 9:
    1052             :                 /* No op, we don't know where to set these */
    1053          18 :                 return NT_STATUS_OK;
    1054             : 
    1055          70 :         case 12:
    1056             :                 /*
    1057             :                  * It is not possible to set lockout_duration < lockout_window.
    1058             :                  * (The test is the other way around since the negative numbers
    1059             :                  *  are stored...)
    1060             :                  *
    1061             :                  * TODO:
    1062             :                  *   This check should be moved to the backend, i.e. to some
    1063             :                  *   ldb module under dsdb/samdb/ldb_modules/ .
    1064             :                  *
    1065             :                  * This constraint is documented here for the samr rpc service:
    1066             :                  * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
    1067             :                  * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
    1068             :                  *
    1069             :                  * And here for the ldap backend:
    1070             :                  * MS-ADTS 3.1.1.5.3.2 Constraints
    1071             :                  * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
    1072             :                  */
    1073          70 :                 if (r->in.info->info12.lockout_duration >
    1074          70 :                     r->in.info->info12.lockout_window)
    1075             :                 {
    1076          12 :                         return NT_STATUS_INVALID_PARAMETER;
    1077             :                 }
    1078          58 :                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
    1079          58 :                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
    1080          58 :                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
    1081          58 :                 break;
    1082             : 
    1083          30 :         default:
    1084             :                 /* many info classes are not valid for SetDomainInfo */
    1085          30 :                 return NT_STATUS_INVALID_INFO_CLASS;
    1086             :         }
    1087             : 
    1088             :         /* modify the samdb record */
    1089         162 :         ret = ldb_modify(sam_ctx, msg);
    1090         162 :         if (ret != LDB_SUCCESS) {
    1091           0 :                 DEBUG(1,("Failed to modify record %s: %s\n",
    1092             :                          ldb_dn_get_linearized(d_state->domain_dn),
    1093             :                          ldb_errstring(sam_ctx)));
    1094           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    1095             :         }
    1096             : 
    1097         162 :         return NT_STATUS_OK;
    1098             : }
    1099             : 
    1100             : /*
    1101             :   samr_CreateDomainGroup
    1102             : */
    1103         982 : static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    1104             :                                        struct samr_CreateDomainGroup *r)
    1105             : {
    1106           0 :         NTSTATUS status;
    1107           0 :         struct samr_domain_state *d_state;
    1108           0 :         struct samr_account_state *a_state;
    1109           0 :         struct dcesrv_handle *h;
    1110           0 :         const char *groupname;
    1111           0 :         struct dom_sid *group_sid;
    1112           0 :         struct ldb_dn *group_dn;
    1113           0 :         struct dcesrv_handle *g_handle;
    1114             : 
    1115         982 :         ZERO_STRUCTP(r->out.group_handle);
    1116         982 :         *r->out.rid = 0;
    1117             : 
    1118         982 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    1119             : 
    1120         982 :         d_state = h->data;
    1121             : 
    1122         982 :         if (d_state->builtin) {
    1123         453 :                 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain\n"));
    1124         453 :                 return NT_STATUS_ACCESS_DENIED;
    1125             :         }
    1126             : 
    1127         529 :         groupname = r->in.name->string;
    1128             : 
    1129         529 :         if (groupname == NULL) {
    1130           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1131             :         }
    1132             : 
    1133         529 :         status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
    1134         529 :         if (!NT_STATUS_IS_OK(status)) {
    1135           1 :                 return status;
    1136             :         }
    1137             : 
    1138         528 :         a_state = talloc(mem_ctx, struct samr_account_state);
    1139         528 :         if (!a_state) {
    1140           0 :                 return NT_STATUS_NO_MEMORY;
    1141             :         }
    1142         528 :         a_state->sam_ctx = d_state->sam_ctx;
    1143         528 :         a_state->access_mask = r->in.access_mask;
    1144         528 :         a_state->domain_state = talloc_reference(a_state, d_state);
    1145         528 :         a_state->account_dn = talloc_steal(a_state, group_dn);
    1146             : 
    1147         528 :         a_state->account_name = talloc_steal(a_state, groupname);
    1148             : 
    1149             :         /* create the policy handle */
    1150         528 :         g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_GROUP);
    1151         528 :         if (!g_handle) {
    1152           0 :                 return NT_STATUS_NO_MEMORY;
    1153             :         }
    1154             : 
    1155         528 :         g_handle->data = talloc_steal(g_handle, a_state);
    1156             : 
    1157         528 :         *r->out.group_handle = g_handle->wire_handle;
    1158         528 :         *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
    1159             : 
    1160         528 :         return NT_STATUS_OK;
    1161             : }
    1162             : 
    1163             : 
    1164             : /*
    1165             :   comparison function for sorting SamEntry array
    1166             : */
    1167       31421 : static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
    1168             : {
    1169       31421 :         return e1->idx - e2->idx;
    1170             : }
    1171             : 
    1172        4289 : static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
    1173        4289 :         struct dom_sid *sid1 = NULL;
    1174        4289 :         struct dom_sid *sid2 = NULL;
    1175           0 :         uint32_t rid1;
    1176           0 :         uint32_t rid2;
    1177        4289 :         int res = 0;
    1178           0 :         NTSTATUS status;
    1179        4289 :         TALLOC_CTX *frame = talloc_stackframe();
    1180             : 
    1181        4289 :         sid1 = samdb_result_dom_sid(frame, *m1, "objectSid");
    1182        4289 :         sid2 = samdb_result_dom_sid(frame, *m2, "objectSid");
    1183             : 
    1184             :         /*
    1185             :          * If entries don't have a SID we want to sort them to the end of
    1186             :          * the list.
    1187             :          */
    1188        4289 :         if (sid1 == NULL && sid2 == NULL) {
    1189           0 :                 res = 0;
    1190           0 :                 goto exit;
    1191        4289 :         } else if (sid2 == NULL) {
    1192           0 :                 res = 1;
    1193           0 :                 goto exit;
    1194        4289 :         } else if (sid1 == NULL) {
    1195           0 :                 res = -1;
    1196           0 :                 goto exit;
    1197             :         }
    1198             : 
    1199             :         /*
    1200             :          * Get and compare the rids, if we fail to extract a rid treat it as a
    1201             :          * missing SID and sort to the end of the list
    1202             :          */
    1203        4289 :         status = dom_sid_split_rid(NULL, sid1, NULL, &rid1);
    1204        4289 :         if (!NT_STATUS_IS_OK(status)) {
    1205           0 :                 res = 1;
    1206           0 :                 goto exit;
    1207             :         }
    1208             : 
    1209        4289 :         status = dom_sid_split_rid(NULL, sid2, NULL, &rid2);
    1210        4289 :         if (!NT_STATUS_IS_OK(status)) {
    1211           0 :                 res = -1;
    1212           0 :                 goto exit;
    1213             :         }
    1214             : 
    1215        4289 :         if (rid1 == rid2) {
    1216           0 :                 res = 0;
    1217             :         }
    1218        4289 :         else if (rid1 > rid2) {
    1219        2249 :                 res = 1;
    1220             :         }
    1221             :         else {
    1222        2040 :                 res = -1;
    1223             :         }
    1224        4289 : exit:
    1225        4289 :         TALLOC_FREE(frame);
    1226        4289 :         return res;
    1227             : }
    1228             : 
    1229             : /*
    1230             :   samr_EnumDomainGroups
    1231             : */
    1232         150 : static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    1233             :                                       struct samr_EnumDomainGroups *r)
    1234             : {
    1235           0 :         struct dcesrv_handle *h;
    1236           0 :         struct samr_domain_state *d_state;
    1237           0 :         struct ldb_message **res;
    1238           0 :         uint32_t i;
    1239           0 :         uint32_t count;
    1240           0 :         uint32_t results;
    1241           0 :         uint32_t max_entries;
    1242           0 :         uint32_t remaining_entries;
    1243           0 :         uint32_t resume_handle;
    1244           0 :         struct samr_SamEntry *entries;
    1245         150 :         const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
    1246         150 :         const char * const cache_attrs[] = { "objectSid", "objectGUID", NULL };
    1247           0 :         struct samr_SamArray *sam;
    1248         150 :         struct samr_guid_cache *cache = NULL;
    1249             : 
    1250         150 :         *r->out.resume_handle = 0;
    1251         150 :         *r->out.sam = NULL;
    1252         150 :         *r->out.num_entries = 0;
    1253             : 
    1254         150 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    1255             : 
    1256         150 :         d_state = h->data;
    1257         150 :         cache = &d_state->guid_caches[SAMR_ENUM_DOMAIN_GROUPS_CACHE];
    1258             : 
    1259             :         /*
    1260             :          * If the resume_handle is zero, query the database and cache the
    1261             :          * matching GUID's
    1262             :          */
    1263         150 :         if (*r->in.resume_handle == 0) {
    1264           0 :                 NTSTATUS status;
    1265           0 :                 int ldb_cnt;
    1266          47 :                 clear_guid_cache(cache);
    1267             :                 /*
    1268             :                  * search for all domain groups in this domain.
    1269             :                  */
    1270          47 :                 ldb_cnt = samdb_search_domain(
    1271          47 :                     d_state->sam_ctx,
    1272             :                     mem_ctx,
    1273             :                     d_state->domain_dn,
    1274             :                     &res,
    1275             :                     cache_attrs,
    1276          47 :                     d_state->domain_sid,
    1277             :                     "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
    1278             :                     GTYPE_SECURITY_UNIVERSAL_GROUP,
    1279             :                     GTYPE_SECURITY_GLOBAL_GROUP);
    1280          47 :                 if (ldb_cnt < 0) {
    1281           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1282             :                 }
    1283             :                 /*
    1284             :                  * Sort the results into RID order, while the spec states there
    1285             :                  * is no order, Windows appears to sort the results by RID and
    1286             :                  * so it is possible that there are clients that depend on
    1287             :                  * this ordering
    1288             :                  */
    1289          47 :                 TYPESAFE_QSORT(res, ldb_cnt, compare_msgRid);
    1290             : 
    1291             :                 /*
    1292             :                  * cache the sorted GUID's
    1293             :                  */
    1294          47 :                 status = load_guid_cache(cache, d_state, ldb_cnt, res);
    1295          47 :                 TALLOC_FREE(res);
    1296          47 :                 if (!NT_STATUS_IS_OK(status)) {
    1297           0 :                         return status;
    1298             :                 }
    1299          47 :                 cache->handle = 0;
    1300             :         }
    1301             : 
    1302             : 
    1303             :         /*
    1304             :          * If the resume handle is out of range we return an empty response
    1305             :          * and invalidate the cache.
    1306             :          *
    1307             :          * From the specification:
    1308             :          * Servers SHOULD validate that EnumerationContext is an expected
    1309             :          * value for the server's implementation. Windows does NOT validate
    1310             :          * the input, though the result of malformed information merely results
    1311             :          * in inconsistent output to the client.
    1312             :          */
    1313         150 :         if (*r->in.resume_handle >= cache->size) {
    1314          10 :                 clear_guid_cache(cache);
    1315          10 :                 sam = talloc(mem_ctx, struct samr_SamArray);
    1316          10 :                 if (!sam) {
    1317           0 :                         return NT_STATUS_NO_MEMORY;
    1318             :                 }
    1319          10 :                 sam->entries = NULL;
    1320          10 :                 sam->count = 0;
    1321             : 
    1322          10 :                 *r->out.sam = sam;
    1323          10 :                 *r->out.resume_handle = 0;
    1324          10 :                 return NT_STATUS_OK;
    1325             :         }
    1326             : 
    1327             : 
    1328             :         /*
    1329             :          * Calculate the number of entries to return limit by max_size.
    1330             :          * Note that we use the w2k3 element size value of 54
    1331             :          */
    1332         140 :         max_entries = 1 + (r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER);
    1333         140 :         remaining_entries = cache->size - *r->in.resume_handle;
    1334         140 :         results = MIN(remaining_entries, max_entries);
    1335             : 
    1336             :         /*
    1337             :          * Process the list of result GUID's.
    1338             :          * Read the details of each object and populate the Entries
    1339             :          * for the current level.
    1340             :          */
    1341         140 :         count = 0;
    1342         140 :         resume_handle = *r->in.resume_handle;
    1343         140 :         entries = talloc_array(mem_ctx, struct samr_SamEntry, results);
    1344         140 :         if (entries == NULL) {
    1345           0 :                 clear_guid_cache(cache);
    1346           0 :                 return NT_STATUS_NO_MEMORY;
    1347             :         }
    1348        1102 :         for (i = 0; i < results; i++) {
    1349           0 :                 struct dom_sid *objectsid;
    1350           0 :                 uint32_t rid;
    1351           0 :                 struct ldb_result *rec;
    1352         962 :                 const uint32_t idx = *r->in.resume_handle + i;
    1353           0 :                 int ret;
    1354           0 :                 NTSTATUS status;
    1355         962 :                 const char *name = NULL;
    1356         962 :                 resume_handle++;
    1357             :                 /*
    1358             :                  * Read an object from disk using the GUID as the key
    1359             :                  *
    1360             :                  * If the object can not be read, or it does not have a SID
    1361             :                  * it is ignored.
    1362             :                  *
    1363             :                  * As a consequence of this, if all the remaining GUID's
    1364             :                  * have been deleted an empty result will be returned.
    1365             :                  * i.e. even if the previous call returned a non zero
    1366             :                  * resume_handle it is possible for no results to be returned.
    1367             :                  *
    1368             :                  */
    1369         962 :                 ret = dsdb_search_by_dn_guid(d_state->sam_ctx,
    1370             :                                              mem_ctx,
    1371             :                                              &rec,
    1372         962 :                                              &cache->entries[idx],
    1373             :                                              attrs,
    1374             :                                              0);
    1375         962 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    1376           0 :                         struct GUID_txt_buf guid_buf;
    1377           1 :                         DBG_WARNING(
    1378             :                             "GUID [%s] not found\n",
    1379             :                             GUID_buf_string(&cache->entries[idx], &guid_buf));
    1380           1 :                         continue;
    1381         961 :                 } else if (ret != LDB_SUCCESS) {
    1382           0 :                         clear_guid_cache(cache);
    1383           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1384             :                 }
    1385             : 
    1386         961 :                 objectsid = samdb_result_dom_sid(mem_ctx,
    1387         961 :                                                  rec->msgs[0],
    1388             :                                                  "objectSID");
    1389         961 :                 if (objectsid == NULL) {
    1390           0 :                         struct GUID_txt_buf guid_buf;
    1391           0 :                         DBG_WARNING(
    1392             :                             "objectSID for GUID [%s] not found\n",
    1393             :                             GUID_buf_string(&cache->entries[idx], &guid_buf));
    1394           0 :                         continue;
    1395             :                 }
    1396         961 :                 status = dom_sid_split_rid(NULL,
    1397             :                                            objectsid,
    1398             :                                            NULL,
    1399             :                                            &rid);
    1400         961 :                 if (!NT_STATUS_IS_OK(status)) {
    1401           0 :                         struct dom_sid_buf sid_buf;
    1402           0 :                         struct GUID_txt_buf guid_buf;
    1403           0 :                         DBG_WARNING(
    1404             :                             "objectSID [%s] for GUID [%s] invalid\n",
    1405             :                             dom_sid_str_buf(objectsid, &sid_buf),
    1406             :                             GUID_buf_string(&cache->entries[idx], &guid_buf));
    1407           0 :                         continue;
    1408             :                 }
    1409             : 
    1410         961 :                 entries[count].idx = rid;
    1411         961 :                 name = ldb_msg_find_attr_as_string(
    1412         961 :                     rec->msgs[0], "sAMAccountName", "");
    1413         961 :                 entries[count].name.string = talloc_strdup(entries, name);
    1414         961 :                 count++;
    1415             :         }
    1416             : 
    1417         140 :         sam = talloc(mem_ctx, struct samr_SamArray);
    1418         140 :         if (!sam) {
    1419           0 :                 clear_guid_cache(cache);
    1420           0 :                 return NT_STATUS_NO_MEMORY;
    1421             :         }
    1422             : 
    1423         140 :         sam->entries = entries;
    1424         140 :         sam->count = count;
    1425             : 
    1426         140 :         *r->out.sam = sam;
    1427         140 :         *r->out.resume_handle = resume_handle;
    1428         140 :         *r->out.num_entries = count;
    1429             : 
    1430             :         /*
    1431             :          * Signal no more results by returning zero resume handle,
    1432             :          * the cache is also cleared at this point
    1433             :          */
    1434         140 :         if (*r->out.resume_handle >= cache->size) {
    1435          36 :                 *r->out.resume_handle = 0;
    1436          36 :                 clear_guid_cache(cache);
    1437          36 :                 return NT_STATUS_OK;
    1438             :         }
    1439             :         /*
    1440             :          * There are more results to be returned.
    1441             :          */
    1442         104 :         return STATUS_MORE_ENTRIES;
    1443             : }
    1444             : 
    1445             : 
    1446             : /*
    1447             :   samr_CreateUser2
    1448             : 
    1449             :   This call uses transactions to ensure we don't get a new conflicting
    1450             :   user while we are processing this, and to ensure the user either
    1451             :   completely exists, or does not.
    1452             : */
    1453        1765 : static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    1454             :                                  struct samr_CreateUser2 *r)
    1455             : {
    1456          72 :         NTSTATUS status;
    1457          72 :         struct samr_domain_state *d_state;
    1458          72 :         struct samr_account_state *a_state;
    1459          72 :         struct dcesrv_handle *h;
    1460          72 :         struct ldb_dn *dn;
    1461          72 :         struct dom_sid *sid;
    1462          72 :         struct dcesrv_handle *u_handle;
    1463          72 :         const char *account_name;
    1464             : 
    1465        1765 :         ZERO_STRUCTP(r->out.user_handle);
    1466        1765 :         *r->out.access_granted = 0;
    1467        1765 :         *r->out.rid = 0;
    1468             : 
    1469        1765 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    1470             : 
    1471        1765 :         d_state = h->data;
    1472             : 
    1473        1765 :         if (d_state->builtin) {
    1474         603 :                 DEBUG(5, ("Cannot create a user in the BUILTIN domain\n"));
    1475         603 :                 return NT_STATUS_ACCESS_DENIED;
    1476        1162 :         } else if (r->in.acct_flags == ACB_DOMTRUST) {
    1477             :                 /* Domain trust accounts must be created by the LSA calls */
    1478          10 :                 return NT_STATUS_ACCESS_DENIED;
    1479             :         }
    1480        1152 :         account_name = r->in.account_name->string;
    1481             : 
    1482        1152 :         if (account_name == NULL) {
    1483           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1484             :         }
    1485             : 
    1486        1152 :         status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
    1487             :                                &sid, &dn);
    1488        1152 :         if (!NT_STATUS_IS_OK(status)) {
    1489         113 :                 return status;
    1490             :         }
    1491        1039 :         a_state = talloc(mem_ctx, struct samr_account_state);
    1492        1039 :         if (!a_state) {
    1493           0 :                 return NT_STATUS_NO_MEMORY;
    1494             :         }
    1495        1039 :         a_state->sam_ctx = d_state->sam_ctx;
    1496        1039 :         a_state->access_mask = r->in.access_mask;
    1497        1039 :         a_state->domain_state = talloc_reference(a_state, d_state);
    1498        1039 :         a_state->account_dn = talloc_steal(a_state, dn);
    1499             : 
    1500        1039 :         a_state->account_name = talloc_steal(a_state, account_name);
    1501        1039 :         if (!a_state->account_name) {
    1502           0 :                 return NT_STATUS_NO_MEMORY;
    1503             :         }
    1504             : 
    1505             :         /* create the policy handle */
    1506        1039 :         u_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_USER);
    1507        1039 :         if (!u_handle) {
    1508           0 :                 return NT_STATUS_NO_MEMORY;
    1509             :         }
    1510             : 
    1511        1039 :         u_handle->data = talloc_steal(u_handle, a_state);
    1512             : 
    1513        1039 :         *r->out.user_handle = u_handle->wire_handle;
    1514        1039 :         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
    1515             : 
    1516        1039 :         *r->out.rid = sid->sub_auths[sid->num_auths-1];
    1517             : 
    1518        1039 :         return NT_STATUS_OK;
    1519             : }
    1520             : 
    1521             : 
    1522             : /*
    1523             :   samr_CreateUser
    1524             : */
    1525         939 : static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    1526             :                                 struct samr_CreateUser *r)
    1527             : {
    1528           0 :         struct samr_CreateUser2 r2;
    1529         939 :         uint32_t access_granted = 0;
    1530             : 
    1531             : 
    1532             :         /* a simple wrapper around samr_CreateUser2 works nicely */
    1533             : 
    1534         939 :         r2 = (struct samr_CreateUser2) {
    1535         939 :                 .in.domain_handle = r->in.domain_handle,
    1536         939 :                 .in.account_name = r->in.account_name,
    1537             :                 .in.acct_flags = ACB_NORMAL,
    1538         939 :                 .in.access_mask = r->in.access_mask,
    1539         939 :                 .out.user_handle = r->out.user_handle,
    1540             :                 .out.access_granted = &access_granted,
    1541         939 :                 .out.rid = r->out.rid
    1542             :         };
    1543             : 
    1544         939 :         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
    1545             : }
    1546             : 
    1547             : struct enum_dom_users_ctx {
    1548             :         struct samr_SamEntry *entries;
    1549             :         uint32_t num_entries;
    1550             :         uint32_t acct_flags;
    1551             :         struct dom_sid *domain_sid;
    1552             : };
    1553             : 
    1554             : static int user_iterate_callback(struct ldb_request *req,
    1555             :                                  struct ldb_reply *ares);
    1556             : 
    1557             : /*
    1558             :  * Iterate users and add all those that match a domain SID and pass an acct
    1559             :  * flags check to an array of SamEntry objects.
    1560             :  */
    1561        4191 : static int user_iterate_callback(struct ldb_request *req,
    1562             :                                  struct ldb_reply *ares)
    1563             : {
    1564           0 :         struct enum_dom_users_ctx *ac =\
    1565        4191 :                 talloc_get_type(req->context, struct enum_dom_users_ctx);
    1566        4191 :         int ret = LDB_ERR_OPERATIONS_ERROR;
    1567             : 
    1568        4191 :         if (!ares) {
    1569           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    1570             :         }
    1571        4191 :         if (ares->error != LDB_SUCCESS) {
    1572           0 :                 return ldb_request_done(req, ares->error);
    1573             :         }
    1574             : 
    1575        4191 :         switch (ares->type) {
    1576        3912 :         case LDB_REPLY_ENTRY:
    1577             :         {
    1578        3912 :                 struct ldb_message *msg = ares->message;
    1579           0 :                 const struct ldb_val *val;
    1580           0 :                 struct samr_SamEntry *ent;
    1581           0 :                 struct dom_sid objectsid;
    1582           0 :                 uint32_t rid;
    1583        3912 :                 size_t entries_array_len = 0;
    1584           0 :                 NTSTATUS status;
    1585           0 :                 ssize_t sid_size;
    1586             : 
    1587        3912 :                 if (ac->acct_flags && ((samdb_result_acct_flags(msg, NULL) &
    1588        3269 :                                         ac->acct_flags) == 0)) {
    1589         247 :                         ret = LDB_SUCCESS;
    1590         247 :                         break;
    1591             :                 }
    1592             : 
    1593        3665 :                 val = ldb_msg_find_ldb_val(msg, "objectSID");
    1594        3665 :                 if (val == NULL) {
    1595           0 :                         DBG_WARNING("objectSID for DN %s not found\n",
    1596             :                                     ldb_dn_get_linearized(msg->dn));
    1597           0 :                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    1598           0 :                         break;
    1599             :                 }
    1600             : 
    1601        3665 :                 sid_size = sid_parse(val->data, val->length, &objectsid);
    1602        3665 :                 if (sid_size == -1) {
    1603           0 :                         struct dom_sid_buf sid_buf;
    1604           0 :                         DBG_WARNING("objectsid [%s] for DN [%s] invalid\n",
    1605             :                                     dom_sid_str_buf(&objectsid, &sid_buf),
    1606             :                                     ldb_dn_get_linearized(msg->dn));
    1607           0 :                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    1608           0 :                         break;
    1609             :                 }
    1610             : 
    1611        3665 :                 if (!dom_sid_in_domain(ac->domain_sid, &objectsid)) {
    1612             :                         /* Ignore if user isn't in the domain */
    1613           0 :                         ret = LDB_SUCCESS;
    1614           0 :                         break;
    1615             :                 }
    1616             : 
    1617        3665 :                 status = dom_sid_split_rid(ares, &objectsid, NULL, &rid);
    1618        3665 :                 if (!NT_STATUS_IS_OK(status)) {
    1619           0 :                         struct dom_sid_buf sid_buf;
    1620           0 :                         DBG_WARNING("Couldn't split RID from "
    1621             :                                     "SID [%s] of DN [%s]\n",
    1622             :                                     dom_sid_str_buf(&objectsid, &sid_buf),
    1623             :                                     ldb_dn_get_linearized(msg->dn));
    1624           0 :                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    1625           0 :                         break;
    1626             :                 }
    1627             : 
    1628        3665 :                 entries_array_len = talloc_array_length(ac->entries);
    1629        3665 :                 if (ac->num_entries >= entries_array_len) {
    1630          11 :                         if (entries_array_len * 2 < entries_array_len) {
    1631           0 :                                 ret = ldb_request_done(req,
    1632             :                                         LDB_ERR_OPERATIONS_ERROR);
    1633           0 :                                 break;
    1634             :                         }
    1635          11 :                         ac->entries = talloc_realloc(ac,
    1636             :                                                      ac->entries,
    1637             :                                                      struct samr_SamEntry,
    1638             :                                                      entries_array_len * 2);
    1639          11 :                         if (ac->entries == NULL) {
    1640           0 :                                 ret = ldb_request_done(req,
    1641             :                                         LDB_ERR_OPERATIONS_ERROR);
    1642           0 :                                 break;
    1643             :                         }
    1644             :                 }
    1645             : 
    1646        3665 :                 ent = &(ac->entries[ac->num_entries++]);
    1647        3665 :                 val = ldb_msg_find_ldb_val(msg, "samaccountname");
    1648        3665 :                 if (val == NULL) {
    1649           0 :                         DBG_WARNING("samaccountname attribute not found\n");
    1650           0 :                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    1651           0 :                         break;
    1652             :                 }
    1653        3665 :                 ent->name.string = talloc_steal(ac->entries,
    1654             :                                                 (char *)val->data);
    1655        3665 :                 ent->idx = rid;
    1656        3665 :                 ret = LDB_SUCCESS;
    1657        3665 :                 break;
    1658             :         }
    1659          98 :         case LDB_REPLY_DONE:
    1660             :         {
    1661          98 :                 if (ac->num_entries != 0 &&
    1662          65 :                     ac->num_entries != talloc_array_length(ac->entries)) {
    1663          65 :                         ac->entries = talloc_realloc(ac,
    1664             :                                                      ac->entries,
    1665             :                                                      struct samr_SamEntry,
    1666             :                                                      ac->num_entries);
    1667          65 :                         if (ac->entries == NULL) {
    1668           0 :                                 ret = ldb_request_done(req,
    1669             :                                         LDB_ERR_OPERATIONS_ERROR);
    1670           0 :                                 break;
    1671             :                         }
    1672             :                 }
    1673          98 :                 ret = ldb_request_done(req, LDB_SUCCESS);
    1674          98 :                 break;
    1675             :         }
    1676         181 :         case LDB_REPLY_REFERRAL:
    1677             :         {
    1678         181 :                 ret = LDB_SUCCESS;
    1679         181 :                 break;
    1680             :         }
    1681           0 :         default:
    1682             :                 /* Doesn't happen */
    1683           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
    1684             :         }
    1685        4191 :         TALLOC_FREE(ares);
    1686             : 
    1687        4191 :         return ret;
    1688             : }
    1689             : 
    1690             : /*
    1691             :  * samr_EnumDomainUsers
    1692             :  * The previous implementation did an initial search and stored a list of
    1693             :  * matching GUIDs on the connection handle's domain state, then did direct
    1694             :  * GUID lookups for each record in a page indexed by resume_handle. That
    1695             :  * approach was memory efficient, requiring only 16 bytes per record, but
    1696             :  * was too slow for winbind which needs this RPC call for getpwent.
    1697             :  *
    1698             :  * Now we use an iterate pattern to populate a cached list of the rids and
    1699             :  * names for each record. This improves runtime performance but requires
    1700             :  * about 200 bytes per record which will mean for a 100k database we use
    1701             :  * about 2MB, which is fine. The speedup achieved by this new approach is
    1702             :  * around 50%.
    1703             :  */
    1704         148 : static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call,
    1705             :                                             TALLOC_CTX *mem_ctx,
    1706             :                                             struct samr_EnumDomainUsers *r)
    1707             : {
    1708           0 :         struct dcesrv_handle *h;
    1709           0 :         struct samr_domain_state *d_state;
    1710           0 :         uint32_t results;
    1711           0 :         uint32_t max_entries;
    1712           0 :         uint32_t num_entries;
    1713           0 :         uint32_t remaining_entries;
    1714           0 :         struct samr_SamEntry *entries;
    1715         148 :         const char * const attrs[] = { "objectSid", "sAMAccountName",
    1716             :                 "userAccountControl", NULL };
    1717           0 :         struct samr_SamArray *sam;
    1718           0 :         struct ldb_request *req;
    1719             : 
    1720         148 :         *r->out.resume_handle = 0;
    1721         148 :         *r->out.sam = NULL;
    1722         148 :         *r->out.num_entries = 0;
    1723             : 
    1724         148 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    1725             : 
    1726         148 :         d_state = h->data;
    1727         148 :         entries = d_state->domain_users_cached;
    1728             : 
    1729             :         /*
    1730             :          * If the resume_handle is zero, query the database and cache the
    1731             :          * matching entries.
    1732             :          */
    1733         148 :         if (*r->in.resume_handle == 0) {
    1734           0 :                 int ret;
    1735           0 :                 struct enum_dom_users_ctx *ac;
    1736          98 :                 if (entries != NULL) {
    1737          38 :                         talloc_free(entries);
    1738          38 :                         d_state->domain_users_cached = NULL;
    1739             :                 }
    1740             : 
    1741          98 :                 ac = talloc(mem_ctx, struct enum_dom_users_ctx);
    1742          98 :                 ac->num_entries = 0;
    1743          98 :                 ac->domain_sid = d_state->domain_sid;
    1744          98 :                 ac->entries = talloc_array(ac,
    1745             :                                            struct samr_SamEntry,
    1746             :                                            100);
    1747          98 :                 if (ac->entries == NULL) {
    1748           0 :                         talloc_free(ac);
    1749           0 :                         return NT_STATUS_NO_MEMORY;
    1750             :                 }
    1751          98 :                 ac->acct_flags = r->in.acct_flags;
    1752             : 
    1753          98 :                 ret = ldb_build_search_req(&req,
    1754          98 :                                            d_state->sam_ctx,
    1755             :                                            mem_ctx,
    1756             :                                            d_state->domain_dn,
    1757             :                                            LDB_SCOPE_SUBTREE,
    1758             :                                            "(objectClass=user)",
    1759             :                                            attrs,
    1760             :                                            NULL,
    1761             :                                            ac,
    1762             :                                            user_iterate_callback,
    1763             :                                            NULL);
    1764          98 :                 if (ret != LDB_SUCCESS) {
    1765           0 :                         talloc_free(ac);
    1766           0 :                         return dsdb_ldb_err_to_ntstatus(ret);
    1767             :                 }
    1768             : 
    1769          98 :                 ret = ldb_request(d_state->sam_ctx, req);
    1770          98 :                 if (ret != LDB_SUCCESS) {
    1771           0 :                         talloc_free(ac);
    1772           0 :                         return dsdb_ldb_err_to_ntstatus(ret);
    1773             :                 }
    1774             : 
    1775          98 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    1776          98 :                 if (ret != LDB_SUCCESS) {
    1777           0 :                         return dsdb_ldb_err_to_ntstatus(ret);
    1778             :                 }
    1779             : 
    1780          98 :                 if (ac->num_entries == 0) {
    1781          33 :                         DBG_WARNING("No users in domain %s\n",
    1782             :                                     ldb_dn_get_linearized(d_state->domain_dn));
    1783          33 :                         talloc_free(ac);
    1784             : 
    1785             :                         /*
    1786             :                          * test_EnumDomainUsers_all() expects that r.out.sam
    1787             :                          * should be non-NULL, even if we have no entries.
    1788             :                          */
    1789          33 :                         sam = talloc_zero(mem_ctx, struct samr_SamArray);
    1790          33 :                         if (sam == NULL) {
    1791           0 :                                 return NT_STATUS_NO_MEMORY;
    1792             :                         }
    1793          33 :                         *r->out.sam = sam;
    1794             : 
    1795          33 :                         return NT_STATUS_OK;
    1796             :                 }
    1797             : 
    1798          65 :                 entries = talloc_steal(d_state, ac->entries);
    1799          65 :                 d_state->domain_users_cached = entries;
    1800          65 :                 num_entries = ac->num_entries;
    1801          65 :                 talloc_free(ac);
    1802             : 
    1803             :                 /*
    1804             :                  * Sort the entries into RID order, while the spec states there
    1805             :                  * is no order, Windows appears to sort the results by RID and
    1806             :                  * so it is possible that there are clients that depend on
    1807             :                  * this ordering
    1808             :                  */
    1809          65 :                 TYPESAFE_QSORT(entries, num_entries, compare_SamEntry);
    1810             :         } else {
    1811          50 :                 num_entries = talloc_array_length(entries);
    1812             :         }
    1813             : 
    1814             :         /*
    1815             :          * If the resume handle is out of range we return an empty response
    1816             :          * and invalidate the cache.
    1817             :          *
    1818             :          * From the specification:
    1819             :          * Servers SHOULD validate that EnumerationContext is an expected
    1820             :          * value for the server's implementation. Windows does NOT validate
    1821             :          * the input, though the result of malformed information merely results
    1822             :          * in inconsistent output to the client.
    1823             :          */
    1824         115 :         if (*r->in.resume_handle >= num_entries) {
    1825           1 :                 talloc_free(entries);
    1826           1 :                 d_state->domain_users_cached = NULL;
    1827           1 :                 sam = talloc(mem_ctx, struct samr_SamArray);
    1828           1 :                 if (!sam) {
    1829           0 :                         return NT_STATUS_NO_MEMORY;
    1830             :                 }
    1831           1 :                 sam->entries = NULL;
    1832           1 :                 sam->count = 0;
    1833             : 
    1834           1 :                 *r->out.sam = sam;
    1835           1 :                 *r->out.resume_handle = 0;
    1836           1 :                 return NT_STATUS_OK;
    1837             :         }
    1838             : 
    1839             :         /*
    1840             :          * Calculate the number of entries to return limit by max_size.
    1841             :          * Note that we use the w2k3 element size value of 54
    1842             :          */
    1843         114 :         max_entries = 1 + (r->in.max_size / SAMR_ENUM_USERS_MULTIPLIER);
    1844         114 :         remaining_entries = num_entries - *r->in.resume_handle;
    1845         114 :         results = MIN(remaining_entries, max_entries);
    1846             : 
    1847         114 :         sam = talloc(mem_ctx, struct samr_SamArray);
    1848         114 :         if (!sam) {
    1849           0 :                 d_state->domain_users_cached = NULL;
    1850           0 :                 return NT_STATUS_NO_MEMORY;
    1851             :         }
    1852             : 
    1853         114 :         sam->entries = entries + *r->in.resume_handle;
    1854         114 :         sam->count = results;
    1855             : 
    1856         114 :         *r->out.sam = sam;
    1857         114 :         *r->out.resume_handle = *r->in.resume_handle + results;
    1858         114 :         *r->out.num_entries = results;
    1859             : 
    1860             :         /*
    1861             :          * Signal no more results by returning zero resume handle,
    1862             :          * the cache is also cleared at this point
    1863             :          */
    1864         114 :         if (*r->out.resume_handle >= num_entries) {
    1865          64 :                 *r->out.resume_handle = 0;
    1866          64 :                 return NT_STATUS_OK;
    1867             :         }
    1868             :         /*
    1869             :          * There are more results to be returned.
    1870             :          */
    1871          50 :         return STATUS_MORE_ENTRIES;
    1872             : }
    1873             : 
    1874             : 
    1875             : /*
    1876             :   samr_CreateDomAlias
    1877             : */
    1878         906 : static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    1879             :                        struct samr_CreateDomAlias *r)
    1880             : {
    1881           0 :         struct samr_domain_state *d_state;
    1882           0 :         struct samr_account_state *a_state;
    1883           0 :         struct dcesrv_handle *h;
    1884           0 :         const char *alias_name;
    1885           0 :         struct dom_sid *sid;
    1886           0 :         struct dcesrv_handle *a_handle;
    1887           0 :         struct ldb_dn *dn;
    1888           0 :         NTSTATUS status;
    1889             : 
    1890         906 :         ZERO_STRUCTP(r->out.alias_handle);
    1891         906 :         *r->out.rid = 0;
    1892             : 
    1893         906 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    1894             : 
    1895         906 :         d_state = h->data;
    1896             : 
    1897         906 :         if (d_state->builtin) {
    1898         453 :                 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain\n"));
    1899         453 :                 return NT_STATUS_ACCESS_DENIED;
    1900             :         }
    1901             : 
    1902         453 :         alias_name = r->in.alias_name->string;
    1903             : 
    1904         453 :         if (alias_name == NULL) {
    1905           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1906             :         }
    1907             : 
    1908         453 :         status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
    1909         453 :         if (!NT_STATUS_IS_OK(status)) {
    1910           0 :                 return status;
    1911             :         }
    1912             : 
    1913         453 :         a_state = talloc(mem_ctx, struct samr_account_state);
    1914         453 :         if (!a_state) {
    1915           0 :                 return NT_STATUS_NO_MEMORY;
    1916             :         }
    1917             : 
    1918         453 :         a_state->sam_ctx = d_state->sam_ctx;
    1919         453 :         a_state->access_mask = r->in.access_mask;
    1920         453 :         a_state->domain_state = talloc_reference(a_state, d_state);
    1921         453 :         a_state->account_dn = talloc_steal(a_state, dn);
    1922             : 
    1923         453 :         a_state->account_name = talloc_steal(a_state, alias_name);
    1924             : 
    1925             :         /* create the policy handle */
    1926         453 :         a_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_ALIAS);
    1927         453 :         if (a_handle == NULL)
    1928           0 :                 return NT_STATUS_NO_MEMORY;
    1929             : 
    1930         453 :         a_handle->data = talloc_steal(a_handle, a_state);
    1931             : 
    1932         453 :         *r->out.alias_handle = a_handle->wire_handle;
    1933             : 
    1934         453 :         *r->out.rid = sid->sub_auths[sid->num_auths-1];
    1935             : 
    1936         453 :         return NT_STATUS_OK;
    1937             : }
    1938             : 
    1939             : 
    1940             : /*
    1941             :   samr_EnumDomainAliases
    1942             : */
    1943          49 : static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    1944             :                        struct samr_EnumDomainAliases *r)
    1945             : {
    1946           0 :         struct dcesrv_handle *h;
    1947           0 :         struct samr_domain_state *d_state;
    1948           0 :         struct ldb_message **res;
    1949           0 :         int i, ldb_cnt;
    1950           0 :         uint32_t first, count;
    1951           0 :         struct samr_SamEntry *entries;
    1952          49 :         const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
    1953           0 :         struct samr_SamArray *sam;
    1954             : 
    1955          49 :         *r->out.resume_handle = 0;
    1956          49 :         *r->out.sam = NULL;
    1957          49 :         *r->out.num_entries = 0;
    1958             : 
    1959          49 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    1960             : 
    1961          49 :         d_state = h->data;
    1962             : 
    1963             :         /* search for all domain aliases in this domain. This could possibly be
    1964             :            cached and resumed based on resume_key */
    1965          49 :         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
    1966             :                                       &res, attrs,
    1967          49 :                                       d_state->domain_sid,
    1968             :                                       "(&(|(grouptype=%d)(grouptype=%d)))"
    1969             :                                       "(objectclass=group))",
    1970             :                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
    1971             :                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
    1972          49 :         if (ldb_cnt < 0) {
    1973           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1974             :         }
    1975             : 
    1976             :         /* convert to SamEntry format */
    1977          49 :         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
    1978          49 :         if (!entries) {
    1979           0 :                 return NT_STATUS_NO_MEMORY;
    1980             :         }
    1981             : 
    1982          49 :         count = 0;
    1983             : 
    1984        1003 :         for (i=0;i<ldb_cnt;i++) {
    1985           0 :                 struct dom_sid *alias_sid;
    1986             : 
    1987         954 :                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
    1988             :                                                  "objectSid");
    1989             : 
    1990         954 :                 if (alias_sid == NULL) {
    1991           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1992             :                 }
    1993             : 
    1994         954 :                 entries[count].idx =
    1995         954 :                         alias_sid->sub_auths[alias_sid->num_auths-1];
    1996        1908 :                 entries[count].name.string =
    1997         954 :                         ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
    1998         954 :                 count += 1;
    1999             :         }
    2000             : 
    2001             :         /* sort the results by rid */
    2002          49 :         TYPESAFE_QSORT(entries, count, compare_SamEntry);
    2003             : 
    2004             :         /* find the first entry to return */
    2005          49 :         for (first=0;
    2006          59 :              first<count && entries[first].idx <= *r->in.resume_handle;
    2007          10 :              first++) ;
    2008             : 
    2009             :         /* return the rest, limit by max_size. Note that we
    2010             :            use the w2k3 element size value of 54 */
    2011          49 :         *r->out.num_entries = count - first;
    2012          49 :         *r->out.num_entries = MIN(*r->out.num_entries,
    2013             :                                   1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
    2014             : 
    2015          49 :         sam = talloc(mem_ctx, struct samr_SamArray);
    2016          49 :         if (!sam) {
    2017           0 :                 return NT_STATUS_NO_MEMORY;
    2018             :         }
    2019             : 
    2020          49 :         sam->entries = entries+first;
    2021          49 :         sam->count = *r->out.num_entries;
    2022             : 
    2023          49 :         *r->out.sam = sam;
    2024             : 
    2025          49 :         if (first == count) {
    2026           0 :                 return NT_STATUS_OK;
    2027             :         }
    2028             : 
    2029          49 :         if (*r->out.num_entries < count - first) {
    2030           5 :                 *r->out.resume_handle =
    2031           5 :                         entries[first+*r->out.num_entries-1].idx;
    2032           5 :                 return STATUS_MORE_ENTRIES;
    2033             :         }
    2034             : 
    2035          44 :         return NT_STATUS_OK;
    2036             : }
    2037             : 
    2038             : 
    2039             : /*
    2040             :   samr_GetAliasMembership
    2041             : */
    2042         257 : static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2043             :                        struct samr_GetAliasMembership *r)
    2044             : {
    2045           0 :         struct dcesrv_handle *h;
    2046           0 :         struct samr_domain_state *d_state;
    2047           0 :         char *filter;
    2048         257 :         const char * const attrs[] = { "objectSid", NULL };
    2049           0 :         struct ldb_message **res;
    2050           0 :         uint32_t i;
    2051         257 :         int count = 0;
    2052             : 
    2053         257 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    2054             : 
    2055         257 :         d_state = h->data;
    2056             : 
    2057         257 :         filter = talloc_asprintf(mem_ctx,
    2058             :                                  "(&(|(grouptype=%d)(grouptype=%d))"
    2059             :                                  "(objectclass=group)(|",
    2060             :                                  GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
    2061             :                                  GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
    2062         257 :         if (filter == NULL) {
    2063           0 :                 return NT_STATUS_NO_MEMORY;
    2064             :         }
    2065             : 
    2066        1057 :         for (i=0; i<r->in.sids->num_sids; i++) {
    2067           0 :                 struct dom_sid_buf buf;
    2068             : 
    2069         800 :                 filter = talloc_asprintf_append(
    2070             :                         filter,
    2071             :                         "(member=<SID=%s>)",
    2072         800 :                         dom_sid_str_buf(r->in.sids->sids[i].sid, &buf));
    2073             : 
    2074         800 :                 if (filter == NULL) {
    2075           0 :                         return NT_STATUS_NO_MEMORY;
    2076             :                 }
    2077             :         }
    2078             : 
    2079             :         /* Find out if we had at least one valid member SID passed - otherwise
    2080             :          * just skip the search. */
    2081         257 :         if (strstr(filter, "member") != NULL) {
    2082         235 :                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
    2083         235 :                                             &res, attrs, d_state->domain_sid,
    2084             :                                             "%s))", filter);
    2085         235 :                 if (count < 0) {
    2086           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2087             :                 }
    2088             :         }
    2089             : 
    2090         257 :         r->out.rids->count = 0;
    2091         257 :         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
    2092         257 :         if (r->out.rids->ids == NULL)
    2093           0 :                 return NT_STATUS_NO_MEMORY;
    2094             : 
    2095         421 :         for (i=0; i<count; i++) {
    2096           0 :                 struct dom_sid *alias_sid;
    2097             : 
    2098         164 :                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
    2099         164 :                 if (alias_sid == NULL) {
    2100           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2101             :                 }
    2102             : 
    2103         164 :                 r->out.rids->ids[r->out.rids->count] =
    2104         164 :                         alias_sid->sub_auths[alias_sid->num_auths-1];
    2105         164 :                 r->out.rids->count += 1;
    2106             :         }
    2107             : 
    2108         257 :         return NT_STATUS_OK;
    2109             : }
    2110             : 
    2111             : 
    2112             : /*
    2113             :   samr_LookupNames
    2114             : */
    2115        5097 : static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2116             :                                  struct samr_LookupNames *r)
    2117             : {
    2118          17 :         struct dcesrv_handle *h;
    2119          17 :         struct samr_domain_state *d_state;
    2120          17 :         uint32_t i, num_mapped;
    2121        5097 :         NTSTATUS status = NT_STATUS_OK;
    2122        5097 :         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
    2123          17 :         int count;
    2124             : 
    2125        5097 :         ZERO_STRUCTP(r->out.rids);
    2126        5097 :         ZERO_STRUCTP(r->out.types);
    2127             : 
    2128        5097 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    2129             : 
    2130        5097 :         d_state = h->data;
    2131             : 
    2132        5097 :         if (r->in.num_names == 0) {
    2133         325 :                 return NT_STATUS_OK;
    2134             :         }
    2135             : 
    2136        4772 :         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
    2137        4772 :         r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
    2138        4772 :         if (!r->out.rids->ids || !r->out.types->ids) {
    2139           0 :                 return NT_STATUS_NO_MEMORY;
    2140             :         }
    2141        4772 :         r->out.rids->count = r->in.num_names;
    2142        4772 :         r->out.types->count = r->in.num_names;
    2143             : 
    2144        4772 :         num_mapped = 0;
    2145             : 
    2146       10224 :         for (i=0;i<r->in.num_names;i++) {
    2147          17 :                 struct ldb_message **res;
    2148          17 :                 struct dom_sid *sid;
    2149          17 :                 uint32_t atype, rtype;
    2150             : 
    2151        5452 :                 r->out.rids->ids[i] = 0;
    2152        5452 :                 r->out.types->ids[i] = SID_NAME_UNKNOWN;
    2153             : 
    2154        5452 :                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
    2155             :                                      "sAMAccountName=%s",
    2156        5452 :                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
    2157        5452 :                 if (count != 1) {
    2158        3967 :                         status = STATUS_SOME_UNMAPPED;
    2159        3967 :                         continue;
    2160             :                 }
    2161             : 
    2162        1485 :                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
    2163        1485 :                 if (sid == NULL) {
    2164           0 :                         status = STATUS_SOME_UNMAPPED;
    2165           0 :                         continue;
    2166             :                 }
    2167             : 
    2168        1485 :                 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
    2169        1485 :                 if (atype == 0) {
    2170           0 :                         status = STATUS_SOME_UNMAPPED;
    2171           0 :                         continue;
    2172             :                 }
    2173             : 
    2174        1485 :                 rtype = ds_atype_map(atype);
    2175             : 
    2176        1485 :                 if (rtype == SID_NAME_UNKNOWN) {
    2177           0 :                         status = STATUS_SOME_UNMAPPED;
    2178           0 :                         continue;
    2179             :                 }
    2180             : 
    2181        1485 :                 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
    2182        1485 :                 r->out.types->ids[i] = rtype;
    2183        1485 :                 num_mapped++;
    2184             :         }
    2185             : 
    2186        4772 :         if (num_mapped == 0) {
    2187        3323 :                 return NT_STATUS_NONE_MAPPED;
    2188             :         }
    2189        1449 :         return status;
    2190             : }
    2191             : 
    2192             : 
    2193             : /*
    2194             :   samr_LookupRids
    2195             : */
    2196         259 : static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2197             :                        struct samr_LookupRids *r)
    2198             : {
    2199           0 :         NTSTATUS status;
    2200           0 :         struct dcesrv_handle *h;
    2201           0 :         struct samr_domain_state *d_state;
    2202           0 :         const char **names;
    2203           0 :         struct lsa_String *lsa_names;
    2204           0 :         enum lsa_SidType *ids;
    2205             : 
    2206         259 :         ZERO_STRUCTP(r->out.names);
    2207         259 :         ZERO_STRUCTP(r->out.types);
    2208             : 
    2209         259 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    2210             : 
    2211         259 :         d_state = h->data;
    2212             : 
    2213         259 :         if (r->in.num_rids == 0)
    2214           7 :                 return NT_STATUS_OK;
    2215             : 
    2216         252 :         lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
    2217         252 :         names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
    2218         252 :         ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
    2219             : 
    2220         252 :         if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
    2221           0 :                 return NT_STATUS_NO_MEMORY;
    2222             : 
    2223         252 :         r->out.names->names = lsa_names;
    2224         252 :         r->out.names->count = r->in.num_rids;
    2225             : 
    2226         252 :         r->out.types->ids = (uint32_t *) ids;
    2227         252 :         r->out.types->count = r->in.num_rids;
    2228             : 
    2229         252 :         status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
    2230             :                                   r->in.num_rids, r->in.rids, names, ids);
    2231         252 :         if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
    2232             :                 uint32_t i;
    2233        3121 :                 for (i = 0; i < r->in.num_rids; i++) {
    2234        2869 :                         lsa_names[i].string = names[i];
    2235             :                 }
    2236             :         }
    2237         252 :         return status;
    2238             : }
    2239             : 
    2240             : 
    2241             : /*
    2242             :   samr_OpenGroup
    2243             : */
    2244         253 : static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2245             :                        struct samr_OpenGroup *r)
    2246             : {
    2247           0 :         struct samr_domain_state *d_state;
    2248           0 :         struct samr_account_state *a_state;
    2249           0 :         struct dcesrv_handle *h;
    2250           0 :         const char *groupname;
    2251           0 :         struct dom_sid *sid;
    2252           0 :         struct ldb_message **msgs;
    2253           0 :         struct dcesrv_handle *g_handle;
    2254         253 :         const char * const attrs[2] = { "sAMAccountName", NULL };
    2255           0 :         int ret;
    2256             : 
    2257         253 :         ZERO_STRUCTP(r->out.group_handle);
    2258             : 
    2259         253 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    2260             : 
    2261         250 :         d_state = h->data;
    2262             : 
    2263             :         /* form the group SID */
    2264         250 :         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
    2265         250 :         if (!sid) {
    2266           0 :                 return NT_STATUS_NO_MEMORY;
    2267             :         }
    2268             : 
    2269             :         /* search for the group record */
    2270         250 :         if (d_state->builtin) {
    2271           0 :                 ret = gendb_search(d_state->sam_ctx,
    2272             :                                    mem_ctx, d_state->domain_dn, &msgs, attrs,
    2273             :                                    "(&(objectSid=%s)(objectClass=group)"
    2274             :                                    "(groupType=%d))",
    2275             :                                    ldap_encode_ndr_dom_sid(mem_ctx, sid),
    2276             :                                    GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
    2277             :         } else {
    2278         250 :                 ret = gendb_search(d_state->sam_ctx,
    2279             :                                    mem_ctx, d_state->domain_dn, &msgs, attrs,
    2280             :                                    "(&(objectSid=%s)(objectClass=group)"
    2281             :                                    "(|(groupType=%d)(groupType=%d)))",
    2282             :                                    ldap_encode_ndr_dom_sid(mem_ctx, sid),
    2283             :                                    GTYPE_SECURITY_UNIVERSAL_GROUP,
    2284             :                                    GTYPE_SECURITY_GLOBAL_GROUP);
    2285             :         }
    2286         250 :         if (ret == 0) {
    2287           0 :                 return NT_STATUS_NO_SUCH_GROUP;
    2288             :         }
    2289         250 :         if (ret != 1) {
    2290           0 :                 DEBUG(0,("Found %d records matching sid %s\n",
    2291             :                          ret, dom_sid_string(mem_ctx, sid)));
    2292           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2293             :         }
    2294             : 
    2295         250 :         groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
    2296         250 :         if (groupname == NULL) {
    2297           0 :                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
    2298             :                          dom_sid_string(mem_ctx, sid)));
    2299           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2300             :         }
    2301             : 
    2302         250 :         a_state = talloc(mem_ctx, struct samr_account_state);
    2303         250 :         if (!a_state) {
    2304           0 :                 return NT_STATUS_NO_MEMORY;
    2305             :         }
    2306         250 :         a_state->sam_ctx = d_state->sam_ctx;
    2307         250 :         a_state->access_mask = r->in.access_mask;
    2308         250 :         a_state->domain_state = talloc_reference(a_state, d_state);
    2309         250 :         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
    2310         250 :         a_state->account_sid = talloc_steal(a_state, sid);
    2311         250 :         a_state->account_name = talloc_strdup(a_state, groupname);
    2312         250 :         if (!a_state->account_name) {
    2313           0 :                 return NT_STATUS_NO_MEMORY;
    2314             :         }
    2315             : 
    2316             :         /* create the policy handle */
    2317         250 :         g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_GROUP);
    2318         250 :         if (!g_handle) {
    2319           0 :                 return NT_STATUS_NO_MEMORY;
    2320             :         }
    2321             : 
    2322         250 :         g_handle->data = talloc_steal(g_handle, a_state);
    2323             : 
    2324         250 :         *r->out.group_handle = g_handle->wire_handle;
    2325             : 
    2326         250 :         return NT_STATUS_OK;
    2327             : }
    2328             : 
    2329             : /*
    2330             :   samr_QueryGroupInfo
    2331             : */
    2332         225 : static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2333             :                        struct samr_QueryGroupInfo *r)
    2334             : {
    2335           0 :         struct dcesrv_handle *h;
    2336           0 :         struct samr_account_state *a_state;
    2337           0 :         struct ldb_message *msg, **res;
    2338         225 :         const char * const attrs[4] = { "sAMAccountName", "description",
    2339             :                                         "numMembers", NULL };
    2340           0 :         int ret;
    2341           0 :         union samr_GroupInfo *info;
    2342             : 
    2343         225 :         *r->out.info = NULL;
    2344             : 
    2345         225 :         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
    2346             : 
    2347         225 :         a_state = h->data;
    2348             : 
    2349             :         /* pull all the group attributes */
    2350         225 :         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
    2351             :                               a_state->account_dn, &res, attrs);
    2352         225 :         if (ret == 0) {
    2353           0 :                 return NT_STATUS_NO_SUCH_GROUP;
    2354             :         }
    2355         225 :         if (ret != 1) {
    2356           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2357             :         }
    2358         225 :         msg = res[0];
    2359             : 
    2360             :         /* allocate the info structure */
    2361         225 :         info = talloc_zero(mem_ctx, union samr_GroupInfo);
    2362         225 :         if (info == NULL) {
    2363           0 :                 return NT_STATUS_NO_MEMORY;
    2364             :         }
    2365             : 
    2366             :         /* Fill in the level */
    2367         225 :         switch (r->in.level) {
    2368          44 :         case GROUPINFOALL:
    2369          44 :                 QUERY_STRING(msg, all.name,        "sAMAccountName");
    2370          44 :                 info->all.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
    2371          44 :                 QUERY_UINT  (msg, all.num_members,      "numMembers")
    2372          44 :                 QUERY_STRING(msg, all.description, "description");
    2373          44 :                 break;
    2374          43 :         case GROUPINFONAME:
    2375          43 :                 QUERY_STRING(msg, name,            "sAMAccountName");
    2376          43 :                 break;
    2377          45 :         case GROUPINFOATTRIBUTES:
    2378          45 :                 info->attributes.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
    2379          45 :                 break;
    2380          43 :         case GROUPINFODESCRIPTION:
    2381          43 :                 QUERY_STRING(msg, description, "description");
    2382          43 :                 break;
    2383          50 :         case GROUPINFOALL2:
    2384          50 :                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
    2385          50 :                 info->all.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
    2386          50 :                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
    2387          50 :                 QUERY_STRING(msg, all2.description, "description");
    2388          50 :                 break;
    2389           0 :         default:
    2390           0 :                 talloc_free(info);
    2391           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
    2392             :         }
    2393             : 
    2394         225 :         *r->out.info = info;
    2395             : 
    2396         225 :         return NT_STATUS_OK;
    2397             : }
    2398             : 
    2399             : 
    2400             : /*
    2401             :   samr_SetGroupInfo
    2402             : */
    2403          13 : static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2404             :                                   struct samr_SetGroupInfo *r)
    2405             : {
    2406           0 :         struct dcesrv_handle *h;
    2407           0 :         struct samr_account_state *g_state;
    2408           0 :         struct ldb_message *msg;
    2409           0 :         int ret;
    2410             : 
    2411          13 :         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
    2412             : 
    2413          13 :         g_state = h->data;
    2414             : 
    2415          13 :         msg = ldb_msg_new(mem_ctx);
    2416          13 :         if (msg == NULL) {
    2417           0 :                 return NT_STATUS_NO_MEMORY;
    2418             :         }
    2419             : 
    2420          13 :         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
    2421          13 :         if (!msg->dn) {
    2422           0 :                 return NT_STATUS_NO_MEMORY;
    2423             :         }
    2424             : 
    2425          13 :         switch (r->in.level) {
    2426           3 :         case GROUPINFODESCRIPTION:
    2427           3 :                 SET_STRING(msg, description,         "description");
    2428           3 :                 break;
    2429           4 :         case GROUPINFONAME:
    2430             :                 /* On W2k3 this does not change the name, it changes the
    2431             :                  * sAMAccountName attribute */
    2432           4 :                 SET_STRING(msg, name,                "sAMAccountName");
    2433           4 :                 break;
    2434           3 :         case GROUPINFOATTRIBUTES:
    2435             :                 /* This does not do anything obviously visible in W2k3 LDAP */
    2436           3 :                 return NT_STATUS_OK;
    2437           3 :         default:
    2438           3 :                 return NT_STATUS_INVALID_INFO_CLASS;
    2439             :         }
    2440             : 
    2441             :         /* modify the samdb record */
    2442           7 :         ret = ldb_modify(g_state->sam_ctx, msg);
    2443           7 :         if (ret != LDB_SUCCESS) {
    2444           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2445             :         }
    2446             : 
    2447           7 :         return NT_STATUS_OK;
    2448             : }
    2449             : 
    2450             : 
    2451             : /*
    2452             :   samr_AddGroupMember
    2453             : */
    2454          81 : static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2455             :                        struct samr_AddGroupMember *r)
    2456             : {
    2457           0 :         struct dcesrv_handle *h;
    2458           0 :         struct samr_account_state *a_state;
    2459           0 :         struct samr_domain_state *d_state;
    2460           0 :         struct ldb_message *mod;
    2461           0 :         struct dom_sid *membersid;
    2462           0 :         const char *memberdn;
    2463           0 :         struct ldb_result *res;
    2464          81 :         const char * const attrs[] = { NULL };
    2465           0 :         int ret;
    2466             : 
    2467          81 :         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
    2468             : 
    2469          81 :         a_state = h->data;
    2470          81 :         d_state = a_state->domain_state;
    2471             : 
    2472          81 :         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
    2473          81 :         if (membersid == NULL) {
    2474           0 :                 return NT_STATUS_NO_MEMORY;
    2475             :         }
    2476             : 
    2477             :         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
    2478          81 :         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
    2479             :                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
    2480             :                          "(objectSid=%s)",
    2481             :                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
    2482             : 
    2483          81 :         if (ret != LDB_SUCCESS) {
    2484           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2485             :         }
    2486             : 
    2487          81 :         if (res->count == 0) {
    2488           0 :                 return NT_STATUS_NO_SUCH_USER;
    2489             :         }
    2490             : 
    2491          81 :         if (res->count > 1) {
    2492           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2493             :         }
    2494             : 
    2495          81 :         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
    2496             : 
    2497          81 :         if (memberdn == NULL)
    2498           0 :                 return NT_STATUS_NO_MEMORY;
    2499             : 
    2500          81 :         mod = ldb_msg_new(mem_ctx);
    2501          81 :         if (mod == NULL) {
    2502           0 :                 return NT_STATUS_NO_MEMORY;
    2503             :         }
    2504             : 
    2505          81 :         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
    2506             : 
    2507          81 :         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
    2508             :                                                                 memberdn);
    2509          81 :         if (ret != LDB_SUCCESS) {
    2510           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2511             :         }
    2512             : 
    2513          81 :         ret = ldb_modify(a_state->sam_ctx, mod);
    2514          81 :         switch (ret) {
    2515          78 :         case LDB_SUCCESS:
    2516          78 :                 return NT_STATUS_OK;
    2517           3 :         case LDB_ERR_ENTRY_ALREADY_EXISTS:
    2518           3 :                 return NT_STATUS_MEMBER_IN_GROUP;
    2519           0 :         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
    2520           0 :                 return NT_STATUS_ACCESS_DENIED;
    2521           0 :         default:
    2522           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2523             :         }
    2524             : }
    2525             : 
    2526             : 
    2527             : /*
    2528             :   samr_DeleteDomainGroup
    2529             : */
    2530         528 : static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2531             :                        struct samr_DeleteDomainGroup *r)
    2532             : {
    2533           0 :         struct dcesrv_handle *h;
    2534           0 :         struct samr_account_state *a_state;
    2535           0 :         int ret;
    2536             : 
    2537         528 :         *r->out.group_handle = *r->in.group_handle;
    2538             : 
    2539         528 :         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
    2540             : 
    2541         528 :         a_state = h->data;
    2542             : 
    2543         528 :         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
    2544         528 :         if (ret != LDB_SUCCESS) {
    2545           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2546             :         }
    2547             : 
    2548         528 :         talloc_free(h);
    2549         528 :         ZERO_STRUCTP(r->out.group_handle);
    2550             : 
    2551         528 :         return NT_STATUS_OK;
    2552             : }
    2553             : 
    2554             : 
    2555             : /*
    2556             :   samr_DeleteGroupMember
    2557             : */
    2558          77 : static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2559             :                        struct samr_DeleteGroupMember *r)
    2560             : {
    2561           0 :         struct dcesrv_handle *h;
    2562           0 :         struct samr_account_state *a_state;
    2563           0 :         struct samr_domain_state *d_state;
    2564           0 :         struct ldb_message *mod;
    2565           0 :         struct dom_sid *membersid;
    2566           0 :         const char *memberdn;
    2567           0 :         struct ldb_result *res;
    2568          77 :         const char * const attrs[] = { NULL };
    2569           0 :         int ret;
    2570             : 
    2571          77 :         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
    2572             : 
    2573          77 :         a_state = h->data;
    2574          77 :         d_state = a_state->domain_state;
    2575             : 
    2576          77 :         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
    2577          77 :         if (membersid == NULL) {
    2578           0 :                 return NT_STATUS_NO_MEMORY;
    2579             :         }
    2580             : 
    2581             :         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
    2582          77 :         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
    2583             :                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
    2584             :                          "(objectSid=%s)",
    2585             :                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
    2586             : 
    2587          77 :         if (ret != LDB_SUCCESS) {
    2588           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2589             :         }
    2590             : 
    2591          77 :         if (res->count == 0) {
    2592           0 :                 return NT_STATUS_NO_SUCH_USER;
    2593             :         }
    2594             : 
    2595          77 :         if (res->count > 1) {
    2596           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2597             :         }
    2598             : 
    2599          77 :         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
    2600             : 
    2601          77 :         if (memberdn == NULL)
    2602           0 :                 return NT_STATUS_NO_MEMORY;
    2603             : 
    2604          77 :         mod = ldb_msg_new(mem_ctx);
    2605          77 :         if (mod == NULL) {
    2606           0 :                 return NT_STATUS_NO_MEMORY;
    2607             :         }
    2608             : 
    2609          77 :         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
    2610             : 
    2611          77 :         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
    2612             :                                                                 memberdn);
    2613          77 :         if (ret != LDB_SUCCESS) {
    2614           0 :                 return NT_STATUS_NO_MEMORY;
    2615             :         }
    2616             : 
    2617          77 :         ret = ldb_modify(a_state->sam_ctx, mod);
    2618          77 :         switch (ret) {
    2619          74 :         case LDB_SUCCESS:
    2620          74 :                 return NT_STATUS_OK;
    2621           3 :         case LDB_ERR_UNWILLING_TO_PERFORM:
    2622             :         case LDB_ERR_NO_SUCH_ATTRIBUTE:
    2623           3 :                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
    2624           0 :         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
    2625           0 :                 return NT_STATUS_ACCESS_DENIED;
    2626           0 :         default:
    2627           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2628             :         }
    2629             : }
    2630             : 
    2631             : 
    2632             : /*
    2633             :   samr_QueryGroupMember
    2634             : */
    2635         164 : static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2636             :                                       struct samr_QueryGroupMember *r)
    2637             : {
    2638           0 :         struct dcesrv_handle *h;
    2639           0 :         struct samr_account_state *a_state;
    2640           0 :         struct samr_domain_state *d_state;
    2641           0 :         struct samr_RidAttrArray *array;
    2642           0 :         unsigned int i, num_members;
    2643           0 :         struct dom_sid *members;
    2644           0 :         NTSTATUS status;
    2645             : 
    2646         164 :         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
    2647             : 
    2648         164 :         a_state = h->data;
    2649         164 :         d_state = a_state->domain_state;
    2650             : 
    2651         164 :         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
    2652             :                                      a_state->account_dn, &members,
    2653             :                                      &num_members);
    2654         164 :         if (!NT_STATUS_IS_OK(status)) {
    2655           0 :                 return status;
    2656             :         }
    2657             : 
    2658         164 :         array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
    2659         164 :         if (array == NULL) {
    2660           0 :                 return NT_STATUS_NO_MEMORY;
    2661             :         }
    2662             : 
    2663         164 :         if (num_members == 0) {
    2664          55 :                 *r->out.rids = array;
    2665             : 
    2666          55 :                 return NT_STATUS_OK;
    2667             :         }
    2668             : 
    2669         109 :         array->rids = talloc_array(array, uint32_t, num_members);
    2670         109 :         if (array->rids == NULL) {
    2671           0 :                 return NT_STATUS_NO_MEMORY;
    2672             :         }
    2673             : 
    2674         109 :         array->attributes = talloc_array(array, uint32_t, num_members);
    2675         109 :         if (array->attributes == NULL) {
    2676           0 :                 return NT_STATUS_NO_MEMORY;
    2677             :         }
    2678             : 
    2679         109 :         array->count = 0;
    2680         218 :         for (i=0; i<num_members; i++) {
    2681         109 :                 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
    2682           0 :                         continue;
    2683             :                 }
    2684             : 
    2685         109 :                 status = dom_sid_split_rid(NULL, &members[i], NULL,
    2686         109 :                                            &array->rids[array->count]);
    2687         109 :                 if (!NT_STATUS_IS_OK(status)) {
    2688           0 :                         return status;
    2689             :                 }
    2690             : 
    2691         109 :                 array->attributes[array->count] = SE_GROUP_DEFAULT_FLAGS;
    2692         109 :                 array->count++;
    2693             :         }
    2694             : 
    2695         109 :         *r->out.rids = array;
    2696             : 
    2697         109 :         return NT_STATUS_OK;
    2698             : }
    2699             : 
    2700             : 
    2701             : /*
    2702             :   samr_SetMemberAttributesOfGroup
    2703             : */
    2704           0 : static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2705             :                        struct samr_SetMemberAttributesOfGroup *r)
    2706             : {
    2707           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    2708             : }
    2709             : 
    2710             : 
    2711             : /*
    2712             :   samr_OpenAlias
    2713             : */
    2714          79 : static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2715             :                        struct samr_OpenAlias *r)
    2716             : {
    2717           0 :         struct samr_domain_state *d_state;
    2718           0 :         struct samr_account_state *a_state;
    2719           0 :         struct dcesrv_handle *h;
    2720           0 :         const char *alias_name;
    2721           0 :         struct dom_sid *sid;
    2722           0 :         struct ldb_message **msgs;
    2723           0 :         struct dcesrv_handle *g_handle;
    2724          79 :         const char * const attrs[2] = { "sAMAccountName", NULL };
    2725           0 :         int ret;
    2726             : 
    2727          79 :         ZERO_STRUCTP(r->out.alias_handle);
    2728             : 
    2729          79 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    2730             : 
    2731          79 :         d_state = h->data;
    2732             : 
    2733             :         /* form the alias SID */
    2734          79 :         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
    2735          79 :         if (sid == NULL)
    2736           0 :                 return NT_STATUS_NO_MEMORY;
    2737             : 
    2738             :         /* search for the group record */
    2739          79 :         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
    2740             :                            "(&(objectSid=%s)(objectclass=group)"
    2741             :                            "(|(grouptype=%d)(grouptype=%d)))",
    2742             :                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
    2743             :                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
    2744             :                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
    2745          79 :         if (ret == 0) {
    2746           0 :                 return NT_STATUS_NO_SUCH_ALIAS;
    2747             :         }
    2748          79 :         if (ret != 1) {
    2749           0 :                 DEBUG(0,("Found %d records matching sid %s\n",
    2750             :                          ret, dom_sid_string(mem_ctx, sid)));
    2751           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2752             :         }
    2753             : 
    2754          79 :         alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
    2755          79 :         if (alias_name == NULL) {
    2756           0 :                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
    2757             :                          dom_sid_string(mem_ctx, sid)));
    2758           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2759             :         }
    2760             : 
    2761          79 :         a_state = talloc(mem_ctx, struct samr_account_state);
    2762          79 :         if (!a_state) {
    2763           0 :                 return NT_STATUS_NO_MEMORY;
    2764             :         }
    2765          79 :         a_state->sam_ctx = d_state->sam_ctx;
    2766          79 :         a_state->access_mask = r->in.access_mask;
    2767          79 :         a_state->domain_state = talloc_reference(a_state, d_state);
    2768          79 :         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
    2769          79 :         a_state->account_sid = talloc_steal(a_state, sid);
    2770          79 :         a_state->account_name = talloc_strdup(a_state, alias_name);
    2771          79 :         if (!a_state->account_name) {
    2772           0 :                 return NT_STATUS_NO_MEMORY;
    2773             :         }
    2774             : 
    2775             :         /* create the policy handle */
    2776          79 :         g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_ALIAS);
    2777          79 :         if (!g_handle) {
    2778           0 :                 return NT_STATUS_NO_MEMORY;
    2779             :         }
    2780             : 
    2781          79 :         g_handle->data = talloc_steal(g_handle, a_state);
    2782             : 
    2783          79 :         *r->out.alias_handle = g_handle->wire_handle;
    2784             : 
    2785          79 :         return NT_STATUS_OK;
    2786             : }
    2787             : 
    2788             : 
    2789             : /*
    2790             :   samr_QueryAliasInfo
    2791             : */
    2792         252 : static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2793             :                        struct samr_QueryAliasInfo *r)
    2794             : {
    2795           0 :         struct dcesrv_handle *h;
    2796           0 :         struct samr_account_state *a_state;
    2797           0 :         struct ldb_message *msg, **res;
    2798         252 :         const char * const attrs[4] = { "sAMAccountName", "description",
    2799             :                                         "numMembers", NULL };
    2800           0 :         int ret;
    2801           0 :         union samr_AliasInfo *info;
    2802             : 
    2803         252 :         *r->out.info = NULL;
    2804             : 
    2805         252 :         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
    2806             : 
    2807         252 :         a_state = h->data;
    2808             : 
    2809             :         /* pull all the alias attributes */
    2810         252 :         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
    2811             :                               a_state->account_dn, &res, attrs);
    2812         252 :         if (ret == 0) {
    2813           0 :                 return NT_STATUS_NO_SUCH_ALIAS;
    2814             :         }
    2815         252 :         if (ret != 1) {
    2816           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2817             :         }
    2818         252 :         msg = res[0];
    2819             : 
    2820             :         /* allocate the info structure */
    2821         252 :         info = talloc_zero(mem_ctx, union samr_AliasInfo);
    2822         252 :         if (info == NULL) {
    2823           0 :                 return NT_STATUS_NO_MEMORY;
    2824             :         }
    2825             : 
    2826         252 :         switch(r->in.level) {
    2827          82 :         case ALIASINFOALL:
    2828          82 :                 QUERY_STRING(msg, all.name, "sAMAccountName");
    2829          82 :                 QUERY_UINT  (msg, all.num_members, "numMembers");
    2830          82 :                 QUERY_STRING(msg, all.description, "description");
    2831          82 :                 break;
    2832          85 :         case ALIASINFONAME:
    2833          85 :                 QUERY_STRING(msg, name, "sAMAccountName");
    2834          85 :                 break;
    2835          85 :         case ALIASINFODESCRIPTION:
    2836          85 :                 QUERY_STRING(msg, description, "description");
    2837          85 :                 break;
    2838           0 :         default:
    2839           0 :                 talloc_free(info);
    2840           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
    2841             :         }
    2842             : 
    2843         252 :         *r->out.info = info;
    2844             : 
    2845         252 :         return NT_STATUS_OK;
    2846             : }
    2847             : 
    2848             : 
    2849             : /*
    2850             :   samr_SetAliasInfo
    2851             : */
    2852           6 : static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2853             :                        struct samr_SetAliasInfo *r)
    2854             : {
    2855           0 :         struct dcesrv_handle *h;
    2856           0 :         struct samr_account_state *a_state;
    2857           0 :         struct ldb_message *msg;
    2858           0 :         int ret;
    2859             : 
    2860           6 :         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
    2861             : 
    2862           6 :         a_state = h->data;
    2863             : 
    2864           6 :         msg = ldb_msg_new(mem_ctx);
    2865           6 :         if (msg == NULL) {
    2866           0 :                 return NT_STATUS_NO_MEMORY;
    2867             :         }
    2868             : 
    2869           6 :         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
    2870           6 :         if (!msg->dn) {
    2871           0 :                 return NT_STATUS_NO_MEMORY;
    2872             :         }
    2873             : 
    2874           6 :         switch (r->in.level) {
    2875           3 :         case ALIASINFODESCRIPTION:
    2876           3 :                 SET_STRING(msg, description,         "description");
    2877           3 :                 break;
    2878           3 :         case ALIASINFONAME:
    2879             :                 /* On W2k3 this does not change the name, it changes the
    2880             :                  * sAMAccountName attribute */
    2881           3 :                 SET_STRING(msg, name,                "sAMAccountName");
    2882           3 :                 break;
    2883           0 :         default:
    2884           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
    2885             :         }
    2886             : 
    2887             :         /* modify the samdb record */
    2888           6 :         ret = ldb_modify(a_state->sam_ctx, msg);
    2889           6 :         if (ret != LDB_SUCCESS) {
    2890           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2891             :         }
    2892             : 
    2893           6 :         return NT_STATUS_OK;
    2894             : }
    2895             : 
    2896             : 
    2897             : /*
    2898             :   samr_DeleteDomAlias
    2899             : */
    2900         453 : static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2901             :                        struct samr_DeleteDomAlias *r)
    2902             : {
    2903           0 :         struct dcesrv_handle *h;
    2904           0 :         struct samr_account_state *a_state;
    2905           0 :         int ret;
    2906             : 
    2907         453 :         *r->out.alias_handle = *r->in.alias_handle;
    2908             : 
    2909         453 :         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
    2910             : 
    2911         453 :         a_state = h->data;
    2912             : 
    2913         453 :         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
    2914         453 :         if (ret != LDB_SUCCESS) {
    2915           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2916             :         }
    2917             : 
    2918         453 :         talloc_free(h);
    2919         453 :         ZERO_STRUCTP(r->out.alias_handle);
    2920             : 
    2921         453 :         return NT_STATUS_OK;
    2922             : }
    2923             : 
    2924             : 
    2925             : /*
    2926             :   samr_AddAliasMember
    2927             : */
    2928           3 : static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2929             :                        struct samr_AddAliasMember *r)
    2930             : {
    2931           0 :         struct dcesrv_handle *h;
    2932           0 :         struct samr_account_state *a_state;
    2933           0 :         struct samr_domain_state *d_state;
    2934           0 :         struct ldb_message *mod;
    2935           0 :         struct ldb_message **msgs;
    2936           3 :         const char * const attrs[] = { NULL };
    2937           3 :         struct ldb_dn *memberdn = NULL;
    2938           0 :         int ret;
    2939           0 :         NTSTATUS status;
    2940             : 
    2941           3 :         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
    2942             : 
    2943           3 :         a_state = h->data;
    2944           3 :         d_state = a_state->domain_state;
    2945             : 
    2946           3 :         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
    2947             :                            &msgs, attrs, "(objectsid=%s)",
    2948           3 :                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
    2949             : 
    2950           3 :         if (ret == 1) {
    2951           3 :                 memberdn = msgs[0]->dn;
    2952           0 :         } else if (ret == 0) {
    2953           0 :                 status = samdb_create_foreign_security_principal(
    2954           0 :                         d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
    2955           0 :                 if (!NT_STATUS_IS_OK(status)) {
    2956           0 :                         return status;
    2957             :                 }
    2958             :         } else {
    2959           0 :                 DEBUG(0,("Found %d records matching sid %s\n",
    2960             :                          ret, dom_sid_string(mem_ctx, r->in.sid)));
    2961           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2962             :         }
    2963             : 
    2964           3 :         if (memberdn == NULL) {
    2965           0 :                 DEBUG(0, ("Could not find memberdn\n"));
    2966           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2967             :         }
    2968             : 
    2969           3 :         mod = ldb_msg_new(mem_ctx);
    2970           3 :         if (mod == NULL) {
    2971           0 :                 return NT_STATUS_NO_MEMORY;
    2972             :         }
    2973             : 
    2974           3 :         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
    2975             : 
    2976           3 :         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
    2977           3 :                                  ldb_dn_alloc_linearized(mem_ctx, memberdn));
    2978           3 :         if (ret != LDB_SUCCESS) {
    2979           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2980             :         }
    2981             : 
    2982           3 :         ret = ldb_modify(a_state->sam_ctx, mod);
    2983           3 :         switch (ret) {
    2984           3 :         case LDB_SUCCESS:
    2985           3 :                 return NT_STATUS_OK;
    2986           0 :         case LDB_ERR_ENTRY_ALREADY_EXISTS:
    2987           0 :                 return NT_STATUS_MEMBER_IN_GROUP;
    2988           0 :         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
    2989           0 :                 return NT_STATUS_ACCESS_DENIED;
    2990           0 :         default:
    2991           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    2992             :         }
    2993             : }
    2994             : 
    2995             : 
    2996             : /*
    2997             :   samr_DeleteAliasMember
    2998             : */
    2999           3 : static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    3000             :                        struct samr_DeleteAliasMember *r)
    3001             : {
    3002           0 :         struct dcesrv_handle *h;
    3003           0 :         struct samr_account_state *a_state;
    3004           0 :         struct samr_domain_state *d_state;
    3005           0 :         struct ldb_message *mod;
    3006           0 :         const char *memberdn;
    3007           0 :         int ret;
    3008             : 
    3009           3 :         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
    3010             : 
    3011           3 :         a_state = h->data;
    3012           3 :         d_state = a_state->domain_state;
    3013             : 
    3014           3 :         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
    3015             :                                        "distinguishedName", "(objectSid=%s)",
    3016           3 :                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
    3017           3 :         if (memberdn == NULL) {
    3018           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    3019             :         }
    3020             : 
    3021           3 :         mod = ldb_msg_new(mem_ctx);
    3022           3 :         if (mod == NULL) {
    3023           0 :                 return NT_STATUS_NO_MEMORY;
    3024             :         }
    3025             : 
    3026           3 :         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
    3027             : 
    3028           3 :         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
    3029             :                                                                  memberdn);
    3030           3 :         if (ret != LDB_SUCCESS) {
    3031           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    3032             :         }
    3033             : 
    3034           3 :         ret = ldb_modify(a_state->sam_ctx, mod);
    3035           3 :         switch (ret) {
    3036           3 :         case LDB_SUCCESS:
    3037           3 :                 return NT_STATUS_OK;
    3038           0 :         case LDB_ERR_UNWILLING_TO_PERFORM:
    3039           0 :                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
    3040           0 :         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
    3041           0 :                 return NT_STATUS_ACCESS_DENIED;
    3042           0 :         default:
    3043           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    3044             :         }
    3045             : }
    3046             : 
    3047             : 
    3048             : /*
    3049             :   samr_GetMembersInAlias
    3050             : */
    3051          79 : static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    3052             :                        struct samr_GetMembersInAlias *r)
    3053             : {
    3054           0 :         struct dcesrv_handle *h;
    3055           0 :         struct samr_account_state *a_state;
    3056           0 :         struct samr_domain_state *d_state;
    3057           0 :         struct lsa_SidPtr *array;
    3058           0 :         unsigned int i, num_members;
    3059           0 :         struct dom_sid *members;
    3060           0 :         NTSTATUS status;
    3061             : 
    3062          79 :         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
    3063             : 
    3064          79 :         a_state = h->data;
    3065          79 :         d_state = a_state->domain_state;
    3066             : 
    3067          79 :         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
    3068             :                                      a_state->account_dn, &members,
    3069             :                                      &num_members);
    3070          79 :         if (!NT_STATUS_IS_OK(status)) {
    3071           0 :                 return status;
    3072             :         }
    3073             : 
    3074          79 :         if (num_members == 0) {
    3075          55 :                 r->out.sids->sids = NULL;
    3076             : 
    3077          55 :                 return NT_STATUS_OK;
    3078             :         }
    3079             : 
    3080          24 :         array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
    3081          24 :         if (array == NULL) {
    3082           0 :                 return NT_STATUS_NO_MEMORY;
    3083             :         }
    3084             : 
    3085          84 :         for (i=0; i<num_members; i++) {
    3086          60 :                 array[i].sid = &members[i];
    3087             :         }
    3088             : 
    3089          24 :         r->out.sids->num_sids = num_members;
    3090          24 :         r->out.sids->sids = array;
    3091             : 
    3092          24 :         return NT_STATUS_OK;
    3093             : }
    3094             : 
    3095             : /*
    3096             :   samr_OpenUser
    3097             : */
    3098        1901 : static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    3099             :                               struct samr_OpenUser *r)
    3100             : {
    3101           0 :         struct samr_domain_state *d_state;
    3102           0 :         struct samr_account_state *a_state;
    3103           0 :         struct dcesrv_handle *h;
    3104           0 :         const char *account_name;
    3105           0 :         struct dom_sid *sid;
    3106           0 :         struct ldb_message **msgs;
    3107           0 :         struct dcesrv_handle *u_handle;
    3108        1901 :         const char * const attrs[2] = { "sAMAccountName", NULL };
    3109           0 :         int ret;
    3110             : 
    3111        1901 :         ZERO_STRUCTP(r->out.user_handle);
    3112             : 
    3113        1901 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    3114             : 
    3115        1898 :         d_state = h->data;
    3116             : 
    3117             :         /* form the users SID */
    3118        1898 :         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
    3119        1898 :         if (!sid) {
    3120           0 :                 return NT_STATUS_NO_MEMORY;
    3121             :         }
    3122             : 
    3123             :         /* search for the user record */
    3124        1898 :         ret = gendb_search(d_state->sam_ctx,
    3125             :                            mem_ctx, d_state->domain_dn, &msgs, attrs,
    3126             :                            "(&(objectSid=%s)(objectclass=user))",
    3127             :                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
    3128        1898 :         if (ret == 0) {
    3129          21 :                 return NT_STATUS_NO_SUCH_USER;
    3130             :         }
    3131        1877 :         if (ret != 1) {
    3132           0 :                 DEBUG(0,("Found %d records matching sid %s\n", ret,
    3133             :                          dom_sid_string(mem_ctx, sid)));
    3134           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    3135             :         }
    3136             : 
    3137        1877 :         account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
    3138        1877 :         if (account_name == NULL) {
    3139           0 :                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
    3140             :                          dom_sid_string(mem_ctx, sid)));
    3141           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    3142             :         }
    3143             : 
    3144        1877 :         a_state = talloc(mem_ctx, struct samr_account_state);
    3145        1877 :         if (!a_state) {
    3146           0 :                 return NT_STATUS_NO_MEMORY;
    3147             :         }
    3148        1877 :         a_state->sam_ctx = d_state->sam_ctx;
    3149        1877 :         a_state->access_mask = r->in.access_mask;
    3150        1877 :         a_state->domain_state = talloc_reference(a_state, d_state);
    3151        1877 :         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
    3152        1877 :         a_state->account_sid = talloc_steal(a_state, sid);
    3153        1877 :         a_state->account_name = talloc_strdup(a_state, account_name);
    3154        1877 :         if (!a_state->account_name) {
    3155           0 :                 return NT_STATUS_NO_MEMORY;
    3156             :         }
    3157             : 
    3158             :         /* create the policy handle */
    3159        1877 :         u_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_USER);
    3160        1877 :         if (!u_handle) {
    3161           0 :                 return NT_STATUS_NO_MEMORY;
    3162             :         }
    3163             : 
    3164        1877 :         u_handle->data = talloc_steal(u_handle, a_state);
    3165             : 
    3166        1877 :         *r->out.user_handle = u_handle->wire_handle;
    3167             : 
    3168        1877 :         return NT_STATUS_OK;
    3169             : 
    3170             : }
    3171             : 
    3172             : 
    3173             : /*
    3174             :   samr_DeleteUser
    3175             : */
    3176        1025 : static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    3177             :                                 struct samr_DeleteUser *r)
    3178             : {
    3179          72 :         struct dcesrv_handle *h;
    3180          72 :         struct samr_account_state *a_state;
    3181          72 :         int ret;
    3182             : 
    3183        1025 :         *r->out.user_handle = *r->in.user_handle;
    3184             : 
    3185        1025 :         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
    3186             : 
    3187        1025 :         a_state = h->data;
    3188             : 
    3189        1025 :         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
    3190        1025 :         if (ret != LDB_SUCCESS) {
    3191           0 :                 DEBUG(1, ("Failed to delete user: %s: %s\n",
    3192             :                           ldb_dn_get_linearized(a_state->account_dn),
    3193             :                           ldb_errstring(a_state->sam_ctx)));
    3194           0 :                 return dsdb_ldb_err_to_ntstatus(ret);
    3195             :         }
    3196             : 
    3197        1025 :         talloc_free(h);
    3198        1025 :         ZERO_STRUCTP(r->out.user_handle);
    3199             : 
    3200        1025 :         return NT_STATUS_OK;
    3201             : }
    3202             : 
    3203             : 
    3204             : /*
    3205             :   samr_QueryUserInfo
    3206             : */
    3207       11207 : static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    3208             :                                    struct samr_QueryUserInfo *r)
    3209             : {
    3210          72 :         struct dcesrv_handle *h;
    3211          72 :         struct samr_account_state *a_state;
    3212          72 :         struct ldb_message *msg, **res;
    3213          72 :         int ret;
    3214          72 :         struct ldb_context *sam_ctx;
    3215             : 
    3216       11207 :         const char * const *attrs = NULL;
    3217          72 :         union samr_UserInfo *info;
    3218             : 
    3219          72 :         NTSTATUS status;
    3220             : 
    3221       11207 :         *r->out.info = NULL;
    3222             : 
    3223       11207 :         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
    3224             : 
    3225       11207 :         a_state = h->data;
    3226       11207 :         sam_ctx = a_state->sam_ctx;
    3227             : 
    3228             :         /* fill in the reply */
    3229       11207 :         switch (r->in.level) {
    3230         227 :         case 1:
    3231             :         {
    3232             :                 static const char * const attrs2[] = {"sAMAccountName",
    3233             :                                                       "displayName",
    3234             :                                                       "primaryGroupID",
    3235             :                                                       "description",
    3236             :                                                       "comment",
    3237             :                                                       NULL};
    3238         227 :                 attrs = attrs2;
    3239         227 :                 break;
    3240             :         }
    3241         263 :         case 2:
    3242             :         {
    3243           0 :                 static const char * const attrs2[] = {"comment",
    3244             :                                                       "countryCode",
    3245             :                                                       "codePage",
    3246             :                                                       NULL};
    3247         263 :                 attrs = attrs2;
    3248         263 :                 break;
    3249             :         }
    3250        1496 :         case 3:
    3251             :         {
    3252           0 :                 static const char * const attrs2[] = {"sAMAccountName",
    3253             :                                                       "displayName",
    3254             :                                                       "objectSid",
    3255             :                                                       "primaryGroupID",
    3256             :                                                       "homeDirectory",
    3257             :                                                       "homeDrive",
    3258             :                                                       "scriptPath",
    3259             :                                                       "profilePath",
    3260             :                                                       "userWorkstations",
    3261             :                                                       "lastLogon",
    3262             :                                                       "lastLogoff",
    3263             :                                                       "pwdLastSet",
    3264             :                                                       "msDS-UserPasswordExpiryTimeComputed",
    3265             :                                                       "logonHours",
    3266             :                                                       "badPwdCount",
    3267             :                                                       "badPasswordTime",
    3268             :                                                       "logonCount",
    3269             :                                                       "userAccountControl",
    3270             :                                                       "msDS-User-Account-Control-Computed",
    3271             :                                                       NULL};
    3272        1496 :                 attrs = attrs2;
    3273        1496 :                 break;
    3274             :         }
    3275         174 :         case 4:
    3276             :         {
    3277           0 :                 static const char * const attrs2[] = {"logonHours",
    3278             :                                                       NULL};
    3279         174 :                 attrs = attrs2;
    3280         174 :                 break;
    3281             :         }
    3282        1732 :         case 5:
    3283             :         {
    3284           0 :                 static const char * const attrs2[] = {"sAMAccountName",
    3285             :                                                       "displayName",
    3286             :                                                       "objectSid",
    3287             :                                                       "primaryGroupID",
    3288             :                                                       "homeDirectory",
    3289             :                                                       "homeDrive",
    3290             :                                                       "scriptPath",
    3291             :                                                       "profilePath",
    3292             :                                                       "description",
    3293             :                                                       "userWorkstations",
    3294             :                                                       "lastLogon",
    3295             :                                                       "lastLogoff",
    3296             :                                                       "logonHours",
    3297             :                                                       "badPwdCount",
    3298             :                                                       "badPasswordTime",
    3299             :                                                       "logonCount",
    3300             :                                                       "pwdLastSet",
    3301             :                                                       "msDS-ResultantPSO",
    3302             :                                                       "msDS-UserPasswordExpiryTimeComputed",
    3303             :                                                       "accountExpires",
    3304             :                                                       "userAccountControl",
    3305             :                                                       "msDS-User-Account-Control-Computed",
    3306             :                                                       NULL};
    3307        1732 :                 attrs = attrs2;
    3308        1732 :                 break;
    3309             :         }
    3310         426 :         case 6:
    3311             :         {
    3312           0 :                 static const char * const attrs2[] = {"sAMAccountName",
    3313             :                                                       "displayName",
    3314             :                                                       NULL};
    3315         426 :                 attrs = attrs2;
    3316         426 :                 break;
    3317             :         }
    3318         258 :         case 7:
    3319             :         {
    3320           0 :                 static const char * const attrs2[] = {"sAMAccountName",
    3321             :                                                       NULL};
    3322         258 :                 attrs = attrs2;
    3323         258 :                 break;
    3324             :         }
    3325         174 :         case 8:
    3326             :         {
    3327           0 :                 static const char * const attrs2[] = {"displayName",
    3328             :                                                       NULL};
    3329         174 :                 attrs = attrs2;
    3330         174 :                 break;
    3331             :         }
    3332         102 :         case 9:
    3333             :         {
    3334           0 :                 static const char * const attrs2[] = {"primaryGroupID",
    3335             :                                                       NULL};
    3336         102 :                 attrs = attrs2;
    3337         102 :                 break;
    3338             :         }
    3339         279 :         case 10:
    3340             :         {
    3341           0 :                 static const char * const attrs2[] = {"homeDirectory",
    3342             :                                                       "homeDrive",
    3343             :                                                       NULL};
    3344         279 :                 attrs = attrs2;
    3345         279 :                 break;
    3346             :         }
    3347         174 :         case 11:
    3348             :         {
    3349           0 :                 static const char * const attrs2[] = {"scriptPath",
    3350             :                                                       NULL};
    3351         174 :                 attrs = attrs2;
    3352         174 :                 break;
    3353             :         }
    3354         186 :         case 12:
    3355             :         {
    3356           0 :                 static const char * const attrs2[] = {"profilePath",
    3357             :                                                       NULL};
    3358         186 :                 attrs = attrs2;
    3359         186 :                 break;
    3360             :         }
    3361         174 :         case 13:
    3362             :         {
    3363           0 :                 static const char * const attrs2[] = {"description",
    3364             :                                                       NULL};
    3365         174 :                 attrs = attrs2;
    3366         174 :                 break;
    3367             :         }
    3368         186 :         case 14:
    3369             :         {
    3370           0 :                 static const char * const attrs2[] = {"userWorkstations",
    3371             :                                                       NULL};
    3372         186 :                 attrs = attrs2;
    3373         186 :                 break;
    3374             :         }
    3375        2049 :         case 16:
    3376             :         {
    3377          72 :                 static const char * const attrs2[] = {"userAccountControl",
    3378             :                                                       "msDS-User-Account-Control-Computed",
    3379             :                                                       "pwdLastSet",
    3380             :                                                       "msDS-UserPasswordExpiryTimeComputed",
    3381             :                                                       NULL};
    3382        2049 :                 attrs = attrs2;
    3383        2049 :                 break;
    3384             :         }
    3385         162 :         case 17:
    3386             :         {
    3387           0 :                 static const char * const attrs2[] = {"accountExpires",
    3388             :                                                       NULL};
    3389         162 :                 attrs = attrs2;
    3390         162 :                 break;
    3391             :         }
    3392           0 :         case 18:
    3393             :         {
    3394           0 :                 return NT_STATUS_NOT_SUPPORTED;
    3395             :         }
    3396         174 :         case 20:
    3397             :         {
    3398           0 :                 static const char * const attrs2[] = {"userParameters",
    3399             :                                                       NULL};
    3400         174 :                 attrs = attrs2;
    3401         174 :                 break;
    3402             :         }
    3403        2971 :         case 21:
    3404             :         {
    3405           0 :                 static const char * const attrs2[] = {"lastLogon",
    3406             :                                                       "lastLogoff",
    3407             :                                                       "pwdLastSet",
    3408             :                                                       "msDS-ResultantPSO",
    3409             :                                                       "msDS-UserPasswordExpiryTimeComputed",
    3410             :                                                       "accountExpires",
    3411             :                                                       "sAMAccountName",
    3412             :                                                       "displayName",
    3413             :                                                       "homeDirectory",
    3414             :                                                       "homeDrive",
    3415             :                                                       "scriptPath",
    3416             :                                                       "profilePath",
    3417             :                                                       "description",
    3418             :                                                       "userWorkstations",
    3419             :                                                       "comment",
    3420             :                                                       "userParameters",
    3421             :                                                       "objectSid",
    3422             :                                                       "primaryGroupID",
    3423             :                                                       "userAccountControl",
    3424             :                                                       "msDS-User-Account-Control-Computed",
    3425             :                                                       "logonHours",
    3426             :                                                       "badPwdCount",
    3427             :                                                       "badPasswordTime",
    3428             :                                                       "logonCount",
    3429             :                                                       "countryCode",
    3430             :                                                       "codePage",
    3431             :                                                       NULL};
    3432        2971 :                 attrs = attrs2;
    3433        2971 :                 break;
    3434             :         }
    3435           0 :         case 23:
    3436             :         case 24:
    3437             :         case 25:
    3438             :         case 26:
    3439             :         {
    3440           0 :                 return NT_STATUS_NOT_SUPPORTED;
    3441             :         }
    3442           0 :         default:
    3443             :         {
    3444           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
    3445             :         }
    3446             :         }
    3447             : 
    3448             :         /* pull all the user attributes */
    3449       11207 :         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
    3450             :                               a_state->account_dn, &res, attrs);
    3451       11207 :         if (ret == 0) {
    3452           0 :                 return NT_STATUS_NO_SUCH_USER;
    3453             :         }
    3454       11207 :         if (ret != 1) {
    3455           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    3456             :         }
    3457       11207 :         msg = res[0];
    3458             : 
    3459             :         /* allocate the info structure */
    3460       11207 :         info = talloc_zero(mem_ctx, union samr_UserInfo);
    3461       11207 :         if (info == NULL) {
    3462           0 :                 return NT_STATUS_NO_MEMORY;
    3463             :         }
    3464             : 
    3465             :         /* fill in the reply */
    3466       11207 :         switch (r->in.level) {
    3467         227 :         case 1:
    3468         227 :                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
    3469         227 :                 QUERY_STRING(msg, info1.full_name,             "displayName");
    3470         227 :                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
    3471         227 :                 QUERY_STRING(msg, info1.description,           "description");
    3472         227 :                 QUERY_STRING(msg, info1.comment,               "comment");
    3473         227 :                 break;
    3474             : 
    3475         263 :         case 2:
    3476         263 :                 QUERY_STRING(msg, info2.comment,               "comment");
    3477         263 :                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
    3478         263 :                 QUERY_UINT  (msg, info2.code_page,             "codePage");
    3479         263 :                 break;
    3480             : 
    3481        1496 :         case 3:
    3482        1496 :                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
    3483        1496 :                 QUERY_STRING(msg, info3.full_name,             "displayName");
    3484        1496 :                 QUERY_RID   (msg, info3.rid,                   "objectSid");
    3485        1496 :                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
    3486        1496 :                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
    3487        1496 :                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
    3488        1496 :                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
    3489        1496 :                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
    3490        1496 :                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
    3491        1496 :                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
    3492        1496 :                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
    3493        1496 :                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
    3494        1496 :                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
    3495        1496 :                 QUERY_UINT64(msg, info3.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
    3496        1496 :                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
    3497             :                 /* level 3 gives the raw badPwdCount value */
    3498        1496 :                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
    3499        1496 :                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
    3500        1496 :                 QUERY_AFLAGS(msg, info3.acct_flags,            "msDS-User-Account-Control-Computed");
    3501        1496 :                 break;
    3502             : 
    3503         174 :         case 4:
    3504         174 :                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
    3505         174 :                 break;
    3506             : 
    3507        1732 :         case 5:
    3508        1732 :                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
    3509        1732 :                 QUERY_STRING(msg, info5.full_name,             "displayName");
    3510        1732 :                 QUERY_RID   (msg, info5.rid,                   "objectSid");
    3511        1732 :                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
    3512        1732 :                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
    3513        1732 :                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
    3514        1732 :                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
    3515        1732 :                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
    3516        1732 :                 QUERY_STRING(msg, info5.description,           "description");
    3517        1732 :                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
    3518        1732 :                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
    3519        1732 :                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
    3520        1732 :                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
    3521        1732 :                 QUERY_BPWDCT(msg, info5.bad_password_count,    "badPwdCount");
    3522        1732 :                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
    3523        1732 :                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
    3524        1732 :                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
    3525        1732 :                 QUERY_AFLAGS(msg, info5.acct_flags,            "msDS-User-Account-Control-Computed");
    3526        1732 :                 break;
    3527             : 
    3528         426 :         case 6:
    3529         426 :                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
    3530         426 :                 QUERY_STRING(msg, info6.full_name,      "displayName");
    3531         426 :                 break;
    3532             : 
    3533         258 :         case 7:
    3534         258 :                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
    3535         258 :                 break;
    3536             : 
    3537         174 :         case 8:
    3538         174 :                 QUERY_STRING(msg, info8.full_name,      "displayName");
    3539         174 :                 break;
    3540             : 
    3541         102 :         case 9:
    3542         102 :                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
    3543         102 :                 break;
    3544             : 
    3545         279 :         case 10:
    3546         279 :                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
    3547         279 :                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
    3548         279 :                 break;
    3549             : 
    3550         174 :         case 11:
    3551         174 :                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
    3552         174 :                 break;
    3553             : 
    3554         186 :         case 12:
    3555         186 :                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
    3556         186 :                 break;
    3557             : 
    3558         174 :         case 13:
    3559         174 :                 QUERY_STRING(msg, info13.description,   "description");
    3560         174 :                 break;
    3561             : 
    3562         186 :         case 14:
    3563         186 :                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
    3564         186 :                 break;
    3565             : 
    3566        2049 :         case 16:
    3567        2049 :                 QUERY_AFLAGS(msg, info16.acct_flags,    "msDS-User-Account-Control-Computed");
    3568        2049 :                 break;
    3569             : 
    3570         162 :         case 17:
    3571         162 :                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
    3572         162 :                 break;
    3573             : 
    3574         174 :         case 20:
    3575         174 :                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
    3576         174 :                 if (!NT_STATUS_IS_OK(status)) {
    3577           0 :                         talloc_free(info);
    3578           0 :                         return status;
    3579             :                 }
    3580         174 :                 break;
    3581             : 
    3582        2971 :         case 21:
    3583        2971 :                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
    3584        2971 :                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
    3585        2971 :                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
    3586        2971 :                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
    3587        2971 :                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
    3588        2971 :                 QUERY_UINT64(msg, info21.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
    3589        2971 :                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
    3590        2971 :                 QUERY_STRING(msg, info21.full_name,            "displayName");
    3591        2971 :                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
    3592        2971 :                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
    3593        2971 :                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
    3594        2971 :                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
    3595        2971 :                 QUERY_STRING(msg, info21.description,          "description");
    3596        2971 :                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
    3597        2971 :                 QUERY_STRING(msg, info21.comment,              "comment");
    3598        2971 :                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
    3599        2971 :                 if (!NT_STATUS_IS_OK(status)) {
    3600           0 :                         talloc_free(info);
    3601           0 :                         return status;
    3602             :                 }
    3603             : 
    3604        2971 :                 QUERY_RID   (msg, info21.rid,                  "objectSid");
    3605        2971 :                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
    3606        2971 :                 QUERY_AFLAGS(msg, info21.acct_flags,           "msDS-User-Account-Control-Computed");
    3607        2971 :                 info->info21.fields_present = 0x08FFFFFF;
    3608        2971 :                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
    3609        2971 :                 QUERY_BPWDCT(msg, info21.bad_password_count,   "badPwdCount");
    3610        2971 :                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
    3611        2971 :                 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
    3612         745 :                         info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
    3613             :                 } else {
    3614        2226 :                         info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
    3615             :                 }
    3616        2971 :                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
    3617        2971 :                 QUERY_UINT  (msg, info21.code_page,            "codePage");
    3618        2971 :                 break;
    3619             : 
    3620             : 
    3621           0 :         default:
    3622           0 :                 talloc_free(info);
    3623           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
    3624             :         }
    3625             : 
    3626       11207 :         *r->out.info = info;
    3627             : 
    3628       11207 :         return NT_STATUS_OK;
    3629             : }
    3630             : 
    3631             : 
    3632             : /*
    3633             :   samr_SetUserInfo
    3634             : */
    3635        4224 : static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    3636             :                                  struct samr_SetUserInfo *r)
    3637             : {
    3638         144 :         struct dcesrv_handle *h;
    3639         144 :         struct samr_account_state *a_state;
    3640         144 :         struct ldb_message *msg;
    3641         144 :         int ret;
    3642        4224 :         NTSTATUS status = NT_STATUS_OK;
    3643         144 :         struct ldb_context *sam_ctx;
    3644        4224 :         DATA_BLOB session_key = data_blob_null;
    3645             : 
    3646        4224 :         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
    3647             : 
    3648        4224 :         a_state = h->data;
    3649        4224 :         sam_ctx = a_state->sam_ctx;
    3650             : 
    3651        4224 :         msg = ldb_msg_new(mem_ctx);
    3652        4224 :         if (msg == NULL) {
    3653           0 :                 return NT_STATUS_NO_MEMORY;
    3654             :         }
    3655             : 
    3656        4224 :         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
    3657        4224 :         if (!msg->dn) {
    3658           0 :                 return NT_STATUS_NO_MEMORY;
    3659             :         }
    3660             : 
    3661        4224 :         ret = ldb_transaction_start(sam_ctx);
    3662        4224 :         if (ret != LDB_SUCCESS) {
    3663           0 :                 DBG_ERR("Failed to start a transaction: %s\n",
    3664             :                         ldb_errstring(sam_ctx));
    3665           0 :                 return NT_STATUS_LOCK_NOT_GRANTED;
    3666             :         }
    3667             : 
    3668        4224 :         switch (r->in.level) {
    3669         125 :         case 2:
    3670         125 :                 SET_STRING(msg, info2.comment,          "comment");
    3671         125 :                 SET_UINT  (msg, info2.country_code,     "countryCode");
    3672         125 :                 SET_UINT  (msg, info2.code_page,        "codePage");
    3673         125 :                 break;
    3674             : 
    3675          72 :         case 4:
    3676          72 :                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
    3677          72 :                 break;
    3678             : 
    3679         288 :         case 6:
    3680         288 :                 SET_STRING(msg, info6.account_name,     "samAccountName");
    3681         288 :                 SET_STRING(msg, info6.full_name,        "displayName");
    3682         288 :                 break;
    3683             : 
    3684         148 :         case 7:
    3685         148 :                 SET_STRING(msg, info7.account_name,     "samAccountName");
    3686         148 :                 break;
    3687             : 
    3688          58 :         case 8:
    3689          58 :                 SET_STRING(msg, info8.full_name,        "displayName");
    3690          58 :                 break;
    3691             : 
    3692           0 :         case 9:
    3693           0 :                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
    3694           0 :                 break;
    3695             : 
    3696         151 :         case 10:
    3697         151 :                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
    3698         151 :                 SET_STRING(msg, info10.home_drive,      "homeDrive");
    3699         151 :                 break;
    3700             : 
    3701          81 :         case 11:
    3702          81 :                 SET_STRING(msg, info11.logon_script,    "scriptPath");
    3703          81 :                 break;
    3704             : 
    3705          79 :         case 12:
    3706          79 :                 SET_STRING(msg, info12.profile_path,    "profilePath");
    3707          79 :                 break;
    3708             : 
    3709          80 :         case 13:
    3710          80 :                 SET_STRING(msg, info13.description,     "description");
    3711          80 :                 break;
    3712             : 
    3713          72 :         case 14:
    3714          72 :                 SET_STRING(msg, info14.workstations,    "userWorkstations");
    3715          72 :                 break;
    3716             : 
    3717         293 :         case 16:
    3718         293 :                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
    3719         293 :                 break;
    3720             : 
    3721          59 :         case 17:
    3722          59 :                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
    3723          59 :                 break;
    3724             : 
    3725         158 :         case 18:
    3726         158 :                 status = samr_set_password_buffers(dce_call,
    3727             :                                                    sam_ctx,
    3728             :                                                    a_state->account_dn,
    3729             :                                                    mem_ctx,
    3730         158 :                                                    r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
    3731         158 :                                                    r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
    3732         158 :                 if (!NT_STATUS_IS_OK(status)) {
    3733         229 :                         goto done;
    3734             :                 }
    3735             : 
    3736         158 :                 if (r->in.info->info18.password_expired > 0) {
    3737           0 :                         struct ldb_message_element *set_el;
    3738          16 :                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
    3739           0 :                                 status = NT_STATUS_NO_MEMORY;
    3740           0 :                                 goto done;
    3741             :                         }
    3742          16 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    3743          16 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    3744             :                 }
    3745         158 :                 break;
    3746             : 
    3747          48 :         case 20:
    3748          48 :                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
    3749          48 :                 break;
    3750             : 
    3751        1491 :         case 21:
    3752        1491 :                 if (r->in.info->info21.fields_present == 0) {
    3753           8 :                         status = NT_STATUS_INVALID_PARAMETER;
    3754           8 :                         goto done;
    3755             :                 }
    3756             : 
    3757             : #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
    3758        1483 :                 IFSET(SAMR_FIELD_LAST_LOGON)
    3759           0 :                         SET_UINT64(msg, info21.last_logon,     "lastLogon");
    3760        1483 :                 IFSET(SAMR_FIELD_LAST_LOGOFF)
    3761           0 :                         SET_UINT64(msg, info21.last_logoff,    "lastLogoff");
    3762        1483 :                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
    3763          74 :                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");
    3764        1483 :                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
    3765          25 :                         SET_STRING(msg, info21.account_name,   "samAccountName");
    3766        1483 :                 IFSET(SAMR_FIELD_FULL_NAME)
    3767         563 :                         SET_STRING(msg, info21.full_name,      "displayName");
    3768        1483 :                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
    3769          50 :                         SET_STRING(msg, info21.home_directory, "homeDirectory");
    3770        1483 :                 IFSET(SAMR_FIELD_HOME_DRIVE)
    3771          50 :                         SET_STRING(msg, info21.home_drive,     "homeDrive");
    3772        1483 :                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
    3773          26 :                         SET_STRING(msg, info21.logon_script,   "scriptPath");
    3774        1483 :                 IFSET(SAMR_FIELD_PROFILE_PATH)
    3775          26 :                         SET_STRING(msg, info21.profile_path,   "profilePath");
    3776        1483 :                 IFSET(SAMR_FIELD_DESCRIPTION)
    3777         540 :                         SET_STRING(msg, info21.description,    "description");
    3778        1483 :                 IFSET(SAMR_FIELD_WORKSTATIONS)
    3779         100 :                         SET_STRING(msg, info21.workstations,   "userWorkstations");
    3780        1483 :                 IFSET(SAMR_FIELD_COMMENT)
    3781         571 :                         SET_STRING(msg, info21.comment,        "comment");
    3782        1483 :                 IFSET(SAMR_FIELD_PARAMETERS)
    3783          96 :                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
    3784        1483 :                 IFSET(SAMR_FIELD_PRIMARY_GID)
    3785           2 :                         SET_UINT(msg, info21.primary_gid,      "primaryGroupID");
    3786        1483 :                 IFSET(SAMR_FIELD_ACCT_FLAGS)
    3787          43 :                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
    3788        1483 :                 IFSET(SAMR_FIELD_LOGON_HOURS)
    3789          27 :                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
    3790        1483 :                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
    3791           0 :                         SET_UINT  (msg, info21.bad_password_count, "badPwdCount");
    3792        1483 :                 IFSET(SAMR_FIELD_NUM_LOGONS)
    3793           0 :                         SET_UINT  (msg, info21.logon_count,    "logonCount");
    3794        1483 :                 IFSET(SAMR_FIELD_COUNTRY_CODE)
    3795          48 :                         SET_UINT  (msg, info21.country_code,   "countryCode");
    3796        1483 :                 IFSET(SAMR_FIELD_CODE_PAGE)
    3797          48 :                         SET_UINT  (msg, info21.code_page,      "codePage");
    3798             : 
    3799             :                 /* password change fields */
    3800        1483 :                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
    3801          40 :                         status = NT_STATUS_ACCESS_DENIED;
    3802          40 :                         goto done;
    3803             :                 }
    3804             : 
    3805        1443 :                 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
    3806             :                                         | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
    3807         188 :                         uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
    3808             : 
    3809         188 :                         if (r->in.info->info21.lm_password_set) {
    3810         100 :                                 if ((r->in.info->info21.lm_owf_password.length != 16)
    3811          88 :                                  || (r->in.info->info21.lm_owf_password.size != 16)) {
    3812          12 :                                         status = NT_STATUS_INVALID_PARAMETER;
    3813          12 :                                         goto done;
    3814             :                                 }
    3815             : 
    3816          88 :                                 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
    3817             :                         }
    3818         176 :                         if (r->in.info->info21.nt_password_set) {
    3819         176 :                                 if ((r->in.info->info21.nt_owf_password.length != 16)
    3820         152 :                                  || (r->in.info->info21.nt_owf_password.size != 16)) {
    3821          24 :                                         status = NT_STATUS_INVALID_PARAMETER;
    3822          24 :                                         goto done;
    3823             :                                 }
    3824             : 
    3825         152 :                                 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
    3826             :                         }
    3827         152 :                         status = samr_set_password_buffers(dce_call,
    3828             :                                                            sam_ctx,
    3829             :                                                            a_state->account_dn,
    3830             :                                                            mem_ctx,
    3831             :                                                            lm_pwd_hash,
    3832             :                                                            nt_pwd_hash);
    3833         152 :                         if (!NT_STATUS_IS_OK(status)) {
    3834           0 :                                 goto done;
    3835             :                         }
    3836             :                 }
    3837             : 
    3838             : 
    3839        1407 :                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
    3840          98 :                         const char *t = "0";
    3841           0 :                         struct ldb_message_element *set_el;
    3842          98 :                         if (r->in.info->info21.password_expired
    3843             :                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
    3844          50 :                                 t = "-1";
    3845             :                         }
    3846          98 :                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
    3847           0 :                                 status = NT_STATUS_NO_MEMORY;
    3848           0 :                                 goto done;
    3849             :                         }
    3850          98 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    3851          98 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    3852             :                 }
    3853             : #undef IFSET
    3854        1335 :                 break;
    3855             : 
    3856          74 :         case 23:
    3857          74 :                 if (r->in.info->info23.info.fields_present == 0) {
    3858           0 :                         status = NT_STATUS_INVALID_PARAMETER;
    3859           0 :                         goto done;
    3860             :                 }
    3861             : 
    3862             : #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
    3863          74 :                 IFSET(SAMR_FIELD_LAST_LOGON)
    3864           0 :                         SET_UINT64(msg, info23.info.last_logon,     "lastLogon");
    3865          74 :                 IFSET(SAMR_FIELD_LAST_LOGOFF)
    3866           0 :                         SET_UINT64(msg, info23.info.last_logoff,    "lastLogoff");
    3867          74 :                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
    3868           0 :                         SET_UINT64(msg, info23.info.acct_expiry,    "accountExpires");
    3869          74 :                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
    3870           0 :                         SET_STRING(msg, info23.info.account_name,   "samAccountName");
    3871          74 :                 IFSET(SAMR_FIELD_FULL_NAME)
    3872           0 :                         SET_STRING(msg, info23.info.full_name,      "displayName");
    3873          74 :                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
    3874           0 :                         SET_STRING(msg, info23.info.home_directory, "homeDirectory");
    3875          74 :                 IFSET(SAMR_FIELD_HOME_DRIVE)
    3876           0 :                         SET_STRING(msg, info23.info.home_drive,     "homeDrive");
    3877          74 :                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
    3878           0 :                         SET_STRING(msg, info23.info.logon_script,   "scriptPath");
    3879          74 :                 IFSET(SAMR_FIELD_PROFILE_PATH)
    3880           0 :                         SET_STRING(msg, info23.info.profile_path,   "profilePath");
    3881          74 :                 IFSET(SAMR_FIELD_DESCRIPTION)
    3882           0 :                         SET_STRING(msg, info23.info.description,    "description");
    3883          74 :                 IFSET(SAMR_FIELD_WORKSTATIONS)
    3884           0 :                         SET_STRING(msg, info23.info.workstations,   "userWorkstations");
    3885          74 :                 IFSET(SAMR_FIELD_COMMENT)
    3886           0 :                         SET_STRING(msg, info23.info.comment,        "comment");
    3887          74 :                 IFSET(SAMR_FIELD_PARAMETERS)
    3888           0 :                         SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
    3889          74 :                 IFSET(SAMR_FIELD_PRIMARY_GID)
    3890           0 :                         SET_UINT(msg, info23.info.primary_gid,      "primaryGroupID");
    3891          74 :                 IFSET(SAMR_FIELD_ACCT_FLAGS)
    3892           0 :                         SET_AFLAGS(msg, info23.info.acct_flags,     "userAccountControl");
    3893          74 :                 IFSET(SAMR_FIELD_LOGON_HOURS)
    3894           0 :                         SET_LHOURS(msg, info23.info.logon_hours,    "logonHours");
    3895          74 :                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
    3896           0 :                         SET_UINT  (msg, info23.info.bad_password_count, "badPwdCount");
    3897          74 :                 IFSET(SAMR_FIELD_NUM_LOGONS)
    3898           0 :                         SET_UINT  (msg, info23.info.logon_count,    "logonCount");
    3899             : 
    3900          74 :                 IFSET(SAMR_FIELD_COUNTRY_CODE)
    3901           0 :                         SET_UINT  (msg, info23.info.country_code,   "countryCode");
    3902          74 :                 IFSET(SAMR_FIELD_CODE_PAGE)
    3903           0 :                         SET_UINT  (msg, info23.info.code_page,      "codePage");
    3904             : 
    3905             :                 /* password change fields */
    3906          74 :                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
    3907           0 :                         status = NT_STATUS_ACCESS_DENIED;
    3908           0 :                         goto done;
    3909             :                 }
    3910             : 
    3911          74 :                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
    3912          50 :                         status = samr_set_password(dce_call,
    3913             :                                                    sam_ctx,
    3914             :                                                    a_state->account_dn,
    3915             :                                                    mem_ctx,
    3916          50 :                                                    &r->in.info->info23.password);
    3917          24 :                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
    3918          24 :                         status = samr_set_password(dce_call,
    3919             :                                                    sam_ctx,
    3920             :                                                    a_state->account_dn,
    3921             :                                                    mem_ctx,
    3922          24 :                                                    &r->in.info->info23.password);
    3923             :                 }
    3924          74 :                 if (!NT_STATUS_IS_OK(status)) {
    3925          36 :                         goto done;
    3926             :                 }
    3927             : 
    3928          38 :                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
    3929           2 :                         const char *t = "0";
    3930           0 :                         struct ldb_message_element *set_el;
    3931           2 :                         if (r->in.info->info23.info.password_expired
    3932             :                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
    3933           2 :                                 t = "-1";
    3934             :                         }
    3935           2 :                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
    3936           0 :                                 status = NT_STATUS_NO_MEMORY;
    3937           0 :                                 goto done;
    3938             :                         }
    3939           2 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    3940           2 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    3941             :                 }
    3942             : #undef IFSET
    3943          38 :                 break;
    3944             : 
    3945             :                 /* the set password levels are handled separately */
    3946         173 :         case 24:
    3947         173 :                 status = samr_set_password(dce_call,
    3948             :                                            sam_ctx,
    3949             :                                            a_state->account_dn,
    3950             :                                            mem_ctx,
    3951         173 :                                            &r->in.info->info24.password);
    3952         173 :                 if (!NT_STATUS_IS_OK(status)) {
    3953           0 :                         goto done;
    3954             :                 }
    3955             : 
    3956         173 :                 if (r->in.info->info24.password_expired > 0) {
    3957           0 :                         struct ldb_message_element *set_el;
    3958           4 :                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
    3959           0 :                                 status = NT_STATUS_NO_MEMORY;
    3960           0 :                                 goto done;
    3961             :                         }
    3962           4 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    3963           4 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    3964             :                 }
    3965         173 :                 break;
    3966             : 
    3967         593 :         case 25:
    3968         593 :                 if (r->in.info->info25.info.fields_present == 0) {
    3969           0 :                         status = NT_STATUS_INVALID_PARAMETER;
    3970           0 :                         goto done;
    3971             :                 }
    3972             : 
    3973             : #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
    3974         593 :                 IFSET(SAMR_FIELD_LAST_LOGON)
    3975           0 :                         SET_UINT64(msg, info25.info.last_logon,     "lastLogon");
    3976         593 :                 IFSET(SAMR_FIELD_LAST_LOGOFF)
    3977           0 :                         SET_UINT64(msg, info25.info.last_logoff,    "lastLogoff");
    3978         593 :                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
    3979           0 :                         SET_UINT64(msg, info25.info.acct_expiry,    "accountExpires");
    3980         593 :                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
    3981           4 :                         SET_STRING(msg, info25.info.account_name,   "samAccountName");
    3982         593 :                 IFSET(SAMR_FIELD_FULL_NAME)
    3983         509 :                         SET_STRING(msg, info25.info.full_name,      "displayName");
    3984         593 :                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
    3985           0 :                         SET_STRING(msg, info25.info.home_directory, "homeDirectory");
    3986         593 :                 IFSET(SAMR_FIELD_HOME_DRIVE)
    3987           0 :                         SET_STRING(msg, info25.info.home_drive,     "homeDrive");
    3988         593 :                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
    3989           0 :                         SET_STRING(msg, info25.info.logon_script,   "scriptPath");
    3990         593 :                 IFSET(SAMR_FIELD_PROFILE_PATH)
    3991           0 :                         SET_STRING(msg, info25.info.profile_path,   "profilePath");
    3992         593 :                 IFSET(SAMR_FIELD_DESCRIPTION)
    3993           2 :                         SET_STRING(msg, info25.info.description,    "description");
    3994         593 :                 IFSET(SAMR_FIELD_WORKSTATIONS)
    3995           0 :                         SET_STRING(msg, info25.info.workstations,   "userWorkstations");
    3996         593 :                 IFSET(SAMR_FIELD_COMMENT)
    3997           0 :                         SET_STRING(msg, info25.info.comment,        "comment");
    3998         593 :                 IFSET(SAMR_FIELD_PARAMETERS)
    3999           0 :                         SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
    4000         593 :                 IFSET(SAMR_FIELD_PRIMARY_GID)
    4001           0 :                         SET_UINT(msg, info25.info.primary_gid,      "primaryGroupID");
    4002         593 :                 IFSET(SAMR_FIELD_ACCT_FLAGS)
    4003         513 :                         SET_AFLAGS(msg, info25.info.acct_flags,     "userAccountControl");
    4004         593 :                 IFSET(SAMR_FIELD_LOGON_HOURS)
    4005           0 :                         SET_LHOURS(msg, info25.info.logon_hours,    "logonHours");
    4006         593 :                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
    4007           0 :                         SET_UINT  (msg, info25.info.bad_password_count, "badPwdCount");
    4008         593 :                 IFSET(SAMR_FIELD_NUM_LOGONS)
    4009           0 :                         SET_UINT  (msg, info25.info.logon_count,    "logonCount");
    4010         593 :                 IFSET(SAMR_FIELD_COUNTRY_CODE)
    4011           0 :                         SET_UINT  (msg, info25.info.country_code,   "countryCode");
    4012         593 :                 IFSET(SAMR_FIELD_CODE_PAGE)
    4013           0 :                         SET_UINT  (msg, info25.info.code_page,      "codePage");
    4014             : 
    4015             :                 /* password change fields */
    4016         593 :                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
    4017           0 :                         status = NT_STATUS_ACCESS_DENIED;
    4018           0 :                         goto done;
    4019             :                 }
    4020             : 
    4021         593 :                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
    4022         569 :                         status = samr_set_password_ex(dce_call,
    4023             :                                                       sam_ctx,
    4024             :                                                       a_state->account_dn,
    4025             :                                                       mem_ctx,
    4026         497 :                                                       &r->in.info->info25.password);
    4027          24 :                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
    4028          24 :                         status = samr_set_password_ex(dce_call,
    4029             :                                                       sam_ctx,
    4030             :                                                       a_state->account_dn,
    4031             :                                                       mem_ctx,
    4032          24 :                                                       &r->in.info->info25.password);
    4033             :                 }
    4034         593 :                 if (!NT_STATUS_IS_OK(status)) {
    4035          36 :                         goto done;
    4036             :                 }
    4037             : 
    4038         557 :                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
    4039           0 :                         const char *t = "0";
    4040           0 :                         struct ldb_message_element *set_el;
    4041           0 :                         if (r->in.info->info25.info.password_expired
    4042             :                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
    4043           0 :                                 t = "-1";
    4044             :                         }
    4045           0 :                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
    4046           0 :                                 status = NT_STATUS_NO_MEMORY;
    4047           0 :                                 goto done;
    4048             :                         }
    4049           0 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    4050           0 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    4051             :                 }
    4052             : #undef IFSET
    4053         485 :                 break;
    4054             : 
    4055             :                 /* the set password levels are handled separately */
    4056          85 :         case 26:
    4057          85 :                 status = samr_set_password_ex(dce_call,
    4058             :                                               sam_ctx,
    4059             :                                               a_state->account_dn,
    4060             :                                               mem_ctx,
    4061          85 :                                               &r->in.info->info26.password);
    4062          85 :                 if (!NT_STATUS_IS_OK(status)) {
    4063          25 :                         goto done;
    4064             :                 }
    4065             : 
    4066          60 :                 if (r->in.info->info26.password_expired > 0) {
    4067          16 :                         const char *t = "0";
    4068           0 :                         struct ldb_message_element *set_el;
    4069          16 :                         if (r->in.info->info26.password_expired
    4070             :                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
    4071           0 :                                 t = "-1";
    4072             :                         }
    4073          16 :                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
    4074           0 :                                 status = NT_STATUS_NO_MEMORY;
    4075           0 :                                 goto done;
    4076             :                         }
    4077          16 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    4078          16 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    4079             :                 }
    4080          60 :                 break;
    4081             : 
    4082          24 :         case 31:
    4083          24 :                 status = dcesrv_transport_session_key(dce_call, &session_key);
    4084          24 :                 if (!NT_STATUS_IS_OK(status)) {
    4085           0 :                         DBG_NOTICE("samr: failed to get session key: %s\n",
    4086             :                                    nt_errstr(status));
    4087           0 :                         goto done;
    4088             :                 }
    4089             : 
    4090          24 :                 status = samr_set_password_aes(dce_call,
    4091             :                                                mem_ctx,
    4092             :                                                &session_key,
    4093             :                                                sam_ctx,
    4094             :                                                a_state->account_dn,
    4095          24 :                                                &r->in.info->info31.password,
    4096             :                                                DSDB_PASSWORD_RESET);
    4097          24 :                 if (!NT_STATUS_IS_OK(status)) {
    4098          12 :                         goto done;
    4099             :                 }
    4100             : 
    4101          12 :                 if (r->in.info->info31.password_expired > 0) {
    4102           0 :                         const char *t = "0";
    4103           0 :                         struct ldb_message_element *set_el = NULL;
    4104             : 
    4105           0 :                         if (r->in.info->info31.password_expired ==
    4106             :                             PASS_DONT_CHANGE_AT_NEXT_LOGON) {
    4107           0 :                                 t = "-1";
    4108             :                         }
    4109             : 
    4110           0 :                         ret = ldb_msg_add_string(msg, "pwdLastSet", t);
    4111           0 :                         if (ret != LDB_SUCCESS) {
    4112           0 :                                 status = NT_STATUS_NO_MEMORY;
    4113           0 :                                 goto done;
    4114             :                         }
    4115           0 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    4116           0 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    4117             :                 }
    4118             : 
    4119          12 :                 break;
    4120          72 :         case 32:
    4121          72 :                 status = dcesrv_transport_session_key(dce_call, &session_key);
    4122          72 :                 if (!NT_STATUS_IS_OK(status)) {
    4123           0 :                         DBG_NOTICE("samr: failed to get session key: %s\n",
    4124             :                                    nt_errstr(status));
    4125           0 :                         goto done;
    4126             :                 }
    4127             : 
    4128          72 :                 if (r->in.info->info32.info.fields_present == 0) {
    4129           0 :                         status = NT_STATUS_INVALID_PARAMETER;
    4130           0 :                         goto done;
    4131             :                 }
    4132             : 
    4133             : #define IFSET(bit) if (bit & r->in.info->info32.info.fields_present)
    4134          72 :                 IFSET(SAMR_FIELD_LAST_LOGON)
    4135             :                 {
    4136           0 :                         SET_UINT64(msg, info32.info.last_logon, "lastLogon");
    4137             :                 }
    4138          72 :                 IFSET(SAMR_FIELD_LAST_LOGOFF)
    4139             :                 {
    4140           0 :                         SET_UINT64(msg, info32.info.last_logoff, "lastLogoff");
    4141             :                 }
    4142          72 :                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
    4143             :                 {
    4144           0 :                         SET_UINT64(msg,
    4145             :                                    info32.info.acct_expiry,
    4146             :                                    "accountExpires");
    4147             :                 }
    4148          72 :                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
    4149             :                 {
    4150           0 :                         SET_STRING(msg,
    4151             :                                    info32.info.account_name,
    4152             :                                    "samAccountName");
    4153             :                 }
    4154          72 :                 IFSET(SAMR_FIELD_FULL_NAME)
    4155             :                 {
    4156           0 :                         SET_STRING(msg, info32.info.full_name, "displayName");
    4157             :                 }
    4158          72 :                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
    4159             :                 {
    4160           0 :                         SET_STRING(msg,
    4161             :                                    info32.info.home_directory,
    4162             :                                    "homeDirectory");
    4163             :                 }
    4164          72 :                 IFSET(SAMR_FIELD_HOME_DRIVE)
    4165             :                 {
    4166           0 :                         SET_STRING(msg, info32.info.home_drive, "homeDrive");
    4167             :                 }
    4168          72 :                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
    4169             :                 {
    4170           0 :                         SET_STRING(msg, info32.info.logon_script, "scriptPath");
    4171             :                 }
    4172          72 :                 IFSET(SAMR_FIELD_PROFILE_PATH)
    4173             :                 {
    4174           0 :                         SET_STRING(msg,
    4175             :                                    info32.info.profile_path,
    4176             :                                    "profilePath");
    4177             :                 }
    4178          72 :                 IFSET(SAMR_FIELD_DESCRIPTION)
    4179             :                 {
    4180           0 :                         SET_STRING(msg, info32.info.description, "description");
    4181             :                 }
    4182          72 :                 IFSET(SAMR_FIELD_WORKSTATIONS)
    4183             :                 {
    4184           0 :                         SET_STRING(msg,
    4185             :                                    info32.info.workstations,
    4186             :                                    "userWorkstations");
    4187             :                 }
    4188          72 :                 IFSET(SAMR_FIELD_COMMENT)
    4189             :                 {
    4190           0 :                         SET_STRING(msg, info32.info.comment, "comment");
    4191             :                 }
    4192          72 :                 IFSET(SAMR_FIELD_PARAMETERS)
    4193             :                 {
    4194           0 :                         SET_PARAMETERS(msg,
    4195             :                                        info32.info.parameters,
    4196             :                                        "userParameters");
    4197             :                 }
    4198          72 :                 IFSET(SAMR_FIELD_PRIMARY_GID)
    4199             :                 {
    4200           0 :                         SET_UINT(msg,
    4201             :                                  info32.info.primary_gid,
    4202             :                                  "primaryGroupID");
    4203             :                 }
    4204          72 :                 IFSET(SAMR_FIELD_ACCT_FLAGS)
    4205             :                 {
    4206           0 :                         SET_AFLAGS(msg,
    4207             :                                    info32.info.acct_flags,
    4208             :                                    "userAccountControl");
    4209             :                 }
    4210          72 :                 IFSET(SAMR_FIELD_LOGON_HOURS)
    4211             :                 {
    4212           0 :                         SET_LHOURS(msg, info32.info.logon_hours, "logonHours");
    4213             :                 }
    4214          72 :                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
    4215             :                 {
    4216           0 :                         SET_UINT(msg,
    4217             :                                  info32.info.bad_password_count,
    4218             :                                  "badPwdCount");
    4219             :                 }
    4220          72 :                 IFSET(SAMR_FIELD_NUM_LOGONS)
    4221             :                 {
    4222           0 :                         SET_UINT(msg, info32.info.logon_count, "logonCount");
    4223             :                 }
    4224          72 :                 IFSET(SAMR_FIELD_COUNTRY_CODE)
    4225             :                 {
    4226           0 :                         SET_UINT(msg, info32.info.country_code, "countryCode");
    4227             :                 }
    4228          72 :                 IFSET(SAMR_FIELD_CODE_PAGE)
    4229             :                 {
    4230           0 :                         SET_UINT(msg, info32.info.code_page, "codePage");
    4231             :                 }
    4232             : 
    4233             :                 /* password change fields */
    4234          72 :                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
    4235             :                 {
    4236           0 :                         status = NT_STATUS_ACCESS_DENIED;
    4237           0 :                         goto done;
    4238             :                 }
    4239             : 
    4240          72 :                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT)
    4241             :                 {
    4242          48 :                         status = samr_set_password_aes(
    4243             :                                 dce_call,
    4244             :                                 mem_ctx,
    4245             :                                 &session_key,
    4246          48 :                                 a_state->sam_ctx,
    4247             :                                 a_state->account_dn,
    4248          48 :                                 &r->in.info->info32.password,
    4249             :                                 DSDB_PASSWORD_RESET);
    4250             :                 }
    4251          24 :                 else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT)
    4252             :                 {
    4253          24 :                         status = samr_set_password_aes(
    4254             :                                 dce_call,
    4255             :                                 mem_ctx,
    4256             :                                 &session_key,
    4257          24 :                                 a_state->sam_ctx,
    4258             :                                 a_state->account_dn,
    4259          24 :                                 &r->in.info->info32.password,
    4260             :                                 DSDB_PASSWORD_RESET);
    4261             :                 }
    4262          72 :                 if (!NT_STATUS_IS_OK(status)) {
    4263          36 :                         goto done;
    4264             :                 }
    4265             : 
    4266          36 :                 IFSET(SAMR_FIELD_EXPIRED_FLAG)
    4267             :                 {
    4268           0 :                         const char *t = "0";
    4269           0 :                         struct ldb_message_element *set_el;
    4270           0 :                         if (r->in.info->info32.info.password_expired ==
    4271             :                             PASS_DONT_CHANGE_AT_NEXT_LOGON) {
    4272           0 :                                 t = "-1";
    4273             :                         }
    4274           0 :                         if (ldb_msg_add_string(msg, "pwdLastSet", t) !=
    4275             :                             LDB_SUCCESS) {
    4276           0 :                                 status = NT_STATUS_NO_MEMORY;
    4277           0 :                                 goto done;
    4278             :                         }
    4279           0 :                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
    4280           0 :                         set_el->flags = LDB_FLAG_MOD_REPLACE;
    4281             :                 }
    4282             : #undef IFSET
    4283             : 
    4284          36 :                 break;
    4285           0 :         default:
    4286             :                 /* many info classes are not valid for SetUserInfo */
    4287           0 :                 status = NT_STATUS_INVALID_INFO_CLASS;
    4288           0 :                 goto done;
    4289             :         }
    4290             : 
    4291        3995 :         if (!NT_STATUS_IS_OK(status)) {
    4292           0 :                 goto done;
    4293             :         }
    4294             : 
    4295             :         /* modify the samdb record */
    4296        3995 :         if (msg->num_elements > 0) {
    4297        3352 :                 ret = ldb_modify(sam_ctx, msg);
    4298        3352 :                 if (ret != LDB_SUCCESS) {
    4299           0 :                         DEBUG(1,("Failed to modify record %s: %s\n",
    4300             :                                  ldb_dn_get_linearized(a_state->account_dn),
    4301             :                                  ldb_errstring(sam_ctx)));
    4302             : 
    4303           0 :                         status = dsdb_ldb_err_to_ntstatus(ret);
    4304           0 :                         goto done;
    4305             :                 }
    4306             :         }
    4307             : 
    4308        3995 :         ret = ldb_transaction_commit(sam_ctx);
    4309        3995 :         if (ret != LDB_SUCCESS) {
    4310           0 :                 DBG_ERR("Failed to commit transaction modifying account record "
    4311             :                         "%s: %s\n",
    4312             :                         ldb_dn_get_linearized(msg->dn),
    4313             :                         ldb_errstring(sam_ctx));
    4314           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4315             :         }
    4316             : 
    4317        3851 :         status = NT_STATUS_OK;
    4318        4224 : done:
    4319        4224 :         if (!NT_STATUS_IS_OK(status)) {
    4320         229 :                 ldb_transaction_cancel(sam_ctx);
    4321             :         }
    4322             : 
    4323        4224 :         return status;
    4324             : }
    4325             : 
    4326             : 
    4327             : /*
    4328             :   samr_GetGroupsForUser
    4329             : */
    4330         210 : static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4331             :                        struct samr_GetGroupsForUser *r)
    4332             : {
    4333           0 :         struct dcesrv_handle *h;
    4334           0 :         struct samr_account_state *a_state;
    4335           0 :         struct samr_domain_state *d_state;
    4336           0 :         struct ldb_result *res, *res_memberof;
    4337         210 :         const char * const attrs[] = { "primaryGroupID",
    4338             :                                        "memberOf",
    4339             :                                        NULL };
    4340         210 :         const char * const group_attrs[] = { "objectSid",
    4341             :                                              NULL };
    4342             : 
    4343           0 :         struct samr_RidWithAttributeArray *array;
    4344           0 :         struct ldb_message_element *memberof_el;
    4345         210 :         int i, ret, count = 0;
    4346           0 :         uint32_t primary_group_id;
    4347           0 :         char *filter;
    4348             : 
    4349         210 :         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
    4350             : 
    4351         210 :         a_state = h->data;
    4352         210 :         d_state = a_state->domain_state;
    4353             : 
    4354         210 :         ret = dsdb_search_dn(a_state->sam_ctx, mem_ctx,
    4355             :                              &res,
    4356             :                              a_state->account_dn,
    4357             :                              attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
    4358             : 
    4359         210 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    4360           0 :                 return NT_STATUS_NO_SUCH_USER;
    4361         210 :         } else if (ret != LDB_SUCCESS) {
    4362           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4363         210 :         } else if (res->count != 1) {
    4364           0 :                 return NT_STATUS_NO_SUCH_USER;
    4365             :         }
    4366             : 
    4367         210 :         primary_group_id = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
    4368             :                                                      0);
    4369             : 
    4370         210 :         filter = talloc_asprintf(mem_ctx,
    4371             :                                  "(&(|(grouptype=%d)(grouptype=%d))"
    4372             :                                  "(objectclass=group)(|",
    4373             :                                  GTYPE_SECURITY_UNIVERSAL_GROUP,
    4374             :                                  GTYPE_SECURITY_GLOBAL_GROUP);
    4375         210 :         if (filter == NULL) {
    4376           0 :                 return NT_STATUS_NO_MEMORY;
    4377             :         }
    4378             : 
    4379         210 :         memberof_el = ldb_msg_find_element(res->msgs[0], "memberOf");
    4380         210 :         if (memberof_el != NULL) {
    4381         226 :                 for (i = 0; i < memberof_el->num_values; i++) {
    4382           0 :                         const struct ldb_val *memberof_sid_binary;
    4383           0 :                         char *memberof_sid_escaped;
    4384           0 :                         struct ldb_dn *memberof_dn
    4385         146 :                                 = ldb_dn_from_ldb_val(mem_ctx,
    4386         146 :                                                       a_state->sam_ctx,
    4387         146 :                                                       &memberof_el->values[i]);
    4388         146 :                         if (memberof_dn == NULL) {
    4389           0 :                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4390             :                         }
    4391             : 
    4392           0 :                         memberof_sid_binary
    4393         146 :                                 = ldb_dn_get_extended_component(memberof_dn,
    4394             :                                                                 "SID");
    4395         146 :                         if (memberof_sid_binary == NULL) {
    4396           0 :                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4397             :                         }
    4398             : 
    4399         146 :                         memberof_sid_escaped = ldb_binary_encode(mem_ctx,
    4400             :                                                                  *memberof_sid_binary);
    4401         146 :                         if (memberof_sid_escaped == NULL) {
    4402           0 :                                 return NT_STATUS_NO_MEMORY;
    4403             :                         }
    4404         146 :                         filter = talloc_asprintf_append(filter, "(objectSID=%s)",
    4405             :                                                         memberof_sid_escaped);
    4406         146 :                         if (filter == NULL) {
    4407           0 :                                 return NT_STATUS_NO_MEMORY;
    4408             :                         }
    4409             :                 }
    4410             : 
    4411          80 :                 ret = dsdb_search(a_state->sam_ctx, mem_ctx,
    4412             :                                   &res_memberof,
    4413             :                                   d_state->domain_dn,
    4414             :                                   LDB_SCOPE_SUBTREE,
    4415             :                                   group_attrs, 0,
    4416             :                                   "%s))", filter);
    4417             : 
    4418          80 :                 if (ret != LDB_SUCCESS) {
    4419           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4420             :                 }
    4421          80 :                 count = res_memberof->count;
    4422             :         }
    4423             : 
    4424         210 :         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
    4425         210 :         if (array == NULL)
    4426           0 :                 return NT_STATUS_NO_MEMORY;
    4427             : 
    4428         210 :         array->count = 0;
    4429         210 :         array->rids = NULL;
    4430             : 
    4431         210 :         array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
    4432             :                                    count + 1);
    4433         210 :         if (array->rids == NULL)
    4434           0 :                 return NT_STATUS_NO_MEMORY;
    4435             : 
    4436             :         /* Adds the primary group */
    4437             : 
    4438         210 :         array->rids[0].rid = primary_group_id;
    4439         210 :         array->rids[0].attributes = SE_GROUP_DEFAULT_FLAGS;
    4440         210 :         array->count += 1;
    4441             : 
    4442             :         /* Adds the additional groups */
    4443         292 :         for (i = 0; i < count; i++) {
    4444           0 :                 struct dom_sid *group_sid;
    4445             : 
    4446          82 :                 group_sid = samdb_result_dom_sid(mem_ctx,
    4447          82 :                                                  res_memberof->msgs[i],
    4448             :                                                  "objectSid");
    4449          82 :                 if (group_sid == NULL) {
    4450           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4451             :                 }
    4452             : 
    4453          82 :                 array->rids[i + 1].rid =
    4454          82 :                         group_sid->sub_auths[group_sid->num_auths-1];
    4455          82 :                 array->rids[i + 1].attributes = SE_GROUP_DEFAULT_FLAGS;
    4456          82 :                 array->count += 1;
    4457             :         }
    4458             : 
    4459         210 :         *r->out.rids = array;
    4460             : 
    4461         210 :         return NT_STATUS_OK;
    4462             : }
    4463             : 
    4464             : /*
    4465             :  * samr_QueryDisplayInfo
    4466             :  *
    4467             :  * A cache of the GUID's matching the last query is maintained
    4468             :  * in the SAMR_QUERY_DISPLAY_INFO_CACHE guid_cache maintained o
    4469             :  * n the dcesrv_handle.
    4470             :  */
    4471         371 : static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4472             :                        struct samr_QueryDisplayInfo *r)
    4473             : {
    4474           0 :         struct dcesrv_handle *h;
    4475           0 :         struct samr_domain_state *d_state;
    4476           0 :         struct ldb_result *res;
    4477           0 :         uint32_t i;
    4478         371 :         uint32_t results = 0;
    4479         371 :         uint32_t count = 0;
    4480         371 :         const char *const cache_attrs[] = {"objectGUID", NULL};
    4481         371 :         const char *const attrs[] = {
    4482             :             "objectSID", "sAMAccountName", "displayName", "description", NULL};
    4483         371 :         struct samr_DispEntryFull *entriesFull = NULL;
    4484         371 :         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
    4485         371 :         struct samr_DispEntryAscii *entriesAscii = NULL;
    4486         371 :         struct samr_DispEntryGeneral *entriesGeneral = NULL;
    4487           0 :         const char *filter;
    4488           0 :         int ret;
    4489           0 :         NTSTATUS status;
    4490         371 :         struct samr_guid_cache *cache = NULL;
    4491             : 
    4492         371 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    4493             : 
    4494         371 :         d_state = h->data;
    4495             : 
    4496         371 :         cache = &d_state->guid_caches[SAMR_QUERY_DISPLAY_INFO_CACHE];
    4497             :         /*
    4498             :          * Can the cached results be used?
    4499             :          * The cache is discarded if the start index is zero, or the requested
    4500             :          * level is different from that in the cache.
    4501             :          */
    4502         371 :         if ((r->in.start_idx == 0) || (r->in.level != cache->handle)) {
    4503             :                 /*
    4504             :                  * The cached results can not be used, so will need to query
    4505             :                  * the database.
    4506             :                  */
    4507             : 
    4508             :                 /*
    4509             :                  * Get the search filter for the current level
    4510             :                  */
    4511         141 :                 switch (r->in.level) {
    4512          59 :                 case 1:
    4513             :                 case 4:
    4514          59 :                         filter = talloc_asprintf(mem_ctx,
    4515             :                                                  "(&(objectclass=user)"
    4516             :                                                  "(sAMAccountType=%d))",
    4517             :                                                  ATYPE_NORMAL_ACCOUNT);
    4518          59 :                         break;
    4519          22 :                 case 2:
    4520          22 :                         filter = talloc_asprintf(mem_ctx,
    4521             :                                                  "(&(objectclass=user)"
    4522             :                                                  "(sAMAccountType=%d))",
    4523             :                                                  ATYPE_WORKSTATION_TRUST);
    4524          22 :                         break;
    4525          60 :                 case 3:
    4526             :                 case 5:
    4527           0 :                         filter =
    4528          60 :                             talloc_asprintf(mem_ctx,
    4529             :                                             "(&(|(groupType=%d)(groupType=%d))"
    4530             :                                             "(objectClass=group))",
    4531             :                                             GTYPE_SECURITY_UNIVERSAL_GROUP,
    4532             :                                             GTYPE_SECURITY_GLOBAL_GROUP);
    4533          60 :                         break;
    4534           0 :                 default:
    4535           0 :                         return NT_STATUS_INVALID_INFO_CLASS;
    4536             :                 }
    4537         141 :                 clear_guid_cache(cache);
    4538             : 
    4539             :                 /*
    4540             :                  * search for all requested objects in all domains.
    4541             :                  */
    4542         141 :                 ret = dsdb_search(d_state->sam_ctx,
    4543             :                                   mem_ctx,
    4544             :                                   &res,
    4545         141 :                                   ldb_get_default_basedn(d_state->sam_ctx),
    4546             :                                   LDB_SCOPE_SUBTREE,
    4547             :                                   cache_attrs,
    4548             :                                   0,
    4549             :                                   "%s",
    4550             :                                   filter);
    4551         141 :                 if (ret != LDB_SUCCESS) {
    4552           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4553             :                 }
    4554         141 :                 if ((res->count == 0) || (r->in.max_entries == 0)) {
    4555           0 :                         return NT_STATUS_OK;
    4556             :                 }
    4557             : 
    4558         141 :                 status = load_guid_cache(cache, d_state, res->count, res->msgs);
    4559         141 :                 TALLOC_FREE(res);
    4560         141 :                 if (!NT_STATUS_IS_OK(status)) {
    4561           0 :                         return status;
    4562             :                 }
    4563         141 :                 cache->handle = r->in.level;
    4564             :         }
    4565         371 :         *r->out.total_size = cache->size;
    4566             : 
    4567             :         /*
    4568             :          * if there are no entries or the requested start index is greater
    4569             :          * than the number of entries, we return an empty response.
    4570             :          */
    4571         371 :         if (r->in.start_idx >= cache->size) {
    4572          11 :                 *r->out.returned_size = 0;
    4573          11 :                 switch(r->in.level) {
    4574           7 :                 case 1:
    4575           7 :                         r->out.info->info1.count = *r->out.returned_size;
    4576           7 :                         r->out.info->info1.entries = NULL;
    4577           7 :                         break;
    4578           1 :                 case 2:
    4579           1 :                         r->out.info->info2.count = *r->out.returned_size;
    4580           1 :                         r->out.info->info2.entries = NULL;
    4581           1 :                         break;
    4582           1 :                 case 3:
    4583           1 :                         r->out.info->info3.count = *r->out.returned_size;
    4584           1 :                         r->out.info->info3.entries = NULL;
    4585           1 :                         break;
    4586           1 :                 case 4:
    4587           1 :                         r->out.info->info4.count = *r->out.returned_size;
    4588           1 :                         r->out.info->info4.entries = NULL;
    4589           1 :                         break;
    4590           1 :                 case 5:
    4591           1 :                         r->out.info->info5.count = *r->out.returned_size;
    4592           1 :                         r->out.info->info5.entries = NULL;
    4593           1 :                         break;
    4594             :                 }
    4595          11 :                 return NT_STATUS_OK;
    4596             :         }
    4597             : 
    4598             :         /*
    4599             :          * Allocate an array of the appropriate result structures for the
    4600             :          * current query level.
    4601             :          *
    4602             :          * r->in.start_idx is always < cache->size due to the check above
    4603             :          */
    4604         360 :         results = MIN((cache->size - r->in.start_idx), r->in.max_entries);
    4605         360 :         switch (r->in.level) {
    4606         134 :         case 1:
    4607         134 :                 entriesGeneral = talloc_array(
    4608             :                     mem_ctx, struct samr_DispEntryGeneral, results);
    4609         134 :                 break;
    4610          26 :         case 2:
    4611           0 :                 entriesFull =
    4612          26 :                     talloc_array(mem_ctx, struct samr_DispEntryFull, results);
    4613          26 :                 break;
    4614          68 :         case 3:
    4615          68 :                 entriesFullGroup = talloc_array(
    4616             :                     mem_ctx, struct samr_DispEntryFullGroup, results);
    4617          68 :                 break;
    4618         132 :         case 4:
    4619             :         case 5:
    4620           0 :                 entriesAscii =
    4621         132 :                     talloc_array(mem_ctx, struct samr_DispEntryAscii, results);
    4622         132 :                 break;
    4623             :         }
    4624             : 
    4625         360 :         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
    4626          68 :             (entriesAscii == NULL) && (entriesFullGroup == NULL))
    4627           0 :                 return NT_STATUS_NO_MEMORY;
    4628             : 
    4629             :         /*
    4630             :          * Process the list of result GUID's.
    4631             :          * Read the details of each object and populate the result structure
    4632             :          * for the current level.
    4633             :          */
    4634         360 :         count = 0;
    4635        2968 :         for (i = 0; i < results; i++) {
    4636           0 :                 struct dom_sid *objectsid;
    4637           0 :                 struct ldb_result *rec;
    4638        2608 :                 const uint32_t idx = r->in.start_idx + i;
    4639           0 :                 uint32_t rid;
    4640             : 
    4641             :                 /*
    4642             :                  * Read an object from disk using the GUID as the key
    4643             :                  *
    4644             :                  * If the object can not be read, or it does not have a SID
    4645             :                  * it is ignored.  In this case the number of entries returned
    4646             :                  * will be less than the requested size, there will also be
    4647             :                  * a gap in the idx numbers in the returned elements e.g. if
    4648             :                  * there are 3 GUIDs a, b, c in the cache and b is deleted from
    4649             :                  * disk then details for a, and c will be returned with
    4650             :                  * idx values of 1 and 3 respectively.
    4651             :                  *
    4652             :                  */
    4653        2608 :                 ret = dsdb_search_by_dn_guid(d_state->sam_ctx,
    4654             :                                              mem_ctx,
    4655             :                                              &rec,
    4656        2608 :                                              &cache->entries[idx],
    4657             :                                              attrs,
    4658             :                                              0);
    4659        2608 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    4660           0 :                         struct GUID_txt_buf guid_buf;
    4661           0 :                         char *guid_str =
    4662          18 :                                 GUID_buf_string(&cache->entries[idx],
    4663             :                                                 &guid_buf);
    4664          18 :                         DBG_WARNING("GUID [%s] not found\n", guid_str);
    4665          18 :                         continue;
    4666        2590 :                 } else if (ret != LDB_SUCCESS) {
    4667           0 :                         clear_guid_cache(cache);
    4668           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4669             :                 }
    4670        2590 :                 objectsid = samdb_result_dom_sid(mem_ctx,
    4671        2590 :                                                  rec->msgs[0],
    4672             :                                                  "objectSID");
    4673        2590 :                 if (objectsid == NULL) {
    4674           0 :                         struct GUID_txt_buf guid_buf;
    4675           0 :                         DBG_WARNING(
    4676             :                             "objectSID for GUID [%s] not found\n",
    4677             :                             GUID_buf_string(&cache->entries[idx], &guid_buf));
    4678           0 :                         continue;
    4679             :                 }
    4680        2590 :                 status = dom_sid_split_rid(NULL,
    4681             :                                            objectsid,
    4682             :                                            NULL,
    4683             :                                            &rid);
    4684        2590 :                 if (!NT_STATUS_IS_OK(status)) {
    4685           0 :                         struct dom_sid_buf sid_buf;
    4686           0 :                         struct GUID_txt_buf guid_buf;
    4687           0 :                         DBG_WARNING(
    4688             :                             "objectSID [%s] for GUID [%s] invalid\n",
    4689             :                             dom_sid_str_buf(objectsid, &sid_buf),
    4690             :                             GUID_buf_string(&cache->entries[idx], &guid_buf));
    4691           0 :                         continue;
    4692             :                 }
    4693             : 
    4694             :                 /*
    4695             :                  * Populate the result structure for the current object
    4696             :                  */
    4697        2590 :                 switch(r->in.level) {
    4698         939 :                 case 1:
    4699             : 
    4700         939 :                         entriesGeneral[count].idx = idx + 1;
    4701         939 :                         entriesGeneral[count].rid = rid;
    4702             : 
    4703        1878 :                         entriesGeneral[count].acct_flags =
    4704         939 :                             samdb_result_acct_flags(rec->msgs[0], NULL);
    4705        1878 :                         entriesGeneral[count].account_name.string =
    4706         939 :                             ldb_msg_find_attr_as_string(
    4707         939 :                                 rec->msgs[0], "sAMAccountName", "");
    4708        1878 :                         entriesGeneral[count].full_name.string =
    4709         939 :                             ldb_msg_find_attr_as_string(
    4710         939 :                                 rec->msgs[0], "displayName", "");
    4711        1878 :                         entriesGeneral[count].description.string =
    4712         939 :                             ldb_msg_find_attr_as_string(
    4713         939 :                                 rec->msgs[0], "description", "");
    4714         939 :                         break;
    4715          52 :                 case 2:
    4716          52 :                         entriesFull[count].idx = idx + 1;
    4717          52 :                         entriesFull[count].rid = rid;
    4718             : 
    4719             :                         /*
    4720             :                          * No idea why we need to or in ACB_NORMAL here,
    4721             :                          * but this is what Win2k3 seems to do...
    4722             :                          */
    4723          52 :                         entriesFull[count].acct_flags =
    4724          52 :                             samdb_result_acct_flags(rec->msgs[0], NULL) |
    4725             :                             ACB_NORMAL;
    4726         104 :                         entriesFull[count].account_name.string =
    4727          52 :                             ldb_msg_find_attr_as_string(
    4728          52 :                                 rec->msgs[0], "sAMAccountName", "");
    4729         104 :                         entriesFull[count].description.string =
    4730          52 :                             ldb_msg_find_attr_as_string(
    4731          52 :                                 rec->msgs[0], "description", "");
    4732          52 :                         break;
    4733         905 :                 case 3:
    4734         905 :                         entriesFullGroup[count].idx = idx + 1;
    4735         905 :                         entriesFullGroup[count].rid = rid;
    4736             : 
    4737             :                         /*
    4738             :                          * We get a "7" here for groups
    4739             :                          */
    4740         905 :                         entriesFullGroup[count].acct_flags = SE_GROUP_DEFAULT_FLAGS;
    4741        1810 :                         entriesFullGroup[count].account_name.string =
    4742         905 :                             ldb_msg_find_attr_as_string(
    4743         905 :                                 rec->msgs[0], "sAMAccountName", "");
    4744        1810 :                         entriesFullGroup[count].description.string =
    4745         905 :                             ldb_msg_find_attr_as_string(
    4746         905 :                                 rec->msgs[0], "description", "");
    4747         905 :                         break;
    4748         694 :                 case 4:
    4749             :                 case 5:
    4750         694 :                         entriesAscii[count].idx = idx + 1;
    4751        1388 :                         entriesAscii[count].account_name.string =
    4752         694 :                             ldb_msg_find_attr_as_string(
    4753         694 :                                 rec->msgs[0], "sAMAccountName", "");
    4754         694 :                         break;
    4755             :                 }
    4756        2590 :                 count++;
    4757             :         }
    4758             : 
    4759             :         /*
    4760             :          * Build the response based on the request level.
    4761             :          */
    4762         360 :         *r->out.returned_size = count;
    4763         360 :         switch(r->in.level) {
    4764         134 :         case 1:
    4765         134 :                 r->out.info->info1.count = count;
    4766         134 :                 r->out.info->info1.entries = entriesGeneral;
    4767         134 :                 break;
    4768          26 :         case 2:
    4769          26 :                 r->out.info->info2.count = count;
    4770          26 :                 r->out.info->info2.entries = entriesFull;
    4771          26 :                 break;
    4772          68 :         case 3:
    4773          68 :                 r->out.info->info3.count = count;
    4774          68 :                 r->out.info->info3.entries = entriesFullGroup;
    4775          68 :                 break;
    4776          56 :         case 4:
    4777          56 :                 r->out.info->info4.count = count;
    4778          56 :                 r->out.info->info4.entries = entriesAscii;
    4779          56 :                 break;
    4780          76 :         case 5:
    4781          76 :                 r->out.info->info5.count = count;
    4782          76 :                 r->out.info->info5.entries = entriesAscii;
    4783          76 :                 break;
    4784             :         }
    4785             : 
    4786         360 :         return ((r->in.start_idx + results) < cache->size)
    4787             :                    ? STATUS_MORE_ENTRIES
    4788         360 :                    : NT_STATUS_OK;
    4789             : }
    4790             : 
    4791             : 
    4792             : /*
    4793             :   samr_GetDisplayEnumerationIndex
    4794             : */
    4795           0 : static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4796             :                        struct samr_GetDisplayEnumerationIndex *r)
    4797             : {
    4798           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    4799             : }
    4800             : 
    4801             : 
    4802             : /*
    4803             :   samr_TestPrivateFunctionsDomain
    4804             : */
    4805           6 : static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4806             :                        struct samr_TestPrivateFunctionsDomain *r)
    4807             : {
    4808           6 :         return NT_STATUS_NOT_IMPLEMENTED;
    4809             : }
    4810             : 
    4811             : 
    4812             : /*
    4813             :   samr_TestPrivateFunctionsUser
    4814             : */
    4815          12 : static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4816             :                        struct samr_TestPrivateFunctionsUser *r)
    4817             : {
    4818          12 :         return NT_STATUS_NOT_IMPLEMENTED;
    4819             : }
    4820             : 
    4821             : 
    4822             : /*
    4823             :   samr_GetUserPwInfo
    4824             : */
    4825        1235 : static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4826             :                                    struct samr_GetUserPwInfo *r)
    4827             : {
    4828          72 :         struct dcesrv_handle *h;
    4829          72 :         struct samr_account_state *a_state;
    4830             : 
    4831        1235 :         ZERO_STRUCTP(r->out.info);
    4832             : 
    4833        1235 :         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
    4834             : 
    4835        1235 :         a_state = h->data;
    4836             : 
    4837        2470 :         r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
    4838        1235 :                 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
    4839             :                 NULL);
    4840        1235 :         r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
    4841             :                 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
    4842             : 
    4843        1235 :         return NT_STATUS_OK;
    4844             : }
    4845             : 
    4846             : 
    4847             : /*
    4848             :   samr_RemoveMemberFromForeignDomain
    4849             : */
    4850          10 : static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
    4851             :                                                           TALLOC_CTX *mem_ctx,
    4852             :                                                           struct samr_RemoveMemberFromForeignDomain *r)
    4853             : {
    4854           0 :         struct dcesrv_handle *h;
    4855           0 :         struct samr_domain_state *d_state;
    4856           0 :         const char *memberdn;
    4857           0 :         struct ldb_message **res;
    4858          10 :         const char *no_attrs[] = { NULL };
    4859           0 :         int i, count;
    4860             : 
    4861          10 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    4862             : 
    4863          10 :         d_state = h->data;
    4864             : 
    4865          10 :         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
    4866             :                                        "distinguishedName", "(objectSid=%s)",
    4867          10 :                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
    4868             :         /* Nothing to do */
    4869          10 :         if (memberdn == NULL) {
    4870           6 :                 return NT_STATUS_OK;
    4871             :         }
    4872             : 
    4873           4 :         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
    4874             :                                     d_state->domain_dn, &res, no_attrs,
    4875           4 :                                     d_state->domain_sid,
    4876             :                                     "(&(member=%s)(objectClass=group)"
    4877             :                                     "(|(groupType=%d)(groupType=%d)))",
    4878             :                                     memberdn,
    4879             :                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
    4880             :                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
    4881             : 
    4882           4 :         if (count < 0)
    4883           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    4884             : 
    4885           4 :         for (i=0; i<count; i++) {
    4886           0 :                 struct ldb_message *mod;
    4887           0 :                 int ret;
    4888             : 
    4889           0 :                 mod = ldb_msg_new(mem_ctx);
    4890           0 :                 if (mod == NULL) {
    4891           0 :                         return NT_STATUS_NO_MEMORY;
    4892             :                 }
    4893             : 
    4894           0 :                 mod->dn = res[i]->dn;
    4895             : 
    4896           0 :                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
    4897             :                                          "member", memberdn) != LDB_SUCCESS)
    4898           0 :                         return NT_STATUS_NO_MEMORY;
    4899             : 
    4900           0 :                 ret = ldb_modify(d_state->sam_ctx, mod);
    4901           0 :                 talloc_free(mod);
    4902           0 :                 if (ret != LDB_SUCCESS) {
    4903           0 :                         return dsdb_ldb_err_to_ntstatus(ret);
    4904             :                 }
    4905             :         }
    4906             : 
    4907           4 :         return NT_STATUS_OK;
    4908             : }
    4909             : 
    4910             : 
    4911             : /*
    4912             :   samr_QueryDomainInfo2
    4913             : 
    4914             :   just an alias for samr_QueryDomainInfo
    4915             : */
    4916         107 : static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4917             :                        struct samr_QueryDomainInfo2 *r)
    4918             : {
    4919           0 :         struct samr_QueryDomainInfo r1;
    4920           0 :         NTSTATUS status;
    4921             : 
    4922         107 :         r1 = (struct samr_QueryDomainInfo) {
    4923         107 :                 .in.domain_handle = r->in.domain_handle,
    4924         107 :                 .in.level  = r->in.level,
    4925         107 :                 .out.info  = r->out.info,
    4926             :         };
    4927             : 
    4928         107 :         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
    4929             : 
    4930         107 :         return status;
    4931             : }
    4932             : 
    4933             : 
    4934             : /*
    4935             :   samr_QueryUserInfo2
    4936             : 
    4937             :   just an alias for samr_QueryUserInfo
    4938             : */
    4939         928 : static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4940             :                                     struct samr_QueryUserInfo2 *r)
    4941             : {
    4942           0 :         struct samr_QueryUserInfo r1;
    4943           0 :         NTSTATUS status;
    4944             : 
    4945         928 :         r1 = (struct samr_QueryUserInfo) {
    4946         928 :                 .in.user_handle = r->in.user_handle,
    4947         928 :                 .in.level  = r->in.level,
    4948         928 :                 .out.info  = r->out.info
    4949             :         };
    4950             : 
    4951         928 :         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
    4952             : 
    4953         928 :         return status;
    4954             : }
    4955             : 
    4956             : 
    4957             : /*
    4958             :   samr_QueryDisplayInfo2
    4959             : */
    4960          34 : static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4961             :                                        struct samr_QueryDisplayInfo2 *r)
    4962             : {
    4963           0 :         struct samr_QueryDisplayInfo q;
    4964           0 :         NTSTATUS result;
    4965             : 
    4966          34 :         q = (struct samr_QueryDisplayInfo) {
    4967          34 :                 .in.domain_handle = r->in.domain_handle,
    4968          34 :                 .in.level = r->in.level,
    4969          34 :                 .in.start_idx = r->in.start_idx,
    4970          34 :                 .in.max_entries = r->in.max_entries,
    4971          34 :                 .in.buf_size = r->in.buf_size,
    4972          34 :                 .out.total_size = r->out.total_size,
    4973          34 :                 .out.returned_size = r->out.returned_size,
    4974          34 :                 .out.info = r->out.info,
    4975             :         };
    4976             : 
    4977          34 :         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
    4978             : 
    4979          34 :         return result;
    4980             : }
    4981             : 
    4982             : 
    4983             : /*
    4984             :   samr_GetDisplayEnumerationIndex2
    4985             : */
    4986           0 : static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4987             :                        struct samr_GetDisplayEnumerationIndex2 *r)
    4988             : {
    4989           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    4990             : }
    4991             : 
    4992             : 
    4993             : /*
    4994             :   samr_QueryDisplayInfo3
    4995             : */
    4996          30 : static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    4997             :                        struct samr_QueryDisplayInfo3 *r)
    4998             : {
    4999           0 :         struct samr_QueryDisplayInfo q;
    5000           0 :         NTSTATUS result;
    5001             : 
    5002          30 :         q = (struct samr_QueryDisplayInfo) {
    5003          30 :                 .in.domain_handle = r->in.domain_handle,
    5004          30 :                 .in.level = r->in.level,
    5005          30 :                 .in.start_idx = r->in.start_idx,
    5006          30 :                 .in.max_entries = r->in.max_entries,
    5007          30 :                 .in.buf_size = r->in.buf_size,
    5008          30 :                 .out.total_size = r->out.total_size,
    5009          30 :                 .out.returned_size = r->out.returned_size,
    5010          30 :                 .out.info = r->out.info,
    5011             :         };
    5012             : 
    5013          30 :         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
    5014             : 
    5015          30 :         return result;
    5016             : }
    5017             : 
    5018             : 
    5019             : /*
    5020             :   samr_AddMultipleMembersToAlias
    5021             : */
    5022           0 : static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5023             :                        struct samr_AddMultipleMembersToAlias *r)
    5024             : {
    5025           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    5026             : }
    5027             : 
    5028             : 
    5029             : /*
    5030             :   samr_RemoveMultipleMembersFromAlias
    5031             : */
    5032           0 : static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5033             :                        struct samr_RemoveMultipleMembersFromAlias *r)
    5034             : {
    5035           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    5036             : }
    5037             : 
    5038             : 
    5039             : /*
    5040             :   samr_GetDomPwInfo
    5041             : 
    5042             :   this fetches the default password properties for a domain
    5043             : 
    5044             :   note that w2k3 completely ignores the domain name in this call, and
    5045             :   always returns the information for the servers primary domain
    5046             : */
    5047        2867 : static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5048             :                                   struct samr_GetDomPwInfo *r)
    5049             : {
    5050         480 :         struct ldb_message **msgs;
    5051         480 :         int ret;
    5052        2867 :         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
    5053         480 :         struct ldb_context *sam_ctx;
    5054             : 
    5055        2867 :         ZERO_STRUCTP(r->out.info);
    5056             : 
    5057        2867 :         sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
    5058        2867 :         if (sam_ctx == NULL) {
    5059           0 :                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
    5060             :         }
    5061             : 
    5062             :         /* The domain name in this call is ignored */
    5063        2867 :         ret = gendb_search_dn(sam_ctx,
    5064             :                            mem_ctx, NULL, &msgs, attrs);
    5065        2867 :         if (ret <= 0) {
    5066           0 :                 talloc_free(sam_ctx);
    5067             : 
    5068           0 :                 return NT_STATUS_NO_SUCH_DOMAIN;
    5069             :         }
    5070        2867 :         if (ret > 1) {
    5071           0 :                 talloc_free(msgs);
    5072           0 :                 talloc_free(sam_ctx);
    5073             : 
    5074           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    5075             :         }
    5076             : 
    5077        2867 :         r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
    5078             :                 "minPwdLength", 0);
    5079        2867 :         r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
    5080             :                 "pwdProperties", 1);
    5081             : 
    5082        2867 :         talloc_free(msgs);
    5083        2867 :         talloc_unlink(mem_ctx, sam_ctx);
    5084             : 
    5085        2867 :         return NT_STATUS_OK;
    5086             : }
    5087             : 
    5088             : 
    5089             : /*
    5090             :   samr_Connect2
    5091             : */
    5092        1013 : static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5093             :                               struct samr_Connect2 *r)
    5094             : {
    5095           4 :         struct samr_Connect c;
    5096             : 
    5097        1013 :         c = (struct samr_Connect) {
    5098             :                 .in.system_name = NULL,
    5099        1013 :                 .in.access_mask = r->in.access_mask,
    5100        1013 :                 .out.connect_handle = r->out.connect_handle,
    5101             :         };
    5102             : 
    5103        1013 :         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
    5104             : }
    5105             : 
    5106             : 
    5107             : /*
    5108             :   samr_SetUserInfo2
    5109             : 
    5110             :   just an alias for samr_SetUserInfo
    5111             : */
    5112        1688 : static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5113             :                                   struct samr_SetUserInfo2 *r)
    5114             : {
    5115          72 :         struct samr_SetUserInfo r2;
    5116             : 
    5117        1688 :         r2 = (struct samr_SetUserInfo) {
    5118        1688 :                 .in.user_handle = r->in.user_handle,
    5119        1688 :                 .in.level = r->in.level,
    5120        1688 :                 .in.info = r->in.info,
    5121             :         };
    5122             : 
    5123        1688 :         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
    5124             : }
    5125             : 
    5126             : 
    5127             : /*
    5128             :   samr_SetBootKeyInformation
    5129             : */
    5130           0 : static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5131             :                        struct samr_SetBootKeyInformation *r)
    5132             : {
    5133           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    5134             : }
    5135             : 
    5136             : 
    5137             : /*
    5138             :   samr_GetBootKeyInformation
    5139             : */
    5140           6 : static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5141             :                        struct samr_GetBootKeyInformation *r)
    5142             : {
    5143             :         /* Windows Server 2008 returns this */
    5144           6 :         return NT_STATUS_NOT_SUPPORTED;
    5145             : }
    5146             : 
    5147             : 
    5148             : /*
    5149             :   samr_Connect3
    5150             : */
    5151          66 : static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5152             :                        struct samr_Connect3 *r)
    5153             : {
    5154           0 :         struct samr_Connect c;
    5155             : 
    5156          66 :         c = (struct samr_Connect) {
    5157             :                 .in.system_name = NULL,
    5158          66 :                 .in.access_mask = r->in.access_mask,
    5159          66 :                 .out.connect_handle = r->out.connect_handle,
    5160             :         };
    5161             : 
    5162          66 :         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
    5163             : }
    5164             : 
    5165             : 
    5166             : /*
    5167             :   samr_Connect4
    5168             : */
    5169          66 : static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5170             :                        struct samr_Connect4 *r)
    5171             : {
    5172           0 :         struct samr_Connect c;
    5173             : 
    5174          66 :         c = (struct samr_Connect) {
    5175             :                 .in.system_name = NULL,
    5176          66 :                 .in.access_mask = r->in.access_mask,
    5177          66 :                 .out.connect_handle = r->out.connect_handle,
    5178             :         };
    5179             : 
    5180          66 :         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
    5181             : }
    5182             : 
    5183             : 
    5184             : /*
    5185             :   samr_Connect5
    5186             : */
    5187         154 : static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5188             :                               struct samr_Connect5 *r)
    5189             : {
    5190           0 :         struct samr_Connect c;
    5191           0 :         NTSTATUS status;
    5192             : 
    5193         154 :         c = (struct samr_Connect) {
    5194             :                 .in.system_name = NULL,
    5195         154 :                 .in.access_mask = r->in.access_mask,
    5196         154 :                 .out.connect_handle = r->out.connect_handle,
    5197             :         };
    5198             : 
    5199         154 :         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
    5200             : 
    5201         154 :         r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
    5202         154 :         r->out.info_out->info1.supported_features = 0;
    5203         154 :         *r->out.level_out = r->in.level_in;
    5204             : 
    5205         154 :         return status;
    5206             : }
    5207             : 
    5208             : 
    5209             : /*
    5210             :   samr_RidToSid
    5211             : */
    5212          24 : static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5213             :                               struct samr_RidToSid *r)
    5214             : {
    5215           0 :         struct samr_domain_state *d_state;
    5216           0 :         struct dcesrv_handle *h;
    5217             : 
    5218          24 :         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
    5219             : 
    5220          24 :         d_state = h->data;
    5221             : 
    5222             :         /* form the users SID */
    5223          24 :         *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
    5224          24 :         if (!*r->out.sid) {
    5225           0 :                 return NT_STATUS_NO_MEMORY;
    5226             :         }
    5227             : 
    5228          24 :         return NT_STATUS_OK;
    5229             : }
    5230             : 
    5231             : 
    5232             : /*
    5233             :   samr_SetDsrmPassword
    5234             : */
    5235           0 : static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    5236             :                        struct samr_SetDsrmPassword *r)
    5237             : {
    5238           0 :         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
    5239             : }
    5240             : 
    5241             : 
    5242             : /*
    5243             :   samr_ValidatePassword
    5244             : 
    5245             :   For now the call checks the password complexity (if active) and the minimum
    5246             :   password length on level 2 and 3. Level 1 is ignored for now.
    5247             : */
    5248           5 : static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
    5249             :                                              TALLOC_CTX *mem_ctx,
    5250             :                                              struct samr_ValidatePassword *r)
    5251             : {
    5252           5 :         struct samr_GetDomPwInfo r2 = {};
    5253           5 :         struct samr_PwInfo pwInfo = {};
    5254           5 :         const char *account = NULL;
    5255           0 :         DATA_BLOB password;
    5256           0 :         enum samr_ValidationStatus res;
    5257           0 :         NTSTATUS status;
    5258           0 :         enum dcerpc_transport_t transport =
    5259           5 :                 dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
    5260           5 :         enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
    5261             : 
    5262           5 :         if (transport != NCACN_IP_TCP && transport != NCALRPC) {
    5263           0 :                 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
    5264             :         }
    5265             : 
    5266           5 :         dcesrv_call_auth_info(dce_call, NULL, &auth_level);
    5267           5 :         if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
    5268           2 :                 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
    5269             :         }
    5270             : 
    5271           3 :         (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
    5272             : 
    5273           3 :         r2 = (struct samr_GetDomPwInfo) {
    5274             :                 .in.domain_name = NULL,
    5275             :                 .out.info = &pwInfo,
    5276             :         };
    5277             : 
    5278           3 :         status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
    5279           3 :         if (!NT_STATUS_IS_OK(status)) {
    5280           0 :                 return status;
    5281             :         }
    5282             : 
    5283           3 :         switch (r->in.level) {
    5284           0 :         case NetValidateAuthentication:
    5285             :                 /* we don't support this yet */
    5286           0 :                 return NT_STATUS_NOT_SUPPORTED;
    5287           0 :         break;
    5288           0 :         case NetValidatePasswordChange:
    5289           0 :                 account = r->in.req->req2.account.string;
    5290           0 :                 password = data_blob_const(r->in.req->req2.password.string,
    5291           0 :                                            r->in.req->req2.password.length);
    5292           0 :                 res = samdb_check_password(mem_ctx,
    5293           0 :                                            dce_call->conn->dce_ctx->lp_ctx,
    5294             :                                            account,
    5295             :                                            NULL, /* userPrincipalName */
    5296             :                                            NULL, /* displayName/full_name */
    5297             :                                            &password,
    5298             :                                            pwInfo.password_properties,
    5299           0 :                                            pwInfo.min_password_length);
    5300           0 :                 (*r->out.rep)->ctr2.status = res;
    5301           0 :         break;
    5302           3 :         case NetValidatePasswordReset:
    5303           3 :                 account = r->in.req->req3.account.string;
    5304           3 :                 password = data_blob_const(r->in.req->req3.password.string,
    5305           3 :                                            r->in.req->req3.password.length);
    5306           3 :                 res = samdb_check_password(mem_ctx,
    5307           3 :                                            dce_call->conn->dce_ctx->lp_ctx,
    5308             :                                            account,
    5309             :                                            NULL, /* userPrincipalName */
    5310             :                                            NULL, /* displayName/full_name */
    5311             :                                            &password,
    5312             :                                            pwInfo.password_properties,
    5313           3 :                                            pwInfo.min_password_length);
    5314           3 :                 (*r->out.rep)->ctr3.status = res;
    5315           3 :         break;
    5316           0 :         default:
    5317           0 :                 return NT_STATUS_INVALID_INFO_CLASS;
    5318             :         break;
    5319             :         }
    5320             : 
    5321           3 :         return NT_STATUS_OK;
    5322             : }
    5323             : 
    5324           0 : static void dcesrv_samr_Opnum68NotUsedOnWire(struct dcesrv_call_state *dce_call,
    5325             :                                              TALLOC_CTX *mem_ctx,
    5326             :                                              struct samr_Opnum68NotUsedOnWire *r)
    5327             : {
    5328           0 :         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
    5329             : }
    5330             : 
    5331           0 : static void dcesrv_samr_Opnum69NotUsedOnWire(struct dcesrv_call_state *dce_call,
    5332             :                                              TALLOC_CTX *mem_ctx,
    5333             :                                              struct samr_Opnum69NotUsedOnWire *r)
    5334             : {
    5335           0 :         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
    5336             : }
    5337             : 
    5338           0 : static void dcesrv_samr_Opnum70NotUsedOnWire(struct dcesrv_call_state *dce_call,
    5339             :                                              TALLOC_CTX *mem_ctx,
    5340             :                                              struct samr_Opnum70NotUsedOnWire *r)
    5341             : {
    5342           0 :         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
    5343             : }
    5344             : 
    5345           0 : static void dcesrv_samr_Opnum71NotUsedOnWire(struct dcesrv_call_state *dce_call,
    5346             :                                              TALLOC_CTX *mem_ctx,
    5347             :                                              struct samr_Opnum71NotUsedOnWire *r)
    5348             : {
    5349           0 :         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
    5350             : }
    5351             : 
    5352           0 : static void dcesrv_samr_Opnum72NotUsedOnWire(struct dcesrv_call_state *dce_call,
    5353             :                                              TALLOC_CTX *mem_ctx,
    5354             :                                              struct samr_Opnum72NotUsedOnWire *r)
    5355             : {
    5356           0 :         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
    5357             : }
    5358             : 
    5359             : /* include the generated boilerplate */
    5360             : #include "librpc/gen_ndr/ndr_samr_s.c"

Generated by: LCOV version 1.14