1 /*
2  * Copyright 2004 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 const char *okshells[] = {
36 	"/usr/bin/sh",
37 	"/usr/bin/csh",
38 	"/usr/bin/ksh",
39 	"/usr/bin/jsh",
40 	"/bin/sh",
41 	"/bin/csh",
42 	"/bin/ksh",
43 	"/bin/jsh",
44 	"/sbin/sh",
45 	"/sbin/jsh",
46 	"/usr/bin/pfsh",
47 	"/usr/bin/pfcsh",
48 	"/usr/bin/pfksh",
49 	"/usr/bin/bash",
50 	"/usr/bin/tcsh",
51 	"/usr/bin/zsh",
52 	"/bin/pfsh",
53 	"/bin/pfcsh",
54 	"/bin/pfksh",
55 	"/bin/bash",
56 	"/bin/tcsh",
57 	"/bin/zsh",
58 	"/usr/xpg4/bin/sh",
59 	"/sbin/pfsh",
60 	NULL
61 };
62 
63 static char **shells, *strings;
64 static char **curshell;
65 static char **initshells(void);
66 
67 /*
68  * Get a list of shells from SHELLS, if it exists.
69  */
70 char *
71 getusershell(void)
72 {
73 	char *ret;
74 
75 	if (curshell == NULL)
76 		curshell = initshells();
77 	ret = *curshell;
78 	if (ret != NULL)
79 		curshell++;
80 	return (ret);
81 }
82 
83 void
84 endusershell(void)
85 {
86 
87 	if (shells != NULL)
88 		(void) free((char *)shells);
89 	shells = NULL;
90 	if (strings != NULL)
91 		(void) free(strings);
92 	strings = NULL;
93 	curshell = NULL;
94 }
95 
96 void
97 setusershell(void)
98 {
99 
100 	curshell = initshells();
101 }
102 
103 static char **
104 initshells(void)
105 {
106 	char **sp, *cp;
107 	FILE *fp;
108 	struct stat statb;
109 
110 	if (shells != NULL)
111 		(void) free((char *)shells);
112 	shells = NULL;
113 	if (strings != NULL)
114 		(void) free(strings);
115 	strings = NULL;
116 	if ((fp = fopen(SHELLS, "r")) == (FILE *)0)
117 		return ((char **)okshells);
118 	/*
119 	 * The +1 in the malloc() below is needed to handle the final
120 	 * fgets() NULL terminator.  From fgets(3S):
121 	 *
122 	 * char *fgets(char *s, int n, FILE *stream);
123 	 *
124 	 * The  fgets()  function reads characters from the stream into
125 	 * the array pointed to by s, until n-1 characters are read, or
126 	 * a newline character is read and transferred to s, or an end-
127 	 * of-file condition is encountered.  The string is then termi-
128 	 * nated with a null character.
129 	 */
130 	if ((fstat(fileno(fp), &statb) == -1) || (statb.st_size > LONG_MAX) ||
131 	    ((strings = malloc((size_t)statb.st_size + 1)) == NULL)) {
132 		(void) fclose(fp);
133 		return ((char **)okshells);
134 	}
135 	shells = calloc((size_t)statb.st_size / 3, sizeof (char *));
136 	if (shells == NULL) {
137 		(void) fclose(fp);
138 		(void) free(strings);
139 		strings = NULL;
140 		return ((char **)okshells);
141 	}
142 	sp = shells;
143 	cp = strings;
144 	while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
145 		while (*cp != '#' && *cp != '/' && *cp != '\0')
146 			cp++;
147 		if (*cp == '#' || *cp == '\0')
148 			continue;
149 		*sp++ = cp;
150 		while (!isspace(*cp) && *cp != '#' && *cp != '\0')
151 			cp++;
152 		*cp++ = '\0';
153 	}
154 	*sp = (char *)0;
155 	(void) fclose(fp);
156 	return (shells);
157 }
158