1 /* 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if defined(LIBC_SCCS) && !defined(lint) 31 static char sccsid[] = "@(#)getusershell.c 8.1 (Berkeley) 6/4/93"; 32 #endif /* LIBC_SCCS and not lint */ 33 /* $NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $ */ 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include "namespace.h" 38 #include <sys/param.h> 39 #include <sys/file.h> 40 41 #include <ctype.h> 42 #include <errno.h> 43 #include <nsswitch.h> 44 #include <paths.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <stringlist.h> 49 #include <unistd.h> 50 51 #ifdef HESIOD 52 #include <hesiod.h> 53 #endif 54 #ifdef YP 55 #include <rpc/rpc.h> 56 #include <rpcsvc/ypclnt.h> 57 #include <rpcsvc/yp_prot.h> 58 #endif 59 #include "un-namespace.h" 60 61 /* 62 * Local shells should NOT be added here. They should be added in 63 * /etc/shells. 64 */ 65 66 static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL }; 67 static const char *const *curshell; 68 static StringList *sl; 69 70 static const char *const *initshells(void); 71 72 /* 73 * Get a list of shells from "shells" nsswitch database 74 */ 75 char * 76 getusershell(void) 77 { 78 char *ret; 79 80 if (curshell == NULL) 81 curshell = initshells(); 82 /*LINTED*/ 83 ret = (char *)*curshell; 84 if (ret != NULL) 85 curshell++; 86 return (ret); 87 } 88 89 void 90 endusershell(void) 91 { 92 if (sl) { 93 sl_free(sl, 1); 94 sl = NULL; 95 } 96 curshell = NULL; 97 } 98 99 void 100 setusershell(void) 101 { 102 103 curshell = initshells(); 104 } 105 106 107 static int _local_initshells(void *, void *, va_list); 108 109 /*ARGSUSED*/ 110 static int 111 _local_initshells(rv, cb_data, ap) 112 void *rv; 113 void *cb_data; 114 va_list ap; 115 { 116 char *sp, *cp; 117 FILE *fp; 118 char line[MAXPATHLEN + 2]; 119 120 if (sl) 121 sl_free(sl, 1); 122 sl = sl_init(); 123 124 if ((fp = fopen(_PATH_SHELLS, "r")) == NULL) 125 return NS_UNAVAIL; 126 127 sp = cp = line; 128 while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) { 129 while (*cp != '#' && *cp != '/' && *cp != '\0') 130 cp++; 131 if (*cp == '#' || *cp == '\0') 132 continue; 133 sp = cp; 134 while (!isspace(*cp) && *cp != '#' && *cp != '\0') 135 cp++; 136 *cp++ = '\0'; 137 sl_add(sl, strdup(sp)); 138 } 139 (void)fclose(fp); 140 return NS_SUCCESS; 141 } 142 143 #ifdef HESIOD 144 static int _dns_initshells(void *, void *, va_list); 145 146 /*ARGSUSED*/ 147 static int 148 _dns_initshells(rv, cb_data, ap) 149 void *rv; 150 void *cb_data; 151 va_list ap; 152 { 153 char shellname[] = "shells-XXXXX"; 154 int hsindex, hpi, r; 155 char **hp; 156 void *context; 157 158 if (sl) 159 sl_free(sl, 1); 160 sl = sl_init(); 161 r = NS_UNAVAIL; 162 if (hesiod_init(&context) == -1) 163 return (r); 164 165 for (hsindex = 0; ; hsindex++) { 166 snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex); 167 hp = hesiod_resolve(context, shellname, "shells"); 168 if (hp == NULL) { 169 if (errno == ENOENT) { 170 if (hsindex == 0) 171 r = NS_NOTFOUND; 172 else 173 r = NS_SUCCESS; 174 } 175 break; 176 } else { 177 for (hpi = 0; hp[hpi]; hpi++) 178 sl_add(sl, hp[hpi]); 179 free(hp); 180 } 181 } 182 hesiod_end(context); 183 return (r); 184 } 185 #endif /* HESIOD */ 186 187 #ifdef YP 188 static int _nis_initshells(void *, void *, va_list); 189 190 /*ARGSUSED*/ 191 static int 192 _nis_initshells(rv, cb_data, ap) 193 void *rv; 194 void *cb_data; 195 va_list ap; 196 { 197 static char *ypdomain; 198 char *key, *data; 199 char *lastkey; 200 int keylen, datalen; 201 int r; 202 203 if (sl) 204 sl_free(sl, 1); 205 sl = sl_init(); 206 207 if (ypdomain == NULL) { 208 switch (yp_get_default_domain(&ypdomain)) { 209 case 0: 210 break; 211 case YPERR_RESRC: 212 return NS_TRYAGAIN; 213 default: 214 return NS_UNAVAIL; 215 } 216 } 217 218 /* 219 * `key' and `data' point to strings dynamically allocated by 220 * the yp_... functions. 221 * `data' is directly put into the stringlist of shells. 222 */ 223 key = data = NULL; 224 if (yp_first(ypdomain, "shells", &key, &keylen, &data, &datalen)) 225 return NS_UNAVAIL; 226 do { 227 data[datalen] = '\0'; /* clear trailing \n */ 228 sl_add(sl, data); 229 230 lastkey = key; 231 r = yp_next(ypdomain, "shells", lastkey, keylen, 232 &key, &keylen, &data, &datalen); 233 free(lastkey); 234 } while (r == 0); 235 236 if (r == YPERR_NOMORE) { 237 /* 238 * `data' and `key' ought to be NULL - do not try to free them. 239 */ 240 return NS_SUCCESS; 241 } 242 243 return NS_UNAVAIL; 244 } 245 #endif /* YP */ 246 247 static const char *const * 248 initshells() 249 { 250 static const ns_dtab dtab[] = { 251 NS_FILES_CB(_local_initshells, NULL) 252 NS_DNS_CB(_dns_initshells, NULL) 253 NS_NIS_CB(_nis_initshells, NULL) 254 { 0 } 255 }; 256 if (sl) 257 sl_free(sl, 1); 258 sl = sl_init(); 259 260 if (_nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc) 261 != NS_SUCCESS) { 262 if (sl) 263 sl_free(sl, 1); 264 sl = NULL; 265 return (okshells); 266 } 267 sl_add(sl, NULL); 268 269 return (const char *const *)(sl->sl_str); 270 } 271