xref: /illumos-gate/usr/src/lib/libc/port/gen/getusershell.c (revision 948f2876ce2a3010558f4f6937e16086ebcd36f2)
1 /*
2  * Copyright 2006 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 	"/usr/sfw/bin/zsh",
61 	NULL
62 };
63 
64 static char **shells, *strings;
65 static char **curshell;
66 static char **initshells(void);
67 
68 /*
69  * Get a list of shells from SHELLS, if it exists.
70  */
71 char *
72 getusershell(void)
73 {
74 	char *ret;
75 
76 	if (curshell == NULL)
77 		curshell = initshells();
78 	ret = *curshell;
79 	if (ret != NULL)
80 		curshell++;
81 	return (ret);
82 }
83 
84 void
85 endusershell(void)
86 {
87 
88 	if (shells != NULL)
89 		(void) free((char *)shells);
90 	shells = NULL;
91 	if (strings != NULL)
92 		(void) free(strings);
93 	strings = NULL;
94 	curshell = NULL;
95 }
96 
97 void
98 setusershell(void)
99 {
100 
101 	curshell = initshells();
102 }
103 
104 static char **
105 initshells(void)
106 {
107 	char **sp, *cp;
108 	FILE *fp;
109 	struct stat statb;
110 
111 	if (shells != NULL)
112 		(void) free((char *)shells);
113 	shells = NULL;
114 	if (strings != NULL)
115 		(void) free(strings);
116 	strings = NULL;
117 	if ((fp = fopen(SHELLS, "rF")) == (FILE *)0)
118 		return ((char **)okshells);
119 	/*
120 	 * The +1 in the malloc() below is needed to handle the final
121 	 * fgets() NULL terminator.  From fgets(3S):
122 	 *
123 	 * char *fgets(char *s, int n, FILE *stream);
124 	 *
125 	 * The  fgets()  function reads characters from the stream into
126 	 * the array pointed to by s, until n-1 characters are read, or
127 	 * a newline character is read and transferred to s, or an end-
128 	 * of-file condition is encountered.  The string is then termi-
129 	 * nated with a null character.
130 	 */
131 	if ((fstat(fileno(fp), &statb) == -1) || (statb.st_size > LONG_MAX) ||
132 	    ((strings = malloc((size_t)statb.st_size + 1)) == NULL)) {
133 		(void) fclose(fp);
134 		return ((char **)okshells);
135 	}
136 	shells = calloc((size_t)statb.st_size / 3, sizeof (char *));
137 	if (shells == NULL) {
138 		(void) fclose(fp);
139 		(void) free(strings);
140 		strings = NULL;
141 		return ((char **)okshells);
142 	}
143 	sp = shells;
144 	cp = strings;
145 	while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
146 		while (*cp != '#' && *cp != '/' && *cp != '\0')
147 			cp++;
148 		if (*cp == '#' || *cp == '\0')
149 			continue;
150 		*sp++ = cp;
151 		while (!isspace(*cp) && *cp != '#' && *cp != '\0')
152 			cp++;
153 		*cp++ = '\0';
154 	}
155 	*sp = (char *)0;
156 	(void) fclose(fp);
157 	return (shells);
158 }
159