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