4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
29 #include <sys/types.h>
32 #include <smb/wintypes.h>
33 #include <libmlrpc/ndr.h>
40 * An MSRPC compatible implementation of OSF DCE RPC. DCE RPC is derived
41 * from the Apollo Network Computing Architecture (NCA) RPC implementation.
43 * CAE Specification (1997)
44 * DCE 1.1: Remote Procedure Call
45 * Document Number: C706
47 * ogspecs@opengroup.org
49 * This implementation is based on the DCE Remote Procedure Call spec with
50 * enhancements to support Unicode strings. The diagram below shows the
51 * DCE RPC layers compared against ONC SUN RPC.
53 * NDR RPC Layers Sun RPC Layers Remark
54 * +---------------+ +---------------+ +---------------+
55 * +---------------+ +---------------+
56 * | Application | | Application | The application
57 * +---------------+ +---------------+
58 * | Hand coded | | RPCGEN gen'd | Where the real
59 * | client/server | | client/server | work happens
60 * | srvsvc.ndl | | *_svc.c *_clnt|
62 * +---------------+ +---------------+
63 * | RPC Library | | RPC Library | Calls/Return
64 * | ndr_*.c | | | Binding/PMAP
65 * +---------------+ +---------------+
66 * | RPC Protocol | | RPC Protocol | Headers, Auth,
68 * +---------------+ +---------------+
69 * | IDL gen'd | | RPCGEN gen'd | Aggregate
70 * | NDR stubs | | XDR stubs | Composition
71 * | *__ndr.c | | *_xdr.c |
72 * +---------------+ +---------------+
73 * | NDR Represen | | XDR Represen | Byte order, padding
74 * +---------------+ +---------------+
75 * | Packet Heaps | | Network Conn | DCERPC does not talk
76 * | ndo_*.c | | clnt_{tcp,udp}| directly to network.
77 * +---------------+ +---------------+
79 * There are two major differences between the DCE RPC and ONC RPC:
81 * 1. NDR RPC only generates or processes packets from buffers. Other
82 * layers must take care of packet transmission and reception.
83 * The packet heaps are managed through a simple interface provided
84 * by the Network Data Representation (NDR) module called ndr_stream_t.
85 * ndo_*.c modules implement the different flavors (operations) of
88 * ONC RPC communicates directly with the network. You have to do
89 * something special for the RPC packet to be placed in a buffer
90 * rather than sent to the wire.
92 * 2. NDR RPC uses application provided heaps to support operations.
93 * A heap is a single, monolithic chunk of memory that NDR RPC manages
94 * as it allocates. When the operation and its result are done, the
95 * heap is disposed of as a single item. The transaction, which
96 * is the anchor of most operations, contains the necessary book-
97 * keeping for the heap.
99 * ONC RPC uses malloc() liberally throughout its run-time system.
100 * To free results, ONC RPC supports an XDR_FREE operation that
101 * traverses data structures freeing memory as it goes, whether
102 * it was malloc'd or not.
106 * Dispatch Return Code (DRC)
108 * 0x8000 15:01 Set to indicate a fault, clear indicates status
109 * 0x7F00 08:07 Status/Fault specific
110 * 0x00FF 00:08 PTYPE_... of PDU, 0xFF for header
112 #define NDR_DRC_OK 0x0000
113 #define NDR_DRC_MASK_FAULT 0x8000
114 #define NDR_DRC_MASK_SPECIFIER 0xFF00
115 #define NDR_DRC_MASK_PTYPE 0x00FF
117 /* Fake PTYPE DRC discriminators */
118 #define NDR_DRC_PTYPE_RPCHDR(DRC) ((DRC) | 0x00FF)
119 #define NDR_DRC_PTYPE_API(DRC) ((DRC) | 0x00AA)
121 /* DRC Recognizers */
122 #define NDR_DRC_IS_OK(DRC) (((DRC) & NDR_DRC_MASK_SPECIFIER) == 0)
123 #define NDR_DRC_IS_FAULT(DRC) (((DRC) & NDR_DRC_MASK_FAULT) != 0)
126 * (Un)Marshalling category specifiers
128 #define NDR_DRC_FAULT_MODE_MISMATCH 0x8100
129 #define NDR_DRC_RECEIVED 0x0200
130 #define NDR_DRC_FAULT_RECEIVED_RUNT 0x8300
131 #define NDR_DRC_FAULT_RECEIVED_MALFORMED 0x8400
132 #define NDR_DRC_DECODED 0x0500
133 #define NDR_DRC_FAULT_DECODE_FAILED 0x8600
134 #define NDR_DRC_ENCODED 0x0700
135 #define NDR_DRC_FAULT_ENCODE_FAILED 0x8800
136 #define NDR_DRC_FAULT_ENCODE_TOO_BIG 0x8900
137 #define NDR_DRC_SENT 0x0A00
138 #define NDR_DRC_FAULT_SEND_FAILED 0x8B00
141 * Resource category specifier
143 #define NDR_DRC_FAULT_RESOURCE_1 0x9100
144 #define NDR_DRC_FAULT_RESOURCE_2 0x9200
147 * Parameters. Usually #define'd with useful alias
149 #define NDR_DRC_FAULT_PARAM_0_INVALID 0xC000
150 #define NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED 0xD000
151 #define NDR_DRC_FAULT_PARAM_1_INVALID 0xC100
152 #define NDR_DRC_FAULT_PARAM_1_UNIMPLEMENTED 0xD100
153 #define NDR_DRC_FAULT_PARAM_2_INVALID 0xC200
154 #define NDR_DRC_FAULT_PARAM_2_UNIMPLEMENTED 0xD200
155 #define NDR_DRC_FAULT_PARAM_3_INVALID 0xC300
156 #define NDR_DRC_FAULT_PARAM_3_UNIMPLEMENTED 0xD300
158 #define NDR_DRC_FAULT_OUT_OF_MEMORY 0xF000
161 #define NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH 0x81FF
162 #define NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT 0x83FF
163 #define NDR_DRC_FAULT_RPCHDR_DECODE_FAILED 0x86FF
164 #define NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID 0xC0FF /* PARAM_0_INVALID */
165 #define NDR_DRC_FAULT_RPCHDR_PTYPE_UNIMPLEMENTED 0xD0FF /* PARAM_0_UNIMP */
168 #define NDR_DRC_FAULT_REQUEST_PCONT_INVALID 0xC000 /* PARAM_0_INVALID */
169 #define NDR_DRC_FAULT_REQUEST_OPNUM_INVALID 0xC100 /* PARAM_1_INVALID */
172 #define NDR_DRC_BINDING_MADE 0x000B /* OK */
173 #define NDR_DRC_FAULT_BIND_PCONT_BUSY 0xC00B /* PARAM_0_INVALID */
174 #define NDR_DRC_FAULT_BIND_UNKNOWN_SERVICE 0xC10B /* PARAM_1_INVALID */
175 #define NDR_DRC_FAULT_BIND_NO_SLOTS 0x910B /* RESOURCE_1 */
178 #define NDR_DRC_FAULT_API_SERVICE_INVALID 0xC0AA /* PARAM_0_INVALID */
179 #define NDR_DRC_FAULT_API_BIND_NO_SLOTS 0x91AA /* RESOURCE_1 */
180 #define NDR_DRC_FAULT_API_OPNUM_INVALID 0xC1AA /* PARAM_1_INVALID */
185 typedef struct ndr_stub_table
{
186 int (*func
)(void *, struct ndr_xa
*);
187 unsigned short opnum
;
190 typedef struct ndr_service
{
195 char *abstract_syntax_uuid
;
196 int abstract_syntax_version
;
197 char *transfer_syntax_uuid
;
198 int transfer_syntax_version
;
199 unsigned bind_instance_size
;
201 int (*unbind_and_close
)();
202 int (*call_stub
)(struct ndr_xa
*);
203 ndr_typeinfo_t
*interface_ti
;
204 ndr_stub_table_t
*stub_table
;
208 * The list of bindings is anchored at a connection. Nothing in the
209 * RPC mechanism allocates them. Binding elements which have service==0
210 * indicate free elements. When a connection is instantiated, at least
211 * one free binding entry should also be established. Something like
212 * this should suffice for most (all) situations:
214 * struct connection {
216 * ndr_binding_t *binding_list_head;
217 * ndr_binding_t binding_pool[N_BINDING_POOL];
221 * init_connection(struct connection *conn) {
223 * ndr_svc_binding_pool_init(&conn->binding_list_head,
224 * conn->binding_pool, N_BINDING_POOL);
226 typedef struct ndr_binding
{
227 struct ndr_binding
*next
;
228 ndr_p_context_id_t p_cont_id
;
229 unsigned char which_side
;
230 struct ndr_client
*clnt
;
231 ndr_service_t
*service
;
232 void *instance_specific
;
235 #define NDR_BIND_SIDE_CLIENT 1
236 #define NDR_BIND_SIDE_SERVER 2
238 #define NDR_BINDING_TO_SPECIFIC(BINDING, TYPE) \
239 ((TYPE *) (BINDING)->instance_specific)
242 * The binding list space must be provided by the application library
243 * for use by the underlying RPC library. We need at least two binding
244 * slots per connection.
246 #define NDR_N_BINDING_POOL 2
248 typedef struct ndr_pipe
{
250 const char *np_endpoint
;
251 struct smb_netuserinfo
*np_user
;
252 int (*np_send
)(struct ndr_pipe
*, void *, size_t);
253 int (*np_recv
)(struct ndr_pipe
*, void *, size_t);
255 uint16_t np_max_xmit_frag
;
256 uint16_t np_max_recv_frag
;
257 ndr_binding_t
*np_binding
;
258 ndr_binding_t np_binding_pool
[NDR_N_BINDING_POOL
];
262 * Number of bytes required to align SIZE on the next dword/4-byte
265 #define NDR_ALIGN4(SIZE) ((4 - (SIZE)) & 3);
268 * DCE RPC strings (CAE section 14.3.4) are represented as varying or varying
269 * and conformant one-dimensional arrays. Characters can be single-byte
270 * or multi-byte as long as all characters conform to a fixed element size,
271 * i.e. UCS-2 is okay but UTF-8 is not a valid DCE RPC string format. The
272 * string is terminated by a null character of the appropriate element size.
274 * MSRPC strings should always be varying/conformant and not null terminated.
275 * This format uses the size_is, first_is and length_is attributes (CAE
278 * typedef struct string {
282 * wchar_t string[ANY_SIZE_ARRAY];
285 * The size_is attribute is used to specify the number of data elements in
286 * each dimension of an array.
288 * The first_is attribute is used to define the lower bound for significant
289 * elements in each dimension of an array. For strings this is always 0.
291 * The length_is attribute is used to define the number of significant
292 * elements in each dimension of an array. For strings this is typically
293 * the same as size_is. Although it might be (size_is - 1) if the string
294 * is null terminated.
296 * 4 bytes 4 bytes 4 bytes 2bytes 2bytes 2bytes 2bytes
297 * +---------+---------+---------+------+------+------+------+
298 * |size_is |first_is |length_is| char | char | char | char |
299 * +---------+---------+---------+------+------+------+------+
301 * Unfortunately, not all MSRPC Unicode strings are null terminated, which
302 * means that the recipient has to manually null-terminate the string after
303 * it has been unmarshalled. There may be a wide-char pad following a
304 * string, and it may sometimes contains zero, but it's not guaranteed.
306 * To deal with this, MSRPC sometimes uses an additional wrapper with two
307 * more fields, as shown below.
308 * length: the array length in bytes excluding terminating null bytes
309 * maxlen: the array length in bytes including null terminator bytes
310 * LPTSTR: converted to a string_t by NDR
312 * typedef struct ms_string {
318 typedef struct ndr_mstring
{
325 * A number of heap areas are used during marshalling and unmarshalling.
326 * Under some circumstances these areas can be discarded by the library
327 * code, i.e. on the server side before returning to the client and on
328 * completion of a client side bind. In the case of a client side RPC
329 * call, these areas must be preserved after an RPC returns to give the
330 * caller time to take a copy of the data. In this case the client must
331 * call ndr_clnt_free_heap to free the memory.
333 * The heap management data definition looks a bit like this:
335 * heap -> +---------------+ +------------+
336 * | iovec[0].base | --> | data block |
337 * | iovec[0].len | +------------+
341 * iov -> +---------------+ +------------+
342 * | iovec[n].base | --> | data block |
343 * | iovec[n].len | +------------+
344 * +---------------+ ^ ^
346 * next ----------------------+ |
347 * top -----------------------------------+
352 * Setting MAXIOV to 384 will use ((8 * 384) + 16) = 3088 bytes
353 * of the first heap block.
355 #define NDR_HEAP_MAXIOV 384
356 #define NDR_HEAP_BLKSZ 8192
358 typedef struct ndr_heap
{
359 struct iovec iovec
[NDR_HEAP_MAXIOV
];
367 * Alternate varying/conformant string definition
368 * - for non-null-terminated strings.
370 typedef struct ndr_vcs
{
372 * size_is (actually a copy of length_is) will
373 * be inserted here by the marshalling library.
375 uint32_t vc_first_is
;
376 uint32_t vc_length_is
;
377 uint16_t buffer
[ANY_SIZE_ARRAY
];
380 typedef struct ndr_vcstr
{
386 typedef struct ndr_vcb
{
388 * size_is (actually a copy of length_is) will
389 * be inserted here by the marshalling library.
391 uint32_t vc_first_is
;
392 uint32_t vc_length_is
;
393 uint8_t buffer
[ANY_SIZE_ARRAY
];
396 typedef struct ndr_vcbuf
{
402 ndr_heap_t
*ndr_heap_create(void);
403 void ndr_heap_destroy(ndr_heap_t
*);
404 void *ndr_heap_dupmem(ndr_heap_t
*, const void *, size_t);
405 void *ndr_heap_malloc(ndr_heap_t
*, unsigned);
406 void *ndr_heap_strdup(ndr_heap_t
*, const char *);
407 int ndr_heap_mstring(ndr_heap_t
*, const char *, ndr_mstring_t
*);
408 void ndr_heap_mkvcs(ndr_heap_t
*, char *, ndr_vcstr_t
*);
409 void ndr_heap_mkvcb(ndr_heap_t
*, uint8_t *, uint32_t, ndr_vcbuf_t
*);
410 int ndr_heap_used(ndr_heap_t
*);
411 int ndr_heap_avail(ndr_heap_t
*);
413 #define NDR_MALLOC(XA, SZ) ndr_heap_malloc((XA)->heap, SZ)
414 #define NDR_NEW(XA, T) ndr_heap_malloc((XA)->heap, sizeof (T))
415 #define NDR_NEWN(XA, T, N) ndr_heap_malloc((XA)->heap, sizeof (T)*(N))
416 #define NDR_STRDUP(XA, S) ndr_heap_strdup((XA)->heap, (S))
417 #define NDR_MSTRING(XA, S, OUT) ndr_heap_mstring((XA)->heap, (S), (OUT))
418 #define NDR_SIDDUP(XA, S) ndr_heap_dupmem((XA)->heap, (S), smb_sid_len(S))
420 typedef struct ndr_xa
{
421 unsigned short ptype
; /* high bits special */
422 unsigned short opnum
;
423 ndr_stream_t recv_nds
;
425 ndr_stream_t send_nds
;
427 ndr_binding_t
*binding
; /* what we're using */
428 ndr_binding_t
*binding_list
; /* from connection */
434 * 20-byte opaque id used by various RPC services.
436 CONTEXT_HANDLE(ndr_hdid
) ndr_hdid_t
;
438 typedef struct ndr_client
{
439 /* transport stuff (xa_* members) */
440 int (*xa_init
)(struct ndr_client
*, ndr_xa_t
*);
441 int (*xa_exchange
)(struct ndr_client
*, ndr_xa_t
*);
442 int (*xa_read
)(struct ndr_client
*, ndr_xa_t
*);
443 void (*xa_preserve
)(struct ndr_client
*, ndr_xa_t
*);
444 void (*xa_destruct
)(struct ndr_client
*, ndr_xa_t
*);
445 void (*xa_release
)(struct ndr_client
*);
450 ndr_binding_t
*binding
;
451 ndr_binding_t
*binding_list
;
452 ndr_binding_t binding_pool
[NDR_N_BINDING_POOL
];
455 boolean_t heap_preserved
;
457 ndr_stream_t
*recv_nds
;
458 ndr_stream_t
*send_nds
;
460 uint32_t next_call_id
;
461 unsigned next_p_cont_id
;
464 typedef struct ndr_handle
{
466 struct ndr_handle
*nh_next
;
468 const ndr_service_t
*nh_svc
;
469 ndr_client_t
*nh_clnt
;
471 void (*nh_data_free
)(void *);
474 #define NDR_PDU_SIZE_HINT_DEFAULT (16*1024)
475 #define NDR_BUF_MAGIC 0x4E425546 /* NBUF */
477 typedef struct ndr_buf
{
481 ndr_typeinfo_t
*nb_ti
;
485 int nds_initialize(ndr_stream_t
*, unsigned, int, ndr_heap_t
*);
486 void nds_destruct(ndr_stream_t
*);
487 void nds_show_state(ndr_stream_t
*);
490 int ndr_clnt_bind(ndr_client_t
*, ndr_service_t
*, ndr_binding_t
**);
491 int ndr_clnt_call(ndr_binding_t
*, int, void *);
492 void ndr_clnt_free_heap(ndr_client_t
*);
495 ndr_buf_t
*ndr_buf_init(ndr_typeinfo_t
*);
496 void ndr_buf_fini(ndr_buf_t
*);
497 int ndr_buf_decode(ndr_buf_t
*, unsigned, unsigned, const char *data
, size_t,
499 int ndr_decode_call(ndr_xa_t
*, void *);
500 int ndr_encode_return(ndr_xa_t
*, void *);
501 int ndr_encode_call(ndr_xa_t
*, void *);
502 int ndr_decode_return(ndr_xa_t
*, void *);
503 int ndr_decode_pdu_hdr(ndr_xa_t
*);
504 int ndr_encode_pdu_hdr(ndr_xa_t
*);
505 void ndr_decode_frag_hdr(ndr_stream_t
*, ndr_common_header_t
*);
506 void ndr_remove_frag_hdr(ndr_stream_t
*);
507 void ndr_show_hdr(ndr_common_header_t
*);
508 unsigned ndr_bind_ack_hdr_size(ndr_xa_t
*);
509 unsigned ndr_alter_context_rsp_hdr_size(void);
512 void ndr_pipe_worker(ndr_pipe_t
*);
514 int ndr_generic_call_stub(ndr_xa_t
*);
517 ndr_stub_table_t
*ndr_svc_find_stub(ndr_service_t
*, int);
518 ndr_service_t
*ndr_svc_lookup_name(const char *);
519 ndr_service_t
*ndr_svc_lookup_uuid(ndr_uuid_t
*, int, ndr_uuid_t
*, int);
520 int ndr_svc_register(ndr_service_t
*);
521 void ndr_svc_unregister(ndr_service_t
*);
522 void ndr_svc_binding_pool_init(ndr_binding_t
**, ndr_binding_t pool
[], int);
523 ndr_binding_t
*ndr_svc_find_binding(ndr_xa_t
*, ndr_p_context_id_t
);
524 ndr_binding_t
*ndr_svc_new_binding(ndr_xa_t
*);
526 int ndr_uuid_parse(char *, ndr_uuid_t
*);
527 void ndr_uuid_unparse(ndr_uuid_t
*, char *);
529 ndr_hdid_t
*ndr_hdalloc(const ndr_xa_t
*, const void *);
530 void ndr_hdfree(const ndr_xa_t
*, const ndr_hdid_t
*);
531 ndr_handle_t
*ndr_hdlookup(const ndr_xa_t
*, const ndr_hdid_t
*);
532 void ndr_hdclose(ndr_pipe_t
*);
534 ssize_t
ndr_uiomove(caddr_t
, size_t, enum uio_rw
, struct uio
*);
537 * An ndr_client_t is created while binding a client connection to hold
538 * the context for calls made using that connection.
540 * Handles are RPC call specific and we use an inheritance mechanism to
541 * ensure that each handle has a pointer to the client_t. When the top
542 * level (bind) handle is released, we close the connection.
544 * There are some places in libmlsvc where the code assumes that the
545 * handle member is first in this struct. careful
547 typedef struct mlrpc_handle
{
548 ndr_hdid_t handle
; /* keep first */
552 int mlrpc_clh_create(mlrpc_handle_t
*, void *);
553 uint32_t mlrpc_clh_bind(mlrpc_handle_t
*, ndr_service_t
*);
554 void mlrpc_clh_unbind(mlrpc_handle_t
*);
555 void *mlrpc_clh_free(mlrpc_handle_t
*);
557 int ndr_rpc_call(mlrpc_handle_t
*, int, void *);
558 int ndr_rpc_get_ssnkey(mlrpc_handle_t
*, unsigned char *, size_t);
559 void *ndr_rpc_malloc(mlrpc_handle_t
*, size_t);
560 ndr_heap_t
*ndr_rpc_get_heap(mlrpc_handle_t
*);
561 void ndr_rpc_release(mlrpc_handle_t
*);
562 void ndr_rpc_set_nonull(mlrpc_handle_t
*);
564 boolean_t
ndr_is_null_handle(mlrpc_handle_t
*);
565 boolean_t
ndr_is_bind_handle(mlrpc_handle_t
*);
566 void ndr_inherit_handle(mlrpc_handle_t
*, mlrpc_handle_t
*);
572 #endif /* _LIBMLRPC_H */