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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * This module provides the high level interface to the LSA RPC functions.
  29  */
  30 
  31 #include <strings.h>
  32 #include <unistd.h>
  33 
  34 #include <smbsrv/libsmb.h>
  35 #include <smbsrv/libmlsvc.h>
  36 #include <smbsrv/smbinfo.h>
  37 #include <smbsrv/smb_token.h>
  38 
  39 #include <lsalib.h>
  40 
  41 static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *);
  42 static uint32_t lsa_lookup_name_domain(char *, smb_account_t *);
  43 
  44 static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *);
  45 static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *);
  46 
  47 static uint32_t lsa_list_accounts(mlsvc_handle_t *);
  48 static uint32_t lsa_map_status(uint32_t);
  49 
  50 /*
  51  * Lookup the given account and returns the account information
  52  * in the passed smb_account_t structure.
  53  *
  54  * The lookup is performed in the following order:
  55  *    well known accounts
  56  *    local accounts
  57  *    domain accounts
  58  *
  59  * If it's established the given account is well know or local
  60  * but the lookup fails for some reason, the next step(s) won't be
  61  * performed.
  62  *
  63  * If the name is a domain account, it may refer to a user, group or
  64  * alias. If it is a local account, its type should be specified
  65  * in the sid_type parameter. In case the account type is unknown
  66  * sid_type should be set to SidTypeUnknown.
  67  *
  68  * account argument could be either [domain\]name or [domain/]name.
  69  *
  70  * Return status:
  71  *
  72  *   NT_STATUS_SUCCESS          Account is successfully translated
  73  *   NT_STATUS_NONE_MAPPED      Couldn't translate the account
  74  */
  75 uint32_t
  76 lsa_lookup_name(char *account, uint16_t type, smb_account_t *info)
  77 {
  78         char nambuf[SMB_USERNAME_MAXLEN];
  79         char dombuf[SMB_PI_MAX_DOMAIN];
  80         char *name, *domain;
  81         uint32_t status;
  82         char *slash;
  83 
  84         (void) strsubst(account, '/', '\\');
  85         (void) strcanon(account, "\\");
  86         /* \john -> john */
  87         account += strspn(account, "\\");
  88 
  89         if ((slash = strchr(account, '\\')) != NULL) {
  90                 *slash = '\0';
  91                 (void) strlcpy(dombuf, account, sizeof (dombuf));
  92                 (void) strlcpy(nambuf, slash + 1, sizeof (nambuf));
  93                 *slash = '\\';
  94                 name = nambuf;
  95                 domain = dombuf;
  96         } else {
  97                 name = account;
  98                 domain = NULL;
  99         }
 100 
 101         status = lsa_lookup_name_builtin(domain, name, info);
 102         if (status == NT_STATUS_NOT_FOUND) {
 103                 status = smb_sam_lookup_name(domain, name, type, info);
 104                 if (status == NT_STATUS_SUCCESS)
 105                         return (status);
 106 
 107                 if ((domain == NULL) || (status == NT_STATUS_NOT_FOUND))
 108                         status = lsa_lookup_name_domain(account, info);
 109         }
 110 
 111         return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
 112 }
 113 
 114 uint32_t
 115 lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info)
 116 {
 117         uint32_t status;
 118 
 119         if (!smb_sid_isvalid(sid))
 120                 return (NT_STATUS_INVALID_SID);
 121 
 122         status = lsa_lookup_sid_builtin(sid, info);
 123         if (status == NT_STATUS_NOT_FOUND) {
 124                 status = smb_sam_lookup_sid(sid, info);
 125                 if (status == NT_STATUS_NOT_FOUND)
 126                         status = lsa_lookup_sid_domain(sid, info);
 127         }
 128 
 129         return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
 130 }
 131 
 132 /*
 133  * Obtains the primary domain SID and name from the specified server
 134  * (domain controller).
 135  *
 136  * The requested information will be returned via 'info' argument.
 137  *
 138  * Returns NT status codes. (Raw, not LSA-ized)
 139  */
 140 DWORD
 141 lsa_query_primary_domain_info(char *server, char *domain,
 142     smb_domain_t *info)
 143 {
 144         mlsvc_handle_t domain_handle;
 145         char user[SMB_USERNAME_MAXLEN];
 146         DWORD status;
 147 
 148         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 149 
 150         status = lsar_open(server, domain, user, &domain_handle);
 151         if (status != 0)
 152                 return (status);
 153 
 154         status = lsar_query_info_policy(&domain_handle,
 155             MSLSA_POLICY_PRIMARY_DOMAIN_INFO, info);
 156 
 157         (void) lsar_close(&domain_handle);
 158         return (status);
 159 }
 160 
 161 /*
 162  * Obtains the account domain SID and name from the current server
 163  * (domain controller).
 164  *
 165  * The requested information will be returned via 'info' argument.
 166  *
 167  * Returns NT status codes. (Raw, not LSA-ized)
 168  */
 169 DWORD
 170 lsa_query_account_domain_info(char *server, char *domain,
 171     smb_domain_t *info)
 172 {
 173         mlsvc_handle_t domain_handle;
 174         char user[SMB_USERNAME_MAXLEN];
 175         DWORD status;
 176 
 177         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 178 
 179         status = lsar_open(server, domain, user, &domain_handle);
 180         if (status != 0)
 181                 return (status);
 182 
 183         status = lsar_query_info_policy(&domain_handle,
 184             MSLSA_POLICY_ACCOUNT_DOMAIN_INFO, info);
 185 
 186         (void) lsar_close(&domain_handle);
 187         return (status);
 188 }
 189 
 190 /*
 191  * lsa_query_dns_domain_info
 192  *
 193  * Obtains the DNS domain info from the specified server
 194  * (domain controller).
 195  *
 196  * The requested information will be returned via 'info' argument.
 197  *
 198  * Returns NT status codes. (Raw, not LSA-ized)
 199  */
 200 DWORD
 201 lsa_query_dns_domain_info(char *server, char *domain, smb_domain_t *info)
 202 {
 203         mlsvc_handle_t domain_handle;
 204         char user[SMB_USERNAME_MAXLEN];
 205         DWORD status;
 206 
 207         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 208 
 209         status = lsar_open(server, domain, user, &domain_handle);
 210         if (status != 0)
 211                 return (status);
 212 
 213         status = lsar_query_info_policy(&domain_handle,
 214             MSLSA_POLICY_DNS_DOMAIN_INFO, info);
 215 
 216         (void) lsar_close(&domain_handle);
 217         return (status);
 218 }
 219 
 220 /*
 221  * Enumerate the trusted domains of  primary domain.
 222  * This is the basic enumaration call which only returns the
 223  * NetBIOS name of the domain and its SID.
 224  *
 225  * The requested information will be returned via 'info' argument.
 226  *
 227  * Returns NT status codes.  (Raw, not LSA-ized)
 228  */
 229 DWORD
 230 lsa_enum_trusted_domains(char *server, char *domain,
 231     smb_trusted_domains_t *info)
 232 {
 233         mlsvc_handle_t domain_handle;
 234         char user[SMB_USERNAME_MAXLEN];
 235         DWORD enum_context;
 236         DWORD status;
 237 
 238         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 239 
 240         status = lsar_open(server, domain, user, &domain_handle);
 241         if (status != 0)
 242                 return (status);
 243 
 244         enum_context = 0;
 245 
 246         status = lsar_enum_trusted_domains(&domain_handle, &enum_context, info);
 247         if (status == NT_STATUS_NO_MORE_ENTRIES) {
 248                 /*
 249                  * STATUS_NO_MORE_ENTRIES indicates that we
 250                  * have all of the available information.
 251                  */
 252                 status = NT_STATUS_SUCCESS;
 253         }
 254 
 255         (void) lsar_close(&domain_handle);
 256         return (status);
 257 }
 258 
 259 /*
 260  * Enumerate the trusted domains of the primary domain.
 261  * This is the extended enumaration call which besides
 262  * NetBIOS name of the domain and its SID, it will return
 263  * the FQDN plus some trust information which is not used.
 264  *
 265  * The requested information will be returned via 'info' argument.
 266  *
 267  * Returns NT status codes. (Raw, not LSA-ized)
 268  */
 269 DWORD
 270 lsa_enum_trusted_domains_ex(char *server, char *domain,
 271     smb_trusted_domains_t *info)
 272 {
 273         mlsvc_handle_t domain_handle;
 274         char user[SMB_USERNAME_MAXLEN];
 275         DWORD enum_context;
 276         DWORD status;
 277 
 278         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 279 
 280         status = lsar_open(server, domain, user, &domain_handle);
 281         if (status != 0)
 282                 return (status);
 283 
 284         enum_context = 0;
 285 
 286         status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context,
 287             info);
 288         if (status == NT_STATUS_NO_MORE_ENTRIES) {
 289                 /*
 290                  * STATUS_NO_MORE_ENTRIES indicates that we
 291                  * have all of the available information.
 292                  */
 293                 status = NT_STATUS_SUCCESS;
 294         }
 295 
 296         (void) lsar_close(&domain_handle);
 297         return (status);
 298 }
 299 
 300 /*
 301  * Lookup well known accounts table
 302  *
 303  * Return status:
 304  *
 305  *   NT_STATUS_SUCCESS          Account is translated successfully
 306  *   NT_STATUS_NOT_FOUND        This is not a well known account
 307  *   NT_STATUS_NONE_MAPPED      Account is found but domains don't match
 308  *   NT_STATUS_NO_MEMORY        Memory shortage
 309  *   NT_STATUS_INTERNAL_ERROR   Internal error/unexpected failure
 310  */
 311 static uint32_t
 312 lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info)
 313 {
 314         smb_wka_t *wka;
 315         char *wkadom;
 316 
 317         bzero(info, sizeof (smb_account_t));
 318 
 319         if ((wka = smb_wka_lookup_name(name)) == NULL)
 320                 return (NT_STATUS_NOT_FOUND);
 321 
 322         if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
 323                 return (NT_STATUS_INTERNAL_ERROR);
 324 
 325         if ((domain != NULL) && (smb_strcasecmp(domain, wkadom, 0) != 0))
 326                 return (NT_STATUS_NONE_MAPPED);
 327 
 328         info->a_name = strdup(name);
 329         info->a_sid = smb_sid_dup(wka->wka_binsid);
 330         info->a_domain = strdup(wkadom);
 331         info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid);
 332         info->a_type = wka->wka_type;
 333 
 334         if (!smb_account_validate(info)) {
 335                 smb_account_free(info);
 336                 return (NT_STATUS_NO_MEMORY);
 337         }
 338 
 339         return (NT_STATUS_SUCCESS);
 340 }
 341 
 342 /*
 343  * Lookup a domain account by its name.
 344  *
 345  * The information is returned in the user_info structure.
 346  * The caller is responsible for allocating and releasing
 347  * this structure.
 348  *
 349  * Returns NT status codes. (LSA-ized)
 350  */
 351 static uint32_t
 352 lsa_lookup_name_domain(char *account_name, smb_account_t *info)
 353 {
 354         mlsvc_handle_t domain_handle;
 355         smb_domainex_t dinfo;
 356         char user[SMB_USERNAME_MAXLEN];
 357         uint32_t status;
 358 
 359         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 360 
 361         if (!smb_domain_getinfo(&dinfo))
 362                 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 363 
 364         status = lsar_open(dinfo.d_dci.dc_name, dinfo.d_primary.di_nbname,
 365             user, &domain_handle);
 366         if (status != 0)
 367                 return (lsa_map_status(status));
 368 
 369         status = lsar_lookup_names(&domain_handle, account_name, info);
 370 
 371         (void) lsar_close(&domain_handle);
 372         return (status);
 373 }
 374 
 375 /*
 376  * lsa_lookup_privs
 377  *
 378  * Request the privileges associated with the specified account. In
 379  * order to get the privileges, we first have to lookup the name on
 380  * the specified domain controller and obtain the appropriate SID.
 381  * The SID can then be used to open the account and obtain the
 382  * account privileges. The results from both the name lookup and the
 383  * privileges are returned in the user_info structure. The caller is
 384  * responsible for allocating and releasing this structure.
 385  *
 386  * Returns NT status codes. (LSA-ized)
 387  */
 388 /*ARGSUSED*/
 389 DWORD
 390 lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo)
 391 {
 392         mlsvc_handle_t domain_handle;
 393         smb_domainex_t dinfo;
 394         char user[SMB_USERNAME_MAXLEN];
 395         DWORD status;
 396 
 397         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 398 
 399         if (!smb_domain_getinfo(&dinfo))
 400                 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 401 
 402         status = lsar_open(dinfo.d_dci.dc_name, dinfo.d_primary.di_nbname,
 403             user, &domain_handle);
 404         if (status != 0)
 405                 return (lsa_map_status(status));
 406 
 407         status = lsa_list_accounts(&domain_handle);
 408         (void) lsar_close(&domain_handle);
 409         return (status);
 410 }
 411 
 412 /*
 413  * lsa_list_privs
 414  *
 415  * List the privileges supported by the specified server.
 416  * This function is only intended for diagnostics.
 417  *
 418  * Returns NT status codes. (LSA-ized)
 419  */
 420 DWORD
 421 lsa_list_privs(char *server, char *domain)
 422 {
 423         static char name[128];
 424         static struct ms_luid luid;
 425         mlsvc_handle_t domain_handle;
 426         char user[SMB_USERNAME_MAXLEN];
 427         DWORD status;
 428         int rc;
 429         int i;
 430 
 431         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 432 
 433         status = lsar_open(server, domain, user, &domain_handle);
 434         if (status != 0)
 435                 return (lsa_map_status(status));
 436 
 437         for (i = 0; i < 30; ++i) {
 438                 luid.low_part = i;
 439                 rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128);
 440                 if (rc != 0)
 441                         continue;
 442 
 443                 (void) lsar_lookup_priv_value(&domain_handle, name, &luid);
 444                 (void) lsar_lookup_priv_display_name(&domain_handle, name,
 445                     name, 128);
 446         }
 447 
 448         (void) lsar_close(&domain_handle);
 449         return (NT_STATUS_SUCCESS);
 450 }
 451 
 452 /*
 453  * lsa_list_accounts
 454  *
 455  * This function can be used to list the accounts in the specified
 456  * domain. For now the SIDs are just listed in the system log.
 457  *
 458  * Returns NT status
 459  */
 460 static DWORD
 461 lsa_list_accounts(mlsvc_handle_t *domain_handle)
 462 {
 463         mlsvc_handle_t account_handle;
 464         struct mslsa_EnumAccountBuf accounts;
 465         struct mslsa_sid *sid;
 466         smb_account_t ainfo;
 467         DWORD enum_context = 0;
 468         DWORD status;
 469         int i;
 470 
 471         bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
 472 
 473         do {
 474                 status = lsar_enum_accounts(domain_handle, &enum_context,
 475                     &accounts);
 476                 if (status != 0)
 477                         return (status);
 478 
 479                 for (i = 0; i < accounts.entries_read; ++i) {
 480                         sid = accounts.info[i].sid;
 481 
 482                         if (lsar_open_account(domain_handle, sid,
 483                             &account_handle) == 0) {
 484                                 (void) lsar_enum_privs_account(&account_handle,
 485                                     &ainfo);
 486                                 (void) lsar_close(&account_handle);
 487                         }
 488 
 489                         free(accounts.info[i].sid);
 490                 }
 491 
 492                 if (accounts.info)
 493                         free(accounts.info);
 494         } while (status == 0 && accounts.entries_read != 0);
 495 
 496         return (0);
 497 }
 498 
 499 /*
 500  * Lookup well known accounts table for the given SID
 501  *
 502  * Return status:
 503  *
 504  *   NT_STATUS_SUCCESS          Account is translated successfully
 505  *   NT_STATUS_NOT_FOUND        This is not a well known account
 506  *   NT_STATUS_NO_MEMORY        Memory shortage
 507  *   NT_STATUS_INTERNAL_ERROR   Internal error/unexpected failure
 508  */
 509 static uint32_t
 510 lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo)
 511 {
 512         smb_wka_t *wka;
 513         char *wkadom;
 514 
 515         bzero(ainfo, sizeof (smb_account_t));
 516 
 517         if ((wka = smb_wka_lookup_sid(sid)) == NULL)
 518                 return (NT_STATUS_NOT_FOUND);
 519 
 520         if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
 521                 return (NT_STATUS_INTERNAL_ERROR);
 522 
 523         ainfo->a_name = strdup(wka->wka_name);
 524         ainfo->a_sid = smb_sid_dup(wka->wka_binsid);
 525         ainfo->a_domain = strdup(wkadom);
 526         ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid);
 527         ainfo->a_type = wka->wka_type;
 528 
 529         if (!smb_account_validate(ainfo)) {
 530                 smb_account_free(ainfo);
 531                 return (NT_STATUS_NO_MEMORY);
 532         }
 533 
 534         return (NT_STATUS_SUCCESS);
 535 }
 536 
 537 /*
 538  * Lookup a domain account by its SID.
 539  *
 540  * The information is returned in the user_info structure.
 541  * The caller is responsible for allocating and releasing
 542  * this structure.
 543  *
 544  * Returns NT status codes. (LSA-ized)
 545  */
 546 static uint32_t
 547 lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo)
 548 {
 549         mlsvc_handle_t domain_handle;
 550         smb_domainex_t dinfo;
 551         char user[SMB_USERNAME_MAXLEN];
 552         uint32_t status;
 553 
 554         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 555 
 556         if (!smb_domain_getinfo(&dinfo))
 557                 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 558 
 559         status = lsar_open(dinfo.d_dci.dc_name, dinfo.d_primary.di_nbname,
 560             user, &domain_handle);
 561         if (status != 0)
 562                 return (lsa_map_status(status));
 563 
 564         status = lsar_lookup_sids(&domain_handle, sid, ainfo);
 565 
 566         (void) lsar_close(&domain_handle);
 567         return (status);
 568 }
 569 
 570 /*
 571  * Most functions that call the local security authority expect
 572  * only a limited set of status returns.  This function maps the
 573  * status we get from talking to our domain controller into one
 574  * that LSA functions can return.  Most common errors become:
 575  * NT_STATUS_CANT_ACCESS_DOMAIN_INFO (when no DC etc.)
 576  */
 577 static uint32_t
 578 lsa_map_status(uint32_t status)
 579 {
 580         switch (status) {
 581         case NT_STATUS_SUCCESS:
 582                 break;
 583         case NT_STATUS_INVALID_PARAMETER:       /* rpc bind */
 584                 break;
 585         case NT_STATUS_NO_MEMORY:
 586                 break;
 587         case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
 588         case NT_STATUS_BAD_NETWORK_PATH:        /* get server addr */
 589         case NT_STATUS_NETWORK_ACCESS_DENIED:   /* authentication */
 590         case NT_STATUS_BAD_NETWORK_NAME:        /* tree connect */
 591         case NT_STATUS_ACCESS_DENIED:           /* open pipe */
 592                 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 593                 break;
 594         default:
 595                 status = NT_STATUS_UNSUCCESSFUL;
 596                 break;
 597         }
 598         return (status);
 599 }