mlrpc.h   [plain text]


/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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.
 */
/*
 * Portions Copyright 2008 Apple, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SMBSRV_MLRPC_H
#define	_SMBSRV_MLRPC_H

#include <stdint.h>

/*
 * MSRPC Like RPC (MLRPC) is an MSRPC compatible implementation of OSF
 * DCE RPC.  DCE RPC is derived from the Apollo Network Computing
 * Architecture (NCA) RPC implementation.  This implementation is based
 * on the X/Open DCE: Remote Procedure Call specification.  The main
 * MSRPC compatibility issue is the use of Unicode strings.  This work
 * was originally based on the X/Open DCE Remote Procedure Call CAE
 * 1994 Specification.  The current DCE RPC specification is detailed
 * below.
 *
 * CAE Specification (1997)
 * DCE 1.1: Remote Procedure Call
 * Document Number: C706
 * The Open Group
 * ogspecs@opengroup.org
 */

/*
 * Layering
 *
 * This shows the software layers of the DCE RPC system compared against
 * ONC SUN RPC.
 *
 *	MLRPC Layers		Sun RPC Layers		Remark
 *	+---------------+	+---------------+	+---------------+
 *	+---------------+	+---------------+
 *	| Application	|	| Application	|	The application
 *	+---------------+	+---------------+
 *	| Hand coded    |	| RPCGEN gen'd  |	Where the real
 *	| client/server |	| client/server |	work happens
 *	| srvsvc.ndl	|	| *_svc.c *_clnt|
 *	| srvsvc.c	|	|               |
 *	+---------------+	+---------------+
 *	| RPC Library	|	| RPC Library   |	Calls/Return
 *	| mlrpc_*.c     |	|               |	Binding/PMAP
 *	+---------------+	+---------------+
 *	| RPC Protocol	|	| RPC Protocol  |	Headers, Auth,
 *	| mlrpcpdu.ndl  |	|               |
 *	+---------------+	+---------------+
 *	| IDL gen'd	|	| RPCGEN gen'd  |	Aggregate
 *	| NDR stubs	|	| XDR stubs     |	Composition
 *	| *__ndr.c      |	| *_xdr.c       |
 *	+---------------+	+---------------+
 *	| NDR Represen	|	| XDR Represen  |	Byte order, padding
 *	+---------------+	+---------------+
 *	| Packet Heaps  |	| Network Conn  |	BIG DIFF: DCERPC does
 *	| mlndo_*.c     |	| clnt_{tcp,udp}|	not talk directly to
 *	+---------------+	+---------------+	network.
 *
 * There are two major differences between the DCE RPC and ONC RPC:
 *
 * 1. MLRPC only generates or processes packets from buffers.  Other
 *    layers must take care of packet transmission and reception.
 *    The packet heaps are managed through a simple interface provided
 *    by the Network Data Representation (NDR) module, called struct
 *    mlndr_stream.  mlndo_*.c modules implement the different flavors
 *    (operations) of packet heaps.
 *
 *    ONC RPC communicates directly with the network.  You have to do
 *    something special for the RPC packet to be placed in a buffer
 *    rather than sent to the wire.
 *
 * 2. MLRPC uses application provided heaps to support operations.
 *    A heap is a single, monolithic chunk of memory that MLRPC manages
 *    as it allocates.  When the operation and its result are done, the
 *    heap is disposed of as a single item.  The mlrpc_xaction, which
 *    is the anchor of most operations, contains the necessary book-
 *    keeping for the heap.
 *
 *    ONC RPC uses malloc() liberally throughout its run-time system.
 *    To free results, ONC RPC supports an XDR_FREE operation that
 *    traverses data structures freeing memory as it goes, whether
 *    it was malloc'd or not.
 */

#include "ndl/rpcpdu.ndl"
#include "libmlrpc/mlsvc.h"
#include "libmlrpc/ndr.h"

#include <libkern/OSByteOrder.h>

