/*
* 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
*/
/*
*/
/*
* 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>
static int ndr_pipe_process(ndr_pipe_t *);
static ndr_pipe_t *ndr_pipe_lookup(int);
static void ndr_pipe_release(ndr_pipe_t *);
static ndr_pipe_t *ndr_pipe_allocate(int);
static void ndr_pipe_deallocate(ndr_pipe_t *);
static void ndr_pipe_rewind(ndr_pipe_t *);
static void ndr_pipe_flush(ndr_pipe_t *);
static int ndr_svc_process(ndr_xa_t *);
static int ndr_svc_defrag(ndr_xa_t *);
static int ndr_svc_bind(ndr_xa_t *);
static int ndr_svc_request(ndr_xa_t *);
static void ndr_reply_prepare_hdr(ndr_xa_t *);
static int ndr_svc_alter_context(ndr_xa_t *);
static void ndr_reply_fault(ndr_xa_t *, unsigned long);
static int ndr_build_reply(ndr_xa_t *);
/*
* Allocate and associate a service context with a fid.
*/
int
{
(void) mutex_lock(&ndr_pipe_lock);
(void) mutex_unlock(&ndr_pipe_lock);
return (EEXIST);
}
(void) mutex_unlock(&ndr_pipe_lock);
return (ENOMEM);
}
(void) mutex_unlock(&ndr_pipe_lock);
return (EINVAL);
}
(void) mutex_unlock(&ndr_pipe_lock);
return (0);
}
/*
* Release the context associated with a fid when an opipe is closed.
*/
int
{
(void) mutex_lock(&ndr_pipe_lock);
(void) mutex_unlock(&ndr_pipe_lock);
return (ENOENT);
}
/*
* Release twice: once for the lookup above
* and again to close the fid.
*/
(void) mutex_unlock(&ndr_pipe_lock);
return (0);
}
/*
* Write RPC request data to the input stream. Input data is buffered
* until the response is requested.
*/
int
{
int rc;
if (len == 0)
return (0);
(void) mutex_lock(&ndr_pipe_lock);
(void) mutex_unlock(&ndr_pipe_lock);
return (ENOENT);
}
(void) mutex_unlock(&ndr_pipe_lock);
return (rc);
}
(void) mutex_unlock(&ndr_pipe_lock);
}
/*
* Read RPC response data.
*/
int
{
if (nbytes == 0) {
*resid = 0;
return (0);
}
(void) mutex_lock(&ndr_pipe_lock);
(void) mutex_unlock(&ndr_pipe_lock);
return (ENOENT);
}
(void) mutex_unlock(&ndr_pipe_lock);
if (*resid == 0) {
/*
* Nothing left, cleanup the output stream.
*/
}
(void) mutex_lock(&ndr_pipe_lock);
(void) mutex_unlock(&ndr_pipe_lock);
return (0);
}
/*
* If the input stream contains an RPC request, process the RPC transaction,
* which will place the RPC response in the output (frags) stream.
*
* arg is freed here; it must have been allocated by malloc().
*/
void *
{
return (NULL);
(void) mutex_lock(&ndr_pipe_lock);
(void) mutex_unlock(&ndr_pipe_lock);
(void) smb_kmod_event_notify(fid);
return (NULL);
}
(void) mutex_unlock(&ndr_pipe_lock);
if (ndr_pipe_process(np) != 0)
(void) mutex_lock(&ndr_pipe_lock);
(void) mutex_unlock(&ndr_pipe_lock);
(void) smb_kmod_event_notify(fid);
return (NULL);
}
/*
* Process a server-side RPC request.
*/
static int
{
char *data;
int datalen;
int rc;
if (datalen == 0)
return (0);
return (ENOMEM);
return (ENOMEM);
}
if (rc != 0) {
return (ENOMEM);
}
/*
* Copy the input data and reset the input stream.
*/
if (rc != 0) {
return (ENOMEM);
}
(void) ndr_svc_process(mxa);
return (0);
}
/*
* Must be called with ndr_pipe_lock held.
*/
static ndr_pipe_t *
{
int i;
for (i = 0; i < NDR_PIPE_MAX; ++i) {
np = &ndr_pipe_table[i];
return (NULL);
return (np);
}
}
return (NULL);
}
/*
* Must be called with ndr_pipe_lock held.
*/
static void
{
}
/*
* Must be called with ndr_pipe_lock held.
*/
static ndr_pipe_t *
{
int i;
for (i = 0; i < NDR_PIPE_MAX; ++i) {
np = &ndr_pipe_table[i];
return (NULL);
return (np);
}
}
return (NULL);
}
/*
* If the desired space exceeds the current pipe size, try to expand
* the pipe. Leave the current pipe intact if the realloc fails.
*
* Must be called with ndr_pipe_lock held.
*/
static int
{
char *newbuf;
return (0);
if (required > NDR_PIPE_BUFMAX) {
smb_tracef("ndr_pipe_grow: required=%d, max=%d (ENOSPC)",
return (ENOSPC);
}
if (required > NDR_PIPE_BUFMAX)
smb_tracef("ndr_pipe_grow: realloc failed (ENOMEM)");
return (ENOMEM);
}
return (0);
}
/*
* Must be called with ndr_pipe_lock held.
*/
static void
{
/*
* Ensure that there are no RPC service policy handles
* (associated with this fid) left around.
*/
}
}
/*
* Rewind the input data stream, ready for the next write.
*/
static void
{
}
/*
* Flush the output data stream.
*/
static void
{
}
}
/*
* Check whether or not the specified user has administrator privileges,
* i.e. is a member of Domain Admins or Administrators.
* Returns true if the user is an administrator, otherwise returns false.
*/
{
}
/*
* Check whether or not the specified user has power-user privileges,
* i.e. is a member of Domain Admins, Administrators or Power Users.
* This is typically required for operations such as managing shares.
* Returns true if the user is a power user, otherwise returns false.
*/
{
}
{
return (ctx->ui_native_os);
}
/*
* This is the entry point for all server-side RPC processing.
* It is assumed that the PDU has already been received.
*/
static int
{
unsigned long saved_offset;
unsigned long saved_size;
int rc;
if (!NDR_DRC_IS_OK(rc))
return (-1);
(void) ndr_reply_prepare_hdr(mxa);
case NDR_PTYPE_BIND:
break;
case NDR_PTYPE_REQUEST:
goto ndr_svc_process_fault;
}
/*
* Multi-fragment request. Preserve the PDU scan
* offset and size during defrag so that we can
* continue as if we had received contiguous data.
*/
if (NDR_DRC_IS_FAULT(rc)) {
goto ndr_svc_process_fault;
}
}
break;
case NDR_PTYPE_ALTER_CONTEXT:
break;
default:
break;
}
if (NDR_DRC_IS_FAULT(rc))
(void) ndr_build_reply(mxa);
return (rc);
}
/*
* Remove RPC fragment headers from the received data stream.
* The first fragment has already been accounted for before this call.
*
* NDR stream on entry:
*
* |<-- frag 2 -->|<-- frag 3 -->| ... |<- last frag ->|
*
* +-----+--------+-----+--------+-----+-----+---------+
* | hdr | data | hdr | data | ... | hdr | data |
* +-----+--------+-----+--------+-----+-----+---------+
*
* NDR stream on return:
*
* +----------------------------------+
* | data |
* +----------------------------------+
*/
static int
{
int frag_size;
int last_frag;
do {
return (NDR_DRC_FAULT_DECODE_FAILED);
return (NDR_DRC_FAULT_DECODE_FAILED);
} while (!last_frag);
return (NDR_DRC_OK);
}
/*
* Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
* p_results[] not supported.
*/
static int
{
unsigned p_cont_id;
int as_vers;
int ts_vers;
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 */
ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
}
/*
* Duplicate presentation context id.
*/
ndo_trace("ndr_svc_bind: duplicate binding");
return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
}
/*
* No free binding slot
*/
ndo_trace("ndr_svc_bind: no resources");
return (NDR_DRC_OK);
}
return (NDR_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 (NDR_DRC_IS_FAULT(rc)) {
mbind->which_side = 0;
mbind->instance_specific = 0;
return (rc);
}
}
return (NDR_DRC_BINDING_MADE);
}
/*
* ndr_svc_alter_context
*
* The alter context request is used to request additional presentation
* a bind request.
*/
static int
{
unsigned p_cont_id;
int as_vers;
int ts_vers;
result_list->reserved = 0;
result_list->reserved2 = 0;
return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
return (NDR_DRC_OK);
}
return (NDR_DRC_OK);
}
/* mbind->context set by app */
mbind->instance_specific = 0;
return (NDR_DRC_BINDING_MADE);
}
static int
{
unsigned p_cont_id;
int rc;
return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
/*
* Make room for the response hdr.
*/
else
if (NDR_DRC_IS_FAULT(rc)) {
ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
}
return (rc);
}
/*
* The transaction and the two nds streams use the same heap, which
* should already exist at this point. The heap will also be available
* to the stub.
*/
int
{
char *param;
int rc;
return (NDR_DRC_FAULT_OUT_OF_MEMORY);
}
ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
}
return (NDR_DRC_FAULT_OUT_OF_MEMORY);
if (!NDR_DRC_IS_OK(rc))
return (rc);
if (rc == NDR_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 NDR_PTYPE_BIND:
/*
* Save the maximum fragment sizes
* for use with subsequent requests.
*/
break;
case NDR_PTYPE_REQUEST:
/* mxa->send_hdr.response_hdr.alloc_hint */
break;
case NDR_PTYPE_ALTER_CONTEXT:
/*
* The max_xmit_frag, max_recv_frag and assoc_group_id are
* ignored by the client but it's useful to fill them in.
*/
break;
default:
}
}
/*
* 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 & NDR_DRC_MASK_SPECIFIER) {
break;
break;
break;
break;
default:
break;
}
}
/*
* Note that the frag_length for bind ack and alter context is
* non-standard.
*/
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 NDR_PTYPE_BIND_ACK:
break;
case NDR_PTYPE_FAULT:
/* already setup */
break;
case NDR_PTYPE_RESPONSE:
break;
break;
default:
break;
}
nds->pdu_scan_offset = 0;
(void) ndr_encode_pdu_hdr(mxa);
return (0);
}
/*
* Multiple fragment response.
*/
nds->pdu_scan_offset = 0;
(void) ndr_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 - NDR_RSP_HDR_SIZE)
*/
while (pdu_data_size) {
if (pdu_data_size <= frag_data_size) {
} else {
}
nds->pdu_scan_offset = 0;
(void) ndr_encode_pdu_hdr(mxa);
break;
}
return (0);
}
/*
* ndr_build_frag
*
* Build an RPC PDU fragment from the specified buffer.
* and report an error.
*/
static void
{
return;
} else {
}
}