summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <Gordon.Ross@Sun.COM>2010-06-04 16:34:40 -0400
committerGordon Ross <Gordon.Ross@Sun.COM>2010-06-04 16:34:40 -0400
commita547be5daca7e465ca82df6d179f6b1f8e0cda72 (patch)
tree1de43ca9ce086e2e22f5d71d8dc2c9f96ae8c0d2
parentbc6a100fe6399f4a72c84c38df0fc9a960ded814 (diff)
downloadillumos-gate-a547be5daca7e465ca82df6d179f6b1f8e0cda72.tar.gz
6944209 Let smbiod run as a service
6948083 Better logging of bad SMB signatures
-rw-r--r--usr/src/cmd/fs.d/smbclnt/Makefile8
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbiod-svc/Makefile57
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbiod-svc/smbiod-svc.c591
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbiod/Makefile7
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c149
-rw-r--r--usr/src/cmd/fs.d/smbclnt/svc/client.xml45
-rw-r--r--usr/src/cmd/fs.d/smbclnt/svc/smb-client23
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h8
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_cl.c112
-rw-r--r--usr/src/lib/libsmbfs/smb/nbns_rq.c6
-rw-r--r--usr/src/pkg/manifests/system-file-system-smb.mf1
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c10
12 files changed, 844 insertions, 173 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/Makefile b/usr/src/cmd/fs.d/smbclnt/Makefile
index 3d02a554b3..4acc9e9f27 100644
--- a/usr/src/cmd/fs.d/smbclnt/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/Makefile
@@ -20,8 +20,7 @@
#
#
-# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
#
#
@@ -31,8 +30,9 @@
include $(SRC)/Makefile.master
-SUBDIRS_CATALOG= smbutil smbiod mount umount
-SUBDIRS= $(SUBDIRS_CATALOG) chacl lsacl svc
+SUBDIRS_CATALOG= smbutil mount umount
+SUBDIRS= $(SUBDIRS_CATALOG) chacl lsacl \
+ smbiod smbiod-svc svc
# for messaging catalog files
#
diff --git a/usr/src/cmd/fs.d/smbclnt/smbiod-svc/Makefile b/usr/src/cmd/fs.d/smbclnt/smbiod-svc/Makefile
new file mode 100644
index 0000000000..29155e44f8
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod-svc/Makefile
@@ -0,0 +1,57 @@
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# cmd/fs.d/smbclnt/smbiod-svc/Makefile
+#
+
+FSTYPE= smbfs
+TYPEPROG= smbiod-svc
+
+include ../../Makefile.fstype
+
+OBJS= $(TYPEPROG).o
+SRCS= $(TYPEPROG).c
+POFILE= $(TYPEPROG).po
+
+CFLAGS += $(CCVERBOSE)
+C99MODE= $(C99_ENABLE)
+
+CPPFLAGS += -I$(SRC)/lib/libsmbfs \
+ -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
+
+# Debugging
+${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
+
+all: $(TYPEPROG)
+
+catalog: $(POFILE)
+
+lint: lint_SRCS
+
+clean:
+ $(RM) $(OBJS) $(POFILE)
+
+.KEEP_STATE:
diff --git a/usr/src/cmd/fs.d/smbclnt/smbiod-svc/smbiod-svc.c b/usr/src/cmd/fs.d/smbclnt/smbiod-svc/smbiod-svc.c
new file mode 100644
index 0000000000..d99e04ba8d
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod-svc/smbiod-svc.c
@@ -0,0 +1,591 @@
+/*
+ * 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) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * SMBFS I/O Daemon (SMF service)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/note.h>
+#include <sys/queue.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <synch.h>
+#include <time.h>
+#include <unistd.h>
+#include <ucred.h>
+#include <wait.h>
+#include <priv_utils.h>
+#include <err.h>
+#include <door.h>
+#include <libscf.h>
+#include <locale.h>
+#include <thread.h>
+#include <assert.h>
+
+#include <netsmb/smb_lib.h>
+
+static boolean_t d_flag = B_FALSE;
+
+/* Keep a list of child processes. */
+typedef struct _child {
+ LIST_ENTRY(_child) list;
+ pid_t pid;
+ uid_t uid;
+} child_t;
+static LIST_HEAD(, _child) child_list = { 0 };
+mutex_t cl_mutex = DEFAULTMUTEX;
+
+static const char smbiod_path[] = "/usr/lib/smbfs/smbiod";
+static const char door_path[] = SMBIOD_SVC_DOOR;
+
+void svc_dispatch(void *cookie, char *argp, size_t argsz,
+ door_desc_t *dp, uint_t n_desc);
+static int cmd_start(uid_t uid, gid_t gid);
+static int new_child(uid_t uid, gid_t gid);
+static void svc_sigchld(void);
+static void child_gone(uid_t, pid_t, int);
+static void svc_cleanup(void);
+
+static child_t *
+child_find_by_pid(pid_t pid)
+{
+ child_t *cp;
+
+ assert(MUTEX_HELD(&cl_mutex));
+ LIST_FOREACH(cp, &child_list, list) {
+ if (cp->pid == pid)
+ return (cp);
+ }
+ return (NULL);
+}
+
+static child_t *
+child_find_by_uid(uid_t uid)
+{
+ child_t *cp;
+
+ assert(MUTEX_HELD(&cl_mutex));
+ LIST_FOREACH(cp, &child_list, list) {
+ if (cp->uid == uid)
+ return (cp);
+ }
+ return (NULL);
+}
+
+/*
+ * Find out if the service is already running.
+ * Return: true, false.
+ */
+static boolean_t
+already_running(void)
+{
+ door_info_t info;
+ int fd, rc;
+
+ if ((fd = open(door_path, O_RDONLY)) < 0)
+ return (B_FALSE);
+
+ rc = door_info(fd, &info);
+ close(fd);
+ if (rc < 0)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * This function will fork off a child process,
+ * from which only the child will return.
+ *
+ * The parent exit status is taken as the SMF start method
+ * success or failure, so the parent waits (via pipe read)
+ * for the child to finish initialization before it exits.
+ * Use SMF error codes only on exit.
+ */
+static int
+daemonize_init(void)
+{
+ int pid, st;
+ int pfds[2];
+
+ chdir("/");
+
+ if (pipe(pfds) < 0) {
+ perror("pipe");
+ exit(SMF_EXIT_ERR_FATAL);
+ }
+ if ((pid = fork1()) == -1) {
+ perror("fork");
+ exit(SMF_EXIT_ERR_FATAL);
+ }
+
+ /*
+ * If we're the parent process, wait for either the child to send us
+ * the appropriate exit status over the pipe or for the read to fail
+ * (presumably with 0 for EOF if our child terminated abnormally).
+ * If the read fails, exit with either the child's exit status if it
+ * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
+ */
+ if (pid != 0) {
+ /* parent */
+ close(pfds[1]);
+ if (read(pfds[0], &st, sizeof (st)) == sizeof (st))
+ _exit(st);
+ if (waitpid(pid, &st, 0) == pid && WIFEXITED(st))
+ _exit(WEXITSTATUS(st));
+ _exit(SMF_EXIT_ERR_FATAL);
+ }
+
+ /* child */
+ close(pfds[0]);
+
+ return (pfds[1]);
+}
+
+static void
+daemonize_fini(int pfd, int rc)
+{
+ /* Tell parent we're ready. */
+ (void) write(pfd, &rc, sizeof (rc));
+ close(pfd);
+}
+
+int
+main(int argc, char **argv)
+{
+ sigset_t oldmask, tmpmask;
+ struct sigaction sa;
+ struct rlimit rl;
+ int door_fd = -1, tmp_fd = -1, pfd = -1;
+ int c, sig;
+ int rc = SMF_EXIT_ERR_FATAL;
+ boolean_t created = B_FALSE, attached = B_FALSE;
+
+ /* set locale and text domain for i18n */
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ while ((c = getopt(argc, argv, "d")) != -1) {
+ switch (c) {
+ case 'd':
+ /* Do debug messages. */
+ d_flag = B_TRUE;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-d]\n", argv[0]);
+ return (SMF_EXIT_ERR_CONFIG);
+ }
+ }
+
+ if (already_running()) {
+ fprintf(stderr, "%s: already running", argv[0]);
+ return (rc);
+ }
+
+ /*
+ * Raise the fd limit to max
+ * errors here are non-fatal
+ */
+ if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
+ fprintf(stderr, "getrlimit failed, err %d\n", errno);
+ } else if (rl.rlim_cur < rl.rlim_max) {
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
+ fprintf(stderr, "setrlimit "
+ "RLIMIT_NOFILE %d, err %d",
+ (int)rl.rlim_cur, errno);
+ }
+
+ /*
+ * Want all signals blocked, as we're doing
+ * synchronous delivery via sigwait below.
+ */
+ sigfillset(&tmpmask);
+ sigprocmask(SIG_BLOCK, &tmpmask, &oldmask);
+
+ /*
+ * Do want SIGCHLD, and will waitpid().
+ */
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_DFL;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGCHLD, &sa, NULL);
+
+ /*
+ * Daemonize, unless debugging.
+ */
+ if (d_flag) {
+ /* debug: run in foregound (not a service) */
+ putenv("SMBFS_DEBUG=1");
+ } else {
+ /* Non-debug: start daemon in the background. */
+ pfd = daemonize_init();
+ }
+
+ /*
+ * Create directory for all smbiod doors.
+ */
+ if ((mkdir(SMBIOD_RUNDIR, 0755) < 0) && errno != EEXIST) {
+ perror(SMBIOD_RUNDIR);
+ goto out;
+ }
+
+ /*
+ * Create a file for the main service door.
+ */
+ unlink(door_path);
+ tmp_fd = open(door_path, O_RDWR|O_CREAT|O_EXCL, 0644);
+ if (tmp_fd < 0) {
+ perror(door_path);
+ goto out;
+ }
+ close(tmp_fd);
+ tmp_fd = -1;
+ created = B_TRUE;
+
+ /* Setup the door service. */
+ door_fd = door_create(svc_dispatch, NULL,
+ DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
+ if (door_fd == -1) {
+ perror("svc door_create");
+ goto out;
+ }
+ fdetach(door_path);
+ if (fattach(door_fd, door_path) < 0) {
+ fprintf(stderr, "%s: fattach failed, %s\n",
+ door_path, strerror(errno));
+ goto out;
+ }
+ attached = B_TRUE;
+
+ /*
+ * Initializations done. Tell start method we're up.
+ */
+ rc = SMF_EXIT_OK;
+ if (pfd != -1) {
+ daemonize_fini(pfd, rc);
+ pfd = -1;
+ }
+
+ /*
+ * Main thread just waits for signals.
+ */
+again:
+ sig = sigwait(&tmpmask);
+ if (d_flag)
+ fprintf(stderr, "main: sig=%d\n", sig);
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ /*
+ * The whole process contract gets a SIGTERM
+ * at once. Give children a chance to exit
+ * so we can do normal SIGCHLD cleanup.
+ * Prevent new door_open calls.
+ */
+ fdetach(door_path);
+ attached = B_FALSE;
+ alarm(2);
+ goto again;
+ case SIGALRM:
+ break; /* normal termination */
+ case SIGCHLD:
+ svc_sigchld();
+ goto again;
+ case SIGCONT:
+ goto again;
+ default:
+ /* Unexpected signal. */
+ fprintf(stderr, "svc_main: unexpected sig=%d\n", sig);
+ break;
+ }
+
+out:
+ if (attached)
+ fdetach(door_path);
+ if (door_fd != -1)
+ door_revoke(door_fd);
+ if (created)
+ unlink(door_path);
+
+ /* NB: door threads gone now. */
+ svc_cleanup();
+
+ /* If startup error, report to parent. */
+ if (pfd != -1)
+ daemonize_fini(pfd, rc);
+
+ return (rc);
+}
+
+/*ARGSUSED*/
+void
+svc_dispatch(void *cookie, char *argp, size_t argsz,
+ door_desc_t *dp, uint_t n_desc)
+{
+ ucred_t *ucred = NULL;
+ uid_t uid;
+ gid_t gid;
+ int32_t cmd, rc;
+
+ /*
+ * Allow a NULL arg call to check if this
+ * daemon is running. Just return zero.
+ */
+ if (argp == NULL) {
+ rc = 0;
+ goto out;
+ }
+
+ /*
+ * Get the caller's credentials.
+ * (from client side of door)
+ */
+ if (door_ucred(&ucred) != 0) {
+ rc = EACCES;
+ goto out;
+ }
+ uid = ucred_getruid(ucred);
+ gid = ucred_getrgid(ucred);
+
+ /*
+ * Arg is just an int command code.
+ * Reply is also an int.
+ */
+ if (argsz != sizeof (cmd)) {
+ rc = EINVAL;
+ goto out;
+ }
+ bcopy(argp, &cmd, sizeof (cmd));
+ switch (cmd) {
+ case SMBIOD_START:
+ rc = cmd_start(uid, gid);
+ break;
+ default:
+ rc = EINVAL;
+ goto out;
+ }
+
+out:
+ if (ucred != NULL)
+ ucred_free(ucred);
+
+ door_return((void *)&rc, sizeof (rc), NULL, 0);
+}
+
+/*
+ * Start a per-user smbiod, if not already running.
+ */
+int
+cmd_start(uid_t uid, gid_t gid)
+{
+ char door_file[64];
+ child_t *cp;
+ int pid, fd = -1;
+
+ mutex_lock(&cl_mutex);
+ cp = child_find_by_uid(uid);
+ if (cp != NULL) {
+ /* This UID already has an IOD. */
+ mutex_unlock(&cl_mutex);
+ if (d_flag) {
+ fprintf(stderr, "cmd_start: uid %d"
+ " already has an iod\n", uid);
+ }
+ return (0);
+ }
+
+ /*
+ * OK, create a new child.
+ */
+ cp = malloc(sizeof (*cp));
+ if (cp == NULL) {
+ mutex_unlock(&cl_mutex);
+ return (ENOMEM);
+ }
+ cp->pid = 0; /* update below */
+ cp->uid = uid;
+ LIST_INSERT_HEAD(&child_list, cp, list);
+ mutex_unlock(&cl_mutex);
+
+ /*
+ * The child will not have permission to create or
+ * destroy files in SMBIOD_RUNDIR so do that here.
+ */
+ snprintf(door_file, sizeof (door_file),
+ SMBIOD_USR_DOOR, cp->uid);
+ unlink(door_file);
+ fd = open(door_file, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (fd < 0) {
+ perror(door_file);
+ goto errout;
+ }
+ if (fchown(fd, uid, gid) < 0) {
+ perror(door_file);
+ goto errout;
+ }
+ close(fd);
+ fd = -1;
+
+ if ((pid = fork1()) == -1) {
+ perror("fork");
+ goto errout;
+ }
+ if (pid == 0) {
+ (void) new_child(uid, gid);
+ _exit(1);
+ }
+ /* parent */
+ cp->pid = pid;
+
+ if (d_flag) {
+ fprintf(stderr, "cmd_start: uid %d new iod, pid %d\n",
+ uid, pid);
+ }
+
+ return (0);
+
+errout:
+ if (fd != -1)
+ close(fd);
+ mutex_lock(&cl_mutex);
+ LIST_REMOVE(cp, list);
+ mutex_unlock(&cl_mutex);
+ free(cp);
+ return (errno);
+}
+
+/*
+ * Assume the passed credentials (from the door client),
+ * drop any extra privileges, and exec the per-user iod.
+ */
+static int
+new_child(uid_t uid, gid_t gid)
+{
+ char *argv[2];
+ int flags, rc;
+
+ flags = PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS;
+ rc = __init_daemon_priv(flags, uid, gid, PRIV_NET_ACCESS, NULL);
+ if (rc != 0)
+ return (errno);
+
+ argv[0] = "smbiod";
+ argv[1] = NULL;
+ (void) execv(smbiod_path, argv);
+ return (errno);
+}
+
+static void
+svc_sigchld(void)
+{
+ child_t *cp;
+ pid_t pid;
+ int err, status, found = 0;
+
+ mutex_lock(&cl_mutex);
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+
+ found++;
+ if (d_flag)
+ fprintf(stderr, "svc_sigchld: pid %d\n", (int)pid);
+
+ cp = child_find_by_pid(pid);
+ if (cp == NULL) {
+ fprintf(stderr, "Unknown pid %d\n", (int)pid);
+ continue;
+ }
+ child_gone(cp->uid, cp->pid, status);
+ LIST_REMOVE(cp, list);
+ free(cp);
+ }
+ err = errno;
+
+ mutex_unlock(&cl_mutex);
+
+ /* ECHILD is the normal end of loop. */
+ if (pid < 0 && err != ECHILD)
+ fprintf(stderr, "svc_sigchld: waitpid err %d\n", err);
+ if (found == 0)
+ fprintf(stderr, "svc_sigchld: no children?\n");
+}
+
+static void
+child_gone(uid_t uid, pid_t pid, int status)
+{
+ char door_file[64];
+ int x;
+
+ if (d_flag)
+ fprintf(stderr, "child_gone: uid %d pid %d\n",
+ uid, (int)pid);
+
+ snprintf(door_file, sizeof (door_file),
+ SMBIOD_RUNDIR "/%d", uid);
+ unlink(door_file);
+
+ if (WIFEXITED(status)) {
+ x = WEXITSTATUS(status);
+ if (x != 0) {
+ fprintf(stderr,
+ "uid %d, pid %d exit %d",
+ uid, (int)pid, x);
+ }
+ }
+ if (WIFSIGNALED(status)) {
+ x = WTERMSIG(status);
+ fprintf(stderr,
+ "uid %d, pid %d signal %d",
+ uid, (int)pid, x);
+ }
+}
+
+/*
+ * Final cleanup before exit. Unlink child doors, etc.
+ * Called while single threaded, so no locks needed here.
+ * The list is normally empty by now due to svc_sigchld
+ * calls during shutdown. But in case there were any
+ * straglers, do cleanup here. Don't bother freeing any
+ * list elements here, as we're exiting.
+ */
+static void
+svc_cleanup(void)
+{
+ child_t *cp;
+
+ LIST_FOREACH(cp, &child_list, list) {
+ child_gone(cp->uid, cp->pid, 0);
+ }
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile b/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile
index 40f531f3e7..f54d107d49 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile
@@ -20,8 +20,7 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
#
@@ -37,14 +36,12 @@ OBJS= $(TYPEPROG).o
SRCS= $(TYPEPROG).c
POFILE= $(TYPEPROG).po
-CLOBBERFILES += $(TYPEPROG)
-
CFLAGS += $(CCVERBOSE)
C99MODE= $(C99_ENABLE)
# This is a multi-thread program but Nevada
# no longer needs -lthread
-LDLIBS += -lsmbfs
+LDLIBS += -lsmbfs -lumem
CPPFLAGS += -I$(SRC)/lib/libsmbfs \
-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
diff --git a/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c b/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c
index 1afb19d3ff..5296cb2be9 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c
@@ -24,7 +24,7 @@
*/
/*
- * SMBFS I/O Deamon (smbiod)
+ * SMBFS I/O Daemon (Per-user IOD)
*/
#include <sys/types.h>
@@ -43,26 +43,20 @@
#include <time.h>
#include <unistd.h>
#include <ucred.h>
-
#include <err.h>
#include <door.h>
+#include <libscf.h>
+#include <locale.h>
#include <thread.h>
#include <netsmb/smb_lib.h>
-#define EXIT_FAIL 1
-#define EXIT_OK 0
-
-#if defined(DEBUG) || defined(__lint)
#define DPRINT(...) do \
{ \
if (smb_debug) \
fprintf(stderr, __VA_ARGS__); \
_NOTE(CONSTCOND) \
} while (0)
-#else
-#define DPRINT(...) ((void)0)
-#endif
mutex_t iod_mutex = DEFAULTMUTEX;
int iod_thr_count; /* threads, excluding main */
@@ -77,13 +71,16 @@ void * iod_work(void *arg);
int
main(int argc, char **argv)
{
- static const int door_attrs =
- DOOR_REFUSE_DESC | DOOR_NO_CANCEL;
sigset_t oldmask, tmpmask;
char *env, *door_path = NULL;
- int door_fd = -1, tmp_fd = -1;
- int err, i, sig;
- int rc = EXIT_FAIL;
+ int door_fd = -1;
+ int err, sig;
+ int rc = SMF_EXIT_ERR_FATAL;
+ boolean_t attached = B_FALSE;
+
+ /* set locale and text domain for i18n */
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
/* Debugging support. */
if ((env = getenv("SMBFS_DEBUG")) != NULL) {
@@ -94,75 +91,42 @@ main(int argc, char **argv)
}
/*
- * Find out if an IOD is already running.
- * If so, we lost a harmless startup race.
- * An IOD did start, so exit success.
+ * If a user runs this command (i.e. by accident)
+ * don't interfere with any already running IOD.
*/
err = smb_iod_open_door(&door_fd);
if (err == 0) {
close(door_fd);
door_fd = -1;
- DPRINT("main: already running\n");
- exit(EXIT_OK);
+ DPRINT("%s: already running\n", argv[0]);
+ exit(SMF_EXIT_OK);
}
/*
- * Create a file for the door.
- */
- door_path = smb_iod_door_path();
- unlink(door_path);
- tmp_fd = open(door_path, O_RDWR|O_CREAT|O_EXCL, 0600);
- if (tmp_fd < 0) {
- perror(door_path);
- exit(EXIT_FAIL);
- }
- close(tmp_fd);
- tmp_fd = -1;
-
-
- /*
- * Close FDs 0,1,2 so we don't have a TTY, and
- * re-open them on /dev/null so they won't be
- * used for device handles (etc.) later, and
- * we don't have to worry about printf calls
- * or whatever going to these FDs.
- */
- for (i = 0; i < 3; i++) {
- /* Exception: If smb_debug, keep stderr */
- if (smb_debug && i == 2)
- break;
- close(i);
- tmp_fd = open("/dev/null", O_RDWR);
- if (tmp_fd < 0)
- perror("/dev/null");
- if (tmp_fd != i)
- DPRINT("Open /dev/null - wrong fd?\n");
- }
-
- /*
- * Become session leader.
- */
- setsid();
-
- /*
- * Create door service threads with signals blocked.
+ * Want all signals blocked, as we're doing
+ * synchronous delivery via sigwait below.
*/
sigfillset(&tmpmask);
sigprocmask(SIG_BLOCK, &tmpmask, &oldmask);
/* Setup the door service. */
- door_fd = door_create(iod_dispatch, NULL, door_attrs);
- if (door_fd < 0) {
- fprintf(stderr, "%s: door_create failed\n", argv[0]);
- rc = EXIT_FAIL;
- goto errout;
+ door_path = smb_iod_door_path();
+ door_fd = door_create(iod_dispatch, NULL,
+ DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
+ if (door_fd == -1) {
+ perror("iod door_create");
+ goto out;
}
fdetach(door_path);
if (fattach(door_fd, door_path) < 0) {
- fprintf(stderr, "%s: fattach failed\n", argv[0]);
- rc = EXIT_FAIL;
- goto errout;
+ fprintf(stderr, "%s: fattach failed, %s\n",
+ door_path, strerror(errno));
+ goto out;
}
+ attached = B_TRUE;
+
+ /* Initializations done. */
+ rc = SMF_EXIT_OK;
/*
* Post the initial alarm, and then just
@@ -172,25 +136,48 @@ main(int argc, char **argv)
again:
sig = sigwait(&tmpmask);
DPRINT("main: sig=%d\n", sig);
+ switch (sig) {
+ case SIGCONT:
+ goto again;
- /*
- * If a door call races with the alarm, ignore the alarm.
- * It will be rescheduled when the threads go away.
- */
- mutex_lock(&iod_mutex);
- if (sig == SIGALRM && iod_thr_count > 0) {
+ case SIGALRM:
+ /* No threads active for a while. */
+ mutex_lock(&iod_mutex);
+ if (iod_thr_count > 0) {
+ /*
+ * Door call thread creation raced with
+ * the alarm. Ignore this alaram.
+ */
+ mutex_unlock(&iod_mutex);
+ goto again;
+ }
+ /* Prevent a race with iod_thr_count */
+ iod_terminating = 1;
mutex_unlock(&iod_mutex);
- goto again;
+ break;
+
+ case SIGINT:
+ case SIGTERM:
+ break; /* normal termination */
+
+ default:
+ /* Unexpected signal. */
+ fprintf(stderr, "iod_main: unexpected sig=%d\n", sig);
+ break;
}
+
+out:
iod_terminating = 1;
- mutex_unlock(&iod_mutex);
- rc = EXIT_OK;
+ if (attached)
+ fdetach(door_path);
+ if (door_fd != -1)
+ door_revoke(door_fd);
-errout:
- fdetach(door_path);
- door_revoke(door_fd);
- door_fd = -1;
- unlink(door_path);
+ /*
+ * We need a reference in -lumem to satisfy check_rtime,
+ * else we get build hoise. This is sufficient.
+ */
+ free(NULL);
return (rc);
}
@@ -226,7 +213,7 @@ iod_dispatch(void *cookie, char *argp, size_t argsz,
/*
* The library uses a NULL arg call to check if
- * the deamon is running. Just return zero.
+ * the daemon is running. Just return zero.
*/
if (argp == NULL) {
rc = 0;
diff --git a/usr/src/cmd/fs.d/smbclnt/svc/client.xml b/usr/src/cmd/fs.d/smbclnt/svc/client.xml
index 8aad037c37..f8b601ca62 100644
--- a/usr/src/cmd/fs.d/smbclnt/svc/client.xml
+++ b/usr/src/cmd/fs.d/smbclnt/svc/client.xml
@@ -1,8 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<!--
- Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- Use is subject to license terms.
+ Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
CDDL HEADER START
@@ -75,33 +74,27 @@
<service_fmri value='svc:/milestone/multi-user' />
</dependent>
- <!--
- Err on the side of caution for the mountalls in the smb-client
- startup script. Don't timeout just because remote servers are
- being sluggish.
- -->
<exec_method
- type='method'
- name='start'
- exec='/lib/svc/method/smb-client %m'
- timeout_seconds='300' />
+ type='method'
+ name='start'
+ exec='/lib/svc/method/smb-client %m'
+ timeout_seconds='60' />
<exec_method
- type='method'
- name='stop'
- exec='/lib/svc/method/smb-client %m'
- timeout_seconds='60' />
-
- <property_group name='general' type='framework'>
- <!-- To Start/Stop/Refresh the service -->
- <propval name='action_authorization' type='astring'
- value='solaris.smf.manage.smbfs' />
- </property_group>
-
- <property_group
- name='startd'
- type='framework'>
- <propval name='duration' type='astring' value='transient' />
+ type='method'
+ name='stop'
+ exec='/lib/svc/method/smb-client %m %{restarter/contract}'
+ timeout_seconds='60' />
+
+ <property_group name='general' type='framework'>
+ <!-- To Start/Stop/Refresh the service -->
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.smbfs' />
+ </property_group>
+
+ <property_group name='application' type='framework'>
+ <stability value='Evolving' />
+ <propval name='auto_enable' type='boolean' value='true' />
</property_group>
<stability value='Unstable' />
diff --git a/usr/src/cmd/fs.d/smbclnt/svc/smb-client b/usr/src/cmd/fs.d/smbclnt/svc/smb-client
index 5f45dbfbac..192cedafd2 100644
--- a/usr/src/cmd/fs.d/smbclnt/svc/smb-client
+++ b/usr/src/cmd/fs.d/smbclnt/svc/smb-client
@@ -19,11 +19,10 @@
#
# CDDL HEADER END
#
+
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
#
-#ident "%Z%%M% %I% %E% SMI"
#
# Start/stop client SMB service
@@ -31,19 +30,29 @@
. /lib/svc/share/smf_include.sh
+result=${SMF_EXIT_OK}
+
case "$1" in
'start')
-
- /sbin/mountall -F smbfs
+ # Start the main smbiod service
+ /usr/lib/smbfs/smbiod-svc
+ result=$?
+ # Do smbfs mounts (background)
+ /usr/bin/ctrun -l none \
+ /sbin/mountall -F smbfs
;;
'stop')
+ # First destroy the mounts,
/sbin/umountall -F smbfs
+ # then kill the smbiod service.
+ smf_kill_contract $2 TERM 1
+ result=$?
;;
*)
echo "Usage: $0 { start | stop }"
- exit 1
+ result=1
;;
esac
-exit $SMF_EXIT_OK
+exit $result
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index 2f7d986adf..1933fdbb6b 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -33,8 +33,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -188,6 +187,11 @@ int smb_ctx_newvc(struct smb_ctx *);
* I/O daemon stuff
*/
+#define SMBIOD_RUNDIR "/var/run/smbiod"
+#define SMBIOD_SVC_DOOR SMBIOD_RUNDIR "/.svc"
+#define SMBIOD_USR_DOOR SMBIOD_RUNDIR "/%d"
+#define SMBIOD_START 1
+
int smb_iod_cl_newvc(smb_ctx_t *ctx);
char *smb_iod_door_path(void);
int smb_iod_open_door(int *);
diff --git a/usr/src/lib/libsmbfs/smb/iod_cl.c b/usr/src/lib/libsmbfs/smb/iod_cl.c
index 7449d68ed5..dbc2931807 100644
--- a/usr/src/lib/libsmbfs/smb/iod_cl.c
+++ b/usr/src/lib/libsmbfs/smb/iod_cl.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -54,30 +53,29 @@
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
+#include <assert.h>
+
#include "charsets.h"
#include "private.h"
-static const char smbiod_path[] = "/usr/lib/smbfs/smbiod";
-
/*
* This is constant for the life of a process,
* and initialized at startup, so no locks.
*/
-static char door_path[40];
+static char door_path[64];
static int iod_start_timeout = 10; /* seconds */
char *
smb_iod_door_path(void)
{
- static const char fmtR[] = "/var/run/smbiod-%d";
- static const char fmtU[] = "/tmp/.smbiod-%d";
- const char *fmt;
uid_t uid;
+ int x;
if (door_path[0] == '\0') {
uid = getuid();
- fmt = (uid == 0) ? fmtR : fmtU;
- snprintf(door_path, sizeof (door_path), fmt, uid);
+ x = snprintf(door_path, sizeof (door_path),
+ SMBIOD_USR_DOOR, uid);
+ assert(x <= sizeof (door_path));
}
return (door_path);
@@ -126,56 +124,86 @@ smb_iod_open_door(int *fdp)
}
/*
- * Start the IOD (if not already running) and
- * wait until its door service is ready.
+ * Request the creation of our per-user smbiod
+ * via door call to the "main" IOD service.
+ */
+static int
+start_iod(void)
+{
+ const char *svc_door = SMBIOD_SVC_DOOR;
+ door_arg_t da;
+ int32_t cmd, err;
+ int fd, rc;
+
+ fd = open(svc_door, O_RDONLY, 0);
+ if (fd < 0) {
+ err = errno;
+ DPRINT("%s: open failed, err %d", svc_door, err);
+ return (err);
+ }
+ cmd = SMBIOD_START;
+ memset(&da, 0, sizeof (da));
+ da.data_ptr = (void *) &cmd;
+ da.data_size = sizeof (cmd);
+ da.rbuf = (void *) &err;
+ da.rsize = sizeof (err);
+ rc = door_call(fd, &da);
+ close(fd);
+ if (rc < 0) {
+ err = errno;
+ DPRINT("door_call, err %d", err);
+ return (err);
+ }
+
+ return (err);
+}
+
+/*
+ * Get a door handle to the IOD, starting it if necessary.
* On success, sets ctx->ct_door_fd
*/
int
smb_iod_start(smb_ctx_t *ctx)
{
- int err, pid, tmo;
+ int err, tmo;
int fd = -1;
- err = smb_iod_open_door(&fd);
- if (err == 0)
- goto OK;
-
- pid = vfork();
- if (pid < 0)
- return (errno);
-
- /*
- * child: start smbiod
- */
- if (pid == 0) {
- char *argv[2];
- argv[0] = "smbiod";
- argv[1] = NULL;
- (void) execv(smbiod_path, argv);
- _exit(1);
- }
-
- /*
- * parent: wait for smbiod to start
- */
tmo = iod_start_timeout;
- while (--tmo >= 0) {
+ while ((err = smb_iod_open_door(&fd)) != 0) {
+ if (--tmo <= 0)
+ goto errout;
+
+ /*
+ * We have no per-user IOD yet. Request one.
+ * Do this request every time through the loop
+ * because the master IOD will only start our
+ * per-user IOD if we don't have one, and our
+ * first requst could have happened while we
+ * had an IOD that was doing shutdown.
+ * (Prevents a shutdown/startup race).
+ */
+ err = start_iod();
+ if (err != 0)
+ goto errout;
+ /*
+ * Wait for it to get ready.
+ */
(void) sleep(1);
- err = smb_iod_open_door(&fd);
- if (err == 0)
- goto OK;
}
- return (err);
-OK:
/* Save the door fd. */
if (ctx->ct_door_fd != -1)
close(ctx->ct_door_fd);
ctx->ct_door_fd = fd;
return (0);
-}
+errout:
+ smb_error(dgettext(TEXT_DOMAIN,
+ "Could not contact service: %s"),
+ 0, "svc:/network/smb/client");
+ return (ENOTACTIVE);
+}
/*
* Ask the IOD to connect using the info in ctx.
diff --git a/usr/src/lib/libsmbfs/smb/nbns_rq.c b/usr/src/lib/libsmbfs/smb/nbns_rq.c
index 7dc46f3983..d28be4b0f9 100644
--- a/usr/src/lib/libsmbfs/smb/nbns_rq.c
+++ b/usr/src/lib/libsmbfs/smb/nbns_rq.c
@@ -32,6 +32,10 @@
* $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $
*/
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -351,7 +355,7 @@ nbns_getnodestatus(struct nb_ctx *ctx,
foundserver = 1;
}
}
- if (!foundserver)
+ if (foundserver == 0 && retname != NULL)
strlcpy(system, retname, NB_NAMELEN);
ctx->nb_lastns = rqp->nr_sender;
diff --git a/usr/src/pkg/manifests/system-file-system-smb.mf b/usr/src/pkg/manifests/system-file-system-smb.mf
index 5bb358cbe2..6642504879 100644
--- a/usr/src/pkg/manifests/system-file-system-smb.mf
+++ b/usr/src/pkg/manifests/system-file-system-smb.mf
@@ -81,6 +81,7 @@ $(i386_ONLY)file path=usr/lib/mdb/kvm/smbfs.so mode=0555
file path=usr/lib/security/$(ARCH64)/pam_smbfs_login.so.1
file path=usr/lib/security/pam_smbfs_login.so.1
file path=usr/lib/smbfs/smbiod mode=0555
+file path=usr/lib/smbfs/smbiod-svc mode=0555
file path=lib/svc/manifest/network/smb/client.xml group=sys mode=0444
legacy pkg=SUNWsmbfskr arch=$(ARCH) category=system \
desc="SMB/CIFS File System client support (Kernel)" \
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
index 140d390670..cf06e75767 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -284,7 +283,8 @@ smb_rq_verify(struct smb_rq *rqp)
if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
return (0);
- SMBSDEBUG("BAD signature, MID=0x%x\n", rqp->sr_mid);
+ SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n",
+ vcp->vc_srvname, rqp->sr_mid, rsn);
#ifdef DEBUG
/*
@@ -302,8 +302,8 @@ smb_rq_verify(struct smb_rq *rqp)
}
}
if (fudge <= nsmb_signing_fudge) {
- SMBSDEBUG("sr_rseqno=%d, but %d would have worked\n",
- rsn, rsn + fudge);
+ SMBERROR("MID=0x%x, Seq=%d, but %d would have worked\n",
+ rqp->sr_mid, rsn, rsn + fudge);
}
#endif
return (EBADRPC);