1/*
2 * Copyright (c) 1985, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34RCSID("$Id: getusershell.c 21005 2007-06-08 01:54:35Z lha $");
35
36#ifndef HAVE_GETUSERSHELL
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <ctype.h>
42#ifdef HAVE_PATHS_H
43#include <paths.h>
44#endif
45#ifdef HAVE_SYS_TYPES_H
46#include <sys/types.h>
47#endif
48#ifdef HAVE_SYS_STAT_H
49#include <sys/stat.h>
50#endif
51#ifdef HAVE_SYS_PARAM_H
52#include <sys/param.h>
53#endif
54
55#ifdef HAVE_USERSEC_H
56struct aud_rec;
57#include <usersec.h>
58#endif
59#ifdef HAVE_USERCONF_H
60#include <userconf.h>
61#endif
62#include "roken.h"
63
64#ifndef _PATH_SHELLS
65#define _PATH_SHELLS "/etc/shells"
66#endif
67
68#ifndef _PATH_BSHELL
69#define _PATH_BSHELL "/bin/sh"
70#endif
71
72#ifndef _PATH_CSHELL
73#define _PATH_CSHELL "/bin/csh"
74#endif
75
76/*
77 * Local shells should NOT be added here.  They should be added in
78 * /etc/shells.
79 */
80
81static char *okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
82static char **curshell, **shells, *strings;
83static char **initshells (void);
84
85/*
86 * Get a list of shells from _PATH_SHELLS, if it exists.
87 */
88char * ROKEN_LIB_FUNCTION
89getusershell()
90{
91    char *ret;
92
93    if (curshell == NULL)
94	curshell = initshells();
95    ret = *curshell;
96    if (ret != NULL)
97	curshell++;
98    return (ret);
99}
100
101void ROKEN_LIB_FUNCTION
102endusershell()
103{
104    if (shells != NULL)
105	free(shells);
106    shells = NULL;
107    if (strings != NULL)
108	free(strings);
109    strings = NULL;
110    curshell = NULL;
111}
112
113void ROKEN_LIB_FUNCTION
114setusershell()
115{
116    curshell = initshells();
117}
118
119static char **
120initshells()
121{
122    char **sp, *cp;
123#ifdef HAVE_GETCONFATTR
124    char *tmp;
125    int nsh;
126#else
127    FILE *fp;
128#endif
129    struct stat statb;
130
131    free(shells);
132    shells = NULL;
133    free(strings);
134    strings = NULL;
135#ifdef HAVE_GETCONFATTR
136    if(getconfattr(SC_SYS_LOGIN, SC_SHELLS, &tmp, SEC_LIST) != 0)
137	return okshells;
138
139    for(cp = tmp, nsh = 0; *cp; cp += strlen(cp) + 1, nsh++);
140
141    shells = calloc(nsh + 1, sizeof(*shells));
142    if(shells == NULL)
143	return okshells;
144
145    strings = malloc(cp - tmp);
146    if(strings == NULL) {
147	free(shells);
148	shells = NULL;
149	return okshells;
150    }
151    memcpy(strings, tmp, cp - tmp);
152    for(sp = shells, cp = strings; *cp; cp += strlen(cp) + 1, sp++)
153	*sp = cp;
154#else
155    if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
156	return (okshells);
157    if (fstat(fileno(fp), &statb) == -1) {
158	fclose(fp);
159	return (okshells);
160    }
161    if ((strings = malloc((u_int)statb.st_size)) == NULL) {
162	fclose(fp);
163	return (okshells);
164    }
165    shells = calloc((unsigned)statb.st_size / 3, sizeof (char *));
166    if (shells == NULL) {
167	fclose(fp);
168	free(strings);
169	strings = NULL;
170	return (okshells);
171    }
172    sp = shells;
173    cp = strings;
174    while (fgets(cp, MaxPathLen + 1, fp) != NULL) {
175	while (*cp != '#' && *cp != '/' && *cp != '\0')
176	    cp++;
177	if (*cp == '#' || *cp == '\0')
178	    continue;
179	*sp++ = cp;
180	while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != '\0')
181	    cp++;
182	*cp++ = '\0';
183    }
184    fclose(fp);
185#endif
186    *sp = NULL;
187    return (shells);
188}
189#endif /* HAVE_GETUSERSHELL */
190