17052Samw /*
27052Samw * CDDL HEADER START
37052Samw *
47052Samw * The contents of this file are subject to the terms of the
57052Samw * Common Development and Distribution License (the "License").
67052Samw * You may not use this file except in compliance with the License.
77052Samw *
87052Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97052Samw * or http://www.opensolaris.org/os/licensing.
107052Samw * See the License for the specific language governing permissions
117052Samw * and limitations under the License.
127052Samw *
137052Samw * When distributing Covered Code, include this CDDL HEADER in each
147052Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157052Samw * If applicable, add the following below this CDDL HEADER, with the
167052Samw * fields enclosed by brackets "[]" replaced with your own identifying
177052Samw * information: Portions Copyright [yyyy] [name of copyright owner]
187052Samw *
197052Samw * CDDL HEADER END
207052Samw */
217052Samw /*
2212508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
237052Samw */
247052Samw
257052Samw /*
267052Samw * This module provides the interface to NDR RPC.
277052Samw */
287052Samw
297052Samw #include <sys/stat.h>
307052Samw #include <sys/door.h>
317052Samw #include <sys/door_data.h>
327052Samw #include <sys/uio.h>
337052Samw #include <sys/ksynch.h>
3410966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
357052Samw #include <smbsrv/smb_xdr.h>
367052Samw
377052Samw #define SMB_OPIPE_ISOPEN(OPIPE) \
3811963SAfshin.Ardakani@Sun.COM (((OPIPE)->p_hdr.dh_magic == SMB_OPIPE_HDR_MAGIC) && \
3911963SAfshin.Ardakani@Sun.COM ((OPIPE)->p_hdr.dh_fid))
407052Samw
417052Samw extern volatile uint32_t smb_fids;
427052Samw
437052Samw static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *);
4411963SAfshin.Ardakani@Sun.COM static char *smb_opipe_lookup(const char *);
4511963SAfshin.Ardakani@Sun.COM static int smb_opipe_sethdr(smb_opipe_t *, uint32_t, uint32_t);
4611963SAfshin.Ardakani@Sun.COM static int smb_opipe_exec(smb_opipe_t *);
477052Samw static void smb_opipe_enter(smb_opipe_t *);
487052Samw static void smb_opipe_exit(smb_opipe_t *);
497052Samw
507052Samw static door_handle_t smb_opipe_door_hd = NULL;
517052Samw static int smb_opipe_door_id = -1;
527052Samw static uint64_t smb_opipe_door_ncall = 0;
537052Samw static kmutex_t smb_opipe_door_mutex;
547052Samw static kcondvar_t smb_opipe_door_cv;
557052Samw
567052Samw static int smb_opipe_door_call(smb_opipe_t *);
577052Samw static int smb_opipe_door_upcall(smb_opipe_t *);
587052Samw
5911963SAfshin.Ardakani@Sun.COM smb_opipe_t *
smb_opipe_alloc(smb_server_t * sv)6011963SAfshin.Ardakani@Sun.COM smb_opipe_alloc(smb_server_t *sv)
6111963SAfshin.Ardakani@Sun.COM {
6211963SAfshin.Ardakani@Sun.COM smb_opipe_t *opipe;
6311963SAfshin.Ardakani@Sun.COM
6411963SAfshin.Ardakani@Sun.COM opipe = kmem_cache_alloc(sv->si_cache_opipe, KM_SLEEP);
6511963SAfshin.Ardakani@Sun.COM
6611963SAfshin.Ardakani@Sun.COM bzero(opipe, sizeof (smb_opipe_t));
6711963SAfshin.Ardakani@Sun.COM mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
6811963SAfshin.Ardakani@Sun.COM cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
6911963SAfshin.Ardakani@Sun.COM opipe->p_magic = SMB_OPIPE_MAGIC;
7011963SAfshin.Ardakani@Sun.COM opipe->p_server = sv;
7111963SAfshin.Ardakani@Sun.COM
7211963SAfshin.Ardakani@Sun.COM smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
7311963SAfshin.Ardakani@Sun.COM smb_llist_insert_tail(&sv->sv_opipe_list, opipe);
7411963SAfshin.Ardakani@Sun.COM smb_llist_exit(&sv->sv_opipe_list);
7511963SAfshin.Ardakani@Sun.COM
7611963SAfshin.Ardakani@Sun.COM return (opipe);
7711963SAfshin.Ardakani@Sun.COM }
7811963SAfshin.Ardakani@Sun.COM
7911963SAfshin.Ardakani@Sun.COM void
smb_opipe_dealloc(smb_opipe_t * opipe)8011963SAfshin.Ardakani@Sun.COM smb_opipe_dealloc(smb_opipe_t *opipe)
8111963SAfshin.Ardakani@Sun.COM {
8211963SAfshin.Ardakani@Sun.COM smb_server_t *sv;
8311963SAfshin.Ardakani@Sun.COM
8411963SAfshin.Ardakani@Sun.COM SMB_OPIPE_VALID(opipe);
8511963SAfshin.Ardakani@Sun.COM sv = opipe->p_server;
8611963SAfshin.Ardakani@Sun.COM SMB_SERVER_VALID(sv);
8711963SAfshin.Ardakani@Sun.COM
8811963SAfshin.Ardakani@Sun.COM smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
8911963SAfshin.Ardakani@Sun.COM smb_llist_remove(&sv->sv_opipe_list, opipe);
9011963SAfshin.Ardakani@Sun.COM smb_llist_exit(&sv->sv_opipe_list);
9111963SAfshin.Ardakani@Sun.COM
9211963SAfshin.Ardakani@Sun.COM opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC;
9311963SAfshin.Ardakani@Sun.COM smb_event_destroy(opipe->p_event);
9411963SAfshin.Ardakani@Sun.COM cv_destroy(&opipe->p_cv);
9511963SAfshin.Ardakani@Sun.COM mutex_destroy(&opipe->p_mutex);
9611963SAfshin.Ardakani@Sun.COM
9711963SAfshin.Ardakani@Sun.COM kmem_cache_free(sv->si_cache_opipe, opipe);
9811963SAfshin.Ardakani@Sun.COM }
9911963SAfshin.Ardakani@Sun.COM
1007052Samw /*
1017052Samw * smb_opipe_open
1027052Samw *
1037052Samw * Open a well-known RPC named pipe. This routine should be called if
1047052Samw * a file open is requested on a share of type STYPE_IPC.
1057052Samw * If we recognize the pipe, we setup a new ofile.
1067052Samw *
1077052Samw * Returns 0 on success, Otherwise an NT status is returned to indicate
1087052Samw * an error.
1097052Samw */
1107052Samw int
smb_opipe_open(smb_request_t * sr)1117052Samw smb_opipe_open(smb_request_t *sr)
1127052Samw {
11312508Samw@Sun.COM smb_arg_open_t *op = &sr->sr_open;
1147052Samw smb_ofile_t *of;
1157052Samw smb_opipe_t *opipe;
11611963SAfshin.Ardakani@Sun.COM smb_doorhdr_t hdr;
1177052Samw smb_error_t err;
1187052Samw char *pipe_name;
1197052Samw
1209343SAfshin.Ardakani@Sun.COM if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL)
1217052Samw return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
1227052Samw
1237348SJose.Borrego@Sun.COM op->create_options = 0;
1247348SJose.Borrego@Sun.COM
1257348SJose.Borrego@Sun.COM of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op,
1267052Samw SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err);
1279231SAfshin.Ardakani@Sun.COM
1287052Samw if (of == NULL)
1297052Samw return (err.status);
1307052Samw
1319231SAfshin.Ardakani@Sun.COM if (!smb_tree_is_connected(sr->tid_tree)) {
1329231SAfshin.Ardakani@Sun.COM smb_ofile_close(of, 0);
1339231SAfshin.Ardakani@Sun.COM smb_ofile_release(of);
1349231SAfshin.Ardakani@Sun.COM return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
1359231SAfshin.Ardakani@Sun.COM }
1369231SAfshin.Ardakani@Sun.COM
1377052Samw op->dsize = 0x01000;
1387052Samw op->dattr = FILE_ATTRIBUTE_NORMAL;
1397052Samw op->ftype = SMB_FTYPE_MESG_PIPE;
1407052Samw op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
1417052Samw op->devstate = SMB_PIPE_READMODE_MESSAGE
1427052Samw | SMB_PIPE_TYPE_MESSAGE
1437052Samw | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
1447052Samw op->fileid = of->f_fid;
1457052Samw
1467052Samw sr->smb_fid = of->f_fid;
1477052Samw sr->fid_ofile = of;
1487052Samw
1497052Samw opipe = of->f_pipe;
1507052Samw smb_opipe_enter(opipe);
1517052Samw
15211963SAfshin.Ardakani@Sun.COM opipe->p_server = of->f_server;
1537052Samw opipe->p_name = pipe_name;
1547052Samw opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP);
1557052Samw
1567052Samw /*
1577052Samw * p_data points to the offset within p_doorbuf at which
1587052Samw * data will be written or read.
1597052Samw */
16011963SAfshin.Ardakani@Sun.COM opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_doorhdr_xdr, &hdr);
1617052Samw
1627052Samw if (smb_opipe_do_open(sr, opipe) != 0) {
1637052Samw /*
1647052Samw * On error, reset the header to clear the fid,
1657052Samw * which avoids confusion when smb_opipe_close() is
1667052Samw * called by smb_ofile_close().
1677052Samw */
16811963SAfshin.Ardakani@Sun.COM bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
1697052Samw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
1707052Samw smb_opipe_exit(opipe);
1717348SJose.Borrego@Sun.COM smb_ofile_close(of, 0);
1727052Samw return (NT_STATUS_NO_MEMORY);
1737052Samw }
1747052Samw smb_opipe_exit(opipe);
1757052Samw return (NT_STATUS_SUCCESS);
1767052Samw }
1777052Samw
1787052Samw /*
1797052Samw * smb_opipe_lookup
1807052Samw *
1817052Samw * Lookup a path to see if it's a well-known RPC named pipe that we support.
1827052Samw * The full pipe path will be in the form \\PIPE\\SERVICE. The first part
1837052Samw * can be assumed, so all we need here are the service names.
1847052Samw *
18510122SJordan.Brown@Sun.COM * Returns a pointer to the pipe name (without any leading \'s) on success.
1867052Samw * Otherwise returns a null pointer.
1877052Samw */
1887052Samw static char *
smb_opipe_lookup(const char * path)1897052Samw smb_opipe_lookup(const char *path)
1907052Samw {
1917052Samw static char *named_pipes[] = {
19210122SJordan.Brown@Sun.COM "lsass",
1937052Samw "LSARPC",
1947052Samw "NETLOGON",
1957052Samw "SAMR",
1967052Samw "SPOOLSS",
1977052Samw "SRVSVC",
1987052Samw "SVCCTL",
1997052Samw "WINREG",
2007052Samw "WKSSVC",
20111963SAfshin.Ardakani@Sun.COM "EVENTLOG",
20211963SAfshin.Ardakani@Sun.COM "NETDFS"
2037052Samw };
2047052Samw
2057052Samw const char *name;
2067052Samw int i;
2077052Samw
2087052Samw if (path == NULL)
2097052Samw return (NULL);
2107052Samw
2117052Samw name = path;
2127052Samw name += strspn(name, "\\");
21310966SJordan.Brown@Sun.COM if (smb_strcasecmp(name, "PIPE", 4) == 0) {
2147052Samw path += 4;
2157052Samw name += strspn(name, "\\");
2167052Samw }
2177052Samw
2187052Samw for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) {
21910966SJordan.Brown@Sun.COM if (smb_strcasecmp(name, named_pipes[i], 0) == 0)
2207052Samw return (named_pipes[i]);
2217052Samw }
2227052Samw
2237052Samw return (NULL);
2247052Samw }
2257052Samw
2267052Samw /*
2277052Samw * Initialize the opipe header and context, and make the door call.
2287052Samw */
2297052Samw static int
smb_opipe_do_open(smb_request_t * sr,smb_opipe_t * opipe)2307052Samw smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
2317052Samw {
23210122SJordan.Brown@Sun.COM smb_netuserinfo_t *userinfo = &opipe->p_user;
2337052Samw smb_user_t *user = sr->uid_user;
2347052Samw uint8_t *buf = opipe->p_doorbuf;
2357052Samw uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
2367052Samw uint32_t len;
2377052Samw
238*12890SJoyce.McIntosh@Sun.COM if ((opipe->p_event = smb_event_create(SMB_EVENT_TIMEOUT)) == NULL)
23911963SAfshin.Ardakani@Sun.COM return (-1);
24011963SAfshin.Ardakani@Sun.COM
24110122SJordan.Brown@Sun.COM smb_user_netinfo_init(user, userinfo);
24210122SJordan.Brown@Sun.COM len = xdr_sizeof(smb_netuserinfo_xdr, userinfo);
2437052Samw
24411963SAfshin.Ardakani@Sun.COM bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
24511963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_magic = SMB_OPIPE_HDR_MAGIC;
24611963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_flags = SMB_DF_SYSSPACE;
24711963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_fid = smb_event_txid(opipe->p_event);
2487052Samw
24911963SAfshin.Ardakani@Sun.COM if (smb_opipe_sethdr(opipe, SMB_OPIPE_OPEN, len) == -1)
2507052Samw return (-1);
2517052Samw
25211963SAfshin.Ardakani@Sun.COM len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
2537052Samw buf += len;
2547052Samw buflen -= len;
2557052Samw
25610122SJordan.Brown@Sun.COM if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1)
2577052Samw return (-1);
2587052Samw
2597052Samw return (smb_opipe_door_call(opipe));
2607052Samw }
2617052Samw
2627052Samw /*
2637052Samw * smb_opipe_close
2647052Samw *
2657052Samw * Called whenever an IPC file/pipe is closed.
2667052Samw */
2677052Samw void
smb_opipe_close(smb_ofile_t * of)2687052Samw smb_opipe_close(smb_ofile_t *of)
2697052Samw {
2707052Samw smb_opipe_t *opipe;
2717052Samw
2727052Samw ASSERT(of);
2737052Samw ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
2747052Samw
2757052Samw opipe = of->f_pipe;
27611963SAfshin.Ardakani@Sun.COM SMB_OPIPE_VALID(opipe);
27711963SAfshin.Ardakani@Sun.COM
27811963SAfshin.Ardakani@Sun.COM (void) smb_server_cancel_event(opipe->p_hdr.dh_fid);
2797052Samw smb_opipe_enter(opipe);
2807052Samw
2817052Samw if (SMB_OPIPE_ISOPEN(opipe)) {
28211963SAfshin.Ardakani@Sun.COM (void) smb_opipe_sethdr(opipe, SMB_OPIPE_CLOSE, 0);
2837052Samw (void) smb_opipe_door_call(opipe);
28411963SAfshin.Ardakani@Sun.COM bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
2857052Samw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
2867052Samw }
2877052Samw
28810122SJordan.Brown@Sun.COM smb_user_netinfo_fini(&opipe->p_user);
2897052Samw smb_opipe_exit(opipe);
2907052Samw }
2917052Samw
2927052Samw static int
smb_opipe_sethdr(smb_opipe_t * opipe,uint32_t cmd,uint32_t datalen)29311963SAfshin.Ardakani@Sun.COM smb_opipe_sethdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen)
2947052Samw {
29511963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_op = cmd;
29611963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_txid = opipe->p_hdr.dh_fid;
29711963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_datalen = datalen;
29811963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_resid = 0;
29911963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_door_rc = EINVAL;
3007052Samw
30111963SAfshin.Ardakani@Sun.COM return (smb_doorhdr_encode(&opipe->p_hdr, opipe->p_doorbuf,
3027052Samw SMB_OPIPE_DOOR_BUFSIZE));
3037052Samw }
3047052Samw
3057052Samw /*
3067052Samw * smb_opipe_transact
3077052Samw *
3087052Samw * This is the entry point for RPC bind and request transactions.
3097052Samw * The fid is an arbitrary id used to associate RPC requests with a
3107052Samw * particular binding handle.
3117052Samw *
3127052Samw * If the data to be returned is larger than the client expects, we
3137052Samw * return as much as the client can handle and report a buffer overflow
3147052Samw * warning, which informs the client that we have more data to return.
3157052Samw * The residual data remains in the pipe until the client claims it or
3167052Samw * closes the pipe.
3177052Samw */
3187052Samw smb_sdrc_t
smb_opipe_transact(smb_request_t * sr,struct uio * uio)3197052Samw smb_opipe_transact(smb_request_t *sr, struct uio *uio)
3207052Samw {
3217052Samw smb_xa_t *xa;
3227052Samw smb_opipe_t *opipe;
3237052Samw struct mbuf *mhead;
3247052Samw int mdrcnt;
3257052Samw int nbytes;
3267052Samw int rc;
3277052Samw
3287052Samw if ((rc = smb_opipe_write(sr, uio)) != 0) {
3297052Samw if (rc == EBADF)
3307052Samw smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
3317052Samw ERRDOS, ERROR_INVALID_HANDLE);
3327052Samw else
3337052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
3347052Samw ERRDOS, ERROR_INTERNAL_ERROR);
3357052Samw return (SDRC_ERROR);
3367052Samw }
3377052Samw
33811963SAfshin.Ardakani@Sun.COM opipe = sr->fid_ofile->f_pipe;
33911963SAfshin.Ardakani@Sun.COM
34011963SAfshin.Ardakani@Sun.COM if ((rc = smb_opipe_exec(opipe)) != 0) {
34111963SAfshin.Ardakani@Sun.COM smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
34211963SAfshin.Ardakani@Sun.COM ERRDOS, ERROR_INTERNAL_ERROR);
34311963SAfshin.Ardakani@Sun.COM return (SDRC_ERROR);
34411963SAfshin.Ardakani@Sun.COM }
34511963SAfshin.Ardakani@Sun.COM
3467052Samw xa = sr->r_xa;
3477052Samw mdrcnt = xa->smb_mdrcnt;
3487052Samw smb_opipe_enter(opipe);
3497052Samw
35011963SAfshin.Ardakani@Sun.COM if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) {
3517052Samw smb_opipe_exit(opipe);
3527052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
3537052Samw ERRDOS, ERROR_INTERNAL_ERROR);
3547052Samw return (SDRC_ERROR);
3557052Samw }
3567052Samw
3577052Samw rc = smb_opipe_door_call(opipe);
35811963SAfshin.Ardakani@Sun.COM nbytes = opipe->p_hdr.dh_datalen;
3597052Samw
3607052Samw if (rc != 0) {
3617052Samw smb_opipe_exit(opipe);
3627052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
3637052Samw ERRDOS, ERROR_INTERNAL_ERROR);
3647052Samw return (SDRC_ERROR);
3657052Samw }
3667052Samw
3677052Samw if (nbytes) {
3687052Samw mhead = smb_mbuf_get(opipe->p_data, nbytes);
3697052Samw xa->rep_data_mb.max_bytes = nbytes;
3707052Samw MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
3717052Samw }
3727052Samw
37311963SAfshin.Ardakani@Sun.COM if (opipe->p_hdr.dh_resid) {
3747052Samw /*
3757052Samw * The pipe contains more data than mdrcnt, warn the
3767052Samw * client that there is more data in the pipe.
3777052Samw * Typically, the client will call SmbReadX, which
3787052Samw * will call smb_opipe_read, to get the data.
3797052Samw */
3807052Samw smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
3817052Samw ERRDOS, ERROR_MORE_DATA);
3827052Samw }
3837052Samw
3847052Samw smb_opipe_exit(opipe);
3857052Samw return (SDRC_SUCCESS);
3867052Samw }
3877052Samw
3887052Samw /*
3897052Samw * smb_opipe_write
3907052Samw *
3917052Samw * Write RPC request data to the pipe. The client should call smb_opipe_read
3927052Samw * to complete the exchange and obtain the RPC response.
3937052Samw *
3947052Samw * Returns 0 on success or an errno on failure.
3957052Samw */
3967052Samw int
smb_opipe_write(smb_request_t * sr,struct uio * uio)3977052Samw smb_opipe_write(smb_request_t *sr, struct uio *uio)
3987052Samw {
3997052Samw smb_opipe_t *opipe;
4007052Samw uint32_t buflen;
4017052Samw uint32_t len;
4027052Samw int rc;
4037052Samw
4047052Samw ASSERT(sr->fid_ofile);
4057052Samw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
4067052Samw
4077052Samw opipe = sr->fid_ofile->f_pipe;
40811963SAfshin.Ardakani@Sun.COM SMB_OPIPE_VALID(opipe);
4097052Samw smb_opipe_enter(opipe);
4107052Samw
4117052Samw if (!SMB_OPIPE_ISOPEN(opipe)) {
4127052Samw smb_opipe_exit(opipe);
4137052Samw return (EBADF);
4147052Samw }
4157052Samw
41611963SAfshin.Ardakani@Sun.COM rc = smb_opipe_sethdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid);
41711963SAfshin.Ardakani@Sun.COM len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
4187052Samw if (rc == -1 || len == 0) {
4197052Samw smb_opipe_exit(opipe);
4207052Samw return (ENOMEM);
4217052Samw }
4227052Samw
4237052Samw buflen = SMB_OPIPE_DOOR_BUFSIZE - len;
4247052Samw (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio);
4257052Samw
4267052Samw rc = smb_opipe_door_call(opipe);
4277052Samw
4287052Samw smb_opipe_exit(opipe);
4297052Samw return ((rc == 0) ? 0 : EIO);
4307052Samw }
4317052Samw
4327052Samw /*
4337052Samw * smb_opipe_read
4347052Samw *
4357052Samw * This interface may be called because smb_opipe_transact could not return
4367052Samw * all of the data in the original transaction or to form the second half
4377052Samw * of a transaction set up using smb_opipe_write. Either way, we just need
4387052Samw * to read data from the pipe and return it.
4397052Samw *
4407052Samw * The response data is encoded into raw_data as required by the smb_read
4417052Samw * functions. The uio_resid value indicates the number of bytes read.
4427052Samw */
4437052Samw int
smb_opipe_read(smb_request_t * sr,struct uio * uio)4447052Samw smb_opipe_read(smb_request_t *sr, struct uio *uio)
4457052Samw {
4467052Samw smb_opipe_t *opipe;
4477052Samw struct mbuf *mhead;
4487052Samw uint32_t nbytes;
4497052Samw int rc;
4507052Samw
4517052Samw ASSERT(sr->fid_ofile);
4527052Samw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
4537052Samw
4547052Samw opipe = sr->fid_ofile->f_pipe;
45511963SAfshin.Ardakani@Sun.COM SMB_OPIPE_VALID(opipe);
45611963SAfshin.Ardakani@Sun.COM
45711963SAfshin.Ardakani@Sun.COM if ((rc = smb_opipe_exec(opipe)) != 0)
45811963SAfshin.Ardakani@Sun.COM return (EIO);
45911963SAfshin.Ardakani@Sun.COM
4607052Samw smb_opipe_enter(opipe);
4617052Samw
4627052Samw if (!SMB_OPIPE_ISOPEN(opipe)) {
4637052Samw smb_opipe_exit(opipe);
4647052Samw return (EBADF);
4657052Samw }
4667052Samw
46711963SAfshin.Ardakani@Sun.COM if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) {
4687052Samw smb_opipe_exit(opipe);
4697052Samw return (ENOMEM);
4707052Samw }
4717052Samw
4727052Samw rc = smb_opipe_door_call(opipe);
47311963SAfshin.Ardakani@Sun.COM nbytes = opipe->p_hdr.dh_datalen;
4747052Samw
4757052Samw if (rc != 0 || nbytes > uio->uio_resid) {
4767052Samw smb_opipe_exit(opipe);
4777052Samw return (EIO);
4787052Samw }
4797052Samw
4807052Samw if (nbytes) {
4817052Samw mhead = smb_mbuf_get(opipe->p_data, nbytes);
4827052Samw MBC_SETUP(&sr->raw_data, nbytes);
4837052Samw MBC_ATTACH_MBUF(&sr->raw_data, mhead);
4847052Samw uio->uio_resid -= nbytes;
4857052Samw }
4867052Samw
4877052Samw smb_opipe_exit(opipe);
4887052Samw return (rc);
4897052Samw }
4907052Samw
49111963SAfshin.Ardakani@Sun.COM static int
smb_opipe_exec(smb_opipe_t * opipe)49211963SAfshin.Ardakani@Sun.COM smb_opipe_exec(smb_opipe_t *opipe)
49311963SAfshin.Ardakani@Sun.COM {
49411963SAfshin.Ardakani@Sun.COM uint32_t len;
49511963SAfshin.Ardakani@Sun.COM int rc;
49611963SAfshin.Ardakani@Sun.COM
49711963SAfshin.Ardakani@Sun.COM smb_opipe_enter(opipe);
49811963SAfshin.Ardakani@Sun.COM
49911963SAfshin.Ardakani@Sun.COM rc = smb_opipe_sethdr(opipe, SMB_OPIPE_EXEC, 0);
50011963SAfshin.Ardakani@Sun.COM len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
50111963SAfshin.Ardakani@Sun.COM if (rc == -1 || len == 0) {
50211963SAfshin.Ardakani@Sun.COM smb_opipe_exit(opipe);
50311963SAfshin.Ardakani@Sun.COM return (ENOMEM);
50411963SAfshin.Ardakani@Sun.COM }
50511963SAfshin.Ardakani@Sun.COM
50611963SAfshin.Ardakani@Sun.COM if ((rc = smb_opipe_door_call(opipe)) == 0)
50711963SAfshin.Ardakani@Sun.COM rc = smb_event_wait(opipe->p_event);
50811963SAfshin.Ardakani@Sun.COM
50911963SAfshin.Ardakani@Sun.COM smb_opipe_exit(opipe);
51011963SAfshin.Ardakani@Sun.COM return (rc);
51111963SAfshin.Ardakani@Sun.COM }
51211963SAfshin.Ardakani@Sun.COM
5137052Samw /*
5147052Samw * Named pipe I/O is serialized per fid to ensure that each request
5157052Samw * has exclusive opipe access for the duration of the request.
5167052Samw */
5177052Samw static void
smb_opipe_enter(smb_opipe_t * opipe)5187052Samw smb_opipe_enter(smb_opipe_t *opipe)
5197052Samw {
5207052Samw mutex_enter(&opipe->p_mutex);
5217052Samw
5227052Samw while (opipe->p_busy)
5237052Samw cv_wait(&opipe->p_cv, &opipe->p_mutex);
5247052Samw
5257052Samw opipe->p_busy = 1;
5267052Samw mutex_exit(&opipe->p_mutex);
5277052Samw }
5287052Samw
52911963SAfshin.Ardakani@Sun.COM /*
53011963SAfshin.Ardakani@Sun.COM * Exit busy state. If we have exec'd an RPC, we may have
53111963SAfshin.Ardakani@Sun.COM * to wait for notification that processing has completed.
53211963SAfshin.Ardakani@Sun.COM */
5337052Samw static void
smb_opipe_exit(smb_opipe_t * opipe)5347052Samw smb_opipe_exit(smb_opipe_t *opipe)
5357052Samw {
5367052Samw mutex_enter(&opipe->p_mutex);
5377052Samw opipe->p_busy = 0;
5387052Samw cv_signal(&opipe->p_cv);
5397052Samw mutex_exit(&opipe->p_mutex);
5407052Samw }
5417052Samw
5427052Samw /*
5437052Samw * opipe door client (to user space door server).
5447052Samw */
5457052Samw void
smb_opipe_door_init(void)5467052Samw smb_opipe_door_init(void)
5477052Samw {
5487052Samw mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
5497052Samw cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL);
5507052Samw }
5517052Samw
5527052Samw void
smb_opipe_door_fini(void)5537052Samw smb_opipe_door_fini(void)
5547052Samw {
5557052Samw smb_opipe_door_close();
5567052Samw cv_destroy(&smb_opipe_door_cv);
5577052Samw mutex_destroy(&smb_opipe_door_mutex);
5587052Samw }
5597052Samw
5607052Samw /*
5617052Samw * Open the (user space) door. If the door is already open,
5627052Samw * close it first because the door-id has probably changed.
5637052Samw */
5647052Samw int
smb_opipe_door_open(int door_id)5657052Samw smb_opipe_door_open(int door_id)
5667052Samw {
5677052Samw smb_opipe_door_close();
5687052Samw
5697052Samw mutex_enter(&smb_opipe_door_mutex);
5707052Samw smb_opipe_door_ncall = 0;
5717052Samw
5727052Samw if (smb_opipe_door_hd == NULL) {
5737052Samw smb_opipe_door_id = door_id;
5747052Samw smb_opipe_door_hd = door_ki_lookup(door_id);
5757052Samw }
5767052Samw
5777052Samw mutex_exit(&smb_opipe_door_mutex);
5787052Samw return ((smb_opipe_door_hd == NULL) ? -1 : 0);
5797052Samw }
5807052Samw
5817052Samw /*
5827052Samw * Close the (user space) door.
5837052Samw */
5847052Samw void
smb_opipe_door_close(void)5857052Samw smb_opipe_door_close(void)
5867052Samw {
5877052Samw mutex_enter(&smb_opipe_door_mutex);
5887052Samw
5897052Samw if (smb_opipe_door_hd != NULL) {
5907052Samw while (smb_opipe_door_ncall > 0)
5917052Samw cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex);
5927052Samw
5937052Samw door_ki_rele(smb_opipe_door_hd);
5947052Samw smb_opipe_door_hd = NULL;
5957052Samw }
5967052Samw
5977052Samw mutex_exit(&smb_opipe_door_mutex);
5987052Samw }
5997052Samw
6007052Samw /*
6017052Samw * opipe door call interface.
6027052Samw * Door serialization and call reference accounting is handled here.
6037052Samw */
6047052Samw static int
smb_opipe_door_call(smb_opipe_t * opipe)6057052Samw smb_opipe_door_call(smb_opipe_t *opipe)
6067052Samw {
6077052Samw int rc;
6087052Samw
6097052Samw mutex_enter(&smb_opipe_door_mutex);
6107052Samw
6117052Samw if (smb_opipe_door_hd == NULL) {
6127052Samw mutex_exit(&smb_opipe_door_mutex);
6137052Samw
6147052Samw if (smb_opipe_door_open(smb_opipe_door_id) != 0)
6157052Samw return (-1);
6167052Samw
6177052Samw mutex_enter(&smb_opipe_door_mutex);
6187052Samw }
6197052Samw
6207052Samw ++smb_opipe_door_ncall;
6217052Samw mutex_exit(&smb_opipe_door_mutex);
6227052Samw
6237052Samw rc = smb_opipe_door_upcall(opipe);
6247052Samw
6257052Samw mutex_enter(&smb_opipe_door_mutex);
62611963SAfshin.Ardakani@Sun.COM if ((--smb_opipe_door_ncall) == 0)
62711963SAfshin.Ardakani@Sun.COM cv_signal(&smb_opipe_door_cv);
6287052Samw mutex_exit(&smb_opipe_door_mutex);
6297052Samw return (rc);
6307052Samw }
6317052Samw
6327052Samw /*
6337052Samw * Door upcall wrapper - handles data marshalling.
6347052Samw * This function should only be called by smb_opipe_door_call.
6357052Samw */
6367052Samw static int
smb_opipe_door_upcall(smb_opipe_t * opipe)6377052Samw smb_opipe_door_upcall(smb_opipe_t *opipe)
6387052Samw {
6397052Samw door_arg_t da;
64011963SAfshin.Ardakani@Sun.COM smb_doorhdr_t hdr;
6417052Samw int i;
6427052Samw int rc;
6437052Samw
6447052Samw da.data_ptr = (char *)opipe->p_doorbuf;
6457052Samw da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
6467052Samw da.desc_ptr = NULL;
6477052Samw da.desc_num = 0;
6487052Samw da.rbuf = (char *)opipe->p_doorbuf;
6497052Samw da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
6507052Samw
6517052Samw for (i = 0; i < 3; ++i) {
65211963SAfshin.Ardakani@Sun.COM if (smb_server_is_stopping())
65311963SAfshin.Ardakani@Sun.COM return (-1);
65411963SAfshin.Ardakani@Sun.COM
6557052Samw if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da,
6567052Samw NULL, SIZE_MAX, 0)) == 0)
6577052Samw break;
6587052Samw
6597052Samw if (rc != EAGAIN && rc != EINTR)
6607052Samw return (-1);
6617052Samw }
6627052Samw
66311963SAfshin.Ardakani@Sun.COM /* Check for door_return(NULL, 0, NULL, 0) */
66411963SAfshin.Ardakani@Sun.COM if (rc != 0 || da.data_size == 0 || da.rsize == 0)
6657052Samw return (-1);
6667052Samw
66711963SAfshin.Ardakani@Sun.COM if (smb_doorhdr_decode(&hdr, (uint8_t *)da.data_ptr, da.rsize) == -1)
66811963SAfshin.Ardakani@Sun.COM return (-1);
66911963SAfshin.Ardakani@Sun.COM
67011963SAfshin.Ardakani@Sun.COM if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) ||
67111963SAfshin.Ardakani@Sun.COM (hdr.dh_fid != opipe->p_hdr.dh_fid) ||
67211963SAfshin.Ardakani@Sun.COM (hdr.dh_op != opipe->p_hdr.dh_op) ||
67311963SAfshin.Ardakani@Sun.COM (hdr.dh_door_rc != 0) ||
67411963SAfshin.Ardakani@Sun.COM (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
6757052Samw return (-1);
6767052Samw }
6777052Samw
67811963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_datalen = hdr.dh_datalen;
67911963SAfshin.Ardakani@Sun.COM opipe->p_hdr.dh_resid = hdr.dh_resid;
6807052Samw return (0);
6817052Samw }
682