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 * 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 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 114 setusershell(void) 115 { 116 117 curshell = initshells(); 118 } 119 120 static char ** 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