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