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