13db3f65cSamw /*
23db3f65cSamw  * CDDL HEADER START
33db3f65cSamw  *
43db3f65cSamw  * The contents of this file are subject to the terms of the
53db3f65cSamw  * Common Development and Distribution License (the "License").
63db3f65cSamw  * You may not use this file except in compliance with the License.
73db3f65cSamw  *
83db3f65cSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93db3f65cSamw  * or http://www.opensolaris.org/os/licensing.
103db3f65cSamw  * See the License for the specific language governing permissions
113db3f65cSamw  * and limitations under the License.
123db3f65cSamw  *
133db3f65cSamw  * When distributing Covered Code, include this CDDL HEADER in each
143db3f65cSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153db3f65cSamw  * If applicable, add the following below this CDDL HEADER, with the
163db3f65cSamw  * fields enclosed by brackets "[]" replaced with your own identifying
173db3f65cSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
183db3f65cSamw  *
193db3f65cSamw  * CDDL HEADER END
203db3f65cSamw  */
213db3f65cSamw /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2368b2bbf2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
243db3f65cSamw  */
253db3f65cSamw 
263db3f65cSamw /*
273db3f65cSamw  * This module provides the interface to NDR RPC.
283db3f65cSamw  */
293db3f65cSamw 
303db3f65cSamw #include <sys/stat.h>
313db3f65cSamw #include <sys/uio.h>
323db3f65cSamw #include <sys/ksynch.h>
3368b2bbf2SGordon Ross #include <sys/stropts.h>
3468b2bbf2SGordon Ross #include <sys/socket.h>
3568b2bbf2SGordon Ross #include <sys/filio.h>
36bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
373db3f65cSamw #include <smbsrv/smb_xdr.h>
38*a90cf9f2SGordon Ross #include <smbsrv/winioctl.h>
39*a90cf9f2SGordon Ross 
40*a90cf9f2SGordon Ross static uint32_t smb_opipe_transceive(smb_request_t *, smb_fsctl_t *);
413db3f65cSamw 
4268b2bbf2SGordon Ross /*
4368b2bbf2SGordon Ross  * Allocate a new opipe and return it, or NULL, in which case
4468b2bbf2SGordon Ross  * the caller will report "internal error".
4568b2bbf2SGordon Ross  */
4668b2bbf2SGordon Ross static smb_opipe_t *
4768b2bbf2SGordon Ross smb_opipe_alloc(smb_request_t *sr)
489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
4968b2bbf2SGordon Ross 	smb_server_t	*sv = sr->sr_server;
509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_opipe_t	*opipe;
5168b2bbf2SGordon Ross 	ksocket_t	sock;
5268b2bbf2SGordon Ross 
5368b2bbf2SGordon Ross 	if (ksocket_socket(&sock, AF_UNIX, SOCK_STREAM, 0,
5468b2bbf2SGordon Ross 	    KSOCKET_SLEEP, sr->user_cr) != 0)
5568b2bbf2SGordon Ross 		return (NULL);
569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
578622ec45SGordon Ross 	opipe = kmem_cache_alloc(smb_cache_opipe, KM_SLEEP);
589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	bzero(opipe, sizeof (smb_opipe_t));
609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = SMB_OPIPE_MAGIC;
639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_server = sv;
6468b2bbf2SGordon Ross 	opipe->p_refcnt = 1;
6568b2bbf2SGordon Ross 	opipe->p_socket = sock;
669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (opipe);
689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7068b2bbf2SGordon Ross /*
7168b2bbf2SGordon Ross  * Destroy an opipe.  This is normally called from smb_ofile_delete
7268b2bbf2SGordon Ross  * when the ofile has no more references and is about to be free'd.
7368b2bbf2SGordon Ross  * This is also called here in error handling code paths, before
7468b2bbf2SGordon Ross  * the opipe is installed under an ofile.
7568b2bbf2SGordon Ross  */
769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(smb_opipe_t *opipe)
789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_server_t *sv;
809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	sv = opipe->p_server;
839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_SERVER_VALID(sv);
849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8568b2bbf2SGordon Ross 	/*
8668b2bbf2SGordon Ross 	 * This is called in the error path when opening,
8768b2bbf2SGordon Ross 	 * in which case we close the socket here.
8868b2bbf2SGordon Ross 	 */
8968b2bbf2SGordon Ross 	if (opipe->p_socket != NULL)
9068b2bbf2SGordon Ross 		(void) ksocket_close(opipe->p_socket, zone_kcred());
919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC;
939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_destroy(&opipe->p_cv);
949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_destroy(&opipe->p_mutex);
959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
968622ec45SGordon Ross 	kmem_cache_free(smb_cache_opipe, opipe);
979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
993db3f65cSamw /*
10068b2bbf2SGordon Ross  * Helper for open: build pipe name and connect.
1013db3f65cSamw  */
10268b2bbf2SGordon Ross static int
10368b2bbf2SGordon Ross smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe)
1043db3f65cSamw {
10568b2bbf2SGordon Ross 	struct sockaddr_un saddr;
106148c5f43SAlan Wright 	smb_arg_open_t	*op = &sr->sr_open;
10768b2bbf2SGordon Ross 	const char *name;
10868b2bbf2SGordon Ross 	int rc;
1093db3f65cSamw 
11068b2bbf2SGordon Ross 	name = op->fqi.fq_path.pn_path;
11168b2bbf2SGordon Ross 	name += strspn(name, "\\");
11268b2bbf2SGordon Ross 	if (smb_strcasecmp(name, "PIPE", 4) == 0) {
11368b2bbf2SGordon Ross 		name += 4;
11468b2bbf2SGordon Ross 		name += strspn(name, "\\");
11568b2bbf2SGordon Ross 	}
11668b2bbf2SGordon Ross 	(void) strlcpy(opipe->p_name, name, SMB_OPIPE_MAXNAME);
11768b2bbf2SGordon Ross 	(void) smb_strlwr(opipe->p_name);
1183db3f65cSamw 
11968b2bbf2SGordon Ross 	bzero(&saddr, sizeof (saddr));
12068b2bbf2SGordon Ross 	saddr.sun_family = AF_UNIX;
12168b2bbf2SGordon Ross 	(void) snprintf(saddr.sun_path, sizeof (saddr.sun_path),
12268b2bbf2SGordon Ross 	    "%s/%s", SMB_PIPE_DIR, opipe->p_name);
12368b2bbf2SGordon Ross 	rc = ksocket_connect(opipe->p_socket, (struct sockaddr *)&saddr,
12468b2bbf2SGordon Ross 	    sizeof (saddr), sr->user_cr);
125b7301bf5SGordon Ross 
12668b2bbf2SGordon Ross 	return (rc);
12768b2bbf2SGordon Ross }
128c8ec8eeaSjose borrego 
12968b2bbf2SGordon Ross /*
13068b2bbf2SGordon Ross  * Helper for open: encode and send the user info.
13168b2bbf2SGordon Ross  *
13268b2bbf2SGordon Ross  * We send information about this client + user to the
13368b2bbf2SGordon Ross  * pipe service so it can use it for access checks.
13468b2bbf2SGordon Ross  * The service MAY deny the open based on this info,
13568b2bbf2SGordon Ross  * (i.e. anonymous session trying to open a pipe that
13668b2bbf2SGordon Ross  * requires authentication) in which case we will read
13768b2bbf2SGordon Ross  * an error status from the service and return that.
13868b2bbf2SGordon Ross  */
13968b2bbf2SGordon Ross static void
14068b2bbf2SGordon Ross smb_opipe_send_userinfo(smb_request_t *sr, smb_opipe_t *opipe,
14168b2bbf2SGordon Ross     smb_error_t *errp)
14268b2bbf2SGordon Ross {
14368b2bbf2SGordon Ross 	XDR xdrs;
14468b2bbf2SGordon Ross 	smb_netuserinfo_t nui;
14568b2bbf2SGordon Ross 	smb_pipehdr_t phdr;
14668b2bbf2SGordon Ross 	char *buf;
14768b2bbf2SGordon Ross 	uint32_t buflen;
14868b2bbf2SGordon Ross 	uint32_t status;
14968b2bbf2SGordon Ross 	size_t iocnt = 0;
15068b2bbf2SGordon Ross 	int rc;
1518b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
15268b2bbf2SGordon Ross 	/*
15368b2bbf2SGordon Ross 	 * Any errors building the XDR message etc.
15468b2bbf2SGordon Ross 	 */
15568b2bbf2SGordon Ross 	errp->status = NT_STATUS_INTERNAL_ERROR;
1563db3f65cSamw 
15768b2bbf2SGordon Ross 	smb_user_netinfo_init(sr->uid_user, &nui);
15868b2bbf2SGordon Ross 	phdr.ph_magic = SMB_PIPE_HDR_MAGIC;
15968b2bbf2SGordon Ross 	phdr.ph_uilen = xdr_sizeof(smb_netuserinfo_xdr, &nui);
1608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
16168b2bbf2SGordon Ross 	buflen = sizeof (phdr) + phdr.ph_uilen;
16268b2bbf2SGordon Ross 	buf = kmem_alloc(buflen, KM_SLEEP);
1633db3f65cSamw 
16468b2bbf2SGordon Ross 	bcopy(&phdr, buf, sizeof (phdr));
16568b2bbf2SGordon Ross 	xdrmem_create(&xdrs, buf + sizeof (phdr),
16668b2bbf2SGordon Ross 	    buflen - (sizeof (phdr)), XDR_ENCODE);
16768b2bbf2SGordon Ross 	if (!smb_netuserinfo_xdr(&xdrs, &nui))
16868b2bbf2SGordon Ross 		goto out;
1693db3f65cSamw 
17068b2bbf2SGordon Ross 	/*
17168b2bbf2SGordon Ross 	 * If we fail sending the netuserinfo or recv'ing the
17268b2bbf2SGordon Ross 	 * status reponse, we have probably run into the limit
17368b2bbf2SGordon Ross 	 * on the number of open pipes.  That's this status:
17468b2bbf2SGordon Ross 	 */
17568b2bbf2SGordon Ross 	errp->status = NT_STATUS_PIPE_NOT_AVAILABLE;
17668b2bbf2SGordon Ross 
17768b2bbf2SGordon Ross 	rc = ksocket_send(opipe->p_socket, buf, buflen, 0,
17868b2bbf2SGordon Ross 	    &iocnt, sr->user_cr);
17968b2bbf2SGordon Ross 	if (rc == 0 && iocnt != buflen)
18068b2bbf2SGordon Ross 		rc = EIO;
18168b2bbf2SGordon Ross 	if (rc != 0)
18268b2bbf2SGordon Ross 		goto out;
1833db3f65cSamw 
18468b2bbf2SGordon Ross 	rc = ksocket_recv(opipe->p_socket, &status, sizeof (status), 0,
18568b2bbf2SGordon Ross 	    &iocnt, sr->user_cr);
18668b2bbf2SGordon Ross 	if (rc != 0 || iocnt != sizeof (status))
18768b2bbf2SGordon Ross 		goto out;
1883db3f65cSamw 
1893db3f65cSamw 	/*
19068b2bbf2SGordon Ross 	 * Return the status we read from the pipe service,
19168b2bbf2SGordon Ross 	 * normally NT_STATUS_SUCCESS, but could be something
19268b2bbf2SGordon Ross 	 * else like NT_STATUS_ACCESS_DENIED.
1933db3f65cSamw 	 */
19468b2bbf2SGordon Ross 	errp->status = status;
19568b2bbf2SGordon Ross 
19668b2bbf2SGordon Ross out:
19768b2bbf2SGordon Ross 	xdr_destroy(&xdrs);
19868b2bbf2SGordon Ross 	kmem_free(buf, buflen);
19968b2bbf2SGordon Ross 	smb_user_netinfo_fini(&nui);
2003db3f65cSamw }
2013db3f65cSamw 
2023db3f65cSamw /*
20368b2bbf2SGordon Ross  * smb_opipe_open
2043db3f65cSamw  *
20568b2bbf2SGordon Ross  * Open an RPC named pipe. This routine should be called if
20668b2bbf2SGordon Ross  * a file open is requested on a share of type STYPE_IPC.
20768b2bbf2SGordon Ross  * If we recognize the pipe, we setup a new ofile.
2083db3f65cSamw  *
20968b2bbf2SGordon Ross  * Returns 0 on success, Otherwise an NT status code.
2103db3f65cSamw  */
21168b2bbf2SGordon Ross int
21268b2bbf2SGordon Ross smb_opipe_open(smb_request_t *sr, uint32_t uniqid)
2133db3f65cSamw {
21468b2bbf2SGordon Ross 	smb_arg_open_t	*op = &sr->sr_open;
21568b2bbf2SGordon Ross 	smb_ofile_t *ofile;
21668b2bbf2SGordon Ross 	smb_opipe_t *opipe;
21768b2bbf2SGordon Ross 	smb_error_t err;
2183db3f65cSamw 
21968b2bbf2SGordon Ross 	opipe = smb_opipe_alloc(sr);
22068b2bbf2SGordon Ross 	if (opipe == NULL)
22168b2bbf2SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
2223db3f65cSamw 
22368b2bbf2SGordon Ross 	if (smb_opipe_connect(sr, opipe) != 0) {
22468b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
22568b2bbf2SGordon Ross 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
2263db3f65cSamw 	}
2273db3f65cSamw 
22868b2bbf2SGordon Ross 	smb_opipe_send_userinfo(sr, opipe, &err);
22968b2bbf2SGordon Ross 	if (err.status != 0) {
23068b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
23168b2bbf2SGordon Ross 		return (err.status);
2323db3f65cSamw 	}
2333db3f65cSamw 
23468b2bbf2SGordon Ross 	/*
23568b2bbf2SGordon Ross 	 * Note: If smb_ofile_open succeeds, the new ofile is
23668b2bbf2SGordon Ross 	 * in the FID lists can can be used by I/O requests.
23768b2bbf2SGordon Ross 	 */
23868b2bbf2SGordon Ross 	op->create_options = 0;
23968b2bbf2SGordon Ross 	op->pipe = opipe;
24068b2bbf2SGordon Ross 	ofile = smb_ofile_open(sr, NULL, op,
24168b2bbf2SGordon Ross 	    SMB_FTYPE_MESG_PIPE, uniqid, &err);
24268b2bbf2SGordon Ross 	op->pipe = NULL;
24368b2bbf2SGordon Ross 	if (ofile == NULL) {
24468b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
24568b2bbf2SGordon Ross 		return (err.status);
24668b2bbf2SGordon Ross 	}
2473db3f65cSamw 
24868b2bbf2SGordon Ross 	/* An "up" pointer, for debug. */
24968b2bbf2SGordon Ross 	opipe->p_ofile = ofile;
2503db3f65cSamw 
25168b2bbf2SGordon Ross 	op->dsize = 0x01000;
25268b2bbf2SGordon Ross 	op->dattr = FILE_ATTRIBUTE_NORMAL;
25368b2bbf2SGordon Ross 	op->ftype = SMB_FTYPE_MESG_PIPE;
25468b2bbf2SGordon Ross 	op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
25568b2bbf2SGordon Ross 	op->devstate = SMB_PIPE_READMODE_MESSAGE
25668b2bbf2SGordon Ross 	    | SMB_PIPE_TYPE_MESSAGE
25768b2bbf2SGordon Ross 	    | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
25868b2bbf2SGordon Ross 	op->fileid = ofile->f_fid;
2593db3f65cSamw 
26068b2bbf2SGordon Ross 	sr->smb_fid = ofile->f_fid;
26168b2bbf2SGordon Ross 	sr->fid_ofile = ofile;
2623db3f65cSamw 
26368b2bbf2SGordon Ross 	return (NT_STATUS_SUCCESS);
2643db3f65cSamw }
2653db3f65cSamw 
2663db3f65cSamw /*
2673db3f65cSamw  * smb_opipe_close
2683db3f65cSamw  *
26968b2bbf2SGordon Ross  * Called by smb_ofile_close for pipes.
27068b2bbf2SGordon Ross  *
27168b2bbf2SGordon Ross  * Note: ksocket_close may block while waiting for
27268b2bbf2SGordon Ross  * any I/O threads with a hold to get out.
2733db3f65cSamw  */
2743db3f65cSamw void
2753db3f65cSamw smb_opipe_close(smb_ofile_t *of)
2763db3f65cSamw {
2773db3f65cSamw 	smb_opipe_t *opipe;
27868b2bbf2SGordon Ross 	ksocket_t sock;
2793db3f65cSamw 
28068b2bbf2SGordon Ross 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
2813db3f65cSamw 	ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
2823db3f65cSamw 	opipe = of->f_pipe;
2839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
2849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
28568b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
28668b2bbf2SGordon Ross 	sock = opipe->p_socket;
28768b2bbf2SGordon Ross 	opipe->p_socket = NULL;
28868b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
2893db3f65cSamw 
29068b2bbf2SGordon Ross 	(void) ksocket_shutdown(sock, SHUT_RDWR, of->f_cr);
29168b2bbf2SGordon Ross 	(void) ksocket_close(sock, of->f_cr);
2923db3f65cSamw }
2933db3f65cSamw 
2943db3f65cSamw /*
2953db3f65cSamw  * smb_opipe_write
2963db3f65cSamw  *
2973db3f65cSamw  * Write RPC request data to the pipe.  The client should call smb_opipe_read
2983db3f65cSamw  * to complete the exchange and obtain the RPC response.
2993db3f65cSamw  *
3003db3f65cSamw  * Returns 0 on success or an errno on failure.
3013db3f65cSamw  */
3023db3f65cSamw int
3033db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio)
3043db3f65cSamw {
30568b2bbf2SGordon Ross 	struct nmsghdr msghdr;
30668b2bbf2SGordon Ross 	smb_ofile_t *ofile;
3073db3f65cSamw 	smb_opipe_t *opipe;
30868b2bbf2SGordon Ross 	ksocket_t sock;
30968b2bbf2SGordon Ross 	size_t sent = 0;
31068b2bbf2SGordon Ross 	int rc = 0;
3113db3f65cSamw 
31268b2bbf2SGordon Ross 	ofile = sr->fid_ofile;
31368b2bbf2SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
31468b2bbf2SGordon Ross 	opipe = ofile->f_pipe;
3159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
3163db3f65cSamw 
31768b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
31868b2bbf2SGordon Ross 	sock = opipe->p_socket;
31968b2bbf2SGordon Ross 	if (sock != NULL)
32068b2bbf2SGordon Ross 		ksocket_hold(sock);
32168b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
32268b2bbf2SGordon Ross 	if (sock == NULL)
3233db3f65cSamw 		return (EBADF);
3243db3f65cSamw 
32568b2bbf2SGordon Ross 	bzero(&msghdr, sizeof (msghdr));
32668b2bbf2SGordon Ross 	msghdr.msg_iov = uio->uio_iov;
32768b2bbf2SGordon Ross 	msghdr.msg_iovlen = uio->uio_iovcnt;
3283db3f65cSamw 
32968b2bbf2SGordon Ross 	/*
33068b2bbf2SGordon Ross 	 * This should block until we've sent it all,
33168b2bbf2SGordon Ross 	 * or given up due to errors (pipe closed).
33268b2bbf2SGordon Ross 	 */
33368b2bbf2SGordon Ross 	while (uio->uio_resid > 0) {
33468b2bbf2SGordon Ross 		rc = ksocket_sendmsg(sock, &msghdr, 0, &sent, ofile->f_cr);
33568b2bbf2SGordon Ross 		if (rc != 0)
33668b2bbf2SGordon Ross 			break;
33768b2bbf2SGordon Ross 		uio->uio_resid -= sent;
33868b2bbf2SGordon Ross 	}
3393db3f65cSamw 
34068b2bbf2SGordon Ross 	ksocket_rele(sock);
3413db3f65cSamw 
34268b2bbf2SGordon Ross 	return (rc);
3433db3f65cSamw }
3443db3f65cSamw 
3453db3f65cSamw /*
3463db3f65cSamw  * smb_opipe_read
3473db3f65cSamw  *
34868b2bbf2SGordon Ross  * This interface may be called from smb_opipe_transact (write, read)
34968b2bbf2SGordon Ross  * or from smb_read / smb2_read to get the rest of an RPC response.
35068b2bbf2SGordon Ross  * The response data (and length) are returned via the uio.
3513db3f65cSamw  */
3523db3f65cSamw int
3533db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio)
3543db3f65cSamw {
35568b2bbf2SGordon Ross 	struct nmsghdr msghdr;
35668b2bbf2SGordon Ross 	smb_ofile_t *ofile;
3573db3f65cSamw 	smb_opipe_t *opipe;
35868b2bbf2SGordon Ross 	ksocket_t sock;
35968b2bbf2SGordon Ross 	size_t recvcnt = 0;
3603db3f65cSamw 	int rc;
3613db3f65cSamw 
36268b2bbf2SGordon Ross 	ofile = sr->fid_ofile;
36368b2bbf2SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
36468b2bbf2SGordon Ross 	opipe = ofile->f_pipe;
3659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
3669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
36768b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
36868b2bbf2SGordon Ross 	sock = opipe->p_socket;
36968b2bbf2SGordon Ross 	if (sock != NULL)
37068b2bbf2SGordon Ross 		ksocket_hold(sock);
37168b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
37268b2bbf2SGordon Ross 	if (sock == NULL)
3733db3f65cSamw 		return (EBADF);
3743db3f65cSamw 
37568b2bbf2SGordon Ross 	bzero(&msghdr, sizeof (msghdr));
37668b2bbf2SGordon Ross 	msghdr.msg_iov = uio->uio_iov;
37768b2bbf2SGordon Ross 	msghdr.msg_iovlen = uio->uio_iovcnt;
3783db3f65cSamw 
37968b2bbf2SGordon Ross 	/*
38068b2bbf2SGordon Ross 	 * This should block only if there's no data.
38168b2bbf2SGordon Ross 	 * A single call to recvmsg does just that.
38268b2bbf2SGordon Ross 	 * (Intentionaly no recv loop here.)
38368b2bbf2SGordon Ross 	 */
38468b2bbf2SGordon Ross 	rc = ksocket_recvmsg(sock, &msghdr, 0,
38568b2bbf2SGordon Ross 	    &recvcnt, ofile->f_cr);
38668b2bbf2SGordon Ross 	if (rc != 0)
38768b2bbf2SGordon Ross 		goto out;
38868b2bbf2SGordon Ross 
38968b2bbf2SGordon Ross 	if (recvcnt == 0) {
39068b2bbf2SGordon Ross 		/* Other side closed. */
39168b2bbf2SGordon Ross 		rc = EPIPE;
39268b2bbf2SGordon Ross 		goto out;
3933db3f65cSamw 	}
39468b2bbf2SGordon Ross 	uio->uio_resid -= recvcnt;
3953db3f65cSamw 
39668b2bbf2SGordon Ross out:
39768b2bbf2SGordon Ross 	ksocket_rele(sock);
3989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
3999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (rc);
4009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
401bce01b59SGordon Ross 
402bce01b59SGordon Ross int
403*a90cf9f2SGordon Ross smb_opipe_ioctl(smb_request_t *sr, int cmd, void *arg, int *rvalp)
404bce01b59SGordon Ross {
405bce01b59SGordon Ross 	smb_ofile_t *ofile;
406bce01b59SGordon Ross 	smb_opipe_t *opipe;
407bce01b59SGordon Ross 	ksocket_t sock;
408*a90cf9f2SGordon Ross 	int rc;
409bce01b59SGordon Ross 
410bce01b59SGordon Ross 	ofile = sr->fid_ofile;
411bce01b59SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
412bce01b59SGordon Ross 	opipe = ofile->f_pipe;
413bce01b59SGordon Ross 	SMB_OPIPE_VALID(opipe);
414bce01b59SGordon Ross 
415bce01b59SGordon Ross 	mutex_enter(&opipe->p_mutex);
416bce01b59SGordon Ross 	sock = opipe->p_socket;
417bce01b59SGordon Ross 	if (sock != NULL)
418bce01b59SGordon Ross 		ksocket_hold(sock);
419bce01b59SGordon Ross 	mutex_exit(&opipe->p_mutex);
420bce01b59SGordon Ross 	if (sock == NULL)
421bce01b59SGordon Ross 		return (EBADF);
422bce01b59SGordon Ross 
423*a90cf9f2SGordon Ross 	rc = ksocket_ioctl(sock, cmd, (intptr_t)arg, rvalp, ofile->f_cr);
424bce01b59SGordon Ross 
425bce01b59SGordon Ross 	ksocket_rele(sock);
426bce01b59SGordon Ross 
427bce01b59SGordon Ross 	return (rc);
428bce01b59SGordon Ross }
429*a90cf9f2SGordon Ross 
430*a90cf9f2SGordon Ross /*
431*a90cf9f2SGordon Ross  * Get the smb_attr_t for a named pipe.
432*a90cf9f2SGordon Ross  * Caller has already cleared to zero.
433*a90cf9f2SGordon Ross  */
434*a90cf9f2SGordon Ross int
435*a90cf9f2SGordon Ross smb_opipe_getattr(smb_ofile_t *of, smb_attr_t *ap)
436*a90cf9f2SGordon Ross {
437*a90cf9f2SGordon Ross 
438*a90cf9f2SGordon Ross 	if (of->f_pipe == NULL)
439*a90cf9f2SGordon Ross 		return (EINVAL);
440*a90cf9f2SGordon Ross 
441*a90cf9f2SGordon Ross 	ap->sa_vattr.va_type = VFIFO;
442*a90cf9f2SGordon Ross 	ap->sa_vattr.va_nlink = 1;
443*a90cf9f2SGordon Ross 	ap->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
444*a90cf9f2SGordon Ross 	ap->sa_allocsz = 0x1000LL;
445*a90cf9f2SGordon Ross 
446*a90cf9f2SGordon Ross 	return (0);
447*a90cf9f2SGordon Ross }
448*a90cf9f2SGordon Ross 
449*a90cf9f2SGordon Ross int
450*a90cf9f2SGordon Ross smb_opipe_getname(smb_ofile_t *of, char *buf, size_t buflen)
451*a90cf9f2SGordon Ross {
452*a90cf9f2SGordon Ross 	smb_opipe_t *opipe;
453*a90cf9f2SGordon Ross 
454*a90cf9f2SGordon Ross 	if ((opipe = of->f_pipe) == NULL)
455*a90cf9f2SGordon Ross 		return (EINVAL);
456*a90cf9f2SGordon Ross 
457*a90cf9f2SGordon Ross 	(void) snprintf(buf, buflen, "\\%s", opipe->p_name);
458*a90cf9f2SGordon Ross 	return (0);
459*a90cf9f2SGordon Ross }
460*a90cf9f2SGordon Ross 
461*a90cf9f2SGordon Ross /*
462*a90cf9f2SGordon Ross  * Handler for smb2_ioctl
463*a90cf9f2SGordon Ross  */
464*a90cf9f2SGordon Ross /* ARGSUSED */
465*a90cf9f2SGordon Ross uint32_t
466*a90cf9f2SGordon Ross smb_opipe_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
467*a90cf9f2SGordon Ross {
468*a90cf9f2SGordon Ross 	uint32_t status;
469*a90cf9f2SGordon Ross 
470*a90cf9f2SGordon Ross 	switch (fsctl->CtlCode) {
471*a90cf9f2SGordon Ross 	case FSCTL_PIPE_TRANSCEIVE:
472*a90cf9f2SGordon Ross 		status = smb_opipe_transceive(sr, fsctl);
473*a90cf9f2SGordon Ross 		break;
474*a90cf9f2SGordon Ross 
475*a90cf9f2SGordon Ross 	case FSCTL_PIPE_PEEK:
476*a90cf9f2SGordon Ross 	case FSCTL_PIPE_WAIT:
477*a90cf9f2SGordon Ross 		/* XXX todo */
478*a90cf9f2SGordon Ross 		status = NT_STATUS_NOT_SUPPORTED;
479*a90cf9f2SGordon Ross 		break;
480*a90cf9f2SGordon Ross 
481*a90cf9f2SGordon Ross 	default:
482*a90cf9f2SGordon Ross 		ASSERT(!"CtlCode");
483*a90cf9f2SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
484*a90cf9f2SGordon Ross 		break;
485*a90cf9f2SGordon Ross 	}
486*a90cf9f2SGordon Ross 
487*a90cf9f2SGordon Ross 	return (status);
488*a90cf9f2SGordon Ross }
489*a90cf9f2SGordon Ross 
490*a90cf9f2SGordon Ross static uint32_t
491*a90cf9f2SGordon Ross smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl)
492*a90cf9f2SGordon Ross {
493*a90cf9f2SGordon Ross 	smb_vdb_t	vdb;
494*a90cf9f2SGordon Ross 	smb_ofile_t	*ofile;
495*a90cf9f2SGordon Ross 	struct mbuf	*mb;
496*a90cf9f2SGordon Ross 	uint32_t	status;
497*a90cf9f2SGordon Ross 	int		len, rc;
498*a90cf9f2SGordon Ross 
499*a90cf9f2SGordon Ross 	/*
500*a90cf9f2SGordon Ross 	 * Caller checked that this is the IPC$ share,
501*a90cf9f2SGordon Ross 	 * and that this call has a valid open handle.
502*a90cf9f2SGordon Ross 	 * Just check the type.
503*a90cf9f2SGordon Ross 	 */
504*a90cf9f2SGordon Ross 	ofile = sr->fid_ofile;
505*a90cf9f2SGordon Ross 	if (ofile->f_ftype != SMB_FTYPE_MESG_PIPE)
506*a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_HANDLE);
507*a90cf9f2SGordon Ross 
508*a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(fsctl->in_mbc, "#B",
509*a90cf9f2SGordon Ross 	    fsctl->InputCount, &vdb);
510*a90cf9f2SGordon Ross 	if (rc != 0) {
511*a90cf9f2SGordon Ross 		/* Not enough data sent. */
512*a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
513*a90cf9f2SGordon Ross 	}
514*a90cf9f2SGordon Ross 
515*a90cf9f2SGordon Ross 	rc = smb_opipe_write(sr, &vdb.vdb_uio);
516*a90cf9f2SGordon Ross 	if (rc != 0)
517*a90cf9f2SGordon Ross 		return (smb_errno2status(rc));
518*a90cf9f2SGordon Ross 
519*a90cf9f2SGordon Ross 	vdb.vdb_tag = 0;
520*a90cf9f2SGordon Ross 	vdb.vdb_uio.uio_iov = &vdb.vdb_iovec[0];
521*a90cf9f2SGordon Ross 	vdb.vdb_uio.uio_iovcnt = MAX_IOVEC;
522*a90cf9f2SGordon Ross 	vdb.vdb_uio.uio_segflg = UIO_SYSSPACE;
523*a90cf9f2SGordon Ross 	vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
524*a90cf9f2SGordon Ross 	vdb.vdb_uio.uio_loffset = (offset_t)0;
525*a90cf9f2SGordon Ross 	vdb.vdb_uio.uio_resid = fsctl->MaxOutputResp;
526*a90cf9f2SGordon Ross 	mb = smb_mbuf_allocate(&vdb.vdb_uio);
527*a90cf9f2SGordon Ross 
528*a90cf9f2SGordon Ross 	rc = smb_opipe_read(sr, &vdb.vdb_uio);
529*a90cf9f2SGordon Ross 	if (rc != 0) {
530*a90cf9f2SGordon Ross 		m_freem(mb);
531*a90cf9f2SGordon Ross 		return (smb_errno2status(rc));
532*a90cf9f2SGordon Ross 	}
533*a90cf9f2SGordon Ross 
534*a90cf9f2SGordon Ross 	len = fsctl->MaxOutputResp - vdb.vdb_uio.uio_resid;
535*a90cf9f2SGordon Ross 	smb_mbuf_trim(mb, len);
536*a90cf9f2SGordon Ross 	MBC_ATTACH_MBUF(fsctl->out_mbc, mb);
537*a90cf9f2SGordon Ross 
538*a90cf9f2SGordon Ross 	/*
539*a90cf9f2SGordon Ross 	 * If the output buffer holds a partial pipe message,
540*a90cf9f2SGordon Ross 	 * we're supposed to return NT_STATUS_BUFFER_OVERFLOW.
541*a90cf9f2SGordon Ross 	 * As we don't have message boundary markers, the best
542*a90cf9f2SGordon Ross 	 * we can do is return that status when we have ALL of:
543*a90cf9f2SGordon Ross 	 *	Output buffer was < SMB_PIPE_MAX_MSGSIZE
544*a90cf9f2SGordon Ross 	 *	We filled the output buffer (resid==0)
545*a90cf9f2SGordon Ross 	 *	There's more data (ioctl FIONREAD)
546*a90cf9f2SGordon Ross 	 */
547*a90cf9f2SGordon Ross 	status = NT_STATUS_SUCCESS;
548*a90cf9f2SGordon Ross 	if (fsctl->MaxOutputResp < SMB_PIPE_MAX_MSGSIZE &&
549*a90cf9f2SGordon Ross 	    vdb.vdb_uio.uio_resid == 0) {
550*a90cf9f2SGordon Ross 		int nread = 0, trval;
551*a90cf9f2SGordon Ross 		rc = smb_opipe_ioctl(sr, FIONREAD, &nread, &trval);
552*a90cf9f2SGordon Ross 		if (rc == 0 && nread != 0)
553*a90cf9f2SGordon Ross 			status = NT_STATUS_BUFFER_OVERFLOW;
554*a90cf9f2SGordon Ross 	}
555*a90cf9f2SGordon Ross 
556*a90cf9f2SGordon Ross 	return (status);
557*a90cf9f2SGordon Ross }
558