summaryrefslogtreecommitdiff
path: root/usr/src/lib/libmlrpc/common/libmlrpc.h
blob: d020532cbeeb899bd3dce5400d1fea17cbb29bc9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
/*
 * 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
 */

#ifndef	_LIBMLRPC_H
#define	_LIBMLRPC_H

#include <sys/types.h>
#include <sys/uio.h>

#include <smb/wintypes.h>
#include <libmlrpc/ndr.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * An MSRPC compatible implementation of OSF DCE RPC.  DCE RPC is derived
 * from the Apollo Network Computing Architecture (NCA) RPC implementation.
 *
 * CAE Specification (1997)
 * DCE 1.1: Remote Procedure Call
 * Document Number: C706
 * The Open Group
 * ogspecs@opengroup.org
 *
 * This implementation is based on the DCE Remote Procedure Call spec with
 * enhancements to support Unicode strings.  The diagram below shows the
 * DCE RPC layers compared against ONC SUN RPC.
 *
 *	NDR RPC 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
 *	| ndr_*.c       |	|               |	Binding/PMAP
 *	+---------------+	+---------------+
 *	| RPC Protocol	|	| RPC Protocol  |	Headers, Auth,
 *	| rpcpdu.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  |	DCERPC does not talk
 *	| ndo_*.c       |	| clnt_{tcp,udp}|	directly to network.
 *	+---------------+	+---------------+
 *
 * There are two major differences between the DCE RPC and ONC RPC:
 *
 * 1. NDR RPC 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 ndr_stream_t.
 *    ndo_*.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. NDR RPC uses application provided heaps to support operations.
 *    A heap is a single, monolithic chunk of memory that NDR RPC manages
 *    as it allocates.  When the operation and its result are done, the
 *    heap is disposed of as a single item.  The transaction, 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.
 */

/*
 * Dispatch Return Code (DRC)
 *
 *	0x8000	15:01	Set to indicate a fault, clear indicates status
 *	0x7F00	08:07	Status/Fault specific
 *	0x00FF	00:08	PTYPE_... of PDU, 0xFF for header
 */
#define	NDR_DRC_OK				0x0000
#define	NDR_DRC_MASK_FAULT			0x8000
#define	NDR_DRC_MASK_SPECIFIER			0xFF00
#define	NDR_DRC_MASK_PTYPE			0x00FF

/* Fake PTYPE DRC discriminators */
#define	NDR_DRC_PTYPE_RPCHDR(DRC)		((DRC) | 0x00FF)
#define	NDR_DRC_PTYPE_API(DRC)			((DRC) | 0x00AA)

/* DRC Recognizers */
#define	NDR_DRC_IS_OK(DRC)	(((DRC) & NDR_DRC_MASK_SPECIFIER) == 0)
#define	NDR_DRC_IS_FAULT(DRC)	(((DRC) & NDR_DRC_MASK_FAULT) != 0)

/*
 * (Un)Marshalling category specifiers
 */
#define	NDR_DRC_FAULT_MODE_MISMATCH		0x8100
#define	NDR_DRC_RECEIVED			0x0200
#define	NDR_DRC_FAULT_RECEIVED_RUNT		0x8300
#define	NDR_DRC_FAULT_RECEIVED_MALFORMED	0x8400
#define	NDR_DRC_DECODED				0x0500
#define	NDR_DRC_FAULT_DECODE_FAILED		0x8600
#define	NDR_DRC_ENCODED				0x0700
#define	NDR_DRC_FAULT_ENCODE_FAILED		0x8800
#define	NDR_DRC_FAULT_ENCODE_TOO_BIG		0x8900
#define	NDR_DRC_SENT				0x0A00
#define	NDR_DRC_FAULT_SEND_FAILED		0x8B00

/*
 * Resource category specifier
 */
#define	NDR_DRC_FAULT_RESOURCE_1		0x9100
#define	NDR_DRC_FAULT_RESOURCE_2		0x9200

/*
 * Parameters. Usually #define'd with useful alias
 */
