1 1.29 christos /* $NetBSD: getusershell.c,v 1.29 2012/03/13 21:13:36 christos Exp $ */ 2 1.24 lukem 3 1.24 lukem /*- 4 1.24 lukem * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc. 5 1.24 lukem * All rights reserved. 6 1.24 lukem * 7 1.24 lukem * This code is derived from software contributed to The NetBSD Foundation 8 1.24 lukem * by Luke Mewburn. 9 1.24 lukem * 10 1.24 lukem * Redistribution and use in source and binary forms, with or without 11 1.24 lukem * modification, are permitted provided that the following conditions 12 1.24 lukem * are met: 13 1.24 lukem * 1. Redistributions of source code must retain the above copyright 14 1.24 lukem * notice, this list of conditions and the following disclaimer. 15 1.24 lukem * 2. Redistributions in binary form must reproduce the above copyright 16 1.24 lukem * notice, this list of conditions and the following disclaimer in the 17 1.24 lukem * documentation and/or other materials provided with the distribution. 18 1.24 lukem * 19 1.24 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.24 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.24 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.24 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.24 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.24 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.24 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.24 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.24 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.24 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.24 lukem * POSSIBILITY OF SUCH DAMAGE. 30 1.24 lukem */ 31 1.5 cgd 32 1.1 cgd /* 33 1.5 cgd * Copyright (c) 1985, 1993 34 1.5 cgd * The Regents of the University of California. All rights reserved. 35 1.1 cgd * 36 1.1 cgd * Redistribution and use in source and binary forms, with or without 37 1.1 cgd * modification, are permitted provided that the following conditions 38 1.1 cgd * are met: 39 1.1 cgd * 1. Redistributions of source code must retain the above copyright 40 1.1 cgd * notice, this list of conditions and the following disclaimer. 41 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 cgd * notice, this list of conditions and the following disclaimer in the 43 1.1 cgd * documentation and/or other materials provided with the distribution. 44 1.23 agc * 3. Neither the name of the University nor the names of its contributors 45 1.1 cgd * may be used to endorse or promote products derived from this software 46 1.1 cgd * without specific prior written permission. 47 1.1 cgd * 48 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 1.1 cgd * SUCH DAMAGE. 59 1.1 cgd */ 60 1.1 cgd 61 1.6 christos #include <sys/cdefs.h> 62 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint) 63 1.5 cgd #if 0 64 1.5 cgd static char sccsid[] = "@(#)getusershell.c 8.1 (Berkeley) 6/4/93"; 65 1.5 cgd #else 66 1.29 christos __RCSID("$NetBSD: getusershell.c,v 1.29 2012/03/13 21:13:36 christos Exp $"); 67 1.5 cgd #endif 68 1.1 cgd #endif /* LIBC_SCCS and not lint */ 69 1.1 cgd 70 1.7 jtc #include "namespace.h" 71 1.24 lukem #include "reentrant.h" 72 1.24 lukem 73 1.1 cgd #include <sys/param.h> 74 1.1 cgd #include <sys/file.h> 75 1.17 lukem 76 1.24 lukem #include <assert.h> 77 1.1 cgd #include <ctype.h> 78 1.17 lukem #include <errno.h> 79 1.13 lukem #include <nsswitch.h> 80 1.17 lukem #include <paths.h> 81 1.22 wiz #include <stdarg.h> 82 1.17 lukem #include <stdio.h> 83 1.1 cgd #include <stdlib.h> 84 1.13 lukem #include <string.h> 85 1.17 lukem #include <unistd.h> 86 1.17 lukem 87 1.13 lukem #ifdef HESIOD 88 1.13 lukem #include <hesiod.h> 89 1.13 lukem #endif 90 1.13 lukem #ifdef YP 91 1.13 lukem #include <rpc/rpc.h> 92 1.13 lukem #include <rpcsvc/ypclnt.h> 93 1.13 lukem #include <rpcsvc/yp_prot.h> 94 1.13 lukem #endif 95 1.7 jtc 96 1.7 jtc #ifdef __weak_alias 97 1.20 mycroft __weak_alias(endusershell,_endusershell) 98 1.20 mycroft __weak_alias(getusershell,_getusershell) 99 1.20 mycroft __weak_alias(setusershell,_setusershell) 100 1.7 jtc #endif 101 1.1 cgd 102 1.1 cgd /* 103 1.24 lukem * Local shells should NOT be added here. 104 1.24 lukem * They should be added in /etc/shells. 105 1.1 cgd */ 106 1.24 lukem static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL }; 107 1.24 lukem 108 1.24 lukem #ifdef _REENTRANT 109 1.24 lukem static mutex_t __shellmutex = MUTEX_INITIALIZER; 110 1.24 lukem #endif 111 1.24 lukem 112 1.24 lukem static char curshell[MAXPATHLEN + 2]; 113 1.24 lukem 114 1.24 lukem static const char *const *curokshell = okshells; 115 1.24 lukem static int shellsfound = 0; 116 1.24 lukem 117 1.24 lukem /* 118 1.24 lukem * files methods 119 1.24 lukem */ 120 1.1 cgd 121 1.24 lukem /* state shared between files methods */ 122 1.24 lukem struct files_state { 123 1.24 lukem FILE *fp; 124 1.24 lukem }; 125 1.24 lukem 126 1.24 lukem static struct files_state _files_state; 127 1.13 lukem 128 1.1 cgd 129 1.24 lukem static int 130 1.24 lukem _files_start(struct files_state *state) 131 1.1 cgd { 132 1.1 cgd 133 1.24 lukem _DIAGASSERT(state != NULL); 134 1.24 lukem 135 1.24 lukem if (state->fp == NULL) { 136 1.28 christos state->fp = fopen(_PATH_SHELLS, "re"); 137 1.24 lukem if (state->fp == NULL) 138 1.24 lukem return NS_UNAVAIL; 139 1.24 lukem } else { 140 1.24 lukem rewind(state->fp); 141 1.24 lukem } 142 1.24 lukem return NS_SUCCESS; 143 1.1 cgd } 144 1.1 cgd 145 1.24 lukem static int 146 1.24 lukem _files_end(struct files_state *state) 147 1.1 cgd { 148 1.24 lukem 149 1.24 lukem _DIAGASSERT(state != NULL); 150 1.24 lukem 151 1.24 lukem if (state->fp) { 152 1.24 lukem (void) fclose(state->fp); 153 1.24 lukem state->fp = NULL; 154 1.24 lukem } 155 1.24 lukem return NS_SUCCESS; 156 1.1 cgd } 157 1.1 cgd 158 1.24 lukem /*ARGSUSED*/ 159 1.24 lukem static int 160 1.24 lukem _files_setusershell(void *nsrv, void *nscb, va_list ap) 161 1.1 cgd { 162 1.1 cgd 163 1.24 lukem return _files_start(&_files_state); 164 1.1 cgd } 165 1.1 cgd 166 1.24 lukem /*ARGSUSED*/ 167 1.24 lukem static int 168 1.24 lukem _files_endusershell(void *nsrv, void *nscb, va_list ap) 169 1.24 lukem { 170 1.13 lukem 171 1.24 lukem return _files_end(&_files_state); 172 1.24 lukem } 173 1.13 lukem 174 1.16 christos /*ARGSUSED*/ 175 1.13 lukem static int 176 1.24 lukem _files_getusershell(void *nsrv, void *nscb, va_list ap) 177 1.1 cgd { 178 1.24 lukem char **retval = va_arg(ap, char **); 179 1.24 lukem 180 1.13 lukem char *sp, *cp; 181 1.24 lukem int rv; 182 1.13 lukem 183 1.24 lukem _DIAGASSERT(retval != NULL); 184 1.13 lukem 185 1.24 lukem *retval = NULL; 186 1.24 lukem if (_files_state.fp == NULL) { /* only start if file not open yet */ 187 1.24 lukem rv = _files_start(&_files_state); 188 1.24 lukem if (rv != NS_SUCCESS) 189 1.24 lukem return rv; 190 1.24 lukem } 191 1.13 lukem 192 1.29 christos while (fgets(curshell, (int)sizeof(curshell) - 1, _files_state.fp) 193 1.29 christos != NULL) { 194 1.24 lukem sp = cp = curshell; 195 1.1 cgd while (*cp != '#' && *cp != '/' && *cp != '\0') 196 1.1 cgd cp++; 197 1.1 cgd if (*cp == '#' || *cp == '\0') 198 1.1 cgd continue; 199 1.13 lukem sp = cp; 200 1.21 itohy while (!isspace((unsigned char) *cp) && *cp != '#' 201 1.21 itohy && *cp != '\0') 202 1.1 cgd cp++; 203 1.1 cgd *cp++ = '\0'; 204 1.24 lukem *retval = sp; 205 1.24 lukem return NS_SUCCESS; 206 1.1 cgd } 207 1.24 lukem 208 1.24 lukem return NS_NOTFOUND; 209 1.13 lukem } 210 1.13 lukem 211 1.24 lukem 212 1.13 lukem #ifdef HESIOD 213 1.24 lukem /* 214 1.24 lukem * dns methods 215 1.24 lukem */ 216 1.24 lukem 217 1.24 lukem /* state shared between dns methods */ 218 1.24 lukem struct dns_state { 219 1.24 lukem void *context; /* Hesiod context */ 220 1.24 lukem int num; /* shell index, -1 if no more */ 221 1.24 lukem }; 222 1.24 lukem 223 1.24 lukem static struct dns_state _dns_state; 224 1.24 lukem 225 1.24 lukem static int 226 1.24 lukem _dns_start(struct dns_state *state) 227 1.24 lukem { 228 1.24 lukem 229 1.24 lukem _DIAGASSERT(state != NULL); 230 1.24 lukem 231 1.24 lukem state->num = 0; 232 1.24 lukem if (state->context == NULL) { /* setup Hesiod */ 233 1.24 lukem if (hesiod_init(&state->context) == -1) 234 1.24 lukem return NS_UNAVAIL; 235 1.24 lukem } 236 1.24 lukem 237 1.24 lukem return NS_SUCCESS; 238 1.24 lukem } 239 1.24 lukem 240 1.24 lukem static int 241 1.24 lukem _dns_end(struct dns_state *state) 242 1.24 lukem { 243 1.24 lukem 244 1.24 lukem _DIAGASSERT(state != NULL); 245 1.24 lukem 246 1.24 lukem state->num = 0; 247 1.24 lukem if (state->context) { 248 1.24 lukem hesiod_end(state->context); 249 1.24 lukem state->context = NULL; 250 1.24 lukem } 251 1.24 lukem return NS_SUCCESS; 252 1.24 lukem } 253 1.24 lukem 254 1.24 lukem /*ARGSUSED*/ 255 1.24 lukem static int 256 1.24 lukem _dns_setusershell(void *nsrv, void *nscb, va_list ap) 257 1.24 lukem { 258 1.24 lukem 259 1.24 lukem return _dns_start(&_dns_state); 260 1.24 lukem } 261 1.13 lukem 262 1.16 christos /*ARGSUSED*/ 263 1.13 lukem static int 264 1.24 lukem _dns_endusershell(void *nsrv, void *nscb, va_list ap) 265 1.24 lukem { 266 1.24 lukem 267 1.24 lukem return _dns_end(&_dns_state); 268 1.24 lukem } 269 1.24 lukem 270 1.24 lukem /*ARGSUSED*/ 271 1.24 lukem static int 272 1.24 lukem _dns_getusershell(void *nsrv, void *nscb, va_list ap) 273 1.24 lukem { 274 1.24 lukem char **retval = va_arg(ap, char **); 275 1.24 lukem 276 1.24 lukem char shellname[] = "shells-NNNNNNNNNN"; 277 1.24 lukem char **hp, *ep; 278 1.24 lukem int rv; 279 1.24 lukem 280 1.24 lukem _DIAGASSERT(retval != NULL); 281 1.24 lukem 282 1.24 lukem *retval = NULL; 283 1.24 lukem 284 1.24 lukem if (_dns_state.num == -1) /* exhausted search */ 285 1.24 lukem return NS_NOTFOUND; 286 1.24 lukem 287 1.24 lukem if (_dns_state.context == NULL) { 288 1.24 lukem /* only start if Hesiod not setup */ 289 1.24 lukem rv = _dns_start(&_dns_state); 290 1.24 lukem if (rv != NS_SUCCESS) 291 1.24 lukem return rv; 292 1.24 lukem } 293 1.24 lukem 294 1.24 lukem hp = NULL; 295 1.24 lukem rv = NS_NOTFOUND; 296 1.19 lukem 297 1.24 lukem /* find shells-NNN */ 298 1.24 lukem snprintf(shellname, sizeof(shellname), "shells-%d", _dns_state.num); 299 1.24 lukem _dns_state.num++; 300 1.24 lukem 301 1.24 lukem hp = hesiod_resolve(_dns_state.context, shellname, "shells"); 302 1.24 lukem if (hp == NULL) { 303 1.24 lukem if (errno == ENOENT) 304 1.24 lukem rv = NS_NOTFOUND; 305 1.24 lukem else 306 1.24 lukem rv = NS_UNAVAIL; 307 1.24 lukem } else { 308 1.24 lukem if ((ep = strchr(hp[0], '\n')) != NULL) 309 1.24 lukem *ep = '\0'; /* clear trailing \n */ 310 1.24 lukem /* only use first result */ 311 1.24 lukem strlcpy(curshell, hp[0], sizeof(curshell)); 312 1.24 lukem *retval = curshell; 313 1.24 lukem rv = NS_SUCCESS; 314 1.13 lukem } 315 1.24 lukem 316 1.24 lukem if (hp) 317 1.24 lukem hesiod_free_list(_dns_state.context, hp); 318 1.24 lukem if (rv != NS_SUCCESS) 319 1.24 lukem _dns_state.num = -1; /* any failure halts search */ 320 1.24 lukem return rv; 321 1.13 lukem } 322 1.24 lukem 323 1.13 lukem #endif /* HESIOD */ 324 1.13 lukem 325 1.24 lukem 326 1.13 lukem #ifdef YP 327 1.24 lukem /* 328 1.24 lukem * nis methods 329 1.24 lukem */ 330 1.24 lukem /* state shared between nis methods */ 331 1.24 lukem struct nis_state { 332 1.24 lukem char *domain; /* NIS domain */ 333 1.24 lukem int done; /* non-zero if search exhausted */ 334 1.24 lukem char *current; /* current first/next match */ 335 1.24 lukem int currentlen; /* length of _nis_current */ 336 1.24 lukem }; 337 1.24 lukem 338 1.24 lukem static struct nis_state _nis_state; 339 1.13 lukem 340 1.13 lukem static int 341 1.24 lukem _nis_start(struct nis_state *state) 342 1.24 lukem { 343 1.13 lukem 344 1.24 lukem _DIAGASSERT(state != NULL); 345 1.24 lukem 346 1.24 lukem state->done = 0; 347 1.24 lukem if (state->current) { 348 1.24 lukem free(state->current); 349 1.24 lukem state->current = NULL; 350 1.24 lukem } 351 1.24 lukem if (state->domain == NULL) { /* setup NIS */ 352 1.24 lukem switch (yp_get_default_domain(&state->domain)) { 353 1.13 lukem case 0: 354 1.13 lukem break; 355 1.13 lukem case YPERR_RESRC: 356 1.24 lukem return NS_TRYAGAIN; 357 1.13 lukem default: 358 1.24 lukem return NS_UNAVAIL; 359 1.13 lukem } 360 1.13 lukem } 361 1.24 lukem return NS_SUCCESS; 362 1.24 lukem } 363 1.24 lukem 364 1.24 lukem static int 365 1.24 lukem _nis_end(struct nis_state *state) 366 1.24 lukem { 367 1.24 lukem 368 1.24 lukem _DIAGASSERT(state != NULL); 369 1.24 lukem 370 1.24 lukem if (state->domain) 371 1.24 lukem state->domain = NULL; 372 1.24 lukem state->done = 0; 373 1.24 lukem if (state->current) 374 1.24 lukem free(state->current); 375 1.24 lukem state->current = NULL; 376 1.24 lukem return NS_SUCCESS; 377 1.24 lukem } 378 1.24 lukem 379 1.24 lukem /*ARGSUSED*/ 380 1.24 lukem static int 381 1.24 lukem _nis_setusershell(void *nsrv, void *nscb, va_list ap) 382 1.24 lukem { 383 1.24 lukem 384 1.24 lukem return _nis_start(&_nis_state); 385 1.24 lukem } 386 1.24 lukem 387 1.24 lukem /*ARGSUSED*/ 388 1.24 lukem static int 389 1.24 lukem _nis_endusershell(void *nsrv, void *nscb, va_list ap) 390 1.24 lukem { 391 1.24 lukem 392 1.24 lukem return _nis_end(&_nis_state); 393 1.24 lukem } 394 1.24 lukem 395 1.24 lukem /*ARGSUSED*/ 396 1.24 lukem static int 397 1.24 lukem _nis_getusershell(void *nsrv, void *nscb, va_list ap) 398 1.24 lukem { 399 1.24 lukem char **retval = va_arg(ap, char **); 400 1.24 lukem 401 1.24 lukem char *key, *data; 402 1.24 lukem int keylen, datalen, rv, nisr; 403 1.24 lukem 404 1.24 lukem _DIAGASSERT(retval != NULL); 405 1.24 lukem 406 1.24 lukem *retval = NULL; 407 1.24 lukem 408 1.24 lukem if (_nis_state.done) /* exhausted search */ 409 1.24 lukem return NS_NOTFOUND; 410 1.24 lukem if (_nis_state.domain == NULL) { 411 1.24 lukem /* only start if NIS not setup */ 412 1.24 lukem rv = _nis_start(&_nis_state); 413 1.24 lukem if (rv != NS_SUCCESS) 414 1.24 lukem return rv; 415 1.24 lukem } 416 1.13 lukem 417 1.24 lukem key = NULL; 418 1.24 lukem data = NULL; 419 1.24 lukem rv = NS_NOTFOUND; 420 1.24 lukem 421 1.24 lukem if (_nis_state.current) { /* already searching */ 422 1.24 lukem nisr = yp_next(_nis_state.domain, "shells", 423 1.24 lukem _nis_state.current, _nis_state.currentlen, 424 1.24 lukem &key, &keylen, &data, &datalen); 425 1.24 lukem free(_nis_state.current); 426 1.24 lukem _nis_state.current = NULL; 427 1.24 lukem switch (nisr) { 428 1.24 lukem case 0: 429 1.24 lukem _nis_state.current = key; 430 1.24 lukem _nis_state.currentlen = keylen; 431 1.24 lukem key = NULL; 432 1.24 lukem break; 433 1.24 lukem case YPERR_NOMORE: 434 1.24 lukem rv = NS_NOTFOUND; 435 1.24 lukem goto nisent_out; 436 1.24 lukem default: 437 1.24 lukem rv = NS_UNAVAIL; 438 1.24 lukem goto nisent_out; 439 1.24 lukem } 440 1.24 lukem } else { /* new search */ 441 1.24 lukem if (yp_first(_nis_state.domain, "shells", 442 1.24 lukem &_nis_state.current, &_nis_state.currentlen, 443 1.24 lukem &data, &datalen)) { 444 1.24 lukem rv = NS_UNAVAIL; 445 1.24 lukem goto nisent_out; 446 1.13 lukem } 447 1.13 lukem } 448 1.24 lukem 449 1.24 lukem data[datalen] = '\0'; /* clear trailing \n */ 450 1.24 lukem strlcpy(curshell, data, sizeof(curshell)); 451 1.24 lukem *retval = curshell; 452 1.24 lukem rv = NS_SUCCESS; 453 1.24 lukem 454 1.24 lukem nisent_out: 455 1.24 lukem if (key) 456 1.24 lukem free(key); 457 1.24 lukem if (data) 458 1.24 lukem free(data); 459 1.24 lukem if (rv != NS_SUCCESS) /* any failure halts search */ 460 1.24 lukem _nis_state.done = 1; 461 1.24 lukem return rv; 462 1.13 lukem } 463 1.24 lukem 464 1.13 lukem #endif /* YP */ 465 1.13 lukem 466 1.24 lukem 467 1.24 lukem /* 468 1.24 lukem * public functions 469 1.24 lukem */ 470 1.24 lukem 471 1.24 lukem void 472 1.24 lukem endusershell(void) 473 1.24 lukem { 474 1.24 lukem static const ns_dtab dtab[] = { 475 1.24 lukem NS_FILES_CB(_files_endusershell, NULL) 476 1.24 lukem NS_DNS_CB(_dns_endusershell, NULL) 477 1.24 lukem NS_NIS_CB(_nis_endusershell, NULL) 478 1.26 christos NS_NULL_CB 479 1.24 lukem }; 480 1.24 lukem 481 1.24 lukem mutex_lock(&__shellmutex); 482 1.24 lukem 483 1.24 lukem curokshell = okshells; /* reset okshells fallback state */ 484 1.24 lukem shellsfound = 0; 485 1.24 lukem 486 1.24 lukem /* force all endusershell() methods */ 487 1.24 lukem (void) nsdispatch(NULL, dtab, NSDB_SHELLS, "endusershell", 488 1.24 lukem __nsdefaultfiles_forceall); 489 1.24 lukem mutex_unlock(&__shellmutex); 490 1.24 lukem } 491 1.24 lukem 492 1.24 lukem __aconst char * 493 1.24 lukem getusershell(void) 494 1.13 lukem { 495 1.24 lukem int rv; 496 1.24 lukem __aconst char *retval; 497 1.24 lukem 498 1.15 lukem static const ns_dtab dtab[] = { 499 1.24 lukem NS_FILES_CB(_files_getusershell, NULL) 500 1.24 lukem NS_DNS_CB(_dns_getusershell, NULL) 501 1.24 lukem NS_NIS_CB(_nis_getusershell, NULL) 502 1.26 christos NS_NULL_CB 503 1.13 lukem }; 504 1.24 lukem 505 1.24 lukem mutex_lock(&__shellmutex); 506 1.24 lukem 507 1.24 lukem retval = NULL; 508 1.24 lukem do { 509 1.24 lukem rv = nsdispatch(NULL, dtab, NSDB_SHELLS, "getusershell", 510 1.24 lukem __nsdefaultsrc, &retval); 511 1.24 lukem /* loop until failure or non-blank result */ 512 1.24 lukem } while (rv == NS_SUCCESS && retval[0] == '\0'); 513 1.24 lukem 514 1.24 lukem if (rv == NS_SUCCESS) { 515 1.24 lukem shellsfound++; 516 1.24 lukem } else if (shellsfound == 0) { /* no shells; fall back to okshells */ 517 1.24 lukem if (curokshell != NULL) { 518 1.25 christos retval = __UNCONST(*curokshell); 519 1.24 lukem curokshell++; 520 1.24 lukem rv = NS_SUCCESS; 521 1.24 lukem } 522 1.13 lukem } 523 1.13 lukem 524 1.24 lukem mutex_unlock(&__shellmutex); 525 1.24 lukem return (rv == NS_SUCCESS) ? retval : NULL; 526 1.24 lukem } 527 1.24 lukem 528 1.24 lukem void 529 1.24 lukem setusershell(void) 530 1.24 lukem { 531 1.24 lukem static const ns_dtab dtab[] = { 532 1.24 lukem NS_FILES_CB(_files_setusershell, NULL) 533 1.24 lukem NS_DNS_CB(_dns_setusershell, NULL) 534 1.24 lukem NS_NIS_CB(_nis_setusershell, NULL) 535 1.26 christos NS_NULL_CB 536 1.24 lukem }; 537 1.24 lukem 538 1.24 lukem mutex_lock(&__shellmutex); 539 1.24 lukem 540 1.24 lukem curokshell = okshells; /* reset okshells fallback state */ 541 1.24 lukem shellsfound = 0; 542 1.24 lukem 543 1.24 lukem /* force all setusershell() methods */ 544 1.24 lukem (void) nsdispatch(NULL, dtab, NSDB_SHELLS, "setusershell", 545 1.24 lukem __nsdefaultfiles_forceall); 546 1.24 lukem mutex_unlock(&__shellmutex); 547 1.1 cgd } 548