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

Generated by: LCOV version 1.14