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. 23adee6784SGordon Ross * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 24*268cac54SGordon Ross * Copyright 2022 RackTop Systems, Inc. 253db3f65cSamw */ 263db3f65cSamw 273db3f65cSamw /* 283db3f65cSamw * This module provides the interface to NDR RPC. 293db3f65cSamw */ 303db3f65cSamw 313db3f65cSamw #include <sys/stat.h> 323db3f65cSamw #include <sys/uio.h> 333db3f65cSamw #include <sys/ksynch.h> 3468b2bbf2SGordon Ross #include <sys/stropts.h> 3568b2bbf2SGordon Ross #include <sys/socket.h> 3668b2bbf2SGordon Ross #include <sys/filio.h> 37bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 383db3f65cSamw #include <smbsrv/smb_xdr.h> 39adee6784SGordon Ross #include <smb/winioctl.h> 40a90cf9f2SGordon Ross 41*268cac54SGordon Ross static uint32_t smb_opipe_wait(smb_request_t *, smb_fsctl_t *); 42*268cac54SGordon Ross 4368b2bbf2SGordon Ross /* 4468b2bbf2SGordon Ross * Allocate a new opipe and return it, or NULL, in which case 4568b2bbf2SGordon Ross * the caller will report "internal error". 4668b2bbf2SGordon Ross */ 4768b2bbf2SGordon Ross static smb_opipe_t * 4868b2bbf2SGordon Ross smb_opipe_alloc(smb_request_t *sr) 499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 5068b2bbf2SGordon Ross smb_server_t *sv = sr->sr_server; 519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_t *opipe; 5268b2bbf2SGordon Ross ksocket_t sock; 5368b2bbf2SGordon Ross 5468b2bbf2SGordon Ross if (ksocket_socket(&sock, AF_UNIX, SOCK_STREAM, 0, 5568b2bbf2SGordon Ross KSOCKET_SLEEP, sr->user_cr) != 0) 5668b2bbf2SGordon Ross return (NULL); 579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 588622ec45SGordon Ross opipe = kmem_cache_alloc(smb_cache_opipe, KM_SLEEP); 599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States bzero(opipe, sizeof (smb_opipe_t)); 619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL); 629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL); 639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States opipe->p_magic = SMB_OPIPE_MAGIC; 649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States opipe->p_server = sv; 6568b2bbf2SGordon Ross opipe->p_refcnt = 1; 6668b2bbf2SGordon Ross opipe->p_socket = sock; 679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (opipe); 699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 7168b2bbf2SGordon Ross /* 7268b2bbf2SGordon Ross * Destroy an opipe. This is normally called from smb_ofile_delete 7368b2bbf2SGordon Ross * when the ofile has no more references and is about to be free'd. 7468b2bbf2SGordon Ross * This is also called here in error handling code paths, before 7568b2bbf2SGordon Ross * the opipe is installed under an ofile. 7668b2bbf2SGordon Ross */ 779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(smb_opipe_t *opipe) 799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_server_t *sv; 819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OPIPE_VALID(opipe); 839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States sv = opipe->p_server; 849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_SERVER_VALID(sv); 859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 8668b2bbf2SGordon Ross /* 8768b2bbf2SGordon Ross * This is called in the error path when opening, 8868b2bbf2SGordon Ross * in which case we close the socket here. 8968b2bbf2SGordon Ross */ 9068b2bbf2SGordon Ross if (opipe->p_socket != NULL) 9168b2bbf2SGordon Ross (void) ksocket_close(opipe->p_socket, zone_kcred()); 929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC; 949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States cv_destroy(&opipe->p_cv); 959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_destroy(&opipe->p_mutex); 969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 978622ec45SGordon Ross kmem_cache_free(smb_cache_opipe, opipe); 989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1003db3f65cSamw /* 101b210fedeSGordon Ross * Unblock a request that might be blocked reading some 102b210fedeSGordon Ross * pipe (AF_UNIX socket). We don't have an easy way to 103b210fedeSGordon Ross * interrupt just the thread servicing this request, so 104b210fedeSGordon Ross * we shutdown(3socket) the socket, waking all readers. 105b210fedeSGordon Ross * That's a bit heavy-handed, making the socket unusable 106b210fedeSGordon Ross * after this, so we do this only when disconnecting a 107b210fedeSGordon Ross * session (i.e. stopping the SMB service), and not when 108b210fedeSGordon Ross * handling an SMB2_cancel or SMB_nt_cancel request. 109b210fedeSGordon Ross */ 110b210fedeSGordon Ross static void 111b210fedeSGordon Ross smb_opipe_cancel(smb_request_t *sr) 112b210fedeSGordon Ross { 113b210fedeSGordon Ross ksocket_t so; 114b210fedeSGordon Ross 115811599a4SMatt Barden switch (sr->session->s_state) { 116811599a4SMatt Barden case SMB_SESSION_STATE_DISCONNECTED: 117811599a4SMatt Barden case SMB_SESSION_STATE_TERMINATED: 118811599a4SMatt Barden if ((so = sr->cancel_arg2) != NULL) 119b210fedeSGordon Ross (void) ksocket_shutdown(so, SHUT_RDWR, sr->user_cr); 120811599a4SMatt Barden break; 121b210fedeSGordon Ross } 122b210fedeSGordon Ross } 123b210fedeSGordon Ross 124b210fedeSGordon Ross /* 12568b2bbf2SGordon Ross * Helper for open: build pipe name and connect. 12668b2bbf2SGordon Ross */ 12768b2bbf2SGordon Ross static int 12868b2bbf2SGordon Ross smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe) 12968b2bbf2SGordon Ross { 13068b2bbf2SGordon Ross struct sockaddr_un saddr; 13168b2bbf2SGordon Ross smb_arg_open_t *op = &sr->sr_open; 13268b2bbf2SGordon Ross const char *name; 13368b2bbf2SGordon Ross int rc; 13468b2bbf2SGordon Ross 13568b2bbf2SGordon Ross name = op->fqi.fq_path.pn_path; 13668b2bbf2SGordon Ross name += strspn(name, "\\"); 13768b2bbf2SGordon Ross if (smb_strcasecmp(name, "PIPE", 4) == 0) { 13868b2bbf2SGordon Ross name += 4; 13968b2bbf2SGordon Ross name += strspn(name, "\\"); 14068b2bbf2SGordon Ross } 14168b2bbf2SGordon Ross (void) strlcpy(opipe->p_name, name, SMB_OPIPE_MAXNAME); 14268b2bbf2SGordon Ross (void) smb_strlwr(opipe->p_name); 14368b2bbf2SGordon Ross 14468b2bbf2SGordon Ross bzero(&saddr, sizeof (saddr)); 14568b2bbf2SGordon Ross saddr.sun_family = AF_UNIX; 14668b2bbf2SGordon Ross (void) snprintf(saddr.sun_path, sizeof (saddr.sun_path), 14768b2bbf2SGordon Ross "%s/%s", SMB_PIPE_DIR, opipe->p_name); 14868b2bbf2SGordon Ross rc = ksocket_connect(opipe->p_socket, (struct sockaddr *)&saddr, 14968b2bbf2SGordon Ross sizeof (saddr), sr->user_cr); 15068b2bbf2SGordon Ross 15168b2bbf2SGordon Ross return (rc); 15268b2bbf2SGordon Ross } 15368b2bbf2SGordon Ross 154*268cac54SGordon Ross static int 155*268cac54SGordon Ross smb_opipe_exists(char *name) 156*268cac54SGordon Ross { 157*268cac54SGordon Ross struct sockaddr_un saddr; 158*268cac54SGordon Ross vnode_t *vp; /* Underlying filesystem vnode */ 159*268cac54SGordon Ross int err; 160*268cac54SGordon Ross 161*268cac54SGordon Ross bzero(&saddr, sizeof (saddr)); 162*268cac54SGordon Ross saddr.sun_family = AF_UNIX; 163*268cac54SGordon Ross (void) snprintf(saddr.sun_path, sizeof (saddr.sun_path), 164*268cac54SGordon Ross "%s/%s", SMB_PIPE_DIR, name); 165*268cac54SGordon Ross 166*268cac54SGordon Ross err = lookupname(saddr.sun_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 167*268cac54SGordon Ross if (err == 0) { 168*268cac54SGordon Ross VN_RELE(vp); /* release hold from lookup */ 169*268cac54SGordon Ross } 170*268cac54SGordon Ross 171*268cac54SGordon Ross return (err); 172*268cac54SGordon Ross } 173*268cac54SGordon Ross 174*268cac54SGordon Ross 17568b2bbf2SGordon Ross /* 17668b2bbf2SGordon Ross * Helper for open: encode and send the user info. 17768b2bbf2SGordon Ross * 17868b2bbf2SGordon Ross * We send information about this client + user to the 17968b2bbf2SGordon Ross * pipe service so it can use it for access checks. 18068b2bbf2SGordon Ross * The service MAY deny the open based on this info, 18168b2bbf2SGordon Ross * (i.e. anonymous session trying to open a pipe that 18268b2bbf2SGordon Ross * requires authentication) in which case we will read 18368b2bbf2SGordon Ross * an error status from the service and return that. 18468b2bbf2SGordon Ross */ 18568b2bbf2SGordon Ross static void 18668b2bbf2SGordon Ross smb_opipe_send_userinfo(smb_request_t *sr, smb_opipe_t *opipe, 18768b2bbf2SGordon Ross smb_error_t *errp) 18868b2bbf2SGordon Ross { 18968b2bbf2SGordon Ross XDR xdrs; 19068b2bbf2SGordon Ross smb_netuserinfo_t nui; 19168b2bbf2SGordon Ross smb_pipehdr_t phdr; 19268b2bbf2SGordon Ross char *buf; 19368b2bbf2SGordon Ross uint32_t buflen; 19468b2bbf2SGordon Ross uint32_t status; 19568b2bbf2SGordon Ross size_t iocnt = 0; 19668b2bbf2SGordon Ross int rc; 19768b2bbf2SGordon Ross 19868b2bbf2SGordon Ross /* 19968b2bbf2SGordon Ross * Any errors building the XDR message etc. 20068b2bbf2SGordon Ross */ 20168b2bbf2SGordon Ross errp->status = NT_STATUS_INTERNAL_ERROR; 20268b2bbf2SGordon Ross 20368b2bbf2SGordon Ross smb_user_netinfo_init(sr->uid_user, &nui); 20468b2bbf2SGordon Ross phdr.ph_magic = SMB_PIPE_HDR_MAGIC; 20568b2bbf2SGordon Ross phdr.ph_uilen = xdr_sizeof(smb_netuserinfo_xdr, &nui); 20668b2bbf2SGordon Ross 20768b2bbf2SGordon Ross buflen = sizeof (phdr) + phdr.ph_uilen; 20868b2bbf2SGordon Ross buf = kmem_alloc(buflen, KM_SLEEP); 20968b2bbf2SGordon Ross 21068b2bbf2SGordon Ross bcopy(&phdr, buf, sizeof (phdr)); 21168b2bbf2SGordon Ross xdrmem_create(&xdrs, buf + sizeof (phdr), 21268b2bbf2SGordon Ross buflen - (sizeof (phdr)), XDR_ENCODE); 21368b2bbf2SGordon Ross if (!smb_netuserinfo_xdr(&xdrs, &nui)) 21468b2bbf2SGordon Ross goto out; 21568b2bbf2SGordon Ross 216b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 217b210fedeSGordon Ross if (sr->sr_state != SMB_REQ_STATE_ACTIVE) { 218b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 219b210fedeSGordon Ross errp->status = NT_STATUS_CANCELLED; 220b210fedeSGordon Ross goto out; 221b210fedeSGordon Ross } 222b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_WAITING_PIPE; 223b210fedeSGordon Ross sr->cancel_method = smb_opipe_cancel; 224b210fedeSGordon Ross sr->cancel_arg2 = opipe->p_socket; 225b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 22668b2bbf2SGordon Ross 22768b2bbf2SGordon Ross rc = ksocket_send(opipe->p_socket, buf, buflen, 0, 22868b2bbf2SGordon Ross &iocnt, sr->user_cr); 22968b2bbf2SGordon Ross if (rc == 0 && iocnt != buflen) 23068b2bbf2SGordon Ross rc = EIO; 231b210fedeSGordon Ross if (rc == 0) 232b210fedeSGordon Ross rc = ksocket_recv(opipe->p_socket, &status, sizeof (status), 233b210fedeSGordon Ross 0, &iocnt, sr->user_cr); 234b210fedeSGordon Ross if (rc == 0 && iocnt != sizeof (status)) 235b210fedeSGordon Ross rc = EIO; 23668b2bbf2SGordon Ross 237b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 238b210fedeSGordon Ross sr->cancel_method = NULL; 239b210fedeSGordon Ross sr->cancel_arg2 = NULL; 240b210fedeSGordon Ross switch (sr->sr_state) { 241b210fedeSGordon Ross case SMB_REQ_STATE_WAITING_PIPE: 242b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 243b210fedeSGordon Ross break; 244b210fedeSGordon Ross case SMB_REQ_STATE_CANCEL_PENDING: 245b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_CANCELLED; 246b210fedeSGordon Ross rc = EINTR; 247b210fedeSGordon Ross break; 248b210fedeSGordon Ross default: 249b210fedeSGordon Ross /* keep rc from above */ 250b210fedeSGordon Ross break; 251b210fedeSGordon Ross } 252b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 253b210fedeSGordon Ross 25468b2bbf2SGordon Ross 25568b2bbf2SGordon Ross /* 25668b2bbf2SGordon Ross * Return the status we read from the pipe service, 25768b2bbf2SGordon Ross * normally NT_STATUS_SUCCESS, but could be something 25868b2bbf2SGordon Ross * else like NT_STATUS_ACCESS_DENIED. 25968b2bbf2SGordon Ross */ 260b210fedeSGordon Ross switch (rc) { 261b210fedeSGordon Ross case 0: 26268b2bbf2SGordon Ross errp->status = status; 263b210fedeSGordon Ross break; 264b210fedeSGordon Ross case EINTR: 265b210fedeSGordon Ross errp->status = NT_STATUS_CANCELLED; 266b210fedeSGordon Ross break; 267b210fedeSGordon Ross /* 268b210fedeSGordon Ross * If we fail sending the netuserinfo or recv'ing the 269b210fedeSGordon Ross * status reponse, we have probably run into the limit 270b210fedeSGordon Ross * on the number of open pipes. That's this status: 271b210fedeSGordon Ross */ 272b210fedeSGordon Ross default: 273b210fedeSGordon Ross errp->status = NT_STATUS_PIPE_NOT_AVAILABLE; 274b210fedeSGordon Ross break; 275b210fedeSGordon Ross } 27668b2bbf2SGordon Ross 27768b2bbf2SGordon Ross out: 27868b2bbf2SGordon Ross xdr_destroy(&xdrs); 27968b2bbf2SGordon Ross kmem_free(buf, buflen); 28068b2bbf2SGordon Ross smb_user_netinfo_fini(&nui); 28168b2bbf2SGordon Ross } 28268b2bbf2SGordon Ross 28368b2bbf2SGordon Ross /* 2843db3f65cSamw * smb_opipe_open 2853db3f65cSamw * 28668b2bbf2SGordon Ross * Open an RPC named pipe. This routine should be called if 2873db3f65cSamw * a file open is requested on a share of type STYPE_IPC. 2883db3f65cSamw * If we recognize the pipe, we setup a new ofile. 2893db3f65cSamw * 29068b2bbf2SGordon Ross * Returns 0 on success, Otherwise an NT status code. 2913db3f65cSamw */ 2923db3f65cSamw int 29394047d49SGordon Ross smb_opipe_open(smb_request_t *sr, smb_ofile_t *ofile) 2943db3f65cSamw { 295148c5f43SAlan Wright smb_arg_open_t *op = &sr->sr_open; 296c5f48fa5SGordon Ross smb_attr_t *ap = &op->fqi.fq_fattr; 2973db3f65cSamw smb_opipe_t *opipe; 2983db3f65cSamw smb_error_t err; 2993db3f65cSamw 30068b2bbf2SGordon Ross opipe = smb_opipe_alloc(sr); 30168b2bbf2SGordon Ross if (opipe == NULL) 30268b2bbf2SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 3033db3f65cSamw 30468b2bbf2SGordon Ross if (smb_opipe_connect(sr, opipe) != 0) { 30568b2bbf2SGordon Ross smb_opipe_dealloc(opipe); 3068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 3078b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 3088b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 30968b2bbf2SGordon Ross smb_opipe_send_userinfo(sr, opipe, &err); 31068b2bbf2SGordon Ross if (err.status != 0) { 31168b2bbf2SGordon Ross smb_opipe_dealloc(opipe); 31268b2bbf2SGordon Ross return (err.status); 31368b2bbf2SGordon Ross } 31468b2bbf2SGordon Ross 31568b2bbf2SGordon Ross /* 31694047d49SGordon Ross * We might have blocked in smb_opipe_connect long enough so 31794047d49SGordon Ross * a tree disconnect might have happened. In that case, we 31894047d49SGordon Ross * would be adding an ofile to a tree that's disconnecting, 31994047d49SGordon Ross * which would interfere with tear-down. 32068b2bbf2SGordon Ross */ 32194047d49SGordon Ross if (!smb_tree_is_connected(sr->tid_tree)) { 32268b2bbf2SGordon Ross smb_opipe_dealloc(opipe); 32394047d49SGordon Ross return (NT_STATUS_NETWORK_NAME_DELETED); 32468b2bbf2SGordon Ross } 32568b2bbf2SGordon Ross 32694047d49SGordon Ross /* 32794047d49SGordon Ross * Note: The new opipe is given to smb_ofile_open 32894047d49SGordon Ross * via op->pipe 32994047d49SGordon Ross */ 33094047d49SGordon Ross op->pipe = opipe; 33194047d49SGordon Ross smb_ofile_open(sr, op, ofile); 33294047d49SGordon Ross op->pipe = NULL; 33394047d49SGordon Ross 33468b2bbf2SGordon Ross /* An "up" pointer, for debug. */ 33568b2bbf2SGordon Ross opipe->p_ofile = ofile; 33668b2bbf2SGordon Ross 337c5f48fa5SGordon Ross /* 338c5f48fa5SGordon Ross * Caller expects attributes in op->fqi 339c5f48fa5SGordon Ross */ 340c5f48fa5SGordon Ross (void) smb_opipe_getattr(ofile, &op->fqi.fq_fattr); 341c5f48fa5SGordon Ross 342c5f48fa5SGordon Ross op->dsize = 0; 343c5f48fa5SGordon Ross op->dattr = ap->sa_dosattr; 344c5f48fa5SGordon Ross op->fileid = ap->sa_vattr.va_nodeid; 3453db3f65cSamw op->ftype = SMB_FTYPE_MESG_PIPE; 346c5f48fa5SGordon Ross op->action_taken = SMB_OACT_OPLOCK | SMB_OACT_OPENED; 3473db3f65cSamw op->devstate = SMB_PIPE_READMODE_MESSAGE 3483db3f65cSamw | SMB_PIPE_TYPE_MESSAGE 3493db3f65cSamw | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 3503db3f65cSamw 35168b2bbf2SGordon Ross sr->smb_fid = ofile->f_fid; 35268b2bbf2SGordon Ross sr->fid_ofile = ofile; 3533db3f65cSamw 3543db3f65cSamw return (NT_STATUS_SUCCESS); 3553db3f65cSamw } 3563db3f65cSamw 3573db3f65cSamw /* 3583db3f65cSamw * smb_opipe_close 3593db3f65cSamw * 36068b2bbf2SGordon Ross * Called by smb_ofile_close for pipes. 36168b2bbf2SGordon Ross * 36268b2bbf2SGordon Ross * Note: ksocket_close may block while waiting for 36368b2bbf2SGordon Ross * any I/O threads with a hold to get out. 3643db3f65cSamw */ 3653db3f65cSamw void 3663db3f65cSamw smb_opipe_close(smb_ofile_t *of) 3673db3f65cSamw { 3683db3f65cSamw smb_opipe_t *opipe; 36968b2bbf2SGordon Ross ksocket_t sock; 3703db3f65cSamw 37168b2bbf2SGordon Ross ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); 3723db3f65cSamw ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 3733db3f65cSamw opipe = of->f_pipe; 3749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OPIPE_VALID(opipe); 3759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 37668b2bbf2SGordon Ross mutex_enter(&opipe->p_mutex); 37768b2bbf2SGordon Ross sock = opipe->p_socket; 37868b2bbf2SGordon Ross opipe->p_socket = NULL; 37968b2bbf2SGordon Ross mutex_exit(&opipe->p_mutex); 3803db3f65cSamw 38168b2bbf2SGordon Ross (void) ksocket_shutdown(sock, SHUT_RDWR, of->f_cr); 38268b2bbf2SGordon Ross (void) ksocket_close(sock, of->f_cr); 3833db3f65cSamw } 3843db3f65cSamw 3853db3f65cSamw /* 3863db3f65cSamw * smb_opipe_write 3873db3f65cSamw * 3883db3f65cSamw * Write RPC request data to the pipe. The client should call smb_opipe_read 3893db3f65cSamw * to complete the exchange and obtain the RPC response. 3903db3f65cSamw * 3913db3f65cSamw * Returns 0 on success or an errno on failure. 3923db3f65cSamw */ 3933db3f65cSamw int 3943db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio) 3953db3f65cSamw { 39668b2bbf2SGordon Ross struct nmsghdr msghdr; 39768b2bbf2SGordon Ross smb_ofile_t *ofile; 3983db3f65cSamw smb_opipe_t *opipe; 39968b2bbf2SGordon Ross ksocket_t sock; 40068b2bbf2SGordon Ross size_t sent = 0; 40168b2bbf2SGordon Ross int rc = 0; 4023db3f65cSamw 40368b2bbf2SGordon Ross ofile = sr->fid_ofile; 40468b2bbf2SGordon Ross ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 40568b2bbf2SGordon Ross opipe = ofile->f_pipe; 4069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OPIPE_VALID(opipe); 4073db3f65cSamw 40868b2bbf2SGordon Ross mutex_enter(&opipe->p_mutex); 40968b2bbf2SGordon Ross sock = opipe->p_socket; 41068b2bbf2SGordon Ross if (sock != NULL) 41168b2bbf2SGordon Ross ksocket_hold(sock); 41268b2bbf2SGordon Ross mutex_exit(&opipe->p_mutex); 41368b2bbf2SGordon Ross if (sock == NULL) 4143db3f65cSamw return (EBADF); 41568b2bbf2SGordon Ross 41668b2bbf2SGordon Ross bzero(&msghdr, sizeof (msghdr)); 41768b2bbf2SGordon Ross msghdr.msg_iov = uio->uio_iov; 41868b2bbf2SGordon Ross msghdr.msg_iovlen = uio->uio_iovcnt; 41968b2bbf2SGordon Ross 42068b2bbf2SGordon Ross /* 42168b2bbf2SGordon Ross * This should block until we've sent it all, 42268b2bbf2SGordon Ross * or given up due to errors (pipe closed). 42368b2bbf2SGordon Ross */ 42468b2bbf2SGordon Ross while (uio->uio_resid > 0) { 42568b2bbf2SGordon Ross rc = ksocket_sendmsg(sock, &msghdr, 0, &sent, ofile->f_cr); 42668b2bbf2SGordon Ross if (rc != 0) 42768b2bbf2SGordon Ross break; 42868b2bbf2SGordon Ross uio->uio_resid -= sent; 4293db3f65cSamw } 4303db3f65cSamw 43168b2bbf2SGordon Ross ksocket_rele(sock); 4323db3f65cSamw 43368b2bbf2SGordon Ross return (rc); 4343db3f65cSamw } 4353db3f65cSamw 4363db3f65cSamw /* 4373db3f65cSamw * smb_opipe_read 4383db3f65cSamw * 43968b2bbf2SGordon Ross * This interface may be called from smb_opipe_transact (write, read) 44068b2bbf2SGordon Ross * or from smb_read / smb2_read to get the rest of an RPC response. 44168b2bbf2SGordon Ross * The response data (and length) are returned via the uio. 4423db3f65cSamw */ 4433db3f65cSamw int 4443db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio) 4453db3f65cSamw { 44668b2bbf2SGordon Ross struct nmsghdr msghdr; 44768b2bbf2SGordon Ross smb_ofile_t *ofile; 4483db3f65cSamw smb_opipe_t *opipe; 44968b2bbf2SGordon Ross ksocket_t sock; 45068b2bbf2SGordon Ross size_t recvcnt = 0; 4513db3f65cSamw int rc; 4523db3f65cSamw 45368b2bbf2SGordon Ross ofile = sr->fid_ofile; 45468b2bbf2SGordon Ross ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 45568b2bbf2SGordon Ross opipe = ofile->f_pipe; 4569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OPIPE_VALID(opipe); 4579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 45868b2bbf2SGordon Ross mutex_enter(&opipe->p_mutex); 45968b2bbf2SGordon Ross sock = opipe->p_socket; 46068b2bbf2SGordon Ross if (sock != NULL) 46168b2bbf2SGordon Ross ksocket_hold(sock); 46268b2bbf2SGordon Ross mutex_exit(&opipe->p_mutex); 46368b2bbf2SGordon Ross if (sock == NULL) 4643db3f65cSamw return (EBADF); 4653db3f65cSamw 466b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 467b210fedeSGordon Ross if (sr->sr_state != SMB_REQ_STATE_ACTIVE) { 468b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 469b210fedeSGordon Ross rc = EINTR; 470b210fedeSGordon Ross goto out; 471b210fedeSGordon Ross } 472b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_WAITING_PIPE; 473b210fedeSGordon Ross sr->cancel_method = smb_opipe_cancel; 474b210fedeSGordon Ross sr->cancel_arg2 = sock; 475b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 4769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 4773db3f65cSamw /* 47868b2bbf2SGordon Ross * This should block only if there's no data. 47968b2bbf2SGordon Ross * A single call to recvmsg does just that. 48068b2bbf2SGordon Ross * (Intentionaly no recv loop here.) 4813db3f65cSamw */ 482b210fedeSGordon Ross bzero(&msghdr, sizeof (msghdr)); 483b210fedeSGordon Ross msghdr.msg_iov = uio->uio_iov; 484b210fedeSGordon Ross msghdr.msg_iovlen = uio->uio_iovcnt; 48568b2bbf2SGordon Ross rc = ksocket_recvmsg(sock, &msghdr, 0, 48668b2bbf2SGordon Ross &recvcnt, ofile->f_cr); 487b210fedeSGordon Ross 488b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 489b210fedeSGordon Ross sr->cancel_method = NULL; 490b210fedeSGordon Ross sr->cancel_arg2 = NULL; 491b210fedeSGordon Ross switch (sr->sr_state) { 492b210fedeSGordon Ross case SMB_REQ_STATE_WAITING_PIPE: 493b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 494b210fedeSGordon Ross break; 495b210fedeSGordon Ross case SMB_REQ_STATE_CANCEL_PENDING: 496b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_CANCELLED; 497b210fedeSGordon Ross rc = EINTR; 498b210fedeSGordon Ross break; 499b210fedeSGordon Ross default: 500b210fedeSGordon Ross /* keep rc from above */ 501b210fedeSGordon Ross break; 502b210fedeSGordon Ross } 503b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 504b210fedeSGordon Ross 50568b2bbf2SGordon Ross if (rc != 0) 50668b2bbf2SGordon Ross goto out; 5073db3f65cSamw 50868b2bbf2SGordon Ross if (recvcnt == 0) { 50968b2bbf2SGordon Ross /* Other side closed. */ 51068b2bbf2SGordon Ross rc = EPIPE; 51168b2bbf2SGordon Ross goto out; 5123db3f65cSamw } 51368b2bbf2SGordon Ross uio->uio_resid -= recvcnt; 5143db3f65cSamw 515bce01b59SGordon Ross out: 516bce01b59SGordon Ross ksocket_rele(sock); 517bce01b59SGordon Ross 518bce01b59SGordon Ross return (rc); 51968b2bbf2SGordon Ross } 52068b2bbf2SGordon Ross 521bce01b59SGordon Ross int 522a90cf9f2SGordon Ross smb_opipe_ioctl(smb_request_t *sr, int cmd, void *arg, int *rvalp) 523bce01b59SGordon Ross { 524bce01b59SGordon Ross smb_ofile_t *ofile; 525bce01b59SGordon Ross smb_opipe_t *opipe; 526bce01b59SGordon Ross ksocket_t sock; 527a90cf9f2SGordon Ross int rc; 528bce01b59SGordon Ross 529bce01b59SGordon Ross ofile = sr->fid_ofile; 530bce01b59SGordon Ross ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 531bce01b59SGordon Ross opipe = ofile->f_pipe; 532bce01b59SGordon Ross SMB_OPIPE_VALID(opipe); 533bce01b59SGordon Ross 534bce01b59SGordon Ross mutex_enter(&opipe->p_mutex); 535bce01b59SGordon Ross sock = opipe->p_socket; 536bce01b59SGordon Ross if (sock != NULL) 537bce01b59SGordon Ross ksocket_hold(sock); 538bce01b59SGordon Ross mutex_exit(&opipe->p_mutex); 539bce01b59SGordon Ross if (sock == NULL) 540bce01b59SGordon Ross return (EBADF); 541bce01b59SGordon Ross 542a90cf9f2SGordon Ross rc = ksocket_ioctl(sock, cmd, (intptr_t)arg, rvalp, ofile->f_cr); 543bce01b59SGordon Ross 54468b2bbf2SGordon Ross ksocket_rele(sock); 54568b2bbf2SGordon Ross 54668b2bbf2SGordon Ross return (rc); 5473db3f65cSamw } 548a90cf9f2SGordon Ross 549a90cf9f2SGordon Ross /* 550a90cf9f2SGordon Ross * Get the smb_attr_t for a named pipe. 551a90cf9f2SGordon Ross * Caller has already cleared to zero. 552a90cf9f2SGordon Ross */ 553a90cf9f2SGordon Ross int 554a90cf9f2SGordon Ross smb_opipe_getattr(smb_ofile_t *of, smb_attr_t *ap) 555a90cf9f2SGordon Ross { 556a90cf9f2SGordon Ross 557a90cf9f2SGordon Ross if (of->f_pipe == NULL) 558a90cf9f2SGordon Ross return (EINVAL); 559a90cf9f2SGordon Ross 560a90cf9f2SGordon Ross ap->sa_vattr.va_type = VFIFO; 561a90cf9f2SGordon Ross ap->sa_vattr.va_nlink = 1; 562c5f48fa5SGordon Ross ap->sa_vattr.va_nodeid = (uintptr_t)of->f_pipe; 563a90cf9f2SGordon Ross ap->sa_dosattr = FILE_ATTRIBUTE_NORMAL; 564c5f48fa5SGordon Ross ap->sa_allocsz = SMB_PIPE_MAX_MSGSIZE; 565a90cf9f2SGordon Ross 566a90cf9f2SGordon Ross return (0); 567a90cf9f2SGordon Ross } 568a90cf9f2SGordon Ross 569a90cf9f2SGordon Ross int 570a90cf9f2SGordon Ross smb_opipe_getname(smb_ofile_t *of, char *buf, size_t buflen) 571a90cf9f2SGordon Ross { 572a90cf9f2SGordon Ross smb_opipe_t *opipe; 573a90cf9f2SGordon Ross 574a90cf9f2SGordon Ross if ((opipe = of->f_pipe) == NULL) 575a90cf9f2SGordon Ross return (EINVAL); 576a90cf9f2SGordon Ross 577a90cf9f2SGordon Ross (void) snprintf(buf, buflen, "\\%s", opipe->p_name); 578a90cf9f2SGordon Ross return (0); 579a90cf9f2SGordon Ross } 580a90cf9f2SGordon Ross 581a90cf9f2SGordon Ross /* 58255f0a249SGordon Ross * Handle device type FILE_DEVICE_NAMED_PIPE 58355f0a249SGordon Ross * for smb2_ioctl 584a90cf9f2SGordon Ross */ 585a90cf9f2SGordon Ross /* ARGSUSED */ 586a90cf9f2SGordon Ross uint32_t 587a90cf9f2SGordon Ross smb_opipe_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl) 588a90cf9f2SGordon Ross { 589a90cf9f2SGordon Ross uint32_t status; 590a90cf9f2SGordon Ross 59155f0a249SGordon Ross if (!STYPE_ISIPC(sr->tid_tree->t_res_type)) 59255f0a249SGordon Ross return (NT_STATUS_INVALID_DEVICE_REQUEST); 59355f0a249SGordon Ross 594a90cf9f2SGordon Ross switch (fsctl->CtlCode) { 595a90cf9f2SGordon Ross case FSCTL_PIPE_TRANSCEIVE: 596a90cf9f2SGordon Ross status = smb_opipe_transceive(sr, fsctl); 597a90cf9f2SGordon Ross break; 598a90cf9f2SGordon Ross 599a90cf9f2SGordon Ross case FSCTL_PIPE_PEEK: 600*268cac54SGordon Ross status = NT_STATUS_INVALID_DEVICE_REQUEST; 601*268cac54SGordon Ross break; 602*268cac54SGordon Ross 603a90cf9f2SGordon Ross case FSCTL_PIPE_WAIT: 604*268cac54SGordon Ross status = smb_opipe_wait(sr, fsctl); 605a90cf9f2SGordon Ross break; 606a90cf9f2SGordon Ross 607a90cf9f2SGordon Ross default: 608a90cf9f2SGordon Ross ASSERT(!"CtlCode"); 609a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 610a90cf9f2SGordon Ross break; 611a90cf9f2SGordon Ross } 612a90cf9f2SGordon Ross 613a90cf9f2SGordon Ross return (status); 614a90cf9f2SGordon Ross } 615a90cf9f2SGordon Ross 61655f0a249SGordon Ross uint32_t 617a90cf9f2SGordon Ross smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl) 618a90cf9f2SGordon Ross { 619a90cf9f2SGordon Ross smb_vdb_t vdb; 620a90cf9f2SGordon Ross smb_ofile_t *ofile; 621a90cf9f2SGordon Ross struct mbuf *mb; 622a90cf9f2SGordon Ross uint32_t status; 623a90cf9f2SGordon Ross int len, rc; 624a90cf9f2SGordon Ross 625a90cf9f2SGordon Ross /* 626a90cf9f2SGordon Ross * Caller checked that this is the IPC$ share, 627a90cf9f2SGordon Ross * and that this call has a valid open handle. 628a90cf9f2SGordon Ross * Just check the type. 629a90cf9f2SGordon Ross */ 630a90cf9f2SGordon Ross ofile = sr->fid_ofile; 631a90cf9f2SGordon Ross if (ofile->f_ftype != SMB_FTYPE_MESG_PIPE) 632a90cf9f2SGordon Ross return (NT_STATUS_INVALID_HANDLE); 633a90cf9f2SGordon Ross 634a90cf9f2SGordon Ross rc = smb_mbc_decodef(fsctl->in_mbc, "#B", 635a90cf9f2SGordon Ross fsctl->InputCount, &vdb); 636a90cf9f2SGordon Ross if (rc != 0) { 637a90cf9f2SGordon Ross /* Not enough data sent. */ 638a90cf9f2SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 639a90cf9f2SGordon Ross } 640a90cf9f2SGordon Ross 641a90cf9f2SGordon Ross rc = smb_opipe_write(sr, &vdb.vdb_uio); 642a90cf9f2SGordon Ross if (rc != 0) 643a90cf9f2SGordon Ross return (smb_errno2status(rc)); 644a90cf9f2SGordon Ross 645a90cf9f2SGordon Ross vdb.vdb_tag = 0; 646a90cf9f2SGordon Ross vdb.vdb_uio.uio_iov = &vdb.vdb_iovec[0]; 647a90cf9f2SGordon Ross vdb.vdb_uio.uio_iovcnt = MAX_IOVEC; 648a90cf9f2SGordon Ross vdb.vdb_uio.uio_segflg = UIO_SYSSPACE; 649a90cf9f2SGordon Ross vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 650a90cf9f2SGordon Ross vdb.vdb_uio.uio_loffset = (offset_t)0; 651a90cf9f2SGordon Ross vdb.vdb_uio.uio_resid = fsctl->MaxOutputResp; 652a90cf9f2SGordon Ross mb = smb_mbuf_allocate(&vdb.vdb_uio); 653a90cf9f2SGordon Ross 654a90cf9f2SGordon Ross rc = smb_opipe_read(sr, &vdb.vdb_uio); 655a90cf9f2SGordon Ross if (rc != 0) { 656a90cf9f2SGordon Ross m_freem(mb); 657a90cf9f2SGordon Ross return (smb_errno2status(rc)); 658a90cf9f2SGordon Ross } 659a90cf9f2SGordon Ross 660a90cf9f2SGordon Ross len = fsctl->MaxOutputResp - vdb.vdb_uio.uio_resid; 661a90cf9f2SGordon Ross smb_mbuf_trim(mb, len); 662a90cf9f2SGordon Ross MBC_ATTACH_MBUF(fsctl->out_mbc, mb); 663a90cf9f2SGordon Ross 664a90cf9f2SGordon Ross /* 665a90cf9f2SGordon Ross * If the output buffer holds a partial pipe message, 666a90cf9f2SGordon Ross * we're supposed to return NT_STATUS_BUFFER_OVERFLOW. 667a90cf9f2SGordon Ross * As we don't have message boundary markers, the best 668a90cf9f2SGordon Ross * we can do is return that status when we have ALL of: 669a90cf9f2SGordon Ross * Output buffer was < SMB_PIPE_MAX_MSGSIZE 670a90cf9f2SGordon Ross * We filled the output buffer (resid==0) 671a90cf9f2SGordon Ross * There's more data (ioctl FIONREAD) 672a90cf9f2SGordon Ross */ 673a90cf9f2SGordon Ross status = NT_STATUS_SUCCESS; 674a90cf9f2SGordon Ross if (fsctl->MaxOutputResp < SMB_PIPE_MAX_MSGSIZE && 675a90cf9f2SGordon Ross vdb.vdb_uio.uio_resid == 0) { 676a90cf9f2SGordon Ross int nread = 0, trval; 677a90cf9f2SGordon Ross rc = smb_opipe_ioctl(sr, FIONREAD, &nread, &trval); 678a90cf9f2SGordon Ross if (rc == 0 && nread != 0) 679a90cf9f2SGordon Ross status = NT_STATUS_BUFFER_OVERFLOW; 680a90cf9f2SGordon Ross } 681a90cf9f2SGordon Ross 682a90cf9f2SGordon Ross return (status); 683a90cf9f2SGordon Ross } 684*268cac54SGordon Ross 685*268cac54SGordon Ross static uint32_t 686*268cac54SGordon Ross smb_opipe_wait(smb_request_t *sr, smb_fsctl_t *fsctl) 687*268cac54SGordon Ross { 688*268cac54SGordon Ross char *name; 689*268cac54SGordon Ross uint64_t timeout; 690*268cac54SGordon Ross uint32_t namelen; 691*268cac54SGordon Ross int rc; 692*268cac54SGordon Ross uint8_t tflag; 693*268cac54SGordon Ross 694*268cac54SGordon Ross rc = smb_mbc_decodef(fsctl->in_mbc, "qlb.", 695*268cac54SGordon Ross &timeout, /* q */ 696*268cac54SGordon Ross &namelen, /* l */ 697*268cac54SGordon Ross &tflag); /* b */ 698*268cac54SGordon Ross if (rc != 0) 699*268cac54SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 700*268cac54SGordon Ross rc = smb_mbc_decodef(fsctl->in_mbc, "%#U", 701*268cac54SGordon Ross sr, /* % */ 702*268cac54SGordon Ross namelen, /* # */ 703*268cac54SGordon Ross &name); /* U */ 704*268cac54SGordon Ross if (rc != 0) 705*268cac54SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 706*268cac54SGordon Ross 707*268cac54SGordon Ross rc = smb_opipe_exists(name); 708*268cac54SGordon Ross if (rc != 0) 709*268cac54SGordon Ross return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 710*268cac54SGordon Ross 711*268cac54SGordon Ross /* 712*268cac54SGordon Ross * At this point we know the pipe exists. 713*268cac54SGordon Ross * 714*268cac54SGordon Ross * If the tflag is set, we're supposed to wait for up to 715*268cac54SGordon Ross * timeout (100s of milliseconds) for a pipe "instance" 716*268cac54SGordon Ross * to become "available" (so pipe open would work). 717*268cac54SGordon Ross * However, this implementation has no need to wait, 718*268cac54SGordon Ross * so just take a short delay instead. 719*268cac54SGordon Ross */ 720*268cac54SGordon Ross if (tflag != 0) { 721*268cac54SGordon Ross clock_t ticks = MSEC_TO_TICK(timeout * 100); 722*268cac54SGordon Ross if (ticks > MSEC_TO_TICK(100)) 723*268cac54SGordon Ross ticks = MSEC_TO_TICK(100); 724*268cac54SGordon Ross delay(ticks); 725*268cac54SGordon Ross } 726*268cac54SGordon Ross 727*268cac54SGordon Ross return (0); 728*268cac54SGordon Ross } 729