diff options
author | Gordon Ross <Gordon.Ross@Sun.COM> | 2010-06-04 16:34:40 -0400 |
---|---|---|
committer | Gordon Ross <Gordon.Ross@Sun.COM> | 2010-06-04 16:34:40 -0400 |
commit | a547be5daca7e465ca82df6d179f6b1f8e0cda72 (patch) | |
tree | 1de43ca9ce086e2e22f5d71d8dc2c9f96ae8c0d2 | |
parent | bc6a100fe6399f4a72c84c38df0fc9a960ded814 (diff) | |
download | illumos-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/Makefile | 8 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/smbclnt/smbiod-svc/Makefile | 57 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/smbclnt/smbiod-svc/smbiod-svc.c | 591 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/smbclnt/smbiod/Makefile | 7 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c | 149 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/smbclnt/svc/client.xml | 45 | ||||
-rw-r--r-- | usr/src/cmd/fs.d/smbclnt/svc/smb-client | 23 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/netsmb/smb_lib.h | 8 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/iod_cl.c | 112 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/nbns_rq.c | 6 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-file-system-smb.mf | 1 | ||||
-rw-r--r-- | usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c | 10 |
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); |