예제 #1
0
/*
 * Code to handle /etc/default/ file for IPv4 command output compatibility
 *
 * Note: Handles BOTH the same as IP_VERSION6.
 *
 * Returns 1 if IP_VERSION4; 0 for other versions.
 * Returns -1 if the value of DEFAULT_IP found in /etc/default/inet_type is
 * invalid.
 */
int
get_compat_flag(char **value)
{
	if (defopen(INET_DEFAULT_FILE) == 0) {
		char	*cp;
		int	flags;

		/*
		 * ignore case
		 */
		flags = defcntl(DC_GETFLAGS, 0);
		TURNOFF(flags, DC_CASE);
		(void) defcntl(DC_SETFLAGS, flags);

		if (cp = defread(DEFAULT_IP_LINE))
			*value = strdup(cp);

		/* close */
		(void) defopen((char *)NULL);

		if (*value != NULL) {
			if (strcasecmp(*value, "IP_VERSION4") == 0) {
				return (DEFAULT_PROT_V4_ONLY);
			} else if (strcasecmp(*value, "BOTH") == 0 ||
			    strcasecmp(*value, "IP_VERSION6") == 0) {
				return (DEFAULT_PROT_BOTH);
			} else {
				return (DEFAULT_PROT_BAD_VALUE);
			}
		}
	}
	/* No value set */
	return (DEFAULT_PROT_BOTH);
}
예제 #2
0
int
get_default_zfs_flags()
{
	int flags = 0;

	if (defopen(DEFAULT_USERADD) == 0) {
		char *defptr;

		if ((defptr = defread(MANAGE_ZFS_OPT)) != NULL) {
			char let = tolower(*defptr);

			switch (let) {
				case 'y':	/* yes */
					flags |= MANAGE_ZFS;
				case 'n':	/* no */
					break;
			}
		}
		(void) defopen((char *)NULL);
	}
	return (flags);
}
예제 #3
0
/*
 * This is used to figure out the default file system type if "-F FStype"
 * is not specified with the file system command and no entry in the
 * /etc/vfstab matches the specified special.
 * If the first character of the "special" is a "/" (eg, "/dev/dsk/c0d1s2"),
 * returns the default local filesystem type.
 * Otherwise (eg, "server:/path/name" or "resource"), returns the default
 * remote filesystem type.
 */
