smbiod-svc.c revision a547be5daca7e465ca82df6d179f6b1f8e0cda72
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * CDDL HEADER START
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * The contents of this file are subject to the terms of the
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Common Development and Distribution License (the "License").
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * You may not use this file except in compliance with the License.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * See the License for the specific language governing permissions
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * and limitations under the License.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * When distributing Covered Code, include this CDDL HEADER in each
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * If applicable, add the following below this CDDL HEADER, with the
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * CDDL HEADER END
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * SMBFS I/O Daemon (SMF service)
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross/* Keep a list of child processes. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Rosstypedef struct _child {
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Rossstatic const char smbiod_path[] = "/usr/lib/smbfs/smbiod";
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Rossvoid svc_dispatch(void *cookie, char *argp, size_t argsz,
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Rossstatic void svc_sigchld(void);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Rossstatic void svc_cleanup(void);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Find out if the service is already running.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Return: true, false.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * This function will fork off a child process,
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * from which only the child will return.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * The parent exit status is taken as the SMF start method
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * success or failure, so the parent waits (via pipe read)
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * for the child to finish initialization before it exits.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Use SMF error codes only on exit.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * If we're the parent process, wait for either the child to send us
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * the appropriate exit status over the pipe or for the read to fail
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * (presumably with 0 for EOF if our child terminated abnormally).
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * If the read fails, exit with either the child's exit status if it
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* parent */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross if (read(pfds[0], &st, sizeof (st)) == sizeof (st))
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross if (waitpid(pid, &st, 0) == pid && WIFEXITED(st))
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* Tell parent we're ready. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross boolean_t created = B_FALSE, attached = B_FALSE;
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* set locale and text domain for i18n */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross switch (c) {
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* Do debug messages. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross fprintf(stderr, "%s: already running", argv[0]);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Raise the fd limit to max
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * errors here are non-fatal
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross fprintf(stderr, "getrlimit failed, err %d\n", errno);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross "RLIMIT_NOFILE %d, err %d",
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Want all signals blocked, as we're doing
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * synchronous delivery via sigwait below.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Do want SIGCHLD, and will waitpid().
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Daemonize, unless debugging.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* debug: run in foregound (not a service) */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* Non-debug: start daemon in the background. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Create directory for all smbiod doors.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross if ((mkdir(SMBIOD_RUNDIR, 0755) < 0) && errno != EEXIST) {
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Create a file for the main service door.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross tmp_fd = open(door_path, O_RDWR|O_CREAT|O_EXCL, 0644);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* Setup the door service. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Initializations done. Tell start method we're up.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Main thread just waits for signals.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * The whole process contract gets a SIGTERM
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * at once. Give children a chance to exit
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * so we can do normal SIGCHLD cleanup.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Prevent new door_open calls.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross break; /* normal termination */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* Unexpected signal. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross fprintf(stderr, "svc_main: unexpected sig=%d\n", sig);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* NB: door threads gone now. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* If startup error, report to parent. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Rosssvc_dispatch(void *cookie, char *argp, size_t argsz,
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Allow a NULL arg call to check if this
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * daemon is running. Just return zero.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Get the caller's credentials.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * (from client side of door)
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Arg is just an int command code.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Reply is also an int.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Start a per-user smbiod, if not already running.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* This UID already has an IOD. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * OK, create a new child.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * The child will not have permission to create or
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * destroy files in SMBIOD_RUNDIR so do that here.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross fd = open(door_file, O_RDWR|O_CREAT|O_EXCL, 0600);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* parent */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross fprintf(stderr, "cmd_start: uid %d new iod, pid %d\n",
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Assume the passed credentials (from the door client),
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * drop any extra privileges, and exec the per-user iod.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross flags = PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS;
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross rc = __init_daemon_priv(flags, uid, gid, PRIV_NET_ACCESS, NULL);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross fprintf(stderr, "svc_sigchld: pid %d\n", (int)pid);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross /* ECHILD is the normal end of loop. */
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross fprintf(stderr, "svc_sigchld: waitpid err %d\n", err);
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross if (x != 0) {
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross "uid %d, pid %d exit %d",
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross "uid %d, pid %d signal %d",
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Final cleanup before exit. Unlink child doors, etc.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * Called while single threaded, so no locks needed here.
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * The list is normally empty by now due to svc_sigchld
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * calls during shutdown. But in case there were any
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * straglers, do cleanup here. Don't bother freeing any
a547be5daca7e465ca82df6d179f6b1f8e0cda72Gordon Ross * list elements here, as we're exiting.