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