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