root/source4/rpc_server/samr/dcesrv_samr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dcesrv_samr_Connect
  2. dcesrv_samr_Close
  3. dcesrv_samr_SetSecurity
  4. dcesrv_samr_QuerySecurity
  5. dcesrv_samr_Shutdown
  6. dcesrv_samr_LookupDomain
  7. dcesrv_samr_EnumDomains
  8. dcesrv_samr_OpenDomain
  9. dcesrv_samr_info_DomInfo1
  10. dcesrv_samr_info_DomGeneralInformation
  11. dcesrv_samr_info_DomInfo3
  12. dcesrv_samr_info_DomOEMInformation
  13. dcesrv_samr_info_DomInfo5
  14. dcesrv_samr_info_DomInfo6
  15. dcesrv_samr_info_DomInfo7
  16. dcesrv_samr_info_DomInfo8
  17. dcesrv_samr_info_DomInfo9
  18. dcesrv_samr_info_DomGeneralInformation2
  19. dcesrv_samr_info_DomInfo12
  20. dcesrv_samr_info_DomInfo13
  21. dcesrv_samr_QueryDomainInfo
  22. dcesrv_samr_SetDomainInfo
  23. dcesrv_samr_CreateDomainGroup
  24. compare_SamEntry
  25. dcesrv_samr_EnumDomainGroups
  26. dcesrv_samr_CreateUser2
  27. dcesrv_samr_CreateUser
  28. dcesrv_samr_EnumDomainUsers
  29. dcesrv_samr_CreateDomAlias
  30. dcesrv_samr_EnumDomainAliases
  31. dcesrv_samr_GetAliasMembership
  32. dcesrv_samr_LookupNames
  33. dcesrv_samr_LookupRids
  34. dcesrv_samr_OpenGroup
  35. dcesrv_samr_QueryGroupInfo
  36. dcesrv_samr_SetGroupInfo
  37. dcesrv_samr_AddGroupMember
  38. dcesrv_samr_DeleteDomainGroup
  39. dcesrv_samr_DeleteGroupMember
  40. dcesrv_samr_QueryGroupMember
  41. dcesrv_samr_SetMemberAttributesOfGroup
  42. dcesrv_samr_OpenAlias
  43. dcesrv_samr_QueryAliasInfo
  44. dcesrv_samr_SetAliasInfo
  45. dcesrv_samr_DeleteDomAlias
  46. dcesrv_samr_AddAliasMember
  47. dcesrv_samr_DeleteAliasMember
  48. dcesrv_samr_GetMembersInAlias
  49. dcesrv_samr_OpenUser
  50. dcesrv_samr_DeleteUser
  51. dcesrv_samr_QueryUserInfo
  52. dcesrv_samr_SetUserInfo
  53. dcesrv_samr_GetGroupsForUser
  54. dcesrv_samr_QueryDisplayInfo
  55. dcesrv_samr_GetDisplayEnumerationIndex
  56. dcesrv_samr_TestPrivateFunctionsDomain
  57. dcesrv_samr_TestPrivateFunctionsUser
  58. dcesrv_samr_GetUserPwInfo
  59. dcesrv_samr_RemoveMemberFromForeignDomain
  60. dcesrv_samr_QueryDomainInfo2
  61. dcesrv_samr_QueryUserInfo2
  62. dcesrv_samr_QueryDisplayInfo2
  63. dcesrv_samr_GetDisplayEnumerationIndex2
  64. dcesrv_samr_QueryDisplayInfo3
  65. dcesrv_samr_AddMultipleMembersToAlias
  66. dcesrv_samr_RemoveMultipleMembersFromAlias
  67. dcesrv_samr_GetDomPwInfo
  68. dcesrv_samr_Connect2
  69. dcesrv_samr_SetUserInfo2
  70. dcesrv_samr_SetBootKeyInformation
  71. dcesrv_samr_GetBootKeyInformation
  72. dcesrv_samr_Connect3
  73. dcesrv_samr_Connect4
  74. dcesrv_samr_Connect5
  75. dcesrv_samr_RidToSid
  76. dcesrv_samr_SetDsrmPassword
  77. dcesrv_samr_ValidatePassword

   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    
  10    This program is free software; you can redistribute it and/or modify
  11    it under the terms of the GNU General Public License as published by
  12    the Free Software Foundation; either version 3 of the License, or
  13    (at your option) any later version.
  14    
  15    This program is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18    GNU General Public License for more details.
  19    
  20    You should have received a copy of the GNU General Public License
  21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 #include "includes.h"
  25 #include "librpc/gen_ndr/ndr_samr.h"
  26 #include "rpc_server/dcerpc_server.h"
  27 #include "rpc_server/common/common.h"
  28 #include "rpc_server/samr/dcesrv_samr.h"
  29 #include "system/time.h"
  30 #include "lib/ldb/include/ldb.h"
  31 #include "lib/ldb/include/ldb_errors.h"
  32 #include "dsdb/common/flags.h"
  33 #include "dsdb/samdb/samdb.h"
  34 #include "libcli/ldap/ldap_ndr.h"
  35 #include "libcli/security/security.h"
  36 #include "rpc_server/samr/proto.h"
  37 #include "../lib/util/util_ldb.h"
  38 #include "param/param.h"
  39 
  40 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
  41 
  42 #define QUERY_STRING(msg, field, attr) \
  43         info->field.string = samdb_result_string(msg, attr, "");
  44 #define QUERY_UINT(msg, field, attr) \
  45         info->field = samdb_result_uint(msg, attr, 0);
  46 #define QUERY_RID(msg, field, attr) \
  47         info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
  48 #define QUERY_UINT64(msg, field, attr) \
  49         info->field = samdb_result_uint64(msg, attr, 0);
  50 #define QUERY_APASSC(msg, field, attr) \
  51         info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
  52                                                          a_state->domain_state->domain_dn, msg, attr);
  53 #define QUERY_FPASSC(msg, field, attr) \
  54         info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
  55                                                          a_state->domain_state->domain_dn, msg);
  56 #define QUERY_LHOURS(msg, field, attr) \
  57         info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
  58 #define QUERY_AFLAGS(msg, field, attr) \
  59         info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
  60 #define QUERY_PARAMETERS(msg, field, attr) \
  61         info->field = samdb_result_parameters(mem_ctx, msg, attr);
  62 
  63 
  64 /* these are used to make the Set[User|Group]Info code easier to follow */
  65 
  66 #define SET_STRING(msg, field, attr) do {                               \
  67         struct ldb_message_element *set_el;                             \
  68         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
  69         if (r->in.info->field.string[0] == '\0') {                      \
  70                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
  71                         return NT_STATUS_NO_MEMORY;                     \
  72                 }                                                       \
  73         }                                                               \
  74         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
  75                 return NT_STATUS_NO_MEMORY;                             \
  76         }                                                               \
  77         set_el = ldb_msg_find_element(msg, attr);                       \
  78         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
  79 } while (0)
  80 
  81 #define SET_UINT(msg, field, attr) do {                                 \
  82         struct ldb_message_element *set_el;                             \
  83         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
  84                 return NT_STATUS_NO_MEMORY;                             \
  85         }                                                               \
  86         set_el = ldb_msg_find_element(msg, attr);                       \
  87         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
  88 } while (0)                                                             
  89                                                                         
  90 #define SET_INT64(msg, field, attr) do {                                \
  91         struct ldb_message_element *set_el;                             \
  92         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
  93                 return NT_STATUS_NO_MEMORY;                             \
  94         }                                                               \
  95         set_el = ldb_msg_find_element(msg, attr);                       \
  96         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
  97 } while (0)                                                             
  98                                                                         
  99 #define SET_UINT64(msg, field, attr) do {                               \
 100         struct ldb_message_element *set_el;                             \
 101         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
 102                 return NT_STATUS_NO_MEMORY;                             \
 103         }                                                               \
 104         set_el = ldb_msg_find_element(msg, attr);                       \
 105         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
 106 } while (0)                                                             
 107 
 108 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags)    \
 109         do { \
 110                 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
 111                         return NT_STATUS_INVALID_PARAMETER;             \
 112                 }                                                       \
 113         } while (0)                                                     \
 114         
 115 /* Set account flags, discarding flags that cannot be set with SAMR */                                                          
 116 #define SET_AFLAGS(msg, field, attr) do {                               \
 117         struct ldb_message_element *set_el;                             \
 118         if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
 119                 return NT_STATUS_INVALID_PARAMETER; \
 120         }                                                               \
 121         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
 122         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
 123         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
 124         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
 125         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
 126                 return NT_STATUS_NO_MEMORY;                             \
 127         }                                                               \
 128         set_el = ldb_msg_find_element(msg, attr);                       \
 129         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
 130 } while (0)                                                             
 131                                                                         
 132 #define SET_LHOURS(msg, field, attr) do {                               \
 133         struct ldb_message_element *set_el;                             \
 134         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
 135                 return NT_STATUS_NO_MEMORY;                             \
 136         }                                                               \
 137         set_el = ldb_msg_find_element(msg, attr);                       \
 138         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
 139 } while (0)
 140 
 141 #define SET_PARAMETERS(msg, field, attr) do {                           \
 142         struct ldb_message_element *set_el;                             \
 143         if (r->in.info->field.length != 0) {                            \
 144                 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
 145                         return NT_STATUS_NO_MEMORY;                     \
 146                 }                                                       \
 147                 set_el = ldb_msg_find_element(msg, attr);               \
 148                 set_el->flags = LDB_FLAG_MOD_REPLACE;                   \
 149         }                                                               \
 150 } while (0)
 151 
 152 
 153 
 154 /* 
 155   samr_Connect 
 156 
 157   create a connection to the SAM database
 158 */
 159 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 160                              struct samr_Connect *r)
 161 {
 162         struct samr_connect_state *c_state;
 163         struct dcesrv_handle *handle;
 164 
 165         ZERO_STRUCTP(r->out.connect_handle);
 166 
 167         c_state = talloc(dce_call->conn, struct samr_connect_state);
 168         if (!c_state) {
 169                 return NT_STATUS_NO_MEMORY;
 170         }
 171 
 172         /* make sure the sam database is accessible */
 173         c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info); 
 174         if (c_state->sam_ctx == NULL) {
 175                 talloc_free(c_state);
 176                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
 177         }
 178 
 179 
 180         handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
 181         if (!handle) {
 182                 talloc_free(c_state);
 183                 return NT_STATUS_NO_MEMORY;
 184         }
 185 
 186         handle->data = talloc_steal(handle, c_state);
 187 
 188         c_state->access_mask = r->in.access_mask;
 189         *r->out.connect_handle = handle->wire_handle;
 190 
 191         return NT_STATUS_OK;
 192 }
 193 
 194 
 195 /* 
 196   samr_Close 
 197 */
 198 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 199                            struct samr_Close *r)
 200 {
 201         struct dcesrv_handle *h;
 202 
 203         *r->out.handle = *r->in.handle;
 204 
 205         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
 206 
 207         talloc_free(h);
 208 
 209         ZERO_STRUCTP(r->out.handle);
 210 
 211         return NT_STATUS_OK;
 212 }
 213 
 214 
 215 /* 
 216   samr_SetSecurity 
 217 */
 218 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 219                                  struct samr_SetSecurity *r)
 220 {
 221         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 222 }
 223 
 224 
 225 /* 
 226   samr_QuerySecurity 
 227 */
 228 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 229                                    struct samr_QuerySecurity *r)
 230 {
 231         struct dcesrv_handle *h;
 232         struct sec_desc_buf *sd;
 233 
 234         *r->out.sdbuf = NULL;
 235 
 236         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
 237 
 238         sd = talloc(mem_ctx, struct sec_desc_buf);
 239         if (sd == NULL) {
 240                 return NT_STATUS_NO_MEMORY;
 241         }
 242 
 243         sd->sd = samdb_default_security_descriptor(mem_ctx);
 244 
 245         *r->out.sdbuf = sd;
 246 
 247         return NT_STATUS_OK;
 248 }
 249 
 250 
 251 /* 
 252   samr_Shutdown 
 253 
 254   we refuse this operation completely. If a admin wants to shutdown samr
 255   in Samba then they should use the samba admin tools to disable the samr pipe
 256 */
 257 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 258                               struct samr_Shutdown *r)
 259 {
 260         return NT_STATUS_ACCESS_DENIED;
 261 }
 262 
 263 
 264 /* 
 265   samr_LookupDomain 
 266 
 267   this maps from a domain name to a SID
 268 */
 269 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 270                                   struct samr_LookupDomain *r)
 271 {
 272         struct samr_connect_state *c_state;
 273         struct dcesrv_handle *h;
 274         struct dom_sid *sid;
 275         const char * const dom_attrs[] = { "objectSid", NULL};
 276         const char * const ref_attrs[] = { "ncName", NULL};
 277         struct ldb_message **dom_msgs;
 278         struct ldb_message **ref_msgs;
 279         int ret;
 280         struct ldb_dn *partitions_basedn;
 281 
 282         *r->out.sid = NULL;
 283 
 284         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
 285 
 286         c_state = h->data;
 287 
 288         if (r->in.domain_name->string == NULL) {
 289                 return NT_STATUS_INVALID_PARAMETER;
 290         }
 291 
 292         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
 293 
 294         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
 295                 ret = gendb_search(c_state->sam_ctx,
 296                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
 297                                    "(objectClass=builtinDomain)");
 298         } else {
 299                 ret = gendb_search(c_state->sam_ctx,
 300                                    mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
 301                                    "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
 302                                    ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
 303                 if (ret != 1) {
 304                         return NT_STATUS_NO_SUCH_DOMAIN;
 305                 }
 306                 
 307                 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx, 
 308                                       samdb_result_dn(c_state->sam_ctx, mem_ctx,
 309                                                       ref_msgs[0], "ncName", NULL), 
 310                                       &dom_msgs, dom_attrs);
 311         }
 312 
 313         if (ret != 1) {
 314                 return NT_STATUS_NO_SUCH_DOMAIN;
 315         }
 316         
 317         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
 318                                    "objectSid");
 319                 
 320         if (sid == NULL) {
 321                 return NT_STATUS_NO_SUCH_DOMAIN;
 322         }
 323 
 324         *r->out.sid = sid;
 325 
 326         return NT_STATUS_OK;
 327 }
 328 
 329 
 330 /* 
 331   samr_EnumDomains 
 332 
 333   list the domains in the SAM
 334 */
 335 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 336                                  struct samr_EnumDomains *r)
 337 {
 338         struct samr_connect_state *c_state;
 339         struct dcesrv_handle *h;
 340         struct samr_SamArray *array;
 341         int i, start_i, ret;
 342         const char * const dom_attrs[] = { "cn", NULL};
 343         const char * const ref_attrs[] = { "nETBIOSName", NULL};
 344         struct ldb_result *dom_res;
 345         struct ldb_result *ref_res;
 346         struct ldb_dn *partitions_basedn;
 347 
 348         *r->out.resume_handle = 0;
 349         *r->out.sam = NULL;
 350         *r->out.num_entries = 0;
 351 
 352         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
 353 
 354         c_state = h->data;
 355 
 356         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
 357 
 358         ret = ldb_search(c_state->sam_ctx, mem_ctx, &dom_res, ldb_get_default_basedn(c_state->sam_ctx),
 359                                  LDB_SCOPE_SUBTREE, dom_attrs, "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
 360         if (ret != LDB_SUCCESS) {
 361                 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
 362                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 363         }
 364 
 365         *r->out.resume_handle = dom_res->count;
 366 
 367         start_i = *r->in.resume_handle;
 368 
 369         if (start_i >= dom_res->count) {
 370                 /* search past end of list is not an error for this call */
 371                 return NT_STATUS_OK;
 372         }
 373 
 374         array = talloc(mem_ctx, struct samr_SamArray);
 375         if (array == NULL) {
 376                 return NT_STATUS_NO_MEMORY;
 377         }
 378                 
 379         array->count = 0;
 380         array->entries = NULL;
 381 
 382         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, dom_res->count - start_i);
 383         if (array->entries == NULL) {
 384                 return NT_STATUS_NO_MEMORY;
 385         }
 386 
 387         for (i=0;i<dom_res->count-start_i;i++) {
 388                 array->entries[i].idx = start_i + i;
 389                 /* try and find the domain */
 390                 ret = ldb_search(c_state->sam_ctx, mem_ctx, &ref_res, partitions_basedn,
 391                                          LDB_SCOPE_SUBTREE, ref_attrs, "(&(objectClass=crossRef)(ncName=%s))", 
 392                                          ldb_dn_get_linearized(dom_res->msgs[i]->dn));
 393 
 394                 if (ret != LDB_SUCCESS) {
 395                         DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
 396                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
 397                 }
 398 
 399                 if (ref_res->count == 1) {
 400                         array->entries[i].name.string = samdb_result_string(ref_res->msgs[0], "nETBIOSName", NULL);
 401                 } else {
 402                         array->entries[i].name.string = samdb_result_string(dom_res->msgs[i], "cn", NULL);
 403                 }
 404         }
 405 
 406         *r->out.sam = array;
 407         *r->out.num_entries = i;
 408         array->count = *r->out.num_entries;
 409 
 410         return NT_STATUS_OK;
 411 }
 412 
 413 
 414 /* 
 415   samr_OpenDomain 
 416 */
 417 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 418                                 struct samr_OpenDomain *r)
 419 {
 420         struct dcesrv_handle *h_conn, *h_domain;
 421         const char *domain_name;
 422         struct samr_connect_state *c_state;
 423         struct samr_domain_state *d_state;
 424         const char * const dom_attrs[] = { "cn", NULL};
 425         const char * const ref_attrs[] = { "nETBIOSName", NULL};
 426         struct ldb_message **dom_msgs;
 427         struct ldb_message **ref_msgs;
 428         int ret;
 429         struct ldb_dn *partitions_basedn;
 430 
 431         ZERO_STRUCTP(r->out.domain_handle);
 432 
 433         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
 434 
 435         c_state = h_conn->data;
 436 
 437         if (r->in.sid == NULL) {
 438                 return NT_STATUS_INVALID_PARAMETER;
 439         }
 440 
 441         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
 442 
 443         ret = gendb_search(c_state->sam_ctx,
 444                            mem_ctx, NULL, &dom_msgs, dom_attrs,
 445                            "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))", 
 446                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
 447         if (ret == 0) {
 448                 return NT_STATUS_NO_SUCH_DOMAIN;
 449         } else if (ret > 1) {
 450                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 451         } else if (ret == -1) {
 452                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
 453                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 454         } else {
 455                 ret = gendb_search(c_state->sam_ctx,
 456                                    mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
 457                                    "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))", 
 458                                    ldb_dn_get_linearized(dom_msgs[0]->dn));
 459                 if (ret == 0) {
 460                         domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL);
 461                         if (domain_name == NULL) {
 462                                 return NT_STATUS_NO_SUCH_DOMAIN;
 463                         }
 464                 } else if (ret == 1) {
 465                 
 466                         domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL);
 467                         if (domain_name == NULL) {
 468                                 return NT_STATUS_NO_SUCH_DOMAIN;
 469                         }
 470                 } else {
 471                         return NT_STATUS_NO_SUCH_DOMAIN;
 472                 }
 473         }
 474 
 475         d_state = talloc(c_state, struct samr_domain_state);
 476         if (!d_state) {
 477                 return NT_STATUS_NO_MEMORY;
 478         }
 479 
 480         d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
 481         d_state->connect_state = talloc_reference(d_state, c_state);
 482         d_state->sam_ctx = c_state->sam_ctx;
 483         d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
 484         d_state->domain_name = talloc_strdup(d_state, domain_name);
 485         d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
 486         if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
 487                 talloc_free(d_state);
 488                 return NT_STATUS_NO_MEMORY;             
 489         }
 490         d_state->access_mask = r->in.access_mask;
 491 
 492         if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
 493                 d_state->builtin = true;
 494         } else {
 495                 d_state->builtin = false;
 496         }
 497 
 498         d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
 499 
 500         h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
 501         if (!h_domain) {
 502                 talloc_free(d_state);
 503                 return NT_STATUS_NO_MEMORY;
 504         }
 505         
 506         h_domain->data = talloc_steal(h_domain, d_state);
 507 
 508         *r->out.domain_handle = h_domain->wire_handle;
 509 
 510         return NT_STATUS_OK;
 511 }
 512 
 513 /*
 514   return DomInfo1
 515 */
 516 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 517                                    TALLOC_CTX *mem_ctx,
 518                                     struct ldb_message **dom_msgs,
 519                                    struct samr_DomInfo1 *info)
 520 {
 521         info->min_password_length =
 522                 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
 523         info->password_history_length =
 524                 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
 525         info->password_properties = 
 526                 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
 527         info->max_password_age = 
 528                 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
 529         info->min_password_age = 
 530                 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
 531 
 532         return NT_STATUS_OK;
 533 }
 534 
 535 /*
 536   return DomInfo2
 537 */
 538 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state, 
     /* [<][>][^][v][top][bottom][index][help] */
 539                                                        TALLOC_CTX *mem_ctx,
 540                                                        struct ldb_message **dom_msgs,
 541                                                        struct samr_DomGeneralInformation *info)
 542 {
 543         /* This pulls the NetBIOS name from the 
 544            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
 545            string */
 546         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
 547 
 548         if (!info->primary.string) {
 549                 info->primary.string = lp_netbios_name(state->lp_ctx);
 550         }
 551 
 552         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
 553                                                             0x8000000000000000LL);
 554 
 555         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
 556         info->domain_name.string  = state->domain_name;
 557 
 558         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
 559                                                  0);
 560         switch (state->role) {
 561         case ROLE_DOMAIN_CONTROLLER:
 562                 /* This pulls the NetBIOS name from the 
 563                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
 564                    string */
 565                 if (samdb_is_pdc(state->sam_ctx)) {
 566                         info->role = SAMR_ROLE_DOMAIN_PDC;
 567                 } else {
 568                         info->role = SAMR_ROLE_DOMAIN_BDC;
 569                 }
 570                 break;
 571         case ROLE_DOMAIN_MEMBER:
 572                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
 573                 break;
 574         case ROLE_STANDALONE:
 575                 info->role = SAMR_ROLE_STANDALONE;
 576                 break;
 577         }
 578 
 579         /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
 580         info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, 
 581                                              "(objectClass=user)");
 582         info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
 583                                               "(&(objectClass=group)(sAMAccountType=%u))",
 584                                               ATYPE_GLOBAL_GROUP);
 585         info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
 586                                                "(&(objectClass=group)(sAMAccountType=%u))",
 587                                                ATYPE_LOCAL_GROUP);
 588 
 589         return NT_STATUS_OK;
 590 }
 591 
 592 /*
 593   return DomInfo3
 594 */
 595 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 596                                    TALLOC_CTX *mem_ctx,
 597                                     struct ldb_message **dom_msgs,
 598                                    struct samr_DomInfo3 *info)
 599 {
 600         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
 601                                                       0x8000000000000000LL);
 602 
 603         return NT_STATUS_OK;
 604 }
 605 
 606 /*
 607   return DomInfo4
 608 */
 609 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 610                                    TALLOC_CTX *mem_ctx,
 611                                     struct ldb_message **dom_msgs,
 612                                    struct samr_DomOEMInformation *info)
 613 {
 614         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
 615 
 616         return NT_STATUS_OK;
 617 }
 618 
 619 /*
 620   return DomInfo5
 621 */
 622 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 623                                    TALLOC_CTX *mem_ctx,
 624                                     struct ldb_message **dom_msgs,
 625                                    struct samr_DomInfo5 *info)
 626 {
 627         info->domain_name.string  = state->domain_name;
 628 
 629         return NT_STATUS_OK;
 630 }
 631 
 632 /*
 633   return DomInfo6
 634 */
 635 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 636                                    TALLOC_CTX *mem_ctx,
 637                                    struct ldb_message **dom_msgs,
 638                                    struct samr_DomInfo6 *info)
 639 {
 640         /* This pulls the NetBIOS name from the 
 641            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
 642            string */
 643         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, 
 644                                                       dom_msgs[0], "fSMORoleOwner");
 645 
 646         if (!info->primary.string) {
 647                 info->primary.string = lp_netbios_name(state->lp_ctx);
 648         }
 649 
 650         return NT_STATUS_OK;
 651 }
 652 
 653 /*
 654   return DomInfo7
 655 */
 656 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 657                                    TALLOC_CTX *mem_ctx,
 658                                     struct ldb_message **dom_msgs,
 659                                    struct samr_DomInfo7 *info)
 660 {
 661 
 662         switch (state->role) {
 663         case ROLE_DOMAIN_CONTROLLER:
 664                 /* This pulls the NetBIOS name from the 
 665                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
 666                    string */
 667                 if (samdb_is_pdc(state->sam_ctx)) {
 668                         info->role = SAMR_ROLE_DOMAIN_PDC;
 669                 } else {
 670                         info->role = SAMR_ROLE_DOMAIN_BDC;
 671                 }
 672                 break;
 673         case ROLE_DOMAIN_MEMBER:
 674                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
 675                 break;
 676         case ROLE_STANDALONE:
 677                 info->role = SAMR_ROLE_STANDALONE;
 678                 break;
 679         }
 680 
 681         return NT_STATUS_OK;
 682 }
 683 
 684 /*
 685   return DomInfo8
 686 */
 687 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 688                                    TALLOC_CTX *mem_ctx,
 689                                     struct ldb_message **dom_msgs,
 690                                    struct samr_DomInfo8 *info)
 691 {
 692         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
 693                                                time(NULL));
 694 
 695         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
 696                                                      0x0LL);
 697 
 698         return NT_STATUS_OK;
 699 }
 700 
 701 /*
 702   return DomInfo9
 703 */
 704 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 705                                    TALLOC_CTX *mem_ctx,
 706                                     struct ldb_message **dom_msgs,
 707                                    struct samr_DomInfo9 *info)
 708 {
 709         info->domain_server_state = DOMAIN_SERVER_ENABLED;
 710 
 711         return NT_STATUS_OK;
 712 }
 713 
 714 /*
 715   return DomInfo11
 716 */
 717 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 718                                     TALLOC_CTX *mem_ctx,
 719                                     struct ldb_message **dom_msgs,
 720                                     struct samr_DomGeneralInformation2 *info)
 721 {
 722         NTSTATUS status;
 723         status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
 724         if (!NT_STATUS_IS_OK(status)) {
 725                 return status;
 726         }
 727         
 728         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
 729                                                     -18000000000LL);
 730         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
 731                                                     -18000000000LL);
 732         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
 733 
 734         return NT_STATUS_OK;
 735 }
 736 
 737 /*
 738   return DomInfo12
 739 */
 740 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 741                                    TALLOC_CTX *mem_ctx,
 742                                     struct ldb_message **dom_msgs,
 743                                    struct samr_DomInfo12 *info)
 744 {
 745         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
 746                                                     -18000000000LL);
 747         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
 748                                                     -18000000000LL);
 749         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
 750 
 751         return NT_STATUS_OK;
 752 }
 753 
 754 /*
 755   return DomInfo13
 756 */
 757 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 758                                     TALLOC_CTX *mem_ctx,
 759                                     struct ldb_message **dom_msgs,
 760                                     struct samr_DomInfo13 *info)
 761 {
 762         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
 763                                                time(NULL));
 764 
 765         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
 766                                                      0x0LL);
 767 
 768         info->modified_count_at_last_promotion = 0;
 769 
 770         return NT_STATUS_OK;
 771 }
 772 
 773 /* 
 774   samr_QueryDomainInfo 
 775 */
 776 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 777                                      struct samr_QueryDomainInfo *r)
 778 {
 779         struct dcesrv_handle *h;
 780         struct samr_domain_state *d_state;
 781         union samr_DomainInfo *info;
 782 
 783         struct ldb_message **dom_msgs;
 784         const char * const *attrs = NULL;
 785         
 786         *r->out.info = NULL;
 787 
 788         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
 789 
 790         d_state = h->data;
 791 
 792         info = talloc(mem_ctx, union samr_DomainInfo);
 793         if (!info) {
 794                 return NT_STATUS_NO_MEMORY;
 795         }
 796 
 797         switch (r->in.level) {
 798         case 1: 
 799         {
 800                 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
 801                                                        "pwdProperties", "maxPwdAge",
 802                                                        "minPwdAge", NULL };
 803                 attrs = attrs2;
 804                 break;
 805         }
 806         case 2:
 807         {
 808                 static const char * const attrs2[] = {"forceLogoff",
 809                                                       "oEMInformation", 
 810                                                       "modifiedCount", 
 811                                                       "fSMORoleOwner",
 812                                                       NULL};
 813                 attrs = attrs2;
 814                 break;
 815         }
 816         case 3:
 817         {
 818                 static const char * const attrs2[] = {"forceLogoff", 
 819                                                       NULL};
 820                 attrs = attrs2;
 821                 break;
 822         }
 823         case 4:
 824         {
 825                 static const char * const attrs2[] = {"oEMInformation", 
 826                                                       NULL};
 827                 attrs = attrs2;
 828                 break;
 829         }
 830         case 5:
 831         {
 832                 attrs = NULL;
 833                 break;
 834         }
 835         case 6:
 836         {
 837                 static const char * const attrs2[] = {"fSMORoleOwner", 
 838                                                       NULL};
 839                 attrs = attrs2;
 840                 break;
 841         }
 842         case 7:
 843         {
 844                 attrs = NULL;
 845                 break;
 846         }
 847         case 8:
 848         {
 849                 static const char * const attrs2[] = { "modifiedCount", 
 850                                                        "creationTime", 
 851                                                        NULL };
 852                 attrs = attrs2;
 853                 break;
 854         }
 855         case 9:
 856                 attrs = NULL;
 857                 break;          
 858         case 11:
 859         {
 860                 static const char * const attrs2[] = { "oEMInformation", "forceLogoff", 
 861                                                        "modifiedCount", 
 862                                                        "lockoutDuration", 
 863                                                        "lockOutObservationWindow", 
 864                                                        "lockoutThreshold", 
 865                                                        NULL};
 866                 attrs = attrs2;
 867                 break;
 868         }
 869         case 12:
 870         {
 871                 static const char * const attrs2[] = { "lockoutDuration", 
 872                                                        "lockOutObservationWindow", 
 873                                                        "lockoutThreshold", 
 874                                                        NULL};
 875                 attrs = attrs2;
 876                 break;
 877         }
 878         case 13:
 879         {
 880                 static const char * const attrs2[] = { "modifiedCount", 
 881                                                        "creationTime", 
 882                                                        NULL };
 883                 attrs = attrs2;
 884                 break;
 885         }
 886         }
 887 
 888         /* some levels don't need a search */
 889         if (attrs) {
 890                 int ret;
 891                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
 892                                       d_state->domain_dn, &dom_msgs, attrs);
 893                 if (ret != 1) {
 894                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
 895                 }
 896         }
 897 
 898         *r->out.info = info;
 899 
 900         ZERO_STRUCTP(info);
 901 
 902         switch (r->in.level) {
 903         case 1:
 904                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs, 
 905                                                  &info->info1);
 906         case 2:
 907                 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs, 
 908                                                               &info->general);
 909         case 3:
 910                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs, 
 911                                                  &info->info3);
 912         case 4:
 913                 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs, 
 914                                                           &info->oem);
 915         case 5:
 916                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs, 
 917                                                  &info->info5);
 918         case 6:
 919                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs, 
 920                                                  &info->info6);
 921         case 7:
 922                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs, 
 923                                                  &info->info7);
 924         case 8:
 925                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs, 
 926                                                  &info->info8);
 927         case 9:
 928                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs, 
 929                                                  &info->info9);
 930         case 11:
 931                 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs, 
 932                                                                &info->general2);
 933         case 12:
 934                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs, 
 935                                                   &info->info12);
 936         case 13:
 937                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs, 
 938                                                   &info->info13);
 939         }
 940 
 941         return NT_STATUS_INVALID_INFO_CLASS;
 942 }
 943 
 944 
 945 /* 
 946   samr_SetDomainInfo 
 947 */
 948 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 949                        struct samr_SetDomainInfo *r)
 950 {
 951         struct dcesrv_handle *h;
 952         struct samr_domain_state *d_state;
 953         struct ldb_message *msg;
 954         int ret;
 955         struct ldb_context *sam_ctx;
 956 
 957         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
 958 
 959         d_state = h->data;
 960         sam_ctx = d_state->sam_ctx;
 961 
 962         msg = ldb_msg_new(mem_ctx);
 963         if (msg == NULL) {
 964                 return NT_STATUS_NO_MEMORY;
 965         }
 966 
 967         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
 968         if (!msg->dn) {
 969                 return NT_STATUS_NO_MEMORY;
 970         }
 971 
 972         switch (r->in.level) {
 973         case 1:
 974                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
 975                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
 976                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
 977                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
 978                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
 979                 break;
 980         case 3:
 981                 SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");
 982                 break;
 983         case 4:
 984                 SET_STRING(msg, oem.oem_information,           "oEMInformation");
 985                 break;
 986 
 987         case 6:
 988         case 7:
 989         case 9:
 990                 /* No op, we don't know where to set these */
 991                 return NT_STATUS_OK;
 992 
 993         case 12:
 994                 
 995                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
 996                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
 997                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
 998                 break;
 999 
1000         default:
1001                 /* many info classes are not valid for SetDomainInfo */
1002                 return NT_STATUS_INVALID_INFO_CLASS;
1003         }
1004 
1005         /* modify the samdb record */
1006         ret = ldb_modify(sam_ctx, msg);
1007         if (ret != 0) {
1008                 DEBUG(1,("Failed to modify record %s: %s\n",
1009                          ldb_dn_get_linearized(d_state->domain_dn),
1010                          ldb_errstring(sam_ctx)));
1011 
1012                 /* we really need samdb.c to return NTSTATUS */
1013                 return NT_STATUS_UNSUCCESSFUL;
1014         }
1015 
1016         return NT_STATUS_OK;
1017 }
1018 
1019 /* 
1020   samr_CreateDomainGroup 
1021 */
1022 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1023                                        struct samr_CreateDomainGroup *r)
1024 {
1025         struct samr_domain_state *d_state;
1026         struct samr_account_state *a_state;
1027         struct dcesrv_handle *h;
1028         const char *name;
1029         struct ldb_message *msg;
1030         struct dom_sid *sid;
1031         const char *groupname;
1032         struct dcesrv_handle *g_handle;
1033         int ret;
1034 
1035         ZERO_STRUCTP(r->out.group_handle);
1036         *r->out.rid = 0;
1037 
1038         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1039 
1040         d_state = h->data;
1041 
1042         if (d_state->builtin) {
1043                 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1044                 return NT_STATUS_ACCESS_DENIED;
1045         }
1046 
1047         groupname = r->in.name->string;
1048 
1049         if (groupname == NULL) {
1050                 return NT_STATUS_INVALID_PARAMETER;
1051         }
1052 
1053         /* check if the group already exists */
1054         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1055                                    "sAMAccountName",
1056                                    "(&(sAMAccountName=%s)(objectclass=group))",
1057                                    ldb_binary_encode_string(mem_ctx, groupname));
1058         if (name != NULL) {
1059                 return NT_STATUS_GROUP_EXISTS;
1060         }
1061 
1062         msg = ldb_msg_new(mem_ctx);
1063         if (msg == NULL) {
1064                 return NT_STATUS_NO_MEMORY;
1065         }
1066 
1067         /* add core elements to the ldb_message for the user */
1068         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1069         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1070         if (!msg->dn) {
1071                 return NT_STATUS_NO_MEMORY;
1072         }
1073         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1074         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1075                              
1076         /* create the group */
1077         ret = ldb_add(d_state->sam_ctx, msg);
1078         switch (ret) {
1079         case  LDB_SUCCESS:
1080                 break;
1081         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1082                 DEBUG(0,("Failed to create group record %s: %s\n",
1083                          ldb_dn_get_linearized(msg->dn),
1084                          ldb_errstring(d_state->sam_ctx)));
1085                 return NT_STATUS_GROUP_EXISTS;
1086         case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1087                 DEBUG(0,("Failed to create group record %s: %s\n",
1088                          ldb_dn_get_linearized(msg->dn),
1089                          ldb_errstring(d_state->sam_ctx)));
1090                 return NT_STATUS_ACCESS_DENIED;
1091         default:
1092                 DEBUG(0,("Failed to create group record %s: %s\n",
1093                          ldb_dn_get_linearized(msg->dn),
1094                          ldb_errstring(d_state->sam_ctx)));
1095                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1096         }
1097 
1098         a_state = talloc(d_state, struct samr_account_state);
1099         if (!a_state) {
1100                 return NT_STATUS_NO_MEMORY;
1101         }
1102         a_state->sam_ctx = d_state->sam_ctx;
1103         a_state->access_mask = r->in.access_mask;
1104         a_state->domain_state = talloc_reference(a_state, d_state);
1105         a_state->account_dn = talloc_steal(a_state, msg->dn);
1106 
1107         /* retrieve the sid for the group just created */
1108         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1109                                    msg->dn, "objectSid", NULL);
1110         if (sid == NULL) {
1111                 return NT_STATUS_UNSUCCESSFUL;
1112         }
1113 
1114         a_state->account_name = talloc_strdup(a_state, groupname);
1115         if (!a_state->account_name) {
1116                 return NT_STATUS_NO_MEMORY;
1117         }
1118 
1119         /* create the policy handle */
1120         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1121         if (!g_handle) {
1122                 return NT_STATUS_NO_MEMORY;
1123         }
1124 
1125         g_handle->data = talloc_steal(g_handle, a_state);
1126 
1127         *r->out.group_handle = g_handle->wire_handle;
1128         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1129 
1130         return NT_STATUS_OK;
1131 }
1132 
1133 
1134 /*
1135   comparison function for sorting SamEntry array
1136 */
1137 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
     /* [<][>][^][v][top][bottom][index][help] */
