xref: /onnv-gate/usr/src/lib/libc/port/gen/getusershell.c (revision 12273:63678502e95e)
10Sstevel@tonic-gate /*
2*12273SCasper.Dik@Sun.COM  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate  */
40Sstevel@tonic-gate 
50Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
60Sstevel@tonic-gate /*	  All Rights Reserved  	*/
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  * Copyright (c) 1985 Regents of the University of California.
100Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
110Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
120Sstevel@tonic-gate  */
130Sstevel@tonic-gate 
146812Sraf #include "lint.h"
150Sstevel@tonic-gate #include <sys/types.h>
160Sstevel@tonic-gate #include <sys/param.h>
170Sstevel@tonic-gate #include <sys/stat.h>
180Sstevel@tonic-gate #include <ctype.h>
190Sstevel@tonic-gate #include <stdio.h>
200Sstevel@tonic-gate #include <limits.h>
210Sstevel@tonic-gate #include <stdlib.h>
220Sstevel@tonic-gate #include <sys/file.h>
230Sstevel@tonic-gate #include "libc.h"
240Sstevel@tonic-gate #include <unistd.h>
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #define	SHELLS "/etc/shells"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Do not add local shells here.  They should be added in /etc/shells
304887Schin  *
314887Schin  * Do not add restricted shells:
324887Schin  * Shells returned by getusershell traditionally allow:
334887Schin  * - users to change away from (i.e., if you have an rksh in
344887Schin  *   getusershell(), then users can change their shell to ksh)
354887Schin  * - by default, ftp in is allowed only for shells returned by
364887Schin  *   getusershell(); since FTP has no restrictions on directory
374887Schin  *   movement, adding rksh to getusershell() would defeat that
384887Schin  *   protection.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate const char *okshells[] = {
410Sstevel@tonic-gate 	"/usr/bin/sh",
420Sstevel@tonic-gate 	"/usr/bin/csh",
430Sstevel@tonic-gate 	"/usr/bin/ksh",
444887Schin 	"/usr/bin/ksh93",
450Sstevel@tonic-gate 	"/usr/bin/jsh",
460Sstevel@tonic-gate 	"/bin/sh",
470Sstevel@tonic-gate 	"/bin/csh",
480Sstevel@tonic-gate 	"/bin/ksh",
494887Schin 	"/bin/ksh93",
500Sstevel@tonic-gate 	"/bin/jsh",
510Sstevel@tonic-gate 	"/sbin/sh",
520Sstevel@tonic-gate 	"/sbin/jsh",
530Sstevel@tonic-gate 	"/usr/bin/pfsh",
540Sstevel@tonic-gate 	"/usr/bin/pfcsh",
550Sstevel@tonic-gate 	"/usr/bin/pfksh",
56*12273SCasper.Dik@Sun.COM 	"/usr/bin/pfksh93",
570Sstevel@tonic-gate 	"/usr/bin/bash",
580Sstevel@tonic-gate 	"/usr/bin/tcsh",
590Sstevel@tonic-gate 	"/usr/bin/zsh",
60*12273SCasper.Dik@Sun.COM 	"/usr/bin/pfbash",
61*12273SCasper.Dik@Sun.COM 	"/usr/bin/pftcsh",
62*12273SCasper.Dik@Sun.COM 	"/usr/bin/pfzsh",
630Sstevel@tonic-gate 	"/bin/pfsh",
640Sstevel@tonic-gate 	"/bin/pfcsh",
650Sstevel@tonic-gate 	"/bin/pfksh",
66*12273SCasper.Dik@Sun.COM 	"/bin/pfksh93",
670Sstevel@tonic-gate 	"/bin/bash",
680Sstevel@tonic-gate 	"/bin/tcsh",
690Sstevel@tonic-gate 	"/bin/zsh",
70*12273SCasper.Dik@Sun.COM 	"/bin/pfbash",
71*12273SCasper.Dik@Sun.COM 	"/bin/pftcsh",
72*12273SCasper.Dik@Sun.COM 	"/bin/pfzsh",
730Sstevel@tonic-gate 	"/usr/xpg4/bin/sh",
74*12273SCasper.Dik@Sun.COM 	"/usr/xpg4/bin/pfsh",
750Sstevel@tonic-gate 	"/sbin/pfsh",
762037Scraigm 	"/usr/sfw/bin/zsh",
770Sstevel@tonic-gate 	NULL
780Sstevel@tonic-gate };
790Sstevel@tonic-gate 
800Sstevel@tonic-gate static char **shells, *strings;
810Sstevel@tonic-gate static char **curshell;
820Sstevel@tonic-gate static char **initshells(void);
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate  * Get a list of shells from SHELLS, if it exists.
860Sstevel@tonic-gate  */
870Sstevel@tonic-gate char *
getusershell(void)880Sstevel@tonic-gate getusershell(void)
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	char *ret;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	if (curshell == NULL)
930Sstevel@tonic-gate 		curshell = initshells();
940Sstevel@tonic-gate 	ret = *curshell;
950Sstevel@tonic-gate 	if (ret != NULL)
960Sstevel@tonic-gate 		curshell++;
970Sstevel@tonic-gate 	return (ret);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate void
endusershell(void)1010Sstevel@tonic-gate endusershell(void)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	if (shells != NULL)
1050Sstevel@tonic-gate 		(void) free((char *)shells);
1060Sstevel@tonic-gate 	shells = NULL;
1070Sstevel@tonic-gate 	if (strings != NULL)
1080Sstevel@tonic-gate 		(void) free(strings);
1090Sstevel@tonic-gate 	strings = NULL;
1100Sstevel@tonic-gate 	curshell = NULL;
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate void
setusershell(void)1140Sstevel@tonic-gate setusershell(void)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	curshell = initshells();
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static char **
initshells(void)1210Sstevel@tonic-gate initshells(void)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate 	char **sp, *cp;
1240Sstevel@tonic-gate 	FILE *fp;
1250Sstevel@tonic-gate 	struct stat statb;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	if (shells != NULL)
1280Sstevel@tonic-gate 		(void) free((char *)shells);
1290Sstevel@tonic-gate 	shells = NULL;
1300Sstevel@tonic-gate 	if (strings != NULL)
1310Sstevel@tonic-gate 		(void) free(strings);
1320Sstevel@tonic-gate 	strings = NULL;
1331914Scasper 	if ((fp = fopen(SHELLS, "rF")) == (FILE *)0)
1340Sstevel@tonic-gate 		return ((char **)okshells);
1350Sstevel@tonic-gate 	/*
1360Sstevel@tonic-gate 	 * The +1 in the malloc() below is needed to handle the final
1370Sstevel@tonic-gate 	 * fgets() NULL terminator.  From fgets(3S):
1380Sstevel@tonic-gate 	 *
1390Sstevel@tonic-gate 	 * char *fgets(char *s, int n, FILE *stream);
1400Sstevel@tonic-gate 	 *
1410Sstevel@tonic-gate 	 * The  fgets()  function reads characters from the stream into
1420Sstevel@tonic-gate 	 * the array pointed to by s, until n-1 characters are read, or
1430Sstevel@tonic-gate 	 * a newline character is read and transferred to s, or an end-
1440Sstevel@tonic-gate 	 * of-file condition is encountered.  The string is then termi-
1450Sstevel@tonic-gate 	 * nated with a null character.
1460Sstevel@tonic-gate 	 */
1470Sstevel@tonic-gate 	if ((fstat(fileno(fp), &statb) == -1) || (statb.st_size > LONG_MAX) ||
1480Sstevel@tonic-gate 	    ((strings = malloc((size_t)statb.st_size + 1)) == NULL)) {
1490Sstevel@tonic-gate 		(void) fclose(fp);
1500Sstevel@tonic-gate 		return ((char **)okshells);
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 	shells = calloc((size_t)statb.st_size / 3, sizeof (char *));
1530Sstevel@tonic-gate 	if (shells == NULL) {
1540Sstevel@tonic-gate 		(void) fclose(fp);
1550Sstevel@tonic-gate 		(void) free(strings);
1560Sstevel@tonic-gate 		strings = NULL;
1570Sstevel@tonic-gate 		return ((char **)okshells);
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 	sp = shells;
1600Sstevel@tonic-gate 	cp = strings;
1610Sstevel@tonic-gate 	while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
1620Sstevel@tonic-gate 		while (*cp != '#' && *cp != '/' && *cp != '\0')
1630Sstevel@tonic-gate 			cp++;
1640Sstevel@tonic-gate 		if (*cp == '#' || *cp == '\0')
1650Sstevel@tonic-gate 			continue;
1660Sstevel@tonic-gate 		*sp++ = cp;
1670Sstevel@tonic-gate 		while (!isspace(*cp) && *cp != '#' && *cp != '\0')
1680Sstevel@tonic-gate 			cp++;
1690Sstevel@tonic-gate 		*cp++ = '\0';
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 	*sp = (char *)0;
1720Sstevel@tonic-gate 	(void) fclose(fp);
1730Sstevel@tonic-gate 	return (shells);
1740Sstevel@tonic-gate }
175