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

Generated by: LCOV version 1.13