xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision 41afdfa77f9af46beb3aaab2eccc0d9afe660d31)
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 *
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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