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  * Local Security Authority RPC (LSAR) client-side interface.
  29  */
  30 
  31 #include <sys/errno.h>
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <strings.h>
  35 
  36 #include <smbsrv/libsmb.h>
  37 #include <smbsrv/libmlsvc.h>
  38 #include <smbsrv/smbinfo.h>
  39 #include <smbsrv/ntaccess.h>
  40 #include <smbsrv/ntlocale.h>
  41 #include <smbsrv/string.h>
  42 #include <lsalib.h>
  43 
  44 /*
  45  * The maximum number of bytes we are prepared to deal with in a
  46  * response.
  47  */
  48 #define MLSVC_MAX_RESPONSE_LEN          1024
  49 
  50 /*
  51  * This structure is used when looking up names. We only lookup one
  52  * name at a time but the structure will allow for more.
  53  */
  54 typedef struct lsa_names {
  55         uint32_t        n_entry;
  56         mslsa_string_t  name[8];
  57 } lsa_names_t;
  58 
  59 typedef DWORD (*lsar_nameop_t)(mlsvc_handle_t *, lsa_names_t *,
  60     smb_account_t *);
  61 
  62 static uint32_t lsar_lookup_names1(mlsvc_handle_t *, lsa_names_t *,
  63     smb_account_t *);
  64 static uint32_t lsar_lookup_names2(mlsvc_handle_t *, lsa_names_t *,
  65     smb_account_t *);
  66 static uint32_t lsar_lookup_names3(mlsvc_handle_t *, lsa_names_t *,
  67     smb_account_t *);
  68 static uint32_t lsar_lookup_sids1(mlsvc_handle_t *, lsa_sid_t *,
  69     smb_account_t *);
  70 static uint32_t lsar_lookup_sids2(mlsvc_handle_t *, lsa_sid_t *,
  71     smb_account_t *account);
  72 
  73 static char *lsar_get_username(const char *);
  74 static void smb_account_trace(const smb_account_t *);
  75 
  76 static void lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *,
  77     smb_trusted_domains_t *);
  78 static void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *,
  79     smb_trusted_domains_t *);
  80 
  81 /*
  82  * lsar_open
  83  *
  84  * This is a wrapper round lsar_open_policy2 to ensure that we connect
  85  * using the appropriate domain information.
  86  *
  87  * If username argument is NULL, an anonymous connection will be established.
  88  * Otherwise, an authenticated connection will be established.
  89  *
  90  * Returns 0 or NT status (Raw, not LSA-ized)
  91  */
  92 DWORD
  93 lsar_open(char *server, char *domain, char *username,
  94     mlsvc_handle_t *domain_handle)
  95 {
  96         DWORD status;
  97 
  98         if (server == NULL || domain == NULL)
  99                 return (NT_STATUS_INTERNAL_ERROR);
 100 
 101         if (username == NULL)
 102                 username = MLSVC_ANON_USER;
 103 
 104         status = lsar_open_policy2(server, domain, username, domain_handle);
 105 
 106         return (status);
 107 }
 108 
 109 /*
 110  * lsar_open_policy2
 111  *
 112  * Obtain an LSA policy handle. A policy handle is required to access
 113  * LSA resources on a remote server. The server name supplied here does
 114  * not need the double backslash prefix; it is added here. Call this
 115  * function via lsar_open to ensure that the appropriate connection is
 116  * in place.
 117  *
 118  * Returns 0 or NT status (Raw, not LSA-ized)
 119  */
 120 DWORD
 121 lsar_open_policy2(char *server, char *domain, char *user,
 122     mlsvc_handle_t *lsa_handle)
 123 {
 124         struct mslsa_OpenPolicy2 arg;
 125         DWORD status;
 126         int opnum;
 127         int len;
 128 
 129         status = ndr_rpc_bind(lsa_handle, server, domain, user, "LSARPC");
 130         if (status != 0)
 131                 return (status);
 132 
 133         opnum = LSARPC_OPNUM_OpenPolicy2;
 134         bzero(&arg, sizeof (struct mslsa_OpenPolicy2));
 135 
 136         len = strlen(server) + 4;
 137         arg.servername = ndr_rpc_malloc(lsa_handle, len);
 138         if (arg.servername == NULL) {
 139                 status = NT_STATUS_NO_MEMORY;
 140                 goto out;
 141         }
 142 
 143         (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
 144         arg.attributes.length = sizeof (struct mslsa_object_attributes);
 145         arg.desiredAccess = MAXIMUM_ALLOWED;
 146 
 147         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 148                 status = RPC_NT_CALL_FAILED;
 149                 goto out;
 150         }
 151         status = arg.status;
 152         if (status == NT_STATUS_SUCCESS) {
 153                 (void) memcpy(&lsa_handle->handle, &arg.domain_handle,
 154                     sizeof (ndr_hdid_t));
 155 
 156                 if (ndr_is_null_handle(lsa_handle))
 157                         status = NT_STATUS_INVALID_PARAMETER;
 158         }
 159 
 160         ndr_rpc_release(lsa_handle);
 161 
 162 out:
 163         if (status != NT_STATUS_SUCCESS)
 164                 ndr_rpc_unbind(lsa_handle);
 165         return (status);
 166 }
 167 
 168 /*
 169  * lsar_open_account
 170  *
 171  * Obtain an LSA account handle. The lsa_handle must be a valid handle
 172  * obtained via lsar_open_policy2. The main thing to remember here is
 173  * to set up the context in the lsa_account_handle. I'm not sure what
 174  * the requirements are for desired access. Some values require admin
 175  * access.
 176  *
 177  * Returns 0 on success. Otherwise non-zero to indicate a failure.
 178  */
 179 int
 180 lsar_open_account(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
 181     mlsvc_handle_t *lsa_account_handle)
 182 {
 183         struct mslsa_OpenAccount arg;
 184         int opnum;
 185         int rc;
 186 
 187         if (ndr_is_null_handle(lsa_handle) || sid == NULL)
 188                 return (-1);
 189 
 190         opnum = LSARPC_OPNUM_OpenAccount;
 191         bzero(&arg, sizeof (struct mslsa_OpenAccount));
 192 
 193         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 194         arg.sid = sid;
 195         arg.access_mask = STANDARD_RIGHTS_REQUIRED
 196 #if 0
 197             | POLICY_VIEW_AUDIT_INFORMATION
 198             | POLICY_GET_PRIVATE_INFORMATION
 199             | POLICY_TRUST_ADMIN
 200 #endif
 201             | POLICY_VIEW_LOCAL_INFORMATION;
 202 
 203         if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0)
 204                 return (-1);
 205 
 206         if (arg.status != 0) {
 207                 rc = -1;
 208         } else {
 209                 ndr_inherit_handle(lsa_account_handle, lsa_handle);
 210 
 211                 (void) memcpy(&lsa_account_handle->handle,
 212                     &arg.account_handle, sizeof (ndr_hdid_t));
 213 
 214                 if (ndr_is_null_handle(lsa_account_handle))
 215                         rc = -1;
 216         }
 217 
 218         ndr_rpc_release(lsa_handle);
 219         return (rc);
 220 }
 221 
 222 /*
 223  * lsar_close
 224  *
 225  * Close the LSA connection associated with the handle. The lsa_handle
 226  * must be a valid handle obtained via a call to lsar_open_policy2 or
 227  * lsar_open_account. On success the handle will be zeroed out to
 228  * ensure that it is not used again. If this is the top level handle
 229  * (i.e. the one obtained via lsar_open_policy2) the pipe is closed.
 230  *
 231  * Returns 0 on success. Otherwise non-zero to indicate a failure.
 232  */
 233 int
 234 lsar_close(mlsvc_handle_t *lsa_handle)
 235 {
 236         struct mslsa_CloseHandle arg;
 237         int opnum;
 238 
 239         if (ndr_is_null_handle(lsa_handle))
 240                 return (-1);
 241 
 242         opnum = LSARPC_OPNUM_CloseHandle;
 243         bzero(&arg, sizeof (struct mslsa_CloseHandle));
 244         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 245 
 246         (void) ndr_rpc_call(lsa_handle, opnum, &arg);
 247         ndr_rpc_release(lsa_handle);
 248 
 249         if (ndr_is_bind_handle(lsa_handle))
 250                 ndr_rpc_unbind(lsa_handle);
 251 
 252         bzero(lsa_handle, sizeof (mlsvc_handle_t));
 253         return (0);
 254 }
 255 
 256 /*
 257  * lsar_query_security_desc
 258  *
 259  * Don't use this call yet. It is just a place holder for now.
 260  */
 261 int
 262 lsar_query_security_desc(mlsvc_handle_t *lsa_handle)
 263 {
 264         struct mslsa_QuerySecurityObject        arg;
 265         int     rc;
 266         int     opnum;
 267 
 268         opnum = LSARPC_OPNUM_QuerySecurityObject;
 269 
 270         bzero(&arg, sizeof (struct mslsa_QuerySecurityObject));
 271         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 272 
 273         rc = ndr_rpc_call(lsa_handle, opnum, &arg);
 274         ndr_rpc_release(lsa_handle);
 275         return (rc);
 276 }
 277 
 278 /*
 279  * lsar_query_info_policy
 280  *
 281  * The general purpose of this function is to allow various pieces of
 282  * information to be queried on the domain controller. The only
 283  * information queries supported are MSLSA_POLICY_PRIMARY_DOMAIN_INFO
 284  * and MSLSA_POLICY_ACCOUNT_DOMAIN_INFO.
 285  *
 286  * On success, the return code will be 0 and the user_info structure
 287  * will be set up. The sid_name_use field will be set to SidTypeDomain
 288  * indicating that the domain name and domain sid fields are vaild. If
 289  * the infoClass returned from the server is not one of the supported
 290  * values, the sid_name_use willbe set to SidTypeUnknown. If the RPC
 291  * fails, a negative error code will be returned, in which case the
 292  * user_info will not have been updated.
 293  */
 294 DWORD
 295 lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass,
 296     smb_domain_t *info)
 297 {
 298         struct mslsa_QueryInfoPolicy    arg;
 299         struct mslsa_PrimaryDomainInfo  *pd_info;
 300         struct mslsa_AccountDomainInfo  *ad_info;
 301         struct mslsa_DnsDomainInfo      *dns_info;
 302         char    guid_str[UUID_PRINTABLE_STRING_LENGTH];
 303         char    sidstr[SMB_SID_STRSZ];
 304         int     opnum;
 305         DWORD   status;
 306 
 307         if (lsa_handle == NULL || info == NULL)
 308                 return (NT_STATUS_INVALID_PARAMETER);
 309 
 310         opnum = LSARPC_OPNUM_QueryInfoPolicy;
 311 
 312         bzero(info, sizeof (smb_domain_t));
 313         bzero(&arg, sizeof (struct mslsa_QueryInfoPolicy));
 314         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 315 
 316         arg.info_class = infoClass;
 317 
 318         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 319                 status = NT_STATUS_INVALID_PARAMETER;
 320         } else if (arg.status != 0) {
 321                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 322                 status = NT_SC_VALUE(arg.status);
 323         } else {
 324 
 325                 switch (infoClass) {
 326                 case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
 327                         pd_info = &arg.ru.pd_info;
 328 
 329                         smb_sid_tostr((smb_sid_t *)pd_info->sid, sidstr);
 330                         info->di_type = SMB_DOMAIN_PRIMARY;
 331                         smb_domain_set_basic_info(sidstr,
 332                             (char *)pd_info->name.str, "", info);
 333 
 334                         status = NT_STATUS_SUCCESS;
 335                         break;
 336 
 337                 case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
 338                         ad_info = &arg.ru.ad_info;
 339 
 340                         smb_sid_tostr((smb_sid_t *)ad_info->sid, sidstr);
 341                         info->di_type = SMB_DOMAIN_ACCOUNT;
 342                         smb_domain_set_basic_info(sidstr,
 343                             (char *)ad_info->name.str, "", info);
 344 
 345                         status = NT_STATUS_SUCCESS;
 346                         break;
 347 
 348                 case MSLSA_POLICY_DNS_DOMAIN_INFO:
 349                         dns_info = &arg.ru.dns_info;
 350                         ndr_uuid_unparse((ndr_uuid_t *)&dns_info->guid,
 351                             guid_str);
 352                         smb_sid_tostr((smb_sid_t *)dns_info->sid, sidstr);
 353 
 354                         info->di_type = SMB_DOMAIN_PRIMARY;
 355                         smb_domain_set_dns_info(sidstr,
 356                             (char *)dns_info->nb_domain.str,
 357                             (char *)dns_info->dns_domain.str,
 358                             (char *)dns_info->forest.str,
 359                             guid_str, info);
 360                         status = NT_STATUS_SUCCESS;
 361                         break;
 362 
 363                 default:
 364                         status = NT_STATUS_INVALID_INFO_CLASS;
 365                         break;
 366                 }
 367         }
 368 
 369         ndr_rpc_release(lsa_handle);
 370         return (status);
 371 }
 372 
 373 /*
 374  * Lookup a name and obtain the sid/rid.
 375  * This is a wrapper for the various lookup sid RPCs.
 376  */
 377 uint32_t
 378 lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info)
 379 {
 380         static lsar_nameop_t ops[] = {
 381                 lsar_lookup_names3,
 382                 lsar_lookup_names2,
 383                 lsar_lookup_names1
 384         };
 385 
 386         const srvsvc_server_info_t      *svinfo;
 387         lsa_names_t     names;
 388         char            *p;
 389         uint32_t        length;
 390         uint32_t        status = NT_STATUS_INVALID_PARAMETER;
 391         int             n_op = (sizeof (ops) / sizeof (ops[0]));
 392         int             i;
 393 
 394         if (lsa_handle == NULL || name == NULL || info == NULL)
 395                 return (NT_STATUS_INVALID_PARAMETER);
 396 
 397         bzero(info, sizeof (smb_account_t));
 398 
 399         svinfo = ndr_rpc_server_info(lsa_handle);
 400         if (svinfo->sv_os == NATIVE_OS_WIN2000 &&
 401             svinfo->sv_version_major == 5 && svinfo->sv_version_minor == 0) {
 402                 /*
 403                  * Windows 2000 doesn't like an LSA lookup for
 404                  * DOMAIN\Administrator.
 405                  */
 406                 if ((p = strchr(name, '\\')) != 0) {
 407                         ++p;
 408 
 409                         if (strcasecmp(p, "administrator") == 0)
 410                                 name = p;
 411                 }
 412 
 413         }
 414 
 415         length = smb_wcequiv_strlen(name);
 416         names.name[0].length = length;
 417         names.name[0].allosize = length;
 418         names.name[0].str = (unsigned char *)name;
 419         names.n_entry = 1;
 420 
 421         if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) {
 422                 for (i = 0; i < n_op; ++i) {
 423                         ndr_rpc_set_nonull(lsa_handle);
 424                         status = (*ops[i])(lsa_handle, &names, info);
 425 
 426                         if (status != NT_STATUS_INVALID_PARAMETER)
 427                                 break;
 428                 }
 429         } else {
 430                 ndr_rpc_set_nonull(lsa_handle);
 431                 status = lsar_lookup_names1(lsa_handle, &names, info);
 432         }
 433 
 434         if (status == NT_STATUS_SUCCESS) {
 435                 info->a_name = lsar_get_username(name);
 436 
 437                 if (!smb_account_validate(info)) {
 438                         smb_account_free(info);
 439                         status = NT_STATUS_NO_MEMORY;
 440                 } else {
 441                         smb_account_trace(info);
 442                 }
 443         }
 444 
 445         return (status);
 446 }
 447 
 448 /*
 449  * The name may be in one of the following forms:
 450  *
 451  *      domain\username
 452  *      domain/username
 453  *      username
 454  *      username@domain
 455  *
 456  * Return a strdup'd copy of the username.  The caller is responsible
 457  * for freeing the allocated memory.
 458  */
 459 static char *
 460 lsar_get_username(const char *name)
 461 {
 462         char    tmp[MAXNAMELEN];
 463         char    *dp = NULL;
 464         char    *np = NULL;
 465 
 466         (void) strlcpy(tmp, name, MAXNAMELEN);
 467         smb_name_parse(tmp, &np, &dp);
 468 
 469         if (dp != NULL && np != NULL)
 470                 return (strdup(np));
 471         else
 472                 return (strdup(name));
 473 }
 474 
 475 /*
 476  * lsar_lookup_names1
 477  *
 478  * Lookup a name and obtain the domain and user rid.
 479  *
 480  * Note: NT returns an error if the mapped_count is non-zero when the RPC
 481  * is called.
 482  *
 483  * If the lookup fails, the status will typically be NT_STATUS_NONE_MAPPED.
 484  */
 485 static uint32_t
 486 lsar_lookup_names1(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
 487     smb_account_t *info)
 488 {
 489         struct mslsa_LookupNames        arg;
 490         struct mslsa_rid_entry          *rid_entry;
 491         struct mslsa_domain_entry       *domain_entry;
 492         uint32_t                        status = NT_STATUS_SUCCESS;
 493         char                            *domname;
 494         int                             opnum = LSARPC_OPNUM_LookupNames;
 495 
 496         bzero(&arg, sizeof (struct mslsa_LookupNames));
 497         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 498         arg.lookup_level = LSA_LOOKUP_WKSTA;
 499         arg.name_table = (struct mslsa_lup_name_table *)names;
 500 
 501         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 502                 ndr_rpc_release(lsa_handle);
 503                 return (NT_STATUS_INVALID_PARAMETER);
 504         }
 505 
 506         if (arg.status != NT_STATUS_SUCCESS) {
 507                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 508                 ndr_rpc_release(lsa_handle);
 509                 return (NT_SC_VALUE(arg.status));
 510         }
 511 
 512         if (arg.mapped_count == 0) {
 513                 ndr_rpc_release(lsa_handle);
 514                 return (NT_STATUS_NONE_MAPPED);
 515         }
 516 
 517         rid_entry = &arg.translated_sids.rids[0];
 518         if (rid_entry->domain_index != 0) {
 519                 ndr_rpc_release(lsa_handle);
 520                 return (NT_STATUS_NONE_MAPPED);
 521         }
 522 
 523         domain_entry = &arg.domain_table->entries[0];
 524 
 525         info->a_type = rid_entry->sid_name_use;
 526         info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 527         if ((domname = (char *)domain_entry->domain_name.str) != NULL)
 528                 info->a_domain = strdup(domname);
 529         info->a_rid = rid_entry->rid;
 530         info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
 531 
 532         ndr_rpc_release(lsa_handle);
 533         return (status);
 534 }
 535 
 536 /*
 537  * lsar_lookup_names2
 538  */
 539 static uint32_t
 540 lsar_lookup_names2(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
 541     smb_account_t *info)
 542 {
 543         struct lsar_LookupNames2        arg;
 544         struct lsar_rid_entry2          *rid_entry;
 545         struct mslsa_domain_entry       *domain_entry;
 546         uint32_t                        status = NT_STATUS_SUCCESS;
 547         char                            *domname;
 548         int                             opnum = LSARPC_OPNUM_LookupNames2;
 549 
 550         bzero(&arg, sizeof (struct lsar_LookupNames2));
 551         (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
 552         arg.lookup_level = LSA_LOOKUP_WKSTA;
 553         arg.client_revision = LSA_CLIENT_REVISION_AD;
 554         arg.name_table = (struct mslsa_lup_name_table *)names;
 555 
 556         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 557                 ndr_rpc_release(lsa_handle);
 558                 return (NT_STATUS_INVALID_PARAMETER);
 559         }
 560 
 561         if (arg.status != NT_STATUS_SUCCESS) {
 562                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 563                 ndr_rpc_release(lsa_handle);
 564                 return (NT_SC_VALUE(arg.status));
 565         }
 566 
 567         if (arg.mapped_count == 0) {
 568                 ndr_rpc_release(lsa_handle);
 569                 return (NT_STATUS_NONE_MAPPED);
 570         }
 571 
 572         rid_entry = &arg.translated_sids.rids[0];
 573         if (rid_entry->domain_index != 0) {
 574                 ndr_rpc_release(lsa_handle);
 575                 return (NT_STATUS_NONE_MAPPED);
 576         }
 577 
 578         domain_entry = &arg.domain_table->entries[0];
 579 
 580         info->a_type = rid_entry->sid_name_use;
 581         info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 582         if ((domname = (char *)domain_entry->domain_name.str) != NULL)
 583                 info->a_domain = strdup(domname);
 584         info->a_rid = rid_entry->rid;
 585         info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
 586 
 587         ndr_rpc_release(lsa_handle);
 588         return (status);
 589 }
 590 
 591 /*
 592  * lsar_lookup_names3
 593  */
 594 static uint32_t
 595 lsar_lookup_names3(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
 596     smb_account_t *info)
 597 {
 598         struct lsar_LookupNames3        arg;
 599         lsar_translated_sid_ex2_t       *sid_entry;
 600         struct mslsa_domain_entry       *domain_entry;
 601         uint32_t                        status = NT_STATUS_SUCCESS;
 602         char                            *domname;
 603         int                             opnum = LSARPC_OPNUM_LookupNames3;
 604 
 605         bzero(&arg, sizeof (struct lsar_LookupNames3));
 606         (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
 607         arg.lookup_level = LSA_LOOKUP_WKSTA;
 608         arg.client_revision = LSA_CLIENT_REVISION_AD;
 609         arg.name_table = (struct mslsa_lup_name_table *)names;
 610 
 611         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 612                 ndr_rpc_release(lsa_handle);
 613                 return (NT_STATUS_INVALID_PARAMETER);
 614         }
 615 
 616         if (arg.status != NT_STATUS_SUCCESS) {
 617                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 618                 ndr_rpc_release(lsa_handle);
 619                 return (NT_SC_VALUE(arg.status));
 620         }
 621 
 622         if (arg.mapped_count == 0) {
 623                 ndr_rpc_release(lsa_handle);
 624                 return (NT_STATUS_NONE_MAPPED);
 625         }
 626 
 627         sid_entry = &arg.translated_sids.sids[0];
 628         if (sid_entry->domain_index != 0) {
 629                 ndr_rpc_release(lsa_handle);
 630                 return (NT_STATUS_NONE_MAPPED);
 631         }
 632 
 633         domain_entry = &arg.domain_table->entries[0];
 634 
 635         info->a_type = sid_entry->sid_name_use;
 636         info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 637         if ((domname = (char *)domain_entry->domain_name.str) != NULL)
 638                 info->a_domain = strdup(domname);
 639         info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
 640         (void) smb_sid_getrid(info->a_sid, &info->a_rid);
 641 
 642         ndr_rpc_release(lsa_handle);
 643         return (status);
 644 }
 645 
 646 /*
 647  * lsar_lookup_names4
 648  *
 649  * This function is only valid if the remote RPC server is a domain
 650  * controller and requires the security extensions defined in MS-RPCE.
 651  *
 652  * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
 653  * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
 654  * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
 655  */
 656 static uint32_t /*LINTED E_STATIC_UNUSED*/
 657 lsar_lookup_names4(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
 658     smb_account_t *info)
 659 {
 660         struct lsar_LookupNames4        arg;
 661         lsar_translated_sid_ex2_t       *sid_entry;
 662         struct mslsa_domain_entry       *domain_entry;
 663         uint32_t                        status = NT_STATUS_SUCCESS;
 664         char                            *domname;
 665         int                             opnum = LSARPC_OPNUM_LookupNames4;
 666 
 667         bzero(&arg, sizeof (struct lsar_LookupNames4));
 668         arg.lookup_level = LSA_LOOKUP_WKSTA;
 669         arg.client_revision = LSA_CLIENT_REVISION_AD;
 670         arg.name_table = (struct mslsa_lup_name_table *)names;
 671 
 672         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 673                 ndr_rpc_release(lsa_handle);
 674                 return (NT_STATUS_INVALID_PARAMETER);
 675         }
 676 
 677         if (arg.status != NT_STATUS_SUCCESS) {
 678                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 679                 ndr_rpc_release(lsa_handle);
 680                 if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
 681                     arg.status == NT_STATUS_INVALID_SERVER_STATE)
 682                         return (NT_STATUS_INVALID_PARAMETER);
 683                 return (NT_SC_VALUE(arg.status));
 684         }
 685 
 686         if (arg.mapped_count == 0) {
 687                 ndr_rpc_release(lsa_handle);
 688                 return (NT_STATUS_NONE_MAPPED);
 689         }
 690 
 691         sid_entry = &arg.translated_sids.sids[0];
 692         if (sid_entry->domain_index != 0) {
 693                 ndr_rpc_release(lsa_handle);
 694                 return (NT_STATUS_NONE_MAPPED);
 695         }
 696 
 697         domain_entry = &arg.domain_table->entries[0];
 698 
 699         info->a_type = sid_entry->sid_name_use;
 700         info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 701         if ((domname = (char *)domain_entry->domain_name.str) != NULL)
 702                 info->a_domain = strdup(domname);
 703         info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
 704         (void) smb_sid_getrid(info->a_sid, &info->a_rid);
 705 
 706         ndr_rpc_release(lsa_handle);
 707         return (status);
 708 }
 709 
 710 /*
 711  * Lookup a sid and obtain the domain sid and account name.
 712  * This is a wrapper for the various lookup sid RPCs.
 713  */
 714 uint32_t
 715 lsar_lookup_sids(mlsvc_handle_t *lsa_handle, smb_sid_t *sid,
 716     smb_account_t *account)
 717 {
 718         char            sidbuf[SMB_SID_STRSZ];
 719         uint32_t        status;
 720 
 721         if (lsa_handle == NULL || sid == NULL || account == NULL)
 722                 return (NT_STATUS_INVALID_PARAMETER);
 723 
 724         bzero(account, sizeof (smb_account_t));
 725         bzero(sidbuf, SMB_SID_STRSZ);
 726         smb_sid_tostr(sid, sidbuf);
 727         smb_tracef("%s", sidbuf);
 728 
 729         if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000)
 730                 status = lsar_lookup_sids2(lsa_handle, (lsa_sid_t *)sid,
 731                     account);
 732         else
 733                 status = lsar_lookup_sids1(lsa_handle, (lsa_sid_t *)sid,
 734                     account);
 735 
 736         if (status == NT_STATUS_SUCCESS) {
 737                 if (!smb_account_validate(account)) {
 738                         smb_account_free(account);
 739                         status = NT_STATUS_NO_MEMORY;
 740                 } else {
 741                         smb_account_trace(account);
 742                 }
 743         }
 744 
 745         return (status);
 746 }
 747 
 748 /*
 749  * lsar_lookup_sids1
 750  */
 751 static uint32_t
 752 lsar_lookup_sids1(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
 753     smb_account_t *account)
 754 {
 755         struct mslsa_LookupSids         arg;
 756         struct mslsa_lup_sid_entry      sid_entry;
 757         struct mslsa_name_entry         *name_entry;
 758         struct mslsa_domain_entry       *domain_entry;
 759         uint32_t                        status = NT_STATUS_SUCCESS;
 760         char                            *name;
 761         int                             opnum = LSARPC_OPNUM_LookupSids;
 762 
 763         bzero(&arg, sizeof (struct mslsa_LookupSids));
 764         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 765         arg.lookup_level = LSA_LOOKUP_WKSTA;
 766 
 767         sid_entry.psid = sid;
 768         arg.lup_sid_table.n_entry = 1;
 769         arg.lup_sid_table.entries = &sid_entry;
 770 
 771         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 772                 ndr_rpc_release(lsa_handle);
 773                 return (NT_STATUS_INVALID_PARAMETER);
 774         }
 775 
 776         if (arg.status != NT_STATUS_SUCCESS) {
 777                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 778                 ndr_rpc_release(lsa_handle);
 779                 return (NT_SC_VALUE(arg.status));
 780         }
 781 
 782         if (arg.mapped_count == 0) {
 783                 ndr_rpc_release(lsa_handle);
 784                 return (NT_STATUS_NONE_MAPPED);
 785         }
 786 
 787         name_entry = &arg.name_table.entries[0];
 788         if (name_entry->domain_ix != 0) {
 789                 ndr_rpc_release(lsa_handle);
 790                 return (NT_STATUS_NONE_MAPPED);
 791         }
 792 
 793         name = (char *)name_entry->name.str;
 794         account->a_name = (name) ? strdup(name) : strdup("");
 795         account->a_type = name_entry->sid_name_use;
 796         account->a_sid = smb_sid_dup((smb_sid_t *)sid);
 797         (void) smb_sid_getrid(account->a_sid, &account->a_rid);
 798 
 799         domain_entry = &arg.domain_table->entries[0];
 800         if ((name = (char *)domain_entry->domain_name.str) != NULL)
 801                 account->a_domain = strdup(name);
 802         account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 803 
 804         ndr_rpc_release(lsa_handle);
 805         return (status);
 806 }
 807 
 808 /*
 809  * lsar_lookup_sids2
 810  */
 811 static uint32_t
 812 lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
 813     smb_account_t *account)
 814 {
 815         struct lsar_lookup_sids2        arg;
 816         struct lsar_name_entry2         *name_entry;
 817         struct mslsa_lup_sid_entry      sid_entry;
 818         struct mslsa_domain_entry       *domain_entry;
 819         uint32_t                        status = NT_STATUS_SUCCESS;
 820         char                            *name;
 821         int                             opnum = LSARPC_OPNUM_LookupSids2;
 822 
 823         bzero(&arg, sizeof (struct lsar_lookup_sids2));
 824         (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
 825 
 826         sid_entry.psid = sid;
 827         arg.lup_sid_table.n_entry = 1;
 828         arg.lup_sid_table.entries = &sid_entry;
 829         arg.lookup_level = LSA_LOOKUP_WKSTA;
 830         arg.client_revision = LSA_CLIENT_REVISION_AD;
 831 
 832         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 833                 ndr_rpc_release(lsa_handle);
 834                 return (NT_STATUS_INVALID_PARAMETER);
 835         }
 836 
 837         if (arg.status != NT_STATUS_SUCCESS) {
 838                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 839                 ndr_rpc_release(lsa_handle);
 840                 return (NT_SC_VALUE(arg.status));
 841         }
 842 
 843         if (arg.mapped_count == 0) {
 844                 ndr_rpc_release(lsa_handle);
 845                 return (NT_STATUS_NONE_MAPPED);
 846         }
 847 
 848         name_entry = &arg.name_table.entries[0];
 849         if (name_entry->domain_ix != 0) {
 850                 ndr_rpc_release(lsa_handle);
 851                 return (NT_STATUS_NONE_MAPPED);
 852         }
 853 
 854         name = (char *)name_entry->name.str;
 855         account->a_name = (name) ? strdup(name) : strdup("");
 856         account->a_type = name_entry->sid_name_use;
 857         account->a_sid = smb_sid_dup((smb_sid_t *)sid);
 858         (void) smb_sid_getrid(account->a_sid, &account->a_rid);
 859 
 860         domain_entry = &arg.domain_table->entries[0];
 861         if ((name = (char *)domain_entry->domain_name.str) != NULL)
 862                 account->a_domain = strdup(name);
 863         account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 864 
 865         ndr_rpc_release(lsa_handle);
 866         return (status);
 867 }
 868 
 869 /*
 870  * lsar_lookup_sids3
 871  *
 872  * This function is only valid if the remote RPC server is a domain
 873  * controller and requires the security extensions defined in MS-RPCE.
 874  *
 875  * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
 876  * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
 877  * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
 878  */
 879 static uint32_t /*LINTED E_STATIC_UNUSED*/
 880 lsar_lookup_sids3(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
 881     smb_account_t *account)
 882 {
 883         struct lsar_lookup_sids3        arg;
 884         lsar_translated_name_ex_t       *name_entry;
 885         struct mslsa_lup_sid_entry      sid_entry;
 886         struct mslsa_domain_entry       *domain_entry;
 887         uint32_t                        status = NT_STATUS_SUCCESS;
 888         char                            *name;
 889         int                             opnum = LSARPC_OPNUM_LookupSids3;
 890 
 891         bzero(&arg, sizeof (struct lsar_lookup_sids3));
 892 
 893         sid_entry.psid = sid;
 894         arg.lup_sid_table.n_entry = 1;
 895         arg.lup_sid_table.entries = &sid_entry;
 896         arg.lookup_level = LSA_LOOKUP_WKSTA;
 897         arg.client_revision = LSA_CLIENT_REVISION_AD;
 898 
 899         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
 900                 ndr_rpc_release(lsa_handle);
 901                 return (NT_STATUS_INVALID_PARAMETER);
 902         }
 903 
 904         if (arg.status != NT_STATUS_SUCCESS) {
 905                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 906                 ndr_rpc_release(lsa_handle);
 907                 if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
 908                     arg.status == NT_STATUS_INVALID_SERVER_STATE)
 909                         return (NT_STATUS_INVALID_PARAMETER);
 910                 return (NT_SC_VALUE(arg.status));
 911         }
 912 
 913         if (arg.mapped_count == 0) {
 914                 ndr_rpc_release(lsa_handle);
 915                 return (NT_STATUS_NONE_MAPPED);
 916         }
 917 
 918         name_entry = &arg.name_table.entries[0];
 919         if (name_entry->domain_ix != 0) {
 920                 ndr_rpc_release(lsa_handle);
 921                 return (NT_STATUS_NONE_MAPPED);
 922         }
 923 
 924         name = (char *)name_entry->name.str;
 925         account->a_name = (name) ? strdup(name) : strdup("");
 926         account->a_type = name_entry->sid_name_use;
 927         account->a_sid = smb_sid_dup((smb_sid_t *)sid);
 928         (void) smb_sid_getrid(account->a_sid, &account->a_rid);
 929 
 930         domain_entry = &arg.domain_table->entries[0];
 931         if ((name = (char *)domain_entry->domain_name.str) != NULL)
 932                 account->a_domain = strdup(name);
 933         account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 934 
 935         ndr_rpc_release(lsa_handle);
 936         return (status);
 937 }
 938 
 939 /*
 940  * lsar_enum_accounts
 941  *
 942  * Enumerate the list of accounts (i.e. SIDs). Use the handle returned
 943  * from lsa_open_policy2. The enum_context is used to support multiple
 944  * calls to this enumeration function. It should be set to 0 on the
 945  * first call. It will be updated by the domain controller and should
 946  * simply be passed unchanged to subsequent calls until there are no
 947  * more accounts. A warning status of 0x1A indicates that no more data
 948  * is available. The list of accounts will be returned in accounts.
 949  * This list is dynamically allocated using malloc, it should be freed
 950  * by the caller when it is no longer required.
 951  */
 952 DWORD
 953 lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
 954     struct mslsa_EnumAccountBuf *accounts)
 955 {
 956         struct mslsa_EnumerateAccounts  arg;
 957         struct mslsa_AccountInfo        *info;
 958         int     opnum;
 959         int     rc;
 960         DWORD   status;
 961         DWORD   n_entries;
 962         DWORD   i;
 963         int     nbytes;
 964 
 965         if (lsa_handle == NULL || enum_context == NULL || accounts == NULL)
 966                 return (NT_STATUS_INTERNAL_ERROR);
 967 
 968         accounts->entries_read = 0;
 969         accounts->info = 0;
 970 
 971         opnum = LSARPC_OPNUM_EnumerateAccounts;
 972 
 973         bzero(&arg, sizeof (struct mslsa_EnumerateAccounts));
 974         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 975         arg.enum_context = *enum_context;
 976         arg.max_length = MLSVC_MAX_RESPONSE_LEN;
 977 
 978         rc = ndr_rpc_call(lsa_handle, opnum, &arg);
 979         if (rc == 0) {
 980                 status = arg.status;
 981                 if (arg.status != 0) {
 982                         if (arg.status == NT_STATUS_NO_MORE_ENTRIES) {
 983                                 *enum_context = arg.enum_context;
 984                         } else {
 985                                 ndr_rpc_status(lsa_handle, opnum, arg.status);
 986                         }
 987                 } else if (arg.enum_buf->entries_read != 0) {
 988                         n_entries = arg.enum_buf->entries_read;
 989                         nbytes = n_entries * sizeof (struct mslsa_AccountInfo);
 990 
 991                         if ((info = malloc(nbytes)) == NULL) {
 992                                 ndr_rpc_release(lsa_handle);
 993                                 return (NT_STATUS_NO_MEMORY);
 994                         }
 995 
 996                         for (i = 0; i < n_entries; ++i)
 997                                 info[i].sid = (lsa_sid_t *)smb_sid_dup(
 998                                     (smb_sid_t *)arg.enum_buf->info[i].sid);
 999 
1000                         accounts->entries_read = n_entries;
1001                         accounts->info = info;
1002                         *enum_context = arg.enum_context;
1003                 }
1004         } else {
1005                 status = NT_STATUS_INVALID_PARAMETER;
1006         }
1007 
1008         ndr_rpc_release(lsa_handle);
1009         return (status);
1010 }
1011 
1012 /*
1013  * lsar_enum_trusted_domains
1014  *
1015  * Enumerate the list of trusted domains. Use the handle returned from
1016  * lsa_open_policy2. The enum_context is used to support multiple calls
1017  * to this enumeration function. It should be set to 0 on the first
1018  * call. It will be updated by the domain controller and should simply
1019  * be passed unchanged to subsequent calls until there are no more
1020  * domains.
1021  *
1022  * The trusted domains aren't actually returned here. They are added
1023  * to the NT domain database. After all of the trusted domains have
1024  * been discovered, the database can be interrogated to find all of
1025  * the trusted domains.
1026  */
1027 DWORD
1028 lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
1029     smb_trusted_domains_t *list)
1030 {
1031         struct mslsa_EnumTrustedDomain  arg;
1032         int     opnum;
1033         DWORD   status;
1034 
1035         if (list == NULL)
1036                 return (NT_STATUS_INVALID_PARAMETER);
1037 
1038         opnum = LSARPC_OPNUM_EnumTrustedDomain;
1039 
1040         bzero(list, sizeof (smb_trusted_domains_t));
1041         bzero(&arg, sizeof (struct mslsa_EnumTrustedDomain));
1042         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1043         arg.enum_context = *enum_context;
1044         arg.max_length = MLSVC_MAX_RESPONSE_LEN;
1045 
1046         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
1047                 status = NT_STATUS_INVALID_PARAMETER;
1048         } else if (arg.status != 0) {
1049                 *enum_context = arg.enum_context;
1050                 status = NT_SC_VALUE(arg.status);
1051 
1052                 /*
1053                  * STATUS_NO_MORE_ENTRIES provides call
1054                  * status but does not indicate an error.
1055                  */
1056                 if (status != NT_STATUS_NO_MORE_ENTRIES)
1057                         ndr_rpc_status(lsa_handle, opnum, arg.status);
1058         } else if (arg.enum_buf->entries_read == 0) {
1059                 *enum_context = arg.enum_context;
1060                 status = 0;
1061         } else {
1062                 lsar_set_trusted_domains(arg.enum_buf, list);
1063                 *enum_context = arg.enum_context;
1064                 status = 0;
1065         }
1066 
1067         ndr_rpc_release(lsa_handle);
1068         return (status);
1069 }
1070 
1071 DWORD
1072 lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
1073     smb_trusted_domains_t *list)
1074 {
1075         struct mslsa_EnumTrustedDomainEx        arg;
1076         int     opnum;
1077         DWORD   status;
1078 
1079         if (list == NULL)
1080                 return (NT_STATUS_INVALID_PARAMETER);
1081 
1082         opnum = LSARPC_OPNUM_EnumTrustedDomainsEx;
1083 
1084         bzero(list, sizeof (smb_trusted_domains_t));
1085         bzero(&arg, sizeof (struct mslsa_EnumTrustedDomainEx));
1086         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1087         arg.enum_context = *enum_context;
1088         arg.max_length = MLSVC_MAX_RESPONSE_LEN;
1089 
1090         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
1091                 status = NT_STATUS_INVALID_PARAMETER;
1092         } else if (arg.status != 0) {
1093                 *enum_context = arg.enum_context;
1094                 status = NT_SC_VALUE(arg.status);
1095 
1096                 /*
1097                  * STATUS_NO_MORE_ENTRIES provides call
1098                  * status but does not indicate an error.
1099                  */
1100                 if (status != NT_STATUS_NO_MORE_ENTRIES)
1101                         ndr_rpc_status(lsa_handle, opnum, arg.status);
1102         } else if (arg.enum_buf->entries_read == 0) {
1103                 *enum_context = arg.enum_context;
1104                 status = 0;
1105         } else {
1106                 lsar_set_trusted_domains_ex(arg.enum_buf, list);
1107                 *enum_context = arg.enum_context;
1108                 status = 0;
1109         }
1110 
1111         ndr_rpc_release(lsa_handle);
1112         return (status);
1113 }
1114 
1115 /*
1116  * lsar_enum_privs_account
1117  *
1118  * Privileges enum? Need an account handle.
1119  */
1120 /*ARGSUSED*/
1121 int
1122 lsar_enum_privs_account(mlsvc_handle_t *account_handle, smb_account_t *account)
1123 {
1124         struct mslsa_EnumPrivsAccount   arg;
1125         int     opnum;
1126         int     rc;
1127 
1128         opnum = LSARPC_OPNUM_EnumPrivsAccount;
1129 
1130         bzero(&arg, sizeof (struct mslsa_EnumPrivsAccount));
1131         (void) memcpy(&arg.account_handle, &account_handle->handle,
1132             sizeof (mslsa_handle_t));
1133 
1134         rc = ndr_rpc_call(account_handle, opnum, &arg);
1135         if ((rc == 0) && (arg.status != 0)) {
1136                 ndr_rpc_status(account_handle, opnum, arg.status);
1137                 rc = -1;
1138         }
1139         ndr_rpc_release(account_handle);
1140         return (rc);
1141 }
1142 
1143 /*
1144  * lsar_lookup_priv_value
1145  *
1146  * Map a privilege name to a local unique id (LUID). Privilege names
1147  * are consistent across the network. LUIDs are machine specific.
1148  * This function provides the means to map a privilege name to the
1149  * LUID used by a remote server to represent it. The handle here is
1150  * a policy handle.
1151  */
1152 int
1153 lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, char *name,
1154     struct ms_luid *luid)
1155 {
1156         struct mslsa_LookupPrivValue    arg;
1157         int     opnum;
1158         int     rc;
1159         size_t  length;
1160 
1161         if (lsa_handle == NULL || name == NULL || luid == NULL)
1162                 return (-1);
1163 
1164         opnum = LSARPC_OPNUM_LookupPrivValue;
1165 
1166         bzero(&arg, sizeof (struct mslsa_LookupPrivValue));
1167         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1168 
1169         length = smb_wcequiv_strlen(name);
1170         if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000)
1171                 length += sizeof (smb_wchar_t);
1172 
1173         arg.name.length = length;
1174         arg.name.allosize = length;
1175         arg.name.str = (unsigned char *)name;
1176 
1177         rc = ndr_rpc_call(lsa_handle, opnum, &arg);
1178         if (rc == 0) {
1179                 if (arg.status != 0)
1180                         rc = -1;
1181                 else
1182                         (void) memcpy(luid, &arg.luid, sizeof (struct ms_luid));
1183         }
1184 
1185         ndr_rpc_release(lsa_handle);
1186         return (rc);
1187 }
1188 
1189 /*
1190  * lsar_lookup_priv_name
1191  *
1192  * Map a local unique id (LUID) to a privilege name. Privilege names
1193  * are consistent across the network. LUIDs are machine specific.
1194  * This function the means to map the LUID used by a remote server to
1195  * the appropriate privilege name. The handle here is a policy handle.
1196  */
1197 int
1198 lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle, struct ms_luid *luid,
1199     char *name, int namelen)
1200 {
1201         struct mslsa_LookupPrivName     arg;
1202         int     opnum;
1203         int     rc;
1204 
1205         if (lsa_handle == NULL || luid == NULL || name == NULL)
1206                 return (-1);
1207 
1208         opnum = LSARPC_OPNUM_LookupPrivName;
1209 
1210         bzero(&arg, sizeof (struct mslsa_LookupPrivName));
1211         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1212         (void) memcpy(&arg.luid, luid, sizeof (struct ms_luid));
1213 
1214         rc = ndr_rpc_call(lsa_handle, opnum, &arg);
1215         if (rc == 0) {
1216                 if (arg.status != 0)
1217                         rc = -1;
1218                 else
1219                         (void) strlcpy(name, (char const *)arg.name->str,
1220                             namelen);
1221         }
1222 
1223         ndr_rpc_release(lsa_handle);
1224         return (rc);
1225 }
1226 
1227 /*
1228  * lsar_lookup_priv_display_name
1229  *
1230  * Map a privilege name to a privilege display name. The input handle
1231  * should be an LSA policy handle and the name would normally be one
1232  * of the privileges defined in smb_privilege.h
1233  *
1234  * There's something peculiar about the return status from NT servers,
1235  * it's not always present. So for now, I'm ignoring the status in the
1236  * RPC response.
1237  *
1238  * Returns NT status codes.
1239  */
1240 DWORD
1241 lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name,
1242     char *display_name, int display_len)
1243 {
1244         struct mslsa_LookupPrivDisplayName      arg;
1245         int     opnum;
1246         size_t  length;
1247         DWORD   status;
1248 
1249         if (lsa_handle == NULL || name == NULL || display_name == NULL)
1250                 return (NT_STATUS_INVALID_PARAMETER);
1251 
1252         opnum = LSARPC_OPNUM_LookupPrivDisplayName;
1253 
1254         bzero(&arg, sizeof (struct mslsa_LookupPrivDisplayName));
1255         (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1256 
1257         length = smb_wcequiv_strlen(name);
1258         arg.name.length = length;
1259         arg.name.allosize = length;
1260         arg.name.str = (unsigned char *)name;
1261 
1262         arg.client_language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
1263         arg.default_language = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
1264 
1265         if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0)
1266                 status = NT_STATUS_INVALID_PARAMETER;
1267 #if 0
1268         else if (arg.status != 0)
1269                 status = NT_SC_VALUE(arg.status);
1270 #endif
1271         else {
1272                 (void) strlcpy(display_name,
1273                     (char const *)arg.display_name->str, display_len);
1274                 status = NT_STATUS_SUCCESS;
1275         }
1276 
1277         ndr_rpc_release(lsa_handle);
1278         return (status);
1279 }
1280 
1281 static void
1282 lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *enum_buf,
1283     smb_trusted_domains_t *list)
1284 {
1285         char    sidstr[SMB_SID_STRSZ];
1286         int     i;
1287 
1288         if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
1289                 return;
1290 
1291         list->td_num = 0;
1292         list->td_domains = calloc(enum_buf->entries_read,
1293             sizeof (smb_domain_t));
1294 
1295         if (list->td_domains == NULL)
1296                 return;
1297 
1298         list->td_num = enum_buf->entries_read;
1299         for (i = 0; i < list->td_num; i++) {
1300                 smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
1301                 smb_domain_set_trust_info(
1302                     sidstr,
1303                     (char *)enum_buf->info[i].nb_name.str,
1304                     (char *)enum_buf->info[i].dns_name.str,
1305                     enum_buf->info[i].trust_direction,
1306                     enum_buf->info[i].trust_type,
1307                     enum_buf->info[i].trust_attrs,
1308                     &list->td_domains[i]);
1309         }
1310 }
1311 
1312 static void
1313 lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *enum_buf,
1314     smb_trusted_domains_t *list)
1315 {
1316         char    sidstr[SMB_SID_STRSZ];
1317         int     i;
1318 
1319         if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
1320                 return;
1321 
1322         list->td_num = 0;
1323         list->td_domains = calloc(enum_buf->entries_read,
1324             sizeof (smb_domain_t));
1325 
1326         if (list->td_domains == NULL)
1327                 return;
1328 
1329         list->td_num = enum_buf->entries_read;
1330         for (i = 0; i < list->td_num; i++) {
1331                 smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
1332                 smb_domain_set_trust_info(
1333                     sidstr, (char *)enum_buf->info[i].name.str,
1334                     "", 0, 0, 0, &list->td_domains[i]);
1335         }
1336 }
1337 
1338 static void
1339 smb_account_trace(const smb_account_t *info)
1340 {
1341         char    sidbuf[SMB_SID_STRSZ];
1342 
1343         bzero(sidbuf, SMB_SID_STRSZ);
1344         smb_sid_tostr(info->a_sid, sidbuf);
1345 
1346         smb_tracef("%s %s %s %lu %s", info->a_domain, info->a_name,
1347             sidbuf, info->a_rid, smb_sid_type2str(info->a_type));
1348 }