2N/A/*
2N/A * Copyright (c) 1990, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A/*
2N/A * Copyright (c) 1985 Regents of the University of California.
2N/A * All rights reserved. The Berkeley software License Agreement
2N/A * specifies the terms and conditions for redistribution.
2N/A */
2N/A
2N/A#include "lint.h"
2N/A#include <sys/types.h>
2N/A#include <sys/param.h>
2N/A#include <sys/stat.h>
2N/A#include <ctype.h>
2N/A#include <stdio.h>
2N/A#include <limits.h>
2N/A#include <stdlib.h>
2N/A#include <sys/file.h>
2N/A#include "libc.h"
2N/A#include <unistd.h>
2N/A
2N/A#define SHELLS "/etc/shells"
2N/A
2N/A/*
2N/A * Do not add local shells here. They should be added in /etc/shells
2N/A *
2N/A * Do not add restricted shells:
2N/A * Shells returned by getusershell traditionally allow:
2N/A * - users to change away from (i.e., if you have an rksh in
2N/A * getusershell(), then users can change their shell to ksh)
2N/A * - by default, ftp in is allowed only for shells returned by
2N/A * getusershell(); since FTP has no restrictions on directory
2N/A * movement, adding rksh to getusershell() would defeat that
2N/A * protection.
2N/A */
2N/A/* The three entries:
2N/A *
2N/A * "/sbin/sh",
2N/A * "/sbin/jsh",
2N/A * "/sbin/pfsh",
2N/A *
2N/A * are included in the array below, to allow compatibility
2N/A * with older systems, where, for example, the shell defined
2N/A * in the 'root' entry in /etc/passwd is /sbin/sh.
2N/A */
2N/Aconst char *okshells[] = {
2N/A "/usr/bin/sh",
2N/A "/usr/bin/csh",
2N/A "/usr/bin/ksh",
2N/A "/usr/bin/ksh93",
2N/A "/usr/bin/jsh",
2N/A "/bin/sh",
2N/A "/bin/csh",
2N/A "/bin/ksh",
2N/A "/bin/ksh93",
2N/A "/bin/jsh",
2N/A "/sbin/sh",
2N/A "/sbin/jsh",
2N/A "/usr/sbin/sh",
2N/A "/usr/sbin/jsh",
2N/A "/usr/bin/pfsh",
2N/A "/usr/bin/pfcsh",
2N/A "/usr/bin/pfksh",
2N/A "/usr/bin/pfksh93",
2N/A "/usr/bin/bash",
2N/A "/usr/bin/tcsh",
2N/A "/usr/bin/zsh",
2N/A "/usr/bin/pfbash",
2N/A "/usr/bin/pftcsh",
2N/A "/usr/bin/pfzsh",
2N/A "/bin/pfsh",
2N/A "/bin/pfcsh",
2N/A "/bin/pfksh",
2N/A "/bin/pfksh93",
2N/A "/bin/bash",
2N/A "/bin/tcsh",
2N/A "/bin/zsh",
2N/A "/bin/pfbash",
2N/A "/bin/pftcsh",
2N/A "/bin/pfzsh",
2N/A "/usr/xpg4/bin/sh",
2N/A "/usr/xpg4/bin/pfsh",
2N/A "/sbin/pfsh",
2N/A "/usr/sbin/pfsh",
2N/A "/usr/sfw/bin/zsh",
2N/A NULL
2N/A};
2N/A
2N/Astatic char **shells, *strings;
2N/Astatic char **curshell;
2N/Astatic char **initshells(void);
2N/A
2N/A/*
2N/A * Get a list of shells from SHELLS, if it exists.
2N/A */
2N/Achar *
2N/Agetusershell(void)
2N/A{
2N/A char *ret;
2N/A
2N/A if (curshell == NULL)
2N/A curshell = initshells();
2N/A ret = *curshell;
2N/A if (ret != NULL)
2N/A curshell++;
2N/A return (ret);
2N/A}
2N/A
2N/Avoid
2N/Aendusershell(void)
2N/A{
2N/A
2N/A if (shells != NULL)
2N/A (void) free((char *)shells);
2N/A shells = NULL;
2N/A if (strings != NULL)
2N/A (void) free(strings);
2N/A strings = NULL;
2N/A curshell = NULL;
2N/A}
2N/A
2N/Avoid
2N/Asetusershell(void)
2N/A{
2N/A
2N/A curshell = initshells();
2N/A}
2N/A
2N/Astatic char **
2N/Ainitshells(void)
2N/A{
2N/A char **sp, *cp;
2N/A FILE *fp;
2N/A struct stat statb;
2N/A
2N/A if (shells != NULL)
2N/A (void) free((char *)shells);
2N/A shells = NULL;
2N/A if (strings != NULL)
2N/A (void) free(strings);
2N/A strings = NULL;
2N/A if ((fp = fopen(SHELLS, "rF")) == (FILE *)0)
2N/A return ((char **)okshells);
2N/A /*
2N/A * The +1 in the malloc() below is needed to handle the final
2N/A * fgets() NULL terminator. From fgets(3S):
2N/A *
2N/A * char *fgets(char *s, int n, FILE *stream);
2N/A *
2N/A * The fgets() function reads characters from the stream into
2N/A * the array pointed to by s, until n-1 characters are read, or
2N/A * a newline character is read and transferred to s, or an end-
2N/A * of-file condition is encountered. The string is then termi-
2N/A * nated with a null character.
2N/A */
2N/A if ((fstat(fileno(fp), &statb) == -1) || (statb.st_size > LONG_MAX) ||
2N/A ((strings = malloc((size_t)statb.st_size + 1)) == NULL)) {
2N/A (void) fclose(fp);
2N/A return ((char **)okshells);
2N/A }
2N/A shells = calloc((size_t)statb.st_size / 3, sizeof (char *));
2N/A if (shells == NULL) {
2N/A (void) fclose(fp);
2N/A (void) free(strings);
2N/A strings = NULL;
2N/A return ((char **)okshells);
2N/A }
2N/A sp = shells;
2N/A cp = strings;
2N/A while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
2N/A while (*cp != '#' && *cp != '/' && *cp != '\0')
2N/A cp++;
2N/A if (*cp == '#' || *cp == '\0')
2N/A continue;
2N/A *sp++ = cp;
2N/A while (!isspace(*cp) && *cp != '#' && *cp != '\0')
2N/A cp++;
2N/A *cp++ = '\0';
2N/A }
2N/A *sp = (char *)0;
2N/A (void) fclose(fp);
2N/A return (shells);
2N/A}