/*
* 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 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Client NDR RPC interface.
*/
#include <time.h>
#include <strings.h>
#include <assert.h>
#include <errno.h>
#include <thread.h>
#include <unistd.h>
#include <syslog.h>
#include <synch.h>
#include <netsmb/smbfs_api.h>
#include <smbsrv/libsmbns.h>
#include <smbsrv/libmlrpc.h>
#include <smbsrv/libmlsvc.h>
#include <libsmbrdr.h>
#include <mlsvc.h>
static void ndr_xa_release(ndr_client_t *);
/*
* This call must be made to initialize an RPC client structure and bind
* to the remote service before any RPCs can be exchanged with that service.
*
* The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
* with the client context for an instance of the interface. The handle
* is zeroed to ensure that it doesn't look like a valid handle -
* handle content is provided by the remove service.
*
* The client points to this top-level handle so that we know when to
* unbind and teardown the connection. As each handle is initialized it
* will inherit a reference to the client context.
*
* Returns 0 or an NT_STATUS:
* NT_STATUS_BAD_NETWORK_PATH (get server addr)
* NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
* NT_STATUS_BAD_NETWORK_NAME (tcon, open)
* NT_STATUS_ACCESS_DENIED (open pipe)
* NT_STATUS_INVALID_PARAMETER (rpc bind)
*
* NT_STATUS_INTERNAL_ERROR (bad args etc)
* NT_STATUS_NO_MEMORY
*/
{
int rc;
return (NT_STATUS_INTERNAL_ERROR);
/* In case the service was not registered... */
return (NT_STATUS_INTERNAL_ERROR);
/*
* Set the default based on the assumption that most
* servers will be Windows 2000 or later. This used to
* try to get the actual server version, but that RPC
* is not necessarily allowed anymore, so don't bother.
*/
svinfo.sv_version_minor = 0;
/*
* Some callers pass this when they want a NULL session.
* Todo: have callers pass an empty string for that.
*/
username = "";
/*
* Setup smbfs library handle, authenticate, connect to
* the IPC$ share. This will reuse an existing connection
* if the driver already has one for this combination of
* server, user, domain. It may return any of:
* NT_STATUS_BAD_NETWORK_PATH (get server addr)
* NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
* NT_STATUS_BAD_NETWORK_NAME (tcon)
*/
if (status != NT_STATUS_SUCCESS) {
"(Srv=%s Dom=%s User=%s), %s (0x%x)",
/* Tell the DC Locator this DC failed. */
goto errout;
}
/*
* Open the named pipe.
*/
if (fd < 0) {
"smb_fh_open (%s) err=%d",
switch (rc) {
case EACCES:
break;
default:
break;
}
goto errout;
}
/*
* Setup the RPC client handle.
*/
goto errout;
}
goto errout;
}
/*
* Fill in the caller's handle.
*/
/*
* Do the OtW RPC bind.
*/
switch (rc) {
break;
case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */
break;
default:
if (NDR_DRC_IS_FAULT(rc)) {
break;
}
/* FALLTHROUGH */
case NDR_DRC_OK:
return (NT_STATUS_SUCCESS);
}
"ndr_clnt_bind, %s (0x%x)",
}
if (fd != -1)
(void) smb_fh_close(fd);
}
return (status);
}
/*
* Unbind and close the pipe to an RPC service.
*
* If the heap has been preserved we need to go through an xa release.
* The heap is preserved during an RPC call because that's where data
* returned from the server is stored.
*
* Otherwise we destroy the heap directly.
*/
void
{
if (clnt->heap_preserved)
else
}
/*
* Call the RPC function identified by opnum. The remote service is
* identified by the handle, which should have been initialized by
* ndr_rpc_bind.
*
* If the RPC call is successful (returns 0), the caller must call
* ndr_rpc_release to release the heap. Otherwise, we release the
* heap here.
*/
int
{
int rc;
return (-1);
/*
* Always clear the nonull flag to ensure
* it is not applied to subsequent calls.
*/
if (NDR_DRC_IS_FAULT(rc)) {
return (-1);
}
return (0);
}
/*
* Outgoing strings should not be null terminated.
*/
void
{
}
/*
* Return a reference to the server info.
*/
const srvsvc_server_info_t *
{
}
/*
* Return the RPC server OS level.
*/
{
}
/*
* Get the session key from a bound RPC client handle.
*
* The key returned is the 16-byte "user session key"
* established by the underlying authentication protocol
* (either Kerberos or NTLM). This key is needed for
* SAM RPC calls such as SamrSetInformationUser, etc.
* See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
*
* Returns zero (success) or an errno.
*/
int
{
int rc;
return (EINVAL);
return (rc);
}
void *
{
return (NULL);
}
{
}
/*
* Must be called by RPC clients to free the heap after a successful RPC
* call, i.e. ndr_rpc_call returned 0. The caller should take a copy
* of any data returned by the RPC prior to calling this function because
* returned data is in the heap.
*/
void
{
if (clnt->heap_preserved)
else
}
/*
* Returns true if the handle is null.
* Otherwise returns false.
*/
{
return (B_TRUE);
return (B_TRUE);
return (B_FALSE);
}
/*
* Returns true if the handle is the top level bind handle.
* Otherwise returns false.
*/
{
}
/*
* Pass the client reference from parent to child.
*/
void
{
}
void
{
char *s = "unknown";
switch (NT_SC_SEVERITY(status)) {
s = "success";
break;
s = "info";
break;
s = "warning";
break;
case NT_STATUS_SEVERITY_ERROR:
s = "error";
break;
}
if (handle) {
}
smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
}
/*
* The following functions provide the client callback interface.
* If the caller hasn't provided a heap, create one here.
*/
static int
{
int rc;
return (-1);
}
if (rc == 0)
if (rc != 0) {
return (-1);
}
return (0);
}
/*
* This is the entry pointy for an RPC client call exchange with
* a server, which will result in an smbrdr SmbTransact request.
*
* SmbTransact should return the number of bytes received, which
* we record as the PDU size, or a negative error code.
*/
static int
{
if (err) {
return (-1);
}
return (0);
}
/*
* This entry point will be invoked if the xa-exchange response contained
* only the first fragment of a multi-fragment response. The RPC client
* code will then make repeated xa-read requests to obtain the remaining
* fragments, which will result in smbrdr SmbReadX requests.
*
* SmbReadX should return the number of bytes received, in which case we
* expand the PDU size to include the received data, or a negative error
* code.
*/
static int
{
int len;
int nbytes;
return (-1);
if (nbytes < 0)
return (-1);
return (-1);
}
return (nbytes);
}
/*
* Preserve the heap so that the client application has access to data
* returned from the server after an RPC call.
*/
static void
{
}
/*
* Dispose of the transaction streams. If the heap has not been
* preserved, we can destroy it here.
*/
static void
{
if (!clnt->heap_preserved) {
}
}
/*
* Dispose of a preserved heap.
*/
static void
{
if (clnt->heap_preserved) {
}
}
/*
* Compare the time here with the remote time on the server
* and report clock skew.
*/
void
{
int priority;
return;
}
else
if (tdiff != 0) {
}
}