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