/* * 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); }
int minor_init() { char *maxport_str; maxport_str = defread("SUNW_port_link.maxports"); if ((maxport_str == NULL) || (sscanf(maxport_str, "%d", &maxports) != 1)) maxports = MAXPORTS_DEFAULT; devfsadm_print(CHATTY_MID, "%s: maximum number of port devices (%d)\n", modname, maxports); if (pma_alloc() == NULL) return (DEVFSADM_FAILURE); return (DEVFSADM_SUCCESS); }
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); }
/* * 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"); }
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); }
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(¤t_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); }
/* 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); }