1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2003 Networks Associates Technology, Inc. 5 * All rights reserved. 6 * 7 * This software was developed for the FreeBSD Project by 8 * Jacques A. Vidrine, Safeport Network Services, and Network 9 * Associates Laboratories, the Security Research Division of Network 10 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 11 * ("CBOSS"), as part of the DARPA CHATS research program. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * Compatibility shims for the GNU C Library-style nsswitch interface. 35 */ 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD$"); 38 39#include "namespace.h" 40#include <sys/param.h> 41#include <errno.h> 42#include <nss.h> 43#include <pthread.h> 44#include <pthread_np.h> 45#include "un-namespace.h" 46#include "libc_private.h" 47 48 49struct group; 50struct passwd; 51 52static int terminator; 53 54#define DECLARE_TERMINATOR(x) \ 55static pthread_key_t _term_key_##x; \ 56static void \ 57_term_create_##x(void) \ 58{ \ 59 (void)_pthread_key_create(&_term_key_##x, NULL); \ 60} \ 61static void *_term_main_##x; \ 62static pthread_once_t _term_once_##x = PTHREAD_ONCE_INIT 63 64#define SET_TERMINATOR(x, y) \ 65do { \ 66 if (!__isthreaded || _pthread_main_np()) \ 67 _term_main_##x = (y); \ 68 else { \ 69 (void)_pthread_once(&_term_once_##x, _term_create_##x); \ 70 (void)_pthread_setspecific(_term_key_##x, y); \ 71 } \ 72} while (0) 73 74#define CHECK_TERMINATOR(x) \ 75(!__isthreaded || _pthread_main_np() ? \ 76 (_term_main_##x) : \ 77 ((void)_pthread_once(&_term_once_##x, _term_create_##x), \ 78 _pthread_getspecific(_term_key_##x))) 79 80 81 82DECLARE_TERMINATOR(group); 83 84int __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap); 85int __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap); 86int __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap); 87int __nss_compat_setgrent(void *retval, void *mdata, va_list ap); 88int __nss_compat_endgrent(void *retval, void *mdata, va_list ap); 89int __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap); 90int __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap); 91int __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap); 92int __nss_compat_setpwent(void *retval, void *mdata, va_list ap); 93int __nss_compat_endpwent(void *retval, void *mdata, va_list ap); 94 95int 96__nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap) 97{ 98 int (*fn)(const char *, struct group *, char *, size_t, int *); 99 const char *name; 100 struct group *grp; 101 char *buffer; 102 int *errnop, ns_status; 103 size_t bufsize; 104 enum nss_status nss_status; 105 106 fn = mdata; 107 name = va_arg(ap, const char *); 108 grp = va_arg(ap, struct group *); 109 buffer = va_arg(ap, char *); 110 bufsize = va_arg(ap, size_t); 111 errnop = va_arg(ap, int *); 112 nss_status = fn(name, grp, buffer, bufsize, errnop); 113 ns_status = __nss_compat_result(nss_status, *errnop); 114 if (ns_status == NS_SUCCESS) 115 *(struct group **)retval = grp; 116 return (ns_status); 117} 118 119 120int 121__nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap) 122{ 123 int (*fn)(gid_t, struct group *, char *, size_t, int *); 124 gid_t gid; 125 struct group *grp; 126 char *buffer; 127 int *errnop, ns_status; 128 size_t bufsize; 129 enum nss_status nss_status; 130 131 fn = mdata; 132 gid = va_arg(ap, gid_t); 133 grp = va_arg(ap, struct group *); 134 buffer = va_arg(ap, char *); 135 bufsize = va_arg(ap, size_t); 136 errnop = va_arg(ap, int *); 137 nss_status = fn(gid, grp, buffer, bufsize, errnop); 138 ns_status = __nss_compat_result(nss_status, *errnop); 139 if (ns_status == NS_SUCCESS) 140 *(struct group **)retval = grp; 141 return (ns_status); 142} 143 144 145int 146__nss_compat_getgrent_r(void *retval, void *mdata, va_list ap) 147{ 148 int (*fn)(struct group *, char *, size_t, int *); 149 struct group *grp; 150 char *buffer; 151 int *errnop, ns_status; 152 size_t bufsize; 153 enum nss_status nss_status; 154 155 if (CHECK_TERMINATOR(group)) 156 return (NS_NOTFOUND); 157 fn = mdata; 158 grp = va_arg(ap, struct group *); 159 buffer = va_arg(ap, char *); 160 bufsize = va_arg(ap, size_t); 161 errnop = va_arg(ap, int *); 162 nss_status = fn(grp, buffer, bufsize, errnop); 163 ns_status = __nss_compat_result(nss_status, *errnop); 164 if (ns_status == NS_SUCCESS) 165 *(struct group **)retval = grp; 166 else if (ns_status != NS_RETURN) 167 SET_TERMINATOR(group, &terminator); 168 return (ns_status); 169} 170 171 172int 173__nss_compat_setgrent(void *retval, void *mdata, va_list ap) 174{ 175 176 SET_TERMINATOR(group, NULL); 177 ((int (*)(void))mdata)(); 178 return (NS_UNAVAIL); 179} 180 181 182int 183__nss_compat_endgrent(void *retval, void *mdata, va_list ap) 184{ 185 186 SET_TERMINATOR(group, NULL); 187 ((int (*)(void))mdata)(); 188 return (NS_UNAVAIL); 189} 190 191 192 193DECLARE_TERMINATOR(passwd); 194 195 196int 197__nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap) 198{ 199 int (*fn)(const char *, struct passwd *, char *, size_t, int *); 200 const char *name; 201 struct passwd *pwd; 202 char *buffer; 203 int *errnop, ns_status; 204 size_t bufsize; 205 enum nss_status nss_status; 206 207 fn = mdata; 208 name = va_arg(ap, const char *); 209 pwd = va_arg(ap, struct passwd *); 210 buffer = va_arg(ap, char *); 211 bufsize = va_arg(ap, size_t); 212 errnop = va_arg(ap, int *); 213 nss_status = fn(name, pwd, buffer, bufsize, errnop); 214 ns_status = __nss_compat_result(nss_status, *errnop); 215 if (ns_status == NS_SUCCESS) 216 *(struct passwd **)retval = pwd; 217 return (ns_status); 218} 219 220 221int 222__nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap) 223{ 224 int (*fn)(uid_t, struct passwd *, char *, size_t, int *); 225 uid_t uid; 226 struct passwd *pwd; 227 char *buffer; 228 int *errnop, ns_status; 229 size_t bufsize; 230 enum nss_status nss_status; 231 232 fn = mdata; 233 uid = va_arg(ap, uid_t); 234 pwd = va_arg(ap, struct passwd *); 235 buffer = va_arg(ap, char *); 236 bufsize = va_arg(ap, size_t); 237 errnop = va_arg(ap, int *); 238 nss_status = fn(uid, pwd, buffer, bufsize, errnop); 239 ns_status = __nss_compat_result(nss_status, *errnop); 240 if (ns_status == NS_SUCCESS) 241 *(struct passwd **)retval = pwd; 242 return (ns_status); 243} 244 245 246int 247__nss_compat_getpwent_r(void *retval, void *mdata, va_list ap) 248{ 249 int (*fn)(struct passwd *, char *, size_t, int *); 250 struct passwd *pwd; 251 char *buffer; 252 int *errnop, ns_status; 253 size_t bufsize; 254 enum nss_status nss_status; 255 256 if (CHECK_TERMINATOR(passwd)) 257 return (NS_NOTFOUND); 258 fn = mdata; 259 pwd = va_arg(ap, struct passwd *); 260 buffer = va_arg(ap, char *); 261 bufsize = va_arg(ap, size_t); 262 errnop = va_arg(ap, int *); 263 nss_status = fn(pwd, buffer, bufsize, errnop); 264 ns_status = __nss_compat_result(nss_status, *errnop); 265 if (ns_status == NS_SUCCESS) 266 *(struct passwd **)retval = pwd; 267 else if (ns_status != NS_RETURN) 268 SET_TERMINATOR(passwd, &terminator); 269 return (ns_status); 270} 271 272 273int 274__nss_compat_setpwent(void *retval, void *mdata, va_list ap) 275{ 276 277 SET_TERMINATOR(passwd, NULL); 278 ((int (*)(void))mdata)(); 279 return (NS_UNAVAIL); 280} 281 282 283int 284__nss_compat_endpwent(void *retval, void *mdata, va_list ap) 285{ 286 287 SET_TERMINATOR(passwd, NULL); 288 ((int (*)(void))mdata)(); 289 return (NS_UNAVAIL); 290} 291