mlsvc_sam.c revision 8d7e41661dc4633488e93b13363137523ce59977
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Security Accounts Manager RPC (SAMR) interface definition.
*/
#include <strings.h>
#include <unistd.h>
#include <netdb.h>
#include <assert.h>
#include <pwd.h>
#include <grp.h>
#include <smbsrv/libmlrpc.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/ntstatus.h>
#include <samlib.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 wire so security shouldn't
* be an issue.
*/
typedef enum {
SAMR_KEY_NULL = 0,
} samr_key_t;
typedef struct samr_keydata {
/*
* DomainDisplayUser All user objects (or those derived from user) with
* userAccountControl containing the UF_NORMAL_ACCOUNT bit.
*
* DomainDisplayMachine All user objects (or those derived from user) with
* userAccountControl containing the
* UF_WORKSTATION_TRUST_ACCOUNT or UF_SERVER_TRUST_ACCOUNT
* bit.
*
* DomainDisplayGroup All group objects (or those derived from group) with
* groupType equal to GROUP_TYPE_SECURITY_UNIVERSAL or
* GROUP_TYPE_SECURITY_ACCOUNT.
*
* DomainDisplayOemUser Same as DomainDisplayUser with OEM strings
*
* DomainDisplayOemGroup Same as DomainDisplayGroup with OEM strings
*/
typedef enum {
DomainDisplayUser = 1,
#define SAMR_VALID_DISPLEVEL(lvl) \
DWORD);
ndr_xa_t *);
static ndr_stub_table_t samr_stub_table[];
static ndr_service_t samr_service = {
"SAMR", /* name */
"Security Accounts Manager", /* desc */
"\\samr", /* endpoint */
PIPE_LSASS, /* sec_addr_port */
"12345778-1234-abcd-ef00-0123456789ac", 1, /* abstract */
0, /* no bind_instance_size */
NULL, /* no bind_req() */
NULL, /* no unbind_and_close() */
samr_call_stub, /* 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) ndr_svc_register(&samr_service);
}
/*
* Custom call_stub to set the stream string policy.
*/
static int
{
return (ndr_generic_call_stub(mxa));
}
/*
* Handle allocation wrapper to setup the local context.
*/
static ndr_hdid_t *
{
return (NULL);
}
/*
* Handle deallocation wrapper to free the local context.
*/
static void
{
}
}
/*
* Handle lookup wrapper to validate the local context.
*/
static ndr_handle_t *
{
return (NULL);
return (NULL);
return (NULL);
return (hd);
}
/*
* 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.
*/
static int
{
ndr_hdid_t *id;
if (id) {
} else {
}
return (NDR_DRC_OK);
}
/*
* samr_s_CloseHandle
*
* Close the SAM interface specified by the handle.
* Free the handle and zero out the result handle for the client.
*/
static int
{
return (NDR_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[SMB_PI_MAX_DOMAIN];
char *domain_name;
return (NDR_DRC_OK);
}
/*
* We should not be asked to provide
* the domain SID for the primary domain.
*/
} else {
}
if (sid) {
return (NDR_DRC_OK);
}
} else {
}
return (NDR_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 (NDR_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 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 connect handle.
* We return a handle to be used to access objects within this domain.
*/
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
if (id) {
} else {
}
return (NDR_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
{
struct samr_QueryDomainInfoRes *info;
char *domain;
char hostname[NETBIOS_NAME_SZ];
int rc = 0;
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
case NT_DOMAIN_BUILTIN:
domain = "BUILTIN";
user_cnt = 0;
break;
case NT_DOMAIN_LOCAL:
if (rc == 0) {
user_cnt = smb_pwd_num();
}
break;
default:
return (NDR_DRC_OK);
}
if (rc != 0) {
return (NDR_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:
break;
default:
return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
};
return (NDR_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
{
int rc;
/*
* Windows NT returns NT_STATUS_NONE_MAPPED.
* Windows 2000 returns STATUS_INVALID_ACCOUNT_NAME.
*/
}
if (status != NT_STATUS_SUCCESS) {
return (NDR_DRC_OK);
}
case NT_DOMAIN_BUILTIN:
return (NDR_DRC_OK);
}
break;
case NT_DOMAIN_LOCAL:
if (rc == SMB_LGRP_SUCCESS) {
smb_lgrp_free(&grp);
return (NDR_DRC_OK);
}
&sid) == IDMAP_SUCCESS) {
return (NDR_DRC_OK);
}
}
break;
default:
return (NDR_DRC_OK);
}
return (NDR_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.
*/
static int
{
return (NDR_DRC_OK);
}
} else {
/*
* Need QueryUserInfo(level 21).
*/
}
return (NDR_DRC_OK);
}
/*
* samr_s_DeleteUser
*
* Request to delete a user within a specified domain in the local
* SAM database. The caller should supply a valid user handle.
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_QueryUserInfo
*
* The caller should provide a valid user key.
*
* Returns:
* NT_STATUS_SUCCESS
* NT_STATUS_ACCESS_DENIED
* NT_STATUS_INVALID_INFO_CLASS
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_QueryUserGroups
*
* Request the list of groups of which a user is a member.
* The user is identified from the handle, which contains an
* rid in the discriminator field. Note that this is a local user.
*/
static int
{
struct samr_UserGroupInfo *info;
struct samr_UserGroups *group;
int size;
int ngrp_max;
goto query_error;
}
case NT_DOMAIN_BUILTIN:
goto query_error;
}
break;
case NT_DOMAIN_LOCAL:
break;
default:
goto query_error;
}
goto query_error;
}
goto query_error;
}
goto query_error;
}
goto query_error;
}
group++;
}
smb_lgrp_free(&grp);
}
return (NDR_DRC_OK);
return (NDR_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.
*/
static int
{
return (NDR_DRC_OK);
}
if (id) {
} else {
}
return (NDR_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.
*/
static int
{
ndr_hdid_t *id;
if (id) {
} else {
}
return (NDR_DRC_OK);
}
/*
* samr_s_GetUserPwInfo
*
* This is a request to get a user's password.
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_CreateUser
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_ChangeUserPasswd
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_GetDomainPwInfo
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_SetUserInfo
*/
/*ARGSUSED*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_QueryDispInfo
*
* This function currently return local users' information only.
* This RPC is called repeatedly until all the users info are
* retrieved.
*
* The total count and the returned count are returned as total size
* and returned size. The client doesn't seem to care.
*/
static int
{
struct user_acct_info *user;
int num_users;
int ret_cnt;
goto error;
}
goto error;
}
goto error;
}
case NT_DOMAIN_BUILTIN:
goto no_info;
case NT_DOMAIN_LOCAL:
num_users = smb_pwd_num();
goto no_info;
ret_cnt * sizeof (struct user_acct_info));
goto error;
}
goto no_info;
continue;
goto error;
}
user++;
ret_cnt++;
}
break;
default:
goto error;
}
return (NDR_DRC_OK);
return (NDR_DRC_OK);
return (NDR_DRC_OK);
}
/*
* samr_s_EnumDomainGroups
*
*
* This function is supposed to return local group information.
* As we don't support local users, this function dosen't send
* back any information.
*
* Added template that returns information for a domain group as None.
* All information is hard-coded from packet captures.
*/
static int
{
param->total_size = 0;
param->returned_size = 0;
return (NDR_DRC_OK);
#ifdef SAMR_SUPPORT_GROUPS
param->total_size = 0;
param->returned_size = 0;
} else {
mxa, sizeof (struct group_disp_info));
}
return (NDR_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.
*/
static int
{
int rc;
goto open_alias_err;
}
goto open_alias_err;
}
if (rc != SMB_LGRP_SUCCESS) {
goto open_alias_err;
}
if (id) {
return (NDR_DRC_OK);
}
return (NDR_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
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
#ifdef SAMR_SUPPORT_ADD_ALIAS
char *alias_name;
if (alias_name == 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 (NDR_DRC_OK);
return (NDR_DRC_OK);
#endif
}
/*
* samr_s_SetAliasInfo
*
* Similar to NetLocalGroupSetInfo.
*/
static int
{
return (NDR_DRC_OK);
}
/*
* samr_s_QueryAliasInfo
*
* Retrieves information about the specified local group account
* by given handle.
*/
static int
{
int rc;
goto query_alias_err;
}
&grp);
if (rc != SMB_LGRP_SUCCESS) {
goto query_alias_err;
}
case SAMR_QUERY_ALIAS_INFO_1:
break;
case SAMR_QUERY_ALIAS_INFO_3:
break;
default:
smb_lgrp_free(&grp);
goto query_alias_err;
};
smb_lgrp_free(&grp);
return (NDR_DRC_OK);
return (NDR_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.
*/
static int
{
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
#ifdef SAMR_SUPPORT_DEL_ALIAS
char *alias_name;
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 (NDR_DRC_OK);
return (NDR_DRC_OK);
#endif
}
/*
* samr_s_EnumDomainAliases
*
* This function sends back a list which contains all local groups' name.
*/
static int
{
return (NDR_DRC_OK);
}
sizeof (struct aliases_info));
return (NDR_DRC_OK);
}
param->out_resume = 0;
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
skip = i = 0;
info++;
}
smb_lgrp_free(&grp);
}
param->out_resume = i;
return (NDR_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 (NDR_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 (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
}
static ndr_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;
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
{
}