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