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