getusershell.c revision 1.18.4.1 1 /* $NetBSD: getusershell.c,v 1.18.4.1 1999/12/27 18:29:37 wrstuden Exp $ */
2
3 /*
4 * Copyright (c) 1985, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #if defined(LIBC_SCCS) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)getusershell.c 8.1 (Berkeley) 6/4/93";
40 #else
41 __RCSID("$NetBSD: getusershell.c,v 1.18.4.1 1999/12/27 18:29:37 wrstuden Exp $");
42 #endif
43 #endif /* LIBC_SCCS and not lint */
44
45 #include "namespace.h"
46 #include <sys/param.h>
47 #include <sys/file.h>
48
49 #include <ctype.h>
50 #include <errno.h>
51 #include <nsswitch.h>
52 #include <paths.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stringlist.h>
57 #include <unistd.h>
58
59 #ifdef __STDC__
60 #include <stdarg.h>
61 #else
62 #include <varargs.h>
63 #endif
64
65 #ifdef HESIOD
66 #include <hesiod.h>
67 #endif
68 #ifdef YP
69 #include <rpc/rpc.h>
70 #include <rpcsvc/ypclnt.h>
71 #include <rpcsvc/yp_prot.h>
72 #endif
73
74 #ifdef __weak_alias
75 __weak_alias(endusershell,_endusershell);
76 __weak_alias(getusershell,_getusershell);
77 __weak_alias(setusershell,_setusershell);
78 #endif
79
80 /*
81 * Local shells should NOT be added here. They should be added in
82 * /etc/shells.
83 */
84
85 static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
86 static const char *const *curshell;
87 static StringList *sl;
88
89 static const char *const *initshells __P((void));
90
91 /*
92 * Get a list of shells from "shells" nsswitch database
93 */
94 __aconst char *
95 getusershell()
96 {
97 __aconst char *ret;
98
99 if (curshell == NULL)
100 curshell = initshells();
101 /*LINTED*/
102 ret = (__aconst char *)*curshell;
103 if (ret != NULL)
104 curshell++;
105 return (ret);
106 }
107
108 void
109 endusershell()
110 {
111 if (sl)
112 sl_free(sl, 1);
113 sl = NULL;
114 curshell = NULL;
115 }
116
117 void
118 setusershell()
119 {
120
121 curshell = initshells();
122 }
123
124
125 static int _local_initshells __P((void *, void *, va_list));
126
127 /*ARGSUSED*/
128 static int
129 _local_initshells(rv, cb_data, ap)
130 void *rv;
131 void *cb_data;
132 va_list ap;
133 {
134 char *sp, *cp;
135 FILE *fp;
136 char line[MAXPATHLEN + 2];
137
138 if (sl)
139 sl_free(sl, 1);
140 sl = sl_init();
141 if (!sl)
142 return (NS_UNAVAIL);
143
144 if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
145 return (NS_UNAVAIL);
146
147 sp = cp = line;
148 while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
149 while (*cp != '#' && *cp != '/' && *cp != '\0')
150 cp++;
151 if (*cp == '#' || *cp == '\0')
152 continue;
153 sp = cp;
154 while (!isspace(*cp) && *cp != '#' && *cp != '\0')
155 cp++;
156 *cp++ = '\0';
157 if (sl_add(sl, strdup(sp)) == -1)
158 return (NS_UNAVAIL);
159 }
160 (void)fclose(fp);
161 return (NS_SUCCESS);
162 }
163
164 #ifdef HESIOD
165 static int _dns_initshells __P((void *, void *, va_list));
166
167 /*ARGSUSED*/
168 static int
169 _dns_initshells(rv, cb_data, ap)
170 void *rv;
171 void *cb_data;
172 va_list ap;
173 {
174 char shellname[] = "shells-XXXXX";
175 int hsindex, hpi, r;
176 char **hp;
177 void *context;
178
179 if (sl)
180 sl_free(sl, 1);
181 sl = sl_init();
182 if (!sl)
183 return (NS_UNAVAIL);
184
185 r = NS_UNAVAIL;
186 if (hesiod_init(&context) == -1)
187 return (r);
188
189 for (hsindex = 0; ; hsindex++) {
190 snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
191 hp = hesiod_resolve(context, shellname, "shells");
192 if (hp == NULL) {
193 if (errno == ENOENT) {
194 if (hsindex == 0)
195 r = NS_NOTFOUND;
196 else
197 r = NS_SUCCESS;
198 }
199 break;
200 } else {
201 int bad = 0;
202
203 for (hpi = 0; hp[hpi]; hpi++)
204 if (sl_add(sl, hp[hpi]) == -1) {
205 bad = 1;
206 break;
207 }
208 free(hp);
209 if (bad)
210 break;
211 }
212 }
213 hesiod_end(context);
214 return (r);
215 }
216 #endif /* HESIOD */
217
218 #ifdef YP
219 static int _nis_initshells __P((void *, void *, va_list));
220
221 /*ARGSUSED*/
222 static int
223 _nis_initshells(rv, cb_data, ap)
224 void *rv;
225 void *cb_data;
226 va_list ap;
227 {
228 static char *ypdomain;
229
230 if (sl)
231 sl_free(sl, 1);
232 sl = sl_init();
233 if (!sl)
234 return (NS_UNAVAIL);
235
236 if (ypdomain == NULL) {
237 switch (yp_get_default_domain(&ypdomain)) {
238 case 0:
239 break;
240 case YPERR_RESRC:
241 return (NS_TRYAGAIN);
242 default:
243 return (NS_UNAVAIL);
244 }
245 }
246
247 for (;;) {
248 char *ypcur = NULL;
249 int ypcurlen = 0; /* XXX: GCC */
250 char *key, *data;
251 int keylen, datalen;
252 int r;
253
254 key = data = NULL;
255 if (ypcur) {
256 r = yp_next(ypdomain, "shells", ypcur, ypcurlen,
257 &key, &keylen, &data, &datalen);
258 free(ypcur);
259 switch (r) {
260 case 0:
261 break;
262 case YPERR_NOMORE:
263 free(key);
264 free(data);
265 return (NS_SUCCESS);
266 default:
267 free(key);
268 free(data);
269 return (NS_UNAVAIL);
270 }
271 ypcur = key;
272 ypcurlen = keylen;
273 } else {
274 if (yp_first(ypdomain, "shells", &ypcur,
275 &ypcurlen, &data, &datalen)) {
276 free(data);
277 return (NS_UNAVAIL);
278 }
279 }
280 data[datalen] = '\0'; /* clear trailing \n */
281 if (sl_add(sl, data) == -1)
282 return (NS_UNAVAIL);
283 }
284 }
285 #endif /* YP */
286
287 static const char *const *
288 initshells()
289 {
290 static const ns_dtab dtab[] = {
291 NS_FILES_CB(_local_initshells, NULL)
292 NS_DNS_CB(_dns_initshells, NULL)
293 NS_NIS_CB(_nis_initshells, NULL)
294 { 0 }
295 };
296 if (sl)
297 sl_free(sl, 1);
298 sl = sl_init();
299 if (!sl)
300 goto badinitshells;
301
302 if (nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
303 != NS_SUCCESS) {
304 badinitshells:
305 if (sl)
306 sl_free(sl, 1);
307 sl = NULL;
308 return (okshells);
309 }
310 if (sl_add(sl, NULL) == -1)
311 goto badinitshells;
312
313 return (const char *const *)(sl->sl_str);
314 }
315