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