mlsvc_sam.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Security Accounts Manager RPC (SAMR) interface definition.
*/
#include <strings.h>
#include <unistd.h>
#include <netdb.h>
#include <pwd.h>
#include <grp.h>
#include <smbsrv/ntstatus.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/mlsvc_util.h>
/*
* The keys associated with the various handles dispensed
* by the SAMR server. These keys can be used to validate
* client activity. These values are never passed over
* the network so security shouldn't be an issue.
*/
#define SAMR_CONNECT_KEY "SamrConnect"
#define SAMR_DOMAIN_KEY "SamrDomain"
#define SAMR_USER_KEY "SamrUser"
#define SAMR_GROUP_KEY "SamrGroup"
#define SAMR_ALIAS_KEY "SamrAlias"
/*
* Domain discriminator values. Set the top bit to try
* to distinguish these values from user and group ids.
*/
#define SAMR_DATABASE_DOMAIN 0x80000001
#define SAMR_LOCAL_DOMAIN 0x80000002
#define SAMR_BUILTIN_DOMAIN 0x80000003
#define SAMR_PRIMARY_DOMAIN 0x80000004
struct mlrpc_xaction *);
static mlrpc_stub_table_t samr_stub_table[];
static mlrpc_service_t samr_service = {
"SAMR", /* name */
"Security Accounts Manager", /* desc */
"\\samr", /* endpoint */
PIPE_LSASS, /* sec_addr_port */
"12345778-1234-abcd-ef000123456789ac", 1, /* abstract */
"8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */
0, /* no bind_instance_size */
0, /* no bind_req() */
0, /* no unbind_and_close() */
0, /* use generic_call_stub() */
samr_stub_table /* stub_table */
};
/*
* samr_initialize
*
* This function registers the SAM 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
samr_initialize(void)
{
(void) mlrpc_register_service(&samr_service);
}
/*
* samr_s_ConnectAnon
*
* This is a request to connect to the local SAM database. We don't
* support any form of update request and our database doesn't
* contain any private information, so there is little point in
* doing any access access checking here.
*
* Return a handle for use with subsequent SAM requests.
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_CloseHandle
*
* This is a request to close the SAM interface specified by the handle.
* Free the handle and zero out the result handle for the client.
*
* We could do some checking here but it probably doesn't matter.
*/
/*ARGSUSED*/
static int
{
#ifdef SAMR_S_DEBUG
return (MLRPC_DRC_OK);
}
#endif /* SAMR_S_DEBUG */
return (MLRPC_DRC_OK);
}
/*
* samr_s_LookupDomain
*
* This is a request to map a domain name to a domain SID. We can map
* the primary domain name, our local domain name (hostname) and the
* builtin domain names to the appropriate SID. Anything else will be
* rejected.
*/
static int
{
char resource_domain[MAXHOSTNAMELEN];
char *domain_name;
char *p;
return (MLRPC_DRC_OK);
}
/*
* We should not be asked to provide
* the domain SID for the primary domain.
*/
} else {
}
if (sid) {
return (MLRPC_DRC_OK);
}
} else {
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_EnumLocalDomains
*
* This is a request for the local domains supported by this server.
* All we do here is validate the handle and set the status. The real
* work is done in samr_s_enum_local_domains.
*/
static int
{
else
if (status == NT_STATUS_SUCCESS) {
} else {
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_enum_local_domains
*
* This function should only be called via samr_s_EnumLocalDomains to
* ensure that the appropriate validation is performed. We will answer
* queries about two domains: the local domain, synonymous with the
* local hostname, and the BUILTIN domain. So we return these two
* strings.
*
* Returns NT status values.
*/
static DWORD
struct mlrpc_xaction *mxa)
{
struct samr_LocalDomainInfo *info;
struct samr_LocalDomainEntry *entry;
char *hostname;
return (NT_STATUS_NO_MEMORY);
return (NT_STATUS_NO_MEMORY);
return (NT_STATUS_NO_MEMORY);
return (NT_STATUS_NO_MEMORY);
return (NT_STATUS_SUCCESS);
}
/*
* samr_s_OpenDomain
*
* This is a request to open a domain within the local SAM database.
* The caller must supply a valid handle obtained via a successful
* connect. We return a handle to be used to access objects within
* this domain.
*/
/*ARGSUSED*/
static int
{
ms_handle_t *handle = 0;
if (!mlsvc_validate_handle(
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_OK);
}
case NT_DOMAIN_BUILTIN:
break;
case NT_DOMAIN_LOCAL:
break;
default:
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_QueryDomainInfo
*
* The caller should pass a domain handle.
*
* Windows 95 Server Manager sends requests for levels 6 and 7 when
* the services menu item is selected. Level 2 is basically for getting
* number of users, groups, and aliases in a domain.
* We have no information on what the various information levels mean.
*/
static int
{
char *hostname;
char *domain_str = "";
int rc;
return (MLRPC_DRC_OK);
}
switch (param->info_level) {
case SAMR_QUERY_DOMAIN_INFO_6:
break;
case SAMR_QUERY_DOMAIN_INFO_7:
break;
case SAMR_QUERY_DOMAIN_INFO_2:
sizeof (struct samr_QueryDomainInfo));
return (MLRPC_DRC_OK);
}
} else {
domain_str = "Builtin";
}
"", mxa);
(void) mlsvc_string_save(
"", mxa);
break;
default:
return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
};
return (MLRPC_DRC_OK);
}
/*
* samr_s_LookupNames
*
* The definition for this interface is obviously wrong but I can't
* seem to get it to work the way I think it should. It should
* support multiple name lookup but I can only get one working for now.
*/
static int
{
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_OK);
}
/*
* Windows NT returns NT_STATUS_NONE_MAPPED when the
* name is NULL.
* Windows 2000 returns STATUS_INVALID_ACCOUNT_NAME.
*/
return (MLRPC_DRC_OK);
}
&rid_type);
if (sid != 0) {
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_OK);
}
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_OpenUser
*
* This is a request to open a user within a specified domain in the
* local SAM database. The caller must supply a valid domain handle,
* obtained via a successful domain open request. The user is
* specified by the rid in the request.
*/
/*ARGSUSED*/
static int
{
if (!mlsvc_validate_handle(
return (MLRPC_DRC_OK);
}
/*
* Need QueryUserInfo(level 21).
*/
return (MLRPC_DRC_OK);
}
/*
* samr_s_DeleteUser
*
* This is a request to delete a user within a specified domain in the
* local SAM database. The caller should supply a valid user handle but
* we deny access regardless.
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_QueryUserInfo
*
* Returns:
* NT_STATUS_SUCCESS
* NT_STATUS_ACCESS_DENIED
* NT_STATUS_INVALID_INFO_CLASS
*/
/*ARGSUSED*/
static int
{
if (!mlsvc_validate_handle(
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_QueryUserGroups
*
* This is a request to obtain a list of groups of which a user is a
* member. The user is identified from the handle, which contains an
* encoded uid in the discriminator field.
*
* Get complete list of groups and check for builtin domain.
*/
static int
{
struct samr_UserGroupInfo *info;
return (MLRPC_DRC_OK);
}
} else {
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_OpenGroup
*
* This is a request to open a group within the specified domain in the
* local SAM database. The caller must supply a valid domain handle,
* obtained via a successful domain open request. The group is
* specified by the rid in the request. If this is a local RID it
* should already be encoded with type information.
*
* We return a handle to be used to access information about this group.
*/
/*ARGSUSED*/
static int
{
if (!mlsvc_validate_handle(
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_Connect
*
* This is a request to connect to the local SAM database. We don't
* support any form of update request and our database doesn't
* contain any private information, so there is little point in
* doing any access access checking here.
*
* Return a handle for use with subsequent SAM requests.
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_GetUserPwInfo
*
* This is a request to get a user's password.
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_CreateUser
*
* This is a request to create a user within a specified domain in the
* local SAM database. We always deny access.
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_ChangeUserPasswd
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_GetDomainPwInfo
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_SetUserInfo
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_OK);
}
/*
* samr_s_QueryDispInfo
*
* This function is supposed to return local users' information.
* As we don't support local users, this function dosen't send
* back any information.
*
* I added a peice of code that returns information for Administrator
* and Guest builtin users. All information are hard-coded which I get
* from packet captures. Currently, this peice of code is opt-out.
*/
/*ARGSUSED*/
static int
{
#ifdef SAMR_SUPPORT_USER
param->total_size = 0;
param->returned_size = 0;
} else {
sizeof (struct user_disp_info));
(void) mlsvc_string_save(
"Administrator", mxa);
(void) mlsvc_string_save(
mxa);
(void) mlsvc_string_save(
"Guest", mxa);
(void) mlsvc_string_save(
mxa);
}
#else
param->total_size = 0;
param->returned_size = 0;
#endif
return (MLRPC_DRC_OK);
}
/*
* samr_s_EnumDomainGroups
*
*
* This function is supposed to return local users' information.
* As we don't support local users, this function dosen't send
* back any information.
*
* I added a peice of code that returns information for a
* domain group as None. All information are hard-coded which I get
* from packet captures. Currently, this peice of code is opt-out.
*/
/*ARGSUSED*/
static int
{
param->total_size = 0;
param->returned_size = 0;
return (MLRPC_DRC_OK);
#ifdef SAMR_SUPPORT_GROUPS
param->total_size = 0;
param->returned_size = 0;
} else {
mxa, sizeof (struct group_disp_info));
(void) mlsvc_string_save(
(void) mlsvc_string_save(
"Ordinary users", mxa);
}
return (MLRPC_DRC_OK);
#endif
}
/*
* samr_s_OpenAlias
*
* Lookup for requested alias, if it exists return a handle
* for that alias. The alias domain sid should match with
* the passed domain handle.
*/
/*ARGSUSED*/
static int
{
ms_handle_desc_t *desc = 0;
goto open_alias_err;
}
goto open_alias_err;
}
if (grp == 0) {
goto open_alias_err;
}
goto open_alias_err;
}
return (MLRPC_DRC_OK);
return (MLRPC_DRC_OK);
}
/*
* samr_s_CreateDomainAlias
*
* Creates a local group in the security database, which is the
* security accounts manager (SAM)
* For more information you can look at MSDN page for NetLocalGroupAdd.
* This RPC is used by CMC and right now it returns access denied.
* The peice of code that creates a local group doesn't get compiled.
*/
/*ARGSUSED*/
static int
{
#ifdef SAMR_SUPPORT_ADD_ALIAS
ms_handle_desc_t *desc = 0;
char *alias_name;
#endif
return (MLRPC_DRC_OK);
#ifdef SAMR_SUPPORT_ADD_ALIAS
if (alias_name == 0) {
goto create_alias_err;
}
if (desc == 0 ||
goto create_alias_err;
}
/*
* Check access mask. User should be member of
* Administrators or Account Operators local group.
*/
if (status != NT_STATUS_SUCCESS)
goto create_alias_err;
goto create_alias_err;
}
return (MLRPC_DRC_OK);
return (MLRPC_DRC_OK);
#endif
}
/*
* samr_s_SetAliasInfo
*
* For more information you can look at MSDN page for NetLocalGroupSetInfo.
*/
/*ARGSUSED*/
static int
{
if (!mlsvc_validate_handle(
}
return (MLRPC_DRC_OK);
}
/*
* samr_s_QueryAliasInfo
*
* Retrieves information about the specified local group account
* by given handle.
*/
static int
{
goto query_alias_err;
}
goto query_alias_err;
}
case SAMR_QUERY_ALIAS_INFO_1:
(void) mlsvc_string_save(
(void) mlsvc_string_save(
break;
case SAMR_QUERY_ALIAS_INFO_3:
(void) mlsvc_string_save(
break;
default:
goto query_alias_err;
};
return (MLRPC_DRC_OK);
return (MLRPC_DRC_OK);
}
/*
* samr_s_DeleteDomainAlias
*
* Deletes a local group account and all its members from the
* security database, which is the security accounts manager (SAM) database.
* Only members of the Administrators or Account Operators local group can
* execute this function.
* For more information you can look at MSDN page for NetLocalGroupSetInfo.
*
* This RPC is used by CMC and right now it returns access denied.
* The peice of code that removes a local group doesn't get compiled.
*/
/*ARGSUSED*/
static int
{
#ifdef SAMR_SUPPORT_DEL_ALIAS
ms_handle_desc_t *desc = 0;
char *alias_name;
#endif
return (MLRPC_DRC_OK);
#ifdef SAMR_SUPPORT_DEL_ALIAS
goto delete_alias_err;
}
if (grp == 0) {
goto delete_alias_err;
}
if (alias_name == 0) {
goto delete_alias_err;
}
if (status != NT_STATUS_SUCCESS)
goto delete_alias_err;
return (MLRPC_DRC_OK);
return (MLRPC_DRC_OK);
#endif
}
/*
* samr_s_EnumDomainAliases
*
* This function sends back a list which contains all local groups' name.
*/
static int
{
goto enum_alias_err;
}
sid = builtin_sid;
} else {
goto enum_alias_err;
}
gi = nt_group_open_iterator();
continue;
cnt++;
}
skip = 0;
gi = nt_group_open_iterator();
continue;
info++;
}
}
return (MLRPC_DRC_OK);
return (MLRPC_DRC_OK);
}
/*
* samr_s_Connect3
*
* This is the connect3 form of the connect request. It contains an
* extra parameter over samr_Connect. See samr_s_Connect for other
* details. NT returns an RPC fault - so we can do the same for now.
* Doing it this way should avoid the unsupported opnum error message
* appearing in the log.
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
}
/*
* samr_s_Connect4
*
* This is the connect4 form of the connect request used by Windows XP.
* Returns an RPC fault for now.
*/
/*ARGSUSED*/
static int
{
return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
}
static mlrpc_stub_table_t samr_stub_table[] = {
{0}
};
/*
* There is a bug in the way that midl 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->switch_value) {
default:
return;
};
}
void
{
unsigned short size1 = 0;
unsigned short size2 = 0;
unsigned short size3 = 0;
default:
return;
};
}
void
{
unsigned short size1 = 0;
unsigned short size2 = 0;
unsigned short size3 = 0;
switch (val->switch_index) {
default:
return;
};
}
/*
* As long as there is only one entry in the union, there is no need
* to patch anything.
*/
/*ARGSUSED*/
void
{
}