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