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