#ifdef __cplusplus
extern "C" {
#endif

#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
/* <libkern/OSByteOrder.h> should define one or the other of these. */
#error Unknown native byte ordering
#endif

/* Since OSHostByteOrder is an inline, this should compile to a constant. */
#define mlrpc_native_byte_order \
    (OSHostByteOrder() == OSBigEndian ? MLRPC_REPLAB_INTG_BIG_ENDIAN \
				    : MLRPC_REPLAB_INTG_LITTLE_ENDIAN)

/*
 * Dispatch Return Code (DRC)
 *
 *	0x8000	15:01	Set to indicate a fault, clear indicates status
 *	0x7F00	08:07	Status/Fault specific
 *	0x00FF	00:08	MLRPC_PTYPE_... of PDU, 0xFF for header
 */
#define	MLRPC_DRC_MASK_FAULT			0x8000
#define	MLRPC_DRC_MASK_SPECIFIER		0xFF00
#define	MLRPC_DRC_MASK_PTYPE			0x00FF

/* Usual stuff */
#define	MLRPC_DRC_OK				0x0000

/* Fake PTYPEs for MLRPC_DRC */
#define	MLRPC_DRC_PTYPE_RPCHDR			0x00FF
#define	MLRPC_DRC_PTYPE_API			0x00AA

/* DRC Recognizers */
#define	MLRPC_DRC_IS_OK(DRC)	(((DRC)&MLRPC_DRC_MASK_SPECIFIER) == 0)
#define	MLRPC_DRC_IS_FAULT(DRC)	(((DRC)&MLRPC_DRC_MASK_FAULT) != 0)

/*
 * (Un)Marshalling category specifiers
 */
#define	MLRPC_DRC_FAULT_MODE_MISMATCH		0x8100
#define	MLRPC_DRC_RECEIVED			0x0200
#define	MLRPC_DRC_FAULT_RECEIVED_RUNT		0x8300
#define	MLRPC_DRC_FAULT_RECEIVED_MALFORMED	0x8400
#define	MLRPC_DRC_DECODED			0x0500
#define	MLRPC_DRC_FAULT_DECODE_FAILED		0x8600
#define	MLRPC_DRC_ENCODED			0x0700
#define	MLRPC_DRC_FAULT_ENCODE_FAILED		0x8800
#define	MLRPC_DRC_FAULT_ENCODE_TOO_BIG		0x8900
#define	MLRPC_DRC_SENT				0x0A00
#define	MLRPC_DRC_FAULT_SEND_FAILED		0x8B00

/*
 * Resource category specifier
 */
#define	MLRPC_DRC_FAULT_RESOURCE_1		0x9100
#define	MLRPC_DRC_FAULT_RESOURCE_2		0x9200

/*
 * Parameters. Usually #define'd with useful alias
 */
#define	MLRPC_DRC_FAULT_PARAM_0_INVALID		0xC000
#define	MLRPC_DRC_FAULT_PARAM_0_UNIMPLEMENTED	0xD000
#define	MLRPC_DRC_FAULT_PARAM_1_INVALID		0xC100
#define	MLRPC_DRC_FAULT_PARAM_1_UNIMPLEMENTED	0xD100
#define	MLRPC_DRC_FAULT_PARAM_2_INVALID		0xC200
#define	MLRPC_DRC_FAULT_PARAM_2_UNIMPLEMENTED	0xD200
#define	MLRPC_DRC_FAULT_PARAM_3_INVALID		0xC300
#define	MLRPC_DRC_FAULT_PARAM_3_UNIMPLEMENTED	0xD300

#define	MLRPC_DRC_FAULT_OUT_OF_MEMORY		0xF000

/* RPCHDR */
#define	MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID	0xC0FF	/* PARAM_0_INVALID */
#define	MLRPC_DRC_FAULT_RPCHDR_PTYPE_UNIMPLEMENTED 0xD0FF /* PARAM_0_UNIMP */

/* Request */
#define	MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID	0xC000	/* PARAM_0_INVALID */
#define	MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID	0xC100	/* PARAM_1_INVALID */

/* Bind */
#define	MLRPC_DRC_FAULT_BIND_PCONT_BUSY		0xC00B	/* PARAM_0_INVALID */
#define	MLRPC_DRC_FAULT_BIND_UNKNOWN_SERVICE	0xC10B	/* PARAM_1_INVALID */
#define	MLRPC_DRC_FAULT_BIND_NO_SLOTS		0x910B	/* RESOURCE_1 */
#define	MLRPC_DRC_BINDING_MADE			0x000B	/* OK */

/* API */
#define	MLRPC_DRC_FAULT_API_SERVICE_INVALID	0xC0AA	/* PARAM_0_INVALID */
#define	MLRPC_DRC_FAULT_API_BIND_NO_SLOTS	0x91AA	/* RESOURCE_1 */
#define	MLRPC_DRC_FAULT_API_OPNUM_INVALID	0xC1AA	/* PARAM_1_INVALID */

struct mlrpc_xaction;

typedef struct mlrpc_stub_table {
	int		(*func)(void *param, struct mlrpc_xaction *mreq);
	unsigned short	opnum;
} mlrpc_stub_table_t;

typedef struct mlrpc_service {
	char		*name;
	char		*desc;
	char		*endpoint;
	char		*sec_addr_port;
	char		*abstract_syntax_uuid;
	int		abstract_syntax_version;
	char		*transfer_syntax_uuid;
	int		transfer_syntax_version;
	unsigned	bind_instance_size;
	int		(*bind_req)();
	int		(*unbind_and_close)();
	int		(*call_stub)(struct mlrpc_xaction *mreq);
	struct ndr_typeinfo *interface_ti;
	struct mlrpc_stub_table *stub_table;
} mlrpc_service_t;

/*
 * 20-byte opaque id used by various RPC services.
 */
typedef struct ndr_hdid {
	uint32_t data[5];
} ndr_hdid_t;

typedef struct ndr_handle {
	struct ndr_handle *nh_next;
	ndr_hdid_t nh_id;
	int nh_fid;
	const mlrpc_service_t *nh_svc;
	void *nh_data;
} ndr_handle_t;

/*
 * The list of bindings is anchored at a connection.  Nothing in the
 * RPC mechanism allocates them.  Binding elements which have service==0
 * indicate free elements.  When a connection is instantiated, at least
 * one free binding entry should also be established.  Something like
 * this should suffice for most (all) situations:
 *
 *	struct connection {
 *		....
 *		struct mlrpc_binding *binding_list_head;
 *		struct mlrpc_binding binding_pool[N_BINDING_POOL];
 *		....
 *	};
 *
 *	init_connection(struct connection *conn) {
 *		....
 *		mlrpc_binding_pool_initialize(&conn->binding_list_head,
 *		    conn->binding_pool, N_BINDING_POOL);
 */
struct mlrpc_binding {
	struct mlrpc_binding 	*next;
	mlrpc_p_context_id_t	p_cont_id;
	unsigned char		which_side;
	void *			context;
	struct mlrpc_service 	*service;
	void 			*instance_specific;
};

#define	MLRPC_BIND_SIDE_CLIENT	1
#define	MLRPC_BIND_SIDE_SERVER	2

#define	MLRPC_BINDING_TO_SPECIFIC(BINDING, TYPE) \
	((TYPE *) (BINDING)->instance_specific)

/*
 * mlrpc_heap.c
 *
 * A number of heap areas are used during marshalling and unmarshalling.
 * Under some circumstances these areas can be discarded by the library
 * code, i.e. on the server side before returning to the client and on
 * completion of a client side bind.  In the case of a client side RPC
 * call, these areas must be preserved after an RPC returns to give the
 * caller time to take a copy of the data.  In this case the client must
 * call mlrpc_c_free_heap to free the memory.
 */

typedef struct mlrpc_heap mlrpc_heap_t;

/*
 * To support the client-side heap preserve functionality.
 */
#define	MLRPC_HRST_PRESERVED		1

typedef struct mlrpc_heapref {
	mlrpc_heap_t *heap;
	char *recv_pdu_buf;
	char *send_pdu_buf;
	unsigned int state;
} mlrpc_heapref_t;

/*
 * Alternate varying/conformant string definition
 * - for non-null-terminated strings.
 */
struct mlrpc_vcb {
	/*
	 * size_is (actually a copy of length_is) will
	 * be inserted here by the marshalling library.
	 */
	uint32_t vc_first_is;
	uint32_t vc_length_is;
	uint16_t buffer[];
};

typedef struct mlrpc_vcbuf {
	uint16_t wclen;
	uint16_t wcsize;
	struct mlrpc_vcb *vcb;
} mlrpc_vcbuf_t;

mlrpc_heap_t *mlrpc_heap_create(void);
void mlrpc_heap_destroy(mlrpc_heap_t *);
void *mlrpc_heap_malloc(mlrpc_heap_t *, size_t);
char *mlrpc_heap_strsave(mlrpc_heap_t *, const char *);
void mlrpc_heap_mkvcs(mlrpc_heap_t *, const char *, mlrpc_vcbuf_t *);
size_t mlrpc_heap_used(mlrpc_heap_t *);

#define	MLRPC_HEAP_MALLOC(MXA, SIZE) \
	mlrpc_heap_malloc((MXA)->heap, SIZE)

#define	MLRPC_HEAP_NEW(MXA, TYPE) \
	mlrpc_heap_malloc((MXA)->heap, sizeof (TYPE))

#define	MLRPC_HEAP_NEWN(MXA, TYPE, N) \
	mlrpc_heap_malloc((MXA)->heap, sizeof (TYPE)*(N))

#define	MLRPC_HEAP_STRSAVE(MXA, STR) \
	mlrpc_heap_strsave((MXA)->heap, (STR))

typedef struct mlrpc_xaction {
	int			fid;
	unsigned short		ptype;		/* just handy, hi bits spcl */
	unsigned short		opnum;		/* for requests */
	struct mlndr_stream	recv_mlnds;
	mlrpcconn_hdr_t		recv_hdr;
	struct mlndr_stream	send_mlnds;
	mlrpcconn_hdr_t		send_hdr;
	struct mlrpc_binding	*binding;	/* what we're using */
	struct mlrpc_binding	*binding_list;	/* from connection */
	mlrpc_heap_t		*heap;
	struct mlsvc_rpc_context *context;
} ndr_xa_t;

/* Do a SMB READ or READX operation, returning the amount of data
 * received, or -errno on error.
 */
typedef ssize_t (*smbrdr_read_t) (
	void *	    xa_context,	    /* client context handle */
	int	    fid,	    /* open pipe FID */
	uint8_t *   buf,	    /* receive buffer */
	size_t	    buflen);	    /* length of receive buffer */

/* Do a SMB TRANSACT_NAMED_PIPE operation, returning the amount of data
 * received, or -errno on error.
 */
typedef ssize_t (*smbrdr_transact_t) (
	void *	    xa_context,	    /* client context handle */
	int	    fid,	    /* open pipe FID */
	const uint8_t * out_buf,    /* data to send */
	size_t	    out_len,	    /* length of data to send */
	uint8_t *   in_buf,	    /* receive buffer */
	size_t	    in_len);	    /* length of receive buffer */

struct mlrpc_smb_client {
	void * smb_context;
	smbrdr_transact_t smb_transact;
	smbrdr_read_t smb_readx;
};

struct mlrpc_client {
	int (*xa_init)(struct mlrpc_client *, struct mlrpc_xaction *,
	    mlrpc_heap_t *);
	int (*xa_exchange)(struct mlrpc_client *, struct mlrpc_xaction *);
	int (*xa_read)(struct mlrpc_client *, struct mlrpc_xaction *);
	int (*xa_preserve)(struct mlrpc_client *, struct mlrpc_xaction *,
	    mlrpc_heapref_t *);
	int (*xa_destruct)(struct mlrpc_client *, struct mlrpc_xaction *);
	void (*xa_release)(struct mlrpc_client *, mlrpc_heapref_t *);

	void *context;

	struct mlrpc_smb_client smbcli;

	struct mlrpc_binding *binding_list;
	uint32_t next_call_id;
	unsigned next_p_cont_id;
};

/* smb_utf8.c */

#ifndef MTS_WCHAR_T
#define MTS_WCHAR_T
typedef uint16_t mts_wchar_t;
#endif /* MTS_WCHAR_T */

size_t mts_mbstowcs(mts_wchar_t *, const char *, size_t);
ssize_t mts_mbtowc(mts_wchar_t *, const char *, size_t);
size_t mts_wctomb(char *, mts_wchar_t);
size_t mts_wcstombs(char *, const mts_wchar_t *, size_t);
size_t mts_wcequiv_strlen(const char *);
size_t mts_sbequiv_strlen(const char *);
ssize_t mts_stombs(char *, const char *, size_t);
ssize_t mts_mbstos(char *, const char *);

/* Maximum number of bytes per multi-byte character. */
#define MTS_MB_CHAR_MAX 3

/* ndr_ops.c */
int mlnds_initialize(struct mlndr_stream *, unsigned, int, mlrpc_heap_t *);
void mlnds_destruct(struct mlndr_stream *);

/* ndr_client.c */
int mlrpc_c_bind(struct mlrpc_client *, const char *, struct mlrpc_binding **);
int mlrpc_c_call(struct mlrpc_binding *, int, void *, mlrpc_heapref_t *);
void mlrpc_c_free_heap(struct mlrpc_binding *, mlrpc_heapref_t *);

/* ndr_marshal.c */
int mlrpc_encode_decode_common(struct mlrpc_xaction *, int, unsigned,
    struct ndr_typeinfo *, void *);
int mlrpc_decode_call(struct mlrpc_xaction *, void *);
int mlrpc_encode_return(struct mlrpc_xaction *, void *);
int mlrpc_encode_call(struct mlrpc_xaction *, void *);
int mlrpc_decode_return(struct mlrpc_xaction *, void *);
int mlrpc_decode_pdu_hdr(struct mlrpc_xaction *);
int mlrpc_encode_pdu_hdr(struct mlrpc_xaction *);
void mlrpc_decode_frag_hdr(struct mlndr_stream *,
    mlrpcconn_request_hdr_t *, const uint8_t *);
unsigned mlrpc_bind_ack_hdr_size(struct mlrpcconn_bind_ack_hdr *);

#if 0
/* ndr_server.c */
int mlrpc_generic_call_stub(struct mlrpc_xaction *);
#endif

/* ndr_svc.c */
struct mlrpc_stub_table *mlrpc_find_stub_in_svc(mlrpc_service_t *, int);
mlrpc_service_t *mlrpc_find_service_by_name(const char *);
mlrpc_service_t *mlrpc_find_service_by_uuids(ndr_uuid_t *, int,
    ndr_uuid_t *, int);
int mlrpc_register_service(mlrpc_service_t *);
void mlrpc_unregister_service(mlrpc_service_t *);
void mlrpc_uuid_to_str(ndr_uuid_t *, char *, size_t);
int mlrpc_str_to_uuid(char *, ndr_uuid_t *);
void mlrpc_binding_pool_initialize(struct mlrpc_binding **,
    struct mlrpc_binding pool[], unsigned);
struct mlrpc_binding *mlrpc_find_binding(struct mlrpc_xaction *,
    mlrpc_p_context_id_t);
struct mlrpc_binding *mlrpc_new_binding(struct mlrpc_xaction *);

ndr_hdid_t *ndr_hdalloc(const ndr_xa_t *, const void *);
void ndr_hdfree(const ndr_xa_t *, const ndr_hdid_t *);
ndr_handle_t *ndr_hdlookup(const ndr_xa_t *, const ndr_hdid_t *);
void ndr_hdclose(int fid);

#ifdef __cplusplus
}
#endif

#endif /* _SMBSRV_MLRPC_H */