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 */
24
25 /*
26 * Server side RPC handler.
27 */
28
29 #include <sys/byteorder.h>
30 #include <sys/errno.h>
31 #include <sys/uio.h>
32 #include <thread.h>
33 #include <synch.h>
34 #include <stdlib.h>
35 #include <strings.h>
36 #include <string.h>
37 #include <time.h>
38
39 #include <smbsrv/libsmb.h>
40 #include <smbsrv/libmlrpc.h>
41 #include <smbsrv/ntaccess.h>
42
43 /*
44 * Fragment size (5680: NT style).
45 */
46 #define NDR_FRAG_SZ 5680
47
48 #define NDR_GROW_SIZE (8 * 1024)
49 #define NDR_GROW_MASK (NDR_GROW_SIZE - 1)
50 #define NDR_ALIGN_BUF(S) (((S) + NDR_GROW_SIZE) & ~NDR_GROW_MASK)
51
52 #define NDR_PIPE_BUFSZ (64 * 1024)
53 #define NDR_PIPE_BUFMAX (64 * 1024 * 1024)
54 #define NDR_PIPE_MAX 128
55
56 static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX];
57 static mutex_t ndr_pipe_lock;
58
59 static int ndr_pipe_process(ndr_pipe_t *);
60 static ndr_pipe_t *ndr_pipe_lookup(int);
61 static void ndr_pipe_release(ndr_pipe_t *);
62 static ndr_pipe_t *ndr_pipe_allocate(int);
63 static int ndr_pipe_grow(ndr_pipe_t *, size_t);
64 static void ndr_pipe_deallocate(ndr_pipe_t *);
65 static void ndr_pipe_rewind(ndr_pipe_t *);
66 static void ndr_pipe_flush(ndr_pipe_t *);
67
68 static int ndr_svc_process(ndr_xa_t *);
69 static int ndr_svc_defrag(ndr_xa_t *);
70 static int ndr_svc_bind(ndr_xa_t *);
71 static int ndr_svc_request(ndr_xa_t *);
72 static void ndr_reply_prepare_hdr(ndr_xa_t *);
73 static int ndr_svc_alter_context(ndr_xa_t *);
74 static void ndr_reply_fault(ndr_xa_t *, unsigned long);
75 static int ndr_build_reply(ndr_xa_t *);
76 static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t);
77
78 /*
79 * Allocate and associate a service context with a fid.
80 */
81 int
ndr_pipe_open(int fid,uint8_t * data,uint32_t datalen)82 ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen)
83 {
84 ndr_pipe_t *np;
85
86 (void) mutex_lock(&ndr_pipe_lock);
87
88 if ((np = ndr_pipe_lookup(fid)) != NULL) {
89 ndr_pipe_release(np);
90 (void) mutex_unlock(&ndr_pipe_lock);
91 return (EEXIST);
92 }
93
94 if ((np = ndr_pipe_allocate(fid)) == NULL) {
95 (void) mutex_unlock(&ndr_pipe_lock);
96 return (ENOMEM);
97 }
98
99 if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) {
100 ndr_pipe_release(np);
101 (void) mutex_unlock(&ndr_pipe_lock);
102 return (EINVAL);
103 }
104
105 ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
106 NDR_N_BINDING_POOL);
107
108 (void) mutex_unlock(&ndr_pipe_lock);
109 return (0);
110 }
111
112 /*
113 * Release the context associated with a fid when an opipe is closed.
114 */
115 int
ndr_pipe_close(int fid)116 ndr_pipe_close(int fid)
117 {
118 ndr_pipe_t *np;
119
120 (void) mutex_lock(&ndr_pipe_lock);
121
122 if ((np = ndr_pipe_lookup(fid)) == NULL) {
123 (void) mutex_unlock(&ndr_pipe_lock);
124 return (ENOENT);
125 }
126
127 /*
128 * Release twice: once for the lookup above
129 * and again to close the fid.
130 */
131 ndr_pipe_release(np);
132 ndr_pipe_release(np);
133 (void) mutex_unlock(&ndr_pipe_lock);
134 return (0);
135 }
136
137 /*
138 * Write RPC request data to the input stream. Input data is buffered
139 * until the response is requested.
140 */
141 int
ndr_pipe_write(int fid,uint8_t * buf,uint32_t len)142 ndr_pipe_write(int fid, uint8_t *buf, uint32_t len)
143 {
144 ndr_pipe_t *np;
145 ssize_t nbytes;
146 int rc;
147
148 if (len == 0)
149 return (0);
150
151 (void) mutex_lock(&ndr_pipe_lock);
152
153 if ((np = ndr_pipe_lookup(fid)) == NULL) {
154 (void) mutex_unlock(&ndr_pipe_lock);
155 return (ENOENT);
156 }
157
158 if ((rc = ndr_pipe_grow(np, len)) != 0) {
159 (void) mutex_unlock(&ndr_pipe_lock);
160 return (rc);
161 }
162
163 nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio);
164
165 ndr_pipe_release(np);
166 (void) mutex_unlock(&ndr_pipe_lock);
167 return ((nbytes == len) ? 0 : EIO);
168 }
169
170 /*
171 * Read RPC response data.
172 */
173 int
ndr_pipe_read(int fid,uint8_t * buf,uint32_t * len,uint32_t * resid)174 ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
175 {
176 ndr_pipe_t *np;
177 ssize_t nbytes = *len;
178
179 if (nbytes == 0) {
180 *resid = 0;
181 return (0);
182 }
183
184 (void) mutex_lock(&ndr_pipe_lock);
185 if ((np = ndr_pipe_lookup(fid)) == NULL) {
186 (void) mutex_unlock(&ndr_pipe_lock);
187 return (ENOENT);
188 }
189 (void) mutex_unlock(&ndr_pipe_lock);
190
191 *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio);
192 *resid = np->np_frags.uio.uio_resid;
193
194 if (*resid == 0) {
195 /*
196 * Nothing left, cleanup the output stream.
197 */
198 ndr_pipe_flush(np);
199 }
200
201 (void) mutex_lock(&ndr_pipe_lock);
202 ndr_pipe_release(np);
203 (void) mutex_unlock(&ndr_pipe_lock);
204 return (0);
205 }
206
207 /*
208 * If the input stream contains an RPC request, process the RPC transaction,
209 * which will place the RPC response in the output (frags) stream.
210 *
211 * arg is freed here; it must have been allocated by malloc().
212 */
213 void *
ndr_pipe_transact(void * arg)214 ndr_pipe_transact(void *arg)
215 {
216 uint32_t *tmp = (uint32_t *)arg;
217 uint32_t fid;
218 ndr_pipe_t *np;
219
220 if (arg == NULL)
221 return (NULL);
222
223 fid = *tmp;
224
225 (void) mutex_lock(&ndr_pipe_lock);
226 if ((np = ndr_pipe_lookup(fid)) == NULL) {
227 (void) mutex_unlock(&ndr_pipe_lock);
228 (void) smb_kmod_event_notify(fid);
229 free(arg);
230 return (NULL);
231 }
232 (void) mutex_unlock(&ndr_pipe_lock);
233
234 if (ndr_pipe_process(np) != 0)
235 ndr_pipe_flush(np);
236
237 (void) mutex_lock(&ndr_pipe_lock);
238 ndr_pipe_release(np);
239 (void) mutex_unlock(&ndr_pipe_lock);
240 (void) smb_kmod_event_notify(fid);
241 free(arg);
242 return (NULL);
243 }
244
245 /*
246 * Process a server-side RPC request.
247 */
248 static int
ndr_pipe_process(ndr_pipe_t * np)249 ndr_pipe_process(ndr_pipe_t *np)
250 {
251 ndr_xa_t *mxa;
252 ndr_stream_t *recv_nds;
253 ndr_stream_t *send_nds;
254 char *data;
255 int datalen;
256 int rc;
257
258 data = np->np_buf;
259 datalen = np->np_uio.uio_offset;
260
261 if (datalen == 0)
262 return (0);
263
264 if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
265 return (ENOMEM);
266
267 bzero(mxa, sizeof (ndr_xa_t));
268 mxa->fid = np->np_fid;
269 mxa->pipe = np;
270 mxa->binding_list = np->np_binding;
271
272 if ((mxa->heap = ndr_heap_create()) == NULL) {
273 free(mxa);
274 return (ENOMEM);
275 }
276
277 recv_nds = &mxa->recv_nds;
278 rc = nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
279 if (rc != 0) {
280 ndr_heap_destroy(mxa->heap);
281 free(mxa);
282 return (ENOMEM);
283 }
284
285 /*
286 * Copy the input data and reset the input stream.
287 */
288 bcopy(data, recv_nds->pdu_base_addr, datalen);
289 ndr_pipe_rewind(np);
290
291 send_nds = &mxa->send_nds;
292 rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
293 if (rc != 0) {
294 nds_destruct(&mxa->recv_nds);
295 ndr_heap_destroy(mxa->heap);
296 free(mxa);
297 return (ENOMEM);
298 }
299
300 (void) ndr_svc_process(mxa);
301
302 nds_finalize(send_nds, &np->np_frags);
303 nds_destruct(&mxa->recv_nds);
304 nds_destruct(&mxa->send_nds);
305 ndr_heap_destroy(mxa->heap);
306 free(mxa);
307 return (0);
308 }
309
310 /*
311 * Must be called with ndr_pipe_lock held.
312 */
313 static ndr_pipe_t *
ndr_pipe_lookup(int fid)314 ndr_pipe_lookup(int fid)
315 {
316 ndr_pipe_t *np;
317 int i;
318
319 for (i = 0; i < NDR_PIPE_MAX; ++i) {
320 np = &ndr_pipe_table[i];
321
322 if (np->np_fid == fid) {
323 if (np->np_refcnt == 0)
324 return (NULL);
325
326 np->np_refcnt++;
327 return (np);
328 }
329 }
330
331 return (NULL);
332 }
333
334 /*
335 * Must be called with ndr_pipe_lock held.
336 */
337 static void
ndr_pipe_release(ndr_pipe_t * np)338 ndr_pipe_release(ndr_pipe_t *np)
339 {
340 np->np_refcnt--;
341 ndr_pipe_deallocate(np);
342 }
343
344 /*
345 * Must be called with ndr_pipe_lock held.
346 */
347 static ndr_pipe_t *
ndr_pipe_allocate(int fid)348 ndr_pipe_allocate(int fid)
349 {
350 ndr_pipe_t *np = NULL;
351 int i;
352
353 for (i = 0; i < NDR_PIPE_MAX; ++i) {
354 np = &ndr_pipe_table[i];
355
356 if (np->np_fid == 0) {
357 bzero(np, sizeof (ndr_pipe_t));
358
359 if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL)
360 return (NULL);
361
362 ndr_pipe_rewind(np);
363 np->np_fid = fid;
364 np->np_refcnt = 1;
365 return (np);
366 }
367 }
368
369 return (NULL);
370 }
371
372 /*
373 * If the desired space exceeds the current pipe size, try to expand
374 * the pipe. Leave the current pipe intact if the realloc fails.
375 *
376 * Must be called with ndr_pipe_lock held.
377 */
378 static int
ndr_pipe_grow(ndr_pipe_t * np,size_t desired)379 ndr_pipe_grow(ndr_pipe_t *np, size_t desired)
380 {
381 char *newbuf;
382 size_t current;
383 size_t required;
384
385 required = np->np_uio.uio_offset + desired;
386 current = np->np_uio.uio_offset + np->np_uio.uio_resid;
387
388 if (required <= current)
389 return (0);
390
391 if (required > NDR_PIPE_BUFMAX) {
392 smb_tracef("ndr_pipe_grow: required=%d, max=%d (ENOSPC)",
393 required, NDR_PIPE_BUFMAX);
394 return (ENOSPC);
395 }
396
397 required = NDR_ALIGN_BUF(required);
398 if (required > NDR_PIPE_BUFMAX)
399 required = NDR_PIPE_BUFMAX;
400
401 if ((newbuf = realloc(np->np_buf, required)) == NULL) {
402 smb_tracef("ndr_pipe_grow: realloc failed (ENOMEM)");
403 return (ENOMEM);
404 }
405
406 np->np_buf = newbuf;
407 np->np_iov.iov_base = np->np_buf + np->np_uio.uio_offset;
408 np->np_uio.uio_resid += desired;
409 np->np_iov.iov_len += desired;
410 return (0);
411 }
412
413 /*
414 * Must be called with ndr_pipe_lock held.
415 */
416 static void
ndr_pipe_deallocate(ndr_pipe_t * np)417 ndr_pipe_deallocate(ndr_pipe_t *np)
418 {
419 if (np->np_refcnt == 0) {
420 /*
421 * Ensure that there are no RPC service policy handles
422 * (associated with this fid) left around.
423 */
424 ndr_hdclose(np->np_fid);
425
426 ndr_pipe_rewind(np);
427 ndr_pipe_flush(np);
428 free(np->np_buf);
429 free(np->np_user.ui_domain);
430 free(np->np_user.ui_account);
431 free(np->np_user.ui_workstation);
432 bzero(np, sizeof (ndr_pipe_t));
433 }
434 }
435
436 /*
437 * Rewind the input data stream, ready for the next write.
438 */
439 static void
ndr_pipe_rewind(ndr_pipe_t * np)440 ndr_pipe_rewind(ndr_pipe_t *np)
441 {
442 np->np_uio.uio_iov = &np->np_iov;
443 np->np_uio.uio_iovcnt = 1;
444 np->np_uio.uio_offset = 0;
445 np->np_uio.uio_segflg = UIO_USERSPACE;
446 np->np_uio.uio_resid = NDR_PIPE_BUFSZ;
447 np->np_iov.iov_base = np->np_buf;
448 np->np_iov.iov_len = NDR_PIPE_BUFSZ;
449 }
450
451 /*
452 * Flush the output data stream.
453 */
454 static void
ndr_pipe_flush(ndr_pipe_t * np)455 ndr_pipe_flush(ndr_pipe_t *np)
456 {
457 ndr_frag_t *frag;
458
459 while ((frag = np->np_frags.head) != NULL) {
460 np->np_frags.head = frag->next;
461 free(frag);
462 }
463
464 free(np->np_frags.iov);
465 bzero(&np->np_frags, sizeof (ndr_fraglist_t));
466 }
467
468 /*
469 * Check whether or not the specified user has administrator privileges,
470 * i.e. is a member of Domain Admins or Administrators.
471 * Returns true if the user is an administrator, otherwise returns false.
472 */
473 boolean_t
ndr_is_admin(ndr_xa_t * xa)474 ndr_is_admin(ndr_xa_t *xa)
475 {
476 smb_netuserinfo_t *ctx = &xa->pipe->np_user;
477
478 return (ctx->ui_flags & SMB_ATF_ADMIN);
479 }
480
481 /*
482 * Check whether or not the specified user has power-user privileges,
483 * i.e. is a member of Domain Admins, Administrators or Power Users.
484 * This is typically required for operations such as managing shares.
485 * Returns true if the user is a power user, otherwise returns false.
486 */
487 boolean_t
ndr_is_poweruser(ndr_xa_t * xa)488 ndr_is_poweruser(ndr_xa_t *xa)
489 {
490 smb_netuserinfo_t *ctx = &xa->pipe->np_user;
491
492 return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
493 (ctx->ui_flags & SMB_ATF_POWERUSER));
494 }
495
496 int32_t
ndr_native_os(ndr_xa_t * xa)497 ndr_native_os(ndr_xa_t *xa)
498 {
499 smb_netuserinfo_t *ctx = &xa->pipe->np_user;
500
501 return (ctx->ui_native_os);
502 }
503
504 /*
505 * This is the entry point for all server-side RPC processing.
506 * It is assumed that the PDU has already been received.
507 */
508 static int
ndr_svc_process(ndr_xa_t * mxa)509 ndr_svc_process(ndr_xa_t *mxa)
510 {
511 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
512 ndr_stream_t *nds = &mxa->recv_nds;
513 unsigned long saved_offset;
514 unsigned long saved_size;
515 int rc;
516
517 rc = ndr_decode_pdu_hdr(mxa);
518 if (!NDR_DRC_IS_OK(rc))
519 return (-1);
520
521 (void) ndr_reply_prepare_hdr(mxa);
522
523 switch (mxa->ptype) {
524 case NDR_PTYPE_BIND:
525 rc = ndr_svc_bind(mxa);
526 break;
527
528 case NDR_PTYPE_REQUEST:
529 if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags)) {
530 ndr_show_hdr(hdr);
531 rc = NDR_DRC_FAULT_DECODE_FAILED;
532 goto ndr_svc_process_fault;
533 }
534
535 if (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) {
536 /*
537 * Multi-fragment request. Preserve the PDU scan
538 * offset and size during defrag so that we can
539 * continue as if we had received contiguous data.
540 */
541 saved_offset = nds->pdu_scan_offset;
542 saved_size = nds->pdu_size;
543
544 nds->pdu_scan_offset = hdr->frag_length;
545 nds->pdu_size = nds->pdu_max_size;
546
547 rc = ndr_svc_defrag(mxa);
548 if (NDR_DRC_IS_FAULT(rc)) {
549 ndr_show_hdr(hdr);
550 nds_show_state(nds);
551 goto ndr_svc_process_fault;
552 }
553
554 nds->pdu_scan_offset = saved_offset;
555 nds->pdu_size = saved_size;
556 }
557
558 rc = ndr_svc_request(mxa);
559 break;
560
561 case NDR_PTYPE_ALTER_CONTEXT:
562 rc = ndr_svc_alter_context(mxa);
563 break;
564
565 default:
566 rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
567 break;
568 }
569
570 ndr_svc_process_fault:
571 if (NDR_DRC_IS_FAULT(rc))
572 ndr_reply_fault(mxa, rc);
573
574 (void) ndr_build_reply(mxa);
575 return (rc);
576 }
577
578 /*
579 * Remove RPC fragment headers from the received data stream.
580 * The first fragment has already been accounted for before this call.
581 *
582 * NDR stream on entry:
583 *
584 * |<-- frag 2 -->|<-- frag 3 -->| ... |<- last frag ->|
585 *
586 * +-----+--------+-----+--------+-----+-----+---------+
587 * | hdr | data | hdr | data | ... | hdr | data |
588 * +-----+--------+-----+--------+-----+-----+---------+
589 *
590 * NDR stream on return:
591 *
592 * +----------------------------------+
593 * | data |
594 * +----------------------------------+
595 */
596 static int
ndr_svc_defrag(ndr_xa_t * mxa)597 ndr_svc_defrag(ndr_xa_t *mxa)
598 {
599 ndr_stream_t *nds = &mxa->recv_nds;
600 ndr_common_header_t frag_hdr;
601 int frag_size;
602 int last_frag;
603
604 do {
605 ndr_decode_frag_hdr(nds, &frag_hdr);
606 ndr_show_hdr(&frag_hdr);
607
608 if (NDR_IS_FIRST_FRAG(frag_hdr.pfc_flags))
609 return (NDR_DRC_FAULT_DECODE_FAILED);
610
611 last_frag = NDR_IS_LAST_FRAG(frag_hdr.pfc_flags);
612 frag_size = frag_hdr.frag_length;
613
614 if (frag_size > (nds->pdu_size - nds->pdu_scan_offset))
615 return (NDR_DRC_FAULT_DECODE_FAILED);
616
617 ndr_remove_frag_hdr(nds);
618 nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE;
619 } while (!last_frag);
620
621 return (NDR_DRC_OK);
622 }
623
624 /*
625 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
626 * p_results[] not supported.
627 */
628 static int
ndr_svc_bind(ndr_xa_t * mxa)629 ndr_svc_bind(ndr_xa_t *mxa)
630 {
631 ndr_p_cont_list_t *cont_list;
632 ndr_p_result_list_t *result_list;
633 ndr_p_result_t *result;
634 unsigned p_cont_id;
635 ndr_binding_t *mbind;
636 ndr_uuid_t *as_uuid;
637 ndr_uuid_t *ts_uuid;
638 int as_vers;
639 int ts_vers;
640 ndr_service_t *msvc;
641 int rc;
642 ndr_port_any_t *sec_addr;
643
644 /* acquire targets */
645 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
646 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
647 result = &result_list->p_results[0];
648
649 /*
650 * Set up temporary secondary address port.
651 * We will correct this later (below).
652 */
653 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
654 sec_addr->length = 13;
655 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
656
657 result_list->n_results = 1;
658 result_list->reserved = 0;
659 result_list->reserved2 = 0;
660 result->result = NDR_PCDR_ACCEPTANCE;
661 result->reason = 0;
662 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
663
664 /* sanity check */
665 if (cont_list->n_context_elem != 1 ||
666 cont_list->p_cont_elem[0].n_transfer_syn != 1) {
667 ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
668 }
669
670 p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
671
672 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
673 /*
674 * Duplicate presentation context id.
675 */
676 ndo_trace("ndr_svc_bind: duplicate binding");
677 return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
678 }
679
680 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
681 /*
682 * No free binding slot
683 */
684 result->result = NDR_PCDR_PROVIDER_REJECTION;
685 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
686 ndo_trace("ndr_svc_bind: no resources");
687 return (NDR_DRC_OK);
688 }
689
690 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
691 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
692
693 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
694 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
695
696 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
697 if (msvc == NULL) {
698 result->result = NDR_PCDR_PROVIDER_REJECTION;
699 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
700 return (NDR_DRC_OK);
701 }
702
703 /*
704 * We can now use the correct secondary address port.
705 */
706 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
707 sec_addr->length = strlen(msvc->sec_addr_port) + 1;
708 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
709 NDR_PORT_ANY_MAX_PORT_SPEC);
710
711 mbind->p_cont_id = p_cont_id;
712 mbind->which_side = NDR_BIND_SIDE_SERVER;
713 /* mbind->context set by app */
714 mbind->service = msvc;
715 mbind->instance_specific = 0;
716
717 mxa->binding = mbind;
718
719 if (msvc->bind_req) {
720 /*
721 * Call the service-specific bind() handler. If
722 * this fails, we shouild send a specific error
723 * on the bind ack.
724 */
725 rc = (msvc->bind_req)(mxa);
726 if (NDR_DRC_IS_FAULT(rc)) {
727 mbind->service = 0; /* free binding slot */
728 mbind->which_side = 0;
729 mbind->p_cont_id = 0;
730 mbind->instance_specific = 0;
731 return (rc);
732 }
733 }
734
735 result->transfer_syntax =
736 cont_list->p_cont_elem[0].transfer_syntaxes[0];
737
738 return (NDR_DRC_BINDING_MADE);
739 }
740
741 /*
742 * ndr_svc_alter_context
743 *
744 * The alter context request is used to request additional presentation
745 * context for another interface and/or version. It is very similar to
746 * a bind request.
747 */
748 static int
ndr_svc_alter_context(ndr_xa_t * mxa)749 ndr_svc_alter_context(ndr_xa_t *mxa)
750 {
751 ndr_p_result_list_t *result_list;
752 ndr_p_result_t *result;
753 ndr_p_cont_list_t *cont_list;
754 ndr_binding_t *mbind;
755 ndr_service_t *msvc;
756 unsigned p_cont_id;
757 ndr_uuid_t *as_uuid;
758 ndr_uuid_t *ts_uuid;
759 int as_vers;
760 int ts_vers;
761 ndr_port_any_t *sec_addr;
762
763 result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
764 result_list->n_results = 1;
765 result_list->reserved = 0;
766 result_list->reserved2 = 0;
767
768 result = &result_list->p_results[0];
769 result->result = NDR_PCDR_ACCEPTANCE;
770 result->reason = 0;
771 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
772
773 cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
774 p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
775
776 if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
777 return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
778
779 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
780 result->result = NDR_PCDR_PROVIDER_REJECTION;
781 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
782 return (NDR_DRC_OK);
783 }
784
785 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
786 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
787
788 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
789 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
790
791 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
792 if (msvc == NULL) {
793 result->result = NDR_PCDR_PROVIDER_REJECTION;
794 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
795 return (NDR_DRC_OK);
796 }
797
798 mbind->p_cont_id = p_cont_id;
799 mbind->which_side = NDR_BIND_SIDE_SERVER;
800 /* mbind->context set by app */
801 mbind->service = msvc;
802 mbind->instance_specific = 0;
803 mxa->binding = mbind;
804
805 sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
806 sec_addr->length = 0;
807 bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
808
809 result->transfer_syntax =
810 cont_list->p_cont_elem[0].transfer_syntaxes[0];
811
812 return (NDR_DRC_BINDING_MADE);
813 }
814
815 static int
ndr_svc_request(ndr_xa_t * mxa)816 ndr_svc_request(ndr_xa_t *mxa)
817 {
818 ndr_binding_t *mbind;
819 ndr_service_t *msvc;
820 unsigned p_cont_id;
821 int rc;
822
823 mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
824 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
825
826 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
827 return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
828
829 mxa->binding = mbind;
830 msvc = mbind->service;
831
832 /*
833 * Make room for the response hdr.
834 */
835 mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
836
837 if (msvc->call_stub)
838 rc = (*msvc->call_stub)(mxa);
839 else
840 rc = ndr_generic_call_stub(mxa);
841
842 if (NDR_DRC_IS_FAULT(rc)) {
843 ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
844 msvc->name, mxa->opnum, rc);
845 }
846
847 return (rc);
848 }
849
850 /*
851 * The transaction and the two nds streams use the same heap, which
852 * should already exist at this point. The heap will also be available
853 * to the stub.
854 */
855 int
ndr_generic_call_stub(ndr_xa_t * mxa)856 ndr_generic_call_stub(ndr_xa_t *mxa)
857 {
858 ndr_binding_t *mbind = mxa->binding;
859 ndr_service_t *msvc = mbind->service;
860 ndr_typeinfo_t *intf_ti = msvc->interface_ti;
861 ndr_stub_table_t *ste;
862 int opnum = mxa->opnum;
863 unsigned p_len = intf_ti->c_size_fixed_part;
864 char *param;
865 int rc;
866
867 if (mxa->heap == NULL) {
868 ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
869 return (NDR_DRC_FAULT_OUT_OF_MEMORY);
870 }
871
872 if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
873 ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
874 msvc->name, opnum);
875 return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
876 }
877
878 if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
879 return (NDR_DRC_FAULT_OUT_OF_MEMORY);
880
881 bzero(param, p_len);
882
883 rc = ndr_decode_call(mxa, param);
884 if (!NDR_DRC_IS_OK(rc))
885 return (rc);
886
887 rc = (*ste->func)(param, mxa);
888 if (rc == NDR_DRC_OK)
889 rc = ndr_encode_return(mxa, param);
890
891 return (rc);
892 }
893
894 /*
895 * We can perform some initial setup of the response header here.
896 * We also need to cache some of the information from the bind
897 * negotiation for use during subsequent RPC calls.
898 */
899 static void
ndr_reply_prepare_hdr(ndr_xa_t * mxa)900 ndr_reply_prepare_hdr(ndr_xa_t *mxa)
901 {
902 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
903 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
904
905 hdr->rpc_vers = 5;
906 hdr->rpc_vers_minor = 0;
907 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
908 hdr->packed_drep = rhdr->packed_drep;
909 hdr->frag_length = 0;
910 hdr->auth_length = 0;
911 hdr->call_id = rhdr->call_id;
912 #ifdef _BIG_ENDIAN
913 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
914 | NDR_REPLAB_INTG_BIG_ENDIAN;
915 #else
916 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
917 | NDR_REPLAB_INTG_LITTLE_ENDIAN;
918 #endif
919
920 switch (mxa->ptype) {
921 case NDR_PTYPE_BIND:
922 hdr->ptype = NDR_PTYPE_BIND_ACK;
923 mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
924 mxa->recv_hdr.bind_hdr.max_xmit_frag;
925 mxa->send_hdr.bind_ack_hdr.max_recv_frag =
926 mxa->recv_hdr.bind_hdr.max_recv_frag;
927 mxa->send_hdr.bind_ack_hdr.assoc_group_id =
928 mxa->recv_hdr.bind_hdr.assoc_group_id;
929
930 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
931 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
932
933 /*
934 * Save the maximum fragment sizes
935 * for use with subsequent requests.
936 */
937 mxa->pipe->np_max_xmit_frag =
938 mxa->recv_hdr.bind_hdr.max_xmit_frag;
939 mxa->pipe->np_max_recv_frag =
940 mxa->recv_hdr.bind_hdr.max_recv_frag;
941 break;
942
943 case NDR_PTYPE_REQUEST:
944 hdr->ptype = NDR_PTYPE_RESPONSE;
945 /* mxa->send_hdr.response_hdr.alloc_hint */
946 mxa->send_hdr.response_hdr.p_cont_id =
947 mxa->recv_hdr.request_hdr.p_cont_id;
948 mxa->send_hdr.response_hdr.cancel_count = 0;
949 mxa->send_hdr.response_hdr.reserved = 0;
950 break;
951
952 case NDR_PTYPE_ALTER_CONTEXT:
953 hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
954 /*
955 * The max_xmit_frag, max_recv_frag and assoc_group_id are
956 * ignored by the client but it's useful to fill them in.
957 */
958 mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
959 mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
960 mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
961 mxa->recv_hdr.alter_context_hdr.max_recv_frag;
962 mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
963 mxa->recv_hdr.alter_context_hdr.assoc_group_id;
964 break;
965
966 default:
967 hdr->ptype = 0xFF;
968 }
969 }
970
971 /*
972 * Signal an RPC fault. The stream is reset and we overwrite whatever
973 * was in the response header with the fault information.
974 */
975 static void
ndr_reply_fault(ndr_xa_t * mxa,unsigned long drc)976 ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
977 {
978 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
979 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
980 ndr_stream_t *nds = &mxa->send_nds;
981 unsigned long fault_status;
982
983 NDS_RESET(nds);
984
985 hdr->rpc_vers = 5;
986 hdr->rpc_vers_minor = 0;
987 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
988 hdr->packed_drep = rhdr->packed_drep;
989 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
990 hdr->auth_length = 0;
991 hdr->call_id = rhdr->call_id;
992 #ifdef _BIG_ENDIAN
993 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
994 | NDR_REPLAB_INTG_BIG_ENDIAN;
995 #else
996 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
997 | NDR_REPLAB_INTG_LITTLE_ENDIAN;
998 #endif
999
1000 switch (drc & NDR_DRC_MASK_SPECIFIER) {
1001 case NDR_DRC_FAULT_OUT_OF_MEMORY:
1002 case NDR_DRC_FAULT_ENCODE_TOO_BIG:
1003 fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
1004 break;
1005
1006 case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
1007 fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
1008 break;
1009
1010 case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
1011 fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
1012 break;
1013
1014 case NDR_DRC_FAULT_DECODE_FAILED:
1015 case NDR_DRC_FAULT_ENCODE_FAILED:
1016 fault_status = NDR_FAULT_NCA_PROTO_ERROR;
1017 break;
1018
1019 default:
1020 fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
1021 break;
1022 }
1023
1024 mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
1025 mxa->send_hdr.fault_hdr.status = fault_status;
1026 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
1027 }
1028
1029 /*
1030 * Note that the frag_length for bind ack and alter context is
1031 * non-standard.
1032 */
1033 static int
ndr_build_reply(ndr_xa_t * mxa)1034 ndr_build_reply(ndr_xa_t *mxa)
1035 {
1036 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
1037 ndr_stream_t *nds = &mxa->send_nds;
1038 uint8_t *pdu_buf;
1039 unsigned long pdu_size;
1040 unsigned long frag_size;
1041 unsigned long pdu_data_size;
1042 unsigned long frag_data_size;
1043
1044 frag_size = NDR_FRAG_SZ;
1045 pdu_size = nds->pdu_size;
1046 pdu_buf = nds->pdu_base_addr;
1047
1048 if (pdu_size <= frag_size) {
1049 /*
1050 * Single fragment response. The PDU size may be zero
1051 * here (i.e. bind or fault response). So don't make
1052 * any assumptions about it until after the header is
1053 * encoded.
1054 */
1055 switch (hdr->ptype) {
1056 case NDR_PTYPE_BIND_ACK:
1057 hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
1058 break;
1059
1060 case NDR_PTYPE_FAULT:
1061 /* already setup */
1062 break;
1063
1064 case NDR_PTYPE_RESPONSE:
1065 hdr->frag_length = pdu_size;
1066 mxa->send_hdr.response_hdr.alloc_hint =
1067 hdr->frag_length;
1068 break;
1069
1070 case NDR_PTYPE_ALTER_CONTEXT_RESP:
1071 hdr->frag_length = ndr_alter_context_rsp_hdr_size();
1072 break;
1073
1074 default:
1075 hdr->frag_length = pdu_size;
1076 break;
1077 }
1078
1079 nds->pdu_scan_offset = 0;
1080 (void) ndr_encode_pdu_hdr(mxa);
1081 pdu_size = nds->pdu_size;
1082 ndr_build_frag(nds, pdu_buf, pdu_size);
1083 return (0);
1084 }
1085
1086 /*
1087 * Multiple fragment response.
1088 */
1089 hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
1090 hdr->frag_length = frag_size;
1091 mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE;
1092 nds->pdu_scan_offset = 0;
1093 (void) ndr_encode_pdu_hdr(mxa);
1094 ndr_build_frag(nds, pdu_buf, frag_size);
1095
1096 /*
1097 * We need to update the 24-byte header in subsequent fragments.
1098 *
1099 * pdu_data_size: total data remaining to be handled
1100 * frag_size: total fragment size including header
1101 * frag_data_size: data in fragment
1102 * (i.e. frag_size - NDR_RSP_HDR_SIZE)
1103 */
1104 pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
1105 frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
1106
1107 while (pdu_data_size) {
1108 mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
1109 pdu_data_size -= frag_data_size;
1110 pdu_buf += frag_data_size;
1111
1112 if (pdu_data_size <= frag_data_size) {
1113 frag_data_size = pdu_data_size;
1114 frag_size = frag_data_size + NDR_RSP_HDR_SIZE;
1115 hdr->pfc_flags = NDR_PFC_LAST_FRAG;
1116 } else {
1117 hdr->pfc_flags = 0;
1118 }
1119
1120 hdr->frag_length = frag_size;
1121 nds->pdu_scan_offset = 0;
1122 (void) ndr_encode_pdu_hdr(mxa);
1123 bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
1124
1125 ndr_build_frag(nds, pdu_buf, frag_size);
1126
1127 if (hdr->pfc_flags & NDR_PFC_LAST_FRAG)
1128 break;
1129 }
1130
1131 return (0);
1132 }
1133
1134 /*
1135 * ndr_build_frag
1136 *
1137 * Build an RPC PDU fragment from the specified buffer.
1138 * If malloc fails, the client will see a header/pdu inconsistency
1139 * and report an error.
1140 */
1141 static void
ndr_build_frag(ndr_stream_t * nds,uint8_t * buf,uint32_t len)1142 ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len)
1143 {
1144 ndr_frag_t *frag;
1145 int size = sizeof (ndr_frag_t) + len;
1146
1147 if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
1148 return;
1149
1150 frag->next = NULL;
1151 frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
1152 frag->len = len;
1153 bcopy(buf, frag->buf, len);
1154
1155 if (nds->frags.head == NULL) {
1156 nds->frags.head = frag;
1157 nds->frags.tail = frag;
1158 nds->frags.nfrag = 1;
1159 } else {
1160 nds->frags.tail->next = frag;
1161 nds->frags.tail = frag;
1162 ++nds->frags.nfrag;
1163 }
1164 }
1165