#define	NDR_DRC_FAULT_PARAM_0_INVALID		0xC000
#define	NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED	0xD000
#define	NDR_DRC_FAULT_PARAM_1_INVALID		0xC100
#define	NDR_DRC_FAULT_PARAM_1_UNIMPLEMENTED	0xD100
#define	NDR_DRC_FAULT_PARAM_2_INVALID		0xC200
#define	NDR_DRC_FAULT_PARAM_2_UNIMPLEMENTED	0xD200
#define	NDR_DRC_FAULT_PARAM_3_INVALID		0xC300
#define	NDR_DRC_FAULT_PARAM_3_UNIMPLEMENTED	0xD300

#define	NDR_DRC_FAULT_OUT_OF_MEMORY		0xF000

/* RPCHDR */
#define	NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH	0x81FF
#define	NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT	0x83FF
#define	NDR_DRC_FAULT_RPCHDR_DECODE_FAILED	0x86FF
#define	NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID	0xC0FF	/* PARAM_0_INVALID */
#define	NDR_DRC_FAULT_RPCHDR_PTYPE_UNIMPLEMENTED 0xD0FF	/* PARAM_0_UNIMP */

/* Request */
#define	NDR_DRC_FAULT_REQUEST_PCONT_INVALID	0xC000	/* PARAM_0_INVALID */
#define	NDR_DRC_FAULT_REQUEST_OPNUM_INVALID	0xC100	/* PARAM_1_INVALID */

/* Bind */
#define	NDR_DRC_BINDING_MADE			0x000B	/* OK */
#define	NDR_DRC_FAULT_BIND_PCONT_BUSY		0xC00B	/* PARAM_0_INVALID */
#define	NDR_DRC_FAULT_BIND_UNKNOWN_SERVICE	0xC10B	/* PARAM_1_INVALID */
#define	NDR_DRC_FAULT_BIND_NO_SLOTS		0x910B	/* RESOURCE_1 */

/* API */
#define	NDR_DRC_FAULT_API_SERVICE_INVALID	0xC0AA	/* PARAM_0_INVALID */
#define	NDR_DRC_FAULT_API_BIND_NO_SLOTS		0x91AA	/* RESOURCE_1 */
#define	NDR_DRC_FAULT_API_OPNUM_INVALID		0xC1AA	/* PARAM_1_INVALID */

struct ndr_xa;
struct ndr_client;

typedef struct ndr_stub_table {
	int		(*func)(void *, struct ndr_xa *);
	unsigned short	opnum;
} ndr_stub_table_t;

