1 /* $NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem 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.17 1999/01/25 01:09:34 lukem 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 HESIOD 60 #include <hesiod.h> 61 #endif 62 #ifdef YP 63 #include <rpc/rpc.h> 64 #include <rpcsvc/ypclnt.h> 65 #include <rpcsvc/yp_prot.h> 66 #endif 67 68 #ifdef __weak_alias 69 __weak_alias(endusershell,_endusershell); 70 __weak_alias(getusershell,_getusershell); 71 __weak_alias(setusershell,_setusershell); 72 #endif 73 74 /* 75 * Local shells should NOT be added here. They should be added in 76 * /etc/shells. 77 */ 78 79 static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL }; 80 static const char *const *curshell; 81 static StringList *sl; 82 83 static const char *const *initshells __P((void)); 84 85 /* 86 * Get a list of shells from "shells" nsswitch database 87 */ 88 __aconst char * 89 getusershell() 90 { 91 __aconst char *ret; 92 93 if (curshell == NULL) 94 curshell = initshells(); 95 /*LINTED*/ 96 ret = (__aconst char *)*curshell; 97 if (ret != NULL) 98 curshell++; 99 return (ret); 100 } 101 102 void 103 endusershell() 104 { 105 if (sl) 106 sl_free(sl, 1); 107 sl = NULL; 108 curshell = NULL; 109 } 110 111 void 112 setusershell() 113 { 114 115 curshell = initshells(); 116 } 117 118 119 static int _local_initshells __P((void *, void *, va_list)); 120 121 /*ARGSUSED*/ 122 static int 123 _local_initshells(rv, cb_data, ap) 124 void *rv; 125 void *cb_data; 126 va_list ap; 127 { 128 char *sp, *cp; 129 FILE *fp; 130 char line[MAXPATHLEN + 2]; 131 132 if (sl) 133 sl_free(sl, 1); 134 sl = sl_init(); 135 136 if ((fp = fopen(_PATH_SHELLS, "r")) == NULL) 137 return NS_UNAVAIL; 138 139 sp = cp = line; 140 while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) { 141 while (*cp != '#' && *cp != '/' && *cp != '\0') 142 cp++; 143 if (*cp == '#' || *cp == '\0') 144 continue; 145 sp = cp; 146 while (!isspace(*cp) && *cp != '#' && *cp != '\0') 147 cp++; 148 *cp++ = '\0'; 149 sl_add(sl, strdup(sp)); 150 } 151 (void)fclose(fp); 152 return NS_SUCCESS; 153 } 154 155 #ifdef HESIOD 156 static int _dns_initshells __P((void *, void *, va_list)); 157 158 /*ARGSUSED*/ 159 static int 160 _dns_initshells(rv, cb_data, ap) 161 void *rv; 162 void *cb_data; 163 va_list ap; 164 { 165 char shellname[] = "shells-XXXXX"; 166 int hsindex, hpi, r; 167 char **hp; 168 void *context; 169 170 if (sl) 171 sl_free(sl, 1); 172 sl = sl_init(); 173 r = NS_UNAVAIL; 174 if (hesiod_init(&context) == -1) 175 return (r); 176 177 for (hsindex = 0; ; hsindex++) { 178 snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex); 179 hp = hesiod_resolve(context, shellname, "shells"); 180 if (hp == NULL) { 181 if (errno == ENOENT) { 182 if (hsindex == 0) 183 r = NS_NOTFOUND; 184 else 185 r = NS_SUCCESS; 186 } 187 break; 188 } else { 189 for (hpi = 0; hp[hpi]; hpi++) 190 sl_add(sl, hp[hpi]); 191 free(hp); 192 } 193 } 194 hesiod_end(context); 195 return (r); 196 } 197 #endif /* HESIOD */ 198 199 #ifdef YP 200 static int _nis_initshells __P((void *, void *, va_list)); 201 202 /*ARGSUSED*/ 203 static int 204 _nis_initshells(rv, cb_data, ap) 205 void *rv; 206 void *cb_data; 207 va_list ap; 208 { 209 static char *ypdomain; 210 211 if (sl) 212 sl_free(sl, 1); 213 sl = sl_init(); 214 215 if (ypdomain == NULL) { 216 switch (yp_get_default_domain(&ypdomain)) { 217 case 0: 218 break; 219 case YPERR_RESRC: 220 return NS_TRYAGAIN; 221 default: 222 return NS_UNAVAIL; 223 } 224 } 225 226 for (;;) { 227 char *ypcur = NULL; 228 int ypcurlen = 0; /* XXX: GCC */ 229 char *key, *data; 230 int keylen, datalen; 231 int r; 232 233 key = data = NULL; 234 if (ypcur) { 235 r = yp_next(ypdomain, "shells", ypcur, ypcurlen, 236 &key, &keylen, &data, &datalen); 237 free(ypcur); 238 switch (r) { 239 case 0: 240 break; 241 case YPERR_NOMORE: 242 free(key); 243 free(data); 244 return NS_SUCCESS; 245 default: 246 free(key); 247 free(data); 248 return NS_UNAVAIL; 249 } 250 ypcur = key; 251 ypcurlen = keylen; 252 } else { 253 if (yp_first(ypdomain, "shells", &ypcur, 254 &ypcurlen, &data, &datalen)) { 255 free(data); 256 return NS_UNAVAIL; 257 } 258 } 259 data[datalen] = '\0'; /* clear trailing \n */ 260 sl_add(sl, data); 261 } 262 } 263 #endif /* YP */ 264 265 static const char *const * 266 initshells() 267 { 268 static const ns_dtab dtab[] = { 269 NS_FILES_CB(_local_initshells, NULL) 270 NS_DNS_CB(_dns_initshells, NULL) 271 NS_NIS_CB(_nis_initshells, NULL) 272 { 0 } 273 }; 274 if (sl) 275 sl_free(sl, 1); 276 sl = sl_init(); 277 278 if (nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc) 279 != NS_SUCCESS) { 280 if (sl) 281 sl_free(sl, 1); 282 sl = NULL; 283 return (okshells); 284 } 285 sl_add(sl, NULL); 286 287 return (const char *const *)(sl->sl_str); 288 } 289