/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Local Security Authority RPC (LSAR) server-side interface.
*/
#include <unistd.h>
#include <strings.h>
#include <pwd.h>
#include <grp.h>
#include <smbsrv/libmlrpc.h>
#include <smbsrv/libmlsvc.h>
#include <lsalib.h>
#include <smbsrv/ntlocale.h>
struct local_group_table {
char *sid;
char *name;
};
static int lsarpc_key_domain;
static int lsarpc_key_account;
static int lsarpc_s_CloseHandle(void *, ndr_xa_t *);
static int lsarpc_s_QuerySecurityObject(void *, ndr_xa_t *);
static int lsarpc_s_EnumAccounts(void *, ndr_xa_t *);
static int lsarpc_s_EnumTrustedDomain(void *, ndr_xa_t *);
static int lsarpc_s_EnumTrustedDomainsEx(void *, ndr_xa_t *);
static int lsarpc_s_OpenAccount(void *, ndr_xa_t *);
static int lsarpc_s_EnumPrivsAccount(void *, ndr_xa_t *);
static int lsarpc_s_LookupPrivValue(void *, ndr_xa_t *);
static int lsarpc_s_LookupPrivName(void *, ndr_xa_t *);
static int lsarpc_s_LookupPrivDisplayName(void *, ndr_xa_t *);
static int lsarpc_s_CreateSecret(void *, ndr_xa_t *);
static int lsarpc_s_OpenSecret(void *, ndr_xa_t *);
static int lsarpc_s_QueryInfoPolicy(void *, ndr_xa_t *);
static int lsarpc_s_OpenDomainHandle(void *, ndr_xa_t *);
static int lsarpc_s_OpenDomainHandle(void *, ndr_xa_t *);
static int lsarpc_s_LookupSids(void *, ndr_xa_t *);
static int lsarpc_s_LookupNames(void *, ndr_xa_t *);
static int lsarpc_s_GetConnectedUser(void *, ndr_xa_t *);
static int lsarpc_s_LookupSids2(void *, ndr_xa_t *);
static int lsarpc_s_LookupSids3(void *, ndr_xa_t *);
static int lsarpc_s_LookupNames2(void *, ndr_xa_t *);
static int lsarpc_s_LookupNames3(void *, ndr_xa_t *);
static int lsarpc_s_LookupNames4(void *, ndr_xa_t *);
ndr_xa_t *);
ndr_xa_t *);
static int lsarpc_s_UpdateDomainTable(ndr_xa_t *,
{0}
};
"LSARPC", /* name */
"Local Security Authority", /* desc */
"\\lsarpc", /* endpoint */
PIPE_LSASS, /* sec_addr_port */
"12345778-1234-abcd-ef00-0123456789ab", 0, /* abstract */
0, /* no bind_instance_size */
NULL, /* no bind_req() */
NULL, /* no unbind_and_close() */
lsarpc_call_stub, /* call_stub() */
lsarpc_stub_table /* stub_table */
};
/*
* lsarpc_initialize
*
* This function registers the LSA RPC interface with the RPC runtime
* library. It must be called in order to use either the client side
* or the server side functions.
*/
void
lsarpc_initialize(void)
{
(void) ndr_svc_register(&lsarpc_service);
}
/*
* Custom call_stub to set the stream string policy.
*/
static int
{
return (ndr_generic_call_stub(mxa));
}
/*
* lsarpc_s_OpenDomainHandle opnum=0x06
*
* This is a request to open the LSA (OpenPolicy and OpenPolicy2).
* The client is looking for an LSA domain handle.
*/
static int
{
} else {
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_CloseHandle opnum=0x00
*
* This is a request to close the LSA interface specified by the handle.
* We don't track handles (yet), so just zero out the handle and return
* NDR_DRC_OK. Setting the handle to zero appears to be standard
* behaviour and someone may rely on it, i.e. we do on the client side.
*/
static int
{
return (NDR_DRC_OK);
}
/*
* lsarpc_s_QuerySecurityObject
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* lsarpc_s_EnumAccounts
*
* Enumerate the list of local accounts SIDs. The client should supply
* a valid OpenPolicy2 handle. The enum_context is used to support
* multiple enumeration calls to obtain the complete list of SIDs.
* It should be set to 0 on the first call and passed unchanged on
* subsequent calls until there are no more accounts - the server will
* return STATUS_NO_MORE_ENTRIES.
*
* For now just set the status to access-denied. Note that we still have
* to provide a valid address for enum_buf because it's a reference and
* the marshalling rules require that references must not be null.
* The enum_context is used to support multiple
*/
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_EnumTrustedDomain
*
* This is the server side function for handling requests to enumerate
* the list of trusted domains: currently held in the NT domain database.
* This call requires an OpenPolicy2 handle. The enum_context is used to
* support multiple enumeration calls to obtain the complete list.
* It should be set to 0 on the first call and passed unchanged on
* subsequent calls until there are no more accounts - the server will
* return STATUS_NO_MORE_ENTRIES.
*
* For now just set the status to access-denied. Note that we still have
* to provide a valid address for enum_buf because it's a reference and
* the marshalling rules require that references must not be null.
*/
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_EnumTrustedDomainsEx
*
* This is the server side function for handling requests to enumerate
* the list of trusted domains: currently held in the NT domain database.
* This call requires an OpenPolicy2 handle. The enum_context is used to
* support multiple enumeration calls to obtain the complete list.
* It should be set to 0 on the first call and passed unchanged on
* subsequent calls until there are no more accounts - the server will
* return STATUS_NO_MORE_ENTRIES.
*
* For now just set the status to access-denied. Note that we still have
* to provide a valid address for enum_buf because it's a reference and
* the marshalling rules require that references must not be null.
*/
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_OpenAccount
*
* This is a request to open an account handle.
*/
static int
{
return (NDR_DRC_OK);
}
} else {
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_EnumPrivsAccount
*
* This is the server side function for handling requests for account
* privileges. For now just set the status to not-supported status and
* return NDR_DRC_OK. Note that we still have to provide a valid
* address for enum_buf because it's a reference and the marshalling
* rules require that references must not be null.
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* lsarpc_s_LookupPrivValue
*
* Server side function used to map a privilege name to a locally unique
* identifier (LUID).
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_LookupPrivName
*
* Server side function used to map a locally unique identifier (LUID)
* to the appropriate privilege name string.
*/
static int
{
int rc;
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
if (rc == -1) {
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_LookupPrivDisplayName
*
* This is the server side function for handling requests for account
* privileges. For now just set the status to not-supported status and
* return NDR_DRC_OK.
*/
static int
{
int rc;
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
if (rc == -1) {
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_GetConnectedUser
*
* Return the account name and NetBIOS domain name for the user making
* the request. The hostname field should be ignored by the server.
*
* Note: MacOS uses this, whether we're a domain member or not.
*/
static int
{
int rc1;
int rc2;
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_QueryInfoPolicy
*
* This is the server side function for handling LSA information policy
* queries. Currently, we only support primary domain and account
* domain queries. This is just a front end to switch on the request
* and hand it off to the appropriate function to actually deal with
* obtaining and building the response.
*/
static int
{
int security_mode;
switch (param->info_class) {
break;
break;
break;
if (security_mode == SMB_SECMODE_DOMAIN)
else
break;
default:
return (NDR_DRC_OK);
}
if (status != NT_STATUS_SUCCESS)
else
return (NDR_DRC_OK);
}
/*
* lsarpc_s_PrimaryDomainInfo
*
* Service primary domain policy queries. In domain mode, return the
* primary domain name and SID. In workgroup mode, return the local
* hostname and local domain SID.
*
* Note: info is zeroed on entry to ensure the SID and name do not
* contain spurious values if an error is returned.
*/
static DWORD
{
int rc;
if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
else
if (!found)
return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
return (NT_STATUS_NO_MEMORY);
return (NT_STATUS_SUCCESS);
}
/*
* lsarpc_s_AccountDomainInfo
*
* Service account domain policy queries. We return our local domain
* information so that the client knows who to query for information
* on local names and SIDs. The domain name is the local hostname.
*
* Note: info is zeroed on entry to ensure the SID and name do not
* contain spurious values if an error is returned.
*/
static DWORD
{
int rc;
return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
return (NT_STATUS_NO_MEMORY);
return (NT_STATUS_SUCCESS);
}
/*
* lsarpc_s_LookupNames
*
* This is the service side function for handling name lookup requests.
* Currently, we only support lookups of a single name. This is also a
* pass through interface so all we do is act as a proxy between the
* client and the DC.
*/
static int
{
char *accname;
int rc = 0;
return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
return (NDR_DRC_OK);
}
if (status != NT_STATUS_SUCCESS) {
return (NDR_DRC_OK);
}
/*
* Set up the rid table.
*/
rids[0].domain_index = 0;
/*
* Set up the domain table.
*/
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* lsarpc_s_LookupSids
*
* This is the service side function for handling sid lookup requests.
* We have to set up both the name table and the domain table in the
* response. For each SID, we check for UNIX domain (local lookup) or
* NT domain (DC lookup) and call the appropriate lookup function. This
* should resolve the SID to a name. Then we need to update the domain
* table and make the name entry point at the appropriate domain table
* entry.
*
*
* This RPC should behave as if LookupOptions is LSA_LOOKUP_OPT_ALL and
* ClientRevision is LSA_CLIENT_REVISION_NT.
*
* On success return 0. Otherwise return an RPC specific error code.
*/
static int
{
int result;
int i;
n_mapped = 0;
goto lookup_sid_failed;
domain_table->n_entry = 0;
if ((result != NT_STATUS_SUCCESS) ||
goto lookup_sid_failed;
} else {
goto lookup_sid_failed;
++n_mapped;
}
if (result == -1)
goto lookup_sid_failed;
}
else if (n_mapped == 0)
else
return (NDR_DRC_OK);
return (NDR_DRC_FAULT_OUT_OF_MEMORY);
}
/*
* lsarpc_s_UpdateDomainTable
*
* This routine is responsible for maintaining the domain table which
* will be returned from a SID lookup. Whenever a name is added to the
* name table, this function should be called with the corresponding
* domain name. If the domain information is not already in the table,
* it is added. On success return 0; Otherwise -1 is returned.
*/
static int
{
DWORD i;
int rc;
/*
* These types don't need to reference an entry in the
* domain table. So return -1.
*/
return (0);
}
return (-1);
return (-1);
for (i = 0; i < n_entry; ++i) {
*domain_idx = i;
return (0);
}
}
if (i == MLSVC_DOMAIN_MAX)
return (-1);
dentry[i].domain_sid =
return (-1);
++domain_table->n_entry;
*domain_idx = i;
return (0);
}
/*
* lsarpc_s_LookupSids2
*
* Other than the use of lsar_lookup_sids2 and lsar_name_entry2, this
* is identical to lsarpc_s_LookupSids.
*
* Ignore lookup_level, it is reserved and should be zero.
*/
static int
{
int result;
int i;
n_mapped = 0;
goto lookup_sid_failed;
domain_table->n_entry = 0;
if ((result != NT_STATUS_SUCCESS) ||
goto lookup_sid_failed;
} else {
goto lookup_sid_failed;
++n_mapped;
}
if (result == -1)
goto lookup_sid_failed;
}
else if (n_mapped == 0)
else
return (NDR_DRC_OK);
return (NDR_DRC_FAULT_OUT_OF_MEMORY);
}
/*
* LookupSids3 is only valid on domain controllers.
* Other servers must return NT_STATUS_INVALID_SERVER_STATE.
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* lsarpc_s_LookupNames2
*
* Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this
* is identical to lsarpc_s_LookupNames.
*
* If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not
* LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER.
*/
static int
{
char *accname;
int rc = 0;
return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
if (status != NT_STATUS_SUCCESS) {
return (NDR_DRC_OK);
}
/*
* Set up the rid table.
*/
rids[0].domain_index = 0;
/*
* Set up the domain table.
*/
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this
* is identical to lsarpc_s_LookupNames.
*
* If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not
* LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER.
*/
static int
{
char *accname;
int rc = 0;
return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
if (status != NT_STATUS_SUCCESS) {
return (NDR_DRC_OK);
}
/*
* Set up the SID table.
*/
sids[0].domain_index = 0;
/*
* Set up the domain table.
*/
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/*
* LookupNames4 is only valid on domain controllers.
* Other servers must return NT_STATUS_INVALID_SERVER_STATE.
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* There is a bug in the way that ndrgen and the marshalling code handles
* unions so we need to fix some of the data offsets at runtime. The
* following macros and the fixup functions handle the corrections.
*/
void
{
unsigned short size1 = 0;
unsigned short size2 = 0;
unsigned short size3 = 0;
switch (val->info_class) {
size1 = sizeof (struct mslsa_AuditEventsInfo);
break;
size1 = sizeof (struct mslsa_PrimaryDomainInfo);
break;
size1 = sizeof (struct mslsa_AccountDomainInfo);
break;
size1 = sizeof (struct mslsa_ServerRoleInfo);
break;
size1 = sizeof (struct mslsa_DnsDomainInfo);
break;
default:
return;
};
}