char	*
default_fstype(char *special)
{
	char	*deffs = NULL;
	static	char	buf[BUFSIZ];
	FILE	*fp;

	if (*special == '/') {
		if (defopen(LOCAL) == 0) {
			deffs = defread("LOCAL=");
			defopen(NULL);	/* close default file */
		}
	} else {
		if ((fp = fopen(REMOTE, "r")) != NULL) {
			if (fgets(buf, sizeof (buf), fp) != NULL)
				deffs = strtok(buf, " \t\n");
			fclose(fp);
		}
		if (deffs == NULL)
			deffs = "nfs";
	}

	return (deffs != NULL ? deffs : "ufs");
}
예제 #4
0
파일: mountd.c 프로젝트: andreiw/polaris
int
main(int argc, char *argv[])
{
	int	pid;
	int	c;
	int	rpc_svc_mode = RPC_SVC_MT_AUTO;
	int	maxthreads;
	int	maxrecsz = RPC_MAXDATASIZE;
	bool_t	exclbind = TRUE;
	bool_t	can_do_mlp;
	long	thr_flags = (THR_NEW_LWP|THR_DAEMON);

	/*
	 * Mountd requires uid 0 for:
	 *	/etc/rmtab updates (we could chown it to daemon)
	 *	/etc/dfs/dfstab reading (it wants to lock out share which
	 *		doesn't do any locking before first truncate;
	 *		NFS share does; should use fcntl locking instead)
	 *	Needed privileges:
	 *		auditing
	 *		nfs syscall
	 *		file dac search (so it can stat all files)
	 *	Optional privileges:
	 *		MLP
	 */
	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
	    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
		(void) fprintf(stderr,
			"%s must be run as with sufficient privileges\n",
			argv[0]);
		exit(1);
	}

	maxthreads = 0;

	while ((c = getopt(argc, argv, "vrm:")) != EOF) {
		switch (c) {
		case 'v':
			verbose++;
			break;
		case 'r':
			rejecting = 1;
			break;
		case 'm':
			maxthreads = atoi(optarg);
			if (maxthreads < 1) {
				(void) fprintf(stderr,
	"%s: must specify positive maximum threads count, using default\n",
						argv[0]);
				maxthreads = 0;
			}
			break;
		}
	}

	/*
	 * Read in the NFS version values from config file.
	 */
	if ((defopen(NFSADMIN)) == 0) {
		char *defval;
		int defvers;

		if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) {
			errno = 0;
			defvers = strtol(defval, (char **)NULL, 10);
			if (errno == 0) {
				mount_vers_min = defvers;
				/*
				 * special because NFSv2 is
				 * supported by mount v1 & v2
				 */
				if (defvers == NFS_VERSION)
					mount_vers_min = MOUNTVERS;
			}
		}
		if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) {
			errno = 0;
			defvers = strtol(defval, (char **)NULL, 10);
			if (errno == 0) {
				mount_vers_max = defvers;
			}
		}

		/* close defaults file */
		defopen(NULL);
	}

	/*
	 * Sanity check versions,
	 * even though we may get versions > MOUNTVERS3, we still need
	 * to start nfsauth service, so continue on regardless of values.
	 */
	if (mount_vers_min > mount_vers_max) {
		syslog(LOG_NOTICE, "NFS_SERVER_VERSMIN > NFS_SERVER_VERSMAX");
		mount_vers_max = mount_vers_min;
	}
	(void) setlocale(LC_ALL, "");
	(void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
	(void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
	netgroup_init();

#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SYS_TEST"
#endif
	(void) textdomain(TEXT_DOMAIN);

	/* Don't drop core if the NFS module isn't loaded. */
	(void) signal(SIGSYS, SIG_IGN);

	(void) signal(SIGHUP, sigexit);
	(void) signal(SIGCLD, sigexit);

	switch (fork()) {
	case 0:		/* child */
		break;
	case -1:
		perror("mountd: can't fork");
		exit(1);
	default:	/* parent */
		for (;;)
			(void) pause();
		/* NOTREACHED */
	}

	(void) signal(SIGHUP, SIG_DFL);
	(void) signal(SIGCLD, SIG_DFL);

	/*
	 * If we coredump it'll be in /core
	 */
	if (chdir("/") < 0)
		syslog(LOG_ERR, "chdir /: %m");

	/*
	 * Close existing file descriptors, open "/dev/null" as
	 * standard input, output, and error, and detach from
	 * controlling terminal.
	 */
	closefrom(0);
	(void) open("/dev/null", O_RDONLY);
	(void) open("/dev/null", O_WRONLY);
	(void) dup(1);
	(void) setsid();

	openlog("mountd", LOG_PID, LOG_DAEMON);

	/*
	 * establish our lock on the lock file and write our pid to it.
	 * exit if some other process holds the lock, or if there's any
	 * error in writing/locking the file.
	 */
	pid = _enter_daemon_lock(MOUNTD);
	switch (pid) {
	case 0:
		break;
	case -1:
		syslog(LOG_ERR, "error locking for %s: %s", MOUNTD,
		    strerror(errno));
		exit(2);
	default:
		/* daemon was already running */
		exit(0);
	}

	audit_mountd_setup();	/* BSM */

	/*
	 * Tell RPC that we want automatic thread mode.
	 * A new thread will be spawned for each request.
	 */
	if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
		syslog(LOG_ERR, "unable to set automatic MT mode");
		exit(1);
	}

	/*
	 * Enable non-blocking mode and maximum record size checks for
	 * connection oriented transports.
	 */
	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
		syslog(LOG_INFO, "unable to set RPC max record size");
	}

	/*
	 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
	 * from being hijacked by a bind to a more specific addr.
	 */
	if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
		syslog(LOG_INFO,  "warning: unable to set udp/tcp EXCLBIND");
	}

	/*
	 * If the -m argument was specified, then set the
	 * maximum number of threads to the value specified.
	 */
	if (maxthreads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) {
		syslog(LOG_ERR, "unable to set maxthreads");
		exit(1);
	}

	/*
	 * Make sure to unregister any previous versions in case the
	 * user is reconfiguring the server in interesting ways.
	 */
	svc_unreg(MOUNTPROG, MOUNTVERS);
	svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
	svc_unreg(MOUNTPROG, MOUNTVERS3);

	/*
	 * Create the nfsauth thread with same signal disposition
	 * as the main thread. We need to create a separate thread
	 * since mountd() will be both an RPC server (for remote
	 * traffic) _and_ a doors server (for kernel upcalls).
	 */
	if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
		syslog(LOG_ERR, gettext("Failed to create NFSAUTH svc thread"));
		exit(2);
	}

	/*
	 * Create datagram and connection oriented services
	 */
	if (mount_vers_max >= MOUNTVERS) {
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register datagram_v MOUNTVERS");
			exit(1);
		}
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register circuit_v MOUNTVERS");
			exit(1);
		}
	}
	if (mount_vers_max >= MOUNTVERS_POSIX) {
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
							"datagram_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register datagram_v MOUNTVERS_POSIX");
			exit(1);
		}
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
							"circuit_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register circuit_v MOUNTVERS_POSIX");
			exit(1);
		}
	}

	if (mount_vers_max >= MOUNTVERS3) {
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register datagram_v MOUNTVERS3");
			exit(1);
		}
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register circuit_v MOUNTVERS3");
			exit(1);
		}
	}

	/*
	 * Start serving
	 */
	rmtab_load();
	(void) kill(getppid(), SIGHUP);

	/* Get rid of the most dangerous basic privileges. */
	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
	    (char *)NULL);

	svc_run();
	syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
	abort();
	/* NOTREACHED */
	return (0);
}
예제 #5
0
파일: automount.c 프로젝트: RomiPierre/osx
int
main(int argc, char *argv[])
{
	long timeout_val;
	int c;
	int flushcache = 0;
	int unmount_automounted = 0;	// Unmount automounted mounts
	struct autodir *dir, *d;
	char real_mntpnt[PATH_MAX];
	struct stat stbuf;
	char *master_map = "auto_master";
	int null;
	struct statfs *mntp;
	int count = 0;
	char *stack[STACKSIZ];
	char **stkptr;
	char *defval;
	int fd;
	int flags, altflags;
	struct staticmap *static_ent;

	/*
	 * Read in the values from config file first before we check
	 * commandline options so the options override the file.
	 */
	if ((defopen(AUTOFSADMIN)) == 0) {
		if ((defval = defread("AUTOMOUNT_TIMEOUT=")) != NULL) {
			errno = 0;
			timeout_val = strtol(defval, (char **)NULL, 10);
			if (errno == 0 && timeout_val > 0 &&
			    timeout_val <= INT_MAX)
				mount_timeout = (int)timeout_val;
		}
		if ((defval = defread("AUTOMOUNT_VERBOSE=")) != NULL) {
			if (strncasecmp("true", defval, 4) == 0)
				verbose = TRUE;
			else
				verbose = FALSE;
		}
		if ((defval = defread("AUTOMOUNTD_TRACE=")) != NULL) {
			/*
			 * Turn on tracing here too if the automountd
			 * is set up to do it - since automount calls
			 * many of the common library functions.
			 */
			errno = 0;
			trace = (int)strtol(defval, (char **)NULL, 10);
			if (errno != 0)
				trace = 0;
		}

		/* close defaults file */
		defopen(NULL);
	}

	while ((c = getopt(argc, argv, "mM:D:f:t:vcu?")) != EOF) {
		switch (c) {
		case 'm':
			pr_msg("Warning: -m option not supported");
			break;
		case 'M':
			pr_msg("Warning: -M option not supported");
			break;
		case 'D':
			pr_msg("Warning: -D option not supported");
			break;
		case 'f':
			pr_msg("Error: -f option no longer supported");
			usage();
			break;
		case 't':
			if (strchr(optarg, '=')) {
				pr_msg("Error: invalid value for -t");
				usage();
			}
			mount_timeout = atoi(optarg);
			break;
		case 'v':
			verbose++;
			break;
		case 'c':
			flushcache++;
			break;
		case 'u':
			unmount_automounted++;
			break;
		default:
			usage();
			break;
		}
	}

	if (optind < argc) {
		pr_msg("%s: command line mountpoints/maps "
			"no longer supported",
			argv[optind]);
		usage();
	}

	/*
	 * Get an array of current system mounts
	 */
	num_current_mounts = getmntinfo(&current_mounts, MNT_NOWAIT);
	if (num_current_mounts == 0) {
		pr_msg("Couldn't get current mounts: %m");
		exit(1);
	}

	autofs_control_fd = open("/dev/" AUTOFS_CONTROL_DEVICE, O_RDONLY);
	if (autofs_control_fd == -1 && errno == ENOENT) {
		/*
		 * Oops, we probably don't have the autofs kext
		 * loaded.
		 */
		FTS *fts;
		static char *const paths[] = { "/Network", NULL };
		FTSENT *ftsent;
		int error;

		/*
		 * This means there can't be any autofs mounts yet, so
		 * this is the first time we're being run since a reboot.
		 * Clean out any stuff left in /Network from the reboot.
		 */
		fts = fts_open(paths, FTS_NOCHDIR|FTS_PHYSICAL|FTS_XDEV,
		    NULL);
		if (fts != NULL) {
			while ((ftsent = fts_read(fts)) != NULL) {
				/*
				 * We only remove directories - if
				 * there are files, we assume they're
				 * there for a purpose.
				 *
				 * We remove directories after we've
				 * removed their children, so we want
				 * to process directories visited in
				 * post-order.
				 *
				 * We don't remove /Network itself.
				 */
				if (ftsent->fts_info == FTS_DP &&
				    ftsent->fts_level > FTS_ROOTLEVEL)
					rmdir(ftsent->fts_accpath);
			}
			fts_close(fts);
		}

		/*
		 * Now load it.
		 */
		error = load_autofs();
		if (error != 0) {
			pr_msg("can't load autofs kext");
			exit(1);
		}

		/*
		 * Try the open again.
		 */
		autofs_control_fd = open("/dev/" AUTOFS_CONTROL_DEVICE,
		    O_RDONLY);
	}
	if (autofs_control_fd == -1) {
		if (errno == EBUSY)
			pr_msg("Another automount is running");
		else
			pr_msg("Couldn't open %s: %m", "/dev/" AUTOFS_CONTROL_DEVICE);
		exit(1);
	}

	/*
	 * Update the mount timeout.
	 */
	if (ioctl(autofs_control_fd, AUTOFS_SET_MOUNT_TO, &mount_timeout) == -1)
		pr_msg("AUTOFS_SET_MOUNT_TO failed: %m");

	/*
	 * Attempt to unmount any non-busy triggered mounts; this includes
	 * not only autofs mounts, but, for example SMB Dfs mounts.
	 *
	 * This is done before sleep, and after a network change, to
	 * try to get rid of as many network mounts as we can; each
	 * unmounted network mount is a network mount on which we
	 * can't hang.
	 */
	if (unmount_automounted) {
		if (verbose)
			pr_msg("Unmounting triggered mounts");
		if (ioctl(autofs_control_fd, AUTOFS_UNMOUNT_TRIGGERED, 0) == -1)
			pr_msg("AUTOFS_UNMOUNT_TRIGGERED failed: %m");
		exit(0);
	}

	if (flushcache) {
		/*
		 * Notify the automounter that it should flush its caches,
		 * as we might be on a different network with different maps.
		 */
		if (ioctl(autofs_control_fd, AUTOFS_NOTIFYCHANGE, 0) == -1)
			pr_msg("AUTOFS_NOTIFYCHANGE failed: %m");
	}

	(void) umask(0);
	ns_setup(stack, &stkptr);

	(void) loadmaster_map(master_map, "", stack, &stkptr);

	/*
	 * Mount the daemon at its mount points.
	 */
	for (dir = dir_head; dir; dir = dir->dir_next) {

		if (realpath(dir->dir_name, real_mntpnt) == NULL) {
			/*
			 * We couldn't get the real path for this,
			 * perhaps because it doesn't exist.
			 * If it's not because it doesn't exist, just
			 * give up on this entry.  Otherwise, just null
			 * out the real path - we'll try creating the
			 * directory later, and will set dir_realpath
			 * then, if that succeeds.
			 */
			if (errno != ENOENT) {
				pr_msg("%s: Can't convert to real path: %m",
				    dir->dir_name);
				continue;
			}
			dir->dir_realpath = NULL;
		} else {
			dir->dir_realpath = strdup(real_mntpnt);
			if (dir->dir_realpath == NULL) {
				pr_msg("Couldn't allocate real path: %m");
				exit(1);
			}
		}

		/*
		 * Skip null entries
		 */
		if (strcmp(dir->dir_map, "-null") == 0)
			continue;

		/*
		 * Skip null'ed entries
		 */
		null = 0;
		for (d = dir->dir_prev; d; d = d->dir_prev) {
			if (paths_match(dir, d))
				null = 1;
		}
		if (null)
			continue;

		/*
		 * If this is -fstab, and there are no fstab "net" entries,
		 * skip this map if our directory search path doesn't
		 * include Active Directory.  We don't want /Network/Servers
		 * (or wherever it shows up) to exist if this system isn't
		 * using AD (AD supplies fstab entries on the fly, so they
		 * might not exist right now) and we don't have any fstab
		 * entries.
		 */
		if (strcmp(dir->dir_map, "-fstab") == 0) {
			if (!have_ad() && !havefstabkeys()) {
				/*
				 * We're not using AD, and fstab is
				 * inaccessible or devoid of "net" entries.
				 */
				free(dir->dir_map);
				dir->dir_map = strdup("-null");
				continue;
			}
			endfsent();
		}

		/*
		 * If this is -fstab or -static, and there's another entry
		 * that's supposed to mount something on the same directory
		 * and isn't "-fstab" or "-static", ignore this; we might
		 * have a server that's supplying real automounter maps for
		 * the benefit of OS X systems with autofs and also supplying
		 * fstab entries for the benefit of older OS X systems, and
		 * we want to mount the real automounter map, not the -fstab
		 * or -static map, in that case.
		 */
		if (strcmp(dir->dir_map, "-fstab") == 0 ||
		    strcmp(dir->dir_map, "-static") == 0) {
			for (d = dir_head; d; d = d->dir_next) {
				if (paths_match(dir, d) &&
				    strcmp(d->dir_map, "-fstab") != 0 &&
				    strcmp(d->dir_map, "-static") != 0) {
					pr_msg("%s: ignoring redundant %s map",
					    dir->dir_name, dir->dir_map);
					break;
				}
			}
			if (d != NULL) {
				continue;
			}
		}

		/*
		 * Parse the mount options and get additional flags to pass
		 * to mount() (standard mount options) and autofs mount
		 * options.
		 *
		 * XXX - we ignore flags on an update; if they're different
		 * from the current flags for that mount, we'd need to do a
		 * remount.
		 */
		if (!parse_mntopts(dir->dir_opts, &flags, &altflags)) {
			/*
			 * Failed.
			 */
			continue;
		}

		/*
		 * If this is -static, check whether the entry refers
		 * to this host; if so, make the appropriate symlink
		 * exist at the "mount point" path.
		 */
		if (strcmp(dir->dir_map, "-static") == 0) {
			static_ent = get_staticmap_entry(dir->dir_name);
			if (static_ent == NULL) {
				/*
				 * Whiskey tango foxtrot?  There should
				 * be an entry here.  Log an error and
				 * ignore this mount.
				 */
				pr_msg("can't find fstab entry for %s",
				    dir->dir_name);
				continue;
			}
			if (host_is_us(static_ent->host, strlen(static_ent->host)) ||
			    self_check(static_ent->host)) {
				/*
				 * Yup, this is us.
				 * Try to make the appropriate symlink.
				 */
				make_symlink(static_ent->localpath,
				    dir->dir_name);
				release_staticmap_entry(static_ent);
				continue;
			}
			release_staticmap_entry(static_ent);
		}

		/*
		 * Check whether there's already an entry
		 * in the mnttab for this mountpoint.
		 */
		if (dir->dir_realpath != NULL &&
		    (mntp = find_mount(dir->dir_realpath)) != NULL) {
			struct autofs_update_args au;

			/*
			 * If it's not an autofs mount - don't
			 * mount over it.
			 */
			if (strcmp(mntp->f_fstypename, MNTTYPE_AUTOFS) != 0) {
				pr_msg("%s: already mounted on %s",
					mntp->f_mntfromname, dir->dir_realpath);
				continue;
			}

			/*
			 * This is already mounted, so just update it.
			 * We don't bother to check whether any options are
			 * changing, as we'd have to make a trip into the
			 * kernel to get the current options to check them,
			 * so we might as well just make a trip to do the
			 * update.
			 */
			au.fsid		= mntp->f_fsid;
			au.opts		= dir->dir_opts;
			au.map		= dir->dir_map;
			au.mntflags	= altflags;
			au.direct 	= dir->dir_direct;
			au.node_type	= dir->dir_direct ? NT_TRIGGER : 0;

			if (ioctl(autofs_control_fd, AUTOFS_UPDATE_OPTIONS,
			    &au) < 0) {
				pr_msg("update %s: %m", dir->dir_realpath);
				continue;
			}
			if (verbose)
				pr_msg("%s updated", dir->dir_realpath);
		} else {
			struct autofs_args ai;
			int st_flags = 0;

			/*
			 * This trigger isn't already mounted; either
			 * the path doesn't exist at all, or it
			 * exists but nothing is mounted on it.
			 *
			 * Create a mount point if necessary
			 * If the path refers to an existing symbolic
			 * link, refuse to mount on it.  This avoids
			 * future problems.  (We don't use dir->dir_realpath
			 * because that's never a symbolic link.)
			 */
			if (lstat(dir->dir_name, &stbuf) == 0) {
				if ((stbuf.st_mode & S_IFMT) != S_IFDIR) {
					pr_msg("%s: Not a directory", dir->dir_name);
					continue;
				}
				st_flags = stbuf.st_flags;

				/*
				 * Either realpath() succeeded or it
				 * failed with ENOENT; otherwise, we
				 * would have quit before getting here.
				 *
				 * If it failed, report an error, as
				 * the problem isn't that "dir->dir_name"
				 * doesn't exist, the problem is that,
				 * somehow, we got ENOENT even though
				 * it exists.
				 */
				if (dir->dir_realpath == NULL) {
					errno = ENOENT;
					pr_msg("%s: Can't convert to real path: %m",
					    dir->dir_name);
					continue;
				}
			} else {
				/*
				 * Mountpoint doesn't exist.
				 *
				 * Create it unless it's under /Volumes.
				 * At boot time it's possible the volume
				 * containing the mountpoint hasn't mounted yet.
				 */
				if (strncmp(dir->dir_name, "/Volumes/", 9) == 0) {
					pr_msg("%s: mountpoint unavailable", dir->dir_name);
					continue;
				}

				if (mkdir_r(dir->dir_name)) {
					pr_msg("%s: %m", dir->dir_name);
					continue;
				}

				/*
				 * realpath() presumably didn't succeed,
				 * as dir->dir_name couldn't be statted.
				 * Call it again, to get the real path
				 * corresponding to the newly-created
				 * mount point.
				 */
				if (realpath(dir->dir_name, real_mntpnt) == NULL) {
					/*
					 * Failed.
					 */
					pr_msg("%s: Can't convert to real path: %m",
					    dir->dir_name);
					continue;
				}
				dir->dir_realpath = strdup(real_mntpnt);
				if (dir->dir_realpath == NULL) {
					pr_msg("Couldn't allocate real path for %s: %m",
					    dir->dir_name);
					continue;
				}
			}

			/*
			 * If the "hidefromfinder" option is set for
			 * this autofs mountpoint then also set the
			 * UF_HIDDEN bit on the directory so it'll still
			 * be invisible to the Finder even if not mounted on.
			 */
			if (altflags & AUTOFS_MNT_HIDEFROMFINDER)
				st_flags |= UF_HIDDEN;
			else
				st_flags &= ~UF_HIDDEN;
			if (chflags(dir->dir_name, st_flags) < 0)
				pr_msg("%s: can't set hidden", dir->dir_name);

			/*
			 * Mount it.  Use the real path (symlink-free),
			 * for reasons mentioned above.
			 */
			ai.version	= AUTOFS_ARGSVERSION;
			ai.path 	= dir->dir_realpath;
			ai.opts		= dir->dir_opts;
			ai.map		= dir->dir_map;
			ai.subdir	= "";
			ai.direct 	= dir->dir_direct;
			if (dir->dir_direct)
				ai.key = dir->dir_name;
			else
				ai.key = "";
			ai.mntflags	= altflags;
			ai.mount_type	= MOUNT_TYPE_MAP;	/* top-level autofs mount */
			ai.node_type	= dir->dir_direct ? NT_TRIGGER : 0;

			if (mount(MNTTYPE_AUTOFS, dir->dir_realpath,
			    MNT_DONTBROWSE | MNT_AUTOMOUNTED | flags,
			    &ai) < 0) {
				pr_msg("mount %s: %m", dir->dir_realpath);
				continue;
			}
			if (verbose)
				pr_msg("%s mounted", dir->dir_realpath);
		}

		count++;
	}

	if (verbose && count == 0)
		pr_msg("no mounts");

	/*
	 * Now compare the /etc/mnttab with the master
	 * map.  Any autofs mounts in the /etc/mnttab
	 * that are not in the master map must be
	 * unmounted
	 *
	 * XXX - if there are no autofs mounts left, should we
	 * unload autofs, or arrange that it be unloaded?
	 */
	do_unmounts();

	/*
	 * Let PremountHomeDirectoryWithAuthentication() know that we're
	 * done.
	 */
	fd = open("/var/run/automount.initialized", O_CREAT|O_WRONLY, 0600);
	close(fd);

	return (0);
}
예제 #6
0
/* ARGSUSED */
int
main(int argc, char **argv)
{
	struct spwd	*shpw;
	int		passreq = B_TRUE;
	int		flags;
	int		fd;
	char		*infop, *ptr, *p;
	pid_t		pid;
	int		bufsize;
	struct stat	st;
	char		cttyname[100];
	char		namedlist[500];
	char		scratchlist[500];
	dev_t		cttyd;

	if (geteuid() != 0) {
		(void) fprintf(stderr, "%s: must be root\n", argv[0]);
		return (EXIT_FAILURE);
	}

	/* Do the magic to determine the children */
	if ((fd = open(SYSMSG, 0)) < 0)
		return (EXIT_FAILURE);

	/*
	 * If the console supports the CIOCTTYCONSOLE ioctl, then fetch
	 * its console device list.  If not, then we use the default
	 * console name.
	 */
	if (ioctl(fd, CIOCTTYCONSOLE, &cttyd) == 0) {
		if ((bufsize = ioctl(fd, CIOCGETCONSOLE, NULL)) < 0)
			return (EXIT_FAILURE);

		if (bufsize > 0) {
			if ((infop = calloc(bufsize, sizeof (char))) == NULL)
				return (EXIT_FAILURE);

			if (ioctl(fd, CIOCGETCONSOLE, infop) < 0)
				return (EXIT_FAILURE);

			(void) snprintf(namedlist, sizeof (namedlist), "%s %s",
			    DEFAULT_CONSOLE, infop);
		} else
			(void) snprintf(namedlist, sizeof (namedlist), "%s",
			    DEFAULT_CONSOLE);
	} else {
		(void) snprintf(namedlist, sizeof (namedlist), "%s",
		    DEFAULT_CONSOLE);
		cttyd = NODEV;
	}

	/*
	 * The attempt to turn the controlling terminals dev_t into a string
	 * may not be successful, thus leaving the variable cttyname as a
	 * NULL.  This occurs if during boot we find
	 * the root partition (or some other partition)
	 * requires manual fsck, thus resulting in sulogin
	 * getting invoked.  The ioctl for CIOCTTYCONSOLE
	 * called above returned NODEV for cttyd
	 * in these cases.  NODEV gets returned when the vnode pointer
	 * in our session structure is NULL.  In these cases it
	 * must be assumed that the default console is used.
	 *
	 * See uts/common/os/session.c:cttydev().
	 */
	(void) strcpy(cttyname, DEFAULT_CONSOLE);
	(void) strcpy(scratchlist, namedlist);
	ptr = scratchlist;
	while (ptr != NULL) {
		p = strchr(ptr, ' ');
		if (p == NULL) {
			if (stat(ptr, &st))
				return (EXIT_FAILURE);
			if (st.st_rdev == cttyd)
				(void) strcpy(cttyname, ptr);
			break;
		}
		*p++ = '\0';
		if (stat(ptr, &st))
			return (EXIT_FAILURE);
		if (st.st_rdev == cttyd) {
			(void) strcpy(cttyname, ptr);
			break;
		}
		ptr = p;
	}

	/*
	 * Use the same value of SLEEPTIME that login(1) uses.  This
	 * is obtained by reading the file /etc/default/login using
	 * the def*() functions.
	 */

	if (defopen(DEFAULT_LOGIN) == 0) {

		/* ignore case */

		flags = defcntl(DC_GETFLAGS, 0);
		TURNOFF(flags, DC_CASE);
		(void) defcntl(DC_SETFLAGS, flags);

		if ((ptr = defread("SLEEPTIME=")) != NULL)
			sleeptime = atoi(ptr);

		if (sleeptime < 0 || sleeptime > SLEEPTIME_MAX)
			sleeptime = SLEEPTIME;

		(void) defopen(NULL);	/* closes DEFAULT_LOGIN */
	}

	/*
	 * Use our own value of PASSREQ, separate from the one login(1) uses.
	 * This is obtained by reading the file /etc/default/sulogin using
	 * the def*() functions.
	 */

	if (defopen(DEFAULT_SULOGIN) == 0) {
		if ((ptr = defread("PASSREQ=")) != NULL)
			if (strcmp("NO", ptr) == 0)
				passreq = B_FALSE;

		(void) defopen(NULL);	/* closes DEFAULT_SULOGIN */
	}

	if (passreq == B_FALSE)
		single(shell, NULL);

	/*
	 * if no 'root' entry in /etc/shadow, give maint. mode single
	 * user shell prompt
	 */
	setspent();
	if ((shpw = getspnam("root")) == NULL) {
		(void) fprintf(stderr, "\n*** Unable to retrieve `root' entry "
		    "in shadow password file ***\n\n");
		single(shell, NULL);
	}
	endspent();
	/*
	 * if no 'root' entry in /etc/passwd, give maint. mode single
	 * user shell prompt
	 */
	setpwent();
	if (getpwnam("root") == NULL) {
		(void) fprintf(stderr, "\n*** Unable to retrieve `root' entry "
		    "in password file ***\n\n");
		single(shell, NULL);
	}
	endpwent();
	/* process with controlling tty treated special */
	if ((pid = fork()) != (pid_t)0) {
		if (pid == -1)
			return (EXIT_FAILURE);
		else {
			setupsigs();
			masterpid = pid;
			originalpid = getpid();
			/*
			 * init() was invoked from a console that was not
			 * the default console, nor was it an auxiliary.
			 */
			if (cttyname[0] == NULL)
				termhandler(0);
				/* Never returns */

			main_loop(cttyname, B_TRUE);
			/* Never returns */
		}
	}
	masterpid = getpid();
	originalpid = getppid();
	pidlist[nchild++] = originalpid;

	sa.sa_handler = childcleanup;
	sa.sa_flags = 0;
	(void) sigemptyset(&sa.sa_mask);
	(void) sigaction(SIGTERM, &sa, NULL);
	(void) sigaction(SIGHUP, &sa, NULL);
	sa.sa_handler = parenthandler;
	sa.sa_flags = SA_SIGINFO;
	(void) sigemptyset(&sa.sa_mask);
	(void) sigaction(SIGUSR1, &sa, NULL);

	sa.sa_handler = SIG_IGN;
	sa.sa_flags = 0;
	(void) sigemptyset(&sa.sa_mask);
	(void) sigaction(SIGCHLD, &sa, NULL);
	/*
	 * If there isn't a password on root, then don't permit
	 * the fanout capability of sulogin.
	 */
	if (*shpw->sp_pwdp != '\0') {
		ptr = namedlist;
		while (ptr != NULL) {
			p = strchr(ptr, ' ');
			if (p == NULL) {
				doit(ptr, cttyname);
				break;
			}
			*p++ = '\0';
			doit(ptr, cttyname);
			ptr = p;
		}
	}
	if (pathcmp(cttyname, DEFAULT_CONSOLE) != 0) {
		if ((pid = fork()) == (pid_t)0) {
			setupsigs();
			main_loop(DEFAULT_CONSOLE, B_FALSE);
		} else if (pid == -1)
			return (EXIT_FAILURE);
		pidlist[nchild++] = pid;
	}
	/*
	 * When parent is all done, it pauses until one of its children
	 * signals that its time to kill the underpriviledged.
	 */
	(void) wait(NULL);

	return (0);
}