summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2013-09-08 19:24:51 -0400
committerGordon Ross <gwr@nexenta.com>2015-06-13 13:27:15 -0400
commit68b2bbf26c7040fea4281dcb58b81e7627e46f34 (patch)
tree7f3a857b4f2d553f8ea52bebb9ae8b7cada1fb37
parent5a48565528ab0659af6d43ebe1659bfff8074e8f (diff)
downloadillumos-joyent-68b2bbf26c7040fea4281dcb58b81e7627e46f34.tar.gz
5995 RPC over SMB named pipes should use AF_UNIX sockets
Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com> Reviewed by: Thomas Keiser <thomas.keiser@nexenta.com> Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com> Approved by: Robert Mustacchi <rm@joyent.com>
-rw-r--r--usr/src/cmd/smbsrv/fksmbd/Makefile3
-rw-r--r--usr/src/cmd/smbsrv/fksmbd/Watch-pipesvc.d62
-rw-r--r--usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c2
-rw-r--r--usr/src/cmd/smbsrv/fksmbd/fksmbd_opipe.c156
-rw-r--r--usr/src/cmd/smbsrv/smbd/Makefile2
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd.h5
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_main.c12
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_opipe_doorsvc.c210
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_pipesvc.c394
-rw-r--r--usr/src/lib/libfakekernel/common/ksocket.c23
-rw-r--r--usr/src/lib/libfakekernel/common/mapfile-vers3
-rw-r--r--usr/src/lib/smbsrv/libfksmbsrv/Makefile.com1
-rw-r--r--usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_opipe_door.c131
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h34
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers7
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c47
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c758
-rw-r--r--usr/src/lib/smbsrv/libmlrpc/common/ndr_svc.c8
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c3
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c6
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c3
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c24
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_transact.c94
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c193
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe.c629
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe_door.c188
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_read.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_server.c12
-rw-r--r--usr/src/uts/common/smbsrv/ndr.h15
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h6
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h41
-rw-r--r--usr/src/uts/common/smbsrv/smb_share.h3
-rw-r--r--usr/src/uts/common/smbsrv/smb_xdr.h32
35 files changed, 1205 insertions, 1913 deletions
diff --git a/usr/src/cmd/smbsrv/fksmbd/Makefile b/usr/src/cmd/smbsrv/fksmbd/Makefile
index cb72f8239e..615818e44a 100644
--- a/usr/src/cmd/smbsrv/fksmbd/Makefile
+++ b/usr/src/cmd/smbsrv/fksmbd/Makefile
@@ -31,7 +31,7 @@ OBJS_SMBD= \
smbd_logon.o \
smbd_main.o \
smbd_nicmon.o \
- smbd_opipe_doorsvc.o \
+ smbd_pipesvc.o \
smbd_share_doorsvc.o \
smbd_spool.o \
smbd_vss.o \
@@ -41,7 +41,6 @@ OBJS_LOCAL = \
fksmbd_door.o \
fksmbd_kmod.o \
fksmbd_ksock.o \
- fksmbd_opipe.o \
fksmbd_log.o \
fksmbd_shr.o
diff --git a/usr/src/cmd/smbsrv/fksmbd/Watch-pipesvc.d b/usr/src/cmd/smbsrv/fksmbd/Watch-pipesvc.d
new file mode 100644
index 0000000000..f11156001d
--- /dev/null
+++ b/usr/src/cmd/smbsrv/fksmbd/Watch-pipesvc.d
@@ -0,0 +1,62 @@
+#!/usr/sbin/dtrace -s
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * User-level dtrace for smbd
+ * Usage: dtrace -s ThisScript.d -p PID
+ */
+
+#pragma D option flowindent
+
+pid$target:fksmbd:pipesvc_worker:entry
+{
+ self->trace++;
+}
+pid$target:fksmbd:pipesvc_worker:return
+{
+ self->trace--;
+}
+
+pid$target:fksmbd::entry,
+pid$target:libfksmbsrv.so.1::entry,
+pid$target:libmlsvc.so.1::entry,
+pid$target:libmlrpc.so.1::entry,
+pid$target:libsmbns.so.1::entry,
+pid$target:libsmb.so.1::entry
+/self->trace/
+{
+ printf("\t0x%x", arg0);
+ printf("\t0x%x", arg1);
+ printf("\t0x%x", arg2);
+ printf("\t0x%x", arg3);
+}
+
+pid$target:fksmbd::return,
+pid$target:libfksmbsrv.so.1::return,
+pid$target:libmlsvc.so.1::return,
+pid$target:libmlrpc.so.1::return,
+pid$target:libsmbns.so.1::return,
+pid$target:libsmb.so.1::return
+/self->trace/
+{
+ printf("\t0x%x", arg1);
+}
+
+pid$target:libmlrpc.so.1:ndo_trace:entry
+/self->trace/
+{
+ printf("ndo_trace: %s", copyinstr(arg0));
+}
diff --git a/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c b/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c
index 067639453b..65fc7cecbb 100644
--- a/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c
+++ b/usr/src/cmd/smbsrv/fksmbd/fksmbd_kmod.c
@@ -134,7 +134,7 @@ smb_kmod_start(int opipe, int lmshr, int udoor)
/* These are the "door" dispatch callbacks */
ioc.lmshr_func = NULL; /* not used */
- ioc.opipe_func = (void *)fksmbd_opipe_dispatch;
+ ioc.opipe_func = NULL; /* not used */
ioc.udoor_func = (void *)fksmbd_door_dispatch;
rc = smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc));
diff --git a/usr/src/cmd/smbsrv/fksmbd/fksmbd_opipe.c b/usr/src/cmd/smbsrv/fksmbd/fksmbd_opipe.c
deleted file mode 100644
index 7fd8df64d3..0000000000
--- a/usr/src/cmd/smbsrv/fksmbd/fksmbd_opipe.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include <sys/list.h>
-#include <assert.h>
-#include <alloca.h>
-#include <door.h>
-#include <errno.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <synch.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <strings.h>
-#include <umem.h>
-
-#include <smbsrv/smb_door.h>
-#include <smbsrv/smb_xdr.h>
-#include <smbsrv/smb_token.h>
-#include <smbsrv/libmlsvc.h>
-#include <smbsrv/libsmbns.h>
-#include "smbd.h"
-
-static int smbd_opipe_exec(uint32_t fid);
-
-
-/*
- * Process smbd opipe requests.
- *
- * This is a special version of smb_opipe_dispatch()
- * for the "fake" smbsrv (running in user space).
- * This is called via function pointer from
- * smbsrv: smb_opipe_door_call()
- *
- * Very similar to smbd_opipe_dispatch()
- */
-int
-fksmbd_opipe_dispatch(door_arg_t *da)
-{
- uint8_t *buf = (uint8_t *)da->data_ptr;
- smb_doorhdr_t hdr;
- size_t hdr_size;
- uint8_t *data;
- uint32_t datalen;
-
- if (!smbd_online())
- return (-1);
-
- bzero(&hdr, sizeof (smb_doorhdr_t));
- hdr_size = xdr_sizeof(smb_doorhdr_xdr, &hdr);
-
- if (da->data_ptr == NULL || da->data_size < hdr_size)
- return (-1);
-
- if (smb_doorhdr_decode(&hdr, buf, hdr_size) == -1)
- return (-1);
-
- if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) || (hdr.dh_fid == 0))
- return (-1);
-
- if (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)
- hdr.dh_datalen = SMB_OPIPE_DOOR_BUFSIZE;
-
- data = buf + hdr_size;
- datalen = hdr.dh_datalen;
-
- switch (hdr.dh_op) {
- case SMB_OPIPE_OPEN:
- hdr.dh_door_rc = ndr_pipe_open(hdr.dh_fid, data, datalen);
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- case SMB_OPIPE_CLOSE:
- hdr.dh_door_rc = ndr_pipe_close(hdr.dh_fid);
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- case SMB_OPIPE_READ:
- data = (uint8_t *)buf + hdr_size;
- datalen = hdr.dh_datalen;
- hdr.dh_door_rc = ndr_pipe_read(hdr.dh_fid, data, &datalen,
- &hdr.dh_resid);
- hdr.dh_datalen = datalen;
- datalen += hdr_size;
- break;
-
- case SMB_OPIPE_WRITE:
- hdr.dh_door_rc = ndr_pipe_write(hdr.dh_fid, data, datalen);
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- case SMB_OPIPE_EXEC:
- hdr.dh_door_rc = smbd_opipe_exec(hdr.dh_fid);
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- default:
- return (-1);
- }
-
- (void) smb_doorhdr_encode(&hdr, (uint8_t *)buf, hdr_size);
- return (0);
-}
-
-/*
- * Normal (from a real kernel) up calls get a thread here.
- * In the "fake" kernel (all user space) we don't need that.
- * NB: arg will be freed by ndr_pipe_transact()
- */
-static int
-smbd_opipe_exec(uint32_t fid)
-{
- uint32_t *arg;
-
- if ((arg = malloc(sizeof (uint32_t))) == NULL)
- return (ENOMEM);
-
- *arg = fid;
-
- (void) ndr_pipe_transact(arg);
-
- return (0);
-}
diff --git a/usr/src/cmd/smbsrv/smbd/Makefile b/usr/src/cmd/smbsrv/smbd/Makefile
index 2927c33ca1..8fd9ccb74a 100644
--- a/usr/src/cmd/smbsrv/smbd/Makefile
+++ b/usr/src/cmd/smbsrv/smbd/Makefile
@@ -31,7 +31,7 @@ OBJS= \
smbd_logon.o \
smbd_main.o \
smbd_nicmon.o \
- smbd_opipe_doorsvc.o \
+ smbd_pipesvc.o \
smbd_share_doorsvc.o \
smbd_spool.o \
smbd_syslog.o \
diff --git a/usr/src/cmd/smbsrv/smbd/smbd.h b/usr/src/cmd/smbsrv/smbd/smbd.h
index 750a662e9e..3ec5877fac 100644
--- a/usr/src/cmd/smbsrv/smbd/smbd.h
+++ b/usr/src/cmd/smbsrv/smbd/smbd.h
@@ -40,8 +40,8 @@ extern "C" {
#include <smbsrv/libmlsvc.h>
void smbd_report(const char *fmt, ...);
-int smbd_opipe_start(void);
-void smbd_opipe_stop(void);
+int smbd_pipesvc_start(void);
+void smbd_pipesvc_stop(void);
int smbd_share_start(void);
void smbd_share_stop(void);
int smbd_nicmon_start(const char *);
@@ -143,7 +143,6 @@ void *smbd_door_dispatch_op(void *);
/* For fksmbd */
void fksmbd_init(void);
int fksmbd_door_dispatch(smb_doorarg_t *);
-int fksmbd_opipe_dispatch(door_arg_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_main.c b/usr/src/cmd/smbsrv/smbd/smbd_main.c
index a0a8793aba..59b11eb702 100644
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c
@@ -431,7 +431,8 @@ smbd_service_init(void)
{ SMB_CVOL, 0755 },
{ SMB_SYSROOT, 0755 },
{ SMB_SYSTEM32, 0755 },
- { SMB_VSS, 0755 }
+ { SMB_VSS, 0755 },
+ { SMB_PIPE_DIR, 0755 },
};
int rc, i;
@@ -497,14 +498,13 @@ smbd_service_init(void)
smbd_report("DC monitor initialization failed %s",
strerror(errno));
- if (mlsvc_init() != 0) {
- smbd_report("msrpc initialization failed");
+ if (smbd_pipesvc_start() != 0) {
+ smbd_report("pipesvc initialization failed");
return (-1);
}
smbd.s_door_srv = smbd_door_start();
- smbd.s_door_opipe = smbd_opipe_start();
- if (smbd.s_door_srv < 0 || smbd.s_door_opipe < 0) {
+ if (smbd.s_door_srv < 0) {
smbd_report("door initialization failed %s", strerror(errno));
return (-1);
}
@@ -553,7 +553,7 @@ smbd_service_fini(void)
smb_kmod_stop();
smb_logon_abort();
smb_lgrp_stop();
- smbd_opipe_stop();
+ smbd_pipesvc_stop();
smbd_door_stop();
smbd_spool_stop();
smbd_kernel_unbind();
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_opipe_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_opipe_doorsvc.c
deleted file mode 100644
index c092e1b395..0000000000
--- a/usr/src/cmd/smbsrv/smbd/smbd_opipe_doorsvc.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <stdio.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <door.h>
-#include <errno.h>
-#include <pthread.h>
-
-#include <smbsrv/libsmb.h>
-#include <smbsrv/libmlrpc.h>
-#include "smbd.h"
-
-static int smbd_opipe_fd = -1;
-static int smbd_opipe_cookie = 0x50495045; /* PIPE */
-static pthread_mutex_t smbd_opipe_mutex = PTHREAD_MUTEX_INITIALIZER;
-static smbd_door_t smbd_opipe_sdh;
-
-static void smbd_opipe_dispatch(void *, char *, size_t, door_desc_t *, uint_t);
-static int smbd_opipe_exec_async(uint32_t);
-
-/*
- * Create the smbd opipe door service.
- * Returns the door descriptor on success. Otherwise returns -1.
- */
-int
-smbd_opipe_start(void)
-{
- (void) pthread_mutex_lock(&smbd_opipe_mutex);
-
- if (smbd_opipe_fd != -1) {
- (void) pthread_mutex_unlock(&smbd_opipe_mutex);
- errno = EEXIST;
- return (-1);
- }
-
- smbd_door_init(&smbd_opipe_sdh, "opipe");
-
- errno = 0;
- if ((smbd_opipe_fd = door_create(smbd_opipe_dispatch,
- &smbd_opipe_cookie, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) {
- smbd_opipe_fd = -1;
- }
-
- (void) pthread_mutex_unlock(&smbd_opipe_mutex);
- return (smbd_opipe_fd);
-}
-
-/*
- * Stop the smbd opipe door service.
- */
-void
-smbd_opipe_stop(void)
-{
- (void) pthread_mutex_lock(&smbd_opipe_mutex);
-
- smbd_door_fini(&smbd_opipe_sdh);
-
- if (smbd_opipe_fd != -1) {
- (void) door_revoke(smbd_opipe_fd);
- smbd_opipe_fd = -1;
- }
-
- (void) pthread_mutex_unlock(&smbd_opipe_mutex);
-}
-
-/*
- * Process smbd opipe requests.
- */
-/*ARGSUSED*/
-static void
-smbd_opipe_dispatch(void *cookie, char *argp, size_t arg_size,
- door_desc_t *dd, uint_t n_desc)
-{
- char buf[SMB_OPIPE_DOOR_BUFSIZE];
- smb_doorhdr_t hdr;
- size_t hdr_size;
- uint8_t *data;
- uint32_t datalen;
-
- smbd_door_enter(&smbd_opipe_sdh);
-
- if (!smbd_online())
- smbd_door_return(&smbd_opipe_sdh, NULL, 0, NULL, 0);
-
- bzero(&hdr, sizeof (smb_doorhdr_t));
- hdr_size = xdr_sizeof(smb_doorhdr_xdr, &hdr);
-
- if ((cookie != &smbd_opipe_cookie) || (argp == NULL) ||
- (arg_size < hdr_size)) {
- smbd_door_return(&smbd_opipe_sdh, NULL, 0, NULL, 0);
- }
-
- if (smb_doorhdr_decode(&hdr, (uint8_t *)argp, hdr_size) == -1)
- smbd_door_return(&smbd_opipe_sdh, NULL, 0, NULL, 0);
-
- if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) || (hdr.dh_fid == 0))
- smbd_door_return(&smbd_opipe_sdh, NULL, 0, NULL, 0);
-
- if (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)
- hdr.dh_datalen = SMB_OPIPE_DOOR_BUFSIZE;
-
- data = (uint8_t *)argp + hdr_size;
- datalen = hdr.dh_datalen;
-
- switch (hdr.dh_op) {
- case SMB_OPIPE_OPEN:
- hdr.dh_door_rc = ndr_pipe_open(hdr.dh_fid, data, datalen);
-
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- case SMB_OPIPE_CLOSE:
- hdr.dh_door_rc = ndr_pipe_close(hdr.dh_fid);
-
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- case SMB_OPIPE_READ:
- data = (uint8_t *)buf + hdr_size;
- datalen = hdr.dh_datalen;
-
- hdr.dh_door_rc = ndr_pipe_read(hdr.dh_fid, data, &datalen,
- &hdr.dh_resid);
-
- hdr.dh_datalen = datalen;
- datalen += hdr_size;
- break;
-
- case SMB_OPIPE_WRITE:
- hdr.dh_door_rc = ndr_pipe_write(hdr.dh_fid, data, datalen);
-
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- case SMB_OPIPE_EXEC:
- hdr.dh_door_rc = smbd_opipe_exec_async(hdr.dh_fid);
-
- hdr.dh_datalen = 0;
- hdr.dh_resid = 0;
- datalen = hdr_size;
- break;
-
- default:
- smbd_door_return(&smbd_opipe_sdh, NULL, 0, NULL, 0);
- break;
- }
-
- (void) smb_doorhdr_encode(&hdr, (uint8_t *)buf, hdr_size);
- smbd_door_return(&smbd_opipe_sdh, buf, datalen, NULL, 0);
-}
-
-/*
- * On success, arg will be freed by the thread.
- */
-static int
-smbd_opipe_exec_async(uint32_t fid)
-{
- pthread_attr_t attr;
- pthread_t tid;
- uint32_t *arg;
- int rc;
-
- if ((arg = malloc(sizeof (uint32_t))) == NULL)
- return (ENOMEM);
-
- *arg = fid;
-
- (void) pthread_attr_init(&attr);
- (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- rc = pthread_create(&tid, &attr, ndr_pipe_transact, arg);
- (void) pthread_attr_destroy(&attr);
-
- if (rc != 0)
- free(arg);
- return (rc);
-}
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_pipesvc.c b/usr/src/cmd/smbsrv/smbd/smbd_pipesvc.c
new file mode 100644
index 0000000000..c6e6682b8e
--- /dev/null
+++ b/usr/src/cmd/smbsrv/smbd/smbd_pipesvc.c
@@ -0,0 +1,394 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * This is the named pipe service for smbd.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <synch.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <door.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/smb_xdr.h>
+#include "smbd.h"
+
+struct pipe_listener {
+ const char *name;
+ int max_allowed;
+ int max_seen;
+ int current;
+ pthread_t tid;
+};
+
+static void *pipesvc_listener(void *);
+static void *pipesvc_worker(void *);
+static int pipe_send(ndr_pipe_t *, void *, size_t);
+static int pipe_recv(ndr_pipe_t *, void *, size_t);
+
+mutex_t pipesvc_mutex = DEFAULTMUTEX;
+int pipesvc_workers_max = 500;
+int pipesvc_workers_cur = 0;
+
+uint16_t pipe_max_msgsize = SMB_PIPE_MAX_MSGSIZE;
+
+/*
+ * Allow more opens on SRVSVC because that's used by many clients
+ * to get the share list, etc.
+ */
+#define SRVSVC_MAX_OPENS 200
+#define DEF_MAX_OPENS 50
+
+#define NLISTENERS 11
+static struct pipe_listener
+pipe_listeners[NLISTENERS] = {
+ { "eventlog", DEF_MAX_OPENS, 0, 0 },
+ { "lsarpc", DEF_MAX_OPENS, 0, 0 },
+ { "lsass", DEF_MAX_OPENS, 0, 0 },
+ { "netdfs", DEF_MAX_OPENS, 0, 0 },
+ { "netlogon", DEF_MAX_OPENS, 0, 0 },
+ { "samr", DEF_MAX_OPENS, 0, 0 },
+ { "spoolss", DEF_MAX_OPENS, 0, 0 },
+ { "srvsvc", SRVSVC_MAX_OPENS, 0, 0 },
+ { "svcctl", DEF_MAX_OPENS, 0, 0 },
+ { "winreg", DEF_MAX_OPENS, 0, 0 },
+ { "wkssvc", DEF_MAX_OPENS, 0, 0 },
+};
+
+static ndr_pipe_t *
+np_new(struct pipe_listener *pl, int fid)
+{
+ ndr_pipe_t *np;
+ size_t len;
+
+ /*
+ * Allocating ndr_pipe_t + smb_netuserinfo_t as one.
+ * We could just make that part of ndr_pipe_t, but
+ * that struct is opaque to libmlrpc.
+ */
+ len = sizeof (*np) + sizeof (smb_netuserinfo_t);
+ np = malloc(len);
+ if (np == NULL)
+ return (NULL);
+
+ bzero(np, len);
+ np->np_listener = pl;
+ np->np_endpoint = pl->name;
+ np->np_user = (void*)(np + 1);
+ np->np_send = pipe_send;
+ np->np_recv = pipe_recv;
+ np->np_fid = fid;
+ np->np_max_xmit_frag = pipe_max_msgsize;
+ np->np_max_recv_frag = pipe_max_msgsize;
+
+ return (np);
+}
+
+static void
+np_free(ndr_pipe_t *np)
+{
+ (void) close(np->np_fid);
+ free(np);
+}
+
+/*
+ * Create the smbd opipe door service.
+ * Returns the door descriptor on success. Otherwise returns -1.
+ */
+int
+smbd_pipesvc_start(void)
+{
+ pthread_t tid;
+ pthread_attr_t tattr;
+ struct pipe_listener *pl;
+ int i, rc;
+
+ if (mlsvc_init() != 0) {
+ smbd_report("msrpc initialization failed");
+ return (-1);
+ }
+
+ (void) pthread_attr_init(&tattr);
+ (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+
+ for (i = 0; i < NLISTENERS; i++) {
+ pl = &pipe_listeners[i];
+ pl->max_seen = 0;
+
+ if (strcasecmp(pl->name, "spoolss") == 0 &&
+ smb_config_getbool(SMB_CI_PRINT_ENABLE) == B_FALSE)
+ continue;
+
+ rc = pthread_create(&tid, &tattr, pipesvc_listener, pl);
+ if (rc != 0)
+ break;
+ pipe_listeners[i].tid = tid;
+ }
+
+ if (rc != 0) {
+ smbd_report("pipesvc pthread_create, %d", rc);
+ }
+
+ (void) pthread_attr_destroy(&tattr);
+
+ return (rc);
+}
+
+void
+smbd_pipesvc_stop(void)
+{
+ int i;
+
+ (void) mutex_lock(&pipesvc_mutex);
+ for (i = 0; i < NLISTENERS; i++) {
+ if (pipe_listeners[i].tid == 0)
+ continue;
+ (void) pthread_kill(pipe_listeners[i].tid, SIGTERM);
+ pipe_listeners[i].tid = 0;
+ }
+ (void) mutex_unlock(&pipesvc_mutex);
+}
+
+static void *
+pipesvc_listener(void *varg)
+{
+ struct sockaddr_un sa;
+ int err, listen_fd, newfd, snlen;
+ struct pipe_listener *pl = varg;
+ ndr_pipe_t *np;
+ pthread_t tid;
+ int rc;
+
+ listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (listen_fd < 0) {
+ smbd_report("pipesvc_listener, so_create: %d", errno);
+ return (NULL);
+ }
+
+ bzero(&sa, sizeof (sa));
+ sa.sun_family = AF_UNIX;
+ (void) snprintf(sa.sun_path, sizeof (sa.sun_path),
+ "%s/%s", SMB_PIPE_DIR, pl->name);
+
+ /* Bind it to a listening name. */
+ (void) unlink(sa.sun_path);
+ if (bind(listen_fd, (struct sockaddr *)&sa, sizeof (sa)) < 0) {
+ smbd_report("pipesvc_listener, so_bind: %d", errno);
+ (void) close(listen_fd);
+ return (NULL);
+ }
+
+ if (listen(listen_fd, SOMAXCONN) < 0) {
+ smbd_report("pipesvc_listener, listen: %d", errno);
+ (void) close(listen_fd);
+ return (NULL);
+ }
+
+ for (;;) {
+
+ snlen = sizeof (sa);
+ newfd = accept(listen_fd, (struct sockaddr *)&sa, &snlen);
+ if (newfd < 0) {
+ err = errno;
+ switch (err) {
+ case ECONNABORTED:
+ continue;
+ case EINTR:
+ /* normal termination */
+ goto out;
+ default:
+ smbd_report("pipesvc_listener, "
+ "accept failed: %d", errno);
+ }
+ smbd_report("pipesvc_listener, accept: %d", err);
+ break;
+ }
+
+ np = np_new(pl, newfd);
+ if (np == NULL) {
+ smbd_report("pipesvc_listener, alloc1 failed");
+ (void) close(newfd);
+ continue;
+ }
+
+ rc = pthread_create(&tid, NULL, pipesvc_worker, np);
+ if (rc != 0) {
+ smbd_report("pipesvc_listener, pthread_create: %d",
+ errno);
+ np_free(np);
+ continue;
+ }
+ (void) pthread_detach(tid);
+
+ /* Note: np_free in pipesvc_worker */
+ np = NULL;
+ }
+
+out:
+ (void) close(listen_fd);
+ pl->tid = 0;
+ return (NULL);
+}
+
+static void *
+pipesvc_worker(void *varg)
+{
+ XDR xdrs;
+ smb_pipehdr_t phdr;
+ ndr_pipe_t *np = varg;
+ struct pipe_listener *pl = np->np_listener;
+ void *buf = NULL;
+ uint32_t status;
+ ssize_t rc;
+
+ (void) mutex_lock(&pipesvc_mutex);
+ if (pipesvc_workers_cur >= pipesvc_workers_max ||
+ pl->current >= pl->max_allowed) {
+ (void) mutex_unlock(&pipesvc_mutex);
+ status = NT_STATUS_PIPE_NOT_AVAILABLE;
+ (void) send(np->np_fid, &status, sizeof (status), 0);
+ goto out_free_np;
+ }
+ pipesvc_workers_cur++;
+ pl->current++;
+ if (pl->max_seen < pl->current)
+ pl->max_seen = pl->current;
+ (void) mutex_unlock(&pipesvc_mutex);
+
+ /*
+ * The smbsrv kmod sends us one initial message containing an
+ * XDR encoded smb_netuserinfo_t that we read and decode here,
+ * all unbeknownst to libmlrpc.
+ *
+ * Might be nice to enhance getpeerucred() so it can give us
+ * all the info smb_netuserinfo_t carries, and then use that,
+ * which would allow using a more generic RPC service.
+ */
+ rc = pipe_recv(np, &phdr, sizeof (phdr));
+ if (rc != 0) {
+ smbd_report("pipesvc_worker, recv1: %d", rc);
+ goto out_decr;
+ }
+ if (phdr.ph_magic != SMB_PIPE_HDR_MAGIC ||
+ phdr.ph_uilen > 8192) {
+ smbd_report("pipesvc_worker, bad hdr");
+ goto out_decr;
+ }
+ buf = malloc(phdr.ph_uilen);
+ if (buf == NULL) {
+ smbd_report("pipesvc_worker, alloc1 failed");
+ goto out_decr;
+ }
+ rc = pipe_recv(np, buf, phdr.ph_uilen);
+ if (rc != 0) {
+ smbd_report("pipesvc_worker, recv2: %d", rc);
+ goto out_decr;
+ }
+
+ xdrmem_create(&xdrs, buf, phdr.ph_uilen, XDR_DECODE);
+ if (!smb_netuserinfo_xdr(&xdrs, np->np_user)) {
+ smbd_report("pipesvc_worker, bad uinfo");
+ goto out_free_buf;
+ }
+
+ /*
+ * Later, could disallow opens of some pipes by
+ * anonymous users, etc. For now, reply "OK".
+ */
+ status = 0;
+ rc = pipe_send(np, &status, sizeof (status));
+ if (rc != 0) {
+ smbd_report("pipesvc_worker, send1: %d", rc);
+ goto out_free_buf;
+ }
+
+ /*
+ * Run the RPC service loop worker, which
+ * returns when it sees the pipe close.
+ */
+ ndr_pipe_worker(np);
+
+ xdrs.x_op = XDR_FREE;
+ (void) smb_netuserinfo_xdr(&xdrs, np->np_user);
+
+out_free_buf:
+ free(buf);
+ xdr_destroy(&xdrs);
+
+out_decr:
+ (void) mutex_lock(&pipesvc_mutex);
+ pipesvc_workers_cur--;
+ pl->current--;
+ (void) mutex_unlock(&pipesvc_mutex);
+
+out_free_np:
+ /* Cleanup what came in by varg. */
+ (void) shutdown(np->np_fid, SHUT_RDWR);
+ np_free(np);
+ return (NULL);
+}
+
+/*
+ * These are the transport get/put callback functions provided
+ * via the ndr_pipe_t object to the libmlrpc`ndr_pipe_worker.
+ * These are called only with known PDU sizes and should
+ * loop as needed to transfer the entire message.
+ */
+static int
+pipe_recv(ndr_pipe_t *np, void *buf, size_t len)
+{
+ int x;
+
+ while (len > 0) {
+ x = recv(np->np_fid, buf, len, 0);
+ if (x < 0)
+ return (errno);
+ if (x == 0)
+ return (EIO);
+ buf = (char *)buf + x;
+ len -= x;
+ }
+
+ return (0);
+}
+
+static int
+pipe_send(ndr_pipe_t *np, void *buf, size_t len)
+{
+ int x;
+
+ while (len > 0) {
+ x = send(np->np_fid, buf, len, 0);
+ if (x < 0)
+ return (errno);
+ if (x == 0)
+ return (EIO);
+ buf = (char *)buf + x;
+ len -= x;
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libfakekernel/common/ksocket.c b/usr/src/lib/libfakekernel/common/ksocket.c
index 53bcf87576..5ff3538926 100644
--- a/usr/src/lib/libfakekernel/common/ksocket.c
+++ b/usr/src/lib/libfakekernel/common/ksocket.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -504,6 +504,27 @@ ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval,
return (0);
}
+int
+ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvp, struct cred *cr)
+{
+ int rval;
+
+ /* All Solaris components should pass a cred for this operation. */
+ ASSERT(cr != NULL);
+
+ if (!KSOCKET_VALID(ks))
+ return (ENOTSOCK);
+
+ rval = ioctl(KSTOSO(ks), cmd, arg);
+ if (rvp != NULL)
+ *rvp = rval;
+
+ if (rval != 0)
+ rval = errno;
+
+ return (rval);
+}
+
void
ksocket_hold(ksocket_t ks)
{
diff --git a/usr/src/lib/libfakekernel/common/mapfile-vers b/usr/src/lib/libfakekernel/common/mapfile-vers
index ea8b9b8ca0..ffbff01f7f 100644
--- a/usr/src/lib/libfakekernel/common/mapfile-vers
+++ b/usr/src/lib/libfakekernel/common/mapfile-vers
@@ -10,7 +10,7 @@
#
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -105,6 +105,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
ksocket_getpeername;
ksocket_getsockname;
ksocket_hold;
+ ksocket_ioctl;
ksocket_listen;
ksocket_recv;
ksocket_recvfrom;
diff --git a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
index 92afcba6ae..d40fa8d629 100644
--- a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
+++ b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
@@ -34,7 +34,6 @@ OBJS_LOCAL = \
fksmb_idmap.o \
fksmb_init.o \
fksmb_kdoor.o \
- fksmb_opipe_door.o \
fksmb_sign_pkcs.o \
fake_lookup.o \
fake_nblk.o \
diff --git a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_opipe_door.c b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_opipe_door.c
deleted file mode 100644
index a61ea7194c..0000000000
--- a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_opipe_door.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * This module provides the interface to NDR RPC.
- */
-
-#include <sys/stat.h>
-#include <sys/door.h>
-#include <sys/door_data.h>
-#include <sys/uio.h>
-#include <sys/ksynch.h>
-#include <smbsrv/smb_kproto.h>
-#include <smbsrv/smb_door.h>
-
-/*
- * opipe door client (to user space door server).
- */
-void
-smb_opipe_door_init(smb_server_t *sv)
-{
- sv->sv_opipe_door_id = -1;
- mutex_init(&sv->sv_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&sv->sv_opipe_door_cv, NULL, CV_DEFAULT, NULL);
-}
-
-void
-smb_opipe_door_fini(smb_server_t *sv)
-{
- smb_opipe_door_close(sv);
- cv_destroy(&sv->sv_opipe_door_cv);
- mutex_destroy(&sv->sv_opipe_door_mutex);
-}
-
-void
-fksmb_opipe_door_open(smb_server_t *sv, void *varg)
-{
- /* varg is the "door" dispatch function. */
- sv->sv_opipe_door_hd = varg;
-}
-
-/*
- * Close the (user space) door.
- */
-void
-smb_opipe_door_close(smb_server_t *sv)
-{
- sv->sv_opipe_door_hd = NULL;
- sv->sv_opipe_door_id = -1;
-}
-
-
-/*
- * opipe door call interface.
- * Door serialization and call reference accounting is handled here.
- */
-int
-smb_opipe_door_call(smb_opipe_t *opipe)
-{
- smb_server_t *sv = opipe->p_server;
- fksmb_opipe_disp_func_t *func;
- door_arg_t da;
- smb_doorhdr_t hdr;
- int rc;
-
- if (sv == NULL)
- return (EFAULT);
- if (smb_server_is_stopping(sv))
- return (-1);
-
- func = (fksmb_opipe_disp_func_t *)(sv->sv_opipe_door_hd);
- if (func == NULL)
- return (EFAULT);
-
- da.data_ptr = (char *)opipe->p_doorbuf;
- da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
- da.desc_ptr = NULL;
- da.desc_num = 0;
- da.rbuf = (char *)opipe->p_doorbuf;
- da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
-
-
- /*
- * Do the "upcall" to smbd-d. In-kernel, this is:
- * door_ki_upcall_limited(...)
- */
- rc = (*func)(&da);
- if (rc != 0)
- return (rc);
-
- /* Check for door_return(NULL, 0, NULL, 0) */
- if (rc != 0 || da.data_size == 0 || da.rsize == 0)
- return (-1);
-
- if (smb_doorhdr_decode(&hdr, (uint8_t *)da.data_ptr, da.rsize) == -1)
- return (-1);
-
- if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) ||
- (hdr.dh_fid != opipe->p_hdr.dh_fid) ||
- (hdr.dh_op != opipe->p_hdr.dh_op) ||
- (hdr.dh_door_rc != 0) ||
- (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
- return (-1);
- }
-
- opipe->p_hdr.dh_datalen = hdr.dh_datalen;
- opipe->p_hdr.dh_resid = hdr.dh_resid;
- return (0);
-}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h
index ba89e34739..5b55ce4c54 100644
--- a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h
+++ b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h
@@ -19,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _LIBMLRPC_H
@@ -247,28 +247,18 @@ typedef struct ndr_binding {
#define NDR_N_BINDING_POOL 2
typedef struct ndr_pipe {
+ void *np_listener;
+ const char *np_endpoint;
+ smb_netuserinfo_t *np_user;
+ int (*np_send)(struct ndr_pipe *, void *, size_t);
+ int (*np_recv)(struct ndr_pipe *, void *, size_t);
int np_fid;
- uint32_t np_txid;
- smb_netuserinfo_t np_user;
- char *np_buf;
- struct uio np_uio;
- iovec_t np_iov;
- ndr_fraglist_t np_frags;
- int np_refcnt;
uint16_t np_max_xmit_frag;
uint16_t np_max_recv_frag;
ndr_binding_t *np_binding;
ndr_binding_t np_binding_pool[NDR_N_BINDING_POOL];
} ndr_pipe_t;
-typedef struct ndr_pipe_info {
- uint32_t npi_fid;
- uint32_t npi_permissions;
- uint32_t npi_num_locks;
- char npi_pathname[MAXPATHLEN];
- char npi_username[MAXNAMELEN];
-} ndr_pipe_info_t;
-
/*
* Number of bytes required to align SIZE on the next dword/4-byte
* boundary.
@@ -429,7 +419,6 @@ int ndr_heap_avail(ndr_heap_t *);
#define NDR_SIDDUP(XA, S) ndr_heap_siddup((XA)->heap, (S))
typedef struct ndr_xa {
- int fid;
unsigned short ptype; /* high bits special */
unsigned short opnum;
ndr_stream_t recv_nds;
@@ -476,7 +465,7 @@ typedef struct ndr_client {
typedef struct ndr_handle {
ndr_hdid_t nh_id;
struct ndr_handle *nh_next;
- int nh_fid;
+ ndr_pipe_t *nh_pipe;
const ndr_service_t *nh_svc;
ndr_client_t *nh_clnt;
void *nh_data;
@@ -495,7 +484,6 @@ typedef struct ndr_buf {
/* ndr_ops.c */
int nds_initialize(ndr_stream_t *, unsigned, int, ndr_heap_t *);
-void nds_finalize(ndr_stream_t *, ndr_fraglist_t *);
void nds_destruct(ndr_stream_t *);
void nds_show_state(ndr_stream_t *);
@@ -522,11 +510,7 @@ unsigned ndr_bind_ack_hdr_size(ndr_xa_t *);
unsigned ndr_alter_context_rsp_hdr_size(void);
/* ndr_server.c */
-int ndr_pipe_open(int, uint8_t *, uint32_t);
-int ndr_pipe_close(int);
-int ndr_pipe_read(int, uint8_t *, uint32_t *, uint32_t *);
-int ndr_pipe_write(int, uint8_t *, uint32_t);
-void *ndr_pipe_transact(void *);
+void ndr_pipe_worker(ndr_pipe_t *);
int ndr_generic_call_stub(ndr_xa_t *);
@@ -550,7 +534,7 @@ void ndr_uuid_unparse(ndr_uuid_t *, char *);
ndr_hdid_t *ndr_hdalloc(const ndr_xa_t *, const void *);
void ndr_hdfree(const ndr_xa_t *, const ndr_hdid_t *);
ndr_handle_t *ndr_hdlookup(const ndr_xa_t *, const ndr_hdid_t *);
-void ndr_hdclose(int fid);
+void ndr_hdclose(ndr_pipe_t *);
ssize_t ndr_uiomove(caddr_t, size_t, enum uio_rw, struct uio *);
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers b/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers
index c6a32420e0..5822d32711 100644
--- a/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -68,11 +69,7 @@ SYMBOL_VERSION SUNWprivate {
ndr_mbtowc;
ndr_native_os;
ndr_params;
- ndr_pipe_open;
- ndr_pipe_close;
- ndr_pipe_read;
- ndr_pipe_transact;
- ndr_pipe_write;
+ ndr_pipe_worker;
ndr_svc_binding_pool_init;
ndr_svc_lookup_name;
ndr_svc_register;
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c
index 0e8fdf575e..0cbcdc6e90 100644
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -160,44 +161,6 @@ nds_initialize(ndr_stream_t *nds, unsigned pdu_size_hint,
return (0);
}
-void
-nds_finalize(ndr_stream_t *nds, ndr_fraglist_t *frags)
-{
- iovec_t *iov;
- ndr_frag_t *frag;
- uint32_t size = 0;
-
- bzero(frags, sizeof (ndr_fraglist_t));
-
- for (frag = nds->frags.head; frag; frag = frag->next)
- size += frag->len;
-
- if (size == 0 || size >= NDR_PDU_MAX_SIZE)
- return;
-
- frags->iov = malloc(nds->frags.nfrag * sizeof (iovec_t));
- if (frags->iov == NULL)
- return;
-
- frags->head = nds->frags.head;
- frags->tail = nds->frags.tail;
- frags->nfrag = nds->frags.nfrag;
- bzero(&nds->frags, sizeof (ndr_fraglist_t));
-
- frags->uio.uio_iov = frags->iov;
- frags->uio.uio_iovcnt = frags->nfrag;
- frags->uio.uio_offset = 0;
- frags->uio.uio_segflg = UIO_USERSPACE;
- frags->uio.uio_resid = size;
-
- iov = frags->uio.uio_iov;
- for (frag = frags->head; frag; frag = frag->next) {
- iov->iov_base = (caddr_t)frag->buf;
- iov->iov_len = frag->len;
- ++iov;
- }
-}
-
/*
* nds_destruct
*
@@ -424,7 +387,6 @@ ndo_reset(ndr_stream_t *nds)
static void
ndo_destruct(ndr_stream_t *nds)
{
- ndr_frag_t *frag;
ndo_printf(nds, 0, "destruct");
@@ -437,13 +399,6 @@ ndo_destruct(ndr_stream_t *nds)
nds->pdu_base_offset = 0;
}
- while ((frag = nds->frags.head) != NULL) {
- nds->frags.head = frag->next;
- free(frag);
- }
-
- bzero(&nds->frags, sizeof (ndr_fraglist_t));
-
nds->outer_queue_head = 0;
nds->outer_current = 0;
nds->outer_queue_tailp = &nds->outer_queue_head;
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c
index bd51913552..198daa7d55 100644
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -27,478 +28,248 @@
*/
#include <sys/byteorder.h>
-#include <sys/errno.h>
#include <sys/uio.h>
-#include <thread.h>
+#include <errno.h>
#include <synch.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
-#include <time.h>
+#include <thread.h>
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlrpc.h>
#include <smbsrv/ntaccess.h>
-/*
- * Fragment size (5680: NT style).
- */
-#define NDR_FRAG_SZ 5680
-
-#define NDR_GROW_SIZE (8 * 1024)
-#define NDR_GROW_MASK (NDR_GROW_SIZE - 1)
-#define NDR_ALIGN_BUF(S) (((S) + NDR_GROW_SIZE) & ~NDR_GROW_MASK)
-
-#define NDR_PIPE_BUFSZ (64 * 1024)
-#define NDR_PIPE_BUFMAX (64 * 1024 * 1024)
-#define NDR_PIPE_MAX 128
-
-static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX];
-static mutex_t ndr_pipe_lock;
-
-static int ndr_pipe_process(ndr_pipe_t *);
-static ndr_pipe_t *ndr_pipe_lookup(int);
-static void ndr_pipe_release(ndr_pipe_t *);
-static ndr_pipe_t *ndr_pipe_allocate(int);
-static int ndr_pipe_grow(ndr_pipe_t *, size_t);
-static void ndr_pipe_deallocate(ndr_pipe_t *);
-static void ndr_pipe_rewind(ndr_pipe_t *);
-static void ndr_pipe_flush(ndr_pipe_t *);
+#define NDR_PIPE_SEND(np, buf, len) \
+ ((np)->np_send)((np), (buf), (len))
+#define NDR_PIPE_RECV(np, buf, len) \
+ ((np)->np_recv)((np), (buf), (len))
static int ndr_svc_process(ndr_xa_t *);
-static int ndr_svc_defrag(ndr_xa_t *);
static int ndr_svc_bind(ndr_xa_t *);
static int ndr_svc_request(ndr_xa_t *);
static void ndr_reply_prepare_hdr(ndr_xa_t *);
static int ndr_svc_alter_context(ndr_xa_t *);
static void ndr_reply_fault(ndr_xa_t *, unsigned long);
-static int ndr_build_reply(ndr_xa_t *);
-static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t);
+
+static int ndr_recv_request(ndr_xa_t *mxa);
+static int ndr_recv_frag(ndr_xa_t *mxa);
+static int ndr_send_reply(ndr_xa_t *);
+
+static int ndr_pipe_process(ndr_pipe_t *, ndr_xa_t *);
/*
- * Allocate and associate a service context with a fid.
+ * External entry point called by smbd.
*/
-int
-ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen)
+void
+ndr_pipe_worker(ndr_pipe_t *np)
{
- ndr_pipe_t *np;
-
- (void) mutex_lock(&ndr_pipe_lock);
-
- if ((np = ndr_pipe_lookup(fid)) != NULL) {
- ndr_pipe_release(np);
- (void) mutex_unlock(&ndr_pipe_lock);
- return (EEXIST);
- }
-
- if ((np = ndr_pipe_allocate(fid)) == NULL) {
- (void) mutex_unlock(&ndr_pipe_lock);
- return (ENOMEM);
- }
-
- if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) {
- ndr_pipe_release(np);
- (void) mutex_unlock(&ndr_pipe_lock);
- return (EINVAL);
- }
+ ndr_xa_t *mxa;
+ int rc;
ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
NDR_N_BINDING_POOL);
- (void) mutex_unlock(&ndr_pipe_lock);
- return (0);
-}
-
-/*
- * Release the context associated with a fid when an opipe is closed.
- */
-int
-ndr_pipe_close(int fid)
-{
- ndr_pipe_t *np;
+ if ((mxa = malloc(sizeof (*mxa))) == NULL)
+ return;
- (void) mutex_lock(&ndr_pipe_lock);
+ do {
+ bzero(mxa, sizeof (*mxa));
+ rc = ndr_pipe_process(np, mxa);
+ } while (rc == 0);
- if ((np = ndr_pipe_lookup(fid)) == NULL) {
- (void) mutex_unlock(&ndr_pipe_lock);
- return (ENOENT);
- }
+ free(mxa);
/*
- * Release twice: once for the lookup above
- * and again to close the fid.
+ * Ensure that there are no RPC service policy handles
+ * (associated with this fid) left around.
*/
- ndr_pipe_release(np);
- ndr_pipe_release(np);
- (void) mutex_unlock(&ndr_pipe_lock);
- return (0);
-}
-
-/*
- * Write RPC request data to the input stream. Input data is buffered
- * until the response is requested.
- */
-int
-ndr_pipe_write(int fid, uint8_t *buf, uint32_t len)
-{
- ndr_pipe_t *np;
- ssize_t nbytes;
- int rc;
-
- if (len == 0)
- return (0);
-
- (void) mutex_lock(&ndr_pipe_lock);
-
- if ((np = ndr_pipe_lookup(fid)) == NULL) {
- (void) mutex_unlock(&ndr_pipe_lock);
- return (ENOENT);
- }
-
- if ((rc = ndr_pipe_grow(np, len)) != 0) {
- (void) mutex_unlock(&ndr_pipe_lock);
- return (rc);
- }
-
- nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio);
-
- ndr_pipe_release(np);
- (void) mutex_unlock(&ndr_pipe_lock);
- return ((nbytes == len) ? 0 : EIO);
-}
-
-/*
- * Read RPC response data.
- */
-int
-ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
-{
- ndr_pipe_t *np;
- ssize_t nbytes = *len;
-
- if (nbytes == 0) {
- *resid = 0;
- return (0);
- }
-
- (void) mutex_lock(&ndr_pipe_lock);
- if ((np = ndr_pipe_lookup(fid)) == NULL) {
- (void) mutex_unlock(&ndr_pipe_lock);
- return (ENOENT);
- }
- (void) mutex_unlock(&ndr_pipe_lock);
-
- *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio);
- *resid = np->np_frags.uio.uio_resid;
-
- if (*resid == 0) {
- /*
- * Nothing left, cleanup the output stream.
- */
- ndr_pipe_flush(np);
- }
-
- (void) mutex_lock(&ndr_pipe_lock);
- ndr_pipe_release(np);
- (void) mutex_unlock(&ndr_pipe_lock);
- return (0);
-}
-
-/*
- * If the input stream contains an RPC request, process the RPC transaction,
- * which will place the RPC response in the output (frags) stream.
- *
- * arg is freed here; it must have been allocated by malloc().
- */
-void *
-ndr_pipe_transact(void *arg)
-{
- uint32_t *tmp = (uint32_t *)arg;
- uint32_t fid;
- ndr_pipe_t *np;
-
- if (arg == NULL)
- return (NULL);
-
- fid = *tmp;
-
- (void) mutex_lock(&ndr_pipe_lock);
- if ((np = ndr_pipe_lookup(fid)) == NULL) {
- (void) mutex_unlock(&ndr_pipe_lock);
- (void) smb_kmod_event_notify(fid);
- free(arg);
- return (NULL);
- }
- (void) mutex_unlock(&ndr_pipe_lock);
-
- if (ndr_pipe_process(np) != 0)
- ndr_pipe_flush(np);
-
- (void) mutex_lock(&ndr_pipe_lock);
- ndr_pipe_release(np);
- (void) mutex_unlock(&ndr_pipe_lock);
- (void) smb_kmod_event_notify(fid);
- free(arg);
- return (NULL);
+ ndr_hdclose(np);
}
/*
- * Process a server-side RPC request.
+ * Process one server-side RPC request.
*/
static int
-ndr_pipe_process(ndr_pipe_t *np)
+ndr_pipe_process(ndr_pipe_t *np, ndr_xa_t *mxa)
{
- ndr_xa_t *mxa;
ndr_stream_t *recv_nds;
ndr_stream_t *send_nds;
- char *data;
- int datalen;
- int rc;
+ int rc = ENOMEM;
- data = np->np_buf;
- datalen = np->np_uio.uio_offset;
-
- if (datalen == 0)
- return (0);
-
- if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
- return (ENOMEM);
-
- bzero(mxa, sizeof (ndr_xa_t));
- mxa->fid = np->np_fid;
mxa->pipe = np;
mxa->binding_list = np->np_binding;
- if ((mxa->heap = ndr_heap_create()) == NULL) {
- free(mxa);
- return (ENOMEM);
- }
+ if ((mxa->heap = ndr_heap_create()) == NULL)
+ goto out1;
recv_nds = &mxa->recv_nds;
- rc = nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
- if (rc != 0) {
- ndr_heap_destroy(mxa->heap);
- free(mxa);
- return (ENOMEM);
- }
-
- /*
- * Copy the input data and reset the input stream.
- */
- bcopy(data, recv_nds->pdu_base_addr, datalen);
- ndr_pipe_rewind(np);
+ rc = nds_initialize(recv_nds, 0, NDR_MODE_CALL_RECV, mxa->heap);
+ if (rc != 0)
+ goto out2;
send_nds = &mxa->send_nds;
rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
- if (rc != 0) {
- nds_destruct(&mxa->recv_nds);
- ndr_heap_destroy(mxa->heap);
- free(mxa);
- return (ENOMEM);
- }
+ if (rc != 0)
+ goto out3;
+
+ rc = ndr_recv_request(mxa);
+ if (rc != 0)
+ goto out4;
(void) ndr_svc_process(mxa);
+ (void) ndr_send_reply(mxa);
+ rc = 0;
- nds_finalize(send_nds, &np->np_frags);
- nds_destruct(&mxa->recv_nds);
+out4:
nds_destruct(&mxa->send_nds);
+out3:
+ nds_destruct(&mxa->recv_nds);
+out2:
ndr_heap_destroy(mxa->heap);
- free(mxa);
- return (0);
+out1:
+ return (rc);
}
/*
- * Must be called with ndr_pipe_lock held.
+ * Check whether or not the specified user has administrator privileges,
+ * i.e. is a member of Domain Admins or Administrators.
+ * Returns true if the user is an administrator, otherwise returns false.
*/
-static ndr_pipe_t *
-ndr_pipe_lookup(int fid)
+boolean_t
+ndr_is_admin(ndr_xa_t *xa)
{
- ndr_pipe_t *np;
- int i;
-
- for (i = 0; i < NDR_PIPE_MAX; ++i) {
- np = &ndr_pipe_table[i];
-
- if (np->np_fid == fid) {
- if (np->np_refcnt == 0)
- return (NULL);
+ smb_netuserinfo_t *ctx = xa->pipe->np_user;
- np->np_refcnt++;
- return (np);
- }
- }
-
- return (NULL);
+ return (ctx->ui_flags & SMB_ATF_ADMIN);
}
/*
- * Must be called with ndr_pipe_lock held.
+ * Check whether or not the specified user has power-user privileges,
+ * i.e. is a member of Domain Admins, Administrators or Power Users.
+ * This is typically required for operations such as managing shares.
+ * Returns true if the user is a power user, otherwise returns false.
*/
-static void
-ndr_pipe_release(ndr_pipe_t *np)
+boolean_t
+ndr_is_poweruser(ndr_xa_t *xa)
{
- np->np_refcnt--;
- ndr_pipe_deallocate(np);
+ smb_netuserinfo_t *ctx = xa->pipe->np_user;
+
+ return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
+ (ctx->ui_flags & SMB_ATF_POWERUSER));
}
-/*
- * Must be called with ndr_pipe_lock held.
- */
-static ndr_pipe_t *
-ndr_pipe_allocate(int fid)
+int32_t
+ndr_native_os(ndr_xa_t *xa)
{
- ndr_pipe_t *np = NULL;
- int i;
+ smb_netuserinfo_t *ctx = xa->pipe->np_user;
- for (i = 0; i < NDR_PIPE_MAX; ++i) {
- np = &ndr_pipe_table[i];
-
- if (np->np_fid == 0) {
- bzero(np, sizeof (ndr_pipe_t));
-
- if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL)
- return (NULL);
-
- ndr_pipe_rewind(np);
- np->np_fid = fid;
- np->np_refcnt = 1;
- return (np);
- }
- }
-
- return (NULL);
+ return (ctx->ui_native_os);
}
/*
- * If the desired space exceeds the current pipe size, try to expand
- * the pipe. Leave the current pipe intact if the realloc fails.
- *
- * Must be called with ndr_pipe_lock held.
+ * Receive an entire RPC request (all fragments)
+ * Returns zero or an NDR fault code.
*/
static int
-ndr_pipe_grow(ndr_pipe_t *np, size_t desired)
+ndr_recv_request(ndr_xa_t *mxa)
{
- char *newbuf;
- size_t current;
- size_t required;
-
- required = np->np_uio.uio_offset + desired;
- current = np->np_uio.uio_offset + np->np_uio.uio_resid;
-
- if (required <= current)
- return (0);
-
- if (required > NDR_PIPE_BUFMAX) {
- smb_tracef("ndr_pipe_grow: required=%d, max=%d (ENOSPC)",
- required, NDR_PIPE_BUFMAX);
- return (ENOSPC);
- }
-
- required = NDR_ALIGN_BUF(required);
- if (required > NDR_PIPE_BUFMAX)
- required = NDR_PIPE_BUFMAX;
-
- if ((newbuf = realloc(np->np_buf, required)) == NULL) {
- smb_tracef("ndr_pipe_grow: realloc failed (ENOMEM)");
- return (ENOMEM);
- }
+ ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
+ ndr_stream_t *nds = &mxa->recv_nds;
+ unsigned long saved_size;
+ int rc;
- np->np_buf = newbuf;
- np->np_iov.iov_base = np->np_buf + np->np_uio.uio_offset;
- np->np_uio.uio_resid += desired;
- np->np_iov.iov_len += desired;
- return (0);
-}
+ rc = ndr_recv_frag(mxa);
+ if (rc != 0)
+ return (rc);
+ if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags))
+ return (NDR_DRC_FAULT_DECODE_FAILED);
-/*
- * Must be called with ndr_pipe_lock held.
- */
-static void
-ndr_pipe_deallocate(ndr_pipe_t *np)
-{
- if (np->np_refcnt == 0) {
- /*
- * Ensure that there are no RPC service policy handles
- * (associated with this fid) left around.
- */
- ndr_hdclose(np->np_fid);
-
- ndr_pipe_rewind(np);
- ndr_pipe_flush(np);
- free(np->np_buf);
- free(np->np_user.ui_domain);
- free(np->np_user.ui_account);
- free(np->np_user.ui_workstation);
- bzero(np, sizeof (ndr_pipe_t));
+ while (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) {
+ rc = ndr_recv_frag(mxa);
+ if (rc != 0)
+ return (rc);
}
-}
-
-/*
- * Rewind the input data stream, ready for the next write.
- */
-static void
-ndr_pipe_rewind(ndr_pipe_t *np)
-{
- np->np_uio.uio_iov = &np->np_iov;
- np->np_uio.uio_iovcnt = 1;
- np->np_uio.uio_offset = 0;
- np->np_uio.uio_segflg = UIO_USERSPACE;
- np->np_uio.uio_resid = NDR_PIPE_BUFSZ;
- np->np_iov.iov_base = np->np_buf;
- np->np_iov.iov_len = NDR_PIPE_BUFSZ;
-}
-
-/*
- * Flush the output data stream.
- */
-static void
-ndr_pipe_flush(ndr_pipe_t *np)
-{
- ndr_frag_t *frag;
+ nds->pdu_scan_offset = 0;
- while ((frag = np->np_frags.head) != NULL) {
- np->np_frags.head = frag->next;
- free(frag);
- }
+ /*
+ * This whacks nds->pdu_size, so save/restore.
+ * It leaves scan_offset after the header.
+ */
+ saved_size = nds->pdu_size;
+ rc = ndr_decode_pdu_hdr(mxa);
+ nds->pdu_size = saved_size;
- free(np->np_frags.iov);
- bzero(&np->np_frags, sizeof (ndr_fraglist_t));
+ return (rc);
}
/*
- * Check whether or not the specified user has administrator privileges,
- * i.e. is a member of Domain Admins or Administrators.
- * Returns true if the user is an administrator, otherwise returns false.
+ * Read one fragment, leaving the decoded frag header in
+ * recv_hdr.common_hdr, and the data in the recv_nds.
+ *
+ * Returns zero or an NDR fault code.
+ *
+ * If a first frag, the header is included in the data
+ * placed in recv_nds (because it's not fully decoded
+ * until later - we only decode the common part here).
+ * Additional frags are placed in the recv_nds without
+ * the header, so that after the first frag header,
+ * the remaining data will be contiguous. We do this
+ * by simply not advancing the offset in recv_nds after
+ * reading and decoding these additional fragments, so
+ * the payload of such frags will overwrite what was
+ * (temporarily) the frag header.
*/
-boolean_t
-ndr_is_admin(ndr_xa_t *xa)
+static int
+ndr_recv_frag(ndr_xa_t *mxa)
{
- smb_netuserinfo_t *ctx = &xa->pipe->np_user;
+ ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
+ ndr_stream_t *nds = &mxa->recv_nds;
+ unsigned char *data;
+ unsigned long next_offset;
+ unsigned long pay_size;
+ int rc;
- return (ctx->ui_flags & SMB_ATF_ADMIN);
-}
+ /* Make room for the frag header. */
+ next_offset = nds->pdu_scan_offset + NDR_RSP_HDR_SIZE;
+ if (!NDS_GROW_PDU(nds, next_offset, 0))
+ return (NDR_DRC_FAULT_OUT_OF_MEMORY);
-/*
- * Check whether or not the specified user has power-user privileges,
- * i.e. is a member of Domain Admins, Administrators or Power Users.
- * This is typically required for operations such as managing shares.
- * Returns true if the user is a power user, otherwise returns false.
- */
-boolean_t
-ndr_is_poweruser(ndr_xa_t *xa)
-{
- smb_netuserinfo_t *ctx = &xa->pipe->np_user;
+ /* Read the frag header. */
+ data = nds->pdu_base_addr + nds->pdu_scan_offset;
+ rc = NDR_PIPE_RECV(mxa->pipe, data, NDR_RSP_HDR_SIZE);
+ if (rc != 0)
+ return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
- return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
- (ctx->ui_flags & SMB_ATF_POWERUSER));
-}
+ /*
+ * Decode the frag header, get the length.
+ * NB: It uses nds->pdu_scan_offset
+ */
+ ndr_decode_frag_hdr(nds, hdr);
+ ndr_show_hdr(hdr);
+ if (hdr->frag_length < NDR_RSP_HDR_SIZE ||
+ hdr->frag_length > mxa->pipe->np_max_xmit_frag)
+ return (NDR_DRC_FAULT_DECODE_FAILED);
+
+ if (nds->pdu_scan_offset == 0) {
+ /* First frag: header stays in the data. */
+ nds->pdu_scan_offset = next_offset;
+ } /* else overwrite with the payload */
+
+ /* Make room for the payload. */
+ pay_size = hdr->frag_length - NDR_RSP_HDR_SIZE;
+ next_offset = nds->pdu_scan_offset + pay_size;
+ if (!NDS_GROW_PDU(nds, next_offset, 0))
+ return (NDR_DRC_FAULT_OUT_OF_MEMORY);
-int32_t
-ndr_native_os(ndr_xa_t *xa)
-{
- smb_netuserinfo_t *ctx = &xa->pipe->np_user;
+ /* Read the payload. */
+ data = nds->pdu_base_addr + nds->pdu_scan_offset;
+ rc = NDR_PIPE_RECV(mxa->pipe, data, pay_size);
+ if (rc != 0)
+ return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
+ nds->pdu_scan_offset = next_offset;
- return (ctx->ui_native_os);
+ return (NDR_DRC_OK);
}
/*
@@ -508,16 +279,8 @@ ndr_native_os(ndr_xa_t *xa)
static int
ndr_svc_process(ndr_xa_t *mxa)
{
- ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
- ndr_stream_t *nds = &mxa->recv_nds;
- unsigned long saved_offset;
- unsigned long saved_size;
int rc;
- rc = ndr_decode_pdu_hdr(mxa);
- if (!NDR_DRC_IS_OK(rc))
- return (-1);
-
(void) ndr_reply_prepare_hdr(mxa);
switch (mxa->ptype) {
@@ -526,35 +289,6 @@ ndr_svc_process(ndr_xa_t *mxa)
break;
case NDR_PTYPE_REQUEST:
- if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags)) {
- ndr_show_hdr(hdr);
- rc = NDR_DRC_FAULT_DECODE_FAILED;
- goto ndr_svc_process_fault;
- }
-
- if (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) {
- /*
- * Multi-fragment request. Preserve the PDU scan
- * offset and size during defrag so that we can
- * continue as if we had received contiguous data.
- */
- saved_offset = nds->pdu_scan_offset;
- saved_size = nds->pdu_size;
-
- nds->pdu_scan_offset = hdr->frag_length;
- nds->pdu_size = nds->pdu_max_size;
-
- rc = ndr_svc_defrag(mxa);
- if (NDR_DRC_IS_FAULT(rc)) {
- ndr_show_hdr(hdr);
- nds_show_state(nds);
- goto ndr_svc_process_fault;
- }
-
- nds->pdu_scan_offset = saved_offset;
- nds->pdu_size = saved_size;
- }
-
rc = ndr_svc_request(mxa);
break;
@@ -567,61 +301,13 @@ ndr_svc_process(ndr_xa_t *mxa)
break;
}
-ndr_svc_process_fault:
if (NDR_DRC_IS_FAULT(rc))
ndr_reply_fault(mxa, rc);
- (void) ndr_build_reply(mxa);
return (rc);
}
/*
- * Remove RPC fragment headers from the received data stream.
- * The first fragment has already been accounted for before this call.
- *
- * NDR stream on entry:
- *
- * |<-- frag 2 -->|<-- frag 3 -->| ... |<- last frag ->|
- *
- * +-----+--------+-----+--------+-----+-----+---------+
- * | hdr | data | hdr | data | ... | hdr | data |
- * +-----+--------+-----+--------+-----+-----+---------+
- *
- * NDR stream on return:
- *
- * +----------------------------------+
- * | data |
- * +----------------------------------+
- */
-static int
-ndr_svc_defrag(ndr_xa_t *mxa)
-{
- ndr_stream_t *nds = &mxa->recv_nds;
- ndr_common_header_t frag_hdr;
- int frag_size;
- int last_frag;
-
- do {
- ndr_decode_frag_hdr(nds, &frag_hdr);
- ndr_show_hdr(&frag_hdr);
-
- if (NDR_IS_FIRST_FRAG(frag_hdr.pfc_flags))
- return (NDR_DRC_FAULT_DECODE_FAILED);
-
- last_frag = NDR_IS_LAST_FRAG(frag_hdr.pfc_flags);
- frag_size = frag_hdr.frag_length;
-
- if (frag_size > (nds->pdu_size - nds->pdu_scan_offset))
- return (NDR_DRC_FAULT_DECODE_FAILED);
-
- ndr_remove_frag_hdr(nds);
- nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE;
- } while (!last_frag);
-
- return (NDR_DRC_OK);
-}
-
-/*
* Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
* p_results[] not supported.
*/
@@ -919,25 +605,37 @@ ndr_reply_prepare_hdr(ndr_xa_t *mxa)
switch (mxa->ptype) {
case NDR_PTYPE_BIND:
+ /*
+ * Compute the maximum fragment sizes for xmit/recv
+ * and store in the pipe endpoint. Note "xmit" is
+ * client-to-server; "recv" is server-to-client.
+ */
+ if (mxa->pipe->np_max_xmit_frag >
+ mxa->recv_hdr.bind_hdr.max_xmit_frag)
+ mxa->pipe->np_max_xmit_frag =
+ mxa->recv_hdr.bind_hdr.max_xmit_frag;
+ if (mxa->pipe->np_max_recv_frag >
+ mxa->recv_hdr.bind_hdr.max_recv_frag)
+ mxa->pipe->np_max_recv_frag =
+ mxa->recv_hdr.bind_hdr.max_recv_frag;
+
hdr->ptype = NDR_PTYPE_BIND_ACK;
mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
- mxa->recv_hdr.bind_hdr.max_xmit_frag;
+ mxa->pipe->np_max_xmit_frag;
mxa->send_hdr.bind_ack_hdr.max_recv_frag =
- mxa->recv_hdr.bind_hdr.max_recv_frag;
+ mxa->pipe->np_max_recv_frag;
+
+ /*
+ * We're supposed to assign a unique "assoc group"
+ * (identifies this connection for the client).
+ * Using the pipe address is adequate.
+ */
mxa->send_hdr.bind_ack_hdr.assoc_group_id =
mxa->recv_hdr.bind_hdr.assoc_group_id;
-
if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
- mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
+ mxa->send_hdr.bind_ack_hdr.assoc_group_id =
+ (DWORD)(uintptr_t)mxa->pipe;
- /*
- * Save the maximum fragment sizes
- * for use with subsequent requests.
- */
- mxa->pipe->np_max_xmit_frag =
- mxa->recv_hdr.bind_hdr.max_xmit_frag;
- mxa->pipe->np_max_recv_frag =
- mxa->recv_hdr.bind_hdr.max_recv_frag;
break;
case NDR_PTYPE_REQUEST:
@@ -1031,7 +729,7 @@ ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
* non-standard.
*/
static int
-ndr_build_reply(ndr_xa_t *mxa)
+ndr_send_reply(ndr_xa_t *mxa)
{
ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
ndr_stream_t *nds = &mxa->send_nds;
@@ -1041,7 +739,7 @@ ndr_build_reply(ndr_xa_t *mxa)
unsigned long pdu_data_size;
unsigned long frag_data_size;
- frag_size = NDR_FRAG_SZ;
+ frag_size = mxa->pipe->np_max_recv_frag;
pdu_size = nds->pdu_size;
pdu_buf = nds->pdu_base_addr;
@@ -1079,22 +777,14 @@ ndr_build_reply(ndr_xa_t *mxa)
nds->pdu_scan_offset = 0;
(void) ndr_encode_pdu_hdr(mxa);
pdu_size = nds->pdu_size;
- ndr_build_frag(nds, pdu_buf, pdu_size);
+ (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, pdu_size);
return (0);
}
/*
* Multiple fragment response.
- */
- hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
- hdr->frag_length = frag_size;
- mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE;
- nds->pdu_scan_offset = 0;
- (void) ndr_encode_pdu_hdr(mxa);
- ndr_build_frag(nds, pdu_buf, frag_size);
-
- /*
- * We need to update the 24-byte header in subsequent fragments.
+ *
+ * We need to update the RPC header for every fragment.
*
* pdu_data_size: total data remaining to be handled
* frag_size: total fragment size including header
@@ -1104,61 +794,45 @@ ndr_build_reply(ndr_xa_t *mxa)
pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
- while (pdu_data_size) {
- mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
- pdu_data_size -= frag_data_size;
- pdu_buf += frag_data_size;
+ /*
+ * Send the first frag.
+ */
+ hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
+ hdr->frag_length = frag_size;
+ mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
+ nds->pdu_scan_offset = 0;
+ (void) ndr_encode_pdu_hdr(mxa);
+ (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
+ pdu_data_size -= frag_data_size;
+ pdu_buf += frag_data_size;
- if (pdu_data_size <= frag_data_size) {
- frag_data_size = pdu_data_size;
- frag_size = frag_data_size + NDR_RSP_HDR_SIZE;
- hdr->pfc_flags = NDR_PFC_LAST_FRAG;
- } else {
- hdr->pfc_flags = 0;
- }
+ /*
+ * Send "middle" (full-sized) fragments...
+ */
+ hdr->pfc_flags = 0;
+ while (pdu_data_size > frag_data_size) {
hdr->frag_length = frag_size;
+ mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
nds->pdu_scan_offset = 0;
(void) ndr_encode_pdu_hdr(mxa);
bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
-
- ndr_build_frag(nds, pdu_buf, frag_size);
-
- if (hdr->pfc_flags & NDR_PFC_LAST_FRAG)
- break;
+ (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
+ pdu_data_size -= frag_data_size;
+ pdu_buf += frag_data_size;
}
- return (0);
-}
-
-/*
- * ndr_build_frag
- *
- * Build an RPC PDU fragment from the specified buffer.
- * If malloc fails, the client will see a header/pdu inconsistency
- * and report an error.
- */
-static void
-ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len)
-{
- ndr_frag_t *frag;
- int size = sizeof (ndr_frag_t) + len;
-
- if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
- return;
+ /*
+ * Last frag (pdu_data_size <= frag_data_size)
+ */
+ hdr->pfc_flags = NDR_PFC_LAST_FRAG;
+ frag_size = pdu_data_size + NDR_RSP_HDR_SIZE;
+ hdr->frag_length = frag_size;
+ mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
+ nds->pdu_scan_offset = 0;
+ (void) ndr_encode_pdu_hdr(mxa);
+ bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
+ (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
- frag->next = NULL;
- frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
- frag->len = len;
- bcopy(buf, frag->buf, len);
-
- if (nds->frags.head == NULL) {
- nds->frags.head = frag;
- nds->frags.tail = frag;
- nds->frags.nfrag = 1;
- } else {
- nds->frags.tail->next = frag;
- nds->frags.tail = frag;
- ++nds->frags.nfrag;
- }
+ return (0);
}
diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_svc.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_svc.c
index ce4af4c094..d5c5f95f01 100644
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_svc.c
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_svc.c
@@ -21,6 +21,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include <uuid/uuid.h>
@@ -211,7 +213,7 @@ ndr_hdalloc(const ndr_xa_t *xa, const void *data)
++id.data2;
bcopy(&id, &hd->nh_id, sizeof (ndr_hdid_t));
- hd->nh_fid = xa->fid;
+ hd->nh_pipe = xa->pipe;
hd->nh_svc = xa->binding->service;
hd->nh_data = (void *)data;
hd->nh_data_free = NULL;
@@ -290,7 +292,7 @@ ndr_hdlookup(const ndr_xa_t *xa, const ndr_hdid_t *id)
* Called when a pipe is closed to release any associated handles.
*/
void
-ndr_hdclose(int fid)
+ndr_hdclose(ndr_pipe_t *pipe)
{
ndr_handle_t *hd;
ndr_handle_t **pphd;
@@ -301,7 +303,7 @@ ndr_hdclose(int fid)
while (*pphd) {
hd = *pphd;
- if (hd->nh_fid == fid) {
+ if (hd->nh_pipe == pipe) {
*pphd = hd->nh_next;
if (hd->nh_data_free)
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c
index e04ef02503..31e3175416 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -517,7 +518,7 @@ static int
lsarpc_s_GetConnectedUser(void *arg, ndr_xa_t *mxa)
{
struct mslsa_GetConnectedUser *param = arg;
- smb_netuserinfo_t *user = &mxa->pipe->np_user;
+ smb_netuserinfo_t *user = mxa->pipe->np_user;
DWORD status = NT_STATUS_SUCCESS;
smb_domainex_t di;
int rc1;
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c
index 5c1bba93cf..ba1c9caece 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -326,9 +326,9 @@ spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa)
else
(void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN);
- spfile->sd_ipaddr = mxa->pipe->np_user.ui_ipaddr;
+ spfile->sd_ipaddr = mxa->pipe->np_user->ui_ipaddr;
(void) strlcpy((char *)spfile->sd_username,
- mxa->pipe->np_user.ui_account, MAXNAMELEN);
+ mxa->pipe->np_user->ui_account, MAXNAMELEN);
(void) memcpy(&spfile->sd_handle, &param->handle, sizeof (ndr_hdid_t));
/*
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c
index 4a6dace4b4..89a395cca5 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -2677,7 +2678,7 @@ mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, smb_svcenum_t *se,
static boolean_t
srvsvc_add_autohome(ndr_xa_t *mxa, smb_svcenum_t *se, void *infop)
{
- smb_netuserinfo_t *user = &mxa->pipe->np_user;
+ smb_netuserinfo_t *user = mxa->pipe->np_user;
char *username;
smb_share_t si;
DWORD status;
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index ca912c05dd..40caa53481 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1221,7 +1221,6 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \
smb_ofile.o \
smb_open_andx.o \
smb_opipe.o \
- smb_opipe_door.o \
smb_oplock.o \
smb_pathname.o \
smb_print.o \
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
index 6e217c51ed..91f9a51bab 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -38,7 +38,7 @@
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smbinfo.h>
-volatile uint32_t smb_fids = 0;
+static volatile uint32_t smb_fids = 0;
#define SMB_UNIQ_FID() atomic_inc_32_nv(&smb_fids)
static uint32_t smb_open_subr(smb_request_t *);
@@ -378,7 +378,9 @@ smb_open_subr(smb_request_t *sr)
* No further processing for IPC, we need to either
* raise an exception or return success here.
*/
- if ((status = smb_opipe_open(sr)) != NT_STATUS_SUCCESS)
+ uniq_fid = SMB_UNIQ_FID();
+ status = smb_opipe_open(sr, uniq_fid);
+ if (status != NT_STATUS_SUCCESS)
smbsr_error(sr, status, 0, 0);
smb_threshold_exit(&sv->sv_opipe_ct);
@@ -825,18 +827,24 @@ smb_open_subr(smb_request_t *sr)
status = NT_STATUS_SUCCESS;
- of = smb_ofile_open(sr, node, sr->smb_pid, op, SMB_FTYPE_DISK, uniq_fid,
+ of = smb_ofile_open(sr, node, op, SMB_FTYPE_DISK, uniq_fid,
&err);
if (of == NULL) {
smbsr_error(sr, err.status, err.errcls, err.errcode);
status = err.status;
}
- if (status == NT_STATUS_SUCCESS) {
- if (!smb_tree_is_connected(sr->tid_tree)) {
- smbsr_error(sr, 0, ERRSRV, ERRinvnid);
- status = NT_STATUS_UNSUCCESSFUL;
- }
+ /*
+ * We might have blocked in smb_ofile_open long enough so a
+ * tree disconnect might have happened. In that case, we've
+ * just added an ofile to a tree that's disconnecting, and
+ * need to undo that to avoid interfering with tear-down of
+ * the tree connection.
+ */
+ if (status == NT_STATUS_SUCCESS &&
+ !smb_tree_is_connected(sr->tid_tree)) {
+ smbsr_error(sr, 0, ERRSRV, ERRinvnid);
+ status = NT_STATUS_INVALID_PARAMETER;
}
/*
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
index 47607b4bb9..6fe650735e 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
@@ -1383,16 +1383,74 @@ is_supported_mailslot(const char *mailslot)
}
/*
- * Currently, just return false if the pipe is \\PIPE\repl.
- * Otherwise, return true.
+ * smb_trans_nmpipe
+ *
+ * This is used for RPC bind and request transactions.
+ *
+ * If the data available from the pipe is larger than the maximum
+ * data size requested by the client, return as much as requested.
+ * The residual data remains in the pipe until the client comes back
+ * with a read request or closes the pipe.
+ *
+ * When we read less than what's available, we MUST return the
+ * status NT_STATUS_BUFFER_OVERFLOW (or ERRDOS/ERROR_MORE_DATA)
*/
-static boolean_t
-is_supported_pipe(const char *pname)
+static smb_sdrc_t
+smb_trans_nmpipe(smb_request_t *sr, smb_xa_t *xa)
{
- if (smb_strcasecmp(pname, PIPE_REPL, 0) == 0)
- return (B_FALSE);
+ smb_vdb_t vdb;
+ struct mbuf *mb;
+ int rc;
+
+ smbsr_lookup_file(sr);
+ if (sr->fid_ofile == NULL) {
+ smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ return (SDRC_ERROR);
+ }
+
+ rc = smb_mbc_decodef(&xa->req_data_mb, "#B",
+ xa->smb_tdscnt, &vdb);
+ if (rc != 0) {
+ /* Not enough data sent. */
+ smbsr_error(sr, 0, ERRSRV, ERRerror);
+ return (SDRC_ERROR);
+ }
+
+ rc = smb_opipe_write(sr, &vdb.vdb_uio);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ vdb.vdb_tag = 0;
+ vdb.vdb_uio.uio_iov = &vdb.vdb_iovec[0];
+ vdb.vdb_uio.uio_iovcnt = MAX_IOVEC;
+ vdb.vdb_uio.uio_segflg = UIO_SYSSPACE;
+ vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
+ vdb.vdb_uio.uio_loffset = (offset_t)0;
+ vdb.vdb_uio.uio_resid = xa->smb_mdrcnt;
+ mb = smb_mbuf_allocate(&vdb.vdb_uio);
+
+ rc = smb_opipe_read(sr, &vdb.vdb_uio);
+ if (rc == E2BIG) {
+ /*
+ * Note: E2BIG is not a real error. It just
+ * tells us there's more data to be read.
+ */
+ smbsr_status(sr, NT_STATUS_BUFFER_OVERFLOW,
+ ERRDOS, ERROR_MORE_DATA);
+ rc = 0;
+ }
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ smb_mbuf_trim(mb, xa->smb_mdrcnt - vdb.vdb_uio.uio_resid);
+ MBC_ATTACH_MBUF(&xa->rep_data_mb, mb);
- return (B_TRUE);
+ return (SDRC_SUCCESS);
}
static smb_sdrc_t
@@ -1405,7 +1463,6 @@ smb_trans_dispatch(smb_request_t *sr, smb_xa_t *xa)
uint16_t devstate;
char *req_fmt;
char *rep_fmt;
- smb_vdb_t vdb;
if (xa->smb_suwcnt > 0 && STYPE_ISIPC(sr->tid_tree->t_res_type)) {
rc = smb_mbc_decodef(&xa->req_setup_mb, "ww", &opcode,
@@ -1422,26 +1479,11 @@ smb_trans_dispatch(smb_request_t *sr, smb_xa_t *xa)
break;
case TRANS_TRANSACT_NMPIPE:
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
- ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- rc = smb_mbc_decodef(&xa->req_data_mb, "#B",
- xa->smb_tdscnt, &vdb);
- if (rc != 0)
- goto trans_err_not_supported;
-
- rc = smb_opipe_transact(sr, &vdb.vdb_uio);
+ rc = smb_trans_nmpipe(sr, xa);
break;
case TRANS_WAIT_NMPIPE:
- if (!is_supported_pipe(xa->xa_pipe_name)) {
- smbsr_error(sr, 0, ERRDOS, ERRbadfile);
- return (SDRC_ERROR);
- }
+ delay(SEC_TO_TICK(1));
rc = SDRC_SUCCESS;
break;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
index e2488c244f..da874155ff 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -970,6 +970,8 @@ static const struct {
{ EROFS, ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED },
{ ESTALE, ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE },
{ EBADF, ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE },
+ { ENOTSOCK, ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE },
+ { EPIPE, ERRDOS, ERROR_BROKEN_PIPE, NT_STATUS_PIPE_BROKEN },
{ EEXIST, ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION },
{ ENXIO, ERRSRV, ERRinvdevice, NT_STATUS_BAD_DEVICE_TYPE },
{ ESRCH, ERRDOS, ERROR_FILE_NOT_FOUND,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
index 41515ee392..a21461efe3 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -177,7 +177,6 @@ smb_ofile_t *
smb_ofile_open(
smb_request_t *sr,
smb_node_t *node,
- uint16_t pid,
struct open_param *op,
uint16_t ftype,
uint32_t uniqid,
@@ -205,7 +204,7 @@ smb_ofile_open(
of->f_refcnt = 1;
of->f_fid = fid;
of->f_uniqid = uniqid;
- of->f_opened_by_pid = pid;
+ of->f_opened_by_pid = sr->smb_pid;
of->f_granted_access = op->desired_access;
of->f_share_access = op->share_access;
of->f_create_options = op->create_options;
@@ -230,7 +229,8 @@ smb_ofile_open(
of->f_state = SMB_OFILE_STATE_OPEN;
if (ftype == SMB_FTYPE_MESG_PIPE) {
- of->f_pipe = smb_opipe_alloc(tree->t_server);
+ /* See smb_opipe_open. */
+ of->f_pipe = op->pipe;
smb_server_inc_pipes(of->f_server);
} else {
ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */
@@ -324,113 +324,104 @@ smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec)
mutex_enter(&of->f_mutex);
ASSERT(of->f_refcnt);
- switch (of->f_state) {
- case SMB_OFILE_STATE_OPEN: {
-
- of->f_state = SMB_OFILE_STATE_CLOSING;
+ if (of->f_state != SMB_OFILE_STATE_OPEN) {
mutex_exit(&of->f_mutex);
+ return;
+ }
+ of->f_state = SMB_OFILE_STATE_CLOSING;
+ mutex_exit(&of->f_mutex);
- if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
- smb_opipe_close(of);
- smb_server_dec_pipes(of->f_server);
- } else {
- smb_attr_t *pa = &of->f_pending_attr;
-
- /*
- * In here we make changes to of->f_pending_attr
- * while not holding of->f_mutex. This is OK
- * because we've changed f_state to CLOSING,
- * so no more threads will take this path.
- */
- if (mtime_sec != 0) {
- pa->sa_vattr.va_mtime.tv_sec = mtime_sec;
- pa->sa_mask |= SMB_AT_MTIME;
- }
+ if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
+ smb_opipe_close(of);
+ smb_server_dec_pipes(of->f_server);
+ } else {
+ smb_attr_t *pa = &of->f_pending_attr;
- /*
- * If we have ever modified data via this handle
- * (write or truncate) and if the mtime was not
- * set via this handle, update the mtime again
- * during the close. Windows expects this.
- * [ MS-FSA 2.1.5.4 "Update Timestamps" ]
- */
- if (of->f_written &&
- (pa->sa_mask & SMB_AT_MTIME) == 0) {
- pa->sa_mask |= SMB_AT_MTIME;
- gethrestime(&now);
- pa->sa_vattr.va_mtime = now;
- }
+ /*
+ * In here we make changes to of->f_pending_attr
+ * while not holding of->f_mutex. This is OK
+ * because we've changed f_state to CLOSING,
+ * so no more threads will take this path.
+ */
+ if (mtime_sec != 0) {
+ pa->sa_vattr.va_mtime.tv_sec = mtime_sec;
+ pa->sa_mask |= SMB_AT_MTIME;
+ }
- if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) {
- if (smb_tree_has_feature(of->f_tree,
- SMB_TREE_CATIA)) {
- flags |= SMB_CATIA;
- }
- (void) smb_node_set_delete_on_close(of->f_node,
- of->f_cr, flags);
- }
- smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid);
- smb_node_destroy_lock_by_ofile(of->f_node, of);
+ /*
+ * If we have ever modified data via this handle
+ * (write or truncate) and if the mtime was not
+ * set via this handle, update the mtime again
+ * during the close. Windows expects this.
+ * [ MS-FSA 2.1.5.4 "Update Timestamps" ]
+ */
+ if (of->f_written &&
+ (pa->sa_mask & SMB_AT_MTIME) == 0) {
+ pa->sa_mask |= SMB_AT_MTIME;
+ gethrestime(&now);
+ pa->sa_vattr.va_mtime = now;
+ }
- if (smb_node_is_file(of->f_node)) {
- (void) smb_fsop_close(of->f_node, of->f_mode,
- of->f_cr);
- smb_oplock_release(of->f_node, of);
- }
- if (smb_node_dec_open_ofiles(of->f_node) == 0) {
- /*
- * Last close. The f_pending_attr has
- * only times (atime,ctime,mtime) so
- * we can borrow it to commit the
- * n_pending_dosattr from the node.
- */
- pa->sa_dosattr =
- of->f_node->n_pending_dosattr;
- if (pa->sa_dosattr != 0)
- pa->sa_mask |= SMB_AT_DOSATTR;
- /* Let's leave this zero when not in use. */
- of->f_node->n_allocsz = 0;
- }
- if (pa->sa_mask != 0) {
- /*
- * Commit any pending attributes from
- * the ofile we're closing. Note that
- * we pass NULL as the ofile to setattr
- * so it will write to the file system
- * and not keep anything on the ofile.
- * This clears n_pending_dosattr if
- * there are no opens, otherwise the
- * dosattr will be pending again.
- */
- (void) smb_node_setattr(NULL, of->f_node,
- of->f_cr, NULL, pa);
+ if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) {
+ if (smb_tree_has_feature(of->f_tree,
+ SMB_TREE_CATIA)) {
+ flags |= SMB_CATIA;
}
+ (void) smb_node_set_delete_on_close(of->f_node,
+ of->f_cr, flags);
+ }
+ smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid);
+ smb_node_destroy_lock_by_ofile(of->f_node, of);
+ if (smb_node_is_file(of->f_node)) {
+ (void) smb_fsop_close(of->f_node, of->f_mode,
+ of->f_cr);
+ smb_oplock_release(of->f_node, of);
+ }
+ if (smb_node_dec_open_ofiles(of->f_node) == 0) {
/*
- * Cancel any notify change requests that
- * may be using this open instance.
+ * Last close. The f_pending_attr has
+ * only times (atime,ctime,mtime) so
+ * we can borrow it to commit the
+ * n_pending_dosattr from the node.
*/
- if (of->f_node->n_fcn.fcn_count)
- smb_notify_file_closed(of);
-
- smb_server_dec_files(of->f_server);
+ pa->sa_dosattr =
+ of->f_node->n_pending_dosattr;
+ if (pa->sa_dosattr != 0)
+ pa->sa_mask |= SMB_AT_DOSATTR;
+ /* Let's leave this zero when not in use. */
+ of->f_node->n_allocsz = 0;
+ }
+ if (pa->sa_mask != 0) {
+ /*
+ * Commit any pending attributes from
+ * the ofile we're closing. Note that
+ * we pass NULL as the ofile to setattr
+ * so it will write to the file system
+ * and not keep anything on the ofile.
+ * This clears n_pending_dosattr if
+ * there are no opens, otherwise the
+ * dosattr will be pending again.
+ */
+ (void) smb_node_setattr(NULL, of->f_node,
+ of->f_cr, NULL, pa);
}
- atomic_dec_32(&of->f_tree->t_open_files);
- mutex_enter(&of->f_mutex);
- ASSERT(of->f_refcnt);
- ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
- of->f_state = SMB_OFILE_STATE_CLOSED;
- break;
- }
- case SMB_OFILE_STATE_CLOSED:
- case SMB_OFILE_STATE_CLOSING:
- break;
+ /*
+ * Cancel any notify change requests that
+ * may be using this open instance.
+ */
+ if (of->f_node->n_fcn.fcn_count)
+ smb_notify_file_closed(of);
- default:
- ASSERT(0);
- break;
+ smb_server_dec_files(of->f_server);
}
+ atomic_dec_32(&of->f_tree->t_open_files);
+
+ mutex_enter(&of->f_mutex);
+ ASSERT(of->f_refcnt);
+ ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
+ of->f_state = SMB_OFILE_STATE_CLOSED;
mutex_exit(&of->f_mutex);
}
@@ -541,14 +532,14 @@ smb_ofile_hold(smb_ofile_t *of)
mutex_enter(&of->f_mutex);
- if (smb_ofile_is_open_locked(of)) {
- of->f_refcnt++;
+ if (of->f_state != SMB_OFILE_STATE_OPEN) {
mutex_exit(&of->f_mutex);
- return (B_TRUE);
+ return (B_FALSE);
}
+ of->f_refcnt++;
mutex_exit(&of->f_mutex);
- return (B_FALSE);
+ return (B_TRUE);
}
/*
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
index 116cdc6e3b..5eacc82a60 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
@@ -19,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -28,32 +28,28 @@
*/
#include <sys/stat.h>
-#include <sys/door.h>
-#include <sys/door_data.h>
#include <sys/uio.h>
#include <sys/ksynch.h>
+#include <sys/stropts.h>
+#include <sys/socket.h>
+#include <sys/filio.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_xdr.h>
-#define SMB_OPIPE_ISOPEN(OPIPE) \
- (((OPIPE)->p_hdr.dh_magic == SMB_OPIPE_HDR_MAGIC) && \
- ((OPIPE)->p_hdr.dh_fid))
-
-extern volatile uint32_t smb_fids;
-#define SMB_UNIQ_FID() atomic_inc_32_nv(&smb_fids)
-
-static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *);
-static char *smb_opipe_lookup(const char *);
-static int smb_opipe_sethdr(smb_opipe_t *, uint32_t, uint32_t);
-static int smb_opipe_exec(smb_opipe_t *);
-static void smb_opipe_enter(smb_opipe_t *);
-static void smb_opipe_exit(smb_opipe_t *);
-
-
-smb_opipe_t *
-smb_opipe_alloc(smb_server_t *sv)
+/*
+ * Allocate a new opipe and return it, or NULL, in which case
+ * the caller will report "internal error".
+ */
+static smb_opipe_t *
+smb_opipe_alloc(smb_request_t *sr)
{
+ smb_server_t *sv = sr->sr_server;
smb_opipe_t *opipe;
+ ksocket_t sock;
+
+ if (ksocket_socket(&sock, AF_UNIX, SOCK_STREAM, 0,
+ KSOCKET_SLEEP, sr->user_cr) != 0)
+ return (NULL);
opipe = kmem_cache_alloc(smb_cache_opipe, KM_SLEEP);
@@ -62,14 +58,18 @@ smb_opipe_alloc(smb_server_t *sv)
cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
opipe->p_magic = SMB_OPIPE_MAGIC;
opipe->p_server = sv;
-
- smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
- smb_llist_insert_tail(&sv->sv_opipe_list, opipe);
- smb_llist_exit(&sv->sv_opipe_list);
+ opipe->p_refcnt = 1;
+ opipe->p_socket = sock;
return (opipe);
}
+/*
+ * Destroy an opipe. This is normally called from smb_ofile_delete
+ * when the ofile has no more references and is about to be free'd.
+ * This is also called here in error handling code paths, before
+ * the opipe is installed under an ofile.
+ */
void
smb_opipe_dealloc(smb_opipe_t *opipe)
{
@@ -79,12 +79,14 @@ smb_opipe_dealloc(smb_opipe_t *opipe)
sv = opipe->p_server;
SMB_SERVER_VALID(sv);
- smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
- smb_llist_remove(&sv->sv_opipe_list, opipe);
- smb_llist_exit(&sv->sv_opipe_list);
+ /*
+ * This is called in the error path when opening,
+ * in which case we close the socket here.
+ */
+ if (opipe->p_socket != NULL)
+ (void) ksocket_close(opipe->p_socket, zone_kcred());
opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC;
- smb_event_destroy(opipe->p_event);
cv_destroy(&opipe->p_cv);
mutex_destroy(&opipe->p_mutex);
@@ -92,299 +94,198 @@ smb_opipe_dealloc(smb_opipe_t *opipe)
}
/*
- * smb_opipe_open
- *
- * Open a well-known RPC named pipe. This routine should be called if
- * a file open is requested on a share of type STYPE_IPC.
- * If we recognize the pipe, we setup a new ofile.
- *
- * Returns 0 on success, Otherwise an NT status is returned to indicate
- * an error.
+ * Helper for open: build pipe name and connect.
*/
-int
-smb_opipe_open(smb_request_t *sr)
+static int
+smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe)
{
+ struct sockaddr_un saddr;
smb_arg_open_t *op = &sr->sr_open;
- smb_ofile_t *of;
- smb_opipe_t *opipe;
- smb_doorhdr_t hdr;
- smb_error_t err;
- char *pipe_name;
+ const char *name;
+ int rc;
- if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL)
- return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ name = op->fqi.fq_path.pn_path;
+ name += strspn(name, "\\");
+ if (smb_strcasecmp(name, "PIPE", 4) == 0) {
+ name += 4;
+ name += strspn(name, "\\");
+ }
+ (void) strlcpy(opipe->p_name, name, SMB_OPIPE_MAXNAME);
+ (void) smb_strlwr(opipe->p_name);
- /*
- * If printing is disabled, pretend spoolss does not exist.
- */
- if (sr->sr_server->sv_cfg.skc_print_enable == 0 &&
- strcmp(pipe_name, "SPOOLSS") == 0)
- return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ bzero(&saddr, sizeof (saddr));
+ saddr.sun_family = AF_UNIX;
+ (void) snprintf(saddr.sun_path, sizeof (saddr.sun_path),
+ "%s/%s", SMB_PIPE_DIR, opipe->p_name);
+ rc = ksocket_connect(opipe->p_socket, (struct sockaddr *)&saddr,
+ sizeof (saddr), sr->user_cr);
- op->create_options = 0;
+ return (rc);
+}
- of = smb_ofile_open(sr, NULL, sr->smb_pid, op, SMB_FTYPE_MESG_PIPE,
- SMB_UNIQ_FID(), &err);
+/*
+ * Helper for open: encode and send the user info.
+ *
+ * We send information about this client + user to the
+ * pipe service so it can use it for access checks.
+ * The service MAY deny the open based on this info,
+ * (i.e. anonymous session trying to open a pipe that
+ * requires authentication) in which case we will read
+ * an error status from the service and return that.
+ */
+static void
+smb_opipe_send_userinfo(smb_request_t *sr, smb_opipe_t *opipe,
+ smb_error_t *errp)
+{
+ XDR xdrs;
+ smb_netuserinfo_t nui;
+ smb_pipehdr_t phdr;
+ char *buf;
+ uint32_t buflen;
+ uint32_t status;
+ size_t iocnt = 0;
+ int rc;
- if (of == NULL)
- return (err.status);
+ /*
+ * Any errors building the XDR message etc.
+ */
+ errp->status = NT_STATUS_INTERNAL_ERROR;
- if (!smb_tree_is_connected(sr->tid_tree)) {
- smb_ofile_close(of, 0);
- smb_ofile_release(of);
- return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
- }
+ smb_user_netinfo_init(sr->uid_user, &nui);
+ phdr.ph_magic = SMB_PIPE_HDR_MAGIC;
+ phdr.ph_uilen = xdr_sizeof(smb_netuserinfo_xdr, &nui);
- op->dsize = 0x01000;
- op->dattr = FILE_ATTRIBUTE_NORMAL;
- op->ftype = SMB_FTYPE_MESG_PIPE;
- op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
- op->devstate = SMB_PIPE_READMODE_MESSAGE
- | SMB_PIPE_TYPE_MESSAGE
- | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
- op->fileid = of->f_fid;
+ buflen = sizeof (phdr) + phdr.ph_uilen;
+ buf = kmem_alloc(buflen, KM_SLEEP);
- sr->smb_fid = of->f_fid;
- sr->fid_ofile = of;
+ bcopy(&phdr, buf, sizeof (phdr));
+ xdrmem_create(&xdrs, buf + sizeof (phdr),
+ buflen - (sizeof (phdr)), XDR_ENCODE);
+ if (!smb_netuserinfo_xdr(&xdrs, &nui))
+ goto out;
- opipe = of->f_pipe;
- smb_opipe_enter(opipe);
+ /*
+ * If we fail sending the netuserinfo or recv'ing the
+ * status reponse, we have probably run into the limit
+ * on the number of open pipes. That's this status:
+ */
+ errp->status = NT_STATUS_PIPE_NOT_AVAILABLE;
+
+ rc = ksocket_send(opipe->p_socket, buf, buflen, 0,
+ &iocnt, sr->user_cr);
+ if (rc == 0 && iocnt != buflen)
+ rc = EIO;
+ if (rc != 0)
+ goto out;
- opipe->p_server = of->f_server;
- opipe->p_name = pipe_name;
- opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP);
+ rc = ksocket_recv(opipe->p_socket, &status, sizeof (status), 0,
+ &iocnt, sr->user_cr);
+ if (rc != 0 || iocnt != sizeof (status))
+ goto out;
/*
- * p_data points to the offset within p_doorbuf at which
- * data will be written or read.
+ * Return the status we read from the pipe service,
+ * normally NT_STATUS_SUCCESS, but could be something
+ * else like NT_STATUS_ACCESS_DENIED.
*/
- opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_doorhdr_xdr, &hdr);
-
- if (smb_opipe_do_open(sr, opipe) != 0) {
- /*
- * On error, reset the header to clear the fid,
- * which avoids confusion when smb_opipe_close() is
- * called by smb_ofile_close().
- */
- bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
- kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
- smb_opipe_exit(opipe);
- smb_ofile_close(of, 0);
- return (NT_STATUS_NO_MEMORY);
- }
- smb_opipe_exit(opipe);
- return (NT_STATUS_SUCCESS);
+ errp->status = status;
+
+out:
+ xdr_destroy(&xdrs);
+ kmem_free(buf, buflen);
+ smb_user_netinfo_fini(&nui);
}
/*
- * smb_opipe_lookup
+ * smb_opipe_open
*
- * Lookup a path to see if it's a well-known RPC named pipe that we support.
- * The full pipe path will be in the form \\PIPE\\SERVICE. The first part
- * can be assumed, so all we need here are the service names.
+ * Open an RPC named pipe. This routine should be called if
+ * a file open is requested on a share of type STYPE_IPC.
+ * If we recognize the pipe, we setup a new ofile.
*
- * Returns a pointer to the pipe name (without any leading \'s) on success.
- * Otherwise returns a null pointer.
+ * Returns 0 on success, Otherwise an NT status code.
*/
-static char *
-smb_opipe_lookup(const char *path)
+int
+smb_opipe_open(smb_request_t *sr, uint32_t uniqid)
{
- static char *named_pipes[] = {
- "lsass",
- "LSARPC",
- "NETLOGON",
- "SAMR",
- "SPOOLSS",
- "SRVSVC",
- "SVCCTL",
- "WINREG",
- "WKSSVC",
- "EVENTLOG",
- "NETDFS"
- };
-
- const char *name;
- int i;
+ smb_arg_open_t *op = &sr->sr_open;
+ smb_ofile_t *ofile;
+ smb_opipe_t *opipe;
+ smb_error_t err;
- if (path == NULL)
- return (NULL);
+ opipe = smb_opipe_alloc(sr);
+ if (opipe == NULL)
+ return (NT_STATUS_INTERNAL_ERROR);
- name = path;
- name += strspn(name, "\\");
- if (smb_strcasecmp(name, "PIPE", 4) == 0) {
- path += 4;
- name += strspn(name, "\\");
+ if (smb_opipe_connect(sr, opipe) != 0) {
+ smb_opipe_dealloc(opipe);
+ return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
}
- for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) {
- if (smb_strcasecmp(name, named_pipes[i], 0) == 0)
- return (named_pipes[i]);
+ smb_opipe_send_userinfo(sr, opipe, &err);
+ if (err.status != 0) {
+ smb_opipe_dealloc(opipe);
+ return (err.status);
}
- return (NULL);
-}
-
-/*
- * Initialize the opipe header and context, and make the door call.
- */
-static int
-smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
-{
- smb_netuserinfo_t *userinfo = &opipe->p_user;
- smb_user_t *user = sr->uid_user;
- smb_server_t *sv = sr->sr_server;
- uint8_t *buf = opipe->p_doorbuf;
- uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
- uint32_t len;
-
- if ((opipe->p_event = smb_event_create(sv, SMB_EVENT_TIMEOUT)) == NULL)
- return (-1);
-
- smb_user_netinfo_init(user, userinfo);
- len = xdr_sizeof(smb_netuserinfo_xdr, userinfo);
-
- bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
- opipe->p_hdr.dh_magic = SMB_OPIPE_HDR_MAGIC;
- opipe->p_hdr.dh_flags = SMB_DF_SYSSPACE;
- opipe->p_hdr.dh_fid = smb_event_txid(opipe->p_event);
+ /*
+ * Note: If smb_ofile_open succeeds, the new ofile is
+ * in the FID lists can can be used by I/O requests.
+ */
+ op->create_options = 0;
+ op->pipe = opipe;
+ ofile = smb_ofile_open(sr, NULL, op,
+ SMB_FTYPE_MESG_PIPE, uniqid, &err);
+ op->pipe = NULL;
+ if (ofile == NULL) {
+ smb_opipe_dealloc(opipe);
+ return (err.status);
+ }
- if (smb_opipe_sethdr(opipe, SMB_OPIPE_OPEN, len) == -1)
- return (-1);
+ /* An "up" pointer, for debug. */
+ opipe->p_ofile = ofile;
- len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
- buf += len;
- buflen -= len;
+ op->dsize = 0x01000;
+ op->dattr = FILE_ATTRIBUTE_NORMAL;
+ op->ftype = SMB_FTYPE_MESG_PIPE;
+ op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
+ op->devstate = SMB_PIPE_READMODE_MESSAGE
+ | SMB_PIPE_TYPE_MESSAGE
+ | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
+ op->fileid = ofile->f_fid;
- if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1)
- return (-1);
+ sr->smb_fid = ofile->f_fid;
+ sr->fid_ofile = ofile;
- return (smb_opipe_door_call(opipe));
+ return (NT_STATUS_SUCCESS);
}
/*
* smb_opipe_close
*
- * Called whenever an IPC file/pipe is closed.
+ * Called by smb_ofile_close for pipes.
+ *
+ * Note: ksocket_close may block while waiting for
+ * any I/O threads with a hold to get out.
*/
void
smb_opipe_close(smb_ofile_t *of)
{
smb_opipe_t *opipe;
+ ksocket_t sock;
- ASSERT(of);
+ ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
-
opipe = of->f_pipe;
SMB_OPIPE_VALID(opipe);
- (void) smb_server_cancel_event(of->f_server, opipe->p_hdr.dh_fid);
- smb_opipe_enter(opipe);
-
- if (SMB_OPIPE_ISOPEN(opipe)) {
- (void) smb_opipe_sethdr(opipe, SMB_OPIPE_CLOSE, 0);
- (void) smb_opipe_door_call(opipe);
- bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
- kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
- }
-
- smb_user_netinfo_fini(&opipe->p_user);
- smb_opipe_exit(opipe);
-}
-
-static int
-smb_opipe_sethdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen)
-{
- opipe->p_hdr.dh_op = cmd;
- opipe->p_hdr.dh_txid = opipe->p_hdr.dh_fid;
- opipe->p_hdr.dh_datalen = datalen;
- opipe->p_hdr.dh_resid = 0;
- opipe->p_hdr.dh_door_rc = EINVAL;
-
- return (smb_doorhdr_encode(&opipe->p_hdr, opipe->p_doorbuf,
- SMB_OPIPE_DOOR_BUFSIZE));
-}
-
-/*
- * smb_opipe_transact
- *
- * This is the entry point for RPC bind and request transactions.
- * The fid is an arbitrary id used to associate RPC requests with a
- * particular binding handle.
- *
- * If the data to be returned is larger than the client expects, we
- * return as much as the client can handle and report a buffer overflow
- * warning, which informs the client that we have more data to return.
- * The residual data remains in the pipe until the client claims it or
- * closes the pipe.
- */
-smb_sdrc_t
-smb_opipe_transact(smb_request_t *sr, struct uio *uio)
-{
- smb_xa_t *xa;
- smb_opipe_t *opipe;
- struct mbuf *mhead;
- int mdrcnt;
- int nbytes;
- int rc;
-
- if ((rc = smb_opipe_write(sr, uio)) != 0) {
- if (rc == EBADF)
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
- ERRDOS, ERROR_INVALID_HANDLE);
- else
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- opipe = sr->fid_ofile->f_pipe;
-
- if ((rc = smb_opipe_exec(opipe)) != 0) {
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- xa = sr->r_xa;
- mdrcnt = xa->smb_mdrcnt;
- smb_opipe_enter(opipe);
-
- if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) {
- smb_opipe_exit(opipe);
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- rc = smb_opipe_door_call(opipe);
- nbytes = opipe->p_hdr.dh_datalen;
-
- if (rc != 0) {
- smb_opipe_exit(opipe);
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- if (nbytes) {
- mhead = smb_mbuf_get(opipe->p_data, nbytes);
- xa->rep_data_mb.max_bytes = nbytes;
- MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
- }
-
- if (opipe->p_hdr.dh_resid) {
- /*
- * The pipe contains more data than mdrcnt, warn the
- * client that there is more data in the pipe.
- * Typically, the client will call SmbReadX, which
- * will call smb_opipe_read, to get the data.
- */
- smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
- ERRDOS, ERROR_MORE_DATA);
- }
+ mutex_enter(&opipe->p_mutex);
+ sock = opipe->p_socket;
+ opipe->p_socket = NULL;
+ mutex_exit(&opipe->p_mutex);
- smb_opipe_exit(opipe);
- return (SDRC_SUCCESS);
+ (void) ksocket_shutdown(sock, SHUT_RDWR, of->f_cr);
+ (void) ksocket_close(sock, of->f_cr);
}
/*
@@ -398,145 +299,111 @@ smb_opipe_transact(smb_request_t *sr, struct uio *uio)
int
smb_opipe_write(smb_request_t *sr, struct uio *uio)
{
+ struct nmsghdr msghdr;
+ smb_ofile_t *ofile;
smb_opipe_t *opipe;
- uint32_t buflen;
- uint32_t len;
- int rc;
-
- ASSERT(sr->fid_ofile);
- ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ksocket_t sock;
+ size_t sent = 0;
+ int rc = 0;
- opipe = sr->fid_ofile->f_pipe;
+ ofile = sr->fid_ofile;
+ ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ opipe = ofile->f_pipe;
SMB_OPIPE_VALID(opipe);
- smb_opipe_enter(opipe);
- if (!SMB_OPIPE_ISOPEN(opipe)) {
- smb_opipe_exit(opipe);
+ mutex_enter(&opipe->p_mutex);
+ sock = opipe->p_socket;
+ if (sock != NULL)
+ ksocket_hold(sock);
+ mutex_exit(&opipe->p_mutex);
+ if (sock == NULL)
return (EBADF);
- }
- rc = smb_opipe_sethdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid);
- len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
- if (rc == -1 || len == 0) {
- smb_opipe_exit(opipe);
- return (ENOMEM);
- }
+ bzero(&msghdr, sizeof (msghdr));
+ msghdr.msg_iov = uio->uio_iov;
+ msghdr.msg_iovlen = uio->uio_iovcnt;
- buflen = SMB_OPIPE_DOOR_BUFSIZE - len;
- (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio);
+ /*
+ * This should block until we've sent it all,
+ * or given up due to errors (pipe closed).
+ */
+ while (uio->uio_resid > 0) {
+ rc = ksocket_sendmsg(sock, &msghdr, 0, &sent, ofile->f_cr);
+ if (rc != 0)
+ break;
+ uio->uio_resid -= sent;
+ }
- rc = smb_opipe_door_call(opipe);
+ ksocket_rele(sock);
- smb_opipe_exit(opipe);
- return ((rc == 0) ? 0 : EIO);
+ return (rc);
}
/*
* smb_opipe_read
*
- * This interface may be called because smb_opipe_transact could not return
- * all of the data in the original transaction or to form the second half
- * of a transaction set up using smb_opipe_write. Either way, we just need
- * to read data from the pipe and return it.
- *
- * The response data is encoded into raw_data as required by the smb_read
- * functions. The uio_resid value indicates the number of bytes read.
+ * This interface may be called from smb_opipe_transact (write, read)
+ * or from smb_read / smb2_read to get the rest of an RPC response.
+ * The response data (and length) are returned via the uio.
*/
int
smb_opipe_read(smb_request_t *sr, struct uio *uio)
{
+ struct nmsghdr msghdr;
+ smb_ofile_t *ofile;
smb_opipe_t *opipe;
- struct mbuf *mhead;
- uint32_t nbytes;
+ ksocket_t sock;
+ size_t recvcnt = 0;
int rc;
- ASSERT(sr->fid_ofile);
- ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
-
- opipe = sr->fid_ofile->f_pipe;
+ ofile = sr->fid_ofile;
+ ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ opipe = ofile->f_pipe;
SMB_OPIPE_VALID(opipe);
- if ((rc = smb_opipe_exec(opipe)) != 0)
- return (EIO);
-
- smb_opipe_enter(opipe);
-
- if (!SMB_OPIPE_ISOPEN(opipe)) {
- smb_opipe_exit(opipe);
+ mutex_enter(&opipe->p_mutex);
+ sock = opipe->p_socket;
+ if (sock != NULL)
+ ksocket_hold(sock);
+ mutex_exit(&opipe->p_mutex);
+ if (sock == NULL)
return (EBADF);
- }
-
- if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) {
- smb_opipe_exit(opipe);
- return (ENOMEM);
- }
- rc = smb_opipe_door_call(opipe);
- nbytes = opipe->p_hdr.dh_datalen;
+ bzero(&msghdr, sizeof (msghdr));
+ msghdr.msg_iov = uio->uio_iov;
+ msghdr.msg_iovlen = uio->uio_iovcnt;
- if (rc != 0 || nbytes > uio->uio_resid) {
- smb_opipe_exit(opipe);
- return (EIO);
- }
-
- if (nbytes) {
- mhead = smb_mbuf_get(opipe->p_data, nbytes);
- MBC_SETUP(&sr->raw_data, nbytes);
- MBC_ATTACH_MBUF(&sr->raw_data, mhead);
- uio->uio_resid -= nbytes;
+ /*
+ * This should block only if there's no data.
+ * A single call to recvmsg does just that.
+ * (Intentionaly no recv loop here.)
+ */
+ rc = ksocket_recvmsg(sock, &msghdr, 0,
+ &recvcnt, ofile->f_cr);
+ if (rc != 0)
+ goto out;
+
+ if (recvcnt == 0) {
+ /* Other side closed. */
+ rc = EPIPE;
+ goto out;
}
+ uio->uio_resid -= recvcnt;
- smb_opipe_exit(opipe);
- return (rc);
-}
-
-static int
-smb_opipe_exec(smb_opipe_t *opipe)
-{
- uint32_t len;
- int rc;
-
- smb_opipe_enter(opipe);
-
- rc = smb_opipe_sethdr(opipe, SMB_OPIPE_EXEC, 0);
- len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
- if (rc == -1 || len == 0) {
- smb_opipe_exit(opipe);
- return (ENOMEM);
+ /*
+ * If we filled the user's buffer,
+ * find out if there's more data.
+ */
+ if (uio->uio_resid == 0) {
+ int rc2, nread, trval;
+ rc2 = ksocket_ioctl(sock, FIONREAD, (intptr_t)&nread,
+ &trval, ofile->f_cr);
+ if (rc2 == 0 && nread != 0)
+ rc = E2BIG; /* more data */
}
- if ((rc = smb_opipe_door_call(opipe)) == 0)
- rc = smb_event_wait(opipe->p_event);
+out:
+ ksocket_rele(sock);
- smb_opipe_exit(opipe);
return (rc);
}
-
-/*
- * Named pipe I/O is serialized per fid to ensure that each request
- * has exclusive opipe access for the duration of the request.
- */
-static void
-smb_opipe_enter(smb_opipe_t *opipe)
-{
- mutex_enter(&opipe->p_mutex);
-
- while (opipe->p_busy)
- cv_wait(&opipe->p_cv, &opipe->p_mutex);
-
- opipe->p_busy = 1;
- mutex_exit(&opipe->p_mutex);
-}
-
-/*
- * Exit busy state. If we have exec'd an RPC, we may have
- * to wait for notification that processing has completed.
- */
-static void
-smb_opipe_exit(smb_opipe_t *opipe)
-{
- mutex_enter(&opipe->p_mutex);
- opipe->p_busy = 0;
- cv_signal(&opipe->p_cv);
- mutex_exit(&opipe->p_mutex);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe_door.c b/usr/src/uts/common/fs/smbsrv/smb_opipe_door.c
deleted file mode 100644
index 6dc1b8c007..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe_door.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * This module provides the interface to the opipe door.
- * (used by the NDR RPC services).
- */
-
-#include <sys/stat.h>
-#include <sys/door.h>
-#include <sys/door_data.h>
-#include <sys/uio.h>
-#include <sys/ksynch.h>
-#include <smbsrv/smb_kproto.h>
-#include <smbsrv/smb_xdr.h>
-
-#ifdef _FAKE_KERNEL
-#error "See libfksmbsrv"
-#endif /* _FAKE_KERNEL */
-
-static int smb_opipe_door_upcall(smb_opipe_t *);
-
-/*
- * opipe door client (to user space door server).
- */
-void
-smb_opipe_door_init(smb_server_t *sv)
-{
- sv->sv_opipe_door_id = -1;
- mutex_init(&sv->sv_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
- cv_init(&sv->sv_opipe_door_cv, NULL, CV_DEFAULT, NULL);
-}
-
-void
-smb_opipe_door_fini(smb_server_t *sv)
-{
- smb_opipe_door_close(sv);
- cv_destroy(&sv->sv_opipe_door_cv);
- mutex_destroy(&sv->sv_opipe_door_mutex);
-}
-
-/*
- * Open the (user space) door. If the door is already open,
- * close it first because the door-id has probably changed.
- */
-int
-smb_opipe_door_open(smb_server_t *sv, int door_id)
-{
- smb_opipe_door_close(sv);
-
- mutex_enter(&sv->sv_opipe_door_mutex);
- sv->sv_opipe_door_ncall = 0;
-
- if (sv->sv_opipe_door_hd == NULL) {
- sv->sv_opipe_door_id = door_id;
- sv->sv_opipe_door_hd = door_ki_lookup(door_id);
- }
-
- mutex_exit(&sv->sv_opipe_door_mutex);
- return ((sv->sv_opipe_door_hd == NULL) ? -1 : 0);
-}
-
-/*
- * Close the (user space) door.
- */
-void
-smb_opipe_door_close(smb_server_t *sv)
-{
- mutex_enter(&sv->sv_opipe_door_mutex);
-
- if (sv->sv_opipe_door_hd != NULL) {
- while (sv->sv_opipe_door_ncall > 0)
- cv_wait(&sv->sv_opipe_door_cv,
- &sv->sv_opipe_door_mutex);
-
- door_ki_rele(sv->sv_opipe_door_hd);
- sv->sv_opipe_door_hd = NULL;
- }
-
- mutex_exit(&sv->sv_opipe_door_mutex);
-}
-
-/*
- * opipe door call interface.
- * Door serialization and call reference accounting is handled here.
- */
-int
-smb_opipe_door_call(smb_opipe_t *opipe)
-{
- int rc;
- smb_server_t *sv = opipe->p_server;
-
- mutex_enter(&sv->sv_opipe_door_mutex);
-
- if (sv->sv_opipe_door_hd == NULL) {
- mutex_exit(&sv->sv_opipe_door_mutex);
-
- if (smb_opipe_door_open(sv, sv->sv_opipe_door_id) != 0)
- return (-1);
-
- mutex_enter(&sv->sv_opipe_door_mutex);
- }
-
- sv->sv_opipe_door_ncall++;
- mutex_exit(&sv->sv_opipe_door_mutex);
-
- rc = smb_opipe_door_upcall(opipe);
-
- mutex_enter(&sv->sv_opipe_door_mutex);
- if ((--sv->sv_opipe_door_ncall) == 0)
- cv_signal(&sv->sv_opipe_door_cv);
- mutex_exit(&sv->sv_opipe_door_mutex);
- return (rc);
-}
-
-/*
- * Door upcall wrapper - handles data marshalling.
- * This function should only be called by smb_opipe_door_call.
- */
-static int
-smb_opipe_door_upcall(smb_opipe_t *opipe)
-{
- smb_server_t *sv = opipe->p_server;
- door_arg_t da;
- smb_doorhdr_t hdr;
- int i;
- int rc;
-
- da.data_ptr = (char *)opipe->p_doorbuf;
- da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
- da.desc_ptr = NULL;
- da.desc_num = 0;
- da.rbuf = (char *)opipe->p_doorbuf;
- da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
-
- for (i = 0; i < 3; ++i) {
- if (smb_server_is_stopping(sv))
- return (-1);
-
- if ((rc = door_ki_upcall_limited(sv->sv_opipe_door_hd,
- &da, NULL, SIZE_MAX, 0)) == 0)
- break;
-
- if (rc != EAGAIN && rc != EINTR)
- return (-1);
- }
-
- /* Check for door_return(NULL, 0, NULL, 0) */
- if (rc != 0 || da.data_size == 0 || da.rsize == 0)
- return (-1);
-
- if (smb_doorhdr_decode(&hdr, (uint8_t *)da.data_ptr, da.rsize) == -1)
- return (-1);
-
- if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) ||
- (hdr.dh_fid != opipe->p_hdr.dh_fid) ||
- (hdr.dh_op != opipe->p_hdr.dh_op) ||
- (hdr.dh_door_rc != 0) ||
- (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
- return (-1);
- }
-
- opipe->p_hdr.dh_datalen = hdr.dh_datalen;
- opipe->p_hdr.dh_resid = hdr.dh_resid;
- return (0);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_read.c b/usr/src/uts/common/fs/smbsrv/smb_read.c
index c5db79c227..2ac137ca10 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_read.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
@@ -420,7 +421,14 @@ smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
break;
case STYPE_IPC:
+ sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
+ top = smb_mbuf_allocate(&vdb->vdb_uio);
+
rc = smb_opipe_read(sr, &vdb->vdb_uio);
+
+ sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
+ smb_mbuf_trim(top, sr->raw_data.max_bytes);
+ MBC_ATTACH_MBUF(&sr->raw_data, top);
break;
default:
diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c
index 2ac120c137..94eeb396dd 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c
@@ -404,9 +404,6 @@ smb_server_create(void)
cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL);
cv_init(&sv->sp_info.sp_cv, NULL, CV_DEFAULT, NULL);
- smb_llist_constructor(&sv->sv_opipe_list, sizeof (smb_opipe_t),
- offsetof(smb_opipe_t, p_lnd));
-
smb_llist_constructor(&sv->sv_event_list, sizeof (smb_event_t),
offsetof(smb_event_t, se_lnd));
@@ -426,7 +423,6 @@ smb_server_create(void)
smb_kdoor_init(sv);
smb_kshare_init(sv);
- smb_opipe_door_init(sv);
smb_server_kstat_init(sv);
smb_threshold_init(&sv->sv_ssetup_ct, SMB_SSETUP_CMD,
@@ -502,10 +498,8 @@ smb_server_delete(void)
smb_server_listener_destroy(&sv->sv_tcp_daemon);
rw_destroy(&sv->sv_cfg_lock);
smb_server_kstat_fini(sv);
- smb_opipe_door_fini(sv);
smb_kshare_fini(sv);
smb_kdoor_fini(sv);
- smb_llist_destructor(&sv->sv_opipe_list);
smb_llist_destructor(&sv->sv_event_list);
kmem_free(sv->sv_disp_stats,
@@ -619,14 +613,9 @@ smb_server_start(smb_ioc_start_t *ioc)
cmn_err(CE_WARN, "Cannot open smbd door");
break;
}
- if (rc = smb_opipe_door_open(sv, ioc->opipe)) {
- cmn_err(CE_WARN, "Cannot open opipe door");
- break;
- }
#else /* _KERNEL */
/* Fake kernel does not use the kshare_door */
fksmb_kdoor_open(sv, ioc->udoor_func);
- fksmb_opipe_door_open(sv, ioc->opipe_func);
#endif /* _KERNEL */
if (rc = smb_thread_start(&sv->si_thread_timers))
@@ -1413,7 +1402,6 @@ smb_server_shutdown(smb_server_t *sv)
smb_threshold_wake_all(&sv->sv_tcon_ct);
smb_threshold_wake_all(&sv->sv_opipe_ct);
- smb_opipe_door_close(sv);
smb_kdoor_close(sv);
#ifdef _KERNEL
smb_kshare_door_fini(sv->sv_lmshrd);
diff --git a/usr/src/uts/common/smbsrv/ndr.h b/usr/src/uts/common/smbsrv/ndr.h
index 3652c2e0b7..584c0798e4 100644
--- a/usr/src/uts/common/smbsrv/ndr.h
+++ b/usr/src/uts/common/smbsrv/ndr.h
@@ -234,20 +234,6 @@ typedef struct ndr_stream_ops {
#define NDS_RESET(NDS) (*(NDS)->ndo->ndo_reset)(NDS)
#define NDS_DESTRUCT(NDS) (*(NDS)->ndo->ndo_destruct)(NDS)
-typedef struct ndr_frag {
- struct ndr_frag *next;
- uint8_t *buf;
- uint32_t len;
-} ndr_frag_t;
-
-typedef struct ndr_fraglist {
- struct uio uio;
- iovec_t *iov;
- ndr_frag_t *head;
- ndr_frag_t *tail;
- uint32_t nfrag;
-} ndr_fraglist_t;
-
typedef struct ndr_stream {
unsigned long pdu_size;
unsigned long pdu_max_size;
@@ -255,7 +241,6 @@ typedef struct ndr_stream {
unsigned long pdu_scan_offset;
unsigned char *pdu_base_addr;
- ndr_fraglist_t frags;
ndr_stream_ops_t *ndo;
unsigned char m_op;
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index 879b21cdba..122f841a5e 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -375,11 +375,9 @@ int smb_net_txr_send(ksocket_t, smb_txlst_t *, smb_txreq_t *);
/*
* SMB RPC interface
*/
-smb_opipe_t *smb_opipe_alloc(smb_server_t *);
void smb_opipe_dealloc(smb_opipe_t *);
-int smb_opipe_open(smb_request_t *);
+int smb_opipe_open(smb_request_t *, uint32_t);
void smb_opipe_close(smb_ofile_t *);
-smb_sdrc_t smb_opipe_transact(smb_request_t *, struct uio *);
int smb_opipe_read(smb_request_t *, struct uio *);
int smb_opipe_write(smb_request_t *, struct uio *);
@@ -598,7 +596,7 @@ void smb_request_free(smb_request_t *);
smb_ofile_t *smb_ofile_lookup_by_fid(smb_request_t *, uint16_t);
smb_ofile_t *smb_ofile_lookup_by_uniqid(smb_tree_t *, uint32_t);
boolean_t smb_ofile_disallow_fclose(smb_ofile_t *);
-smb_ofile_t *smb_ofile_open(smb_request_t *, smb_node_t *, uint16_t,
+smb_ofile_t *smb_ofile_open(smb_request_t *, smb_node_t *,
smb_arg_open_t *, uint16_t, uint32_t, smb_error_t *);
void smb_ofile_close(smb_ofile_t *, int32_t);
void smb_ofile_delete(void *);
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 74e2b9f437..64f96db9bd 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -1132,6 +1132,7 @@ typedef struct smb_tree {
#define SMB_OPIPE_MAGIC 0x50495045 /* 'PIPE' */
#define SMB_OPIPE_VALID(p) \
ASSERT(((p) != NULL) && (p)->p_magic == SMB_OPIPE_MAGIC)
+#define SMB_OPIPE_MAXNAME 32
/*
* Data structure for SMB_FTYPE_MESG_PIPE ofiles, which is used
@@ -1139,17 +1140,14 @@ typedef struct smb_tree {
*/
typedef struct smb_opipe {
uint32_t p_magic;
- list_node_t p_lnd;
kmutex_t p_mutex;
kcondvar_t p_cv;
+ struct smb_ofile *p_ofile;
struct smb_server *p_server;
- struct smb_event *p_event;
- char *p_name;
- uint32_t p_busy;
- smb_doorhdr_t p_hdr;
- smb_netuserinfo_t p_user;
- uint8_t *p_doorbuf;
- uint8_t *p_data;
+ uint32_t p_refcnt;
+ ksocket_t p_socket;
+ /* This is the "flat" name, without path prefix */
+ char p_name[SMB_OPIPE_MAXNAME];
} smb_opipe_t;
/*
@@ -1439,8 +1437,8 @@ typedef struct open_param {
uint64_t fileid;
uint32_t rootdirfid;
smb_ofile_t *dir;
- /* This is only set by NTTransactCreate */
- struct smb_sd *sd;
+ smb_opipe_t *pipe; /* for smb_opipe_open */
+ struct smb_sd *sd; /* for NTTransactCreate */
uint8_t op_oplock_level; /* requested/granted level */
boolean_t op_oplock_levelII; /* TRUE if levelII supported */
} smb_arg_open_t;
@@ -1642,6 +1640,14 @@ typedef struct smb_request {
struct smb_ofile *fid_ofile;
smb_user_t *uid_user;
+ cred_t *user_cr;
+ kthread_t *sr_worker;
+ hrtime_t sr_time_submitted;
+ hrtime_t sr_time_active;
+ hrtime_t sr_time_start;
+ int32_t sr_txb;
+ uint32_t sr_seqnum;
+
union {
smb_arg_negotiate_t *negprot;
smb_arg_sessionsetup_t *ssetup;
@@ -1651,14 +1657,6 @@ typedef struct smb_request {
smb_rw_param_t *rw;
int32_t timestamp;
} arg;
-
- cred_t *user_cr;
- kthread_t *sr_worker;
- hrtime_t sr_time_submitted;
- hrtime_t sr_time_active;
- hrtime_t sr_time_start;
- int32_t sr_txb;
- uint32_t sr_seqnum;
} smb_request_t;
#define sr_ssetup arg.ssetup
@@ -1859,13 +1857,6 @@ typedef struct smb_server {
kmutex_t sv_kdoor_mutex;
kcondvar_t sv_kdoor_cv;
- /* RPC pipes (client side) */
- struct __door_handle *sv_opipe_door_hd;
- int sv_opipe_door_id;
- uint64_t sv_opipe_door_ncall;
- kmutex_t sv_opipe_door_mutex;
- kcondvar_t sv_opipe_door_cv;
-
int32_t si_gmtoff;
smb_thread_t si_thread_timers;
diff --git a/usr/src/uts/common/smbsrv/smb_share.h b/usr/src/uts/common/smbsrv/smb_share.h
index 2ca97856c0..319be08801 100644
--- a/usr/src/uts/common/smbsrv/smb_share.h
+++ b/usr/src/uts/common/smbsrv/smb_share.h
@@ -47,6 +47,9 @@ extern "C" {
#define SMB_SYSTEM32 SMB_SYSROOT "/system32"
#define SMB_VSS SMB_SYSTEM32 "/vss"
+/* Exported named pipes are in... */
+#define SMB_PIPE_DIR "/var/smb/pipe"
+
/*
* Share Properties:
*
diff --git a/usr/src/uts/common/smbsrv/smb_xdr.h b/usr/src/uts/common/smbsrv/smb_xdr.h
index 8990884b19..e4df610969 100644
--- a/usr/src/uts/common/smbsrv/smb_xdr.h
+++ b/usr/src/uts/common/smbsrv/smb_xdr.h
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_SMB_XDR_H
@@ -60,21 +60,27 @@ typedef struct smb_string {
struct smb_buf32;
-#define SMB_OPIPE_HDR_MAGIC 0x4F484452 /* OHDR */
-#define SMB_OPIPE_DOOR_BUFSIZE (30 * 1024)
+/*
+ * Initial message on server named pipes.
+ * Followed by smb_netuserinfo
+ */
+typedef struct smb_pipehdr {
+ uint32_t ph_magic;
+ uint32_t ph_uilen;
+} smb_pipehdr_t;
+
+#define SMB_PIPE_HDR_MAGIC 0x50495045 /* PIPE */
/*
- * Door operations for opipes.
+ * Maximum message size for SMB named pipes.
+ * Should be less than PIPE_BUF (5120).
+ * Use the same value Windows does.
+ */
+#define SMB_PIPE_MAX_MSGSIZE 4280
+
+/*
+ * Door up-call stuff shared with smbd
*/
-typedef enum {
- SMB_OPIPE_NULL = 0,
- SMB_OPIPE_LOOKUP,
- SMB_OPIPE_OPEN,
- SMB_OPIPE_CLOSE,
- SMB_OPIPE_READ,
- SMB_OPIPE_WRITE,
- SMB_OPIPE_EXEC
-} smb_opipe_op_t;
#define SMB_DOOR_HDR_MAGIC 0x444F4F52 /* DOOR */