1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Security Accounts Manager RPC (SAMR) server-side interface.
  29  *
  30  * The SAM is a hierarchical database:
  31  * - If you want to talk to the SAM you need a SAM handle.
  32  * - If you want to work with a domain, use the SAM handle.
  33  *   to obtain a domain handle.
  34  * - Use domain handles to obtain user handles etc.
  35  */
  36 
  37 #include <strings.h>
  38 #include <unistd.h>
  39 #include <netdb.h>
  40 #include <assert.h>
  41 #include <grp.h>
  42 #include <smbsrv/libsmb.h>
  43 #include <smbsrv/libmlrpc.h>
  44 #include <smbsrv/libmlsvc.h>
  45 #include <smbsrv/smbinfo.h>
  46 #include <smbsrv/nmpipes.h>
  47 #include <smbsrv/ndl/samrpc.ndl>
  48 #include <samlib.h>
  49 
  50 /*
  51  * The keys associated with the various handles dispensed by the SAMR
  52  * server.  These keys can be used to validate client activity.
  53  * These values are never passed over the wire so security shouldn't
  54  * be an issue.
  55  */
  56 typedef enum {
  57         SAMR_KEY_NULL = 0,
  58         SAMR_KEY_CONNECT,
  59         SAMR_KEY_DOMAIN,
  60         SAMR_KEY_USER,
  61         SAMR_KEY_GROUP,
  62         SAMR_KEY_ALIAS
  63 } samr_key_t;
  64 
  65 typedef struct samr_keydata {
  66         samr_key_t kd_key;
  67         smb_domain_type_t kd_type;
  68         DWORD kd_rid;
  69 } samr_keydata_t;
  70 
  71 /*
  72  * DomainDisplayUser    All user objects (or those derived from user) with
  73  *                      userAccountControl containing the UF_NORMAL_ACCOUNT bit.
  74  *
  75  * DomainDisplayMachine All user objects (or those derived from user) with
  76  *                      userAccountControl containing the
  77  *                      UF_WORKSTATION_TRUST_ACCOUNT or UF_SERVER_TRUST_ACCOUNT
  78  *                      bit.
  79  *
  80  * DomainDisplayGroup   All group objects (or those derived from group) with
  81  *                      groupType equal to GROUP_TYPE_SECURITY_UNIVERSAL or
  82  *                      GROUP_TYPE_SECURITY_ACCOUNT.
  83  *
  84  * DomainDisplayOemUser Same as DomainDisplayUser with OEM strings
  85  *
  86  * DomainDisplayOemGroup Same as DomainDisplayGroup with OEM strings
  87  */
  88 typedef enum {
  89         DomainDisplayUser = 1,
  90         DomainDisplayMachine,
  91         DomainDispalyGroup,
  92         DomainDisplayOemUser,
  93         DomainDisplayOemGroup
  94 } samr_displvl_t;
  95 
  96 #define SAMR_VALID_DISPLEVEL(lvl) \
  97         (((lvl) >= DomainDisplayUser) && ((lvl) <= DomainDisplayOemGroup))
  98 
  99 #define SAMR_SUPPORTED_DISPLEVEL(lvl) (lvl == DomainDisplayUser)
 100 
 101 static ndr_hdid_t *samr_hdalloc(ndr_xa_t *, samr_key_t, smb_domain_type_t,
 102     DWORD);
 103 static void samr_hdfree(ndr_xa_t *, ndr_hdid_t *);
 104 static ndr_handle_t *samr_hdlookup(ndr_xa_t *, ndr_hdid_t *, samr_key_t);
 105 static int samr_call_stub(ndr_xa_t *mxa);
 106 static DWORD samr_s_enum_local_domains(struct samr_EnumLocalDomain *,
 107     ndr_xa_t *);
 108 
 109 static ndr_stub_table_t samr_stub_table[];
 110 
 111 static ndr_service_t samr_service = {
 112         "SAMR",                         /* name */
 113         "Security Accounts Manager",    /* desc */
 114         "\\samr",                       /* endpoint */
 115         PIPE_LSASS,                     /* sec_addr_port */
 116         "12345778-1234-abcd-ef00-0123456789ac", 1,      /* abstract */
 117         NDR_TRANSFER_SYNTAX_UUID,               2,      /* transfer */
 118         0,                              /* no bind_instance_size */
 119         NULL,                           /* no bind_req() */
 120         NULL,                           /* no unbind_and_close() */
 121         samr_call_stub,                 /* call_stub() */
 122         &TYPEINFO(samr_interface),  /* interface ti */
 123         samr_stub_table                 /* stub_table */
 124 };
 125 
 126 /*
 127  * samr_initialize
 128  *
 129  * This function registers the SAM RPC interface with the RPC runtime
 130  * library. It must be called in order to use either the client side
 131  * or the server side functions.
 132  */
 133 void
 134 samr_initialize(void)
 135 {
 136         (void) ndr_svc_register(&samr_service);
 137 }
 138 
 139 /*
 140  * Custom call_stub to set the stream string policy.
 141  */
 142 static int
 143 samr_call_stub(ndr_xa_t *mxa)
 144 {
 145         NDS_SETF(&mxa->send_nds, NDS_F_NOTERM);
 146         NDS_SETF(&mxa->recv_nds, NDS_F_NOTERM);
 147 
 148         return (ndr_generic_call_stub(mxa));
 149 }
 150 
 151 /*
 152  * Handle allocation wrapper to setup the local context.
 153  */
 154 static ndr_hdid_t *
 155 samr_hdalloc(ndr_xa_t *mxa, samr_key_t key, smb_domain_type_t domain_type,
 156     DWORD rid)
 157 {
 158         ndr_handle_t    *hd;
 159         ndr_hdid_t      *id;
 160         samr_keydata_t  *data;
 161 
 162         if ((data = malloc(sizeof (samr_keydata_t))) == NULL)
 163                 return (NULL);
 164 
 165         data->kd_key = key;
 166         data->kd_type = domain_type;
 167         data->kd_rid = rid;
 168 
 169         if ((id = ndr_hdalloc(mxa, data)) == NULL) {
 170                 free(data);
 171                 return (NULL);
 172         }
 173 
 174         if ((hd = ndr_hdlookup(mxa, id)) != NULL)
 175                 hd->nh_data_free = free;
 176 
 177         return (id);
 178 }
 179 
 180 /*
 181  * Handle deallocation wrapper to free the local context.
 182  */
 183 static void
 184 samr_hdfree(ndr_xa_t *mxa, ndr_hdid_t *id)
 185 {
 186         ndr_handle_t *hd;
 187 
 188         if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
 189                 free(hd->nh_data);
 190                 hd->nh_data = NULL;
 191                 ndr_hdfree(mxa, id);
 192         }
 193 }
 194 
 195 /*
 196  * Handle lookup wrapper to validate the local context.
 197  */
 198 static ndr_handle_t *
 199 samr_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id, samr_key_t key)
 200 {
 201         ndr_handle_t *hd;
 202         samr_keydata_t *data;
 203 
 204         if ((hd = ndr_hdlookup(mxa, id)) == NULL)
 205                 return (NULL);
 206 
 207         if ((data = (samr_keydata_t *)hd->nh_data) == NULL)
 208                 return (NULL);
 209 
 210         if (data->kd_key != key)
 211                 return (NULL);
 212 
 213         return (hd);
 214 }
 215 
 216 /*
 217  * samr_s_Connect
 218  *
 219  * This is a request to connect to the local SAM database. We don't
 220  * support any form of update request and our database doesn't
 221  * contain any private information, so there is little point in
 222  * doing any access access checking here.
 223  *
 224  * Return a handle for use with subsequent SAM requests.
 225  */
 226 static int
 227 samr_s_Connect(void *arg, ndr_xa_t *mxa)
 228 {
 229         struct samr_Connect *param = arg;
 230         ndr_hdid_t *id;
 231 
 232         id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
 233         if (id) {
 234                 bcopy(id, &param->handle, sizeof (samr_handle_t));
 235                 param->status = 0;
 236         } else {
 237                 bzero(&param->handle, sizeof (samr_handle_t));
 238                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 239         }
 240 
 241         return (NDR_DRC_OK);
 242 }
 243 
 244 /*
 245  * samr_s_CloseHandle
 246  *
 247  * Close the SAM interface specified by the handle.
 248  * Free the handle and zero out the result handle for the client.
 249  */
 250 static int
 251 samr_s_CloseHandle(void *arg, ndr_xa_t *mxa)
 252 {
 253         struct samr_CloseHandle *param = arg;
 254         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 255 
 256         samr_hdfree(mxa, id);
 257 
 258         bzero(&param->result_handle, sizeof (samr_handle_t));
 259         param->status = 0;
 260         return (NDR_DRC_OK);
 261 }
 262 
 263 /*
 264  * samr_s_LookupDomain
 265  *
 266  * This is a request to map a domain name to a domain SID. We can map
 267  * the primary domain name, our local domain name (hostname) and the
 268  * builtin domain names to the appropriate SID. Anything else will be
 269  * rejected.
 270  */
 271 static int
 272 samr_s_LookupDomain(void *arg, ndr_xa_t *mxa)
 273 {
 274         struct samr_LookupDomain *param = arg;
 275         char *domain_name;
 276         smb_domain_t di;
 277 
 278         if ((domain_name = (char *)param->domain_name.str) == NULL) {
 279                 bzero(param, sizeof (struct samr_LookupDomain));
 280                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
 281                 return (NDR_DRC_OK);
 282         }
 283 
 284         if (!smb_domain_lookup_name(domain_name, &di)) {
 285                 bzero(param, sizeof (struct samr_LookupDomain));
 286                 param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_DOMAIN);
 287                 return (NDR_DRC_OK);
 288         }
 289 
 290         param->sid = (struct samr_sid *)NDR_SIDDUP(mxa, di.di_binsid);
 291         if (param->sid == NULL) {
 292                 bzero(param, sizeof (struct samr_LookupDomain));
 293                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 294                 return (NDR_DRC_OK);
 295         }
 296 
 297         param->status = NT_STATUS_SUCCESS;
 298         return (NDR_DRC_OK);
 299 }
 300 
 301 /*
 302  * samr_s_EnumLocalDomains
 303  *
 304  * This is a request for the local domains supported by this server.
 305  * All we do here is validate the handle and set the status. The real
 306  * work is done in samr_s_enum_local_domains.
 307  */
 308 static int
 309 samr_s_EnumLocalDomains(void *arg, ndr_xa_t *mxa)
 310 {
 311         struct samr_EnumLocalDomain *param = arg;
 312         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 313         DWORD status;
 314 
 315         if (samr_hdlookup(mxa, id, SAMR_KEY_CONNECT) == NULL)
 316                 status = NT_STATUS_ACCESS_DENIED;
 317         else
 318                 status = samr_s_enum_local_domains(param, mxa);
 319 
 320         if (status == NT_STATUS_SUCCESS) {
 321                 param->enum_context = param->info->entries_read;
 322                 param->total_entries = param->info->entries_read;
 323                 param->status = NT_STATUS_SUCCESS;
 324         } else {
 325                 bzero(param, sizeof (struct samr_EnumLocalDomain));
 326                 param->status = NT_SC_ERROR(status);
 327         }
 328 
 329         return (NDR_DRC_OK);
 330 }
 331 
 332 
 333 /*
 334  * samr_s_enum_local_domains
 335  *
 336  * This function should only be called via samr_s_EnumLocalDomains to
 337  * ensure that the appropriate validation is performed. We will answer
 338  * queries about two domains: the local domain, synonymous with the
 339  * local hostname, and the BUILTIN domain. So we return these two
 340  * strings.
 341  *
 342  * Returns NT status values.
 343  */
 344 static DWORD
 345 samr_s_enum_local_domains(struct samr_EnumLocalDomain *param,
 346     ndr_xa_t *mxa)
 347 {
 348         struct samr_LocalDomainInfo *info;
 349         struct samr_LocalDomainEntry *entry;
 350         char *hostname;
 351 
 352         hostname = NDR_MALLOC(mxa, NETBIOS_NAME_SZ);
 353         if (hostname == NULL)
 354                 return (NT_STATUS_NO_MEMORY);
 355 
 356         if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0)
 357                 return (NT_STATUS_NO_MEMORY);
 358 
 359         entry = NDR_NEWN(mxa, struct samr_LocalDomainEntry, 2);
 360         if (entry == NULL)
 361                 return (NT_STATUS_NO_MEMORY);
 362 
 363         bzero(entry, (sizeof (struct samr_LocalDomainEntry) * 2));
 364         (void) NDR_MSTRING(mxa, hostname, (ndr_mstring_t *)&entry[0].name);
 365         (void) NDR_MSTRING(mxa, "Builtin", (ndr_mstring_t *)&entry[1].name);
 366 
 367         info = NDR_NEW(mxa, struct samr_LocalDomainInfo);
 368         if (info == NULL)
 369                 return (NT_STATUS_NO_MEMORY);
 370 
 371         info->entries_read = 2;
 372         info->entry = entry;
 373         param->info = info;
 374         return (NT_STATUS_SUCCESS);
 375 }
 376 
 377 /*
 378  * samr_s_OpenDomain
 379  *
 380  * This is a request to open a domain within the local SAM database.
 381  * The caller must supply a valid connect handle.
 382  * We return a handle to be used to access objects within this domain.
 383  */
 384 static int
 385 samr_s_OpenDomain(void *arg, ndr_xa_t *mxa)
 386 {
 387         struct samr_OpenDomain *param = arg;
 388         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 389         smb_domain_t domain;
 390 
 391         if (samr_hdlookup(mxa, id, SAMR_KEY_CONNECT) == NULL) {
 392                 bzero(&param->domain_handle, sizeof (samr_handle_t));
 393                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 394                 return (NDR_DRC_OK);
 395         }
 396 
 397         if (!smb_domain_lookup_sid((smb_sid_t *)param->sid, &domain)) {
 398                 bzero(&param->domain_handle, sizeof (samr_handle_t));
 399                 param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 400                 return (NDR_DRC_OK);
 401         }
 402 
 403         if ((domain.di_type != SMB_DOMAIN_BUILTIN) &&
 404             (domain.di_type != SMB_DOMAIN_LOCAL)) {
 405                 bzero(&param->domain_handle, sizeof (samr_handle_t));
 406                 param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 407                 return (NDR_DRC_OK);
 408         }
 409 
 410         id = samr_hdalloc(mxa, SAMR_KEY_DOMAIN, domain.di_type, 0);
 411         if (id) {
 412                 bcopy(id, &param->domain_handle, sizeof (samr_handle_t));
 413                 param->status = 0;
 414         } else {
 415                 bzero(&param->domain_handle, sizeof (samr_handle_t));
 416                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 417         }
 418 
 419         return (NDR_DRC_OK);
 420 }
 421 
 422 /*
 423  * samr_s_QueryDomainInfo
 424  *
 425  * The caller should pass a domain handle.
 426  *
 427  * Windows 95 Server Manager sends requests for levels 6 and 7 when
 428  * the services menu item is selected. Level 2 is basically for getting
 429  * number of users, groups, and aliases in a domain.
 430  * We have no information on what the various information levels mean.
 431  */
 432 static int
 433 samr_s_QueryDomainInfo(void *arg, ndr_xa_t *mxa)
 434 {
 435         struct samr_QueryDomainInfo *param = arg;
 436         struct samr_QueryDomainInfoRes *info;
 437         ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
 438         ndr_handle_t *hd;
 439         samr_keydata_t *data;
 440         char *domain;
 441         char hostname[NETBIOS_NAME_SZ];
 442         int alias_cnt, user_cnt;
 443         int rc = 0;
 444 
 445         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
 446                 bzero(param, sizeof (struct samr_QueryDomainInfo));
 447                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 448                 return (NDR_DRC_OK);
 449         }
 450 
 451         info = NDR_NEW(mxa, struct samr_QueryDomainInfoRes);
 452         if (info == NULL) {
 453                 bzero(param, sizeof (struct samr_QueryDomainInfo));
 454                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 455                 return (NDR_DRC_OK);
 456         }
 457         info->switch_value = param->info_level;
 458         param->info = info;
 459 
 460         data = (samr_keydata_t *)hd->nh_data;
 461 
 462         switch (data->kd_type) {
 463         case SMB_DOMAIN_BUILTIN:
 464                 domain = "BUILTIN";
 465                 user_cnt = 0;
 466                 alias_cnt = smb_sam_grp_cnt(data->kd_type);
 467                 break;
 468 
 469         case SMB_DOMAIN_LOCAL:
 470                 rc = smb_getnetbiosname(hostname, sizeof (hostname));
 471                 if (rc == 0) {
 472                         domain = hostname;
 473                         user_cnt = smb_sam_usr_cnt();
 474                         alias_cnt = smb_sam_grp_cnt(data->kd_type);
 475                 }
 476                 break;
 477 
 478         default:
 479                 bzero(param, sizeof (struct samr_QueryDomainInfo));
 480                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 481                 return (NDR_DRC_OK);
 482         }
 483 
 484         if (rc != 0) {
 485                 bzero(param, sizeof (struct samr_QueryDomainInfo));
 486                 param->status = NT_SC_ERROR(NT_STATUS_INTERNAL_ERROR);
 487                 return (NDR_DRC_OK);
 488         }
 489 
 490         switch (param->info_level) {
 491         case SAMR_QUERY_DOMAIN_INFO_6:
 492                 info->ru.info6.unknown1 = 0x00000000;
 493                 info->ru.info6.unknown2 = 0x00147FB0;
 494                 info->ru.info6.unknown3 = 0x00000000;
 495                 info->ru.info6.unknown4 = 0x00000000;
 496                 info->ru.info6.unknown5 = 0x00000000;
 497                 param->status = NT_STATUS_SUCCESS;
 498                 break;
 499 
 500         case SAMR_QUERY_DOMAIN_INFO_7:
 501                 info->ru.info7.unknown1 = 0x00000003;
 502                 param->status = NT_STATUS_SUCCESS;
 503                 break;
 504 
 505         case SAMR_QUERY_DOMAIN_INFO_2:
 506                 info->ru.info2.unknown1 = 0x00000000;
 507                 info->ru.info2.unknown2 = 0x80000000;
 508 
 509                 (void) NDR_MSTRING(mxa, "",
 510                     (ndr_mstring_t *)&(info->ru.info2.s1));
 511                 (void) NDR_MSTRING(mxa, domain,
 512                     (ndr_mstring_t *)&(info->ru.info2.domain));
 513                 (void) NDR_MSTRING(mxa, "",
 514                     (ndr_mstring_t *)&(info->ru.info2.s2));
 515 
 516                 info->ru.info2.sequence_num = 0x0000002B;
 517                 info->ru.info2.unknown3 = 0x00000000;
 518                 info->ru.info2.unknown4 = 0x00000001;
 519                 info->ru.info2.unknown5 = 0x00000003;
 520                 info->ru.info2.unknown6 = 0x00000001;
 521                 info->ru.info2.num_users = user_cnt;
 522                 info->ru.info2.num_groups = 0;
 523                 info->ru.info2.num_aliases = alias_cnt;
 524                 param->status = NT_STATUS_SUCCESS;
 525                 break;
 526 
 527         default:
 528                 bzero(param, sizeof (struct samr_QueryDomainInfo));
 529                 return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
 530         };
 531 
 532         return (NDR_DRC_OK);
 533 }
 534 
 535 /*
 536  * QueryInfoDomain2: Identical to QueryDomainInfo.
 537  */
 538 static int
 539 samr_s_QueryInfoDomain2(void *arg, ndr_xa_t *mxa)
 540 {
 541         return (samr_s_QueryDomainInfo(arg, mxa));
 542 }
 543 
 544 /*
 545  * Looks up the given name in the specified domain which could
 546  * be either the built-in or local domain.
 547  *
 548  * CAVEAT: this function should be able to handle a list of
 549  * names but currently it can only handle one name at a time.
 550  */
 551 static int
 552 samr_s_LookupNames(void *arg, ndr_xa_t *mxa)
 553 {
 554         struct samr_LookupNames *param = arg;
 555         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 556         ndr_handle_t *hd;
 557         samr_keydata_t *data;
 558         smb_account_t account;
 559         smb_wka_t *wka;
 560         uint32_t status = NT_STATUS_SUCCESS;
 561 
 562         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL)
 563                 status = NT_STATUS_INVALID_HANDLE;
 564 
 565         if (param->n_entry != 1)
 566                 status = NT_STATUS_ACCESS_DENIED;
 567 
 568         if (param->name.str == NULL) {
 569                 /*
 570                  * Windows NT returns NT_STATUS_NONE_MAPPED.
 571                  * Windows 2000 returns STATUS_INVALID_ACCOUNT_NAME.
 572                  */
 573                 status = NT_STATUS_NONE_MAPPED;
 574         }
 575 
 576         if (status != NT_STATUS_SUCCESS) {
 577                 bzero(param, sizeof (struct samr_LookupNames));
 578                 param->status = NT_SC_ERROR(status);
 579                 return (NDR_DRC_OK);
 580         }
 581 
 582         param->rids.rid = NDR_NEW(mxa, DWORD);
 583         param->rid_types.rid_type = NDR_NEW(mxa, DWORD);
 584 
 585         data = (samr_keydata_t *)hd->nh_data;
 586 
 587         switch (data->kd_type) {
 588         case SMB_DOMAIN_BUILTIN:
 589                 wka = smb_wka_lookup_builtin((char *)param->name.str);
 590                 if (wka != NULL) {
 591                         param->rids.n_entry = 1;
 592                         (void) smb_sid_getrid(wka->wka_binsid,
 593                             &param->rids.rid[0]);
 594                         param->rid_types.n_entry = 1;
 595                         param->rid_types.rid_type[0] = wka->wka_type;
 596                         param->status = NT_STATUS_SUCCESS;
 597                         return (NDR_DRC_OK);
 598                 }
 599                 break;
 600 
 601         case SMB_DOMAIN_LOCAL:
 602                 status = smb_sam_lookup_name(NULL, (char *)param->name.str,
 603                     SidTypeUnknown, &account);
 604                 if (status == NT_STATUS_SUCCESS) {
 605                         param->rids.n_entry = 1;
 606                         param->rids.rid[0] = account.a_rid;
 607                         param->rid_types.n_entry = 1;
 608                         param->rid_types.rid_type[0] = account.a_type;
 609                         param->status = NT_STATUS_SUCCESS;
 610                         smb_account_free(&account);
 611                         return (NDR_DRC_OK);
 612                 }
 613                 break;
 614 
 615         default:
 616                 bzero(param, sizeof (struct samr_LookupNames));
 617                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 618                 return (NDR_DRC_OK);
 619         }
 620 
 621         param->rids.n_entry = 0;
 622         param->rid_types.n_entry = 0;
 623         param->status = NT_SC_ERROR(NT_STATUS_NONE_MAPPED);
 624         return (NDR_DRC_OK);
 625 }
 626 
 627 /*
 628  * samr_s_OpenUser
 629  *
 630  * This is a request to open a user within a specified domain in the
 631  * local SAM database. The caller must supply a valid domain handle,
 632  * obtained via a successful domain open request. The user is
 633  * specified by the rid in the request.
 634  */
 635 static int
 636 samr_s_OpenUser(void *arg, ndr_xa_t *mxa)
 637 {
 638         struct samr_OpenUser *param = arg;
 639         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 640         ndr_handle_t *hd;
 641         samr_keydata_t *data;
 642 
 643         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
 644                 bzero(&param->user_handle, sizeof (samr_handle_t));
 645                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 646                 return (NDR_DRC_OK);
 647         }
 648 
 649         data = (samr_keydata_t *)hd->nh_data;
 650 
 651         id = samr_hdalloc(mxa, SAMR_KEY_USER, data->kd_type, param->rid);
 652         if (id == NULL) {
 653                 bzero(&param->user_handle, sizeof (samr_handle_t));
 654                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 655         } else {
 656                 bcopy(id, &param->user_handle, sizeof (samr_handle_t));
 657                 param->status = NT_STATUS_SUCCESS;
 658         }
 659 
 660         return (NDR_DRC_OK);
 661 }
 662 
 663 /*
 664  * samr_s_DeleteUser
 665  *
 666  * Request to delete a user within a specified domain in the local
 667  * SAM database.  The caller should supply a valid user handle.
 668  */
 669 /*ARGSUSED*/
 670 static int
 671 samr_s_DeleteUser(void *arg, ndr_xa_t *mxa)
 672 {
 673         struct samr_DeleteUser *param = arg;
 674 
 675         bzero(param, sizeof (struct samr_DeleteUser));
 676         param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 677         return (NDR_DRC_OK);
 678 }
 679 
 680 /*
 681  * samr_s_QueryUserInfo
 682  *
 683  * Returns:
 684  * NT_STATUS_SUCCESS
 685  * NT_STATUS_ACCESS_DENIED
 686  * NT_STATUS_INVALID_INFO_CLASS
 687  */
 688 /*ARGSUSED*/
 689 static int
 690 samr_s_QueryUserInfo(void *arg, ndr_xa_t *mxa)
 691 {
 692         static uint16_t                 owf_buf[8];
 693         static uint8_t                  hour_buf[SAMR_SET_USER_HOURS_SZ];
 694         struct samr_QueryUserInfo       *param = arg;
 695         struct samr_QueryUserInfo21     *all_info;
 696         ndr_hdid_t                      *id;
 697         ndr_handle_t                    *hd;
 698         samr_keydata_t                  *data;
 699         smb_domain_t                    di;
 700         smb_account_t                   account;
 701         smb_sid_t                       *sid;
 702         uint32_t                        status;
 703 
 704         id = (ndr_hdid_t *)&param->user_handle;
 705         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_USER)) == NULL) {
 706                 status = NT_STATUS_INVALID_HANDLE;
 707                 goto QueryUserInfoError;
 708         }
 709 
 710         data = (samr_keydata_t *)hd->nh_data;
 711 
 712         if (param->switch_value != SAMR_QUERY_USER_ALL_INFO) {
 713                 status = NT_STATUS_ACCESS_DENIED;
 714                 goto QueryUserInfoError;
 715         }
 716 
 717         if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di)) {
 718                 status = NT_STATUS_ACCESS_DENIED;
 719                 goto QueryUserInfoError;
 720         }
 721 
 722         if ((sid = smb_sid_splice(di.di_binsid, data->kd_rid)) == NULL) {
 723                 status = NT_STATUS_ACCESS_DENIED;
 724                 goto QueryUserInfoError;
 725         }
 726 
 727         if (smb_sam_lookup_sid(sid, &account) != NT_STATUS_SUCCESS) {
 728                 status = NT_STATUS_ACCESS_DENIED;
 729                 goto QueryUserInfoError;
 730         }
 731 
 732         all_info = &param->ru.info21;
 733         bzero(all_info, sizeof (struct samr_QueryUserInfo21));
 734 
 735         all_info->WhichFields = SAMR_USER_ALL_USERNAME | SAMR_USER_ALL_USERID;
 736 
 737         (void) NDR_MSTRING(mxa, account.a_name,
 738             (ndr_mstring_t *)&all_info->UserName);
 739         all_info->UserId = data->kd_rid;
 740 
 741         all_info->LmOwfPassword.length = 16;
 742         all_info->LmOwfPassword.maxlen = 16;
 743         all_info->LmOwfPassword.buf = owf_buf;
 744         all_info->NtOwfPassword.length = 16;
 745         all_info->NtOwfPassword.maxlen = 16;
 746         all_info->NtOwfPassword.buf = owf_buf;
 747         all_info->LogonHours.units_per_week = SAMR_HOURS_PER_WEEK;
 748         all_info->LogonHours.hours = hour_buf;
 749 
 750         param->address = 1;
 751         param->switch_index = SAMR_QUERY_USER_ALL_INFO;
 752         param->status = NT_STATUS_SUCCESS;
 753         smb_account_free(&account);
 754         smb_sid_free(sid);
 755         return (NDR_DRC_OK);
 756 
 757 QueryUserInfoError:
 758         smb_sid_free(sid);
 759         bzero(param, sizeof (struct samr_QueryUserInfo));
 760         param->status = NT_SC_ERROR(status);
 761         return (NDR_DRC_OK);
 762 }
 763 
 764 /*
 765  * samr_s_QueryUserGroups
 766  *
 767  * Request the list of groups of which a user is a member.
 768  * The user is identified from the handle, which contains an
 769  * rid in the discriminator field. Note that this is a local user.
 770  */
 771 static int
 772 samr_s_QueryUserGroups(void *arg, ndr_xa_t *mxa)
 773 {
 774         struct samr_QueryUserGroups *param = arg;
 775         struct samr_UserGroupInfo *info;
 776         struct samr_UserGroups *group;
 777         ndr_hdid_t *id = (ndr_hdid_t *)&param->user_handle;
 778         ndr_handle_t *hd;
 779         samr_keydata_t *data;
 780         smb_sid_t *user_sid = NULL;
 781         smb_group_t grp;
 782         smb_giter_t gi;
 783         smb_domain_t di;
 784         uint32_t status;
 785         int size;
 786         int ngrp_max;
 787 
 788         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_USER)) == NULL) {
 789                 status = NT_STATUS_ACCESS_DENIED;
 790                 goto query_error;
 791         }
 792 
 793         data = (samr_keydata_t *)hd->nh_data;
 794         switch (data->kd_type) {
 795         case SMB_DOMAIN_BUILTIN:
 796         case SMB_DOMAIN_LOCAL:
 797                 if (!smb_domain_lookup_type(data->kd_type, &di)) {
 798                         status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 799                         goto query_error;
 800                 }
 801                 break;
 802         default:
 803                 status = NT_STATUS_INVALID_HANDLE;
 804                 goto query_error;
 805         }
 806 
 807         user_sid = smb_sid_splice(di.di_binsid, data->kd_rid);
 808         if (user_sid == NULL) {
 809                 status = NT_STATUS_NO_MEMORY;
 810                 goto query_error;
 811         }
 812 
 813         info = NDR_NEW(mxa, struct samr_UserGroupInfo);
 814         if (info == NULL) {
 815                 status = NT_STATUS_NO_MEMORY;
 816                 goto query_error;
 817         }
 818         bzero(info, sizeof (struct samr_UserGroupInfo));
 819 
 820         size = 32 * 1024;
 821         info->groups = NDR_MALLOC(mxa, size);
 822         if (info->groups == NULL) {
 823                 status = NT_STATUS_NO_MEMORY;
 824                 goto query_error;
 825         }
 826         ngrp_max = size / sizeof (struct samr_UserGroups);
 827 
 828         if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) {
 829                 status = NT_STATUS_INTERNAL_ERROR;
 830                 goto query_error;
 831         }
 832 
 833         info->n_entry = 0;
 834         group = info->groups;
 835         while ((info->n_entry < ngrp_max) &&
 836             (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS)) {
 837                 if (smb_lgrp_is_member(&grp, user_sid)) {
 838                         group->rid = grp.sg_rid;
 839                         group->attr = grp.sg_attr;
 840                         group++;
 841                         info->n_entry++;
 842                 }
 843                 smb_lgrp_free(&grp);
 844         }
 845         smb_lgrp_iterclose(&gi);
 846 
 847         free(user_sid);
 848         param->info = info;
 849         param->status = NT_STATUS_SUCCESS;
 850         return (NDR_DRC_OK);
 851 
 852 query_error:
 853         free(user_sid);
 854         bzero(param, sizeof (struct samr_QueryUserGroups));
 855         param->status = NT_SC_ERROR(status);
 856         return (NDR_DRC_OK);
 857 }
 858 
 859 /*
 860  * samr_s_OpenGroup
 861  *
 862  * This is a request to open a group within the specified domain in the
 863  * local SAM database. The caller must supply a valid domain handle,
 864  * obtained via a successful domain open request. The group is
 865  * specified by the rid in the request. If this is a local RID it
 866  * should already be encoded with type information.
 867  *
 868  * We return a handle to be used to access information about this group.
 869  */
 870 static int
 871 samr_s_OpenGroup(void *arg, ndr_xa_t *mxa)
 872 {
 873         struct samr_OpenGroup *param = arg;
 874         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 875         ndr_handle_t *hd;
 876         samr_keydata_t *data;
 877 
 878         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
 879                 bzero(&param->group_handle, sizeof (samr_handle_t));
 880                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 881                 return (NDR_DRC_OK);
 882         }
 883 
 884         data = (samr_keydata_t *)hd->nh_data;
 885         id = samr_hdalloc(mxa, SAMR_KEY_GROUP, data->kd_type, param->rid);
 886 
 887         if (id) {
 888                 bcopy(id, &param->group_handle, sizeof (samr_handle_t));
 889                 param->status = 0;
 890         } else {
 891                 bzero(&param->group_handle, sizeof (samr_handle_t));
 892                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 893         }
 894 
 895         return (NDR_DRC_OK);
 896 }
 897 
 898 /*
 899  * samr_s_AddAliasMember
 900  *
 901  * Add a member to a local SAM group.
 902  * The caller must supply a valid group handle.
 903  * The member is specified by the sid in the request.
 904  */
 905 static int
 906 samr_s_AddAliasMember(void *arg, ndr_xa_t *mxa)
 907 {
 908         struct samr_AddAliasMember *param = arg;
 909         ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
 910         ndr_handle_t *hd;
 911         samr_keydata_t *data;
 912         smb_group_t grp;
 913         uint32_t rc;
 914         uint32_t status = NT_STATUS_SUCCESS;
 915 
 916         if (param->sid == NULL) {
 917                 bzero(param, sizeof (struct samr_AddAliasMember));
 918                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
 919                 return (NDR_DRC_OK);
 920         }
 921 
 922         if (!ndr_is_admin(mxa)) {
 923                 bzero(param, sizeof (struct samr_AddAliasMember));
 924                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 925                 return (NDR_DRC_OK);
 926         }
 927 
 928 
 929         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
 930                 bzero(param, sizeof (struct samr_AddAliasMember));
 931                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 932                 return (NDR_DRC_OK);
 933         }
 934 
 935         data = (samr_keydata_t *)hd->nh_data;
 936         rc = smb_lgrp_getbyrid(data->kd_rid, data->kd_type, &grp);
 937         if (rc != SMB_LGRP_SUCCESS) {
 938                 bzero(param, sizeof (struct samr_AddAliasMember));
 939                 status = smb_lgrp_err_to_ntstatus(rc);
 940                 param->status = NT_SC_ERROR(status);
 941                 return (NDR_DRC_OK);
 942         }
 943 
 944         rc = smb_lgrp_add_member(grp.sg_name,
 945             (smb_sid_t *)param->sid, SidTypeUser);
 946         if (rc != SMB_LGRP_SUCCESS) {
 947                 bzero(param, sizeof (struct samr_AddAliasMember));
 948                 status = smb_lgrp_err_to_ntstatus(rc);
 949                 param->status = NT_SC_ERROR(status);
 950         }
 951         smb_lgrp_free(&grp);
 952 
 953         param->status = status;
 954         return (NDR_DRC_OK);
 955 }
 956 
 957 /*
 958  * samr_s_DeleteAliasMember
 959  *
 960  * Delete a member from a local SAM group.
 961  * The caller must supply a valid group handle.
 962  * The member is specified by the sid in the request.
 963  */
 964 static int
 965 samr_s_DeleteAliasMember(void *arg, ndr_xa_t *mxa)
 966 {
 967         struct samr_DeleteAliasMember *param = arg;
 968         ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
 969         ndr_handle_t *hd;
 970         samr_keydata_t *data;
 971         smb_group_t grp;
 972         uint32_t rc;
 973         uint32_t status = NT_STATUS_SUCCESS;
 974 
 975         if (param->sid == NULL) {
 976                 bzero(param, sizeof (struct samr_DeleteAliasMember));
 977                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
 978                 return (NDR_DRC_OK);
 979         }
 980 
 981         if (!ndr_is_admin(mxa)) {
 982                 bzero(param, sizeof (struct samr_DeleteAliasMember));
 983                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 984                 return (NDR_DRC_OK);
 985         }
 986 
 987         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
 988                 bzero(param, sizeof (struct samr_DeleteAliasMember));
 989                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 990                 return (NDR_DRC_OK);
 991         }
 992 
 993         data = (samr_keydata_t *)hd->nh_data;
 994         rc = smb_lgrp_getbyrid(data->kd_rid, data->kd_type, &grp);
 995         if (rc != SMB_LGRP_SUCCESS) {
 996                 bzero(param, sizeof (struct samr_DeleteAliasMember));
 997                 status = smb_lgrp_err_to_ntstatus(rc);
 998                 param->status = NT_SC_ERROR(status);
 999                 return (NDR_DRC_OK);
1000         }
1001 
1002         rc = smb_lgrp_del_member(grp.sg_name,
1003             (smb_sid_t *)param->sid, SidTypeUser);
1004         if (rc != SMB_LGRP_SUCCESS) {
1005                 bzero(param, sizeof (struct samr_DeleteAliasMember));
1006                 status = smb_lgrp_err_to_ntstatus(rc);
1007                 param->status = NT_SC_ERROR(status);
1008         }
1009         smb_lgrp_free(&grp);
1010 
1011         param->status = status;
1012         return (NDR_DRC_OK);
1013 }
1014 
1015 /*
1016  * samr_s_ListAliasMembers
1017  *
1018  * List members from a local SAM group.
1019  * The caller must supply a valid group handle.
1020  * A list of user SIDs in the specified group is returned to the caller.
1021  */
1022 static int
1023 samr_s_ListAliasMembers(void *arg, ndr_xa_t *mxa)
1024 {
1025         struct samr_ListAliasMembers *param = arg;
1026         ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1027         ndr_handle_t *hd;
1028         samr_keydata_t *data;
1029         smb_group_t grp;
1030         smb_gsid_t *members;
1031         struct samr_SidInfo info;
1032         struct samr_SidList *user;
1033         uint32_t num = 0, size;
1034         int i;
1035         uint32_t rc;
1036         uint32_t status = NT_STATUS_SUCCESS;
1037 
1038         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
1039                 bzero(param, sizeof (struct samr_ListAliasMembers));
1040                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1041                 return (NDR_DRC_OK);
1042         }
1043 
1044         bzero(&info, sizeof (struct samr_SidInfo));
1045         data = (samr_keydata_t *)hd->nh_data;
1046         rc = smb_lgrp_getbyrid(data->kd_rid, data->kd_type, &grp);
1047         if (rc != SMB_LGRP_SUCCESS) {
1048                 bzero(param, sizeof (struct samr_ListAliasMembers));
1049                 status = smb_lgrp_err_to_ntstatus(rc);
1050                 param->status = NT_SC_ERROR(status);
1051                 return (NDR_DRC_OK);
1052         }
1053 
1054         num = grp.sg_nmembers;
1055         members = grp.sg_members;
1056         size = num * sizeof (struct samr_SidList);
1057         info.sidlist = NDR_MALLOC(mxa, size);
1058         if (info.sidlist == NULL) {
1059                 bzero(param, sizeof (struct samr_ListAliasMembers));
1060                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1061                 smb_lgrp_free(&grp);
1062                 return (NDR_DRC_OK);
1063         }
1064 
1065         info.n_entry = num;
1066         user = info.sidlist;
1067         for (i = 0; i < num; i++) {
1068                 user->sid = (struct samr_sid *)NDR_SIDDUP(mxa,
1069                     members[i].gs_sid);
1070                 if (user->sid == NULL) {
1071                         bzero(param, sizeof (struct samr_ListAliasMembers));
1072                         param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1073                         smb_lgrp_free(&grp);
1074                         return (NDR_DRC_OK);
1075                 }
1076                 user++;
1077         }
1078         smb_lgrp_free(&grp);
1079 
1080         param->info = info;
1081         param->status = status;
1082         return (NDR_DRC_OK);
1083 }
1084 
1085 /*
1086  * samr_s_Connect2
1087  *
1088  * This is a request to connect to the local SAM database.
1089  * We don't support any form of update request and our database doesn't
1090  * contain any private information, so there is little point in doing
1091  * any access access checking here.
1092  *
1093  * Return a handle for use with subsequent SAM requests.
1094  */
1095 static int
1096 samr_s_Connect2(void *arg, ndr_xa_t *mxa)
1097 {
1098         struct samr_Connect2 *param = arg;
1099         ndr_hdid_t *id;
1100 
1101         id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
1102         if (id) {
1103                 bcopy(id, &param->handle, sizeof (samr_handle_t));
1104                 param->status = 0;
1105         } else {
1106                 bzero(&param->handle, sizeof (samr_handle_t));
1107                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1108         }
1109 
1110         return (NDR_DRC_OK);
1111 }
1112 
1113 /*
1114  * samr_s_GetUserPwInfo
1115  *
1116  * Request for a user's password policy information.
1117  */
1118 /*ARGSUSED*/
1119 static int
1120 samr_s_GetUserPwInfo(void *arg, ndr_xa_t *mxa)
1121 {
1122         static samr_password_info_t     pwinfo;
1123         struct samr_GetUserPwInfo       *param = arg;
1124 
1125         param->pwinfo = &pwinfo;
1126         param->status = NT_STATUS_SUCCESS;
1127         return (NDR_DRC_OK);
1128 }
1129 
1130 /*
1131  * samr_s_CreateUser
1132  */
1133 /*ARGSUSED*/
1134 static int
1135 samr_s_CreateUser(void *arg, ndr_xa_t *mxa)
1136 {
1137         struct samr_CreateUser *param = arg;
1138 
1139         bzero(&param->user_handle, sizeof (samr_handle_t));
1140         param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1141         return (NDR_DRC_OK);
1142 }
1143 
1144 /*
1145  * samr_s_ChangePasswordUser2
1146  */
1147 /*ARGSUSED*/
1148 static int
1149 samr_s_ChangePasswordUser2(void *arg, ndr_xa_t *mxa)
1150 {
1151         struct samr_ChangePasswordUser2 *param = arg;
1152 
1153         bzero(param, sizeof (*param));
1154         param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1155         return (NDR_DRC_OK);
1156 }
1157 
1158 /*
1159  * samr_s_GetDomainPwInfo
1160  *
1161  * Request for the domain password policy information.
1162  */
1163 /*ARGSUSED*/
1164 static int
1165 samr_s_GetDomainPwInfo(void *arg, ndr_xa_t *mxa)
1166 {
1167         static samr_password_info_t     pwinfo;
1168         struct samr_GetDomainPwInfo     *param = arg;
1169 
1170         param->pwinfo = &pwinfo;
1171         param->status = NT_STATUS_SUCCESS;
1172         return (NDR_DRC_OK);
1173 }
1174 
1175 /*
1176  * samr_s_SetUserInfo
1177  */
1178 /*ARGSUSED*/
1179 static int
1180 samr_s_SetUserInfo(void *arg, ndr_xa_t *mxa)
1181 {
1182         struct samr_SetUserInfo *param = arg;
1183 
1184         bzero(param, sizeof (struct samr_SetUserInfo));
1185         param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1186         return (NDR_DRC_OK);
1187 }
1188 
1189 /*
1190  * samr_s_QueryDispInfo
1191  *
1192  * This function currently return local users' information only.
1193  * This RPC is called repeatedly until all the users info are
1194  * retrieved.
1195  *
1196  * The total count and the returned count are returned as total size
1197  * and returned size.  The client doesn't seem to care.
1198  */
1199 static int
1200 samr_s_QueryDispInfo(void *arg, ndr_xa_t *mxa)
1201 {
1202         struct samr_QueryDispInfo *param = arg;
1203         ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
1204         ndr_handle_t *hd;
1205         samr_keydata_t *data;
1206         DWORD status = NT_STATUS_SUCCESS;
1207         struct user_acct_info *user;
1208         smb_pwditer_t pwi;
1209         smb_luser_t *uinfo;
1210         int num_users;
1211         int start_idx;
1212         int max_retcnt, retcnt;
1213         int skip;
1214 
1215         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
1216                 status = NT_STATUS_INVALID_HANDLE;
1217                 goto error;
1218         }
1219 
1220         if (!SAMR_VALID_DISPLEVEL(param->level)) {
1221                 status = NT_STATUS_INVALID_INFO_CLASS;
1222                 goto error;
1223         }
1224 
1225         if (!SAMR_SUPPORTED_DISPLEVEL(param->level)) {
1226                 status = NT_STATUS_NOT_IMPLEMENTED;
1227                 goto error;
1228         }
1229 
1230         data = (samr_keydata_t *)hd->nh_data;
1231 
1232         switch (data->kd_type) {
1233         case SMB_DOMAIN_BUILTIN:
1234                 goto no_info;
1235 
1236         case SMB_DOMAIN_LOCAL:
1237                 num_users = smb_sam_usr_cnt();
1238                 start_idx = param->start_idx;
1239                 if ((num_users == 0) || (start_idx >= num_users))
1240                         goto no_info;
1241 
1242                 max_retcnt = num_users - start_idx;
1243                 if (max_retcnt > param->max_entries)
1244                         max_retcnt = param->max_entries;
1245                 param->users.acct = NDR_MALLOC(mxa,
1246                     max_retcnt * sizeof (struct user_acct_info));
1247                 user = param->users.acct;
1248                 if (user == NULL) {
1249                         status = NT_STATUS_NO_MEMORY;
1250                         goto error;
1251                 }
1252                 bzero(user, max_retcnt * sizeof (struct user_acct_info));
1253 
1254                 if (smb_pwd_iteropen(&pwi) != SMB_PWE_SUCCESS)
1255                         goto no_info;
1256 
1257                 skip = retcnt = 0;
1258                 while ((uinfo = smb_pwd_iterate(&pwi)) != NULL) {
1259                         if (skip++ < start_idx)
1260                                 continue;
1261 
1262                         if (retcnt++ >= max_retcnt)
1263                                 break;
1264 
1265                         assert(uinfo->su_name != NULL);
1266 
1267                         user->index = start_idx + retcnt;
1268                         user->rid = uinfo->su_rid;
1269                         user->ctrl = ACF_NORMUSER | ACF_PWDNOEXP;
1270                         if (uinfo->su_ctrl & SMB_PWF_DISABLE)
1271                                 user->ctrl |= ACF_DISABLED;
1272                         if (NDR_MSTRING(mxa, uinfo->su_name,
1273                             (ndr_mstring_t *)&user->name) == -1) {
1274                                 smb_pwd_iterclose(&pwi);
1275                                 status = NT_STATUS_NO_MEMORY;
1276                                 goto error;
1277                         }
1278                         (void) NDR_MSTRING(mxa, uinfo->su_fullname,
1279                             (ndr_mstring_t *)&user->fullname);
1280                         (void) NDR_MSTRING(mxa, uinfo->su_desc,
1281                             (ndr_mstring_t *)&user->desc);
1282                         user++;
1283                 }
1284                 smb_pwd_iterclose(&pwi);
1285 
1286                 if (retcnt >= max_retcnt) {
1287                         retcnt = max_retcnt;
1288                         param->status = status;
1289                 } else {
1290                         param->status = NT_STATUS_MORE_ENTRIES;
1291                 }
1292 
1293                 param->users.total_size = num_users;
1294                 param->users.returned_size = retcnt;
1295                 param->users.switch_value = param->level;
1296                 param->users.count = retcnt;
1297 
1298                 break;
1299 
1300         default:
1301                 status = NT_STATUS_INVALID_HANDLE;
1302                 goto error;
1303         }
1304 
1305         return (NDR_DRC_OK);
1306 
1307 no_info:
1308         param->users.total_size = 0;
1309         param->users.returned_size = 0;
1310         param->users.switch_value = param->level;
1311         param->users.count = 0;
1312         param->users.acct = NULL;
1313         param->status = status;
1314         return (NDR_DRC_OK);
1315 
1316 error:
1317         bzero(param, sizeof (struct samr_QueryDispInfo));
1318         param->status = NT_SC_ERROR(status);
1319         return (NDR_DRC_OK);
1320 }
1321 
1322 /*
1323  * samr_s_EnumDomainGroups
1324  *
1325  *
1326  * This function is supposed to return local group information.
1327  * As we don't support local users, this function dosen't send
1328  * back any information.
1329  *
1330  * Added template that returns information for a domain group as None.
1331  * All information is hard-coded from packet captures.
1332  */
1333 static int
1334 samr_s_EnumDomainGroups(void *arg, ndr_xa_t *mxa)
1335 {
1336         struct samr_EnumDomainGroups *param = arg;
1337         ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
1338         DWORD status = NT_STATUS_SUCCESS;
1339 
1340         if (samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN) == NULL)
1341                 status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1342 
1343         param->total_size = 0;
1344         param->returned_size = 0;
1345         param->switch_value = 3;
1346         param->count = 0;
1347         param->groups = 0;
1348         param->status = status;
1349         return (NDR_DRC_OK);
1350 
1351 #ifdef SAMR_SUPPORT_GROUPS
1352         if ((desc->discrim != SAMR_LOCAL_DOMAIN) || (param->start_idx != 0)) {
1353                 param->total_size = 0;
1354                 param->returned_size = 0;
1355                 param->switch_value = 3;
1356                 param->count = 0;
1357                 param->groups = 0;
1358         } else {
1359                 param->total_size = 64;
1360                 param->returned_size = 64;
1361                 param->switch_value = 3;
1362                 param->count = 1;
1363                 param->groups = (struct group_disp_info *)NDR_MALLOC(
1364                     mxa, sizeof (struct group_disp_info));
1365 
1366                 param->groups->count = 1;
1367                 param->groups->acct[0].index = 1;
1368                 param->groups->acct[0].rid = 513;
1369                 param->groups->acct[0].ctrl = 0x7;
1370                 (void) NDR_MSTRING(mxa, "None",
1371                     (ndr_mstring_t *)&param->groups->acct[0].name);
1372 
1373                 (void) NDR_MSTRING(mxa, "Ordinary users",
1374                     (ndr_mstring_t *)&param->groups->acct[0].desc);
1375         }
1376 
1377         param->status = NT_STATUS_SUCCESS;
1378         return (NDR_DRC_OK);
1379 #endif
1380 }
1381 
1382 /*
1383  * samr_s_OpenAlias
1384  *
1385  * Lookup for requested alias, if it exists return a handle
1386  * for that alias. The alias domain sid should match with
1387  * the passed domain handle.
1388  */
1389 static int
1390 samr_s_OpenAlias(void *arg, ndr_xa_t *mxa)
1391 {
1392         struct samr_OpenAlias *param = arg;
1393         ndr_hdid_t      *id = (ndr_hdid_t *)&param->domain_handle;
1394         ndr_handle_t    *hd;
1395         samr_keydata_t  *data;
1396         smb_domain_type_t gd_type;
1397         smb_sid_t       *sid;
1398         smb_wka_t       *wka;
1399         char            sidstr[SMB_SID_STRSZ];
1400         uint32_t        rid;
1401         uint32_t        status;
1402         int             rc;
1403 
1404         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
1405                 status = NT_STATUS_INVALID_HANDLE;
1406                 goto open_alias_err;
1407         }
1408 
1409         if ((param->access_mask & SAMR_ALIAS_ACCESS_ALL_ACCESS) == 0) {
1410                 status = NT_STATUS_ACCESS_DENIED;
1411                 goto open_alias_err;
1412         }
1413 
1414         data = (samr_keydata_t *)hd->nh_data;
1415         gd_type = (smb_domain_type_t)data->kd_type;
1416         rid = param->rid;
1417 
1418         switch (gd_type) {
1419         case SMB_DOMAIN_BUILTIN:
1420                 (void) snprintf(sidstr, SMB_SID_STRSZ, "%s-%d",
1421                     NT_BUILTIN_DOMAIN_SIDSTR, rid);
1422                 if ((sid = smb_sid_fromstr(sidstr)) == NULL) {
1423                         status = NT_STATUS_NO_SUCH_ALIAS;
1424                         goto open_alias_err;
1425                 }
1426 
1427                 wka = smb_wka_lookup_sid(sid);
1428                 smb_sid_free(sid);
1429 
1430                 if (wka == NULL) {
1431                         status = NT_STATUS_NO_SUCH_ALIAS;
1432                         goto open_alias_err;
1433                 }
1434                 break;
1435 
1436         case SMB_DOMAIN_LOCAL:
1437                 rc = smb_lgrp_getbyrid(rid, gd_type, NULL);
1438                 if (rc != SMB_LGRP_SUCCESS) {
1439                         status = NT_STATUS_NO_SUCH_ALIAS;
1440                         goto open_alias_err;
1441                 }
1442                 break;
1443 
1444         default:
1445                 status = NT_STATUS_NO_SUCH_ALIAS;
1446                 goto open_alias_err;
1447         }
1448 
1449         id = samr_hdalloc(mxa, SAMR_KEY_ALIAS, data->kd_type, param->rid);
1450         if (id) {
1451                 bcopy(id, &param->alias_handle, sizeof (samr_handle_t));
1452                 param->status = NT_STATUS_SUCCESS;
1453                 return (NDR_DRC_OK);
1454         }
1455 
1456         status = NT_STATUS_NO_MEMORY;
1457 
1458 open_alias_err:
1459         bzero(&param->alias_handle, sizeof (samr_handle_t));
1460         param->status = NT_SC_ERROR(status);
1461         return (NDR_DRC_OK);
1462 }
1463 
1464 /*
1465  * samr_s_CreateDomainAlias
1466  *
1467  * Create a local group in the security accounts manager (SAM) database.
1468  * A local SAM group can only be added if a Solaris group already exists
1469  * with the same name.  On success, a valid group handle is returned.
1470  *
1471  * The caller must have administrator rights to execute this function.
1472  */
1473 static int
1474 samr_s_CreateDomainAlias(void *arg, ndr_xa_t *mxa)
1475 {
1476         struct samr_CreateDomainAlias *param = arg;
1477         ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1478         uint32_t status = NT_STATUS_SUCCESS;
1479         smb_group_t grp;
1480         uint32_t rc;
1481         char *gname;
1482 
1483         if (samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN) != NULL) {
1484                 bzero(param, sizeof (struct samr_CreateDomainAlias));
1485                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1486                 return (NDR_DRC_OK);
1487         }
1488 
1489         gname = (char *)param->alias_name.str;
1490         if (gname == NULL) {
1491                 bzero(&param->alias_handle, sizeof (samr_handle_t));
1492                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
1493                 return (NDR_DRC_OK);
1494         }
1495 
1496         if ((!ndr_is_admin(mxa)) ||
1497             ((param->access_mask & SAMR_ALIAS_ACCESS_WRITE_ACCOUNT) == 0)) {
1498                 bzero(&param->alias_handle, sizeof (samr_handle_t));
1499                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1500                 return (NDR_DRC_OK);
1501         }
1502 
1503         rc = smb_lgrp_add(gname, "");
1504         if (rc != SMB_LGRP_SUCCESS) {
1505                 bzero(&param->alias_handle, sizeof (samr_handle_t));
1506                 status = smb_lgrp_err_to_ntstatus(rc);
1507                 param->status = NT_SC_ERROR(status);
1508                 return (NDR_DRC_OK);
1509         }
1510 
1511         rc = smb_lgrp_getbyname((char *)gname, &grp);
1512         if (rc != SMB_LGRP_SUCCESS) {
1513                 bzero(&param->alias_handle, sizeof (samr_handle_t));
1514                 status = smb_lgrp_err_to_ntstatus(rc);
1515                 param->status = NT_SC_ERROR(status);
1516                 return (NDR_DRC_OK);
1517         }
1518 
1519         id = samr_hdalloc(mxa, SAMR_KEY_ALIAS, SMB_DOMAIN_LOCAL, grp.sg_rid);
1520         smb_lgrp_free(&grp);
1521         if (id) {
1522                 bcopy(id, &param->alias_handle, sizeof (samr_handle_t));
1523                 param->status = status;
1524         } else {
1525                 bzero(&param->alias_handle, sizeof (samr_handle_t));
1526                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1527         }
1528 
1529         return (NDR_DRC_OK);
1530 }
1531 
1532 /*
1533  * samr_s_SetAliasInfo
1534  *
1535  * Similar to NetLocalGroupSetInfo.
1536  */
1537 static int
1538 samr_s_SetAliasInfo(void *arg, ndr_xa_t *mxa)
1539 {
1540         struct samr_SetAliasInfo *param = arg;
1541         ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1542         DWORD status = NT_STATUS_SUCCESS;
1543 
1544         if (samr_hdlookup(mxa, id, SAMR_KEY_ALIAS) == NULL)
1545                 status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1546 
1547         param->status = status;
1548         return (NDR_DRC_OK);
1549 }
1550 
1551 /*
1552  * samr_s_QueryAliasInfo
1553  *
1554  * Retrieves information about the specified local group account
1555  * by given handle.
1556  */
1557 static int
1558 samr_s_QueryAliasInfo(void *arg, ndr_xa_t *mxa)
1559 {
1560         struct samr_QueryAliasInfo *param = arg;
1561         ndr_hdid_t      *id = (ndr_hdid_t *)&param->alias_handle;
1562         ndr_handle_t    *hd;
1563         samr_keydata_t  *data;
1564         smb_group_t     grp;
1565         smb_domain_type_t gd_type;
1566         smb_sid_t       *sid;
1567         smb_wka_t       *wka;
1568         char            sidstr[SMB_SID_STRSZ];
1569         char            *name;
1570         char            *desc;
1571         uint32_t        rid;
1572         uint32_t        status;
1573         int             rc;
1574 
1575         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
1576                 status = NT_STATUS_INVALID_HANDLE;
1577                 goto query_alias_err;
1578         }
1579 
1580         data = (samr_keydata_t *)hd->nh_data;
1581         gd_type = (smb_domain_type_t)data->kd_type;
1582         rid = data->kd_rid;
1583 
1584         switch (gd_type) {
1585         case SMB_DOMAIN_BUILTIN:
1586                 (void) snprintf(sidstr, SMB_SID_STRSZ, "%s-%d",
1587                     NT_BUILTIN_DOMAIN_SIDSTR, rid);
1588                 if ((sid = smb_sid_fromstr(sidstr)) == NULL) {
1589                         status = NT_STATUS_NO_SUCH_ALIAS;
1590                         goto query_alias_err;
1591                 }
1592 
1593                 wka = smb_wka_lookup_sid(sid);
1594                 smb_sid_free(sid);
1595 
1596                 if (wka == NULL) {
1597                         status = NT_STATUS_NO_SUCH_ALIAS;
1598                         goto query_alias_err;
1599                 }
1600 
1601                 name = wka->wka_name;
1602                 desc = (wka->wka_desc != NULL) ? wka->wka_desc : "";
1603                 break;
1604 
1605         case SMB_DOMAIN_LOCAL:
1606                 rc = smb_lgrp_getbyrid(rid, gd_type, &grp);
1607                 if (rc != SMB_LGRP_SUCCESS) {
1608                         status = NT_STATUS_NO_SUCH_ALIAS;
1609                         goto query_alias_err;
1610                 }
1611                 name = grp.sg_name;
1612                 desc = grp.sg_cmnt;
1613                 break;
1614 
1615         default:
1616                 status = NT_STATUS_NO_SUCH_ALIAS;
1617                 goto query_alias_err;
1618         }
1619 
1620         switch (param->level) {
1621         case SAMR_QUERY_ALIAS_INFO_GENERAL:
1622                 param->ru.info1.level = param->level;
1623                 (void) NDR_MSTRING(mxa, name,
1624                     (ndr_mstring_t *)&param->ru.info1.name);
1625                 (void) NDR_MSTRING(mxa, desc,
1626                     (ndr_mstring_t *)&param->ru.info1.desc);
1627                 param->ru.info1.member_count = 1;
1628                 break;
1629 
1630         case SAMR_QUERY_ALIAS_INFO_NAME:
1631                 param->ru.info2.level = param->level;
1632                 (void) NDR_MSTRING(mxa, name,
1633                     (ndr_mstring_t *)&param->ru.info2.name);
1634                 break;
1635 
1636         case SAMR_QUERY_ALIAS_INFO_COMMENT:
1637                 param->ru.info3.level = param->level;
1638                 (void) NDR_MSTRING(mxa, desc,
1639                     (ndr_mstring_t *)&param->ru.info3.desc);
1640                 break;
1641 
1642         default:
1643                 if (gd_type == SMB_DOMAIN_LOCAL)
1644                         smb_lgrp_free(&grp);
1645                 status = NT_STATUS_INVALID_INFO_CLASS;
1646                 goto query_alias_err;
1647         };
1648 
1649         if (gd_type == SMB_DOMAIN_LOCAL)
1650                 smb_lgrp_free(&grp);
1651         param->address = (DWORD)(uintptr_t)&param->ru;
1652         param->status = 0;
1653         return (NDR_DRC_OK);
1654 
1655 query_alias_err:
1656         param->status = NT_SC_ERROR(status);
1657         return (NDR_DRC_OK);
1658 }
1659 
1660 /*
1661  * samr_s_DeleteDomainAlias
1662  *
1663  * Deletes a local group in the security database, which is the
1664  * security accounts manager (SAM). A valid group handle is returned
1665  * to the caller upon success.
1666  *
1667  * The caller must have administrator rights to execute this function.
1668  */
1669 static int
1670 samr_s_DeleteDomainAlias(void *arg, ndr_xa_t *mxa)
1671 {
1672         struct samr_DeleteDomainAlias *param = arg;
1673         ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1674         ndr_handle_t    *hd;
1675         smb_group_t grp;
1676         samr_keydata_t  *data;
1677         smb_domain_type_t       gd_type;
1678         uint32_t        rid;
1679         uint32_t        rc;
1680         uint32_t        status = NT_STATUS_SUCCESS;
1681 
1682         if (!ndr_is_admin(mxa)) {
1683                 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1684                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1685                 return (NDR_DRC_OK);
1686         }
1687 
1688         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
1689                 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1690                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1691                 return (NDR_DRC_OK);
1692         }
1693 
1694         data = (samr_keydata_t *)hd->nh_data;
1695         gd_type = (smb_domain_type_t)data->kd_type;
1696         rid = data->kd_rid;
1697 
1698         switch (gd_type) {
1699         case SMB_DOMAIN_BUILTIN:
1700                 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1701                 status = NT_SC_ERROR(NT_STATUS_NOT_SUPPORTED);
1702                 break;
1703 
1704         case SMB_DOMAIN_LOCAL:
1705                 rc = smb_lgrp_getbyrid(rid, gd_type, &grp);
1706                 if (rc != SMB_LGRP_SUCCESS) {
1707                         bzero(param, sizeof (struct samr_DeleteDomainAlias));
1708                         status = smb_lgrp_err_to_ntstatus(rc);
1709                         status = NT_SC_ERROR(status);
1710                         break;
1711                 }
1712 
1713                 rc = smb_lgrp_delete(grp.sg_name);
1714                 if (rc != SMB_LGRP_SUCCESS) {
1715                         bzero(param, sizeof (struct samr_DeleteDomainAlias));
1716                         status = smb_lgrp_err_to_ntstatus(rc);
1717                         status = NT_SC_ERROR(status);
1718                 }
1719                 smb_lgrp_free(&grp);
1720                 break;
1721 
1722         default:
1723                 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1724                 status = NT_SC_ERROR(NT_STATUS_NO_SUCH_ALIAS);
1725         }
1726 
1727         param->status = status;
1728         return (NDR_DRC_OK);
1729 }
1730 
1731 /*
1732  * samr_s_EnumDomainAliases
1733  *
1734  * This function sends back a list which contains all local groups' name.
1735  */
1736 static int
1737 samr_s_EnumDomainAliases(void *arg, ndr_xa_t *mxa)
1738 {
1739         struct samr_EnumDomainAliases *param = arg;
1740         ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
1741         ndr_handle_t *hd;
1742         samr_keydata_t *data;
1743         smb_group_t grp;
1744         smb_giter_t gi;
1745         int cnt, skip, i;
1746         struct name_rid *info;
1747 
1748         if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
1749                 bzero(param, sizeof (struct samr_EnumDomainAliases));
1750                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1751                 return (NDR_DRC_OK);
1752         }
1753 
1754         data = (samr_keydata_t *)hd->nh_data;
1755 
1756         cnt = smb_sam_grp_cnt(data->kd_type);
1757         if (cnt <= param->resume_handle) {
1758                 param->aliases = (struct aliases_info *)NDR_MALLOC(mxa,
1759                     sizeof (struct aliases_info));
1760 
1761                 if (param->aliases == NULL) {
1762                         bzero(param, sizeof (struct samr_EnumDomainAliases));
1763                         param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1764                         return (NDR_DRC_OK);
1765                 }
1766 
1767                 bzero(param->aliases, sizeof (struct aliases_info));
1768                 param->out_resume = 0;
1769                 param->entries = 0;
1770                 param->status = NT_STATUS_SUCCESS;
1771                 return (NDR_DRC_OK);
1772         }
1773 
1774         cnt -= param->resume_handle;
1775         param->aliases = (struct aliases_info *)NDR_MALLOC(mxa,
1776             sizeof (struct aliases_info) + (cnt-1) * sizeof (struct name_rid));
1777 
1778         if (param->aliases == NULL) {
1779                 bzero(param, sizeof (struct samr_EnumDomainAliases));
1780                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1781                 return (NDR_DRC_OK);
1782         }
1783 
1784         if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) {
1785                 bzero(param, sizeof (struct samr_EnumDomainAliases));
1786                 param->status = NT_SC_ERROR(NT_STATUS_INTERNAL_ERROR);
1787                 return (NDR_DRC_OK);
1788         }
1789 
1790         skip = i = 0;
1791         info = param->aliases->info;
1792         while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) {
1793                 if ((skip++ >= param->resume_handle) &&
1794                     (grp.sg_domain == data->kd_type) && (i++ < cnt)) {
1795                         info->rid = grp.sg_rid;
1796                         (void) NDR_MSTRING(mxa, grp.sg_name,
1797                             (ndr_mstring_t *)&info->name);
1798 
1799                         info++;
1800                 }
1801                 smb_lgrp_free(&grp);
1802         }
1803         smb_lgrp_iterclose(&gi);
1804 
1805         param->aliases->count = i;
1806         param->aliases->address = i;
1807 
1808         param->out_resume = i;
1809         param->entries = i;
1810         param->status = 0;
1811         return (NDR_DRC_OK);
1812 }
1813 
1814 /*
1815  * samr_s_Connect4
1816  */
1817 static int
1818 samr_s_Connect4(void *arg, ndr_xa_t *mxa)
1819 {
1820         struct samr_Connect4    *param = arg;
1821         ndr_hdid_t              *id;
1822 
1823         id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
1824         if (id) {
1825                 bcopy(id, &param->handle, sizeof (samr_handle_t));
1826                 param->status = 0;
1827         } else {
1828                 bzero(&param->handle, sizeof (samr_handle_t));
1829                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1830         }
1831 
1832         return (NDR_DRC_OK);
1833 }
1834 
1835 /*
1836  * samr_s_Connect5
1837  *
1838  * This is the connect5 form of the connect request used by Windows XP.
1839  * Returns an RPC fault for now.
1840  */
1841 /*ARGSUSED*/
1842 static int
1843 samr_s_Connect5(void *arg, ndr_xa_t *mxa)
1844 {
1845         struct samr_Connect5 *param = arg;
1846 
1847         bzero(param, sizeof (struct samr_Connect5));
1848         return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
1849 }
1850 
1851 static ndr_stub_table_t samr_stub_table[] = {
1852         { samr_s_Connect,               SAMR_OPNUM_Connect },
1853         { samr_s_CloseHandle,           SAMR_OPNUM_CloseHandle },
1854         { samr_s_LookupDomain,          SAMR_OPNUM_LookupDomain },
1855         { samr_s_EnumLocalDomains,      SAMR_OPNUM_EnumLocalDomains },
1856         { samr_s_OpenDomain,            SAMR_OPNUM_OpenDomain },
1857         { samr_s_QueryDomainInfo,       SAMR_OPNUM_QueryDomainInfo },
1858         { samr_s_QueryInfoDomain2,      SAMR_OPNUM_QueryInfoDomain2 },
1859         { samr_s_LookupNames,           SAMR_OPNUM_LookupNames },
1860         { samr_s_OpenUser,              SAMR_OPNUM_OpenUser },
1861         { samr_s_DeleteUser,            SAMR_OPNUM_DeleteUser },
1862         { samr_s_QueryUserInfo,         SAMR_OPNUM_QueryUserInfo },
1863         { samr_s_QueryUserGroups,       SAMR_OPNUM_QueryUserGroups },
1864         { samr_s_OpenGroup,             SAMR_OPNUM_OpenGroup },
1865         { samr_s_Connect2,              SAMR_OPNUM_Connect2 },
1866         { samr_s_GetUserPwInfo,         SAMR_OPNUM_GetUserPwInfo },
1867         { samr_s_CreateUser,            SAMR_OPNUM_CreateUser },
1868         { samr_s_ChangePasswordUser2,   SAMR_OPNUM_ChangePasswordUser2 },
1869         { samr_s_GetDomainPwInfo,       SAMR_OPNUM_GetDomainPwInfo },
1870         { samr_s_SetUserInfo,           SAMR_OPNUM_SetUserInfo },
1871         { samr_s_Connect4,              SAMR_OPNUM_Connect4 },
1872         { samr_s_Connect5,              SAMR_OPNUM_Connect5 },
1873         { samr_s_QueryDispInfo,         SAMR_OPNUM_QueryDispInfo },
1874         { samr_s_OpenAlias,             SAMR_OPNUM_OpenAlias },
1875         { samr_s_CreateDomainAlias,     SAMR_OPNUM_CreateDomainAlias },
1876         { samr_s_SetAliasInfo,          SAMR_OPNUM_SetAliasInfo },
1877         { samr_s_QueryAliasInfo,        SAMR_OPNUM_QueryAliasInfo },
1878         { samr_s_DeleteDomainAlias,     SAMR_OPNUM_DeleteDomainAlias },
1879         { samr_s_EnumDomainAliases,     SAMR_OPNUM_EnumDomainAliases },
1880         { samr_s_EnumDomainGroups,      SAMR_OPNUM_EnumDomainGroups },
1881         { samr_s_AddAliasMember,        SAMR_OPNUM_AddAliasMember },
1882         { samr_s_DeleteAliasMember,     SAMR_OPNUM_DeleteAliasMember },
1883         { samr_s_ListAliasMembers,      SAMR_OPNUM_ListAliasMembers },
1884         {0}
1885 };
1886 
1887 /*
1888  * There is a bug in the way that midl and the marshalling code handles
1889  * unions so we need to fix some of the data offsets at runtime. The
1890  * following macros and the fixup functions handle the corrections.
1891  */
1892 
1893 DECL_FIXUP_STRUCT(samr_QueryAliasInfo_ru);
1894 DECL_FIXUP_STRUCT(samr_QueryAliasInfoRes);
1895 DECL_FIXUP_STRUCT(samr_QueryAliasInfo);
1896 
1897 DECL_FIXUP_STRUCT(QueryUserInfo_result_u);
1898 DECL_FIXUP_STRUCT(QueryUserInfo_result);
1899 DECL_FIXUP_STRUCT(samr_QueryUserInfo);
1900 
1901 void
1902 fixup_samr_QueryAliasInfo(struct samr_QueryAliasInfo *val)
1903 {
1904         unsigned short size1 = 0;
1905         unsigned short size2 = 0;
1906         unsigned short size3 = 0;
1907 
1908         switch (val->level) {
1909         case SAMR_QUERY_ALIAS_INFO_GENERAL:
1910                 size1 = sizeof (struct samr_QueryAliasInfoGeneral);
1911                 break;
1912         case SAMR_QUERY_ALIAS_INFO_NAME:
1913                 size1 = sizeof (struct samr_QueryAliasInfoName);
1914                 break;
1915         case SAMR_QUERY_ALIAS_INFO_COMMENT:
1916                 size1 = sizeof (struct samr_QueryAliasInfoComment);
1917                 break;
1918 
1919         default:
1920                 return;
1921         };
1922 
1923         size2 = size1 + (2 * sizeof (DWORD));
1924         size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1925 
1926         FIXUP_PDU_SIZE(samr_QueryAliasInfo_ru, size1);
1927         FIXUP_PDU_SIZE(samr_QueryAliasInfoRes, size2);
1928         FIXUP_PDU_SIZE(samr_QueryAliasInfo, size3);
1929 }
1930 
1931 void
1932 fixup_samr_QueryUserInfo(struct samr_QueryUserInfo *val)
1933 {
1934         unsigned short size1 = 0;
1935         unsigned short size2 = 0;
1936         unsigned short size3 = 0;
1937 
1938         switch (val->switch_index) {
1939                 CASE_INFO_ENT(samr_QueryUserInfo, 1);
1940                 CASE_INFO_ENT(samr_QueryUserInfo, 6);
1941                 CASE_INFO_ENT(samr_QueryUserInfo, 7);
1942                 CASE_INFO_ENT(samr_QueryUserInfo, 8);
1943                 CASE_INFO_ENT(samr_QueryUserInfo, 9);
1944                 CASE_INFO_ENT(samr_QueryUserInfo, 16);
1945                 CASE_INFO_ENT(samr_QueryUserInfo, 21);
1946 
1947                 default:
1948                         return;
1949         };
1950 
1951         size2 = size1 + (2 * sizeof (DWORD));
1952         size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1953 
1954         FIXUP_PDU_SIZE(QueryUserInfo_result_u, size1);
1955         FIXUP_PDU_SIZE(QueryUserInfo_result, size2);
1956         FIXUP_PDU_SIZE(samr_QueryUserInfo, size3);
1957 }
1958 
1959 /*
1960  * As long as there is only one entry in the union, there is no need
1961  * to patch anything.
1962  */
1963 /*ARGSUSED*/
1964 void
1965 fixup_samr_QueryGroupInfo(struct samr_QueryGroupInfo *val)
1966 {
1967 }