1*3db3f65cSamw /* 2*3db3f65cSamw * CDDL HEADER START 3*3db3f65cSamw * 4*3db3f65cSamw * The contents of this file are subject to the terms of the 5*3db3f65cSamw * Common Development and Distribution License (the "License"). 6*3db3f65cSamw * You may not use this file except in compliance with the License. 7*3db3f65cSamw * 8*3db3f65cSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3db3f65cSamw * or http://www.opensolaris.org/os/licensing. 10*3db3f65cSamw * See the License for the specific language governing permissions 11*3db3f65cSamw * and limitations under the License. 12*3db3f65cSamw * 13*3db3f65cSamw * When distributing Covered Code, include this CDDL HEADER in each 14*3db3f65cSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3db3f65cSamw * If applicable, add the following below this CDDL HEADER, with the 16*3db3f65cSamw * fields enclosed by brackets "[]" replaced with your own identifying 17*3db3f65cSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18*3db3f65cSamw * 19*3db3f65cSamw * CDDL HEADER END 20*3db3f65cSamw */ 21*3db3f65cSamw /* 22*3db3f65cSamw * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*3db3f65cSamw * Use is subject to license terms. 24*3db3f65cSamw */ 25*3db3f65cSamw 26*3db3f65cSamw #pragma ident "%Z%%M% %I% %E% SMI" 27*3db3f65cSamw 28*3db3f65cSamw /* 29*3db3f65cSamw * This module provides the interface to NDR RPC. 30*3db3f65cSamw */ 31*3db3f65cSamw 32*3db3f65cSamw #include <sys/stat.h> 33*3db3f65cSamw #include <sys/door.h> 34*3db3f65cSamw #include <sys/door_data.h> 35*3db3f65cSamw #include <sys/uio.h> 36*3db3f65cSamw #include <sys/ksynch.h> 37*3db3f65cSamw #include <smbsrv/smb_incl.h> 38*3db3f65cSamw #include <smbsrv/smb_xdr.h> 39*3db3f65cSamw 40*3db3f65cSamw #define SMB_OPIPE_ISOPEN(OPIPE) \ 41*3db3f65cSamw (((OPIPE)->p_hdr.oh_magic == SMB_OPIPE_HDR_MAGIC) && \ 42*3db3f65cSamw ((OPIPE)->p_hdr.oh_fid)) 43*3db3f65cSamw 44*3db3f65cSamw extern volatile uint32_t smb_fids; 45*3db3f65cSamw 46*3db3f65cSamw static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *); 47*3db3f65cSamw static char *smb_opipe_lookup(const char *path); 48*3db3f65cSamw static uint32_t smb_opipe_fid(void); 49*3db3f65cSamw static int smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t, uint32_t); 50*3db3f65cSamw static void smb_opipe_enter(smb_opipe_t *); 51*3db3f65cSamw static void smb_opipe_exit(smb_opipe_t *); 52*3db3f65cSamw 53*3db3f65cSamw static door_handle_t smb_opipe_door_hd = NULL; 54*3db3f65cSamw static int smb_opipe_door_id = -1; 55*3db3f65cSamw static uint64_t smb_opipe_door_ncall = 0; 56*3db3f65cSamw static kmutex_t smb_opipe_door_mutex; 57*3db3f65cSamw static kcondvar_t smb_opipe_door_cv; 58*3db3f65cSamw 59*3db3f65cSamw static int smb_opipe_door_call(smb_opipe_t *); 60*3db3f65cSamw static int smb_opipe_door_upcall(smb_opipe_t *); 61*3db3f65cSamw static void smb_user_context_fini(smb_opipe_context_t *); 62*3db3f65cSamw 63*3db3f65cSamw /* 64*3db3f65cSamw * smb_opipe_open 65*3db3f65cSamw * 66*3db3f65cSamw * Open a well-known RPC named pipe. This routine should be called if 67*3db3f65cSamw * a file open is requested on a share of type STYPE_IPC. 68*3db3f65cSamw * If we recognize the pipe, we setup a new ofile. 69*3db3f65cSamw * 70*3db3f65cSamw * Returns 0 on success, Otherwise an NT status is returned to indicate 71*3db3f65cSamw * an error. 72*3db3f65cSamw */ 73*3db3f65cSamw int 74*3db3f65cSamw smb_opipe_open(smb_request_t *sr) 75*3db3f65cSamw { 76*3db3f65cSamw struct open_param *op = &sr->arg.open; 77*3db3f65cSamw smb_ofile_t *of; 78*3db3f65cSamw smb_opipe_t *opipe; 79*3db3f65cSamw smb_opipe_hdr_t hdr; 80*3db3f65cSamw smb_error_t err; 81*3db3f65cSamw char *pipe_name; 82*3db3f65cSamw 83*3db3f65cSamw if ((pipe_name = smb_opipe_lookup(op->fqi.path)) == NULL) 84*3db3f65cSamw return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 85*3db3f65cSamw 86*3db3f65cSamw of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, 87*3db3f65cSamw op->desired_access, 0, op->share_access, 88*3db3f65cSamw SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err); 89*3db3f65cSamw if (of == NULL) 90*3db3f65cSamw return (err.status); 91*3db3f65cSamw 92*3db3f65cSamw op->dsize = 0x01000; 93*3db3f65cSamw op->dattr = FILE_ATTRIBUTE_NORMAL; 94*3db3f65cSamw op->ftype = SMB_FTYPE_MESG_PIPE; 95*3db3f65cSamw op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */ 96*3db3f65cSamw op->devstate = SMB_PIPE_READMODE_MESSAGE 97*3db3f65cSamw | SMB_PIPE_TYPE_MESSAGE 98*3db3f65cSamw | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 99*3db3f65cSamw op->fileid = of->f_fid; 100*3db3f65cSamw op->create_options = 0; 101*3db3f65cSamw 102*3db3f65cSamw sr->smb_fid = of->f_fid; 103*3db3f65cSamw sr->fid_ofile = of; 104*3db3f65cSamw 105*3db3f65cSamw opipe = of->f_pipe; 106*3db3f65cSamw mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL); 107*3db3f65cSamw cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL); 108*3db3f65cSamw smb_opipe_enter(opipe); 109*3db3f65cSamw 110*3db3f65cSamw opipe->p_name = pipe_name; 111*3db3f65cSamw opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP); 112*3db3f65cSamw 113*3db3f65cSamw /* 114*3db3f65cSamw * p_data points to the offset within p_doorbuf at which 115*3db3f65cSamw * data will be written or read. 116*3db3f65cSamw */ 117*3db3f65cSamw opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr); 118*3db3f65cSamw 119*3db3f65cSamw if (smb_opipe_do_open(sr, opipe) != 0) { 120*3db3f65cSamw /* 121*3db3f65cSamw * On error, reset the header to clear the fid, 122*3db3f65cSamw * which avoids confusion when smb_opipe_close() is 123*3db3f65cSamw * called by smb_ofile_close(). 124*3db3f65cSamw */ 125*3db3f65cSamw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 126*3db3f65cSamw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 127*3db3f65cSamw smb_opipe_exit(opipe); 128*3db3f65cSamw (void) smb_ofile_close(of, 0); 129*3db3f65cSamw return (NT_STATUS_NO_MEMORY); 130*3db3f65cSamw } 131*3db3f65cSamw 132*3db3f65cSamw smb_opipe_exit(opipe); 133*3db3f65cSamw return (NT_STATUS_SUCCESS); 134*3db3f65cSamw } 135*3db3f65cSamw 136*3db3f65cSamw /* 137*3db3f65cSamw * smb_opipe_lookup 138*3db3f65cSamw * 139*3db3f65cSamw * Lookup a path to see if it's a well-known RPC named pipe that we support. 140*3db3f65cSamw * The full pipe path will be in the form \\PIPE\\SERVICE. The first part 141*3db3f65cSamw * can be assumed, so all we need here are the service names. 142*3db3f65cSamw * 143*3db3f65cSamw * Returns a pointer to the pipe name (without any leading \'s) on sucess. 144*3db3f65cSamw * Otherwise returns a null pointer. 145*3db3f65cSamw */ 146*3db3f65cSamw static char * 147*3db3f65cSamw smb_opipe_lookup(const char *path) 148*3db3f65cSamw { 149*3db3f65cSamw static char *named_pipes[] = { 150*3db3f65cSamw "LSARPC", 151*3db3f65cSamw "NETLOGON", 152*3db3f65cSamw "SAMR", 153*3db3f65cSamw "SPOOLSS", 154*3db3f65cSamw "SRVSVC", 155*3db3f65cSamw "SVCCTL", 156*3db3f65cSamw "WINREG", 157*3db3f65cSamw "WKSSVC", 158*3db3f65cSamw "EVENTLOG" 159*3db3f65cSamw }; 160*3db3f65cSamw 161*3db3f65cSamw const char *name; 162*3db3f65cSamw int i; 163*3db3f65cSamw 164*3db3f65cSamw if (path == NULL) 165*3db3f65cSamw return (NULL); 166*3db3f65cSamw 167*3db3f65cSamw name = path; 168*3db3f65cSamw name += strspn(name, "\\"); 169*3db3f65cSamw if (utf8_strncasecmp(name, "PIPE", 4) == 0) { 170*3db3f65cSamw path += 4; 171*3db3f65cSamw name += strspn(name, "\\"); 172*3db3f65cSamw } 173*3db3f65cSamw 174*3db3f65cSamw for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) { 175*3db3f65cSamw if (utf8_strcasecmp(name, named_pipes[i]) == 0) 176*3db3f65cSamw return (named_pipes[i]); 177*3db3f65cSamw } 178*3db3f65cSamw 179*3db3f65cSamw return (NULL); 180*3db3f65cSamw } 181*3db3f65cSamw 182*3db3f65cSamw /* 183*3db3f65cSamw * Initialize the opipe header and context, and make the door call. 184*3db3f65cSamw */ 185*3db3f65cSamw static int 186*3db3f65cSamw smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) 187*3db3f65cSamw { 188*3db3f65cSamw smb_opipe_context_t *ctx = &opipe->p_context; 189*3db3f65cSamw smb_user_t *user = sr->uid_user; 190*3db3f65cSamw uint8_t *buf = opipe->p_doorbuf; 191*3db3f65cSamw uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; 192*3db3f65cSamw uint32_t len; 193*3db3f65cSamw 194*3db3f65cSamw smb_user_context_init(user, ctx); 195*3db3f65cSamw len = xdr_sizeof(smb_opipe_context_xdr, ctx); 196*3db3f65cSamw 197*3db3f65cSamw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 198*3db3f65cSamw opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC; 199*3db3f65cSamw opipe->p_hdr.oh_fid = smb_opipe_fid(); 200*3db3f65cSamw 201*3db3f65cSamw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1) 202*3db3f65cSamw return (-1); 203*3db3f65cSamw 204*3db3f65cSamw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 205*3db3f65cSamw buf += len; 206*3db3f65cSamw buflen -= len; 207*3db3f65cSamw 208*3db3f65cSamw if (smb_opipe_context_encode(ctx, buf, buflen) == -1) 209*3db3f65cSamw return (-1); 210*3db3f65cSamw 211*3db3f65cSamw return (smb_opipe_door_call(opipe)); 212*3db3f65cSamw } 213*3db3f65cSamw 214*3db3f65cSamw /* 215*3db3f65cSamw * smb_opipe_fid 216*3db3f65cSamw * 217*3db3f65cSamw * The opipe_fid is an arbitrary id used to associate RPC requests 218*3db3f65cSamw * with a binding handle. A new fid is returned on each call. 219*3db3f65cSamw * 0 or -1 are not assigned: 0 is used to indicate an invalid fid 220*3db3f65cSamw * and SMB sometimes uses -1 to indicate all open fid's. 221*3db3f65cSamw */ 222*3db3f65cSamw static uint32_t 223*3db3f65cSamw smb_opipe_fid(void) 224*3db3f65cSamw { 225*3db3f65cSamw static uint32_t opipe_fid; 226*3db3f65cSamw static kmutex_t smb_opipe_fid_mutex; 227*3db3f65cSamw 228*3db3f65cSamw mutex_enter(&smb_opipe_fid_mutex); 229*3db3f65cSamw 230*3db3f65cSamw if (opipe_fid == 0) 231*3db3f65cSamw opipe_fid = lbolt << 11; 232*3db3f65cSamw 233*3db3f65cSamw do { 234*3db3f65cSamw ++opipe_fid; 235*3db3f65cSamw } while (opipe_fid == 0 || opipe_fid == (uint32_t)-1); 236*3db3f65cSamw 237*3db3f65cSamw mutex_exit(&smb_opipe_fid_mutex); 238*3db3f65cSamw 239*3db3f65cSamw return (opipe_fid); 240*3db3f65cSamw } 241*3db3f65cSamw 242*3db3f65cSamw /* 243*3db3f65cSamw * smb_opipe_close 244*3db3f65cSamw * 245*3db3f65cSamw * Called whenever an IPC file/pipe is closed. 246*3db3f65cSamw */ 247*3db3f65cSamw void 248*3db3f65cSamw smb_opipe_close(smb_ofile_t *of) 249*3db3f65cSamw { 250*3db3f65cSamw smb_opipe_t *opipe; 251*3db3f65cSamw 252*3db3f65cSamw ASSERT(of); 253*3db3f65cSamw ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 254*3db3f65cSamw ASSERT(of->f_pipe != NULL); 255*3db3f65cSamw 256*3db3f65cSamw opipe = of->f_pipe; 257*3db3f65cSamw smb_opipe_enter(opipe); 258*3db3f65cSamw 259*3db3f65cSamw if (SMB_OPIPE_ISOPEN(opipe)) { 260*3db3f65cSamw (void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0); 261*3db3f65cSamw (void) smb_opipe_door_call(opipe); 262*3db3f65cSamw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 263*3db3f65cSamw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 264*3db3f65cSamw } 265*3db3f65cSamw 266*3db3f65cSamw smb_user_context_fini(&opipe->p_context); 267*3db3f65cSamw smb_opipe_exit(opipe); 268*3db3f65cSamw cv_destroy(&opipe->p_cv); 269*3db3f65cSamw mutex_destroy(&opipe->p_mutex); 270*3db3f65cSamw } 271*3db3f65cSamw 272*3db3f65cSamw static int 273*3db3f65cSamw smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen) 274*3db3f65cSamw { 275*3db3f65cSamw opipe->p_hdr.oh_op = cmd; 276*3db3f65cSamw opipe->p_hdr.oh_datalen = datalen; 277*3db3f65cSamw opipe->p_hdr.oh_resid = 0; 278*3db3f65cSamw opipe->p_hdr.oh_status = 0; 279*3db3f65cSamw 280*3db3f65cSamw return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf, 281*3db3f65cSamw SMB_OPIPE_DOOR_BUFSIZE)); 282*3db3f65cSamw } 283*3db3f65cSamw 284*3db3f65cSamw /* 285*3db3f65cSamw * smb_opipe_transact 286*3db3f65cSamw * 287*3db3f65cSamw * This is the entry point for RPC bind and request transactions. 288*3db3f65cSamw * The fid is an arbitrary id used to associate RPC requests with a 289*3db3f65cSamw * particular binding handle. 290*3db3f65cSamw * 291*3db3f65cSamw * If the data to be returned is larger than the client expects, we 292*3db3f65cSamw * return as much as the client can handle and report a buffer overflow 293*3db3f65cSamw * warning, which informs the client that we have more data to return. 294*3db3f65cSamw * The residual data remains in the pipe until the client claims it or 295*3db3f65cSamw * closes the pipe. 296*3db3f65cSamw */ 297*3db3f65cSamw smb_sdrc_t 298*3db3f65cSamw smb_opipe_transact(smb_request_t *sr, struct uio *uio) 299*3db3f65cSamw { 300*3db3f65cSamw smb_xa_t *xa; 301*3db3f65cSamw smb_opipe_t *opipe; 302*3db3f65cSamw struct mbuf *mhead; 303*3db3f65cSamw int mdrcnt; 304*3db3f65cSamw int nbytes; 305*3db3f65cSamw int rc; 306*3db3f65cSamw 307*3db3f65cSamw if ((rc = smb_opipe_write(sr, uio)) != 0) { 308*3db3f65cSamw if (rc == EBADF) 309*3db3f65cSamw smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 310*3db3f65cSamw ERRDOS, ERROR_INVALID_HANDLE); 311*3db3f65cSamw else 312*3db3f65cSamw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 313*3db3f65cSamw ERRDOS, ERROR_INTERNAL_ERROR); 314*3db3f65cSamw return (SDRC_ERROR); 315*3db3f65cSamw } 316*3db3f65cSamw 317*3db3f65cSamw xa = sr->r_xa; 318*3db3f65cSamw mdrcnt = xa->smb_mdrcnt; 319*3db3f65cSamw opipe = sr->fid_ofile->f_pipe; 320*3db3f65cSamw smb_opipe_enter(opipe); 321*3db3f65cSamw 322*3db3f65cSamw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) { 323*3db3f65cSamw smb_opipe_exit(opipe); 324*3db3f65cSamw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 325*3db3f65cSamw ERRDOS, ERROR_INTERNAL_ERROR); 326*3db3f65cSamw return (SDRC_ERROR); 327*3db3f65cSamw } 328*3db3f65cSamw 329*3db3f65cSamw rc = smb_opipe_door_call(opipe); 330*3db3f65cSamw nbytes = opipe->p_hdr.oh_datalen; 331*3db3f65cSamw 332*3db3f65cSamw if (rc != 0) { 333*3db3f65cSamw smb_opipe_exit(opipe); 334*3db3f65cSamw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 335*3db3f65cSamw ERRDOS, ERROR_INTERNAL_ERROR); 336*3db3f65cSamw return (SDRC_ERROR); 337*3db3f65cSamw } 338*3db3f65cSamw 339*3db3f65cSamw if (nbytes) { 340*3db3f65cSamw mhead = smb_mbuf_get(opipe->p_data, nbytes); 341*3db3f65cSamw xa->rep_data_mb.max_bytes = nbytes; 342*3db3f65cSamw MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead); 343*3db3f65cSamw } 344*3db3f65cSamw 345*3db3f65cSamw if (opipe->p_hdr.oh_resid) { 346*3db3f65cSamw /* 347*3db3f65cSamw * The pipe contains more data than mdrcnt, warn the 348*3db3f65cSamw * client that there is more data in the pipe. 349*3db3f65cSamw * Typically, the client will call SmbReadX, which 350*3db3f65cSamw * will call smb_opipe_read, to get the data. 351*3db3f65cSamw */ 352*3db3f65cSamw smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, 353*3db3f65cSamw ERRDOS, ERROR_MORE_DATA); 354*3db3f65cSamw } 355*3db3f65cSamw 356*3db3f65cSamw smb_opipe_exit(opipe); 357*3db3f65cSamw return (SDRC_SUCCESS); 358*3db3f65cSamw } 359*3db3f65cSamw 360*3db3f65cSamw /* 361*3db3f65cSamw * smb_opipe_write 362*3db3f65cSamw * 363*3db3f65cSamw * Write RPC request data to the pipe. The client should call smb_opipe_read 364*3db3f65cSamw * to complete the exchange and obtain the RPC response. 365*3db3f65cSamw * 366*3db3f65cSamw * Returns 0 on success or an errno on failure. 367*3db3f65cSamw */ 368*3db3f65cSamw int 369*3db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio) 370*3db3f65cSamw { 371*3db3f65cSamw smb_opipe_t *opipe; 372*3db3f65cSamw uint32_t buflen; 373*3db3f65cSamw uint32_t len; 374*3db3f65cSamw int rc; 375*3db3f65cSamw 376*3db3f65cSamw ASSERT(sr->fid_ofile); 377*3db3f65cSamw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 378*3db3f65cSamw ASSERT(sr->fid_ofile->f_pipe != NULL); 379*3db3f65cSamw 380*3db3f65cSamw opipe = sr->fid_ofile->f_pipe; 381*3db3f65cSamw smb_opipe_enter(opipe); 382*3db3f65cSamw 383*3db3f65cSamw if (!SMB_OPIPE_ISOPEN(opipe)) { 384*3db3f65cSamw smb_opipe_exit(opipe); 385*3db3f65cSamw return (EBADF); 386*3db3f65cSamw } 387*3db3f65cSamw 388*3db3f65cSamw rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid); 389*3db3f65cSamw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 390*3db3f65cSamw if (rc == -1 || len == 0) { 391*3db3f65cSamw smb_opipe_exit(opipe); 392*3db3f65cSamw return (ENOMEM); 393*3db3f65cSamw } 394*3db3f65cSamw 395*3db3f65cSamw buflen = SMB_OPIPE_DOOR_BUFSIZE - len; 396*3db3f65cSamw (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio); 397*3db3f65cSamw 398*3db3f65cSamw rc = smb_opipe_door_call(opipe); 399*3db3f65cSamw 400*3db3f65cSamw smb_opipe_exit(opipe); 401*3db3f65cSamw return ((rc == 0) ? 0 : EIO); 402*3db3f65cSamw } 403*3db3f65cSamw 404*3db3f65cSamw /* 405*3db3f65cSamw * smb_opipe_read 406*3db3f65cSamw * 407*3db3f65cSamw * This interface may be called because smb_opipe_transact could not return 408*3db3f65cSamw * all of the data in the original transaction or to form the second half 409*3db3f65cSamw * of a transaction set up using smb_opipe_write. Either way, we just need 410*3db3f65cSamw * to read data from the pipe and return it. 411*3db3f65cSamw * 412*3db3f65cSamw * The response data is encoded into raw_data as required by the smb_read 413*3db3f65cSamw * functions. The uio_resid value indicates the number of bytes read. 414*3db3f65cSamw */ 415*3db3f65cSamw int 416*3db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio) 417*3db3f65cSamw { 418*3db3f65cSamw smb_opipe_t *opipe; 419*3db3f65cSamw struct mbuf *mhead; 420*3db3f65cSamw uint32_t nbytes; 421*3db3f65cSamw int rc; 422*3db3f65cSamw 423*3db3f65cSamw ASSERT(sr->fid_ofile); 424*3db3f65cSamw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 425*3db3f65cSamw ASSERT(sr->fid_ofile->f_pipe != NULL); 426*3db3f65cSamw 427*3db3f65cSamw opipe = sr->fid_ofile->f_pipe; 428*3db3f65cSamw smb_opipe_enter(opipe); 429*3db3f65cSamw 430*3db3f65cSamw if (!SMB_OPIPE_ISOPEN(opipe)) { 431*3db3f65cSamw smb_opipe_exit(opipe); 432*3db3f65cSamw return (EBADF); 433*3db3f65cSamw } 434*3db3f65cSamw 435*3db3f65cSamw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) { 436*3db3f65cSamw smb_opipe_exit(opipe); 437*3db3f65cSamw return (ENOMEM); 438*3db3f65cSamw } 439*3db3f65cSamw 440*3db3f65cSamw rc = smb_opipe_door_call(opipe); 441*3db3f65cSamw nbytes = opipe->p_hdr.oh_datalen; 442*3db3f65cSamw 443*3db3f65cSamw if (rc != 0 || nbytes > uio->uio_resid) { 444*3db3f65cSamw smb_opipe_exit(opipe); 445*3db3f65cSamw return (EIO); 446*3db3f65cSamw } 447*3db3f65cSamw 448*3db3f65cSamw if (nbytes) { 449*3db3f65cSamw mhead = smb_mbuf_get(opipe->p_data, nbytes); 450*3db3f65cSamw MBC_SETUP(&sr->raw_data, nbytes); 451*3db3f65cSamw MBC_ATTACH_MBUF(&sr->raw_data, mhead); 452*3db3f65cSamw uio->uio_resid -= nbytes; 453*3db3f65cSamw } 454*3db3f65cSamw 455*3db3f65cSamw smb_opipe_exit(opipe); 456*3db3f65cSamw return (rc); 457*3db3f65cSamw } 458*3db3f65cSamw 459*3db3f65cSamw /* 460*3db3f65cSamw * Named pipe I/O is serialized per fid to ensure that each request 461*3db3f65cSamw * has exclusive opipe access for the duration of the request. 462*3db3f65cSamw */ 463*3db3f65cSamw static void 464*3db3f65cSamw smb_opipe_enter(smb_opipe_t *opipe) 465*3db3f65cSamw { 466*3db3f65cSamw mutex_enter(&opipe->p_mutex); 467*3db3f65cSamw 468*3db3f65cSamw while (opipe->p_busy) 469*3db3f65cSamw cv_wait(&opipe->p_cv, &opipe->p_mutex); 470*3db3f65cSamw 471*3db3f65cSamw opipe->p_busy = 1; 472*3db3f65cSamw mutex_exit(&opipe->p_mutex); 473*3db3f65cSamw } 474*3db3f65cSamw 475*3db3f65cSamw static void 476*3db3f65cSamw smb_opipe_exit(smb_opipe_t *opipe) 477*3db3f65cSamw { 478*3db3f65cSamw mutex_enter(&opipe->p_mutex); 479*3db3f65cSamw opipe->p_busy = 0; 480*3db3f65cSamw cv_signal(&opipe->p_cv); 481*3db3f65cSamw mutex_exit(&opipe->p_mutex); 482*3db3f65cSamw } 483*3db3f65cSamw 484*3db3f65cSamw /* 485*3db3f65cSamw * opipe door client (to user space door server). 486*3db3f65cSamw */ 487*3db3f65cSamw void 488*3db3f65cSamw smb_opipe_door_init(void) 489*3db3f65cSamw { 490*3db3f65cSamw mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL); 491*3db3f65cSamw cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL); 492*3db3f65cSamw } 493*3db3f65cSamw 494*3db3f65cSamw void 495*3db3f65cSamw smb_opipe_door_fini(void) 496*3db3f65cSamw { 497*3db3f65cSamw smb_opipe_door_close(); 498*3db3f65cSamw cv_destroy(&smb_opipe_door_cv); 499*3db3f65cSamw mutex_destroy(&smb_opipe_door_mutex); 500*3db3f65cSamw } 501*3db3f65cSamw 502*3db3f65cSamw /* 503*3db3f65cSamw * Open the (user space) door. If the door is already open, 504*3db3f65cSamw * close it first because the door-id has probably changed. 505*3db3f65cSamw */ 506*3db3f65cSamw int 507*3db3f65cSamw smb_opipe_door_open(int door_id) 508*3db3f65cSamw { 509*3db3f65cSamw smb_opipe_door_close(); 510*3db3f65cSamw 511*3db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 512*3db3f65cSamw smb_opipe_door_ncall = 0; 513*3db3f65cSamw 514*3db3f65cSamw if (smb_opipe_door_hd == NULL) { 515*3db3f65cSamw smb_opipe_door_id = door_id; 516*3db3f65cSamw smb_opipe_door_hd = door_ki_lookup(door_id); 517*3db3f65cSamw } 518*3db3f65cSamw 519*3db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 520*3db3f65cSamw return ((smb_opipe_door_hd == NULL) ? -1 : 0); 521*3db3f65cSamw } 522*3db3f65cSamw 523*3db3f65cSamw /* 524*3db3f65cSamw * Close the (user space) door. 525*3db3f65cSamw */ 526*3db3f65cSamw void 527*3db3f65cSamw smb_opipe_door_close(void) 528*3db3f65cSamw { 529*3db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 530*3db3f65cSamw 531*3db3f65cSamw if (smb_opipe_door_hd != NULL) { 532*3db3f65cSamw while (smb_opipe_door_ncall > 0) 533*3db3f65cSamw cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex); 534*3db3f65cSamw 535*3db3f65cSamw door_ki_rele(smb_opipe_door_hd); 536*3db3f65cSamw smb_opipe_door_hd = NULL; 537*3db3f65cSamw } 538*3db3f65cSamw 539*3db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 540*3db3f65cSamw } 541*3db3f65cSamw 542*3db3f65cSamw /* 543*3db3f65cSamw * opipe door call interface. 544*3db3f65cSamw * Door serialization and call reference accounting is handled here. 545*3db3f65cSamw */ 546*3db3f65cSamw static int 547*3db3f65cSamw smb_opipe_door_call(smb_opipe_t *opipe) 548*3db3f65cSamw { 549*3db3f65cSamw int rc; 550*3db3f65cSamw 551*3db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 552*3db3f65cSamw 553*3db3f65cSamw if (smb_opipe_door_hd == NULL) { 554*3db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 555*3db3f65cSamw 556*3db3f65cSamw if (smb_opipe_door_open(smb_opipe_door_id) != 0) 557*3db3f65cSamw return (-1); 558*3db3f65cSamw 559*3db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 560*3db3f65cSamw } 561*3db3f65cSamw 562*3db3f65cSamw ++smb_opipe_door_ncall; 563*3db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 564*3db3f65cSamw 565*3db3f65cSamw rc = smb_opipe_door_upcall(opipe); 566*3db3f65cSamw 567*3db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 568*3db3f65cSamw --smb_opipe_door_ncall; 569*3db3f65cSamw cv_signal(&smb_opipe_door_cv); 570*3db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 571*3db3f65cSamw return (rc); 572*3db3f65cSamw } 573*3db3f65cSamw 574*3db3f65cSamw /* 575*3db3f65cSamw * Door upcall wrapper - handles data marshalling. 576*3db3f65cSamw * This function should only be called by smb_opipe_door_call. 577*3db3f65cSamw */ 578*3db3f65cSamw static int 579*3db3f65cSamw smb_opipe_door_upcall(smb_opipe_t *opipe) 580*3db3f65cSamw { 581*3db3f65cSamw door_arg_t da; 582*3db3f65cSamw smb_opipe_hdr_t hdr; 583*3db3f65cSamw int i; 584*3db3f65cSamw int rc; 585*3db3f65cSamw 586*3db3f65cSamw da.data_ptr = (char *)opipe->p_doorbuf; 587*3db3f65cSamw da.data_size = SMB_OPIPE_DOOR_BUFSIZE; 588*3db3f65cSamw da.desc_ptr = NULL; 589*3db3f65cSamw da.desc_num = 0; 590*3db3f65cSamw da.rbuf = (char *)opipe->p_doorbuf; 591*3db3f65cSamw da.rsize = SMB_OPIPE_DOOR_BUFSIZE; 592*3db3f65cSamw 593*3db3f65cSamw for (i = 0; i < 3; ++i) { 594*3db3f65cSamw if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da, 595*3db3f65cSamw NULL, SIZE_MAX, 0)) == 0) 596*3db3f65cSamw break; 597*3db3f65cSamw 598*3db3f65cSamw if (rc != EAGAIN && rc != EINTR) 599*3db3f65cSamw return (-1); 600*3db3f65cSamw } 601*3db3f65cSamw 602*3db3f65cSamw if (rc != 0) 603*3db3f65cSamw return (-1); 604*3db3f65cSamw 605*3db3f65cSamw if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1) 606*3db3f65cSamw return (-1); 607*3db3f65cSamw 608*3db3f65cSamw if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) || 609*3db3f65cSamw (hdr.oh_fid != opipe->p_hdr.oh_fid) || 610*3db3f65cSamw (hdr.oh_op != opipe->p_hdr.oh_op) || 611*3db3f65cSamw (hdr.oh_status != 0) || 612*3db3f65cSamw (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) { 613*3db3f65cSamw return (-1); 614*3db3f65cSamw } 615*3db3f65cSamw 616*3db3f65cSamw opipe->p_hdr.oh_datalen = hdr.oh_datalen; 617*3db3f65cSamw opipe->p_hdr.oh_resid = hdr.oh_resid; 618*3db3f65cSamw return (0); 619*3db3f65cSamw } 620*3db3f65cSamw 621*3db3f65cSamw void 622*3db3f65cSamw smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx) 623*3db3f65cSamw { 624*3db3f65cSamw smb_session_t *session; 625*3db3f65cSamw 626*3db3f65cSamw ASSERT(user); 627*3db3f65cSamw ASSERT(user->u_domain); 628*3db3f65cSamw ASSERT(user->u_name); 629*3db3f65cSamw 630*3db3f65cSamw session = user->u_session; 631*3db3f65cSamw ASSERT(session); 632*3db3f65cSamw ASSERT(session->workstation); 633*3db3f65cSamw 634*3db3f65cSamw ctx->oc_session_id = session->s_kid; 635*3db3f65cSamw ctx->oc_native_os = session->native_os; 636*3db3f65cSamw ctx->oc_ipaddr = session->ipaddr; 637*3db3f65cSamw ctx->oc_uid = user->u_uid; 638*3db3f65cSamw ctx->oc_logon_time = user->u_logon_time; 639*3db3f65cSamw ctx->oc_flags = user->u_flags; 640*3db3f65cSamw 641*3db3f65cSamw ctx->oc_domain_len = user->u_domain_len; 642*3db3f65cSamw ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len); 643*3db3f65cSamw 644*3db3f65cSamw ctx->oc_account_len = user->u_name_len; 645*3db3f65cSamw ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len); 646*3db3f65cSamw 647*3db3f65cSamw ctx->oc_workstation_len = strlen(session->workstation) + 1; 648*3db3f65cSamw ctx->oc_workstation = smb_kstrdup(session->workstation, 649*3db3f65cSamw ctx->oc_workstation_len); 650*3db3f65cSamw } 651*3db3f65cSamw 652*3db3f65cSamw static void 653*3db3f65cSamw smb_user_context_fini(smb_opipe_context_t *ctx) 654*3db3f65cSamw { 655*3db3f65cSamw if (ctx) { 656*3db3f65cSamw if (ctx->oc_domain) 657*3db3f65cSamw kmem_free(ctx->oc_domain, ctx->oc_domain_len); 658*3db3f65cSamw if (ctx->oc_account) 659*3db3f65cSamw kmem_free(ctx->oc_account, ctx->oc_account_len); 660*3db3f65cSamw if (ctx->oc_workstation) 661*3db3f65cSamw kmem_free(ctx->oc_workstation, ctx->oc_workstation_len); 662*3db3f65cSamw bzero(ctx, sizeof (smb_opipe_context_t)); 663*3db3f65cSamw } 664*3db3f65cSamw } 665*3db3f65cSamw 666*3db3f65cSamw void 667*3db3f65cSamw smb_user_list_free(smb_dr_ulist_t *userlist) 668*3db3f65cSamw { 669*3db3f65cSamw int i; 670*3db3f65cSamw 671*3db3f65cSamw if (userlist) { 672*3db3f65cSamw for (i = 0; i < userlist->dul_cnt; i++) 673*3db3f65cSamw smb_user_context_fini(&userlist->dul_users[i]); 674*3db3f65cSamw } 675*3db3f65cSamw } 676