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