1138 {
1139         return e1->idx - e2->idx;
1140 }
1141 
1142 /* 
1143   samr_EnumDomainGroups 
1144 */
1145 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1146                                       struct samr_EnumDomainGroups *r)
1147 {
1148         struct dcesrv_handle *h;
1149         struct samr_domain_state *d_state;
1150         struct ldb_message **res;
1151         int ldb_cnt, count, i, first;
1152         struct samr_SamEntry *entries;
1153         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1154         struct samr_SamArray *sam;
1155 
1156         *r->out.resume_handle = 0;
1157         *r->out.sam = NULL;
1158         *r->out.num_entries = 0;
1159 
1160         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1161 
1162         d_state = h->data;
1163 
1164         /* search for all domain groups in this domain. This could possibly be
1165            cached and resumed based on resume_key */
1166         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1167                                       d_state->domain_dn, &res, attrs,
1168                                       d_state->domain_sid,
1169                                       "(&(grouptype=%d)(objectclass=group))",
1170                                       GTYPE_SECURITY_GLOBAL_GROUP);
1171         if (ldb_cnt == -1) {
1172                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1173         }
1174 
1175         /* convert to SamEntry format */
1176         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1177         if (!entries) {
1178                 return NT_STATUS_NO_MEMORY;
1179         }
1180 
1181         count = 0;
1182 
1183         for (i=0;i<ldb_cnt;i++) {
1184                 struct dom_sid *group_sid;
1185 
1186                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1187                                                  "objectSid");
1188                 if (group_sid == NULL)
1189                         continue;
1190 
1191                 entries[count].idx =
1192                         group_sid->sub_auths[group_sid->num_auths-1];
1193                 entries[count].name.string =
1194                         samdb_result_string(res[i], "sAMAccountName", "");
1195                 count += 1;
1196         }
1197 
1198         /* sort the results by rid */
1199         qsort(entries, count, sizeof(struct samr_SamEntry), 
1200               (comparison_fn_t)compare_SamEntry);
1201 
1202         /* find the first entry to return */
1203         for (first=0;
1204              first<count && entries[first].idx <= *r->in.resume_handle;
1205              first++) ;
1206 
1207         /* return the rest, limit by max_size. Note that we 
1208            use the w2k3 element size value of 54 */
1209         *r->out.num_entries = count - first;
1210         *r->out.num_entries = MIN(*r->out.num_entries,
1211                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1212 
1213         sam = talloc(mem_ctx, struct samr_SamArray);
1214         if (!sam) {
1215                 return NT_STATUS_NO_MEMORY;
1216         }
1217 
1218         sam->entries = entries+first;
1219         sam->count = *r->out.num_entries;
1220 
1221         *r->out.sam = sam;
1222 
1223         if (*r->out.num_entries < count - first) {
1224                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1225                 return STATUS_MORE_ENTRIES;
1226         }
1227 
1228         return NT_STATUS_OK;
1229 }
1230 
1231 
1232 /* 
1233   samr_CreateUser2 
1234 
1235   This call uses transactions to ensure we don't get a new conflicting
1236   user while we are processing this, and to ensure the user either
1237   completly exists, or does not.
1238 */
1239 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1240                                  struct samr_CreateUser2 *r)
1241 {
1242         struct samr_domain_state *d_state;
1243         struct samr_account_state *a_state;
1244         struct dcesrv_handle *h;
1245         const char *name;
1246         struct ldb_message *msg;
1247         struct dom_sid *sid;
1248         const char *account_name;
1249         struct dcesrv_handle *u_handle;
1250         int ret;
1251         const char *container, *obj_class=NULL;
1252         char *cn_name;
1253         int cn_name_len;
1254 
1255         const char *attrs[] = {
1256                 "objectSid", 
1257                 "userAccountControl",
1258                 NULL
1259         };
1260 
1261         uint32_t user_account_control;
1262 
1263         struct ldb_message **msgs;
1264 
1265         ZERO_STRUCTP(r->out.user_handle);
1266         *r->out.access_granted = 0;
1267         *r->out.rid = 0;
1268 
1269         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1270 
1271         d_state = h->data;
1272 
1273         if (d_state->builtin) {
1274                 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1275                 return NT_STATUS_ACCESS_DENIED;
1276         }
1277         account_name = r->in.account_name->string;
1278 
1279         if (account_name == NULL) {
1280                 return NT_STATUS_INVALID_PARAMETER;
1281         }
1282 
1283         ret = ldb_transaction_start(d_state->sam_ctx);
1284         if (ret != 0) {
1285                 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1286                          ldb_errstring(d_state->sam_ctx)));
1287                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1288         }
1289 
1290         /* check if the user already exists */
1291         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1292                                    "sAMAccountName", 
1293                                    "(&(sAMAccountName=%s)(objectclass=user))", 
1294                                    ldb_binary_encode_string(mem_ctx, account_name));
1295         if (name != NULL) {
1296                 ldb_transaction_cancel(d_state->sam_ctx);
1297                 return NT_STATUS_USER_EXISTS;
1298         }
1299 
1300         msg = ldb_msg_new(mem_ctx);
1301         if (msg == NULL) {
1302                 ldb_transaction_cancel(d_state->sam_ctx);
1303                 return NT_STATUS_NO_MEMORY;
1304         }
1305 
1306         cn_name   = talloc_strdup(mem_ctx, account_name);
1307         if (!cn_name) {
1308                 ldb_transaction_cancel(d_state->sam_ctx);
1309                 return NT_STATUS_NO_MEMORY;
1310         }
1311 
1312         cn_name_len = strlen(cn_name);
1313 
1314         /* This must be one of these values *only* */
1315         if (r->in.acct_flags == ACB_NORMAL) {
1316                 container = "CN=Users";
1317                 obj_class = "user";
1318 
1319         } else if (r->in.acct_flags == ACB_WSTRUST) {
1320                 if (cn_name[cn_name_len - 1] != '$') {
1321                         return NT_STATUS_FOOBAR;
1322                 }
1323                 cn_name[cn_name_len - 1] = '\0';
1324                 container = "CN=Computers";
1325                 obj_class = "computer";
1326                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1327 
1328         } else if (r->in.acct_flags == ACB_SVRTRUST) {
1329                 if (cn_name[cn_name_len - 1] != '$') {
1330                         return NT_STATUS_FOOBAR;                
1331                 }
1332                 cn_name[cn_name_len - 1] = '\0';
1333                 container = "OU=Domain Controllers";
1334                 obj_class = "computer";
1335                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS);
1336 
1337         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1338                 container = "CN=Users";
1339                 obj_class = "user";
1340 
1341         } else {
1342                 ldb_transaction_cancel(d_state->sam_ctx);
1343                 return NT_STATUS_INVALID_PARAMETER;
1344         }
1345 
1346         /* add core elements to the ldb_message for the user */
1347         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1348         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1349                 ldb_transaction_cancel(d_state->sam_ctx);
1350                 return NT_STATUS_FOOBAR;
1351         }
1352 
1353         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1354         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1355         
1356         /* Start a transaction, so we can query and do a subsequent atomic modify */
1357         
1358         /* create the user */
1359         ret = ldb_add(d_state->sam_ctx, msg);
1360         switch (ret) {
1361         case LDB_SUCCESS:
1362                 break;
1363         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1364                 ldb_transaction_cancel(d_state->sam_ctx);
1365                 DEBUG(0,("Failed to create user record %s: %s\n",
1366                          ldb_dn_get_linearized(msg->dn),
1367                          ldb_errstring(d_state->sam_ctx)));
1368                 return NT_STATUS_USER_EXISTS;
1369         case LDB_ERR_UNWILLING_TO_PERFORM:
1370         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1371                 ldb_transaction_cancel(d_state->sam_ctx);
1372                 DEBUG(0,("Failed to create user record %s: %s\n",
1373                          ldb_dn_get_linearized(msg->dn),
1374                          ldb_errstring(d_state->sam_ctx)));
1375                 return NT_STATUS_ACCESS_DENIED;
1376         default:
1377                 ldb_transaction_cancel(d_state->sam_ctx);
1378                 DEBUG(0,("Failed to create user record %s: %s\n",
1379                          ldb_dn_get_linearized(msg->dn),
1380                          ldb_errstring(d_state->sam_ctx)));
1381                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1382         }
1383 
1384         a_state = talloc(d_state, struct samr_account_state);
1385         if (!a_state) {
1386                 ldb_transaction_cancel(d_state->sam_ctx);
1387                 return NT_STATUS_NO_MEMORY;
1388         }
1389         a_state->sam_ctx = d_state->sam_ctx;
1390         a_state->access_mask = r->in.access_mask;
1391         a_state->domain_state = talloc_reference(a_state, d_state);
1392         a_state->account_dn = talloc_steal(a_state, msg->dn);
1393 
1394         /* retrieve the sid and account control bits for the user just created */
1395         ret = gendb_search_dn(d_state->sam_ctx, a_state,
1396                               msg->dn, &msgs, attrs);
1397 
1398         if (ret != 1) {
1399                 ldb_transaction_cancel(d_state->sam_ctx);
1400                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1401                          ldb_dn_get_linearized(msg->dn)));
1402                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1403         }
1404         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1405         if (sid == NULL) {
1406                 ldb_transaction_cancel(d_state->sam_ctx);
1407                 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1408                          ldb_dn_get_linearized(msg->dn)));
1409                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1410         }
1411 
1412         /* Change the account control to be the correct account type.
1413          * The default is for a workstation account */
1414         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1415         user_account_control = (user_account_control & 
1416                                 ~(UF_NORMAL_ACCOUNT |
1417                                   UF_INTERDOMAIN_TRUST_ACCOUNT | 
1418                                   UF_WORKSTATION_TRUST_ACCOUNT | 
1419                                   UF_SERVER_TRUST_ACCOUNT));
1420         user_account_control |= samdb_acb2uf(r->in.acct_flags);
1421 
1422         talloc_free(msg);
1423         msg = ldb_msg_new(mem_ctx);
1424         if (msg == NULL) {
1425                 ldb_transaction_cancel(d_state->sam_ctx);
1426                 return NT_STATUS_NO_MEMORY;
1427         }
1428 
1429         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1430 
1431         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
1432                                "userAccountControl", 
1433                                user_account_control) != 0) { 
1434                 ldb_transaction_cancel(d_state->sam_ctx);
1435                 return NT_STATUS_NO_MEMORY; 
1436         }
1437 
1438         /* modify the samdb record */
1439         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1440         if (ret != 0) {
1441                 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1442                          ldb_dn_get_linearized(msg->dn),
1443                          ldb_errstring(d_state->sam_ctx)));
1444                 ldb_transaction_cancel(d_state->sam_ctx);
1445 
1446                 /* we really need samdb.c to return NTSTATUS */
1447                 return NT_STATUS_UNSUCCESSFUL;
1448         }
1449 
1450         ret = ldb_transaction_commit(d_state->sam_ctx);
1451         if (ret != 0) {
1452                 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1453                          ldb_dn_get_linearized(msg->dn),
1454                          ldb_errstring(d_state->sam_ctx)));
1455                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1456         }
1457 
1458         a_state->account_name = talloc_steal(a_state, account_name);
1459         if (!a_state->account_name) {
1460                 return NT_STATUS_NO_MEMORY;
1461         }
1462 
1463         /* create the policy handle */
1464         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1465         if (!u_handle) {
1466                 return NT_STATUS_NO_MEMORY;
1467         }
1468 
1469         u_handle->data = talloc_steal(u_handle, a_state);
1470 
1471         *r->out.user_handle = u_handle->wire_handle;
1472         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1473 
1474         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1475 
1476         return NT_STATUS_OK;
1477 }
1478 
1479 
1480 /* 
1481   samr_CreateUser 
1482 */
1483 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1484                                 struct samr_CreateUser *r)
1485 {
1486         struct samr_CreateUser2 r2;
1487         uint32_t access_granted = 0;
1488 
1489 
1490         /* a simple wrapper around samr_CreateUser2 works nicely */
1491         r2.in.domain_handle = r->in.domain_handle;
1492         r2.in.account_name = r->in.account_name;
1493         r2.in.acct_flags = ACB_NORMAL;
1494         r2.in.access_mask = r->in.access_mask;
1495         r2.out.user_handle = r->out.user_handle;
1496         r2.out.access_granted = &access_granted;
1497         r2.out.rid = r->out.rid;
1498 
1499         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1500 }
1501 
1502 /* 
1503   samr_EnumDomainUsers 
1504 */
1505 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1506                                      struct samr_EnumDomainUsers *r)
1507 {
1508         struct dcesrv_handle *h;
1509         struct samr_domain_state *d_state;
1510         struct ldb_result *res;
1511         int ret, num_filtered_entries, i, first;
1512         struct samr_SamEntry *entries;
1513         const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
1514         struct samr_SamArray *sam;
1515 
1516         *r->out.resume_handle = 0;
1517         *r->out.sam = NULL;
1518         *r->out.num_entries = 0;
1519 
1520         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1521 
1522         d_state = h->data;
1523         
1524         /* don't have to worry about users in the builtin domain, as there are none */
1525         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1526 
1527         if (ret != LDB_SUCCESS) {
1528                 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n", 
1529                           ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1530                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1531         }
1532 
1533         /* convert to SamEntry format */
1534         entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1535         if (!entries) {
1536                 return NT_STATUS_NO_MEMORY;
1537         }
1538         num_filtered_entries = 0;
1539         for (i=0;i<res->count;i++) {
1540                 /* Check if a mask has been requested */
1541                 if (r->in.acct_flags
1542                     && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i], 
1543                                                  d_state->domain_dn) & r->in.acct_flags) == 0)) {
1544                         continue;
1545                 }
1546                 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1547                 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1548                 num_filtered_entries++;
1549         }
1550 
1551         /* sort the results by rid */
1552         qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), 
1553               (comparison_fn_t)compare_SamEntry);
1554 
1555         /* find the first entry to return */
1556         for (first=0;
1557              first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1558              first++) ;
1559 
1560         /* return the rest, limit by max_size. Note that we 
1561            use the w2k3 element size value of 54 */
1562         *r->out.num_entries = num_filtered_entries - first;
1563         *r->out.num_entries = MIN(*r->out.num_entries,
1564                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1565 
1566         sam = talloc(mem_ctx, struct samr_SamArray);
1567         if (!sam) {
1568                 return NT_STATUS_NO_MEMORY;
1569         }
1570 
1571         sam->entries = entries+first;
1572         sam->count = *r->out.num_entries;
1573 
1574         *r->out.sam = sam;
1575 
1576         if (first == num_filtered_entries) {
1577                 return NT_STATUS_OK;
1578         }
1579 
1580         if (*r->out.num_entries < num_filtered_entries - first) {
1581                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1582                 return STATUS_MORE_ENTRIES;
1583         }
1584 
1585         return NT_STATUS_OK;
1586 }
1587 
1588 
1589 /* 
1590   samr_CreateDomAlias 
1591 */
1592 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1593                        struct samr_CreateDomAlias *r)
1594 {
1595         struct samr_domain_state *d_state;
1596         struct samr_account_state *a_state;
1597         struct dcesrv_handle *h;
1598         const char *alias_name, *name;
1599         struct ldb_message *msg;
1600         struct dom_sid *sid;
1601         struct dcesrv_handle *a_handle;
1602         int ret;
1603 
1604         ZERO_STRUCTP(r->out.alias_handle);
1605         *r->out.rid = 0;
1606 
1607         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1608 
1609         d_state = h->data;
1610 
1611         if (d_state->builtin) {
1612                 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1613                 return NT_STATUS_ACCESS_DENIED;
1614         }
1615 
1616         alias_name = r->in.alias_name->string;
1617 
1618         if (alias_name == NULL) {
1619                 return NT_STATUS_INVALID_PARAMETER;
1620         }
1621 
1622         /* Check if alias already exists */
1623         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1624                                    "sAMAccountName",
1625                                    "(sAMAccountName=%s)(objectclass=group))",
1626                                    ldb_binary_encode_string(mem_ctx, alias_name));
1627 
1628         if (name != NULL) {
1629                 return NT_STATUS_ALIAS_EXISTS;
1630         }
1631 
1632         msg = ldb_msg_new(mem_ctx);
1633         if (msg == NULL) {
1634                 return NT_STATUS_NO_MEMORY;
1635         }
1636 
1637         /* add core elements to the ldb_message for the alias */
1638         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1639         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1640         if (!msg->dn) {
1641                 return NT_STATUS_NO_MEMORY;
1642         }
1643 
1644         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1645         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1646         samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1647 
1648         /* create the alias */
1649         ret = ldb_add(d_state->sam_ctx, msg);
1650         switch (ret) {
1651         case LDB_SUCCESS:
1652                 break;
1653         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1654                 return NT_STATUS_ALIAS_EXISTS;
1655         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1656                 return NT_STATUS_ACCESS_DENIED;
1657         default:
1658                 DEBUG(0,("Failed to create alias record %s: %s\n",
1659                          ldb_dn_get_linearized(msg->dn),
1660                          ldb_errstring(d_state->sam_ctx)));
1661                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1662         }
1663 
1664         a_state = talloc(d_state, struct samr_account_state);
1665         if (!a_state) {
1666                 return NT_STATUS_NO_MEMORY;
1667         }
1668 
1669         a_state->sam_ctx = d_state->sam_ctx;
1670         a_state->access_mask = r->in.access_mask;
1671         a_state->domain_state = talloc_reference(a_state, d_state);
1672         a_state->account_dn = talloc_steal(a_state, msg->dn);
1673 
1674         /* retrieve the sid for the alias just created */
1675         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1676                                    msg->dn, "objectSid", NULL);
1677 
1678         a_state->account_name = talloc_strdup(a_state, alias_name);
1679         if (!a_state->account_name) {
1680                 return NT_STATUS_NO_MEMORY;
1681         }
1682 
1683         /* create the policy handle */
1684         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1685         if (a_handle == NULL)
1686                 return NT_STATUS_NO_MEMORY;
1687 
1688         a_handle->data = talloc_steal(a_handle, a_state);
1689 
1690         *r->out.alias_handle = a_handle->wire_handle;
1691 
1692         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1693 
1694         return NT_STATUS_OK;
1695 }
1696 
1697 
1698 /* 
1699   samr_EnumDomainAliases 
1700 */
1701 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1702                        struct samr_EnumDomainAliases *r)
1703 {
1704         struct dcesrv_handle *h;
1705         struct samr_domain_state *d_state;
1706         struct ldb_message **res;
1707         int ldb_cnt, count, i, first;
1708         struct samr_SamEntry *entries;
1709         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1710         struct samr_SamArray *sam;
1711 
1712         *r->out.resume_handle = 0;
1713         *r->out.sam = NULL;
1714         *r->out.num_entries = 0;
1715 
1716         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1717 
1718         d_state = h->data;
1719 
1720         /* search for all domain groups in this domain. This could possibly be
1721            cached and resumed based on resume_key */
1722         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1723                                       d_state->domain_dn,
1724                                       &res, attrs, 
1725                                       d_state->domain_sid,
1726                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1727                                       "(objectclass=group))",
1728                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1729                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1730         if (ldb_cnt == -1) {
1731                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1732         }
1733         if (ldb_cnt == 0) {
1734                 return NT_STATUS_OK;
1735         }
1736 
1737         /* convert to SamEntry format */
1738         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1739         if (!entries) {
1740                 return NT_STATUS_NO_MEMORY;
1741         }
1742 
1743         count = 0;
1744 
1745         for (i=0;i<ldb_cnt;i++) {
1746                 struct dom_sid *alias_sid;
1747 
1748                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1749                                                  "objectSid");
1750 
1751                 if (alias_sid == NULL)
1752                         continue;
1753 
1754                 entries[count].idx =
1755                         alias_sid->sub_auths[alias_sid->num_auths-1];
1756                 entries[count].name.string =
1757                         samdb_result_string(res[i], "sAMAccountName", "");
1758                 count += 1;
1759         }
1760 
1761         /* sort the results by rid */
1762         qsort(entries, count, sizeof(struct samr_SamEntry), 
1763               (comparison_fn_t)compare_SamEntry);
1764 
1765         /* find the first entry to return */
1766         for (first=0;
1767              first<count && entries[first].idx <= *r->in.resume_handle;
1768              first++) ;
1769 
1770         if (first == count) {
1771                 return NT_STATUS_OK;
1772         }
1773 
1774         *r->out.num_entries = count - first;
1775         *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1776 
1777         sam = talloc(mem_ctx, struct samr_SamArray);
1778         if (!sam) {
1779                 return NT_STATUS_NO_MEMORY;
1780         }
1781 
1782         sam->entries = entries+first;
1783         sam->count = *r->out.num_entries;
1784 
1785         *r->out.sam = sam;
1786 
1787         if (*r->out.num_entries < count - first) {
1788                 *r->out.resume_handle =
1789                         entries[first+*r->out.num_entries-1].idx;
1790                 return STATUS_MORE_ENTRIES;
1791         }
1792 
1793         return NT_STATUS_OK;
1794 }
1795 
1796 
1797 /* 
1798   samr_GetAliasMembership 
1799 */
1800 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1801                        struct samr_GetAliasMembership *r)
1802 {
1803         struct dcesrv_handle *h;
1804         struct samr_domain_state *d_state;
1805         struct ldb_message **res;
1806         int i, count = 0;
1807 
1808         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1809 
1810         d_state = h->data;
1811 
1812         if (r->in.sids->num_sids > 0) {
1813                 const char *filter;
1814                 const char * const attrs[2] = { "objectSid", NULL };
1815 
1816                 filter = talloc_asprintf(mem_ctx,
1817                                          "(&(|(grouptype=%d)(grouptype=%d))"
1818                                          "(objectclass=group)(|",
1819                                          GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1820                                          GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1821                 if (filter == NULL)
1822                         return NT_STATUS_NO_MEMORY;
1823 
1824                 for (i=0; i<r->in.sids->num_sids; i++) {
1825                         const char *memberdn;
1826 
1827                         memberdn = 
1828                                 samdb_search_string(d_state->sam_ctx,
1829                                                     mem_ctx, NULL, "distinguishedName",
1830                                                     "(objectSid=%s)",
1831                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1832                                                                             r->in.sids->sids[i].sid));
1833 
1834                         if (memberdn == NULL)
1835                                 continue;
1836 
1837                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1838                                                  filter, memberdn);
1839                         if (filter == NULL)
1840                                 return NT_STATUS_NO_MEMORY;
1841                 }
1842 
1843                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1844                                             d_state->domain_dn, &res, attrs,
1845                                             d_state->domain_sid, "%s))", filter);
1846                 if (count < 0)
1847                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1848         }
1849 
1850         r->out.rids->count = 0;
1851         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1852         if (r->out.rids->ids == NULL)
1853                 return NT_STATUS_NO_MEMORY;
1854 
1855         for (i=0; i<count; i++) {
1856                 struct dom_sid *alias_sid;
1857 
1858                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1859 
1860                 if (alias_sid == NULL) {
1861                         DEBUG(0, ("Could not find objectSid\n"));
1862                         continue;
1863                 }
1864 
1865                 r->out.rids->ids[r->out.rids->count] =
1866                         alias_sid->sub_auths[alias_sid->num_auths-1];
1867                 r->out.rids->count += 1;
1868         }
1869 
1870         return NT_STATUS_OK;
1871 }
1872 
1873 
1874 /* 
1875   samr_LookupNames 
1876 */
1877 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1878                                  struct samr_LookupNames *r)
1879 {
1880         struct dcesrv_handle *h;
1881         struct samr_domain_state *d_state;
1882         int i, num_mapped;
1883         NTSTATUS status = NT_STATUS_OK;
1884         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1885         int count;
1886 
1887         ZERO_STRUCTP(r->out.rids);
1888         ZERO_STRUCTP(r->out.types);
1889 
1890         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1891 
1892         d_state = h->data;
1893 
1894         if (r->in.num_names == 0) {
1895                 return NT_STATUS_OK;
1896         }
1897 
1898         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1899         r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1900         if (!r->out.rids->ids || !r->out.types->ids) {
1901                 return NT_STATUS_NO_MEMORY;
1902         }
1903         r->out.rids->count = r->in.num_names;
1904         r->out.types->count = r->in.num_names;
1905 
1906         num_mapped = 0;
1907 
1908         for (i=0;i<r->in.num_names;i++) {
1909                 struct ldb_message **res;
1910                 struct dom_sid *sid;
1911                 uint32_t atype, rtype;
1912 
1913                 r->out.rids->ids[i] = 0;
1914                 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1915 
1916                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1917                                      "sAMAccountName=%s", 
1918                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1919                 if (count != 1) {
1920                         status = STATUS_SOME_UNMAPPED;
1921                         continue;
1922                 }
1923 
1924                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1925                 if (sid == NULL) {
1926                         status = STATUS_SOME_UNMAPPED;
1927                         continue;
1928                 }
1929                 
1930                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1931                 if (atype == 0) {
1932                         status = STATUS_SOME_UNMAPPED;
1933                         continue;
1934                 }
1935 
1936                 rtype = samdb_atype_map(atype);
1937                 
1938                 if (rtype == SID_NAME_UNKNOWN) {
1939                         status = STATUS_SOME_UNMAPPED;
1940                         continue;
1941                 }
1942 
1943                 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1944                 r->out.types->ids[i] = rtype;
1945                 num_mapped++;
1946         }
1947         
1948         if (num_mapped == 0) {
1949                 return NT_STATUS_NONE_MAPPED;
1950         }
1951         return status;
1952 }
1953 
1954 
1955 /* 
1956   samr_LookupRids 
1957 */
1958 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1959                        struct samr_LookupRids *r)
1960 {
1961         struct dcesrv_handle *h;
1962         struct samr_domain_state *d_state;
1963         int i, total;
1964         NTSTATUS status = NT_STATUS_OK;
1965         struct lsa_String *names;
1966         uint32_t *ids;
1967 
1968         ZERO_STRUCTP(r->out.names);
1969         ZERO_STRUCTP(r->out.types);
1970 
1971         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1972 
1973         d_state = h->data;
1974 
1975         if (r->in.num_rids == 0)
1976                 return NT_STATUS_OK;
1977 
1978         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1979         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1980 
1981         if ((names == NULL) || (ids == NULL))
1982                 return NT_STATUS_NO_MEMORY;
1983 
1984         total = 0;
1985 
1986         for (i=0; i<r->in.num_rids; i++) {
1987                 struct ldb_message **res;
1988                 int count;
1989                 const char * const attrs[] = {  "sAMAccountType",
1990                                                 "sAMAccountName", NULL };
1991                 uint32_t atype;
1992                 struct dom_sid *sid;
1993 
1994                 ids[i] = SID_NAME_UNKNOWN;
1995 
1996                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1997                 if (sid == NULL) {
1998                         names[i].string = NULL;
1999                         status = STATUS_SOME_UNMAPPED;
2000                         continue;
2001                 }
2002                 
2003                 count = gendb_search(d_state->sam_ctx, mem_ctx,
2004                                      d_state->domain_dn, &res, attrs,
2005                                      "(objectSid=%s)", 
2006                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
2007                 if (count != 1) {
2008                         names[i].string = NULL;
2009                         status = STATUS_SOME_UNMAPPED;
2010                         continue;
2011                 }
2012 
2013                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
2014                                                       NULL);
2015 
2016                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
2017                 if (atype == 0) {
2018                         status = STATUS_SOME_UNMAPPED;
2019                         continue;
2020                 }
2021 
2022                 ids[i] = samdb_atype_map(atype);
2023                 
2024                 if (ids[i] == SID_NAME_UNKNOWN) {
2025                         status = STATUS_SOME_UNMAPPED;
2026                         continue;
2027                 }
2028         }
2029 
2030         r->out.names->names = names;
2031         r->out.names->count = r->in.num_rids;
2032 
2033         r->out.types->ids = ids;
2034         r->out.types->count = r->in.num_rids;
2035 
2036         return status;
2037 }
2038 
2039 
2040 /* 
2041   samr_OpenGroup 
2042 */
2043 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2044                        struct samr_OpenGroup *r)
2045 {
2046         struct samr_domain_state *d_state;
2047         struct samr_account_state *a_state;
2048         struct dcesrv_handle *h;
2049         const char *groupname;
2050         struct dom_sid *sid;
2051         struct ldb_message **msgs;
2052         struct dcesrv_handle *g_handle;
2053         const char * const attrs[2] = { "sAMAccountName", NULL };
2054         int ret;
2055 
2056         ZERO_STRUCTP(r->out.group_handle);
2057 
2058         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2059 
2060         d_state = h->data;
2061 
2062         /* form the group SID */
2063         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2064         if (!sid) {
2065                 return NT_STATUS_NO_MEMORY;
2066         }
2067 
2068         /* search for the group record */
2069         ret = gendb_search(d_state->sam_ctx,
2070                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2071                            "(&(objectSid=%s)(objectclass=group)"
2072                            "(grouptype=%d))",
2073                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2074                            GTYPE_SECURITY_GLOBAL_GROUP);
2075         if (ret == 0) {
2076                 return NT_STATUS_NO_SUCH_GROUP;
2077         }
2078         if (ret != 1) {
2079                 DEBUG(0,("Found %d records matching sid %s\n", 
2080                          ret, dom_sid_string(mem_ctx, sid)));
2081                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2082         }
2083 
2084         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2085         if (groupname == NULL) {
2086                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2087                          dom_sid_string(mem_ctx, sid)));
2088                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2089         }
2090 
2091         a_state = talloc(d_state, struct samr_account_state);
2092         if (!a_state) {
2093                 return NT_STATUS_NO_MEMORY;
2094         }
2095         a_state->sam_ctx = d_state->sam_ctx;
2096         a_state->access_mask = r->in.access_mask;
2097         a_state->domain_state = talloc_reference(a_state, d_state);
2098         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2099         a_state->account_sid = talloc_steal(a_state, sid);
2100         a_state->account_name = talloc_strdup(a_state, groupname);
2101         if (!a_state->account_name) {
2102                 return NT_STATUS_NO_MEMORY;
2103         }
2104 
2105         /* create the policy handle */
2106         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2107         if (!g_handle) {
2108                 return NT_STATUS_NO_MEMORY;
2109         }
2110 
2111         g_handle->data = talloc_steal(g_handle, a_state);
2112 
2113         *r->out.group_handle = g_handle->wire_handle;
2114 
2115         return NT_STATUS_OK;
2116 }
2117 
2118 /* 
2119   samr_QueryGroupInfo 
2120 */
2121 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2122                        struct samr_QueryGroupInfo *r)
2123 {
2124         struct dcesrv_handle *h;
2125         struct samr_account_state *a_state;
2126         struct ldb_message *msg;
2127         struct ldb_result *res;
2128         const char * const attrs[4] = { "sAMAccountName", "description",
2129                                         "numMembers", NULL };
2130         int ret;
2131         union samr_GroupInfo *info;
2132 
2133         *r->out.info = NULL;
2134 
2135         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2136 
2137         a_state = h->data;
2138         
2139         ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2140         
2141         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2142                 return NT_STATUS_NO_SUCH_GROUP;
2143         } else if (ret != LDB_SUCCESS) {
2144                 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2145                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2146         }
2147 
2148         if (res->count != 1) {
2149                 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2150                 
2151                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2152         }
2153         msg = res->msgs[0];
2154 
2155         /* allocate the info structure */
2156         info = talloc_zero(mem_ctx, union samr_GroupInfo);
2157         if (info == NULL) {
2158                 return NT_STATUS_NO_MEMORY;
2159         }
2160 
2161         /* Fill in the level */
2162         switch (r->in.level) {
2163         case GROUPINFOALL:
2164                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2165                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2166                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2167                 QUERY_STRING(msg, all.description, "description");
2168                 break;
2169         case GROUPINFONAME:
2170                 QUERY_STRING(msg, name,            "sAMAccountName");
2171                 break;
2172         case GROUPINFOATTRIBUTES:
2173                 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2174                 break;
2175         case GROUPINFODESCRIPTION:
2176                 QUERY_STRING(msg, description, "description");
2177                 break;
2178         case GROUPINFOALL2:
2179                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2180                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2181                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2182                 QUERY_STRING(msg, all2.description, "description");
2183                 break;
2184         default:
2185                 talloc_free(info);
2186                 return NT_STATUS_INVALID_INFO_CLASS;
2187         }
2188 
2189         *r->out.info = info;
2190 
2191         return NT_STATUS_OK;
2192 }
2193 
2194 
2195 /* 
2196   samr_SetGroupInfo 
2197 */
2198 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2199                                   struct samr_SetGroupInfo *r)
2200 {
2201         struct dcesrv_handle *h;
2202         struct samr_account_state *g_state;
2203         struct ldb_message *msg;
2204         struct ldb_context *sam_ctx;
2205         int ret;
2206 
2207         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2208 
2209         g_state = h->data;
2210         sam_ctx = g_state->sam_ctx;
2211 
2212         msg = ldb_msg_new(mem_ctx);
2213         if (msg == NULL) {
2214                 return NT_STATUS_NO_MEMORY;
2215         }       
2216 
2217         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2218         if (!msg->dn) {
2219                 return NT_STATUS_NO_MEMORY;
2220         }
2221 
2222         switch (r->in.level) {
2223         case GROUPINFODESCRIPTION:
2224                 SET_STRING(msg, description,         "description");
2225                 break;
2226         case GROUPINFONAME:
2227                 /* On W2k3 this does not change the name, it changes the
2228                  * sAMAccountName attribute */
2229                 SET_STRING(msg, name,                "sAMAccountName");
2230                 break;
2231         case GROUPINFOATTRIBUTES:
2232                 /* This does not do anything obviously visible in W2k3 LDAP */
2233                 return NT_STATUS_OK;
2234         default:
2235                 return NT_STATUS_INVALID_INFO_CLASS;
2236         }
2237 
2238         /* modify the samdb record */
2239         ret = ldb_modify(g_state->sam_ctx, msg);
2240         if (ret != 0) {
2241                 /* we really need samdb.c to return NTSTATUS */
2242                 return NT_STATUS_UNSUCCESSFUL;
2243         }
2244 
2245         return NT_STATUS_OK;
2246 }
2247 
2248 
2249 /* 
2250   samr_AddGroupMember 
2251 */
2252 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2253                        struct samr_AddGroupMember *r)
2254 {
2255         struct dcesrv_handle *h;
2256         struct samr_account_state *a_state;
2257         struct samr_domain_state *d_state;
2258         struct ldb_message *mod;
2259         struct dom_sid *membersid;
2260         const char *memberdn;
2261         struct ldb_result *res;
2262         const char * const attrs[] = { NULL };
2263         int ret;
2264 
2265         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2266 
2267         a_state = h->data;
2268         d_state = a_state->domain_state;
2269 
2270         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2271         if (membersid == NULL)
2272                 return NT_STATUS_NO_MEMORY;
2273 
2274         /* In native mode, AD can also nest domain groups. Not sure yet
2275          * whether this is also available via RPC. */
2276         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2277                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2278                                  "(&(objectSid=%s)(objectclass=user))",
2279                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2280 
2281         if (ret != 0) {
2282                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2283         }
2284 
2285         if (res->count == 0) {
2286                 return NT_STATUS_NO_SUCH_USER;
2287         }
2288                 
2289         if (res->count > 1) {
2290                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2291         }
2292 
2293         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2294 
2295         if (memberdn == NULL)
2296                 return NT_STATUS_NO_MEMORY;
2297 
2298         mod = ldb_msg_new(mem_ctx);
2299         if (mod == NULL) {
2300                 return NT_STATUS_NO_MEMORY;
2301         }
2302 
2303         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2304 
2305         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2306                                  memberdn) != 0)
2307                 return NT_STATUS_UNSUCCESSFUL;
2308 
2309         ret = ldb_modify(a_state->sam_ctx, mod);
2310         switch (ret) {
2311         case LDB_SUCCESS:
2312                 return NT_STATUS_OK;
2313         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2314                 return NT_STATUS_MEMBER_IN_GROUP;
2315         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2316                 return NT_STATUS_ACCESS_DENIED;
2317         default:
2318                 return NT_STATUS_UNSUCCESSFUL;
2319         }
2320 
2321 }
2322 
2323 
2324 /* 
2325   samr_DeleteDomainGroup 
2326 */
2327 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2328                        struct samr_DeleteDomainGroup *r)
2329 {
2330         struct dcesrv_handle *h;
2331         struct samr_account_state *a_state;
2332         int ret;
2333 
2334         *r->out.group_handle = *r->in.group_handle;
2335 
2336         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2337 
2338         a_state = h->data;
2339 
2340         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2341         if (ret != 0) {
2342                 return NT_STATUS_UNSUCCESSFUL;
2343         }
2344 
2345         ZERO_STRUCTP(r->out.group_handle);
2346 
2347         return NT_STATUS_OK;
2348 }
2349 
2350 
2351 /* 
2352   samr_DeleteGroupMember 
2353 */
2354 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2355                        struct samr_DeleteGroupMember *r)
2356 {
2357         struct dcesrv_handle *h;
2358         struct samr_account_state *a_state;
2359         struct samr_domain_state *d_state;
2360         struct ldb_message *mod;
2361         struct dom_sid *membersid;
2362         const char *memberdn;
2363         struct ldb_result *res;
2364         const char * const attrs[] = { NULL };
2365         int ret;
2366 
2367         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2368 
2369         a_state = h->data;
2370         d_state = a_state->domain_state;
2371 
2372         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2373         if (membersid == NULL)
2374                 return NT_STATUS_NO_MEMORY;
2375 
2376         /* In native mode, AD can also nest domain groups. Not sure yet
2377          * whether this is also available via RPC. */
2378         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2379                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2380                                  "(&(objectSid=%s)(objectclass=user))",
2381                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2382 
2383         if (ret != 0) {
2384                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2385         }
2386 
2387         if (res->count == 0) {
2388                 return NT_STATUS_NO_SUCH_USER;
2389         }
2390                 
2391         if (res->count > 1) {
2392                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2393         }
2394 
2395         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2396 
2397         if (memberdn == NULL)
2398                 return NT_STATUS_NO_MEMORY;
2399 
2400         mod = ldb_msg_new(mem_ctx);
2401         if (mod == NULL) {
2402                 return NT_STATUS_NO_MEMORY;
2403         }
2404 
2405         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2406 
2407         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2408                                  memberdn) != 0) {
2409                 return NT_STATUS_NO_MEMORY;
2410         }
2411 
2412         ret = ldb_modify(a_state->sam_ctx, mod);
2413         switch (ret) {
2414         case LDB_SUCCESS:
2415                 return NT_STATUS_OK;
2416         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2417                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2418         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2419                 return NT_STATUS_ACCESS_DENIED;
2420         default:
2421                 return NT_STATUS_UNSUCCESSFUL;
2422         }
2423 
2424 }
2425 
2426 
2427 /* 
2428   samr_QueryGroupMember 
2429 */
2430 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2431                                       struct samr_QueryGroupMember *r)
2432 {
2433         struct dcesrv_handle *h;
2434         struct samr_account_state *a_state;
2435         struct ldb_message **res;
2436         struct ldb_message_element *el;
2437         struct samr_RidTypeArray *array;
2438         const char * const attrs[2] = { "member", NULL };
2439         int ret;
2440 
2441         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2442 
2443         a_state = h->data;
2444 
2445         /* pull the member attribute */
2446         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2447                               a_state->account_dn, &res, attrs);
2448 
2449         if (ret != 1) {
2450                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2451         }
2452 
2453         array = talloc(mem_ctx, struct samr_RidTypeArray);
2454 
2455         if (array == NULL)
2456                 return NT_STATUS_NO_MEMORY;
2457 
2458         ZERO_STRUCTP(array);
2459 
2460         el = ldb_msg_find_element(res[0], "member");
2461 
2462         if (el != NULL) {
2463                 int i;
2464 
2465                 array->count = el->num_values;
2466 
2467                 array->rids = talloc_array(mem_ctx, uint32_t,
2468                                              el->num_values);
2469                 if (array->rids == NULL)
2470                         return NT_STATUS_NO_MEMORY;
2471 
2472                 array->types = talloc_array(mem_ctx, uint32_t,
2473                                             el->num_values);
2474                 if (array->types == NULL)
2475                         return NT_STATUS_NO_MEMORY;
2476 
2477                 for (i=0; i<el->num_values; i++) {
2478                         struct ldb_message **res2;
2479                         const char * const attrs2[2] = { "objectSid", NULL };
2480                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2481                                            ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2482                                            &res2, attrs2);
2483                         if (ret != 1)
2484                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2485 
2486                         array->rids[i] =
2487                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2488                                                           "objectSid", 0);
2489 
2490                         if (array->rids[i] == 0)
2491                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2492 
2493                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2494                 }
2495         }
2496 
2497         *r->out.rids = array;
2498 
2499         return NT_STATUS_OK;
2500 }
2501 
2502 
2503 /* 
2504   samr_SetMemberAttributesOfGroup 
2505 */
2506 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2507                        struct samr_SetMemberAttributesOfGroup *r)
2508 {
2509         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2510 }
2511 
2512 
2513 /* 
2514   samr_OpenAlias 
2515 */
2516 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2517                        struct samr_OpenAlias *r)
2518 {
2519         struct samr_domain_state *d_state;
2520         struct samr_account_state *a_state;
2521         struct dcesrv_handle *h;
2522         const char *alias_name;
2523         struct dom_sid *sid;
2524         struct ldb_message **msgs;
2525         struct dcesrv_handle *g_handle;
2526         const char * const attrs[2] = { "sAMAccountName", NULL };
2527         int ret;
2528 
2529         ZERO_STRUCTP(r->out.alias_handle);
2530 
2531         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2532 
2533         d_state = h->data;
2534 
2535         /* form the alias SID */
2536         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2537         if (sid == NULL)
2538                 return NT_STATUS_NO_MEMORY;
2539 
2540         /* search for the group record */
2541         ret = gendb_search(d_state->sam_ctx,
2542                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2543                            "(&(objectSid=%s)(objectclass=group)"
2544                            "(|(grouptype=%d)(grouptype=%d)))",
2545                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2546                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2547                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2548         if (ret == 0) {
2549                 return NT_STATUS_NO_SUCH_ALIAS;
2550         }
2551         if (ret != 1) {
2552                 DEBUG(0,("Found %d records matching sid %s\n", 
2553                          ret, dom_sid_string(mem_ctx, sid)));
2554                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2555         }
2556 
2557         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2558         if (alias_name == NULL) {
2559                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2560                          dom_sid_string(mem_ctx, sid)));
2561                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2562         }
2563 
2564         a_state = talloc(d_state, struct samr_account_state);
2565         if (!a_state) {
2566                 return NT_STATUS_NO_MEMORY;
2567         }
2568         a_state->sam_ctx = d_state->sam_ctx;
2569         a_state->access_mask = r->in.access_mask;
2570         a_state->domain_state = talloc_reference(a_state, d_state);
2571         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2572         a_state->account_sid = talloc_steal(a_state, sid);
2573         a_state->account_name = talloc_strdup(a_state, alias_name);
2574         if (!a_state->account_name) {
2575                 return NT_STATUS_NO_MEMORY;
2576         }
2577 
2578         /* create the policy handle */
2579         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2580         if (!g_handle) {
2581                 return NT_STATUS_NO_MEMORY;
2582         }
2583 
2584         g_handle->data = talloc_steal(g_handle, a_state);
2585 
2586         *r->out.alias_handle = g_handle->wire_handle;
2587 
2588         return NT_STATUS_OK;
2589 }
2590 
2591 
2592 /* 
2593   samr_QueryAliasInfo 
2594 */
2595 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2596                        struct samr_QueryAliasInfo *r)
2597 {
2598         struct dcesrv_handle *h;
2599         struct samr_account_state *a_state;
2600         struct ldb_message *msg, **res;
2601         const char * const attrs[4] = { "sAMAccountName", "description",
2602                                         "numMembers", NULL };
2603         int ret;
2604         union samr_AliasInfo *info;
2605 
2606         *r->out.info = NULL;
2607 
2608         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2609 
2610         a_state = h->data;
2611 
2612         /* pull all the alias attributes */
2613         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2614                               a_state->account_dn ,&res, attrs);
2615         if (ret != 1) {
2616                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2617         }
2618         msg = res[0];
2619 
2620         /* allocate the info structure */
2621         info = talloc_zero(mem_ctx, union samr_AliasInfo);
2622         if (info == NULL) {
2623                 return NT_STATUS_NO_MEMORY;
2624         }
2625 
2626         switch(r->in.level) {
2627         case ALIASINFOALL:
2628                 QUERY_STRING(msg, all.name, "sAMAccountName");
2629                 QUERY_UINT  (msg, all.num_members, "numMembers");
2630                 QUERY_STRING(msg, all.description, "description");
2631                 break;
2632         case ALIASINFONAME:
2633                 QUERY_STRING(msg, name, "sAMAccountName");
2634                 break;
2635         case ALIASINFODESCRIPTION:
2636                 QUERY_STRING(msg, description, "description");
2637                 break;
2638         default:
2639                 talloc_free(info);
2640                 return NT_STATUS_INVALID_INFO_CLASS;
2641         }
2642 
2643         *r->out.info = info;
2644 
2645         return NT_STATUS_OK;
2646 }
2647 
2648 
2649 /* 
2650   samr_SetAliasInfo 
2651 */
2652 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2653                        struct samr_SetAliasInfo *r)
2654 {
2655         struct dcesrv_handle *h;
2656         struct samr_account_state *a_state;
2657         struct ldb_message *msg;
2658         struct ldb_context *sam_ctx;
2659         int ret;
2660 
2661         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2662 
2663         a_state = h->data;
2664         sam_ctx = a_state->sam_ctx;
2665 
2666         msg = ldb_msg_new(mem_ctx);
2667         if (msg == NULL) {
2668                 return NT_STATUS_NO_MEMORY;
2669         }
2670 
2671         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2672         if (!msg->dn) {
2673                 return NT_STATUS_NO_MEMORY;
2674         }
2675 
2676         switch (r->in.level) {
2677         case ALIASINFODESCRIPTION:
2678                 SET_STRING(msg, description,         "description");
2679                 break;
2680         case ALIASINFONAME:
2681                 /* On W2k3 this does not change the name, it changes the
2682                  * sAMAccountName attribute */
2683                 SET_STRING(msg, name,                "sAMAccountName");
2684                 break;
2685         default:
2686                 return NT_STATUS_INVALID_INFO_CLASS;
2687         }
2688 
2689         /* modify the samdb record */
2690         ret = ldb_modify(a_state->sam_ctx, msg);
2691         if (ret != 0) {
2692                 /* we really need samdb.c to return NTSTATUS */
2693                 return NT_STATUS_UNSUCCESSFUL;
2694         }
2695 
2696         return NT_STATUS_OK;
2697 }
2698 
2699 
2700 /* 
2701   samr_DeleteDomAlias 
2702 */
2703 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2704                        struct samr_DeleteDomAlias *r)
2705 {
2706         struct dcesrv_handle *h;
2707         struct samr_account_state *a_state;
2708         int ret;
2709 
2710         *r->out.alias_handle = *r->in.alias_handle;
2711 
2712         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2713 
2714         a_state = h->data;
2715 
2716         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2717         if (ret != 0) {
2718                 return NT_STATUS_UNSUCCESSFUL;
2719         }
2720 
2721         ZERO_STRUCTP(r->out.alias_handle);
2722 
2723         return NT_STATUS_OK;
2724 }
2725 
2726 
2727 /* 
2728   samr_AddAliasMember 
2729 */
2730 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2731                        struct samr_AddAliasMember *r)
2732 {
2733         struct dcesrv_handle *h;
2734         struct samr_account_state *a_state;
2735         struct samr_domain_state *d_state;
2736         struct ldb_message *mod;
2737         struct ldb_message **msgs;
2738         const char * const attrs[] = { NULL };
2739         struct ldb_dn *memberdn = NULL;
2740         int ret;
2741         NTSTATUS status;
2742 
2743         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2744 
2745         a_state = h->data;
2746         d_state = a_state->domain_state;
2747 
2748         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2749                            &msgs, attrs, "(objectsid=%s)", 
2750                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2751 
2752         if (ret == 1) {
2753                 memberdn = msgs[0]->dn;
2754         } else  if (ret > 1) {
2755                 DEBUG(0,("Found %d records matching sid %s\n", 
2756                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2757                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2758         } else if (ret == 0) {
2759                 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx, 
2760                                                                  r->in.sid, &memberdn);
2761                 if (!NT_STATUS_IS_OK(status)) {
2762                         return status;
2763                 }
2764         } else {
2765                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2766         }
2767 
2768         if (memberdn == NULL) {
2769                 DEBUG(0, ("Could not find memberdn\n"));
2770                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2771         }
2772 
2773         mod = ldb_msg_new(mem_ctx);
2774         if (mod == NULL) {
2775                 return NT_STATUS_NO_MEMORY;
2776         }
2777 
2778         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2779 
2780         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2781                                  ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2782                 return NT_STATUS_UNSUCCESSFUL;
2783 
2784         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2785                 return NT_STATUS_UNSUCCESSFUL;
2786 
2787         return NT_STATUS_OK;
2788 }
2789 
2790 
2791 /* 
2792   samr_DeleteAliasMember 
2793 */
2794 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2795                        struct samr_DeleteAliasMember *r)
2796 {
2797         struct dcesrv_handle *h;
2798         struct samr_account_state *a_state;
2799         struct samr_domain_state *d_state;
2800         struct ldb_message *mod;
2801         const char *memberdn;
2802 
2803         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2804 
2805         a_state = h->data;
2806         d_state = a_state->domain_state;
2807 
2808         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2809                                        "distinguishedName", "(objectSid=%s)", 
2810                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2811 
2812         if (memberdn == NULL)
2813                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2814 
2815         mod = ldb_msg_new(mem_ctx);
2816         if (mod == NULL) {
2817                 return NT_STATUS_NO_MEMORY;
2818         }
2819 
2820         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2821 
2822         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2823                                  memberdn) != 0)
2824                 return NT_STATUS_UNSUCCESSFUL;
2825 
2826         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2827                 return NT_STATUS_UNSUCCESSFUL;
2828 
2829         return NT_STATUS_OK;
2830 }
2831 
2832 
2833 /* 
2834   samr_GetMembersInAlias 
2835 */
2836 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2837                        struct samr_GetMembersInAlias *r)
2838 {
2839         struct dcesrv_handle *h;
2840         struct samr_account_state *a_state;
2841         struct samr_domain_state *d_state;
2842         struct ldb_message **msgs;
2843         struct lsa_SidPtr *sids;
2844         struct ldb_message_element *el;
2845         const char * const attrs[2] = { "member", NULL};
2846         int ret;
2847 
2848         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2849 
2850         a_state = h->data;
2851         d_state = a_state->domain_state;
2852 
2853         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2854                               a_state->account_dn, &msgs, attrs);
2855 
2856         if (ret == -1) {
2857                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2858         } else if (ret == 0) {
2859                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2860         } else if (ret != 1) {
2861                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2862         }
2863 
2864         r->out.sids->num_sids = 0;
2865         r->out.sids->sids = NULL;
2866 
2867         el = ldb_msg_find_element(msgs[0], "member");
2868 
2869         if (el != NULL) {
2870                 int i;
2871 
2872                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2873                                       el->num_values);
2874 
2875                 if (sids == NULL)
2876                         return NT_STATUS_NO_MEMORY;
2877 
2878                 for (i=0; i<el->num_values; i++) {
2879                         struct ldb_message **msgs2;
2880                         const char * const attrs2[2] = { "objectSid", NULL };
2881                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2882                                               ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2883                                               &msgs2, attrs2);
2884                         if (ret != 1)
2885                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2886 
2887                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2888                                                            "objectSid");
2889 
2890                         if (sids[i].sid == NULL)
2891                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2892                 }
2893                 r->out.sids->num_sids = el->num_values;
2894                 r->out.sids->sids = sids;
2895         }
2896 
2897         return NT_STATUS_OK;
2898 }
2899 
2900 /* 
2901   samr_OpenUser 
2902 */
2903 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2904                               struct samr_OpenUser *r)
2905 {
2906         struct samr_domain_state *d_state;
2907         struct samr_account_state *a_state;
2908         struct dcesrv_handle *h;
2909         const char *account_name;
2910         struct dom_sid *sid;
2911         struct ldb_message **msgs;
2912         struct dcesrv_handle *u_handle;
2913         const char * const attrs[2] = { "sAMAccountName", NULL };
2914         int ret;
2915 
2916         ZERO_STRUCTP(r->out.user_handle);
2917 
2918         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2919 
2920         d_state = h->data;
2921 
2922         /* form the users SID */
2923         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2924         if (!sid) {
2925                 return NT_STATUS_NO_MEMORY;
2926         }
2927 
2928         /* search for the user record */
2929         ret = gendb_search(d_state->sam_ctx,
2930                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2931                            "(&(objectSid=%s)(objectclass=user))", 
2932                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2933         if (ret == 0) {
2934                 return NT_STATUS_NO_SUCH_USER;
2935         }
2936         if (ret != 1) {
2937                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2938                          dom_sid_string(mem_ctx, sid)));
2939                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2940         }
2941 
2942         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2943         if (account_name == NULL) {
2944                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2945                          dom_sid_string(mem_ctx, sid)));
2946                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2947         }
2948 
2949         a_state = talloc(mem_ctx, struct samr_account_state);
2950         if (!a_state) {
2951                 return NT_STATUS_NO_MEMORY;
2952         }
2953         a_state->sam_ctx = d_state->sam_ctx;
2954         a_state->access_mask = r->in.access_mask;
2955         a_state->domain_state = talloc_reference(a_state, d_state);
2956         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2957         a_state->account_sid = talloc_steal(a_state, sid);
2958         a_state->account_name = talloc_strdup(a_state, account_name);
2959         if (!a_state->account_name) {
2960                 return NT_STATUS_NO_MEMORY;
2961         }
2962 
2963         /* create the policy handle */
2964         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2965         if (!u_handle) {
2966                 return NT_STATUS_NO_MEMORY;
2967         }
2968 
2969         u_handle->data = talloc_steal(u_handle, a_state);
2970 
2971         *r->out.user_handle = u_handle->wire_handle;
2972 
2973         return NT_STATUS_OK;
2974 
2975 }
2976 
2977 
2978 /* 
2979   samr_DeleteUser 
2980 */
2981 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2982                                 struct samr_DeleteUser *r)
2983 {
2984         struct dcesrv_handle *h;
2985         struct samr_account_state *a_state;
2986         int ret;
2987 
2988         *r->out.user_handle = *r->in.user_handle;
2989 
2990         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2991 
2992         a_state = h->data;
2993 
2994         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2995         if (ret != 0) {
2996                 DEBUG(1, ("Failed to delete user: %s: %s\n", 
2997                           ldb_dn_get_linearized(a_state->account_dn), 
2998                           ldb_errstring(a_state->sam_ctx)));
2999                 return NT_STATUS_UNSUCCESSFUL;
3000         }
3001 
3002         ZERO_STRUCTP(r->out.user_handle);
3003 
3004         return NT_STATUS_OK;
3005 }
3006 
3007 
3008 /* 
3009   samr_QueryUserInfo 
3010 */
3011 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3012                                    struct samr_QueryUserInfo *r)
3013 {
3014         struct dcesrv_handle *h;
3015         struct samr_account_state *a_state;
3016         struct ldb_message *msg, **res;
3017         int ret;
3018         struct ldb_context *sam_ctx;
3019 
3020         const char * const *attrs = NULL;
3021         union samr_UserInfo *info;
3022 
3023         *r->out.info = NULL;
3024 
3025         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3026 
3027         a_state = h->data;
3028         sam_ctx = a_state->sam_ctx;
3029 
3030         /* fill in the reply */
3031         switch (r->in.level) {
3032         case 1:
3033         {
3034                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
3035                                                       "primaryroupID", "description",
3036                                                       "comment", NULL};
3037                 attrs = attrs2;
3038                 break;
3039         }
3040         case 2:
3041         {
3042                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
3043                 attrs = attrs2;
3044                 break;
3045         }
3046         case 3:
3047         {
3048                 static const char * const attrs2[] = {"sAMAccountName",
3049                                                       "displayName",
3050                                                       "objectSid",
3051                                                       "primaryGroupID",
3052                                                       "homeDirectory",
3053                                                       "homeDrive",
3054                                                       "scriptPath",
3055                                                       "profilePath",
3056                                                       "userWorkstations",
3057                                                       "lastLogon",
3058                                                       "lastLogoff",
3059                                                       "pwdLastSet",
3060                                                       "logonHours",
3061                                                       "badPwdCount",
3062                                                       "logonCount",
3063                                                       "userAccountControl", NULL};
3064                 attrs = attrs2;
3065                 break;
3066         }
3067         case 4:
3068         {
3069                 static const char * const attrs2[] = {"logonHours", NULL};
3070                 attrs = attrs2;
3071                 break;
3072         }
3073         case 5:
3074         {
3075                 static const char * const attrs2[] = {"sAMAccountName", 
3076                                                       "displayName",
3077                                                       "objectSid",
3078                                                       "primaryGroupID",
3079                                                       "homeDirectory",
3080                                                       "homeDrive",
3081                                                       "scriptPath", 
3082                                                       "profilePath",
3083                                                       "description",
3084                                                       "userWorkstations",
3085                                                       "lastLogon",
3086                                                       "lastLogoff",
3087                                                       "logonHours",
3088                                                       "badPwdCount",
3089                                                       "logonCount",
3090                                                       "pwdLastSet",
3091                                                       "accountExpires",
3092                                                       "userAccountControl",
3093                                                       NULL};
3094                 attrs = attrs2;
3095                 break;
3096         }
3097         case 6:
3098         {
3099                 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
3100                 attrs = attrs2;
3101                 break;
3102         }
3103         case 7:
3104         {
3105                 static const char * const attrs2[] = {"sAMAccountName", NULL};
3106                 attrs = attrs2;
3107                 break;
3108         }
3109         case 8:
3110         {
3111                 static const char * const attrs2[] = {"displayName", NULL};
3112                 attrs = attrs2;
3113                 break;
3114         }
3115         case 9:
3116         {
3117                 static const char * const attrs2[] = {"primaryGroupID", NULL};
3118                 attrs = attrs2;
3119                 break;
3120         }
3121         case 10:
3122         {
3123                 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3124                 attrs = attrs2;
3125                 break;
3126         }
3127         case 11:
3128         {
3129                 static const char * const attrs2[] = {"scriptPath", NULL};
3130                 attrs = attrs2;
3131                 break;
3132         }
3133         case 12:
3134         {
3135                 static const char * const attrs2[] = {"profilePath", NULL};
3136                 attrs = attrs2;
3137                 break;
3138         }
3139         case 13:
3140         {
3141                 static const char * const attrs2[] = {"description", NULL};
3142                 attrs = attrs2;
3143                 break;
3144         }
3145         case 14:
3146         {
3147                 static const char * const attrs2[] = {"userWorkstations", NULL};
3148                 attrs = attrs2;
3149                 break;
3150         }
3151         case 16:
3152         {
3153                 static const char * const attrs2[] = {"userAccountControl", "pwdLastSet", NULL};
3154                 attrs = attrs2;
3155                 break;
3156         }
3157         case 17:
3158         {
3159                 static const char * const attrs2[] = {"accountExpires", NULL};
3160                 attrs = attrs2;
3161                 break;
3162         }
3163         case 20:
3164         {
3165                 static const char * const attrs2[] = {"userParameters", NULL};
3166                 attrs = attrs2;
3167                 break;
3168         }
3169         case 21:
3170         {
3171                 static const char * const attrs2[] = {"lastLogon",
3172                                                       "lastLogoff",
3173                                                       "pwdLastSet",
3174                                                       "accountExpires",
3175                                                       "sAMAccountName",
3176                                                       "displayName",
3177                                                       "homeDirectory",
3178                                                       "homeDrive",
3179                                                       "scriptPath",
3180                                                       "profilePath",
3181                                                       "description",
3182                                                       "userWorkstations",
3183                                                       "comment",
3184                                                       "userParameters",
3185                                                       "objectSid",
3186                                                       "primaryGroupID",
3187                                                       "userAccountControl",
3188                                                       "logonHours",
3189                                                       "badPwdCount",
3190                                                       "logonCount",
3191                                                       "countryCode",
3192                                                       "codePage",
3193                                                       NULL};
3194                 attrs = attrs2;
3195                 break;
3196         }
3197         }
3198 
3199         /* pull all the user attributes */
3200         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3201                               a_state->account_dn ,&res, attrs);
3202         if (ret != 1) {
3203                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3204         }
3205         msg = res[0];
3206 
3207         /* allocate the info structure */
3208         info = talloc_zero(mem_ctx, union samr_UserInfo);
3209         if (info == NULL) {
3210                 return NT_STATUS_NO_MEMORY;
3211         }
3212 
3213         /* fill in the reply */
3214         switch (r->in.level) {
3215         case 1:
3216                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3217                 QUERY_STRING(msg, info1.full_name,             "displayName");
3218                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3219                 QUERY_STRING(msg, info1.description,           "description");
3220                 QUERY_STRING(msg, info1.comment,               "comment");
3221                 break;
3222 
3223         case 2:
3224                 QUERY_STRING(msg, info2.comment,               "comment");
3225                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3226                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3227                 break;
3228 
3229         case 3:
3230                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3231                 QUERY_STRING(msg, info3.full_name,             "displayName");
3232                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3233                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3234                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3235                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3236                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3237                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3238                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3239                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3240                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3241                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3242                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3243                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3244                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3245                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3246                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3247                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3248                 break;
3249 
3250         case 4:
3251                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3252                 break;
3253 
3254         case 5:
3255                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3256                 QUERY_STRING(msg, info5.full_name,             "displayName");
3257                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3258                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3259                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3260                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3261                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3262                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3263                 QUERY_STRING(msg, info5.description,           "description");
3264                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3265                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3266                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3267                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3268                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3269                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3270                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3271                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3272                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3273                 break;
3274 
3275         case 6:
3276                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3277                 QUERY_STRING(msg, info6.full_name,      "displayName");
3278                 break;
3279 
3280         case 7:
3281                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3282                 break;
3283 
3284         case 8:
3285                 QUERY_STRING(msg, info8.full_name,      "displayName");
3286                 break;
3287 
3288         case 9:
3289                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3290                 break;
3291 
3292         case 10:
3293                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3294                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3295                 break;
3296 
3297         case 11:
3298                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3299                 break;
3300 
3301         case 12:
3302                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3303                 break;
3304 
3305         case 13:
3306                 QUERY_STRING(msg, info13.description,   "description");
3307                 break;
3308 
3309         case 14:
3310                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3311                 break;
3312 
3313         case 16:
3314                 QUERY_AFLAGS(msg, info16.acct_flags,    "userAccountControl");
3315                 break;
3316 
3317         case 17:
3318                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3319                 break;
3320 
3321         case 20:
3322                 QUERY_PARAMETERS(msg, info20.parameters,    "userParameters");
3323                 break;
3324 
3325         case 21:
3326                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3327                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3328                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3329                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3330                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3331                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3332                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3333                 QUERY_STRING(msg, info21.full_name,            "displayName");
3334                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3335                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3336                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3337                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3338                 QUERY_STRING(msg, info21.description,          "description");
3339                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3340                 QUERY_STRING(msg, info21.comment,              "comment");
3341                 QUERY_PARAMETERS(msg, info21.parameters,       "userParameters");
3342                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3343                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3344                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3345                 info->info21.fields_present = 0x00FFFFFF;
3346                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3347                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3348                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3349                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3350                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3351                 break;
3352                 
3353 
3354         default:
3355                 talloc_free(info);
3356                 return NT_STATUS_INVALID_INFO_CLASS;
3357         }
3358 
3359         *r->out.info = info;
3360 
3361         return NT_STATUS_OK;
3362 }
3363 
3364 
3365 /* 
3366   samr_SetUserInfo 
3367 */
3368 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3369                                  struct samr_SetUserInfo *r)
3370 {
3371         struct dcesrv_handle *h;
3372         struct samr_account_state *a_state;
3373         struct ldb_message *msg;
3374         int ret;
3375         NTSTATUS status = NT_STATUS_OK;
3376         struct ldb_context *sam_ctx;
3377 
3378         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3379 
3380         a_state = h->data;
3381         sam_ctx = a_state->sam_ctx;
3382 
3383         msg = ldb_msg_new(mem_ctx);
3384         if (msg == NULL) {
3385                 return NT_STATUS_NO_MEMORY;
3386         }
3387 
3388         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3389         if (!msg->dn) {
3390                 return NT_STATUS_NO_MEMORY;
3391         }
3392 
3393         switch (r->in.level) {
3394         case 2:
3395                 SET_STRING(msg, info2.comment,          "comment");
3396                 SET_UINT  (msg, info2.country_code,     "countryCode");
3397                 SET_UINT  (msg, info2.code_page,        "codePage");
3398                 break;
3399 
3400         case 4:
3401                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3402                 break;
3403 
3404         case 6:
3405                 SET_STRING(msg, info6.full_name,        "displayName");
3406                 break;
3407 
3408         case 7:
3409                 SET_STRING(msg, info7.account_name,     "samAccountName");
3410                 break;
3411 
3412         case 8:
3413                 SET_STRING(msg, info8.full_name,        "displayName");
3414                 break;
3415 
3416         case 9:
3417                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3418                 break;
3419 
3420         case 10:
3421                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3422                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3423                 break;
3424 
3425         case 11:
3426                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3427                 break;
3428 
3429         case 12:
3430                 SET_STRING(msg, info12.profile_path,    "profilePath");
3431                 break;
3432 
3433         case 13:
3434                 SET_STRING(msg, info13.description,     "description");
3435                 break;
3436 
3437         case 14:
3438                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3439                 break;
3440 
3441         case 16:
3442                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3443                 break;
3444 
3445         case 17:
3446                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3447                 break;
3448 
3449         case 20:
3450                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
3451                 break;
3452 
3453         case 21:
3454 #define IFSET(bit) if (bit & r->in.info->info21.fields_present) 
3455                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3456                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");       
3457                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3458                         SET_STRING(msg, info21.account_name,   "samAccountName");
3459                 IFSET(SAMR_FIELD_FULL_NAME) 
3460                         SET_STRING(msg, info21.full_name,      "displayName");
3461                 IFSET(SAMR_FIELD_DESCRIPTION)
3462                         SET_STRING(msg, info21.description,    "description");
3463                 IFSET(SAMR_FIELD_COMMENT)
3464                         SET_STRING(msg, info21.comment,        "comment");
3465                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3466                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3467                 IFSET(SAMR_FIELD_PROFILE_PATH)
3468                         SET_STRING(msg, info21.profile_path,   "profilePath");
3469                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3470                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3471                 IFSET(SAMR_FIELD_HOME_DRIVE)
3472                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3473                 IFSET(SAMR_FIELD_WORKSTATIONS)
3474                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3475                 IFSET(SAMR_FIELD_LOGON_HOURS)
3476                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3477                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3478                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3479                 IFSET(SAMR_FIELD_PARAMETERS)   
3480                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
3481                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3482                         SET_UINT  (msg, info21.country_code,   "countryCode");
3483                 IFSET(SAMR_FIELD_CODE_PAGE)
3484                         SET_UINT  (msg, info21.code_page,      "codePage");     
3485 #undef IFSET
3486                 break;
3487 
3488         case 23:
3489 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3490                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3491                         SET_UINT64(msg, info23.info.acct_expiry,  "accountExpires");    
3492                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3493                         SET_STRING(msg, info23.info.account_name, "samAccountName");
3494                 IFSET(SAMR_FIELD_FULL_NAME)         
3495                         SET_STRING(msg, info23.info.full_name,    "displayName");
3496                 IFSET(SAMR_FIELD_DESCRIPTION)  
3497                         SET_STRING(msg, info23.info.description,  "description");
3498                 IFSET(SAMR_FIELD_COMMENT)      
3499                         SET_STRING(msg, info23.info.comment,      "comment");
3500                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3501                         SET_STRING(msg, info23.info.logon_script, "scriptPath");
3502                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3503                         SET_STRING(msg, info23.info.profile_path, "profilePath");
3504                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3505                         SET_STRING(msg, info23.info.workstations, "userWorkstations");
3506                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3507                         SET_LHOURS(msg, info23.info.logon_hours,  "logonHours");
3508                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3509                         SET_AFLAGS(msg, info23.info.acct_flags,   "userAccountControl");
3510                 IFSET(SAMR_FIELD_PARAMETERS)     
3511                         SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3512                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3513                         SET_UINT  (msg, info23.info.country_code, "countryCode");
3514                 IFSET(SAMR_FIELD_CODE_PAGE)    
3515                         SET_UINT  (msg, info23.info.code_page,    "codePage");
3516                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3517                         status = samr_set_password(dce_call,
3518                                                    a_state->sam_ctx,
3519                                                    a_state->account_dn,
3520                                                    a_state->domain_state->domain_dn,
3521                                                    mem_ctx, msg, 
3522                                                    &r->in.info->info23.password);
3523                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3524                         status = samr_set_password(dce_call,
3525                                                    a_state->sam_ctx,
3526                                                    a_state->account_dn,
3527                                                    a_state->domain_state->domain_dn,
3528                                                    mem_ctx, msg, 
3529                                                    &r->in.info->info23.password);
3530                 }
3531 #undef IFSET
3532                 break;
3533 
3534                 /* the set password levels are handled separately */
3535         case 24:
3536                 status = samr_set_password(dce_call,
3537                                            a_state->sam_ctx,
3538                                            a_state->account_dn,
3539                                            a_state->domain_state->domain_dn,
3540                                            mem_ctx, msg, 
3541                                            &r->in.info->info24.password);
3542                 break;
3543 
3544         case 25:
3545 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3546                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3547                         SET_UINT64(msg, info25.info.acct_expiry,  "accountExpires");    
3548                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3549                         SET_STRING(msg, info25.info.account_name, "samAccountName");
3550                 IFSET(SAMR_FIELD_FULL_NAME)         
3551                         SET_STRING(msg, info25.info.full_name,    "displayName");
3552                 IFSET(SAMR_FIELD_DESCRIPTION)  
3553                         SET_STRING(msg, info25.info.description,  "description");
3554                 IFSET(SAMR_FIELD_COMMENT)      
3555                         SET_STRING(msg, info25.info.comment,      "comment");
3556                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3557                         SET_STRING(msg, info25.info.logon_script, "scriptPath");
3558                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3559                         SET_STRING(msg, info25.info.profile_path, "profilePath");
3560                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3561                         SET_STRING(msg, info25.info.workstations, "userWorkstations");
3562                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3563                         SET_LHOURS(msg, info25.info.logon_hours,  "logonHours");
3564                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3565                         SET_AFLAGS(msg, info25.info.acct_flags,   "userAccountControl");
3566                 IFSET(SAMR_FIELD_PARAMETERS)     
3567                         SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3568                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3569                         SET_UINT  (msg, info25.info.country_code, "countryCode");
3570                 IFSET(SAMR_FIELD_CODE_PAGE)    
3571                         SET_UINT  (msg, info25.info.code_page,    "codePage");
3572                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3573                         status = samr_set_password_ex(dce_call,
3574                                                       a_state->sam_ctx,
3575                                                       a_state->account_dn,
3576                                                       a_state->domain_state->domain_dn,
3577                                                       mem_ctx, msg, 
3578                                                       &r->in.info->info25.password);
3579                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3580                         status = samr_set_password_ex(dce_call,
3581                                                       a_state->sam_ctx,
3582                                                       a_state->account_dn,
3583                                                       a_state->domain_state->domain_dn,
3584                                                       mem_ctx, msg, 
3585                                                       &r->in.info->info25.password);
3586                 }
3587 #undef IFSET
3588                 break;
3589 
3590                 /* the set password levels are handled separately */
3591         case 26:
3592                 status = samr_set_password_ex(dce_call,
3593                                               a_state->sam_ctx,
3594                                               a_state->account_dn,
3595                                               a_state->domain_state->domain_dn,
3596                                               mem_ctx, msg, 
3597                                               &r->in.info->info26.password);
3598                 break;
3599                 
3600 
3601         default:
3602                 /* many info classes are not valid for SetUserInfo */
3603                 return NT_STATUS_INVALID_INFO_CLASS;
3604         }
3605 
3606         if (!NT_STATUS_IS_OK(status)) {
3607                 return status;
3608         }
3609 
3610         /* modify the samdb record */
3611         ret = ldb_modify(a_state->sam_ctx, msg);
3612         if (ret != 0) {
3613                 DEBUG(1,("Failed to modify record %s: %s\n",
3614                          ldb_dn_get_linearized(a_state->account_dn),
3615                          ldb_errstring(a_state->sam_ctx)));
3616 
3617                 /* we really need samdb.c to return NTSTATUS */
3618                 return NT_STATUS_UNSUCCESSFUL;
3619         }
3620 
3621         return NT_STATUS_OK;
3622 }
3623 
3624 
3625 /* 
3626   samr_GetGroupsForUser 
3627 */
3628 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3629                        struct samr_GetGroupsForUser *r)
3630 {
3631         struct dcesrv_handle *h;
3632         struct samr_account_state *a_state;
3633         struct samr_domain_state *d_state;
3634         struct ldb_message **res;
3635         const char * const attrs[2] = { "objectSid", NULL };
3636         struct samr_RidWithAttributeArray *array;
3637         int count;
3638 
3639         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3640 
3641         a_state = h->data;
3642         d_state = a_state->domain_state;
3643 
3644         count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3645                                     attrs, d_state->domain_sid,
3646                                     "(&(member=%s)(grouptype=%d)(objectclass=group))",
3647                                     ldb_dn_get_linearized(a_state->account_dn),
3648                                     GTYPE_SECURITY_GLOBAL_GROUP);
3649         if (count < 0)
3650                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3651 
3652         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3653         if (array == NULL)
3654                 return NT_STATUS_NO_MEMORY;
3655 
3656         array->count = 0;
3657         array->rids = NULL;
3658 
3659         if (count > 0) {
3660                 int i;
3661                 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3662                                             count);
3663 
3664                 if (array->rids == NULL)
3665                         return NT_STATUS_NO_MEMORY;
3666 
3667                 for (i=0; i<count; i++) {
3668                         struct dom_sid *group_sid;
3669 
3670                         group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3671                                                          "objectSid");
3672                         if (group_sid == NULL) {
3673                                 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3674                                 continue;
3675                         }
3676 
3677                         array->rids[array->count].rid =
3678                                 group_sid->sub_auths[group_sid->num_auths-1];
3679                         array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3680                         array->count += 1;
3681                 }
3682         }
3683 
3684         *r->out.rids = array;
3685 
3686         return NT_STATUS_OK;
3687 }
3688 
3689 
3690 /* 
3691   samr_QueryDisplayInfo 
3692 */
3693 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3694                        struct samr_QueryDisplayInfo *r)
3695 {
3696         struct dcesrv_handle *h;
3697         struct samr_domain_state *d_state;
3698         struct ldb_message **res;
3699         int ldb_cnt, count, i;
3700         const char * const attrs[] = { "objectSid", "sAMAccountName", "displayName",
3701                                        "description", "userAccountControl", "pwdLastSet", NULL };
3702         struct samr_DispEntryFull *entriesFull = NULL;
3703         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3704         struct samr_DispEntryAscii *entriesAscii = NULL;
3705         struct samr_DispEntryGeneral * entriesGeneral = NULL;
3706         const char *filter;
3707 
3708         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3709 
3710         d_state = h->data;
3711 
3712         switch (r->in.level) {
3713         case 1:
3714         case 4:
3715                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3716                                          "(sAMAccountType=%u))",
3717                                          ATYPE_NORMAL_ACCOUNT);
3718                 break;
3719         case 2:
3720                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3721                                          "(sAMAccountType=%u))",
3722                                          ATYPE_WORKSTATION_TRUST);
3723                 break;
3724         case 3:
3725         case 5:
3726                 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3727                                          "(objectclass=group))",
3728                                          GTYPE_SECURITY_GLOBAL_GROUP);
3729                 break;
3730         default:
3731                 return NT_STATUS_INVALID_INFO_CLASS;
3732         }
3733 
3734         /* search for all requested objects in this domain. This could
3735            possibly be cached and resumed based on resume_key */
3736         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3737                                       d_state->domain_dn, &res, attrs,
3738                                       d_state->domain_sid, "%s", filter);
3739         if (ldb_cnt == -1) {
3740                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3741         }
3742         if (ldb_cnt == 0 || r->in.max_entries == 0) {
3743                 return NT_STATUS_OK;
3744         }
3745 
3746         switch (r->in.level) {
3747         case 1:
3748                 entriesGeneral = talloc_array(mem_ctx,
3749                                                 struct samr_DispEntryGeneral,
3750                                                 ldb_cnt);
3751                 break;
3752         case 2:
3753                 entriesFull = talloc_array(mem_ctx,
3754                                              struct samr_DispEntryFull,
3755                                              ldb_cnt);
3756                 break;
3757         case 3:
3758                 entriesFullGroup = talloc_array(mem_ctx,
3759                                              struct samr_DispEntryFullGroup,
3760                                              ldb_cnt);
3761                 break;
3762         case 4:
3763         case 5:
3764                 entriesAscii = talloc_array(mem_ctx,
3765                                               struct samr_DispEntryAscii,
3766                                               ldb_cnt);
3767                 break;
3768         }
3769 
3770         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3771             (entriesAscii == NULL) && (entriesFullGroup == NULL))
3772                 return NT_STATUS_NO_MEMORY;
3773 
3774         count = 0;
3775 
3776         for (i=0; i<ldb_cnt; i++) {
3777                 struct dom_sid *objectsid;
3778 
3779                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3780                                                  "objectSid");
3781                 if (objectsid == NULL)
3782                         continue;
3783 
3784                 switch(r->in.level) {
3785                 case 1:
3786                         entriesGeneral[count].idx = count + 1;
3787                         entriesGeneral[count].rid = 
3788                                 objectsid->sub_auths[objectsid->num_auths-1];
3789                         entriesGeneral[count].acct_flags =
3790                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3791                                                         res[i], 
3792                                                         d_state->domain_dn);
3793                         entriesGeneral[count].account_name.string =
3794                                 samdb_result_string(res[i],
3795                                                     "sAMAccountName", "");
3796                         entriesGeneral[count].full_name.string =
3797                                 samdb_result_string(res[i], "displayName", "");
3798                         entriesGeneral[count].description.string =
3799                                 samdb_result_string(res[i], "description", "");
3800                         break;
3801                 case 2:
3802                         entriesFull[count].idx = count + 1;
3803                         entriesFull[count].rid =
3804                                 objectsid->sub_auths[objectsid->num_auths-1];
3805 
3806                         /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3807                         entriesFull[count].acct_flags =
3808                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3809                                                         res[i], 
3810                                                         d_state->domain_dn) | ACB_NORMAL;
3811                         entriesFull[count].account_name.string =
3812                                 samdb_result_string(res[i], "sAMAccountName",
3813                                                     "");
3814                         entriesFull[count].description.string =
3815                                 samdb_result_string(res[i], "description", "");
3816                         break;
3817                 case 3:
3818                         entriesFullGroup[count].idx = count + 1;
3819                         entriesFullGroup[count].rid =
3820                                 objectsid->sub_auths[objectsid->num_auths-1];
3821                         /* We get a "7" here for groups */
3822                         entriesFullGroup[count].acct_flags
3823                                 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3824                         entriesFullGroup[count].account_name.string =
3825                                 samdb_result_string(res[i], "sAMAccountName",
3826                                                     "");
3827                         entriesFullGroup[count].description.string =
3828                                 samdb_result_string(res[i], "description", "");
3829                         break;
3830                 case 4:
3831                 case 5:
3832                         entriesAscii[count].idx = count + 1;
3833                         entriesAscii[count].account_name.string =
3834                                 samdb_result_string(res[i], "sAMAccountName",
3835                                                     "");
3836                         break;
3837                 }
3838 
3839                 count += 1;
3840         }
3841 
3842         *r->out.total_size = count;
3843 
3844         if (r->in.start_idx >= count) {
3845                 *r->out.returned_size = 0;
3846                 switch(r->in.level) {
3847                 case 1:
3848                         r->out.info->info1.count = *r->out.returned_size;
3849                         r->out.info->info1.entries = NULL;
3850                         break;
3851                 case 2:
3852                         r->out.info->info2.count = *r->out.returned_size;
3853                         r->out.info->info2.entries = NULL;
3854                         break;
3855                 case 3:
3856                         r->out.info->info3.count = *r->out.returned_size;
3857                         r->out.info->info3.entries = NULL;
3858                         break;
3859                 case 4:
3860                         r->out.info->info4.count = *r->out.returned_size;
3861                         r->out.info->info4.entries = NULL;
3862                         break;
3863                 case 5:
3864                         r->out.info->info5.count = *r->out.returned_size;
3865                         r->out.info->info5.entries = NULL;
3866                         break;
3867                 }
3868         } else {
3869                 *r->out.returned_size = MIN(count - r->in.start_idx,
3870                                            r->in.max_entries);
3871                 switch(r->in.level) {
3872                 case 1:
3873                         r->out.info->info1.count = *r->out.returned_size;
3874                         r->out.info->info1.entries =
3875                                 &(entriesGeneral[r->in.start_idx]);
3876                         break;
3877                 case 2:
3878                         r->out.info->info2.count = *r->out.returned_size;
3879                         r->out.info->info2.entries =
3880                                 &(entriesFull[r->in.start_idx]);
3881                         break;
3882                 case 3:
3883                         r->out.info->info3.count = *r->out.returned_size;
3884                         r->out.info->info3.entries =
3885                                 &(entriesFullGroup[r->in.start_idx]);
3886                         break;
3887                 case 4:
3888                         r->out.info->info4.count = *r->out.returned_size;
3889                         r->out.info->info4.entries =
3890                                 &(entriesAscii[r->in.start_idx]);
3891                         break;
3892                 case 5:
3893                         r->out.info->info5.count = *r->out.returned_size;
3894                         r->out.info->info5.entries =
3895                                 &(entriesAscii[r->in.start_idx]);
3896                         break;
3897                 }
3898         }
3899 
3900         return (*r->out.returned_size < (count - r->in.start_idx)) ?
3901                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3902 }
3903 
3904 
3905 /* 
3906   samr_GetDisplayEnumerationIndex 
3907 */
3908 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3909                        struct samr_GetDisplayEnumerationIndex *r)
3910 {
3911         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3912 }
3913 
3914 
3915 /* 
3916   samr_TestPrivateFunctionsDomain 
3917 */
3918 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3919                        struct samr_TestPrivateFunctionsDomain *r)
3920 {
3921         return NT_STATUS_NOT_IMPLEMENTED;
3922 }
3923 
3924 
3925 /* 
3926   samr_TestPrivateFunctionsUser 
3927 */
3928 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3929                        struct samr_TestPrivateFunctionsUser *r)
3930 {
3931         return NT_STATUS_NOT_IMPLEMENTED;
3932 }
3933 
3934 
3935 /* 
3936   samr_GetUserPwInfo 
3937 */
3938 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3939                                    struct samr_GetUserPwInfo *r)
3940 {
3941         struct dcesrv_handle *h;
3942         struct samr_account_state *a_state;
3943 
3944         ZERO_STRUCTP(r->out.info);
3945 
3946         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3947 
3948         a_state = h->data;
3949 
3950         r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3951                                                              a_state->domain_state->domain_dn, "minPwdLength",
3952                                                              NULL);
3953         r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3954                                                              a_state->account_dn,
3955                                                              "pwdProperties", NULL);
3956         return NT_STATUS_OK;
3957 }
3958 
3959 
3960 /* 
3961   samr_RemoveMemberFromForeignDomain 
3962 */
3963 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
3964                        struct samr_RemoveMemberFromForeignDomain *r)
3965 {
3966         struct dcesrv_handle *h;
3967         struct samr_domain_state *d_state;
3968         const char *memberdn;
3969         struct ldb_message **res;
3970         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3971         int i, count;
3972 
3973         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3974 
3975         d_state = h->data;
3976 
3977         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3978                                        "distinguishedName", "(objectSid=%s)", 
3979                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3980         /* Nothing to do */
3981         if (memberdn == NULL) {
3982                 return NT_STATUS_OK;
3983         }
3984 
3985         /* TODO: Does this call only remove alias members, or does it do this
3986          * for domain groups as well? */
3987 
3988         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3989                                     d_state->domain_dn, &res, attrs,
3990                                     d_state->domain_sid,
3991                                     "(&(member=%s)(objectClass=group)"
3992                                     "(|(groupType=%d)(groupType=%d)))",
3993                                     memberdn,
3994                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3995                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3996 
3997         if (count < 0)
3998                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3999 
4000         for (i=0; i<count; i++) {
4001                 struct ldb_message *mod;
4002 
4003                 mod = ldb_msg_new(mem_ctx);
4004                 if (mod == NULL) {
4005                         return NT_STATUS_NO_MEMORY;
4006                 }
4007 
4008                 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4009                 if (mod->dn == NULL) {
4010                         talloc_free(mod);
4011                         continue;
4012                 }
4013 
4014                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4015                                          "member", memberdn) != 0)
4016                         return NT_STATUS_NO_MEMORY;
4017 
4018                 if (ldb_modify(d_state->sam_ctx, mod) != 0)
4019                         return NT_STATUS_UNSUCCESSFUL;
4020 
4021                 talloc_free(mod);
4022         }
4023 
4024         return NT_STATUS_OK;
4025 }
4026 
4027 
4028 /* 
4029   samr_QueryDomainInfo2 
4030 
4031   just an alias for samr_QueryDomainInfo
4032 */
4033 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4034                        struct samr_QueryDomainInfo2 *r)
4035 {
4036         struct samr_QueryDomainInfo r1;
4037         NTSTATUS status;
4038 
4039         ZERO_STRUCT(r1.out);
4040         r1.in.domain_handle = r->in.domain_handle;
4041         r1.in.level  = r->in.level;
4042         r1.out.info  = r->out.info;
4043 
4044         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4045         
4046         return status;
4047 }
4048 
4049 
4050 /* 
4051   samr_QueryUserInfo2 
4052 
4053   just an alias for samr_QueryUserInfo
4054 */
4055 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4056                                     struct samr_QueryUserInfo2 *r)
4057 {
4058         struct samr_QueryUserInfo r1;
4059         NTSTATUS status;
4060 
4061         r1.in.user_handle = r->in.user_handle;
4062         r1.in.level  = r->in.level;
4063         r1.out.info  = r->out.info;
4064         
4065         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4066 
4067         return status;
4068 }
4069 
4070 
4071 /* 
4072   samr_QueryDisplayInfo2 
4073 */
4074 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4075                                        struct samr_QueryDisplayInfo2 *r)
4076 {
4077         struct samr_QueryDisplayInfo q;
4078         NTSTATUS result;
4079 
4080         q.in.domain_handle = r->in.domain_handle;
4081         q.in.level = r->in.level;
4082         q.in.start_idx = r->in.start_idx;
4083         q.in.max_entries = r->in.max_entries;
4084         q.in.buf_size = r->in.buf_size;
4085         q.out.total_size = r->out.total_size;
4086         q.out.returned_size = r->out.returned_size;
4087         q.out.info = r->out.info;
4088 
4089         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4090 
4091         return result;
4092 }
4093 
4094 
4095 /* 
4096   samr_GetDisplayEnumerationIndex2 
4097 */
4098 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4099                        struct samr_GetDisplayEnumerationIndex2 *r)
4100 {
4101         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4102 }
4103 
4104 
4105 /* 
4106   samr_QueryDisplayInfo3 
4107 */
4108 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4109                        struct samr_QueryDisplayInfo3 *r)
4110 {
4111         struct samr_QueryDisplayInfo q;
4112         NTSTATUS result;
4113 
4114         q.in.domain_handle = r->in.domain_handle;
4115         q.in.level = r->in.level;
4116         q.in.start_idx = r->in.start_idx;
4117         q.in.max_entries = r->in.max_entries;
4118         q.in.buf_size = r->in.buf_size;
4119         q.out.total_size = r->out.total_size;
4120         q.out.returned_size = r->out.returned_size;
4121         q.out.info = r->out.info;
4122 
4123         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4124 
4125         return result;
4126 }
4127 
4128 
4129 /* 
4130   samr_AddMultipleMembersToAlias 
4131 */
4132 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4133                        struct samr_AddMultipleMembersToAlias *r)
4134 {
4135         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4136 }
4137 
4138 
4139 /* 
4140   samr_RemoveMultipleMembersFromAlias 
4141 */
4142 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4143                        struct samr_RemoveMultipleMembersFromAlias *r)
4144 {
4145         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4146 }
4147 
4148 
4149 /* 
4150   samr_GetDomPwInfo 
4151 
4152   this fetches the default password properties for a domain
4153 
4154   note that w2k3 completely ignores the domain name in this call, and 
4155   always returns the information for the servers primary domain
4156 */
4157 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4158                                   struct samr_GetDomPwInfo *r)
4159 {
4160         struct ldb_message **msgs;
4161         int ret;
4162         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4163         struct ldb_context *sam_ctx;
4164 
4165         ZERO_STRUCTP(r->out.info);
4166 
4167         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info); 
4168         if (sam_ctx == NULL) {
4169                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4170         }
4171 
4172         /* The domain name in this call is ignored */
4173         ret = gendb_search_dn(sam_ctx, 
4174                            mem_ctx, NULL, &msgs, attrs);
4175         if (ret <= 0) {
4176                 return NT_STATUS_NO_SUCH_DOMAIN;
4177         }
4178         if (ret > 1) {
4179                 talloc_free(msgs);
4180                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4181         }
4182 
4183         r->out.info->min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
4184         r->out.info->password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
4185 
4186         talloc_free(msgs);
4187 
4188         talloc_free(sam_ctx);
4189         return NT_STATUS_OK;
4190 }
4191 
4192 
4193 /* 
4194   samr_Connect2 
4195 */
4196 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4197                               struct samr_Connect2 *r)
4198 {
4199         struct samr_Connect c;
4200 
4201         c.in.system_name = NULL;
4202         c.in.access_mask = r->in.access_mask;
4203         c.out.connect_handle = r->out.connect_handle;
4204 
4205         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4206 }
4207 
4208 
4209 /* 
4210   samr_SetUserInfo2 
4211 
4212   just an alias for samr_SetUserInfo
4213 */
4214 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4215                                   struct samr_SetUserInfo2 *r)
4216 {
4217         struct samr_SetUserInfo r2;
4218 
4219         r2.in.user_handle = r->in.user_handle;
4220         r2.in.level = r->in.level;
4221         r2.in.info = r->in.info;
4222 
4223         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4224 }
4225 
4226 
4227 /* 
4228   samr_SetBootKeyInformation 
4229 */
4230 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4231                        struct samr_SetBootKeyInformation *r)
4232 {
4233         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4234 }
4235 
4236 
4237 /* 
4238   samr_GetBootKeyInformation 
4239 */
4240 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4241                        struct samr_GetBootKeyInformation *r)
4242 {
4243         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4244 }
4245 
4246 
4247 /* 
4248   samr_Connect3 
4249 */
4250 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4251                        struct samr_Connect3 *r)
4252 {
4253         struct samr_Connect c;
4254 
4255         c.in.system_name = NULL;
4256         c.in.access_mask = r->in.access_mask;
4257         c.out.connect_handle = r->out.connect_handle;
4258 
4259         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4260 }
4261 
4262 
4263 /* 
4264   samr_Connect4 
4265 */
4266 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4267                        struct samr_Connect4 *r)
4268 {
4269         struct samr_Connect c;
4270 
4271         c.in.system_name = NULL;
4272         c.in.access_mask = r->in.access_mask;
4273         c.out.connect_handle = r->out.connect_handle;
4274 
4275         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4276 }
4277 
4278 
4279 /* 
4280   samr_Connect5 
4281 */
4282 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4283                               struct samr_Connect5 *r)
4284 {
4285         struct samr_Connect c;
4286         NTSTATUS status;
4287 
4288         c.in.system_name = NULL;
4289         c.in.access_mask = r->in.access_mask;
4290         c.out.connect_handle = r->out.connect_handle;
4291 
4292         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4293 
4294         r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4295         r->out.info_out->info1.unknown2 = 0;
4296         *r->out.level_out = r->in.level_in;
4297 
4298         return status;
4299 }
4300 
4301 
4302 /* 
4303   samr_RidToSid 
4304 */
4305 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4306                               struct samr_RidToSid *r)
4307 {
4308         struct samr_domain_state *d_state;
4309         struct dcesrv_handle *h;
4310 
4311         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4312 
4313         d_state = h->data;
4314 
4315         /* form the users SID */
4316         *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4317         if (!*r->out.sid) {
4318                 return NT_STATUS_NO_MEMORY;
4319         }
4320 
4321         return NT_STATUS_OK;
4322 }
4323 
4324 
4325 /* 
4326   samr_SetDsrmPassword 
4327 */
4328 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4329                        struct samr_SetDsrmPassword *r)
4330 {
4331         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4332 }
4333 
4334 
4335 /* 
4336   samr_ValidatePassword 
4337 */
4338 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
4339                                       struct samr_ValidatePassword *r)
4340 {
4341         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4342 }
4343 
4344 
4345 /* include the generated boilerplate */
4346 #include "librpc/gen_ndr/ndr_samr_s.c"

/* [<][>][^][v][top][bottom][index][help] */