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