1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #ifndef _LIBMLRPC_H 27 #define _LIBMLRPC_H 28 29 #include <sys/types.h> 30 #include <sys/uio.h> 31 #include <smbsrv/wintypes.h> 32 #include <smbsrv/ndr.h> 33 #include <smbsrv/smb_sid.h> 34 #include <smbsrv/smb_xdr.h> 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 /* 41 * An MSRPC compatible implementation of OSF DCE RPC. DCE RPC is derived 42 * from the Apollo Network Computing Architecture (NCA) RPC implementation. 43 * 44 * CAE Specification (1997) 45 * DCE 1.1: Remote Procedure Call 46 * Document Number: C706 47 * The Open Group 48 * ogspecs@opengroup.org 49 * 50 * This implementation is based on the DCE Remote Procedure Call spec with 51 * enhancements to support Unicode strings. The diagram below shows the 52 * DCE RPC layers compared against ONC SUN RPC. 53 * 54 * NDR RPC Layers Sun RPC Layers Remark 55 * +---------------+ +---------------+ +---------------+ 56 * +---------------+ +---------------+ 57 * | Application | | Application | The application 58 * +---------------+ +---------------+ 59 * | Hand coded | | RPCGEN gen'd | Where the real 60 * | client/server | | client/server | work happens 61 * | srvsvc.ndl | | *_svc.c *_clnt| 62 * | srvsvc.c | | | 63 * +---------------+ +---------------+ 64 * | RPC Library | | RPC Library | Calls/Return 65 * | ndr_*.c | | | Binding/PMAP 66 * +---------------+ +---------------+ 67 * | RPC Protocol | | RPC Protocol | Headers, Auth, 68 * | rpcpdu.ndl | | | 69 * +---------------+ +---------------+ 70 * | IDL gen'd | | RPCGEN gen'd | Aggregate 71 * | NDR stubs | | XDR stubs | Composition 72 * | *__ndr.c | | *_xdr.c | 73 * +---------------+ +---------------+ 74 * | NDR Represen | | XDR Represen | Byte order, padding 75 * +---------------+ +---------------+ 76 * | Packet Heaps | | Network Conn | DCERPC does not talk 77 * | ndo_*.c | | clnt_{tcp,udp}| directly to network. 78 * +---------------+ +---------------+ 79 * 80 * There are two major differences between the DCE RPC and ONC RPC: 81 * 82 * 1. NDR RPC only generates or processes packets from buffers. Other 83 * layers must take care of packet transmission and reception. 84 * The packet heaps are managed through a simple interface provided 85 * by the Network Data Representation (NDR) module called ndr_stream_t. 86 * ndo_*.c modules implement the different flavors (operations) of 87 * packet heaps. 88 * 89 * ONC RPC communicates directly with the network. You have to do 90 * something special for the RPC packet to be placed in a buffer 91 * rather than sent to the wire. 92 * 93 * 2. NDR RPC uses application provided heaps to support operations. 94 * A heap is a single, monolithic chunk of memory that NDR RPC manages 95 * as it allocates. When the operation and its result are done, the 96 * heap is disposed of as a single item. The transaction, which 97 * is the anchor of most operations, contains the necessary book- 98 * keeping for the heap. 99 * 100 * ONC RPC uses malloc() liberally throughout its run-time system. 101 * To free results, ONC RPC supports an XDR_FREE operation that 102 * traverses data structures freeing memory as it goes, whether 103 * it was malloc'd or not. 104 */ 105 106 /* 107 * Dispatch Return Code (DRC) 108 * 109 * 0x8000 15:01 Set to indicate a fault, clear indicates status 110 * 0x7F00 08:07 Status/Fault specific 111 * 0x00FF 00:08 PTYPE_... of PDU, 0xFF for header 112 */ 113 #define NDR_DRC_OK 0x0000 114 #define NDR_DRC_MASK_FAULT 0x8000 115 #define NDR_DRC_MASK_SPECIFIER 0xFF00 116 #define NDR_DRC_MASK_PTYPE 0x00FF 117 118 /* Fake PTYPE DRC discriminators */ 119 #define NDR_DRC_PTYPE_RPCHDR(DRC) ((DRC) | 0x00FF) 120 #define NDR_DRC_PTYPE_API(DRC) ((DRC) | 0x00AA) 121 122 /* DRC Recognizers */ 123 #define NDR_DRC_IS_OK(DRC) (((DRC) & NDR_DRC_MASK_SPECIFIER) == 0) 124 #define NDR_DRC_IS_FAULT(DRC) (((DRC) & NDR_DRC_MASK_FAULT) != 0) 125 126 /* 127 * (Un)Marshalling category specifiers 128 */ 129 #define NDR_DRC_FAULT_MODE_MISMATCH 0x8100 130 #define NDR_DRC_RECEIVED 0x0200 131 #define NDR_DRC_FAULT_RECEIVED_RUNT 0x8300 132 #define NDR_DRC_FAULT_RECEIVED_MALFORMED 0x8400 133 #define NDR_DRC_DECODED 0x0500 134 #define NDR_DRC_FAULT_DECODE_FAILED 0x8600 135 #define NDR_DRC_ENCODED 0x0700 136 #define NDR_DRC_FAULT_ENCODE_FAILED 0x8800 137 #define NDR_DRC_FAULT_ENCODE_TOO_BIG 0x8900 138 #define NDR_DRC_SENT 0x0A00 139 #define NDR_DRC_FAULT_SEND_FAILED 0x8B00 140 141 /* 142 * Resource category specifier 143 */ 144 #define NDR_DRC_FAULT_RESOURCE_1 0x9100 145 #define NDR_DRC_FAULT_RESOURCE_2 0x9200 146 147 /* 148 * Parameters. Usually #define'd with useful alias 149 */ 150 #define NDR_DRC_FAULT_PARAM_0_INVALID 0xC000 151 #define NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED 0xD000 152 #define NDR_DRC_FAULT_PARAM_1_INVALID 0xC100 153 #define NDR_DRC_FAULT_PARAM_1_UNIMPLEMENTED 0xD100 154 #define NDR_DRC_FAULT_PARAM_2_INVALID 0xC200 155 #define NDR_DRC_FAULT_PARAM_2_UNIMPLEMENTED 0xD200 156 #define NDR_DRC_FAULT_PARAM_3_INVALID 0xC300 157 #define NDR_DRC_FAULT_PARAM_3_UNIMPLEMENTED 0xD300 158 159 #define NDR_DRC_FAULT_OUT_OF_MEMORY 0xF000 160 161 /* RPCHDR */ 162 #define NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH 0x81FF 163 #define NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT 0x83FF 164 #define NDR_DRC_FAULT_RPCHDR_DECODE_FAILED 0x86FF 165 #define NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID 0xC0FF /* PARAM_0_INVALID */ 166 #define NDR_DRC_FAULT_RPCHDR_PTYPE_UNIMPLEMENTED 0xD0FF /* PARAM_0_UNIMP */ 167 168 /* Request */ 169 #define NDR_DRC_FAULT_REQUEST_PCONT_INVALID 0xC000 /* PARAM_0_INVALID */ 170 #define NDR_DRC_FAULT_REQUEST_OPNUM_INVALID 0xC100 /* PARAM_1_INVALID */ 171 172 /* Bind */ 173 #define NDR_DRC_BINDING_MADE 0x000B /* OK */ 174 #define NDR_DRC_FAULT_BIND_PCONT_BUSY 0xC00B /* PARAM_0_INVALID */ 175 #define NDR_DRC_FAULT_BIND_UNKNOWN_SERVICE 0xC10B /* PARAM_1_INVALID */ 176 #define NDR_DRC_FAULT_BIND_NO_SLOTS 0x910B /* RESOURCE_1 */ 177 178 /* API */ 179 #define NDR_DRC_FAULT_API_SERVICE_INVALID 0xC0AA /* PARAM_0_INVALID */ 180 #define NDR_DRC_FAULT_API_BIND_NO_SLOTS 0x91AA /* RESOURCE_1 */ 181 #define NDR_DRC_FAULT_API_OPNUM_INVALID 0xC1AA /* PARAM_1_INVALID */ 182 183 struct ndr_xa; 184 struct ndr_client; 185 186 typedef struct ndr_stub_table { 187 int (*func)(void *, struct ndr_xa *); 188 unsigned short opnum; 189 } ndr_stub_table_t; 190 191 typedef struct ndr_service { 192 char *name; 193 char *desc; 194 char *endpoint; 195 char *sec_addr_port; 196 char *abstract_syntax_uuid; 197 int abstract_syntax_version; 198 char *transfer_syntax_uuid; 199 int transfer_syntax_version; 200 unsigned bind_instance_size; 201 int (*bind_req)(); 202 int (*unbind_and_close)(); 203 int (*call_stub)(struct ndr_xa *); 204 ndr_typeinfo_t *interface_ti; 205 ndr_stub_table_t *stub_table; 206 } ndr_service_t; 207 208 /* 209 * The list of bindings is anchored at a connection. Nothing in the 210 * RPC mechanism allocates them. Binding elements which have service==0 211 * indicate free elements. When a connection is instantiated, at least 212 * one free binding entry should also be established. Something like 213 * this should suffice for most (all) situations: 214 * 215 * struct connection { 216 * .... 217 * ndr_binding_t *binding_list_head; 218 * ndr_binding_t binding_pool[N_BINDING_POOL]; 219 * .... 220 * }; 221 * 222 * init_connection(struct connection *conn) { 223 * .... 224 * ndr_svc_binding_pool_init(&conn->binding_list_head, 225 * conn->binding_pool, N_BINDING_POOL); 226 */ 227 typedef struct ndr_binding { 228 struct ndr_binding *next; 229 ndr_p_context_id_t p_cont_id; 230 unsigned char which_side; 231 struct ndr_client *clnt; 232 ndr_service_t *service; 233 void *instance_specific; 234 } ndr_binding_t; 235 236 #define NDR_BIND_SIDE_CLIENT 1 237 #define NDR_BIND_SIDE_SERVER 2 238 239 #define NDR_BINDING_TO_SPECIFIC(BINDING, TYPE) \ 240 ((TYPE *) (BINDING)->instance_specific) 241 242 /* 243 * The binding list space must be provided by the application library 244 * for use by the underlying RPC library. We need at least two binding 245 * slots per connection. 246 */ 247 #define NDR_N_BINDING_POOL 2 248 249 typedef struct ndr_pipe { 250 int np_fid; 251 uint32_t np_txid; 252 smb_netuserinfo_t np_user; 253 char *np_buf; 254 struct uio np_uio; 255 iovec_t np_iov; 256 ndr_fraglist_t np_frags; 257 int np_refcnt; 258 uint16_t np_max_xmit_frag; 259 uint16_t np_max_recv_frag; 260 ndr_binding_t *np_binding; 261 ndr_binding_t np_binding_pool[NDR_N_BINDING_POOL]; 262 } ndr_pipe_t; 263 264 typedef struct ndr_pipe_info { 265 uint32_t npi_fid; 266 uint32_t npi_permissions; 267 uint32_t npi_num_locks; 268 char npi_pathname[MAXPATHLEN]; 269 char npi_username[MAXNAMELEN]; 270 } ndr_pipe_info_t; 271 272 /* 273 * Number of bytes required to align SIZE on the next dword/4-byte 274 * boundary. 275 */ 276 #define NDR_ALIGN4(SIZE) ((4 - (SIZE)) & 3); 277 278 /* 279 * DCE RPC strings (CAE section 14.3.4) are represented as varying or varying 280 * and conformant one-dimensional arrays. Characters can be single-byte 281 * or multi-byte as long as all characters conform to a fixed element size, 282 * i.e. UCS-2 is okay but UTF-8 is not a valid DCE RPC string format. The 283 * string is terminated by a null character of the appropriate element size. 284 * 285 * MSRPC strings should always be varying/conformant and not null terminated. 286 * This format uses the size_is, first_is and length_is attributes (CAE 287 * section 4.2.18). 288 * 289 * typedef struct string { 290 * DWORD size_is; 291 * DWORD first_is; 292 * DWORD length_is; 293 * wchar_t string[ANY_SIZE_ARRAY]; 294 * } string_t; 295 * 296 * The size_is attribute is used to specify the number of data elements in 297 * each dimension of an array. 298 * 299 * The first_is attribute is used to define the lower bound for significant 300 * elements in each dimension of an array. For strings this is always 0. 301 * 302 * The length_is attribute is used to define the number of significant 303 * elements in each dimension of an array. For strings this is typically 304 * the same as size_is. Although it might be (size_is - 1) if the string 305 * is null terminated. 306 * 307 * 4 bytes 4 bytes 4 bytes 2bytes 2bytes 2bytes 2bytes 308 * +---------+---------+---------+------+------+------+------+ 309 * |size_is |first_is |length_is| char | char | char | char | 310 * +---------+---------+---------+------+------+------+------+ 311 * 312 * Unfortunately, not all MSRPC Unicode strings are null terminated, which 313 * means that the recipient has to manually null-terminate the string after 314 * it has been unmarshalled. There may be a wide-char pad following a 315 * string, and it may sometimes contains zero, but it's not guaranteed. 316 * 317 * To deal with this, MSRPC sometimes uses an additional wrapper with two 318 * more fields, as shown below. 319 * length: the array length in bytes excluding terminating null bytes 320 * maxlen: the array length in bytes including null terminator bytes 321 * LPTSTR: converted to a string_t by NDR 322 * 323 * typedef struct ms_string { 324 * WORD length; 325 * WORD maxlen; 326 * LPTSTR str; 327 * } ms_string_t; 328 */ 329 typedef struct ndr_mstring { 330 uint16_t length; 331 uint16_t allosize; 332 LPTSTR str; 333 } ndr_mstring_t; 334 335 /* 336 * A number of heap areas are used during marshalling and unmarshalling. 337 * Under some circumstances these areas can be discarded by the library 338 * code, i.e. on the server side before returning to the client and on 339 * completion of a client side bind. In the case of a client side RPC 340 * call, these areas must be preserved after an RPC returns to give the 341 * caller time to take a copy of the data. In this case the client must 342 * call ndr_clnt_free_heap to free the memory. 343 * 344 * The heap management data definition looks a bit like this: 345 * 346 * heap -> +---------------+ +------------+ 347 * | iovec[0].base | --> | data block | 348 * | iovec[0].len | +------------+ 349 * +---------------+ 350 * :: 351 * :: 352 * iov -> +---------------+ +------------+ 353 * | iovec[n].base | --> | data block | 354 * | iovec[n].len | +------------+ 355 * +---------------+ ^ ^ 356 * | | 357 * next ----------------------+ | 358 * top -----------------------------------+ 359 * 360 */ 361 362 /* 363 * Setting MAXIOV to 384 will use ((8 * 384) + 16) = 3088 bytes 364 * of the first heap block. 365 */ 366 #define NDR_HEAP_MAXIOV 384 367 #define NDR_HEAP_BLKSZ 8192 368 369 typedef struct ndr_heap { 370 struct iovec iovec[NDR_HEAP_MAXIOV]; 371 struct iovec *iov; 372 int iovcnt; 373 char *top; 374 char *next; 375 } ndr_heap_t; 376 377 /* 378 * Alternate varying/conformant string definition 379 * - for non-null-terminated strings. 380 */ 381 typedef struct ndr_vcs { 382 /* 383 * size_is (actually a copy of length_is) will 384 * be inserted here by the marshalling library. 385 */ 386 uint32_t vc_first_is; 387 uint32_t vc_length_is; 388 uint16_t buffer[ANY_SIZE_ARRAY]; 389 } ndr_vcs_t; 390 391 typedef struct ndr_vcstr { 392 uint16_t wclen; 393 uint16_t wcsize; 394 ndr_vcs_t *vcs; 395 } ndr_vcstr_t; 396 397 typedef struct ndr_vcb { 398 /* 399 * size_is (actually a copy of length_is) will 400 * be inserted here by the marshalling library. 401 */ 402 uint32_t vc_first_is; 403 uint32_t vc_length_is; 404 uint8_t buffer[ANY_SIZE_ARRAY]; 405 } ndr_vcb_t; 406 407 typedef struct ndr_vcbuf { 408 uint16_t len; 409 uint16_t size; 410 ndr_vcb_t *vcb; 411 } ndr_vcbuf_t; 412 413 ndr_heap_t *ndr_heap_create(void); 414 void ndr_heap_destroy(ndr_heap_t *); 415 void *ndr_heap_malloc(ndr_heap_t *, unsigned); 416 void *ndr_heap_strdup(ndr_heap_t *, const char *); 417 int ndr_heap_mstring(ndr_heap_t *, const char *, ndr_mstring_t *); 418 void ndr_heap_mkvcs(ndr_heap_t *, char *, ndr_vcstr_t *); 419 void ndr_heap_mkvcb(ndr_heap_t *, uint8_t *, uint32_t, ndr_vcbuf_t *); 420 smb_sid_t *ndr_heap_siddup(ndr_heap_t *, smb_sid_t *); 421 int ndr_heap_used(ndr_heap_t *); 422 int ndr_heap_avail(ndr_heap_t *); 423 424 #define NDR_MALLOC(XA, SZ) ndr_heap_malloc((XA)->heap, SZ) 425 #define NDR_NEW(XA, T) ndr_heap_malloc((XA)->heap, sizeof (T)) 426 #define NDR_NEWN(XA, T, N) ndr_heap_malloc((XA)->heap, sizeof (T)*(N)) 427 #define NDR_STRDUP(XA, S) ndr_heap_strdup((XA)->heap, (S)) 428 #define NDR_MSTRING(XA, S, OUT) ndr_heap_mstring((XA)->heap, (S), (OUT)) 429 #define NDR_SIDDUP(XA, S) ndr_heap_siddup((XA)->heap, (S)) 430 431 typedef struct ndr_xa { 432 int fid; 433 unsigned short ptype; /* high bits special */ 434 unsigned short opnum; 435 ndr_stream_t recv_nds; 436 ndr_hdr_t recv_hdr; 437 ndr_stream_t send_nds; 438 ndr_hdr_t send_hdr; 439 ndr_binding_t *binding; /* what we're using */ 440 ndr_binding_t *binding_list; /* from connection */ 441 ndr_heap_t *heap; 442 ndr_pipe_t *pipe; 443 } ndr_xa_t; 444 445 /* 446 * 20-byte opaque id used by various RPC services. 447 */ 448 CONTEXT_HANDLE(ndr_hdid) ndr_hdid_t; 449 450 typedef struct ndr_client { 451 /* transport stuff (xa_* members) */ 452 int (*xa_init)(struct ndr_client *, ndr_xa_t *); 453 int (*xa_exchange)(struct ndr_client *, ndr_xa_t *); 454 int (*xa_read)(struct ndr_client *, ndr_xa_t *); 455 void (*xa_preserve)(struct ndr_client *, ndr_xa_t *); 456 void (*xa_destruct)(struct ndr_client *, ndr_xa_t *); 457 void (*xa_release)(struct ndr_client *); 458 void *xa_private; 459 int xa_fd; 460 461 ndr_hdid_t *handle; 462 ndr_binding_t *binding; 463 ndr_binding_t *binding_list; 464 ndr_binding_t binding_pool[NDR_N_BINDING_POOL]; 465 466 boolean_t nonull; 467 boolean_t heap_preserved; 468 ndr_heap_t *heap; 469 ndr_stream_t *recv_nds; 470 ndr_stream_t *send_nds; 471 472 uint32_t next_call_id; 473 unsigned next_p_cont_id; 474 } ndr_client_t; 475 476 typedef struct ndr_handle { 477 ndr_hdid_t nh_id; 478 struct ndr_handle *nh_next; 479 int nh_fid; 480 const ndr_service_t *nh_svc; 481 ndr_client_t *nh_clnt; 482 void *nh_data; 483 void (*nh_data_free)(void *); 484 } ndr_handle_t; 485 486 #define NDR_PDU_SIZE_HINT_DEFAULT (16*1024) 487 #define NDR_BUF_MAGIC 0x4E425546 /* NBUF */ 488 489 typedef struct ndr_buf { 490 uint32_t nb_magic; 491 ndr_stream_t nb_nds; 492 ndr_heap_t *nb_heap; 493 ndr_typeinfo_t *nb_ti; 494 } ndr_buf_t; 495 496 /* ndr_ops.c */ 497 int nds_initialize(ndr_stream_t *, unsigned, int, ndr_heap_t *); 498 void nds_finalize(ndr_stream_t *, ndr_fraglist_t *); 499 void nds_destruct(ndr_stream_t *); 500 void nds_show_state(ndr_stream_t *); 501 502 /* ndr_client.c */ 503 int ndr_clnt_bind(ndr_client_t *, const char *, ndr_binding_t **); 504 int ndr_clnt_call(ndr_binding_t *, int, void *); 505 void ndr_clnt_free_heap(ndr_client_t *); 506 507 /* ndr_marshal.c */ 508 ndr_buf_t *ndr_buf_init(ndr_typeinfo_t *); 509 void ndr_buf_fini(ndr_buf_t *); 510 int ndr_buf_decode(ndr_buf_t *, unsigned, unsigned, const char *data, size_t, 511 void *); 512 int ndr_decode_call(ndr_xa_t *, void *); 513 int ndr_encode_return(ndr_xa_t *, void *); 514 int ndr_encode_call(ndr_xa_t *, void *); 515 int ndr_decode_return(ndr_xa_t *, void *); 516 int ndr_decode_pdu_hdr(ndr_xa_t *); 517 int ndr_encode_pdu_hdr(ndr_xa_t *); 518 void ndr_decode_frag_hdr(ndr_stream_t *, ndr_common_header_t *); 519 void ndr_remove_frag_hdr(ndr_stream_t *); 520 void ndr_show_hdr(ndr_common_header_t *); 521 unsigned ndr_bind_ack_hdr_size(ndr_xa_t *); 522 unsigned ndr_alter_context_rsp_hdr_size(void); 523 524 /* ndr_server.c */ 525 int ndr_pipe_open(int, uint8_t *, uint32_t); 526 int ndr_pipe_close(int); 527 int ndr_pipe_read(int, uint8_t *, uint32_t *, uint32_t *); 528 int ndr_pipe_write(int, uint8_t *, uint32_t); 529 void *ndr_pipe_transact(void *); 530 531 int ndr_generic_call_stub(ndr_xa_t *); 532 533 boolean_t ndr_is_admin(ndr_xa_t *); 534 boolean_t ndr_is_poweruser(ndr_xa_t *); 535 int32_t ndr_native_os(ndr_xa_t *); 536 537 /* ndr_svc.c */ 538 ndr_stub_table_t *ndr_svc_find_stub(ndr_service_t *, int); 539 ndr_service_t *ndr_svc_lookup_name(const char *); 540 ndr_service_t *ndr_svc_lookup_uuid(ndr_uuid_t *, int, ndr_uuid_t *, int); 541 int ndr_svc_register(ndr_service_t *); 542 void ndr_svc_unregister(ndr_service_t *); 543 void ndr_svc_binding_pool_init(ndr_binding_t **, ndr_binding_t pool[], int); 544 ndr_binding_t *ndr_svc_find_binding(ndr_xa_t *, ndr_p_context_id_t); 545 ndr_binding_t *ndr_svc_new_binding(ndr_xa_t *); 546 547 int ndr_uuid_parse(char *, ndr_uuid_t *); 548 void ndr_uuid_unparse(ndr_uuid_t *, char *); 549 550 ndr_hdid_t *ndr_hdalloc(const ndr_xa_t *, const void *); 551 void ndr_hdfree(const ndr_xa_t *, const ndr_hdid_t *); 552 ndr_handle_t *ndr_hdlookup(const ndr_xa_t *, const ndr_hdid_t *); 553 void ndr_hdclose(int fid); 554 555 ssize_t ndr_uiomove(caddr_t, size_t, enum uio_rw, struct uio *); 556 557 #ifdef __cplusplus 558 } 559 #endif 560 561 #endif /* _LIBMLRPC_H */ 562