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