getusershell.c revision 1.16 1 /* $NetBSD: getusershell.c,v 1.16 1999/01/20 13:11:18 christos 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.16 1999/01/20 13:11:18 christos 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 #include <stdio.h>
49 #include <ctype.h>
50 #include <nsswitch.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <paths.h>
54 #include <string.h>
55 #include <stringlist.h>
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
133 if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
134 return NS_UNAVAIL;
135
136 sp = cp = line;
137 while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
138 while (*cp != '#' && *cp != '/' && *cp != '\0')
139 cp++;
140 if (*cp == '#' || *cp == '\0')
141 continue;
142 sp = cp;
143 while (!isspace(*cp) && *cp != '#' && *cp != '\0')
144 cp++;
145 *cp++ = '\0';
146 sl_add(sl, strdup(sp));
147 }
148 (void)fclose(fp);
149 return NS_SUCCESS;
150 }
151
152 #ifdef HESIOD
153 static int _dns_initshells __P((void *, void *, va_list));
154
155 /*ARGSUSED*/
156 static int
157 _dns_initshells(rv, cb_data, ap)
158 void *rv;
159 void *cb_data;
160 va_list ap;
161 {
162 char shellname[] = "shells-XXXXX";
163 int hsindex, hpi;
164 char **hp;
165
166 if (sl)
167 sl_free(sl, 1);
168 sl = sl_init();
169
170 for (hsindex = 0; ; hsindex++) {
171 snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
172 hp = hes_resolve(shellname, "shells");
173 if (hp == NULL) {
174 switch(hes_error()) {
175 case HES_ER_OK:
176 break;
177 case HES_ER_NOTFOUND:
178 if (hsindex == 0)
179 return NS_NOTFOUND;
180 return NS_SUCCESS;
181 default:
182 return NS_UNAVAIL;
183 }
184 } else {
185 for (hpi = 0; hp[hpi]; hpi++)
186 sl_add(sl, hp[hpi]);
187 free(hp);
188 }
189 }
190 }
191 #endif /* HESIOD */
192
193 #ifdef YP
194 static int _nis_initshells __P((void *, void *, va_list));
195
196 /*ARGSUSED*/
197 static int
198 _nis_initshells(rv, cb_data, ap)
199 void *rv;
200 void *cb_data;
201 va_list ap;
202 {
203 static char *ypdomain;
204
205 if (sl)
206 sl_free(sl, 1);
207 sl = sl_init();
208
209 if (ypdomain == NULL) {
210 switch (yp_get_default_domain(&ypdomain)) {
211 case 0:
212 break;
213 case YPERR_RESRC:
214 return NS_TRYAGAIN;
215 default:
216 return NS_UNAVAIL;
217 }
218 }
219
220 for (;;) {
221 char *ypcur = NULL;
222 int ypcurlen = 0; /* XXX: GCC */
223 char *key, *data;
224 int keylen, datalen;
225 int r;
226
227 key = data = NULL;
228 if (ypcur) {
229 r = yp_next(ypdomain, "shells", ypcur, ypcurlen,
230 &key, &keylen, &data, &datalen);
231 free(ypcur);
232 switch (r) {
233 case 0:
234 break;
235 case YPERR_NOMORE:
236 free(key);
237 free(data);
238 return NS_SUCCESS;
239 default:
240 free(key);
241 free(data);
242 return NS_UNAVAIL;
243 }
244 ypcur = key;
245 ypcurlen = keylen;
246 } else {
247 if (yp_first(ypdomain, "shells", &ypcur,
248 &ypcurlen, &data, &datalen)) {
249 free(data);
250 return NS_UNAVAIL;
251 }
252 }
253 data[datalen] = '\0'; /* clear trailing \n */
254 sl_add(sl, data);
255 }
256 }
257 #endif /* YP */
258
259 static const char *const *
260 initshells()
261 {
262 static const ns_dtab dtab[] = {
263 NS_FILES_CB(_local_initshells, NULL)
264 NS_DNS_CB(_dns_initshells, NULL)
265 NS_NIS_CB(_nis_initshells, NULL)
266 { 0 }
267 };
268 if (sl)
269 sl_free(sl, 1);
270 sl = sl_init();
271
272 if (nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
273 != NS_SUCCESS) {
274 if (sl)
275 sl_free(sl, 1);
276 sl = NULL;
277 return (okshells);
278 }
279 sl_add(sl, NULL);
280
281 return (const char *const *)(sl->sl_str);
282 }
283