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. 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> 38adee6784SGordon Ross #include <smb/winioctl.h> 39a90cf9f2SGordon Ross 40a90cf9f2SGordon 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 /* 100*b210fedeSGordon Ross * Unblock a request that might be blocked reading some 101*b210fedeSGordon Ross * pipe (AF_UNIX socket). We don't have an easy way to 102*b210fedeSGordon Ross * interrupt just the thread servicing this request, so 103*b210fedeSGordon Ross * we shutdown(3socket) the socket, waking all readers. 104*b210fedeSGordon Ross * That's a bit heavy-handed, making the socket unusable 105*b210fedeSGordon Ross * after this, so we do this only when disconnecting a 106*b210fedeSGordon Ross * session (i.e. stopping the SMB service), and not when 107*b210fedeSGordon Ross * handling an SMB2_cancel or SMB_nt_cancel request. 108*b210fedeSGordon Ross */ 109*b210fedeSGordon Ross static void 110*b210fedeSGordon Ross smb_opipe_cancel(smb_request_t *sr) 111*b210fedeSGordon Ross { 112*b210fedeSGordon Ross ksocket_t so; 113*b210fedeSGordon Ross 114*b210fedeSGordon Ross if (sr->session->s_state == SMB_SESSION_STATE_DISCONNECTED && 115*b210fedeSGordon Ross (so = sr->cancel_arg2) != NULL) { 116*b210fedeSGordon Ross (void) ksocket_shutdown(so, SHUT_RDWR, sr->user_cr); 117*b210fedeSGordon Ross } 118*b210fedeSGordon Ross } 119*b210fedeSGordon Ross 120*b210fedeSGordon Ross /* 12168b2bbf2SGordon Ross * Helper for open: build pipe name and connect. 12268b2bbf2SGordon Ross */ 12368b2bbf2SGordon Ross static int 12468b2bbf2SGordon Ross smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe) 12568b2bbf2SGordon Ross { 12668b2bbf2SGordon Ross struct sockaddr_un saddr; 12768b2bbf2SGordon Ross smb_arg_open_t *op = &sr->sr_open; 12868b2bbf2SGordon Ross const char *name; 12968b2bbf2SGordon Ross int rc; 13068b2bbf2SGordon Ross 13168b2bbf2SGordon Ross name = op->fqi.fq_path.pn_path; 13268b2bbf2SGordon Ross name += strspn(name, "\\"); 13368b2bbf2SGordon Ross if (smb_strcasecmp(name, "PIPE", 4) == 0) { 13468b2bbf2SGordon Ross name += 4; 13568b2bbf2SGordon Ross name += strspn(name, "\\"); 13668b2bbf2SGordon Ross } 13768b2bbf2SGordon Ross (void) strlcpy(opipe->p_name, name, SMB_OPIPE_MAXNAME); 13868b2bbf2SGordon Ross (void) smb_strlwr(opipe->p_name); 13968b2bbf2SGordon Ross 14068b2bbf2SGordon Ross bzero(&saddr, sizeof (saddr)); 14168b2bbf2SGordon Ross saddr.sun_family = AF_UNIX; 14268b2bbf2SGordon Ross (void) snprintf(saddr.sun_path, sizeof (saddr.sun_path), 14368b2bbf2SGordon Ross "%s/%s", SMB_PIPE_DIR, opipe->p_name); 14468b2bbf2SGordon Ross rc = ksocket_connect(opipe->p_socket, (struct sockaddr *)&saddr, 14568b2bbf2SGordon Ross sizeof (saddr), sr->user_cr); 14668b2bbf2SGordon Ross 14768b2bbf2SGordon Ross return (rc); 14868b2bbf2SGordon Ross } 14968b2bbf2SGordon Ross 15068b2bbf2SGordon Ross /* 15168b2bbf2SGordon Ross * Helper for open: encode and send the user info. 15268b2bbf2SGordon Ross * 15368b2bbf2SGordon Ross * We send information about this client + user to the 15468b2bbf2SGordon Ross * pipe service so it can use it for access checks. 15568b2bbf2SGordon Ross * The service MAY deny the open based on this info, 15668b2bbf2SGordon Ross * (i.e. anonymous session trying to open a pipe that 15768b2bbf2SGordon Ross * requires authentication) in which case we will read 15868b2bbf2SGordon Ross * an error status from the service and return that. 15968b2bbf2SGordon Ross */ 16068b2bbf2SGordon Ross static void 16168b2bbf2SGordon Ross smb_opipe_send_userinfo(smb_request_t *sr, smb_opipe_t *opipe, 16268b2bbf2SGordon Ross smb_error_t *errp) 16368b2bbf2SGordon Ross { 16468b2bbf2SGordon Ross XDR xdrs; 16568b2bbf2SGordon Ross smb_netuserinfo_t nui; 16668b2bbf2SGordon Ross smb_pipehdr_t phdr; 16768b2bbf2SGordon Ross char *buf; 16868b2bbf2SGordon Ross uint32_t buflen; 16968b2bbf2SGordon Ross uint32_t status; 17068b2bbf2SGordon Ross size_t iocnt = 0; 17168b2bbf2SGordon Ross int rc; 17268b2bbf2SGordon Ross 17368b2bbf2SGordon Ross /* 17468b2bbf2SGordon Ross * Any errors building the XDR message etc. 17568b2bbf2SGordon Ross */ 17668b2bbf2SGordon Ross errp->status = NT_STATUS_INTERNAL_ERROR; 17768b2bbf2SGordon Ross 17868b2bbf2SGordon Ross smb_user_netinfo_init(sr->uid_user, &nui); 17968b2bbf2SGordon Ross phdr.ph_magic = SMB_PIPE_HDR_MAGIC; 18068b2bbf2SGordon Ross phdr.ph_uilen = xdr_sizeof(smb_netuserinfo_xdr, &nui); 18168b2bbf2SGordon Ross 18268b2bbf2SGordon Ross buflen = sizeof (phdr) + phdr.ph_uilen; 18368b2bbf2SGordon Ross buf = kmem_alloc(buflen, KM_SLEEP); 18468b2bbf2SGordon Ross 18568b2bbf2SGordon Ross bcopy(&phdr, buf, sizeof (phdr)); 18668b2bbf2SGordon Ross xdrmem_create(&xdrs, buf + sizeof (phdr), 18768b2bbf2SGordon Ross buflen - (sizeof (phdr)), XDR_ENCODE); 18868b2bbf2SGordon Ross if (!smb_netuserinfo_xdr(&xdrs, &nui)) 18968b2bbf2SGordon Ross goto out; 19068b2bbf2SGordon Ross 191*b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 192*b210fedeSGordon Ross if (sr->sr_state != SMB_REQ_STATE_ACTIVE) { 193*b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 194*b210fedeSGordon Ross errp->status = NT_STATUS_CANCELLED; 195*b210fedeSGordon Ross goto out; 196*b210fedeSGordon Ross } 197*b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_WAITING_PIPE; 198*b210fedeSGordon Ross sr->cancel_method = smb_opipe_cancel; 199*b210fedeSGordon Ross sr->cancel_arg2 = opipe->p_socket; 200*b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 20168b2bbf2SGordon Ross 20268b2bbf2SGordon Ross rc = ksocket_send(opipe->p_socket, buf, buflen, 0, 20368b2bbf2SGordon Ross &iocnt, sr->user_cr); 20468b2bbf2SGordon Ross if (rc == 0 && iocnt != buflen) 20568b2bbf2SGordon Ross rc = EIO; 206*b210fedeSGordon Ross if (rc == 0) 207*b210fedeSGordon Ross rc = ksocket_recv(opipe->p_socket, &status, sizeof (status), 208*b210fedeSGordon Ross 0, &iocnt, sr->user_cr); 209*b210fedeSGordon Ross if (rc == 0 && iocnt != sizeof (status)) 210*b210fedeSGordon Ross rc = EIO; 21168b2bbf2SGordon Ross 212*b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 213*b210fedeSGordon Ross sr->cancel_method = NULL; 214*b210fedeSGordon Ross sr->cancel_arg2 = NULL; 215*b210fedeSGordon Ross switch (sr->sr_state) { 216*b210fedeSGordon Ross case SMB_REQ_STATE_WAITING_PIPE: 217*b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 218*b210fedeSGordon Ross break; 219*b210fedeSGordon Ross case SMB_REQ_STATE_CANCEL_PENDING: 220*b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_CANCELLED; 221*b210fedeSGordon Ross rc = EINTR; 222*b210fedeSGordon Ross break; 223*b210fedeSGordon Ross default: 224*b210fedeSGordon Ross /* keep rc from above */ 225*b210fedeSGordon Ross break; 226*b210fedeSGordon Ross } 227*b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 228*b210fedeSGordon Ross 22968b2bbf2SGordon Ross 23068b2bbf2SGordon Ross /* 23168b2bbf2SGordon Ross * Return the status we read from the pipe service, 23268b2bbf2SGordon Ross * normally NT_STATUS_SUCCESS, but could be something 23368b2bbf2SGordon Ross * else like NT_STATUS_ACCESS_DENIED. 23468b2bbf2SGordon Ross */ 235*b210fedeSGordon Ross switch (rc) { 236*b210fedeSGordon Ross case 0: 23768b2bbf2SGordon Ross errp->status = status; 238*b210fedeSGordon Ross break; 239*b210fedeSGordon Ross case EINTR: 240*b210fedeSGordon Ross errp->status = NT_STATUS_CANCELLED; 241*b210fedeSGordon Ross break; 242*b210fedeSGordon Ross /* 243*b210fedeSGordon Ross * If we fail sending the netuserinfo or recv'ing the 244*b210fedeSGordon Ross * status reponse, we have probably run into the limit 245*b210fedeSGordon Ross * on the number of open pipes. That's this status: 246*b210fedeSGordon Ross */ 247*b210fedeSGordon Ross default: 248*b210fedeSGordon Ross errp->status = NT_STATUS_PIPE_NOT_AVAILABLE; 249*b210fedeSGordon Ross break; 250*b210fedeSGordon Ross } 25168b2bbf2SGordon Ross 25268b2bbf2SGordon Ross out: 25368b2bbf2SGordon Ross xdr_destroy(&xdrs); 25468b2bbf2SGordon Ross kmem_free(buf, buflen); 25568b2bbf2SGordon Ross smb_user_netinfo_fini(&nui); 25668b2bbf2SGordon Ross } 25768b2bbf2SGordon Ross 25868b2bbf2SGordon Ross /* 2593db3f65cSamw * smb_opipe_open 2603db3f65cSamw * 26168b2bbf2SGordon Ross * Open an RPC named pipe. This routine should be called if 2623db3f65cSamw * a file open is requested on a share of type STYPE_IPC. 2633db3f65cSamw * If we recognize the pipe, we setup a new ofile. 2643db3f65cSamw * 26568b2bbf2SGordon Ross * Returns 0 on success, Otherwise an NT status code. 2663db3f65cSamw */ 2673db3f65cSamw int 26868b2bbf2SGordon Ross smb_opipe_open(smb_request_t *sr, uint32_t uniqid) 2693db3f65cSamw { 270148c5f43SAlan Wright smb_arg_open_t *op = &sr->sr_open; 271c5f48fa5SGordon Ross smb_attr_t *ap = &op->fqi.fq_fattr; 27268b2bbf2SGordon Ross smb_ofile_t *ofile; 2733db3f65cSamw smb_opipe_t *opipe; 2743db3f65cSamw smb_error_t err; 2753db3f65cSamw 27668b2bbf2SGordon Ross opipe = smb_opipe_alloc(sr); 27768b2bbf2SGordon Ross if (opipe == NULL) 27868b2bbf2SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 2793db3f65cSamw 28068b2bbf2SGordon Ross if (smb_opipe_connect(sr, opipe) != 0) { 28168b2bbf2SGordon Ross smb_opipe_dealloc(opipe); 2828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 2838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 2848b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 28568b2bbf2SGordon Ross smb_opipe_send_userinfo(sr, opipe, &err); 28668b2bbf2SGordon Ross if (err.status != 0) { 28768b2bbf2SGordon Ross smb_opipe_dealloc(opipe); 28868b2bbf2SGordon Ross return (err.status); 28968b2bbf2SGordon Ross } 29068b2bbf2SGordon Ross 29168b2bbf2SGordon Ross /* 29268b2bbf2SGordon Ross * Note: If smb_ofile_open succeeds, the new ofile is 29368b2bbf2SGordon Ross * in the FID lists can can be used by I/O requests. 29468b2bbf2SGordon Ross */ 29568b2bbf2SGordon Ross op->create_options = 0; 29668b2bbf2SGordon Ross op->pipe = opipe; 29768b2bbf2SGordon Ross ofile = smb_ofile_open(sr, NULL, op, 29868b2bbf2SGordon Ross SMB_FTYPE_MESG_PIPE, uniqid, &err); 29968b2bbf2SGordon Ross op->pipe = NULL; 30068b2bbf2SGordon Ross if (ofile == NULL) { 30168b2bbf2SGordon Ross smb_opipe_dealloc(opipe); 30268b2bbf2SGordon Ross return (err.status); 30368b2bbf2SGordon Ross } 30468b2bbf2SGordon Ross 30568b2bbf2SGordon Ross /* An "up" pointer, for debug. */ 30668b2bbf2SGordon Ross opipe->p_ofile = ofile; 30768b2bbf2SGordon Ross 308c5f48fa5SGordon Ross /* 309c5f48fa5SGordon Ross * Caller expects attributes in op->fqi 310c5f48fa5SGordon Ross */ 311c5f48fa5SGordon Ross (void) smb_opipe_getattr(ofile, &op->fqi.fq_fattr); 312c5f48fa5SGordon Ross 313c5f48fa5SGordon Ross op->dsize = 0; 314c5f48fa5SGordon Ross op->dattr = ap->sa_dosattr; 315c5f48fa5SGordon Ross op->fileid = ap->sa_vattr.va_nodeid; 3163db3f65cSamw op->ftype = SMB_FTYPE_MESG_PIPE; 317c5f48fa5SGordon Ross op->action_taken = SMB_OACT_OPLOCK | SMB_OACT_OPENED; 3183db3f65cSamw op->devstate = SMB_PIPE_READMODE_MESSAGE 3193db3f65cSamw | SMB_PIPE_TYPE_MESSAGE 3203db3f65cSamw | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 3213db3f65cSamw 32268b2bbf2SGordon Ross sr->smb_fid = ofile->f_fid; 32368b2bbf2SGordon Ross sr->fid_ofile = ofile; 3243db3f65cSamw 3253db3f65cSamw return (NT_STATUS_SUCCESS); 3263db3f65cSamw } 3273db3f65cSamw 3283db3f65cSamw /* 3293db3f65cSamw * smb_opipe_close 3303db3f65cSamw * 33168b2bbf2SGordon Ross * Called by smb_ofile_close for pipes. 33268b2bbf2SGordon Ross * 33368b2bbf2SGordon Ross * Note: ksocket_close may block while waiting for 33468b2bbf2SGordon Ross * any I/O threads with a hold to get out. 3353db3f65cSamw */ 3363db3f65cSamw void 3373db3f65cSamw smb_opipe_close(smb_ofile_t *of) 3383db3f65cSamw { 3393db3f65cSamw smb_opipe_t *opipe; 34068b2bbf2SGordon Ross ksocket_t sock; 3413db3f65cSamw 34268b2bbf2SGordon Ross ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); 3433db3f65cSamw ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 3443db3f65cSamw opipe = of->f_pipe; 3459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OPIPE_VALID(opipe); 3469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 34768b2bbf2SGordon Ross mutex_enter(&opipe->p_mutex); 34868b2bbf2SGordon Ross sock = opipe->p_socket; 34968b2bbf2SGordon Ross opipe->p_socket = NULL; 35068b2bbf2SGordon Ross mutex_exit(&opipe->p_mutex); 3513db3f65cSamw 35268b2bbf2SGordon Ross (void) ksocket_shutdown(sock, SHUT_RDWR, of->f_cr); 35368b2bbf2SGordon Ross (void) ksocket_close(sock, of->f_cr); 3543db3f65cSamw } 3553db3f65cSamw 3563db3f65cSamw /* 3573db3f65cSamw * smb_opipe_write 3583db3f65cSamw * 3593db3f65cSamw * Write RPC request data to the pipe. The client should call smb_opipe_read 3603db3f65cSamw * to complete the exchange and obtain the RPC response. 3613db3f65cSamw * 3623db3f65cSamw * Returns 0 on success or an errno on failure. 3633db3f65cSamw */ 3643db3f65cSamw int 3653db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio) 3663db3f65cSamw { 36768b2bbf2SGordon Ross struct nmsghdr msghdr; 36868b2bbf2SGordon Ross smb_ofile_t *ofile; 3693db3f65cSamw smb_opipe_t *opipe; 37068b2bbf2SGordon Ross ksocket_t sock; 37168b2bbf2SGordon Ross size_t sent = 0; 37268b2bbf2SGordon Ross int rc = 0; 3733db3f65cSamw 37468b2bbf2SGordon Ross ofile = sr->fid_ofile; 37568b2bbf2SGordon Ross ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 37668b2bbf2SGordon Ross opipe = ofile->f_pipe; 3779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OPIPE_VALID(opipe); 3783db3f65cSamw 37968b2bbf2SGordon Ross mutex_enter(&opipe->p_mutex); 38068b2bbf2SGordon Ross sock = opipe->p_socket; 38168b2bbf2SGordon Ross if (sock != NULL) 38268b2bbf2SGordon Ross ksocket_hold(sock); 38368b2bbf2SGordon Ross mutex_exit(&opipe->p_mutex); 38468b2bbf2SGordon Ross if (sock == NULL) 3853db3f65cSamw return (EBADF); 38668b2bbf2SGordon Ross 38768b2bbf2SGordon Ross bzero(&msghdr, sizeof (msghdr)); 38868b2bbf2SGordon Ross msghdr.msg_iov = uio->uio_iov; 38968b2bbf2SGordon Ross msghdr.msg_iovlen = uio->uio_iovcnt; 39068b2bbf2SGordon Ross 39168b2bbf2SGordon Ross /* 39268b2bbf2SGordon Ross * This should block until we've sent it all, 39368b2bbf2SGordon Ross * or given up due to errors (pipe closed). 39468b2bbf2SGordon Ross */ 39568b2bbf2SGordon Ross while (uio->uio_resid > 0) { 39668b2bbf2SGordon Ross rc = ksocket_sendmsg(sock, &msghdr, 0, &sent, ofile->f_cr); 39768b2bbf2SGordon Ross if (rc != 0) 39868b2bbf2SGordon Ross break; 39968b2bbf2SGordon Ross uio->uio_resid -= sent; 4003db3f65cSamw } 4013db3f65cSamw 40268b2bbf2SGordon Ross ksocket_rele(sock); 4033db3f65cSamw 40468b2bbf2SGordon Ross return (rc); 4053db3f65cSamw } 4063db3f65cSamw 4073db3f65cSamw /* 4083db3f65cSamw * smb_opipe_read 4093db3f65cSamw * 41068b2bbf2SGordon Ross * This interface may be called from smb_opipe_transact (write, read) 41168b2bbf2SGordon Ross * or from smb_read / smb2_read to get the rest of an RPC response. 41268b2bbf2SGordon Ross * The response data (and length) are returned via the uio. 4133db3f65cSamw */ 4143db3f65cSamw int 4153db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio) 4163db3f65cSamw { 41768b2bbf2SGordon Ross struct nmsghdr msghdr; 41868b2bbf2SGordon Ross smb_ofile_t *ofile; 4193db3f65cSamw smb_opipe_t *opipe; 42068b2bbf2SGordon Ross ksocket_t sock; 42168b2bbf2SGordon Ross size_t recvcnt = 0; 4223db3f65cSamw int rc; 4233db3f65cSamw 42468b2bbf2SGordon Ross ofile = sr->fid_ofile; 42568b2bbf2SGordon Ross ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 42668b2bbf2SGordon Ross opipe = ofile->f_pipe; 4279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OPIPE_VALID(opipe); 4289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 42968b2bbf2SGordon Ross mutex_enter(&opipe->p_mutex); 43068b2bbf2SGordon Ross sock = opipe->p_socket; 43168b2bbf2SGordon Ross if (sock != NULL) 43268b2bbf2SGordon Ross ksocket_hold(sock); 43368b2bbf2SGordon Ross mutex_exit(&opipe->p_mutex); 43468b2bbf2SGordon Ross if (sock == NULL) 4353db3f65cSamw return (EBADF); 4363db3f65cSamw 437*b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 438*b210fedeSGordon Ross if (sr->sr_state != SMB_REQ_STATE_ACTIVE) { 439*b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 440*b210fedeSGordon Ross rc = EINTR; 441*b210fedeSGordon Ross goto out; 442*b210fedeSGordon Ross } 443*b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_WAITING_PIPE; 444*b210fedeSGordon Ross sr->cancel_method = smb_opipe_cancel; 445*b210fedeSGordon Ross sr->cancel_arg2 = sock; 446*b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 4479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 4483db3f65cSamw /* 44968b2bbf2SGordon Ross * This should block only if there's no data. 45068b2bbf2SGordon Ross * A single call to recvmsg does just that. 45168b2bbf2SGordon Ross * (Intentionaly no recv loop here.) 4523db3f65cSamw */ 453*b210fedeSGordon Ross bzero(&msghdr, sizeof (msghdr)); 454*b210fedeSGordon Ross msghdr.msg_iov = uio->uio_iov; 455*b210fedeSGordon Ross msghdr.msg_iovlen = uio->uio_iovcnt; 45668b2bbf2SGordon Ross rc = ksocket_recvmsg(sock, &msghdr, 0, 45768b2bbf2SGordon Ross &recvcnt, ofile->f_cr); 458*b210fedeSGordon Ross 459*b210fedeSGordon Ross mutex_enter(&sr->sr_mutex); 460*b210fedeSGordon Ross sr->cancel_method = NULL; 461*b210fedeSGordon Ross sr->cancel_arg2 = NULL; 462*b210fedeSGordon Ross switch (sr->sr_state) { 463*b210fedeSGordon Ross case SMB_REQ_STATE_WAITING_PIPE: 464*b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 465*b210fedeSGordon Ross break; 466*b210fedeSGordon Ross case SMB_REQ_STATE_CANCEL_PENDING: 467*b210fedeSGordon Ross sr->sr_state = SMB_REQ_STATE_CANCELLED; 468*b210fedeSGordon Ross rc = EINTR; 469*b210fedeSGordon Ross break; 470*b210fedeSGordon Ross default: 471*b210fedeSGordon Ross /* keep rc from above */ 472*b210fedeSGordon Ross break; 473*b210fedeSGordon Ross } 474*b210fedeSGordon Ross mutex_exit(&sr->sr_mutex); 475*b210fedeSGordon Ross 47668b2bbf2SGordon Ross if (rc != 0) 47768b2bbf2SGordon Ross goto out; 4783db3f65cSamw 47968b2bbf2SGordon Ross if (recvcnt == 0) { 48068b2bbf2SGordon Ross /* Other side closed. */ 48168b2bbf2SGordon Ross rc = EPIPE; 48268b2bbf2SGordon Ross goto out; 4833db3f65cSamw } 48468b2bbf2SGordon Ross uio->uio_resid -= recvcnt; 4853db3f65cSamw 486bce01b59SGordon Ross out: 487bce01b59SGordon Ross ksocket_rele(sock); 488bce01b59SGordon Ross 489bce01b59SGordon Ross return (rc); 49068b2bbf2SGordon Ross } 49168b2bbf2SGordon Ross 492bce01b59SGordon Ross int 493a90cf9f2SGordon Ross smb_opipe_ioctl(smb_request_t *sr, int cmd, void *arg, int *rvalp) 494bce01b59SGordon Ross { 495bce01b59SGordon Ross smb_ofile_t *ofile; 496bce01b59SGordon Ross smb_opipe_t *opipe; 497bce01b59SGordon Ross ksocket_t sock; 498a90cf9f2SGordon Ross int rc; 499bce01b59SGordon Ross 500bce01b59SGordon Ross ofile = sr->fid_ofile; 501bce01b59SGordon Ross ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 502bce01b59SGordon Ross opipe = ofile->f_pipe; 503bce01b59SGordon Ross SMB_OPIPE_VALID(opipe); 504bce01b59SGordon Ross 505bce01b59SGordon Ross mutex_enter(&opipe->p_mutex); 506bce01b59SGordon Ross sock = opipe->p_socket; 507bce01b59SGordon Ross if (sock != NULL) 508bce01b59SGordon Ross ksocket_hold(sock); 509bce01b59SGordon Ross mutex_exit(&opipe->p_mutex); 510bce01b59SGordon Ross if (sock == NULL) 511bce01b59SGordon Ross return (EBADF); 512bce01b59SGordon Ross 513a90cf9f2SGordon Ross rc = ksocket_ioctl(sock, cmd, (intptr_t)arg, rvalp, ofile->f_cr); 514bce01b59SGordon Ross 51568b2bbf2SGordon Ross ksocket_rele(sock); 51668b2bbf2SGordon Ross 51768b2bbf2SGordon Ross return (rc); 5183db3f65cSamw } 519a90cf9f2SGordon Ross 520a90cf9f2SGordon Ross /* 521a90cf9f2SGordon Ross * Get the smb_attr_t for a named pipe. 522a90cf9f2SGordon Ross * Caller has already cleared to zero. 523a90cf9f2SGordon Ross */ 524a90cf9f2SGordon Ross int 525a90cf9f2SGordon Ross smb_opipe_getattr(smb_ofile_t *of, smb_attr_t *ap) 526a90cf9f2SGordon Ross { 527a90cf9f2SGordon Ross 528a90cf9f2SGordon Ross if (of->f_pipe == NULL) 529a90cf9f2SGordon Ross return (EINVAL); 530a90cf9f2SGordon Ross 531a90cf9f2SGordon Ross ap->sa_vattr.va_type = VFIFO; 532a90cf9f2SGordon Ross ap->sa_vattr.va_nlink = 1; 533c5f48fa5SGordon Ross ap->sa_vattr.va_nodeid = (uintptr_t)of->f_pipe; 534a90cf9f2SGordon Ross ap->sa_dosattr = FILE_ATTRIBUTE_NORMAL; 535c5f48fa5SGordon Ross ap->sa_allocsz = SMB_PIPE_MAX_MSGSIZE; 536a90cf9f2SGordon Ross 537a90cf9f2SGordon Ross return (0); 538a90cf9f2SGordon Ross } 539a90cf9f2SGordon Ross 540a90cf9f2SGordon Ross int 541a90cf9f2SGordon Ross smb_opipe_getname(smb_ofile_t *of, char *buf, size_t buflen) 542a90cf9f2SGordon Ross { 543a90cf9f2SGordon Ross smb_opipe_t *opipe; 544a90cf9f2SGordon Ross 545a90cf9f2SGordon Ross if ((opipe = of->f_pipe) == NULL) 546a90cf9f2SGordon Ross return (EINVAL); 547a90cf9f2SGordon Ross 548a90cf9f2SGordon Ross (void) snprintf(buf, buflen, "\\%s", opipe->p_name); 549a90cf9f2SGordon Ross return (0); 550a90cf9f2SGordon Ross } 551a90cf9f2SGordon Ross 552a90cf9f2SGordon Ross /* 553a90cf9f2SGordon Ross * Handler for smb2_ioctl 554a90cf9f2SGordon Ross */ 555a90cf9f2SGordon Ross /* ARGSUSED */ 556a90cf9f2SGordon Ross uint32_t 557a90cf9f2SGordon Ross smb_opipe_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl) 558a90cf9f2SGordon Ross { 559a90cf9f2SGordon Ross uint32_t status; 560a90cf9f2SGordon Ross 561a90cf9f2SGordon Ross switch (fsctl->CtlCode) { 562a90cf9f2SGordon Ross case FSCTL_PIPE_TRANSCEIVE: 563a90cf9f2SGordon Ross status = smb_opipe_transceive(sr, fsctl); 564a90cf9f2SGordon Ross break; 565a90cf9f2SGordon Ross 566a90cf9f2SGordon Ross case FSCTL_PIPE_PEEK: 567a90cf9f2SGordon Ross case FSCTL_PIPE_WAIT: 568a90cf9f2SGordon Ross /* XXX todo */ 569a90cf9f2SGordon Ross status = NT_STATUS_NOT_SUPPORTED; 570a90cf9f2SGordon Ross break; 571a90cf9f2SGordon Ross 572a90cf9f2SGordon Ross default: 573a90cf9f2SGordon Ross ASSERT(!"CtlCode"); 574a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 575a90cf9f2SGordon Ross break; 576a90cf9f2SGordon Ross } 577a90cf9f2SGordon Ross 578a90cf9f2SGordon Ross return (status); 579a90cf9f2SGordon Ross } 580a90cf9f2SGordon Ross 581a90cf9f2SGordon Ross static uint32_t 582a90cf9f2SGordon Ross smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl) 583a90cf9f2SGordon Ross { 584a90cf9f2SGordon Ross smb_vdb_t vdb; 585a90cf9f2SGordon Ross smb_ofile_t *ofile; 586a90cf9f2SGordon Ross struct mbuf *mb; 587a90cf9f2SGordon Ross uint32_t status; 588a90cf9f2SGordon Ross int len, rc; 589a90cf9f2SGordon Ross 590a90cf9f2SGordon Ross /* 591a90cf9f2SGordon Ross * Caller checked that this is the IPC$ share, 592a90cf9f2SGordon Ross * and that this call has a valid open handle. 593a90cf9f2SGordon Ross * Just check the type. 594a90cf9f2SGordon Ross */ 595a90cf9f2SGordon Ross ofile = sr->fid_ofile; 596a90cf9f2SGordon Ross if (ofile->f_ftype != SMB_FTYPE_MESG_PIPE) 597a90cf9f2SGordon Ross return (NT_STATUS_INVALID_HANDLE); 598a90cf9f2SGordon Ross 599a90cf9f2SGordon Ross rc = smb_mbc_decodef(fsctl->in_mbc, "#B", 600a90cf9f2SGordon Ross fsctl->InputCount, &vdb); 601a90cf9f2SGordon Ross if (rc != 0) { 602a90cf9f2SGordon Ross /* Not enough data sent. */ 603a90cf9f2SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 604a90cf9f2SGordon Ross } 605a90cf9f2SGordon Ross 606a90cf9f2SGordon Ross rc = smb_opipe_write(sr, &vdb.vdb_uio); 607a90cf9f2SGordon Ross if (rc != 0) 608a90cf9f2SGordon Ross return (smb_errno2status(rc)); 609a90cf9f2SGordon Ross 610a90cf9f2SGordon Ross vdb.vdb_tag = 0; 611a90cf9f2SGordon Ross vdb.vdb_uio.uio_iov = &vdb.vdb_iovec[0]; 612a90cf9f2SGordon Ross vdb.vdb_uio.uio_iovcnt = MAX_IOVEC; 613a90cf9f2SGordon Ross vdb.vdb_uio.uio_segflg = UIO_SYSSPACE; 614a90cf9f2SGordon Ross vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 615a90cf9f2SGordon Ross vdb.vdb_uio.uio_loffset = (offset_t)0; 616a90cf9f2SGordon Ross vdb.vdb_uio.uio_resid = fsctl->MaxOutputResp; 617a90cf9f2SGordon Ross mb = smb_mbuf_allocate(&vdb.vdb_uio); 618a90cf9f2SGordon Ross 619a90cf9f2SGordon Ross rc = smb_opipe_read(sr, &vdb.vdb_uio); 620a90cf9f2SGordon Ross if (rc != 0) { 621a90cf9f2SGordon Ross m_freem(mb); 622a90cf9f2SGordon Ross return (smb_errno2status(rc)); 623a90cf9f2SGordon Ross } 624a90cf9f2SGordon Ross 625a90cf9f2SGordon Ross len = fsctl->MaxOutputResp - vdb.vdb_uio.uio_resid; 626a90cf9f2SGordon Ross smb_mbuf_trim(mb, len); 627a90cf9f2SGordon Ross MBC_ATTACH_MBUF(fsctl->out_mbc, mb); 628a90cf9f2SGordon Ross 629a90cf9f2SGordon Ross /* 630a90cf9f2SGordon Ross * If the output buffer holds a partial pipe message, 631a90cf9f2SGordon Ross * we're supposed to return NT_STATUS_BUFFER_OVERFLOW. 632a90cf9f2SGordon Ross * As we don't have message boundary markers, the best 633a90cf9f2SGordon Ross * we can do is return that status when we have ALL of: 634a90cf9f2SGordon Ross * Output buffer was < SMB_PIPE_MAX_MSGSIZE 635a90cf9f2SGordon Ross * We filled the output buffer (resid==0) 636a90cf9f2SGordon Ross * There's more data (ioctl FIONREAD) 637a90cf9f2SGordon Ross */ 638a90cf9f2SGordon Ross status = NT_STATUS_SUCCESS; 639a90cf9f2SGordon Ross if (fsctl->MaxOutputResp < SMB_PIPE_MAX_MSGSIZE && 640a90cf9f2SGordon Ross vdb.vdb_uio.uio_resid == 0) { 641a90cf9f2SGordon Ross int nread = 0, trval; 642a90cf9f2SGordon Ross rc = smb_opipe_ioctl(sr, FIONREAD, &nread, &trval); 643a90cf9f2SGordon Ross if (rc == 0 && nread != 0) 644a90cf9f2SGordon Ross status = NT_STATUS_BUFFER_OVERFLOW; 645a90cf9f2SGordon Ross } 646a90cf9f2SGordon Ross 647a90cf9f2SGordon Ross return (status); 648a90cf9f2SGordon Ross } 649