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