typedef struct ndr_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 ndr_xa *);
	ndr_typeinfo_t	*interface_ti;
	ndr_stub_table_t *stub_table;
} ndr_service_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 {
 *		....
 *		ndr_binding_t *binding_list_head;
 *		ndr_binding_t binding_pool[N_BINDING_POOL];
 *		....
 *	};
 *
 *	init_connection(struct connection *conn) {
 *		....
 *		ndr_svc_binding_pool_init(&conn->binding_list_head,
 *		    conn->binding_pool, N_BINDING_POOL);
 */
typedef struct ndr_binding {
	struct ndr_binding 	*next;
	ndr_p_context_id_t	p_cont_id;
	unsigned char		which_side;
	struct ndr_client	*clnt;
	ndr_service_t		*service;
	void 			*instance_specific;
} ndr_binding_t;

#define	NDR_BIND_SIDE_CLIENT	1
#define	NDR_BIND_SIDE_SERVER	2

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

/*
 * The binding list space must be provided by the application library
 * for use by the underlying RPC library.  We need at least two binding
 * slots per connection.
 */
#define	NDR_N_BINDING_POOL	2

typedef struct ndr_pipe {
	void			*np_listener;
	const char		*np_endpoint;
	struct smb_netuserinfo	*np_user;
	int			(*np_send)(struct ndr_pipe *, void *, size_t);
	int			(*np_recv)(struct ndr_pipe *, void *, size_t);
	int			np_fid;
	uint16_t		np_max_xmit_frag;
	uint16_t		np_max_recv_frag;
	ndr_binding_t		*np_binding;
	ndr_binding_t		np_binding_pool[NDR_N_BINDING_POOL];
} ndr_pipe_t;

/*
 * Number of bytes required to align SIZE on the next dword/4-byte
 * boundary.
 */
#define	NDR_ALIGN4(SIZE)	((4 - (SIZE)) & 3);

/*
 * DCE RPC strings (CAE section 14.3.4) are represented as varying or varying
 * and conformant one-dimensional arrays. Characters can be single-byte
 * or multi-byte as long as all characters conform to a fixed element size,
 * i.e. UCS-2 is okay but UTF-8 is not a valid DCE RPC string format. The
 * string is terminated by a null character of the appropriate element size.
 *
 * MSRPC strings should always be varying/conformant and not null terminated.
 * This format uses the size_is, first_is and length_is attributes (CAE
 * section 4.2.18).
 *
 *	typedef struct string {
 *		DWORD size_is;
 *		DWORD first_is;
 *		DWORD length_is;
 *		wchar_t string[ANY_SIZE_ARRAY];
 *	} string_t;
 *
 * The size_is attribute is used to specify the number of data elements in
 * each dimension of an array.
 *
 * The first_is attribute is used to define the lower bound for significant
 * elements in each dimension of an array. For strings this is always 0.
 *
 * The length_is attribute is used to define the number of significant
 * elements in each dimension of an array. For strings this is typically
 * the same as size_is. Although it might be (size_is - 1) if the string
 * is null terminated.
 *
 *   4 bytes   4 bytes   4 bytes  2bytes 2bytes 2bytes 2bytes
 * +---------+---------+---------+------+------+------+------+
 * |size_is  |first_is |length_is| char | char | char | char |
 * +---------+---------+---------+------+------+------+------+
 *
 * Unfortunately, not all MSRPC Unicode strings are null terminated, which
 * means that the recipient has to manually null-terminate the string after
 * it has been unmarshalled.  There may be a wide-char pad following a
 * string, and it may sometimes contains zero, but it's not guaranteed.
 *
 * To deal with this, MSRPC sometimes uses an additional wrapper with two
 * more fields, as shown below.
 *	length: the array length in bytes excluding terminating null bytes
 *	maxlen: the array length in bytes including null terminator bytes
 *	LPTSTR: converted to a string_t by NDR
 *
 * typedef struct ms_string {
 *		WORD length;
 *		WORD maxlen;
 *		LPTSTR str;
 * } ms_string_t;
 */
typedef struct ndr_mstring {
	uint16_t length;
	uint16_t allosize;
	LPTSTR str;
} ndr_mstring_t;

/*
 * 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 ndr_clnt_free_heap to free the memory.
 *
 * The heap management data definition looks a bit like this:
 *
 * heap -> +---------------+     +------------+
 *         | iovec[0].base | --> | data block |
 *         | iovec[0].len  |     +------------+
 *         +---------------+
 *                ::
 *                ::
 * iov  -> +---------------+     +------------+
 *         | iovec[n].base | --> | data block |
 *         | iovec[n].len  |     +------------+
 *         +---------------+     ^            ^
 *                               |            |
 *    next ----------------------+            |
 *    top  -----------------------------------+
 *
 */

/*
 * Setting MAXIOV to 384 will use ((8 * 384) + 16) = 3088 bytes
 * of the first heap block.
 */
#define	NDR_HEAP_MAXIOV		384
#define	NDR_HEAP_BLKSZ		8192

typedef struct ndr_heap {
	struct iovec iovec[NDR_HEAP_MAXIOV];
	struct iovec *iov;
	int iovcnt;
	char *top;
	char *next;
} ndr_heap_t;

/*
 * Alternate varying/conformant string definition
 * - for non-null-terminated strings.
 */
typedef struct ndr_vcs {
	/*
	 * 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[ANY_SIZE_ARRAY];
} ndr_vcs_t;

typedef struct ndr_vcstr {
	uint16_t wclen;
	uint16_t wcsize;
	ndr_vcs_t *vcs;
} ndr_vcstr_t;

typedef struct ndr_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;
	uint8_t buffer[ANY_SIZE_ARRAY];
} ndr_vcb_t;

typedef struct ndr_vcbuf {
	uint16_t len;
	uint16_t size;
	ndr_vcb_t *vcb;
} ndr_vcbuf_t;

ndr_heap_t *ndr_heap_create(void);
void ndr_heap_destroy(ndr_heap_t *);
void *ndr_heap_dupmem(ndr_heap_t *, const void *, size_t);
void *ndr_heap_malloc(ndr_heap_t *, unsigned);
void *ndr_heap_strdup(ndr_heap_t *, const char *);
int ndr_heap_mstring(ndr_heap_t *, const char *, ndr_mstring_t *);
void ndr_heap_mkvcs(ndr_heap_t *, char *, ndr_vcstr_t *);
void ndr_heap_mkvcb(ndr_heap_t *, uint8_t *, uint32_t, ndr_vcbuf_t *);
int ndr_heap_used(ndr_heap_t *);
int ndr_heap_avail(ndr_heap_t *);

#define	NDR_MALLOC(XA, SZ)	ndr_heap_malloc((XA)->heap, SZ)
#define	NDR_NEW(XA, T)		ndr_heap_malloc((XA)->heap, sizeof (T))
#define	NDR_NEWN(XA, T, N)	ndr_heap_malloc((XA)->heap, sizeof (T)*(N))
#define	NDR_STRDUP(XA, S)	ndr_heap_strdup((XA)->heap, (S))
#define	NDR_MSTRING(XA, S, OUT)	ndr_heap_mstring((XA)->heap, (S), (OUT))
#define	NDR_SIDDUP(XA, S)	ndr_heap_dupmem((XA)->heap, (S), smb_sid_len(S))

typedef struct ndr_xa {
	unsigned short		ptype;		/* high bits special */
	unsigned short		opnum;
	ndr_stream_t		recv_nds;
	ndr_hdr_t		recv_hdr;
	ndr_stream_t		send_nds;
	ndr_hdr_t		send_hdr;
	ndr_binding_t		*binding;	/* what we're using */
	ndr_binding_t		*binding_list;	/* from connection */
	ndr_heap_t		*heap;
	ndr_pipe_t		*pipe;
} ndr_xa_t;

/*
 * 20-byte opaque id used by various RPC services.
 */
CONTEXT_HANDLE(ndr_hdid) ndr_hdid_t;

typedef struct ndr_client {
	/* transport stuff (xa_* members) */
	int (*xa_init)(struct ndr_client *, ndr_xa_t *);
	int (*xa_exchange)(struct ndr_client *, ndr_xa_t *);
	int (*xa_read)(struct ndr_client *, ndr_xa_t *);
	void (*xa_preserve)(struct ndr_client *, ndr_xa_t *);
	void (*xa_destruct)(struct ndr_client *, ndr_xa_t *);
	void (*xa_release)(struct ndr_client *);
	void			*xa_private;
	int			xa_fd;

	ndr_hdid_t		*handle;
	ndr_binding_t		*binding;
	ndr_binding_t		*binding_list;
	ndr_binding_t		binding_pool[NDR_N_BINDING_POOL];

	boolean_t		nonull;
	boolean_t		heap_preserved;
	ndr_heap_t		*heap;
	ndr_stream_t		*recv_nds;
	ndr_stream_t		*send_nds;

	uint32_t		next_call_id;
	unsigned		next_p_cont_id;
} ndr_client_t;

typedef struct ndr_handle {
	ndr_hdid_t		nh_id;
	struct ndr_handle	*nh_next;
	ndr_pipe_t		*nh_pipe;
	const ndr_service_t	*nh_svc;
	ndr_client_t		*nh_clnt;
	void			*nh_data;
	void			(*nh_data_free)(void *);
} ndr_handle_t;

#define	NDR_PDU_SIZE_HINT_DEFAULT	(16*1024)
#define	NDR_BUF_MAGIC			0x4E425546	/* NBUF */

typedef struct ndr_buf {
	uint32_t		nb_magic;
	ndr_stream_t		nb_nds;
	ndr_heap_t		*nb_heap;
	ndr_typeinfo_t		*nb_ti;
} ndr_buf_t;

/* ndr_ops.c */
int nds_initialize(ndr_stream_t *, unsigned, int, ndr_heap_t *);
void nds_destruct(ndr_stream_t *);
void nds_show_state(ndr_stream_t *);

/* ndr_client.c */
int ndr_clnt_bind(ndr_client_t *, ndr_service_t *, ndr_binding_t **);
int ndr_clnt_call(ndr_binding_t *, int, void *);
void ndr_clnt_free_heap(ndr_client_t *);

/* ndr_marshal.c */
ndr_buf_t *ndr_buf_init(ndr_typeinfo_t *);
void ndr_buf_fini(ndr_buf_t *);
int ndr_buf_decode(ndr_buf_t *, unsigned, unsigned, const char *data, size_t,
    void *);
int ndr_decode_call(ndr_xa_t *, void *);
int ndr_encode_return(ndr_xa_t *, void *);
int ndr_encode_call(ndr_xa_t *, void *);
int ndr_decode_return(ndr_xa_t *, void *);
int ndr_decode_pdu_hdr(ndr_xa_t *);
int ndr_encode_pdu_hdr(ndr_xa_t *);
void ndr_decode_frag_hdr(ndr_stream_t *, ndr_common_header_t *);
void ndr_remove_frag_hdr(ndr_stream_t *);
void ndr_show_hdr(ndr_common_header_t *);
unsigned ndr_bind_ack_hdr_size(ndr_xa_t *);
unsigned ndr_alter_context_rsp_hdr_size(void);

/* ndr_server.c */
void ndr_pipe_worker(ndr_pipe_t *);

int ndr_generic_call_stub(ndr_xa_t *);

/* ndr_svc.c */
ndr_stub_table_t *ndr_svc_find_stub(ndr_service_t *, int);
ndr_service_t *ndr_svc_lookup_name(const char *);
ndr_service_t *ndr_svc_lookup_uuid(ndr_uuid_t *, int, ndr_uuid_t *, int);
int ndr_svc_register(ndr_service_t *);
void ndr_svc_unregister(ndr_service_t *);
void ndr_svc_binding_pool_init(ndr_binding_t **, ndr_binding_t pool[], int);
ndr_binding_t *ndr_svc_find_binding(ndr_xa_t *, ndr_p_context_id_t);
ndr_binding_t *ndr_svc_new_binding(ndr_xa_t *);

int ndr_uuid_parse(char *, ndr_uuid_t *);
void ndr_uuid_unparse(ndr_uuid_t *, char *);

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(ndr_pipe_t *);

ssize_t ndr_uiomove(caddr_t, size_t, enum uio_rw, struct uio *);

/*
 * An ndr_client_t is created while binding a client connection to hold
 * the context for calls made using that connection.
 *
 * Handles are RPC call specific and we use an inheritance mechanism to
 * ensure that each handle has a pointer to the client_t.  When the top
 * level (bind) handle is released, we close the connection.
 *
 * There are some places in libmlsvc where the code assumes that the
 * handle member is first in this struct.  careful
 */
typedef struct mlrpc_handle {
	ndr_hdid_t	handle;		/* keep first */
	ndr_client_t	*clnt;
} mlrpc_handle_t;

int mlrpc_clh_create(mlrpc_handle_t *, void *);
uint32_t mlrpc_clh_bind(mlrpc_handle_t *, ndr_service_t *);
void mlrpc_clh_unbind(mlrpc_handle_t *);
void *mlrpc_clh_free(mlrpc_handle_t *);

int ndr_rpc_call(mlrpc_handle_t *, int, void *);
int ndr_rpc_get_ssnkey(mlrpc_handle_t *, unsigned char *, size_t);
void *ndr_rpc_malloc(mlrpc_handle_t *, size_t);
ndr_heap_t *ndr_rpc_get_heap(mlrpc_handle_t *);
void ndr_rpc_release(mlrpc_handle_t *);
void ndr_rpc_set_nonull(mlrpc_handle_t *);

boolean_t ndr_is_null_handle(mlrpc_handle_t *);
boolean_t ndr_is_bind_handle(mlrpc_handle_t *);
void ndr_inherit_handle(mlrpc_handle_t *, mlrpc_handle_t *);

#ifdef	__cplusplus
}
#endif

#endif	/* _LIBMLRPC_H */