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