lsalib.c revision 2
2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * This module provides the high level interface to the LSA RPC functions.
2N/A */
2N/A
2N/A#include <strings.h>
2N/A#include <unistd.h>
2N/A
2N/A#include <smbsrv/libsmb.h>
2N/A#include <smbsrv/libntsvcs.h>
2N/A#include <smbsrv/smbinfo.h>
2N/A#include <smbsrv/smb_token.h>
2N/A
2N/A#include <lsalib.h>
2N/A
2N/Astatic uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *);
2N/A/*LINTED E_STATIC_UNUSED*/
2N/Astatic int lsa_list_accounts(mlsvc_handle_t *);
2N/Astatic uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *);
2N/A
2N/Astatic uint32_t lsa_lookup_name_domain(char *, smb_account_t *);
2N/Astatic uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *);
2N/A
2N/A
2N/A/*
2N/A * Lookup the given account and returns the account information
2N/A * in the passed smb_account_t structure.
2N/A *
2N/A * The lookup is performed in the following order:
2N/A * well known accounts
2N/A * local accounts
2N/A * domain accounts
2N/A *
2N/A * If it's established the given account is well know or local
2N/A * but the lookup fails for some reason, the next step(s) won't be
2N/A * performed.
2N/A *
2N/A * If the name is a domain account, it may refer to a user, group or
2N/A * alias. If it is a local account, its type should be specified
2N/A * in the sid_type parameter. In case the account type is unknown
2N/A * sid_type should be set to SidTypeUnknown.
2N/A *
2N/A * account argument could be either [domain\]name or [domain/]name.
2N/A *
2N/A * Return status:
2N/A *
2N/A * NT_STATUS_SUCCESS Account is successfully translated
2N/A * NT_STATUS_NONE_MAPPED Couldn't translate the account
2N/A *
2N/A * Retries for DC failover
2N/A * ---------------------------
2N/A * Required by the called function: lsa_lookup_name_domain().
2N/A */
2N/Auint32_t
2N/Alsa_lookup_name(char *account, uint16_t type, smb_account_t *info)
2N/A{
2N/A char domain_acct[MAXNAMELEN];
2N/A char nambuf[MAXNAMELEN];
2N/A char *domain = NULL;
2N/A char *name = NULL;
2N/A uint32_t status;
2N/A
2N/A (void) strlcpy(nambuf, account, MAXNAMELEN);
2N/A (void) strsubst(nambuf, '/', '\\');
2N/A (void) strcanon(nambuf, "\\");
2N/A (void) strlcpy(domain_acct, nambuf, MAXNAMELEN);
2N/A
2N/A smb_name_parse(nambuf, &name, &domain);
2N/A if (name == NULL)
2N/A name = account;
2N/A
2N/A status = lsa_lookup_name_builtin(domain, name, info);
2N/A if (status == NT_STATUS_NOT_FOUND) {
2N/A status = smb_sam_lookup_name(domain, name, type, info);
2N/A if (status == NT_STATUS_SUCCESS)
2N/A return (status);
2N/A
2N/A if ((domain == NULL) || (status == NT_STATUS_NOT_FOUND))
2N/A status = lsa_lookup_name_domain(domain_acct, info);
2N/A }
2N/A
2N/A return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
2N/A}
2N/A
2N/A/*
2N/A * Retries for DC failover
2N/A * ---------------------------
2N/A * Required by the called function: lsa_lookup_sid_domain().
2N/A */
2N/Auint32_t
2N/Alsa_lookup_sid(smb_sid_t *sid, smb_account_t *info)
2N/A{
2N/A uint32_t status;
2N/A
2N/A if (!smb_sid_isvalid(sid))
2N/A return (NT_STATUS_INVALID_SID);
2N/A
2N/A status = lsa_lookup_sid_builtin(sid, info);
2N/A if (status == NT_STATUS_NOT_FOUND) {
2N/A status = smb_sam_lookup_sid(sid, info);
2N/A if (status == NT_STATUS_NOT_FOUND)
2N/A status = lsa_lookup_sid_domain(sid, info);
2N/A }
2N/A
2N/A return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
2N/A}
2N/A
2N/A/*
2N/A * Obtains the primary domain SID and name from the specified server
2N/A * (domain controller).
2N/A *
2N/A * The requested information will be returned via 'info' argument.
2N/A *
2N/A * Returns NT status codes.
2N/A */
2N/ADWORD
2N/Alsa_query_primary_domain_info(char *server, char *domain,
2N/A smb_domain_t *info)
2N/A{
2N/A mlsvc_handle_t domain_handle;
2N/A DWORD status;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A if ((lsar_open(server, domain, user, &domain_handle)) != 0)
2N/A return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
2N/A
2N/A status = lsar_query_info_policy(&domain_handle,
2N/A MSLSA_POLICY_PRIMARY_DOMAIN_INFO, info);
2N/A
2N/A (void) lsar_close(&domain_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Obtains the account domain SID and name from the current server
2N/A * (domain controller).
2N/A *
2N/A * The requested information will be returned via 'info' argument.
2N/A *
2N/A * Returns NT status codes.
2N/A */
2N/ADWORD
2N/Alsa_query_account_domain_info(char *server, char *domain,
2N/A smb_domain_t *info)
2N/A{
2N/A mlsvc_handle_t domain_handle;
2N/A DWORD status;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A if ((lsar_open(server, domain, user, &domain_handle)) != 0)
2N/A return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
2N/A
2N/A status = lsar_query_info_policy(&domain_handle,
2N/A MSLSA_POLICY_ACCOUNT_DOMAIN_INFO, info);
2N/A
2N/A (void) lsar_close(&domain_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsa_query_dns_domain_info
2N/A *
2N/A * Obtains the DNS domain info from the specified server
2N/A * (domain controller).
2N/A *
2N/A * The requested information will be returned via 'info' argument.
2N/A *
2N/A * Returns NT status codes.
2N/A */
2N/ADWORD
2N/Alsa_query_dns_domain_info(char *server, char *domain, smb_domain_t *info)
2N/A{
2N/A mlsvc_handle_t domain_handle;
2N/A DWORD status;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A if ((lsar_open(server, domain, user, &domain_handle)) != 0)
2N/A return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
2N/A
2N/A status = lsar_query_info_policy(&domain_handle,
2N/A MSLSA_POLICY_DNS_DOMAIN_INFO, info);
2N/A
2N/A (void) lsar_close(&domain_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Enumerate the trusted domains of the primary domain.
2N/A *
2N/A * Try the extended enumaration call, which returns the FQDN and
2N/A * trust information in addition to the trusted domain's NetBIOS
2N/A * name and SID.
2N/A *
2N/A * If the extended call fails, we fall back to the original enum
2N/A * call.
2N/A *
2N/A * The requested information will be returned via the info pointer.
2N/A *
2N/A * Returns NT status codes.
2N/A * STATUS_NO_MORE_ENTRIES indicates that we have all of the available
2N/A * information, which we can translate to NT_STATUS_SUCCESS.
2N/A */
2N/ADWORD
2N/Alsa_enum_trusted_domains(char *server, char *domain,
2N/A smb_trusted_domains_t *info)
2N/A{
2N/A mlsvc_handle_t domain_handle;
2N/A DWORD enum_context;
2N/A DWORD status;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A if ((lsar_open(server, domain, user, &domain_handle)) != 0)
2N/A return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
2N/A
2N/A enum_context = 0;
2N/A
2N/A status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context,
2N/A info);
2N/A if (status == NT_STATUS_NO_MORE_ENTRIES)
2N/A status = NT_STATUS_SUCCESS;
2N/A
2N/A if (status != NT_STATUS_SUCCESS) {
2N/A enum_context = 0;
2N/A
2N/A status = lsar_enum_trusted_domains(&domain_handle,
2N/A &enum_context, info);
2N/A
2N/A if (status == NT_STATUS_NO_MORE_ENTRIES)
2N/A status = NT_STATUS_SUCCESS;
2N/A }
2N/A
2N/A (void) lsar_close(&domain_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Lookup well known accounts table
2N/A *
2N/A * Return status:
2N/A *
2N/A * NT_STATUS_SUCCESS Account is translated successfully
2N/A * NT_STATUS_NOT_FOUND This is not a well known account
2N/A * NT_STATUS_NONE_MAPPED Account is found but domains don't match
2N/A * NT_STATUS_NO_MEMORY Memory shortage
2N/A * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure
2N/A */
2N/Astatic uint32_t
2N/Alsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info)
2N/A{
2N/A smb_wka_t *wka;
2N/A char *wkadom;
2N/A
2N/A bzero(info, sizeof (smb_account_t));
2N/A
2N/A if ((wka = smb_wka_lookup_name(name)) == NULL)
2N/A return (NT_STATUS_NOT_FOUND);
2N/A
2N/A if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
2N/A return (NT_STATUS_INTERNAL_ERROR);
2N/A
2N/A if ((domain != NULL) && (smb_strcasecmp(domain, wkadom, 0) != 0))
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A
2N/A info->a_name = strdup(name);
2N/A info->a_sid = smb_sid_dup(wka->wka_binsid);
2N/A info->a_domain = strdup(wkadom);
2N/A info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid);
2N/A info->a_type = wka->wka_type;
2N/A
2N/A if (!smb_account_validate(info)) {
2N/A smb_account_free(info);
2N/A return (NT_STATUS_NO_MEMORY);
2N/A }
2N/A
2N/A return (NT_STATUS_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Lookup the given account in domain.
2N/A *
2N/A * The information is returned in the user_info structure.
2N/A * The caller is responsible for allocating and releasing
2N/A * this structure.
2N/A *
2N/A * Retries for DC failover
2N/A * ---------------------------
2N/A * Handled by the called function: lsar_lookup().
2N/A */
2N/Astatic uint32_t
2N/Alsa_lookup_name_domain(char *account_name, smb_account_t *info)
2N/A{
2N/A lsar_lookup_op_t op;
2N/A
2N/A op.l_func = lsar_lookup_names;
2N/A op.l_key = account_name;
2N/A op.l_acct = info;
2N/A return (lsar_lookup(&op));
2N/A}
2N/A
2N/A/*
2N/A * lsa_lookup_privs (NOT IMPLEMENTED)
2N/A *
2N/A * Request the privileges associated with the specified account. In
2N/A * order to get the privileges, we first have to lookup the name on
2N/A * the specified domain controller and obtain the appropriate SID.
2N/A * The SID can then be used to open the account and obtain the
2N/A * account privileges. The results from both the name lookup and the
2N/A * privileges are returned in the user_info structure. The caller is
2N/A * responsible for allocating and releasing this structure.
2N/A *
2N/A * On success 0 is returned. Otherwise a -ve error code.
2N/A *
2N/A * Retries for DC failover
2N/A * ---------------------------
2N/A * Handled by the called function: lsar_lookup().
2N/A */
2N/A/*ARGSUSED*/
2N/Auint32_t
2N/Alsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo)
2N/A{
2N/A lsar_lookup_op_t op;
2N/A
2N/A op.l_func = NULL;
2N/A op.l_key = NULL;
2N/A op.l_acct = ainfo;
2N/A return (lsar_lookup(&op));
2N/A}
2N/A
2N/A/*
2N/A * lsa_list_privs
2N/A *
2N/A * List the privileges supported by the specified server.
2N/A * This function is only intended for diagnostics.
2N/A *
2N/A * Returns NT status codes.
2N/A */
2N/ADWORD
2N/Alsa_list_privs(char *server, char *domain)
2N/A{
2N/A static char name[128];
2N/A static struct ms_luid luid;
2N/A mlsvc_handle_t domain_handle;
2N/A int rc;
2N/A int i;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A rc = lsar_open(server, domain, user, &domain_handle);
2N/A if (rc != 0)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A for (i = 0; i < 30; ++i) {
2N/A luid.low_part = i;
2N/A rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128);
2N/A if (rc != 0)
2N/A continue;
2N/A
2N/A (void) lsar_lookup_priv_value(&domain_handle, name, &luid);
2N/A (void) lsar_lookup_priv_display_name(&domain_handle, name,
2N/A name, 128);
2N/A }
2N/A
2N/A (void) lsar_close(&domain_handle);
2N/A return (NT_STATUS_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * lsa_list_accounts
2N/A *
2N/A * This function can be used to list the accounts in the specified
2N/A * domain. For now the SIDs are just listed in the system log.
2N/A *
2N/A * On success 0 is returned. Otherwise a -ve error code.
2N/A */
2N/Astatic int
2N/Alsa_list_accounts(mlsvc_handle_t *domain_handle)
2N/A{
2N/A mlsvc_handle_t account_handle;
2N/A struct mslsa_EnumAccountBuf accounts;
2N/A struct mslsa_sid *sid;
2N/A smb_account_t ainfo;
2N/A DWORD enum_context = 0;
2N/A int rc;
2N/A int i;
2N/A
2N/A bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
2N/A
2N/A do {
2N/A rc = lsar_enum_accounts(domain_handle, &enum_context,
2N/A &accounts);
2N/A if (rc != 0)
2N/A return (rc);
2N/A
2N/A for (i = 0; i < accounts.entries_read; ++i) {
2N/A sid = accounts.info[i].sid;
2N/A
2N/A if (lsar_open_account(domain_handle, sid,
2N/A &account_handle) == 0) {
2N/A (void) lsar_enum_privs_account(&account_handle,
2N/A &ainfo);
2N/A (void) lsar_close(&account_handle);
2N/A }
2N/A
2N/A free(accounts.info[i].sid);
2N/A }
2N/A
2N/A if (accounts.info)
2N/A free(accounts.info);
2N/A } while (rc == 0 && accounts.entries_read != 0);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Lookup well known accounts table for the given SID
2N/A *
2N/A * Return status:
2N/A *
2N/A * NT_STATUS_SUCCESS Account is translated successfully
2N/A * NT_STATUS_NOT_FOUND This is not a well known account
2N/A * NT_STATUS_NO_MEMORY Memory shortage
2N/A * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure
2N/A */
2N/Astatic uint32_t
2N/Alsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo)
2N/A{
2N/A smb_wka_t *wka;
2N/A char *wkadom;
2N/A
2N/A bzero(ainfo, sizeof (smb_account_t));
2N/A
2N/A if ((wka = smb_wka_lookup_sid(sid)) == NULL)
2N/A return (NT_STATUS_NOT_FOUND);
2N/A
2N/A if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
2N/A return (NT_STATUS_INTERNAL_ERROR);
2N/A
2N/A ainfo->a_name = strdup(wka->wka_name);
2N/A ainfo->a_sid = smb_sid_dup(wka->wka_binsid);
2N/A ainfo->a_domain = strdup(wkadom);
2N/A ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid);
2N/A ainfo->a_type = wka->wka_type;
2N/A
2N/A if (!smb_account_validate(ainfo)) {
2N/A smb_account_free(ainfo);
2N/A return (NT_STATUS_NO_MEMORY);
2N/A }
2N/A
2N/A return (NT_STATUS_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Retries for DC failover
2N/A * ---------------------------
2N/A * Handled by the called function: lsar_lookup().
2N/A */
2N/Astatic uint32_t
2N/Alsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo)
2N/A{
2N/A lsar_lookup_op_t op;
2N/A
2N/A op.l_func = lsar_lookup_sids;
2N/A op.l_key = sid;
2N/A op.l_acct = ainfo;
2N/A
2N/A return (lsar_lookup(&op));
2N/A}