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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 2018, Joyent, Inc.
25 */
26
27 /*
28 * Server side RPC handler.
29 */
30
31 #include <sys/byteorder.h>
32 #include <sys/uio.h>
33 #include <errno.h>
34 #include <synch.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <string.h>
38 #include <thread.h>
39
40 #include <libmlrpc.h>
41
42 #define NDR_PIPE_SEND(np, buf, len) \
43 ((np)->np_send)((np), (buf), (len))
44 #define NDR_PIPE_RECV(np, buf, len) \
45 ((np)->np_recv)((np), (buf), (len))
46
47 static int ndr_svc_process(ndr_xa_t *);
48 static int ndr_svc_bind(ndr_xa_t *);
49 static int ndr_svc_request(ndr_xa_t *);
50 static void ndr_reply_prepare_hdr(ndr_xa_t *);
51 static int ndr_svc_alter_context(ndr_xa_t *);
52 static void ndr_reply_fault(ndr_xa_t *, unsigned long);
53
54 static int ndr_recv_request(ndr_xa_t *mxa);
55 static int ndr_recv_frag(ndr_xa_t *mxa);
56 static int ndr_send_reply(ndr_xa_t *);
57
58 static int ndr_pipe_process(ndr_pipe_t *, ndr_xa_t *);
59
60 /*
61 * External entry point called by smbd.
62 */
63 void
ndr_pipe_worker(ndr_pipe_t * np)64 ndr_pipe_worker(ndr_pipe_t *np)
65 {
66 ndr_xa_t *mxa;
67 int rc;
68
69 ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
70 NDR_N_BINDING_POOL);
71
72 if ((mxa = malloc(sizeof (*mxa))) == NULL)
73 return;
74
75 do {
76 bzero(mxa, sizeof (*mxa));
77 rc = ndr_pipe_process(np, mxa);
78 } while (rc == 0);
79
80 free(mxa);
81
82 /*
83 * Ensure that there are no RPC service policy handles
84 * (associated with this fid) left around.
85 */
86 ndr_hdclose(np);
87 }
88
89 /*
90 * Process one server-side RPC request.
91 */
92 static int
ndr_pipe_process(ndr_pipe_t * np,ndr_xa_t * mxa)93 ndr_pipe_process(ndr_pipe_t *np, ndr_xa_t *mxa)
94 {
95 ndr_stream_t *recv_nds;
96 ndr_stream_t *send_nds;
97 int rc = ENOMEM;
98
99 mxa->pipe = np;
100 mxa->binding_list = np->np_binding;
101
102 if ((mxa->heap = ndr_heap_create()) == NULL)
103 goto out1;
104
105 recv_nds = &mxa->recv_nds;
106 rc = nds_initialize(recv_nds, 0, NDR_MODE_CALL_RECV, mxa->heap);
107 if (rc != 0)
108 goto out2;
109
110 send_nds = &mxa->send_nds;
111 rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
112 if (rc != 0)
113 goto out3;
114
115 rc = ndr_recv_request(mxa);
116 if (rc != 0)
117 goto out4;
118
119 (void) ndr_svc_process(mxa);
120 (void) ndr_send_reply(mxa);
121 rc = 0;
122
123 out4:
124 nds_destruct(&mxa->send_nds);
125 out3:
126 nds_destruct(&mxa->recv_nds);
127 out2:
128 ndr_heap_destroy(mxa->heap);
129 out1:
130 return (rc);
131 }
132
133 /*
134 * Receive an entire RPC request (all fragments)
135 * Returns zero or an NDR fault code.
136 */
137 static int
ndr_recv_request(ndr_xa_t * mxa)138 ndr_recv_request(ndr_xa_t *mxa)
139 {
140 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
141 ndr_stream_t *nds = &mxa->recv_nds;
142 unsigned long saved_size;
143 int rc;
144
145 rc = ndr_recv_frag(mxa);
146 if (rc != 0)
147 return (rc);
148 if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags))
149 return (NDR_DRC_FAULT_DECODE_FAILED);
150
151 while (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) {
152 rc = ndr_recv_frag(mxa);
153 if (rc != 0)
154 return (rc);
155 }
156 nds->pdu_scan_offset = 0;
157
158 /*
159 * This whacks nds->pdu_size, so save/restore.
160 * It leaves scan_offset after the header.
161 */
162 saved_size = nds->pdu_size;
163 rc = ndr_decode_pdu_hdr(mxa);
164 nds->pdu_size = saved_size;
165
166 return (rc);
167 }
168
169 /*
170 * Read one fragment, leaving the decoded frag header in
171 * recv_hdr.common_hdr, and the data in the recv_nds.
172 *
173 * Returns zero or an NDR fault code.
174 *
175 * If a first frag, the header is included in the data
176 * placed in recv_nds (because it's not fully decoded
177 * until later - we only decode the common part here).
178 * Additional frags are placed in the recv_nds without
179 * the header, so that after the first frag header,
180 * the remaining data will be contiguous. We do this
181 * by simply not advancing the offset in recv_nds after
182 * reading and decoding these additional fragments, so
183 * the payload of such frags will overwrite what was
184 * (temporarily) the frag header.
185 */
186 static int
ndr_recv_frag(ndr_xa_t * mxa)187 ndr_recv_frag(ndr_xa_t *mxa)
188 {
189 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
190 ndr_stream_t *nds = &mxa->recv_nds;
191 unsigned char *data;
192 unsigned long next_offset;
193 unsigned long pay_size;
194 int rc;
195
196 /* Make room for the frag header. */
197 next_offset = nds->pdu_scan_offset + NDR_RSP_HDR_SIZE;
198 if (!NDS_GROW_PDU(nds, next_offset, 0))
199 return (NDR_DRC_FAULT_OUT_OF_MEMORY);
200
201 /* Read the frag header. */
202 data = nds->pdu_base_addr + nds->pdu_scan_offset;
203 rc = NDR_PIPE_RECV(mxa->pipe, data, NDR_RSP_HDR_SIZE);
204 if (rc != 0)
205 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
206
207 /*
208 * Decode the frag header, get the length.
209 * NB: It uses nds->pdu_scan_offset
210 */
211 ndr_decode_frag_hdr(nds, hdr);
212 ndr_show_hdr(hdr);
213 if (hdr->frag_length < NDR_RSP_HDR_SIZE ||
214 hdr->frag_length > mxa->pipe->np_max_xmit_frag)
215 return (NDR_DRC_FAULT_DECODE_FAILED);
216
217 if (nds->pdu_scan_offset == 0) {
218 /* First frag: header stays in the data. */
219 nds->pdu_scan_offset = next_offset;
220 } /* else overwrite with the payload */
221
222 /* Make room for the payload. */
223 pay_size = hdr->frag_length - NDR_RSP_HDR_SIZE;
224 next_offset = nds->pdu_scan_offset + pay_size;
225 if (!NDS_GROW_PDU(nds, next_offset, 0))
226 return (NDR_DRC_FAULT_OUT_OF_MEMORY);
227
228 /* Read the payload. */
229 data = nds->pdu_base_addr + nds->pdu_scan_offset;
230 rc = NDR_PIPE_RECV(mxa->pipe, data, pay_size);
231 if (rc != 0)
232 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
233 nds->pdu_scan_offset = next_offset;
234
235 return (NDR_DRC_OK);
236 }
237
238 /*
239 * This is the entry point for all server-side RPC processing.
240 * It is assumed that the PDU has already been received.
241 */
242 static int
ndr_svc_process(ndr_xa_t * mxa)243 ndr_svc_process(ndr_xa_t *mxa)
244 {
245 int rc;
246
247 (void) ndr_reply_prepare_hdr(mxa);
248
249 switch (mxa->ptype) {
250 case NDR_PTYPE_BIND:
251 rc = ndr_svc_bind(mxa);
252 break;
253
254 case NDR_PTYPE_REQUEST:
255 rc = ndr_svc_request(mxa);
256 break;
257
258 case NDR_PTYPE_ALTER_CONTEXT:
259 rc = ndr_svc_alter_context(mxa);
260 break;
261
262 default:
263 rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
264 break;
265 }
266
267 if (NDR_DRC_IS_FAULT(rc))
268 ndr_reply_fault(mxa, rc);
269
270 return (rc);
271 }
272
273 /*
274 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
275 * p_results[] not supported.
276 */
277 static int
ndr_svc_bind(ndr_xa_t * mxa)278 ndr_svc_bind(ndr_xa_t *mxa)
279 {
280 ndr_p_cont_list_t *cont_list;
281 ndr_p_result_list_t *result_list;
282 ndr_p_result_t *result;
283 unsigned p_cont_id;
284 ndr_binding_t *mbind;
285 ndr_uuid_t *as_uuid;
286 ndr_uuid_t *ts_uuid;
287 int as_vers;
288 int ts_vers;
289 ndr_service_t *msvc;
290 int rc;
291 ndr_port_any_t *sec_addr;
292
293 /* acquire targets */
294 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
295 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
296 result = &result_list->p_results[0];
297
298 /*
299 * Set up temporary secondary address port.
300 * We will correct this later (below).
301 */
302 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
303 sec_addr->length = 13;
304 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
305
306 result_list->n_results = 1;
307 result_list->reserved = 0;
308 result_list->reserved2 = 0;
309 result->result = NDR_PCDR_ACCEPTANCE;
310 result->reason = 0;
311 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
312
313 /* sanity check */
314 if (cont_list->n_context_elem != 1 ||
315 cont_list->p_cont_elem[0].n_transfer_syn != 1) {
316 ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
317 }
318
319 p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
320
321 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
322 /*
323 * Duplicate presentation context id.
324 */
325 ndo_trace("ndr_svc_bind: duplicate binding");
326 return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
327 }
328
329 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
330 /*
331 * No free binding slot
332 */
333 result->result = NDR_PCDR_PROVIDER_REJECTION;
334 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
335 ndo_trace("ndr_svc_bind: no resources");
336 return (NDR_DRC_OK);
337 }
338
339 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
340 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
341
342 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
343 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
344
345 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
346 if (msvc == NULL) {
347 result->result = NDR_PCDR_PROVIDER_REJECTION;
348 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
349 return (NDR_DRC_OK);
350 }
351
352 /*
353 * We can now use the correct secondary address port.
354 */
355 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
356 sec_addr->length = strlen(msvc->sec_addr_port) + 1;
357 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
358 NDR_PORT_ANY_MAX_PORT_SPEC);
359
360 mbind->p_cont_id = p_cont_id;
361 mbind->which_side = NDR_BIND_SIDE_SERVER;
362 /* mbind->context set by app */
363 mbind->service = msvc;
364 mbind->instance_specific = 0;
365
366 mxa->binding = mbind;
367
368 if (msvc->bind_req) {
369 /*
370 * Call the service-specific bind() handler. If
371 * this fails, we shouild send a specific error
372 * on the bind ack.
373 */
374 rc = (msvc->bind_req)(mxa);
375 if (NDR_DRC_IS_FAULT(rc)) {
376 mbind->service = 0; /* free binding slot */
377 mbind->which_side = 0;
378 mbind->p_cont_id = 0;
379 mbind->instance_specific = 0;
380 return (rc);
381 }
382 }
383
384 result->transfer_syntax =
385 cont_list->p_cont_elem[0].transfer_syntaxes[0];
386
387 return (NDR_DRC_BINDING_MADE);
388 }
389
390 /*
391 * ndr_svc_alter_context
392 *
393 * The alter context request is used to request additional presentation
394 * context for another interface and/or version. It is very similar to
395 * a bind request.
396 */
397 static int
ndr_svc_alter_context(ndr_xa_t * mxa)398 ndr_svc_alter_context(ndr_xa_t *mxa)
399 {
400 ndr_p_result_list_t *result_list;
401 ndr_p_result_t *result;
402 ndr_p_cont_list_t *cont_list;
403 ndr_binding_t *mbind;
404 ndr_service_t *msvc;
405 unsigned p_cont_id;
406 ndr_uuid_t *as_uuid;
407 ndr_uuid_t *ts_uuid;
408 int as_vers;
409 int ts_vers;
410 ndr_port_any_t *sec_addr;
411
412 result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
413 result_list->n_results = 1;
414 result_list->reserved = 0;
415 result_list->reserved2 = 0;
416
417 result = &result_list->p_results[0];
418 result->result = NDR_PCDR_ACCEPTANCE;
419 result->reason = 0;
420 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
421
422 cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
423 p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
424
425 if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
426 return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
427
428 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
429 result->result = NDR_PCDR_PROVIDER_REJECTION;
430 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
431 return (NDR_DRC_OK);
432 }
433
434 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
435 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
436
437 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
438 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
439
440 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
441 if (msvc == NULL) {
442 result->result = NDR_PCDR_PROVIDER_REJECTION;
443 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
444 return (NDR_DRC_OK);
445 }
446
447 mbind->p_cont_id = p_cont_id;
448 mbind->which_side = NDR_BIND_SIDE_SERVER;
449 /* mbind->context set by app */
450 mbind->service = msvc;
451 mbind->instance_specific = 0;
452 mxa->binding = mbind;
453
454 sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
455 sec_addr->length = 0;
456 bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
457
458 result->transfer_syntax =
459 cont_list->p_cont_elem[0].transfer_syntaxes[0];
460
461 return (NDR_DRC_BINDING_MADE);
462 }
463
464 static int
ndr_svc_request(ndr_xa_t * mxa)465 ndr_svc_request(ndr_xa_t *mxa)
466 {
467 ndr_binding_t *mbind;
468 ndr_service_t *msvc;
469 unsigned p_cont_id;
470 int rc;
471
472 mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
473 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
474
475 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
476 return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
477
478 mxa->binding = mbind;
479 msvc = mbind->service;
480
481 /*
482 * Make room for the response hdr.
483 */
484 mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
485
486 if (msvc->call_stub)
487 rc = (*msvc->call_stub)(mxa);
488 else
489 rc = ndr_generic_call_stub(mxa);
490
491 if (NDR_DRC_IS_FAULT(rc)) {
492 ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
493 msvc->name, mxa->opnum, rc);
494 }
495
496 return (rc);
497 }
498
499 /*
500 * The transaction and the two nds streams use the same heap, which
501 * should already exist at this point. The heap will also be available
502 * to the stub.
503 */
504 int
ndr_generic_call_stub(ndr_xa_t * mxa)505 ndr_generic_call_stub(ndr_xa_t *mxa)
506 {
507 ndr_binding_t *mbind = mxa->binding;
508 ndr_service_t *msvc = mbind->service;
509 ndr_typeinfo_t *intf_ti = msvc->interface_ti;
510 ndr_stub_table_t *ste;
511 int opnum = mxa->opnum;
512 unsigned p_len = intf_ti->c_size_fixed_part;
513 char *param;
514 int rc;
515
516 if (mxa->heap == NULL) {
517 ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
518 return (NDR_DRC_FAULT_OUT_OF_MEMORY);
519 }
520
521 if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
522 ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
523 msvc->name, opnum);
524 return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
525 }
526
527 if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
528 return (NDR_DRC_FAULT_OUT_OF_MEMORY);
529
530 bzero(param, p_len);
531
532 rc = ndr_decode_call(mxa, param);
533 if (!NDR_DRC_IS_OK(rc))
534 return (rc);
535
536 rc = (*ste->func)(param, mxa);
537 if (rc == NDR_DRC_OK)
538 rc = ndr_encode_return(mxa, param);
539
540 return (rc);
541 }
542
543 /*
544 * We can perform some initial setup of the response header here.
545 * We also need to cache some of the information from the bind
546 * negotiation for use during subsequent RPC calls.
547 */
548 static void
ndr_reply_prepare_hdr(ndr_xa_t * mxa)549 ndr_reply_prepare_hdr(ndr_xa_t *mxa)
550 {
551 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
552 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
553
554 hdr->rpc_vers = 5;
555 hdr->rpc_vers_minor = 0;
556 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
557 hdr->packed_drep = rhdr->packed_drep;
558 hdr->frag_length = 0;
559 hdr->auth_length = 0;
560 hdr->call_id = rhdr->call_id;
561 #ifdef _BIG_ENDIAN
562 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
563 | NDR_REPLAB_INTG_BIG_ENDIAN;
564 #else
565 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
566 | NDR_REPLAB_INTG_LITTLE_ENDIAN;
567 #endif
568
569 switch (mxa->ptype) {
570 case NDR_PTYPE_BIND:
571 /*
572 * Compute the maximum fragment sizes for xmit/recv
573 * and store in the pipe endpoint. Note "xmit" is
574 * client-to-server; "recv" is server-to-client.
575 */
576 if (mxa->pipe->np_max_xmit_frag >
577 mxa->recv_hdr.bind_hdr.max_xmit_frag)
578 mxa->pipe->np_max_xmit_frag =
579 mxa->recv_hdr.bind_hdr.max_xmit_frag;
580 if (mxa->pipe->np_max_recv_frag >
581 mxa->recv_hdr.bind_hdr.max_recv_frag)
582 mxa->pipe->np_max_recv_frag =
583 mxa->recv_hdr.bind_hdr.max_recv_frag;
584
585 hdr->ptype = NDR_PTYPE_BIND_ACK;
586 mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
587 mxa->pipe->np_max_xmit_frag;
588 mxa->send_hdr.bind_ack_hdr.max_recv_frag =
589 mxa->pipe->np_max_recv_frag;
590
591 /*
592 * We're supposed to assign a unique "assoc group"
593 * (identifies this connection for the client).
594 * Using the pipe address is adequate.
595 */
596 mxa->send_hdr.bind_ack_hdr.assoc_group_id =
597 mxa->recv_hdr.bind_hdr.assoc_group_id;
598 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
599 mxa->send_hdr.bind_ack_hdr.assoc_group_id =
600 (DWORD)(uintptr_t)mxa->pipe;
601
602 break;
603
604 case NDR_PTYPE_REQUEST:
605 hdr->ptype = NDR_PTYPE_RESPONSE;
606 /* mxa->send_hdr.response_hdr.alloc_hint */
607 mxa->send_hdr.response_hdr.p_cont_id =
608 mxa->recv_hdr.request_hdr.p_cont_id;
609 mxa->send_hdr.response_hdr.cancel_count = 0;
610 mxa->send_hdr.response_hdr.reserved = 0;
611 break;
612
613 case NDR_PTYPE_ALTER_CONTEXT:
614 hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
615 /*
616 * The max_xmit_frag, max_recv_frag and assoc_group_id are
617 * ignored by the client but it's useful to fill them in.
618 */
619 mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
620 mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
621 mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
622 mxa->recv_hdr.alter_context_hdr.max_recv_frag;
623 mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
624 mxa->recv_hdr.alter_context_hdr.assoc_group_id;
625 break;
626
627 default:
628 hdr->ptype = 0xFF;
629 }
630 }
631
632 /*
633 * Signal an RPC fault. The stream is reset and we overwrite whatever
634 * was in the response header with the fault information.
635 */
636 static void
ndr_reply_fault(ndr_xa_t * mxa,unsigned long drc)637 ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
638 {
639 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
640 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
641 ndr_stream_t *nds = &mxa->send_nds;
642 unsigned long fault_status;
643
644 (void) NDS_RESET(nds);
645
646 hdr->rpc_vers = 5;
647 hdr->rpc_vers_minor = 0;
648 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
649 hdr->packed_drep = rhdr->packed_drep;
650 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
651 hdr->auth_length = 0;
652 hdr->call_id = rhdr->call_id;
653 #ifdef _BIG_ENDIAN
654 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
655 | NDR_REPLAB_INTG_BIG_ENDIAN;
656 #else
657 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
658 | NDR_REPLAB_INTG_LITTLE_ENDIAN;
659 #endif
660
661 switch (drc & NDR_DRC_MASK_SPECIFIER) {
662 case NDR_DRC_FAULT_OUT_OF_MEMORY:
663 case NDR_DRC_FAULT_ENCODE_TOO_BIG:
664 fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
665 break;
666
667 case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
668 fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
669 break;
670
671 case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
672 fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
673 break;
674
675 case NDR_DRC_FAULT_DECODE_FAILED:
676 case NDR_DRC_FAULT_ENCODE_FAILED:
677 fault_status = NDR_FAULT_NCA_PROTO_ERROR;
678 break;
679
680 default:
681 fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
682 break;
683 }
684
685 mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
686 mxa->send_hdr.fault_hdr.status = fault_status;
687 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
688 }
689
690 /*
691 * Note that the frag_length for bind ack and alter context is
692 * non-standard.
693 */
694 static int
ndr_send_reply(ndr_xa_t * mxa)695 ndr_send_reply(ndr_xa_t *mxa)
696 {
697 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
698 ndr_stream_t *nds = &mxa->send_nds;
699 uint8_t *pdu_buf;
700 unsigned long pdu_size;
701 unsigned long frag_size;
702 unsigned long pdu_data_size;
703 unsigned long frag_data_size;
704
705 frag_size = mxa->pipe->np_max_recv_frag;
706 pdu_size = nds->pdu_size;
707 pdu_buf = nds->pdu_base_addr;
708
709 if (pdu_size <= frag_size) {
710 /*
711 * Single fragment response. The PDU size may be zero
712 * here (i.e. bind or fault response). So don't make
713 * any assumptions about it until after the header is
714 * encoded.
715 */
716 switch (hdr->ptype) {
717 case NDR_PTYPE_BIND_ACK:
718 hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
719 break;
720
721 case NDR_PTYPE_FAULT:
722 /* already setup */
723 break;
724
725 case NDR_PTYPE_RESPONSE:
726 hdr->frag_length = pdu_size;
727 mxa->send_hdr.response_hdr.alloc_hint =
728 hdr->frag_length;
729 break;
730
731 case NDR_PTYPE_ALTER_CONTEXT_RESP:
732 hdr->frag_length = ndr_alter_context_rsp_hdr_size();
733 break;
734
735 default:
736 hdr->frag_length = pdu_size;
737 break;
738 }
739
740 nds->pdu_scan_offset = 0;
741 (void) ndr_encode_pdu_hdr(mxa);
742 pdu_size = nds->pdu_size;
743 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, pdu_size);
744 return (0);
745 }
746
747 /*
748 * Multiple fragment response.
749 *
750 * We need to update the RPC header for every fragment.
751 *
752 * pdu_data_size: total data remaining to be handled
753 * frag_size: total fragment size including header
754 * frag_data_size: data in fragment
755 * (i.e. frag_size - NDR_RSP_HDR_SIZE)
756 */
757 pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
758 frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
759
760 /*
761 * Send the first frag.
762 */
763 hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
764 hdr->frag_length = frag_size;
765 mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
766 nds->pdu_scan_offset = 0;
767 (void) ndr_encode_pdu_hdr(mxa);
768 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
769 pdu_data_size -= frag_data_size;
770 pdu_buf += frag_data_size;
771
772 /*
773 * Send "middle" (full-sized) fragments...
774 */
775 hdr->pfc_flags = 0;
776 while (pdu_data_size > frag_data_size) {
777
778 hdr->frag_length = frag_size;
779 mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
780 nds->pdu_scan_offset = 0;
781 (void) ndr_encode_pdu_hdr(mxa);
782 bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
783 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
784 pdu_data_size -= frag_data_size;
785 pdu_buf += frag_data_size;
786 }
787
788 /*
789 * Last frag (pdu_data_size <= frag_data_size)
790 */
791 hdr->pfc_flags = NDR_PFC_LAST_FRAG;
792 frag_size = pdu_data_size + NDR_RSP_HDR_SIZE;
793 hdr->frag_length = frag_size;
794 mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
795 nds->pdu_scan_offset = 0;
796 (void) ndr_encode_pdu_hdr(mxa);
797 bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
798 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
799
800 return (0);
801 }
802