LCOV - code coverage report
Current view: top level - source4/rpc_server/samr - dcesrv_samr.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 1865 2270 82.2 %
Date: 2021-09-23 10:06:22 Functions: 81 96 84.4 %

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

Generated by: LCOV version 1.13