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 * This module provides the interface to NDR RPC.
27 */
28
29 #include <sys/stat.h>
30 #include <sys/door.h>
31 #include <sys/door_data.h>
32 #include <sys/uio.h>
33 #include <sys/ksynch.h>
34 #include <smbsrv/smb_kproto.h>
35 #include <smbsrv/smb_xdr.h>
36
37 #define SMB_OPIPE_ISOPEN(OPIPE) \
38 (((OPIPE)->p_hdr.dh_magic == SMB_OPIPE_HDR_MAGIC) && \
39 ((OPIPE)->p_hdr.dh_fid))
40
41 extern volatile uint32_t smb_fids;
42
43 static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *);
44 static char *smb_opipe_lookup(const char *);
45 static int smb_opipe_sethdr(smb_opipe_t *, uint32_t, uint32_t);
46 static int smb_opipe_exec(smb_opipe_t *);
47 static void smb_opipe_enter(smb_opipe_t *);
48 static void smb_opipe_exit(smb_opipe_t *);
49
50 static door_handle_t smb_opipe_door_hd = NULL;
51 static int smb_opipe_door_id = -1;
52 static uint64_t smb_opipe_door_ncall = 0;
53 static kmutex_t smb_opipe_door_mutex;
54 static kcondvar_t smb_opipe_door_cv;
55
56 static int smb_opipe_door_call(smb_opipe_t *);
57 static int smb_opipe_door_upcall(smb_opipe_t *);
58
59 smb_opipe_t *
smb_opipe_alloc(smb_server_t * sv)60 smb_opipe_alloc(smb_server_t *sv)
61 {
62 smb_opipe_t *opipe;
63
64 opipe = kmem_cache_alloc(sv->si_cache_opipe, KM_SLEEP);
65
66 bzero(opipe, sizeof (smb_opipe_t));
67 mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
68 cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
69 opipe->p_magic = SMB_OPIPE_MAGIC;
70 opipe->p_server = sv;
71
72 smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
73 smb_llist_insert_tail(&sv->sv_opipe_list, opipe);
74 smb_llist_exit(&sv->sv_opipe_list);
75
76 return (opipe);
77 }
78
79 void
smb_opipe_dealloc(smb_opipe_t * opipe)80 smb_opipe_dealloc(smb_opipe_t *opipe)
81 {
82 smb_server_t *sv;
83
84 SMB_OPIPE_VALID(opipe);
85 sv = opipe->p_server;
86 SMB_SERVER_VALID(sv);
87
88 smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
89 smb_llist_remove(&sv->sv_opipe_list, opipe);
90 smb_llist_exit(&sv->sv_opipe_list);
91
92 opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC;
93 smb_event_destroy(opipe->p_event);
94 cv_destroy(&opipe->p_cv);
95 mutex_destroy(&opipe->p_mutex);
96
97 kmem_cache_free(sv->si_cache_opipe, opipe);
98 }
99
100 /*
101 * smb_opipe_open
102 *
103 * Open a well-known RPC named pipe. This routine should be called if
104 * a file open is requested on a share of type STYPE_IPC.
105 * If we recognize the pipe, we setup a new ofile.
106 *
107 * Returns 0 on success, Otherwise an NT status is returned to indicate
108 * an error.
109 */
110 int
smb_opipe_open(smb_request_t * sr)111 smb_opipe_open(smb_request_t *sr)
112 {
113 smb_arg_open_t *op = &sr->sr_open;
114 smb_ofile_t *of;
115 smb_opipe_t *opipe;
116 smb_doorhdr_t hdr;
117 smb_error_t err;
118 char *pipe_name;
119
120 if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL)
121 return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
122
123 op->create_options = 0;
124
125 of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op,
126 SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err);
127
128 if (of == NULL)
129 return (err.status);
130
131 if (!smb_tree_is_connected(sr->tid_tree)) {
132 smb_ofile_close(of, 0);
133 smb_ofile_release(of);
134 return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
135 }
136
137 op->dsize = 0x01000;
138 op->dattr = FILE_ATTRIBUTE_NORMAL;
139 op->ftype = SMB_FTYPE_MESG_PIPE;
140 op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
141 op->devstate = SMB_PIPE_READMODE_MESSAGE
142 | SMB_PIPE_TYPE_MESSAGE
143 | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
144 op->fileid = of->f_fid;
145
146 sr->smb_fid = of->f_fid;
147 sr->fid_ofile = of;
148
149 opipe = of->f_pipe;
150 smb_opipe_enter(opipe);
151
152 opipe->p_server = of->f_server;
153 opipe->p_name = pipe_name;
154 opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP);
155
156 /*
157 * p_data points to the offset within p_doorbuf at which
158 * data will be written or read.
159 */
160 opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_doorhdr_xdr, &hdr);
161
162 if (smb_opipe_do_open(sr, opipe) != 0) {
163 /*
164 * On error, reset the header to clear the fid,
165 * which avoids confusion when smb_opipe_close() is
166 * called by smb_ofile_close().
167 */
168 bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
169 kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
170 smb_opipe_exit(opipe);
171 smb_ofile_close(of, 0);
172 return (NT_STATUS_NO_MEMORY);
173 }
174 smb_opipe_exit(opipe);
175 return (NT_STATUS_SUCCESS);
176 }
177
178 /*
179 * smb_opipe_lookup
180 *
181 * Lookup a path to see if it's a well-known RPC named pipe that we support.
182 * The full pipe path will be in the form \\PIPE\\SERVICE. The first part
183 * can be assumed, so all we need here are the service names.
184 *
185 * Returns a pointer to the pipe name (without any leading \'s) on success.
186 * Otherwise returns a null pointer.
187 */
188 static char *
smb_opipe_lookup(const char * path)189 smb_opipe_lookup(const char *path)
190 {
191 static char *named_pipes[] = {
192 "lsass",
193 "LSARPC",
194 "NETLOGON",
195 "SAMR",
196 "SPOOLSS",
197 "SRVSVC",
198 "SVCCTL",
199 "WINREG",
200 "WKSSVC",
201 "EVENTLOG",
202 "NETDFS"
203 };
204
205 const char *name;
206 int i;
207
208 if (path == NULL)
209 return (NULL);
210
211 name = path;
212 name += strspn(name, "\\");
213 if (smb_strcasecmp(name, "PIPE", 4) == 0) {
214 path += 4;
215 name += strspn(name, "\\");
216 }
217
218 for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) {
219 if (smb_strcasecmp(name, named_pipes[i], 0) == 0)
220 return (named_pipes[i]);
221 }
222
223 return (NULL);
224 }
225
226 /*
227 * Initialize the opipe header and context, and make the door call.
228 */
229 static int
smb_opipe_do_open(smb_request_t * sr,smb_opipe_t * opipe)230 smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
231 {
232 smb_netuserinfo_t *userinfo = &opipe->p_user;
233 smb_user_t *user = sr->uid_user;
234 uint8_t *buf = opipe->p_doorbuf;
235 uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
236 uint32_t len;
237
238 if ((opipe->p_event = smb_event_create(SMB_EVENT_TIMEOUT)) == NULL)
239 return (-1);
240
241 smb_user_netinfo_init(user, userinfo);
242 len = xdr_sizeof(smb_netuserinfo_xdr, userinfo);
243
244 bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
245 opipe->p_hdr.dh_magic = SMB_OPIPE_HDR_MAGIC;
246 opipe->p_hdr.dh_flags = SMB_DF_SYSSPACE;
247 opipe->p_hdr.dh_fid = smb_event_txid(opipe->p_event);
248
249 if (smb_opipe_sethdr(opipe, SMB_OPIPE_OPEN, len) == -1)
250 return (-1);
251
252 len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
253 buf += len;
254 buflen -= len;
255
256 if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1)
257 return (-1);
258
259 return (smb_opipe_door_call(opipe));
260 }
261
262 /*
263 * smb_opipe_close
264 *
265 * Called whenever an IPC file/pipe is closed.
266 */
267 void
smb_opipe_close(smb_ofile_t * of)268 smb_opipe_close(smb_ofile_t *of)
269 {
270 smb_opipe_t *opipe;
271
272 ASSERT(of);
273 ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
274
275 opipe = of->f_pipe;
276 SMB_OPIPE_VALID(opipe);
277
278 (void) smb_server_cancel_event(opipe->p_hdr.dh_fid);
279 smb_opipe_enter(opipe);
280
281 if (SMB_OPIPE_ISOPEN(opipe)) {
282 (void) smb_opipe_sethdr(opipe, SMB_OPIPE_CLOSE, 0);
283 (void) smb_opipe_door_call(opipe);
284 bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
285 kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
286 }
287
288 smb_user_netinfo_fini(&opipe->p_user);
289 smb_opipe_exit(opipe);
290 }
291
292 static int
smb_opipe_sethdr(smb_opipe_t * opipe,uint32_t cmd,uint32_t datalen)293 smb_opipe_sethdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen)
294 {
295 opipe->p_hdr.dh_op = cmd;
296 opipe->p_hdr.dh_txid = opipe->p_hdr.dh_fid;
297 opipe->p_hdr.dh_datalen = datalen;
298 opipe->p_hdr.dh_resid = 0;
299 opipe->p_hdr.dh_door_rc = EINVAL;
300
301 return (smb_doorhdr_encode(&opipe->p_hdr, opipe->p_doorbuf,
302 SMB_OPIPE_DOOR_BUFSIZE));
303 }
304
305 /*
306 * smb_opipe_transact
307 *
308 * This is the entry point for RPC bind and request transactions.
309 * The fid is an arbitrary id used to associate RPC requests with a
310 * particular binding handle.
311 *
312 * If the data to be returned is larger than the client expects, we
313 * return as much as the client can handle and report a buffer overflow
314 * warning, which informs the client that we have more data to return.
315 * The residual data remains in the pipe until the client claims it or
316 * closes the pipe.
317 */
318 smb_sdrc_t
smb_opipe_transact(smb_request_t * sr,struct uio * uio)319 smb_opipe_transact(smb_request_t *sr, struct uio *uio)
320 {
321 smb_xa_t *xa;
322 smb_opipe_t *opipe;
323 struct mbuf *mhead;
324 int mdrcnt;
325 int nbytes;
326 int rc;
327
328 if ((rc = smb_opipe_write(sr, uio)) != 0) {
329 if (rc == EBADF)
330 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
331 ERRDOS, ERROR_INVALID_HANDLE);
332 else
333 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
334 ERRDOS, ERROR_INTERNAL_ERROR);
335 return (SDRC_ERROR);
336 }
337
338 opipe = sr->fid_ofile->f_pipe;
339
340 if ((rc = smb_opipe_exec(opipe)) != 0) {
341 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
342 ERRDOS, ERROR_INTERNAL_ERROR);
343 return (SDRC_ERROR);
344 }
345
346 xa = sr->r_xa;
347 mdrcnt = xa->smb_mdrcnt;
348 smb_opipe_enter(opipe);
349
350 if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) {
351 smb_opipe_exit(opipe);
352 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
353 ERRDOS, ERROR_INTERNAL_ERROR);
354 return (SDRC_ERROR);
355 }
356
357 rc = smb_opipe_door_call(opipe);
358 nbytes = opipe->p_hdr.dh_datalen;
359
360 if (rc != 0) {
361 smb_opipe_exit(opipe);
362 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
363 ERRDOS, ERROR_INTERNAL_ERROR);
364 return (SDRC_ERROR);
365 }
366
367 if (nbytes) {
368 mhead = smb_mbuf_get(opipe->p_data, nbytes);
369 xa->rep_data_mb.max_bytes = nbytes;
370 MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
371 }
372
373 if (opipe->p_hdr.dh_resid) {
374 /*
375 * The pipe contains more data than mdrcnt, warn the
376 * client that there is more data in the pipe.
377 * Typically, the client will call SmbReadX, which
378 * will call smb_opipe_read, to get the data.
379 */
380 smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
381 ERRDOS, ERROR_MORE_DATA);
382 }
383
384 smb_opipe_exit(opipe);
385 return (SDRC_SUCCESS);
386 }
387
388 /*
389 * smb_opipe_write
390 *
391 * Write RPC request data to the pipe. The client should call smb_opipe_read
392 * to complete the exchange and obtain the RPC response.
393 *
394 * Returns 0 on success or an errno on failure.
395 */
396 int
smb_opipe_write(smb_request_t * sr,struct uio * uio)397 smb_opipe_write(smb_request_t *sr, struct uio *uio)
398 {
399 smb_opipe_t *opipe;
400 uint32_t buflen;
401 uint32_t len;
402 int rc;
403
404 ASSERT(sr->fid_ofile);
405 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
406
407 opipe = sr->fid_ofile->f_pipe;
408 SMB_OPIPE_VALID(opipe);
409 smb_opipe_enter(opipe);
410
411 if (!SMB_OPIPE_ISOPEN(opipe)) {
412 smb_opipe_exit(opipe);
413 return (EBADF);
414 }
415
416 rc = smb_opipe_sethdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid);
417 len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
418 if (rc == -1 || len == 0) {
419 smb_opipe_exit(opipe);
420 return (ENOMEM);
421 }
422
423 buflen = SMB_OPIPE_DOOR_BUFSIZE - len;
424 (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio);
425
426 rc = smb_opipe_door_call(opipe);
427
428 smb_opipe_exit(opipe);
429 return ((rc == 0) ? 0 : EIO);
430 }
431
432 /*
433 * smb_opipe_read
434 *
435 * This interface may be called because smb_opipe_transact could not return
436 * all of the data in the original transaction or to form the second half
437 * of a transaction set up using smb_opipe_write. Either way, we just need
438 * to read data from the pipe and return it.
439 *
440 * The response data is encoded into raw_data as required by the smb_read
441 * functions. The uio_resid value indicates the number of bytes read.
442 */
443 int
smb_opipe_read(smb_request_t * sr,struct uio * uio)444 smb_opipe_read(smb_request_t *sr, struct uio *uio)
445 {
446 smb_opipe_t *opipe;
447 struct mbuf *mhead;
448 uint32_t nbytes;
449 int rc;
450
451 ASSERT(sr->fid_ofile);
452 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
453
454 opipe = sr->fid_ofile->f_pipe;
455 SMB_OPIPE_VALID(opipe);
456
457 if ((rc = smb_opipe_exec(opipe)) != 0)
458 return (EIO);
459
460 smb_opipe_enter(opipe);
461
462 if (!SMB_OPIPE_ISOPEN(opipe)) {
463 smb_opipe_exit(opipe);
464 return (EBADF);
465 }
466
467 if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) {
468 smb_opipe_exit(opipe);
469 return (ENOMEM);
470 }
471
472 rc = smb_opipe_door_call(opipe);
473 nbytes = opipe->p_hdr.dh_datalen;
474
475 if (rc != 0 || nbytes > uio->uio_resid) {
476 smb_opipe_exit(opipe);
477 return (EIO);
478 }
479
480 if (nbytes) {
481 mhead = smb_mbuf_get(opipe->p_data, nbytes);
482 MBC_SETUP(&sr->raw_data, nbytes);
483 MBC_ATTACH_MBUF(&sr->raw_data, mhead);
484 uio->uio_resid -= nbytes;
485 }
486
487 smb_opipe_exit(opipe);
488 return (rc);
489 }
490
491 static int
smb_opipe_exec(smb_opipe_t * opipe)492 smb_opipe_exec(smb_opipe_t *opipe)
493 {
494 uint32_t len;
495 int rc;
496
497 smb_opipe_enter(opipe);
498
499 rc = smb_opipe_sethdr(opipe, SMB_OPIPE_EXEC, 0);
500 len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
501 if (rc == -1 || len == 0) {
502 smb_opipe_exit(opipe);
503 return (ENOMEM);
504 }
505
506 if ((rc = smb_opipe_door_call(opipe)) == 0)
507 rc = smb_event_wait(opipe->p_event);
508
509 smb_opipe_exit(opipe);
510 return (rc);
511 }
512
513 /*
514 * Named pipe I/O is serialized per fid to ensure that each request
515 * has exclusive opipe access for the duration of the request.
516 */
517 static void
smb_opipe_enter(smb_opipe_t * opipe)518 smb_opipe_enter(smb_opipe_t *opipe)
519 {
520 mutex_enter(&opipe->p_mutex);
521
522 while (opipe->p_busy)
523 cv_wait(&opipe->p_cv, &opipe->p_mutex);
524
525 opipe->p_busy = 1;
526 mutex_exit(&opipe->p_mutex);
527 }
528
529 /*
530 * Exit busy state. If we have exec'd an RPC, we may have
531 * to wait for notification that processing has completed.
532 */
533 static void
smb_opipe_exit(smb_opipe_t * opipe)534 smb_opipe_exit(smb_opipe_t *opipe)
535 {
536 mutex_enter(&opipe->p_mutex);
537 opipe->p_busy = 0;
538 cv_signal(&opipe->p_cv);
539 mutex_exit(&opipe->p_mutex);
540 }
541
542 /*
543 * opipe door client (to user space door server).
544 */
545 void
smb_opipe_door_init(void)546 smb_opipe_door_init(void)
547 {
548 mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
549 cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL);
550 }
551
552 void
smb_opipe_door_fini(void)553 smb_opipe_door_fini(void)
554 {
555 smb_opipe_door_close();
556 cv_destroy(&smb_opipe_door_cv);
557 mutex_destroy(&smb_opipe_door_mutex);
558 }
559
560 /*
561 * Open the (user space) door. If the door is already open,
562 * close it first because the door-id has probably changed.
563 */
564 int
smb_opipe_door_open(int door_id)565 smb_opipe_door_open(int door_id)
566 {
567 smb_opipe_door_close();
568
569 mutex_enter(&smb_opipe_door_mutex);
570 smb_opipe_door_ncall = 0;
571
572 if (smb_opipe_door_hd == NULL) {
573 smb_opipe_door_id = door_id;
574 smb_opipe_door_hd = door_ki_lookup(door_id);
575 }
576
577 mutex_exit(&smb_opipe_door_mutex);
578 return ((smb_opipe_door_hd == NULL) ? -1 : 0);
579 }
580
581 /*
582 * Close the (user space) door.
583 */
584 void
smb_opipe_door_close(void)585 smb_opipe_door_close(void)
586 {
587 mutex_enter(&smb_opipe_door_mutex);
588
589 if (smb_opipe_door_hd != NULL) {
590 while (smb_opipe_door_ncall > 0)
591 cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex);
592
593 door_ki_rele(smb_opipe_door_hd);
594 smb_opipe_door_hd = NULL;
595 }
596
597 mutex_exit(&smb_opipe_door_mutex);
598 }
599
600 /*
601 * opipe door call interface.
602 * Door serialization and call reference accounting is handled here.
603 */
604 static int
smb_opipe_door_call(smb_opipe_t * opipe)605 smb_opipe_door_call(smb_opipe_t *opipe)
606 {
607 int rc;
608
609 mutex_enter(&smb_opipe_door_mutex);
610
611 if (smb_opipe_door_hd == NULL) {
612 mutex_exit(&smb_opipe_door_mutex);
613
614 if (smb_opipe_door_open(smb_opipe_door_id) != 0)
615 return (-1);
616
617 mutex_enter(&smb_opipe_door_mutex);
618 }
619
620 ++smb_opipe_door_ncall;
621 mutex_exit(&smb_opipe_door_mutex);
622
623 rc = smb_opipe_door_upcall(opipe);
624
625 mutex_enter(&smb_opipe_door_mutex);
626 if ((--smb_opipe_door_ncall) == 0)
627 cv_signal(&smb_opipe_door_cv);
628 mutex_exit(&smb_opipe_door_mutex);
629 return (rc);
630 }
631
632 /*
633 * Door upcall wrapper - handles data marshalling.
634 * This function should only be called by smb_opipe_door_call.
635 */
636 static int
smb_opipe_door_upcall(smb_opipe_t * opipe)637 smb_opipe_door_upcall(smb_opipe_t *opipe)
638 {
639 door_arg_t da;
640 smb_doorhdr_t hdr;
641 int i;
642 int rc;
643
644 da.data_ptr = (char *)opipe->p_doorbuf;
645 da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
646 da.desc_ptr = NULL;
647 da.desc_num = 0;
648 da.rbuf = (char *)opipe->p_doorbuf;
649 da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
650
651 for (i = 0; i < 3; ++i) {
652 if (smb_server_is_stopping())
653 return (-1);
654
655 if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da,
656 NULL, SIZE_MAX, 0)) == 0)
657 break;
658
659 if (rc != EAGAIN && rc != EINTR)
660 return (-1);
661 }
662
663 /* Check for door_return(NULL, 0, NULL, 0) */
664 if (rc != 0 || da.data_size == 0 || da.rsize == 0)
665 return (-1);
666
667 if (smb_doorhdr_decode(&hdr, (uint8_t *)da.data_ptr, da.rsize) == -1)
668 return (-1);
669
670 if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) ||
671 (hdr.dh_fid != opipe->p_hdr.dh_fid) ||
672 (hdr.dh_op != opipe->p_hdr.dh_op) ||
673 (hdr.dh_door_rc != 0) ||
674 (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
675 return (-1);
676 }
677
678 opipe->p_hdr.dh_datalen = hdr.dh_datalen;
679 opipe->p_hdr.dh_resid = hdr.dh_resid;
680 return (0);
681 }
682