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