1 /*
2 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
6 /* All Rights Reserved */
7
8 /*
9 * Copyright (c) 1985 Regents of the University of California.
10 * All rights reserved. The Berkeley software License Agreement
11 * specifies the terms and conditions for redistribution.
12 */
13
14 #include "lint.h"
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/stat.h>
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <limits.h>
21 #include <stdlib.h>
22 #include <sys/file.h>
23 #include "libc.h"
24 #include <unistd.h>
25
26 #define SHELLS "/etc/shells"
27
28 /*
29 * Do not add local shells here. They should be added in /etc/shells
30 *
31 * Do not add restricted shells:
32 * Shells returned by getusershell traditionally allow:
33 * - users to change away from (i.e., if you have an rksh in
34 * getusershell(), then users can change their shell to ksh)
35 * - by default, ftp in is allowed only for shells returned by
36 * getusershell(); since FTP has no restrictions on directory
37 * movement, adding rksh to getusershell() would defeat that
38 * protection.
39 */
40 const char *okshells[] = {
41 "/usr/bin/sh",
42 "/usr/bin/csh",
43 "/usr/bin/ksh",
44 "/usr/bin/ksh93",
45 "/usr/bin/jsh",
46 "/bin/sh",
47 "/bin/csh",
48 "/bin/ksh",
49 "/bin/ksh93",
50 "/bin/jsh",
51 "/sbin/sh",
52 "/sbin/jsh",
53 "/usr/bin/pfsh",
54 "/usr/bin/pfcsh",
55 "/usr/bin/pfksh",
56 "/usr/bin/pfksh93",
57 "/usr/bin/bash",
58 "/usr/bin/tcsh",
59 "/usr/bin/zsh",
60 "/usr/bin/pfbash",
61 "/usr/bin/pftcsh",
62 "/usr/bin/pfzsh",
63 "/bin/pfsh",
64 "/bin/pfcsh",
65 "/bin/pfksh",
66 "/bin/pfksh93",
67 "/bin/bash",
68 "/bin/tcsh",
69 "/bin/zsh",
70 "/bin/pfbash",
71 "/bin/pftcsh",
72 "/bin/pfzsh",
73 "/usr/xpg4/bin/sh",
74 "/usr/xpg4/bin/pfsh",
75 "/sbin/pfsh",
76 "/usr/sfw/bin/zsh",
77 NULL
78 };
79
80 static char **shells, *strings;
81 static char **curshell;
82 static char **initshells(void);
83
84 /*
85 * Get a list of shells from SHELLS, if it exists.
86 */
87 char *
getusershell(void)88 getusershell(void)
89 {
90 char *ret;
91
92 if (curshell == NULL)
93 curshell = initshells();
94 ret = *curshell;
95 if (ret != NULL)
96 curshell++;
97 return (ret);
98 }
99
100 void
endusershell(void)101 endusershell(void)
102 {
103
104 if (shells != NULL)
105 (void) free((char *)shells);
106 shells = NULL;
107 if (strings != NULL)
108 (void) free(strings);
109 strings = NULL;
110 curshell = NULL;
111 }
112
113 void
setusershell(void)114 setusershell(void)
115 {
116
117 curshell = initshells();
118 }
119
120 static char **
initshells(void)121 initshells(void)
122 {
123 char **sp, *cp;
124 FILE *fp;
125 struct stat statb;
126
127 if (shells != NULL)
128 (void) free((char *)shells);
129 shells = NULL;
130 if (strings != NULL)
131 (void) free(strings);
132 strings = NULL;
133 if ((fp = fopen(SHELLS, "rF")) == (FILE *)0)
134 return ((char **)okshells);
135 /*
136 * The +1 in the malloc() below is needed to handle the final
137 * fgets() NULL terminator. From fgets(3S):
138 *
139 * char *fgets(char *s, int n, FILE *stream);
140 *
141 * The fgets() function reads characters from the stream into
142 * the array pointed to by s, until n-1 characters are read, or
143 * a newline character is read and transferred to s, or an end-
144 * of-file condition is encountered. The string is then termi-
145 * nated with a null character.
146 */
147 if ((fstat(fileno(fp), &statb) == -1) || (statb.st_size > LONG_MAX) ||
148 ((strings = malloc((size_t)statb.st_size + 1)) == NULL)) {
149 (void) fclose(fp);
150 return ((char **)okshells);
151 }
152 shells = calloc((size_t)statb.st_size / 3, sizeof (char *));
153 if (shells == NULL) {
154 (void) fclose(fp);
155 (void) free(strings);
156 strings = NULL;
157 return ((char **)okshells);
158 }
159 sp = shells;
160 cp = strings;
161 while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
162 while (*cp != '#' && *cp != '/' && *cp != '\0')
163 cp++;
164 if (*cp == '#' || *cp == '\0')
165 continue;
166 *sp++ = cp;
167 while (!isspace(*cp) && *cp != '#' && *cp != '\0')
168 cp++;
169 *cp++ = '\0';
170 }
171 *sp = (char *)0;
172 (void) fclose(fp);
173 return (shells);
174 }
175