/*
* 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 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Security Accounts Manager RPC (SAMR) client-side interface.
*
* The SAM is a hierarchical database:
* - If you want to talk to the SAM you need a SAM handle.
* - If you want to work with a domain, use the SAM handle.
* to obtain a domain handle.
* - Use domain handles to obtain user handles etc.
*
* Be careful about returning null handles to the application. Use of a
* null handle may crash the domain controller if you attempt to use it.
*/
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <smbsrv/libmlrpc.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/ntaccess.h>
#include <samlib.h>
mlsvc_handle_t *);
union samr_user_info *);
/*
* samr_open
*
* Wrapper round samr_connect to ensure that we connect using the server
* and domain. We default to the resource domain if the caller doesn't
* supply a server name and a domain name.
*
* If username argument is NULL, an anonymous connection will be established.
* Otherwise, an authenticated connection will be established.
*
* On success 0 is returned. Otherwise a -ve error code.
*/
{
if (!smb_domain_getinfo(&di))
return (NT_STATUS_INTERNAL_ERROR);
}
return (status);
}
/*
* samr_connect
*
* Connect to the SAMR service on the specified server (domain controller).
* New SAM connect calls have been added to Windows over time:
*
* Windows NT3.x: SamrConnect
* Windows NT4.0: SamrConnect2
* Windows 2000: SamrConnect4
* Windows XP: SamrConnect5
*
* Try the calls from most recent to oldest until the server responds with
* something other than an RPC protocol error. We don't use the original
* connect call because all supported servers should support SamrConnect2.
*/
{
};
int i;
if (status)
return (status);
for (i = 0; i < n_op; ++i) {
if (status == NT_STATUS_SUCCESS)
return (status);
}
return (status);
}
/*
* samr_connect2
*
* Connect to the SAM on a Windows NT 4.0 server (domain controller).
* We need the domain controller name and, if everything works, we
* return a handle. This function adds the double backslash prefx to
* make it easy for applications.
*
* Returns 0 on success. Otherwise returns a -ve error code.
*/
/*ARGSUSED*/
static DWORD
{
int opnum;
int len;
} else {
sizeof (ndr_hdid_t));
}
return (status);
}
/*
* samr_connect4
*
* Connect to the SAM on a Windows 2000 domain controller.
*/
/*ARGSUSED*/
static DWORD
{
int opnum;
int len;
} else {
sizeof (ndr_hdid_t));
}
return (status);
}
/*
* samr_connect5
*
* Connect to the SAM on a Windows XP domain controller. On Windows
* XP, the server should be the fully qualified DNS domain name with
* a double backslash prefix. At this point, it is assumed that we
* need to add the prefix and the DNS domain name here.
*
* If this call succeeds, a SAMR handle is placed in samr_handle and
* zero is returned. Otherwise, a -ve error code is returned.
*/
/*ARGSUSED*/
static DWORD
{
int len;
int opnum;
} else {
sizeof (ndr_hdid_t));
}
return (status);
}
/*
* samr_close_handle
*
* This is function closes any valid handle, i.e. sam, domain, user etc.
* If the handle being closed is the top level connect handle, we unbind.
* Then we zero out the handle to invalidate it.
*/
void
{
int opnum;
return;
}
/*
* samr_open_domain
*
* We use a SAM handle to obtain a handle for a domain, specified by
* the SID. The SID can be obtain via the LSA interface. A handle for
* the domain is returned in domain_handle.
*/
{
int opnum;
if (ndr_is_null_handle(samr_handle) ||
return (NT_STATUS_INVALID_PARAMETER);
}
} else {
sizeof (ndr_hdid_t));
}
if (status != NT_STATUS_SUCCESS)
return (status);
}
/*
* samr_open_user
*
* Use a domain handle to obtain a handle for a user, specified by the
* user RID. A user RID (effectively a uid) can be obtained via the
* LSA interface. A handle for the user is returned in user_handle.
* Once you have a user handle it should be possible to query the SAM
* for information on that user.
*/
{
int opnum;
return (NT_STATUS_INVALID_PARAMETER);
sizeof (ndr_hdid_t));
} else {
sizeof (ndr_hdid_t));
}
return (status);
}
/*
* samr_delete_user
*
* Delete the user specified by the user_handle.
*/
{
int opnum;
return (NT_STATUS_INVALID_PARAMETER);
sizeof (ndr_hdid_t));
} else {
status = 0;
}
return (status);
}
/*
* samr_open_group
*
* Use a domain handle to obtain a handle for a group, specified by the
* group RID. A group RID (effectively a gid) can be obtained via the
* LSA interface. A handle for the group is returned in group_handle.
* Once you have a group handle it should be possible to query the SAM
* for information on that group.
*/
int
{
int opnum;
int rc;
return (-1);
sizeof (ndr_hdid_t));
return (-1);
rc = -1;
} else {
sizeof (ndr_hdid_t));
rc = -1;
}
return (rc);
}
/*
* samr_create_user
*
* Create a user in the domain specified by the domain handle. If this
* call is successful, the server will return the RID for the user and
* a user handle, which may be used to set or query the SAM.
*
* Observed status codes:
* NT_STATUS_INVALID_PARAMETER
* NT_STATUS_INVALID_ACCOUNT_NAME
* NT_STATUS_ACCESS_DENIED
* NT_STATUS_USER_EXISTS
*
* Returns 0 on success. Otherwise returns an NT status code.
*/
{
int opnum;
int rc;
if (ndr_is_null_handle(domain_handle) ||
return (NT_STATUS_INVALID_PARAMETER);
}
sizeof (ndr_hdid_t));
if (rc != 0) {
if (status != NT_STATUS_USER_EXISTS) {
smb_tracef("SamrCreateUser[%s]: %s",
}
} else {
sizeof (ndr_hdid_t));
else
status = 0;
}
return (status);
}
/*
* samr_lookup_domain
*
* Lookup up the domain SID for the specified domain name. The handle
* should be one returned from samr_connect. The allocated memory for
* the returned SID must be freed by caller.
*/
{
int opnum;
return (NULL);
sizeof (samr_handle_t));
length += sizeof (smb_wchar_t);
return (domsid);
}
/*
* samr_enum_local_domains
*
* Get the list of local domains supported by a server.
*
* Returns NT status codes.
*/
{
int opnum;
return (NT_STATUS_INVALID_PARAMETER);
sizeof (samr_handle_t));
arg.enum_context = 0;
} else {
/*
* Handle none-mapped status quietly.
*/
if (status != NT_STATUS_NONE_MAPPED)
}
return (status);
}
/*
* samr_lookup_domain_names
*
* Lookup up the given name in the domain specified by domain_handle.
* Upon a successful lookup the information is returned in the account
* arg and caller must free allocated memories by calling smb_account_free().
*
* Returns NT status codes.
*/
{
int opnum;
if (ndr_is_null_handle(domain_handle) ||
return (NT_STATUS_INVALID_PARAMETER);
}
sizeof (samr_handle_t));
length += sizeof (smb_wchar_t);
/*
* Handle none-mapped status quietly.
*/
if (status != NT_STATUS_NONE_MAPPED)
} else {
}
return (status);
}
/*
* samr_query_user_info
*
* Query information on a specific user. The handle must be a valid
* user handle obtained via samr_open_user.
*
* Returns 0 on success, otherwise returns NT status code.
*/
union samr_user_info *user_info)
{
int opnum;
return (NT_STATUS_INTERNAL_ERROR);
sizeof (samr_handle_t));
}
/*
* samr_setup_user_info
*
* Private function to set up the samr_user_info data. Dependent on
* the switch value this function may use strdup which will malloc
* memory. The caller is responsible for deallocating this memory.
*
* Returns 0 on success, otherwise returns -1.
*/
static int
{
switch (switch_value) {
case 1:
return (0);
case 6:
return (0);
case 7:
return (0);
case 8:
return (0);
case 9:
return (0);
case 16:
return (0);
default:
break;
};
return (-1);
}
/*
* samr_query_user_groups
*
* Query the groups for a specific user. The handle must be a valid
* user handle obtained via samr_open_user. The list of groups is
* returned in group_info. Note that group_info->groups is allocated
* using malloc. The caller is responsible for deallocating this
* memory when it is no longer required. If group_info->n_entry is 0
* then no memory was allocated.
*
* Returns 0 on success, otherwise returns -1.
*/
int
struct samr_UserGroups **groups)
{
int opnum;
int rc;
int nbytes;
return (-1);
sizeof (samr_handle_t));
if (rc == 0) {
rc = -1;
} else {
sizeof (struct samr_UserGroups);
*n_groups = 0;
rc = -1;
} else {
}
}
}
return (rc);
}
/*
* samr_get_user_pwinfo
*
* Get some user password info. I'm not sure what this is yet but it is
* part of the create user sequence. The handle must be a valid user
* handle. Since I don't know what this is returning, I haven't provided
* any return data yet.
*
* Returns 0 on success. Otherwise returns an NT status code.
*/
{
int opnum;
return (NT_STATUS_INVALID_PARAMETER);
sizeof (samr_handle_t));
} else {
status = 0;
}
return (status);
}
/*
* samr_set_user_info
*
* Returns 0 on success. Otherwise returns an NT status code.
* NT status codes observed so far:
* NT_STATUS_WRONG_PASSWORD
*/
int info_level,
void *info_buf)
{
int opnum;
return (NT_STATUS_INTERNAL_ERROR);
/*
* Only support a few levels
* MS-SAMR: UserInternal4Information
*/
switch (info_level) {
case 16: /* samr_SetUserInfo16 */
usize = sizeof (struct samr_SetUserInfo16);
break;
case 21: /* samr_SetUserInfo21 */
usize = sizeof (struct samr_SetUserInfo21);
break;
case 23: /* samr_SetUserInfo23 */
usize = sizeof (struct samr_SetUserInfo23);
break;
case 24: /* samr_SetUserInfo24 */
usize = sizeof (struct samr_SetUserInfo24);
break;
default:
return (NT_STATUS_INVALID_LEVEL);
}
/*
* OK, now this gets really ugly, because
* ndrgen doesn't do unions correctly.
*/
sizeof (samr_handle_t));
}
/*
* Client side wrapper for SamrUnicodeChangePasswordUser2
* [MS-SAMR 3.1.5.10.3]
*/
char *server,
char *account,
struct samr_encr_passwd *newpw,
struct samr_encr_hash *oldpw)
{
char *slashserver;
int len;
/* Need server name with slashes */
if (slashserver == NULL)
return (NT_STATUS_NO_MEMORY);
return (NT_STATUS_NO_MEMORY);
if (len < 1)
return (NT_STATUS_INVALID_PARAMETER);
return (NT_STATUS_NO_MEMORY);
if (len < 1)
return (NT_STATUS_INVALID_PARAMETER);
}