ndr_server.c revision 44994d75036fba0ed84f658da8346ea5305ffcca
/*
* 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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Server side RPC handler.
*/
#include <sys/byteorder.h>
#include <thread.h>
#include <synch.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <time.h>
#include <smbsrv/libmlrpc.h>
#include <smbsrv/mlsvc_util.h>
#include <smbsrv/smb_winpipe.h>
/*
* Fragment size (5680: NT style).
*/
#define MLRPC_FRAG_SZ 5680
static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ;
/*
* Context table.
*/
#define CTXT_TABLE_ENTRIES 128
static mutex_t mlrpc_context_lock;
static int mlrpc_s_process(struct mlrpc_xaction *);
static int mlrpc_s_bind(struct mlrpc_xaction *);
static int mlrpc_s_request(struct mlrpc_xaction *);
static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *);
static int mlrpc_s_alter_context(struct mlrpc_xaction *);
static void mlrpc_reply_bind_ack(struct mlrpc_xaction *);
static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long);
static int mlrpc_build_reply(struct mlrpc_xaction *);
/*
* This is the RPC service server-side entry point. All MSRPC encoded
* messages should be passed through here. We use the same context
* structure as the client side but we don't need to set up the client
* side info.
*/
struct mlsvc_rpc_context *
{
struct mlsvc_rpc_context *context;
struct mlrpc_xaction *mxa;
struct mlndr_stream *recv_mlnds;
struct mlndr_stream *send_mlnds;
char *data;
int datalen;
return (NULL);
return (NULL);
return (NULL);
}
(void) mlrpc_s_process(mxa);
SMB_CTXT_PIPE_SZ - sizeof (smb_pipe_t));
return (context);
}
/*
* Lookup the context for pipeid. If one exists, return a pointer to it.
* Otherwise attempt to allocate a new context and return it. If the
* context table is full, return a null pointer.
*/
struct mlsvc_rpc_context *
mlrpc_lookup(int fid)
{
struct mlsvc_rpc_context *context;
int i;
(void) mutex_lock(&mlrpc_context_lock);
for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
context = &context_table[i];
continue;
}
(void) mutex_unlock(&mlrpc_context_lock);
return (context);
}
}
if (available) {
(void) mutex_unlock(&mlrpc_context_lock);
return (NULL);
}
}
(void) mutex_unlock(&mlrpc_context_lock);
return (available);
}
/*
* This function should be called to release the context associated
* with a fid when the client performs a close file.
*/
void
mlrpc_release(int fid)
{
struct mlsvc_rpc_context *context;
int i;
(void) mutex_lock(&mlrpc_context_lock);
for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
context = &context_table[i];
break;
}
}
(void) mutex_unlock(&mlrpc_context_lock);
}
/*
* This is the entry point for all server-side RPC processing.
* It is assumed that the PDU has already been received.
*/
static int
{
int rc;
if (!MLRPC_DRC_IS_OK(rc))
return (-1);
(void) mlrpc_reply_prepare_hdr(mxa);
case MLRPC_PTYPE_BIND:
break;
case MLRPC_PTYPE_REQUEST:
break;
break;
default:
break;
}
if (MLRPC_DRC_IS_FAULT(rc))
(void) mlrpc_build_reply(mxa);
return (rc);
}
/*
* Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
* p_results[] not supported.
*/
static int
{
unsigned p_cont_id;
struct mlrpc_binding *mbind;
char as_buf[64];
char ts_buf[64];
int as_vers;
int ts_vers;
struct mlndr_stream *send_mlnds;
struct mlrpc_service *msvc;
int rc;
/* acquire targets */
/*
* Set up temporary secondary address port.
* We will correct this later (below).
*/
result_list->reserved = 0;
result_list->reserved2 = 0;
/* sanity check */
mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem");
}
/*
* Duplicate p_cont_id.
* Send a bind_ack with a better error.
*/
mlndo_trace("mlrpc_s_bind: duplicate binding");
return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
}
/*
* No free binding slot
*/
mlndo_trace("mlrpc_s_bind: no resources");
return (MLRPC_DRC_OK);
}
if (!msvc) {
return (MLRPC_DRC_OK);
}
/*
* We can now use the correct secondary address port.
*/
/* mbind->context set by app */
mbind->instance_specific = 0;
/*
* Call the service-specific bind() handler. If
* this fails, we shouild send a specific error
* on the bind ack.
*/
if (MLRPC_DRC_IS_FAULT(rc)) {
mbind->which_side = 0;
mbind->instance_specific = 0;
return (rc);
}
}
/*
* Special rejection of Windows 2000 DSSETUP interface.
* This interface was introduced in Windows 2000 but has
* been subsequently deprecated due to problems.
*/
}
return (MLRPC_DRC_BINDING_MADE);
}
/*
* mlrpc_s_alter_context
*
* The alter context request is used to request additional presentation
* bind request.
*
* We don't fully support multiple contexts so, for now, we reject this
* request. Windows 2000 clients attempt to use an alternate LSA context
* when ACLs are modified.
*/
static int
{
struct mlrpc_binding *mbind;
struct mlrpc_service *msvc;
unsigned p_cont_id;
int as_vers;
int ts_vers;
result_list->reserved = 0;
result_list->reserved2 = 0;
return (MLRPC_DRC_OK);
}
return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
return (MLRPC_DRC_OK);
}
if (msvc == 0) {
return (MLRPC_DRC_OK);
}
/* mbind->context set by app */
mbind->instance_specific = 0;
return (MLRPC_DRC_BINDING_MADE);
}
static int
{
struct mlrpc_binding *mbind;
struct mlrpc_service *msvc;
unsigned p_cont_id;
int rc;
return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID);
/*
* Make room for the response hdr.
*/
else
if (MLRPC_DRC_IS_FAULT(rc)) {
mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
}
return (rc);
}
/*
* The transaction and the two mlnds streams use the same heap, which
* should already exist at this point. The heap will also be available
* to the stub.
*/
int
{
struct mlrpc_stub_table *ste;
char *param;
int rc;
return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
}
mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
}
return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
if (!MLRPC_DRC_IS_OK(rc))
return (rc);
if (rc == MLRPC_DRC_OK)
return (rc);
}
/*
* We can perform some initial setup of the response header here.
* We also need to cache some of the information from the bind
* negotiation for use during subsequent RPC calls.
*/
static void
{
hdr->rpc_vers_minor = 0;
hdr->frag_length = 0;
hdr->auth_length = 0;
#ifdef _BIG_ENDIAN
#else
#endif
case MLRPC_PTYPE_BIND:
/*
* Save the maximum fragment sizes
* for use with subsequent requests.
*/
break;
case MLRPC_PTYPE_REQUEST:
/* mxa->send_hdr.response_hdr.alloc_hint */
break;
/*
* The max_xmit_frag, max_recv_frag
* and assoc_group_id are ignored.
*/
break;
default:
}
}
/*
* Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header.
* The frag_length is different from a regular RPC response.
*/
static void
{
}
/*
* Signal an RPC fault. The stream is reset and we overwrite whatever
* was in the response header with the fault information.
*/
static void
{
unsigned long fault_status;
hdr->rpc_vers_minor = 0;
hdr->auth_length = 0;
#ifdef _BIG_ENDIAN
#else
#endif
switch (drc & MLRPC_DRC_MASK_SPECIFIER) {
break;
break;
break;
break;
default:
break;
}
}
static int
{
unsigned long pdu_size;
unsigned long frag_size;
unsigned long pdu_data_size;
unsigned long frag_data_size;
/*
* Single fragment response. The PDU size may be zero
* here (i.e. bind or fault response). So don't make
* any assumptions about it until after the header is
* encoded.
*/
case MLRPC_PTYPE_BIND_ACK:
break;
case MLRPC_PTYPE_FAULT:
/* already setup */
break;
case MLRPC_PTYPE_RESPONSE:
break;
default:
break;
}
mlnds->pdu_scan_offset = 0;
(void) mlrpc_encode_pdu_hdr(mxa);
return (0);
}
/*
* Multiple fragment response.
*/
mlnds->pdu_scan_offset = 0;
(void) mlrpc_encode_pdu_hdr(mxa);
/*
* We need to update the 24-byte header in subsequent fragments.
*
* pdu_data_size: total data remaining to be handled
* frag_size: total fragment size including header
* frag_data_size: data in fragment
* (i.e. frag_size - MLRPC_RSP_HDR_SIZE)
*/
while (pdu_data_size) {
if (pdu_data_size <= frag_data_size) {
} else {
}
mlnds->pdu_scan_offset = 0;
(void) mlrpc_encode_pdu_hdr(mxa);
break;
}
return (0);
}
/*
* mlrpc_build_frag
*
* Build an RPC PDU fragment from the specified buffer.
* and report an error.
*/
static void
{
return;
} else {
}
}