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 49 struct group; 50 struct passwd; 51 52 static int terminator; 53 54 #define DECLARE_TERMINATOR(x) \ 55 static pthread_key_t _term_key_##x; \ 56 static void \ 57 _term_create_##x(void) \ 58 { \ 59 (void)_pthread_key_create(&_term_key_##x, NULL); \ 60 } \ 61 static void *_term_main_##x; \ 62 static pthread_once_t _term_once_##x = PTHREAD_ONCE_INIT 63 64 #define SET_TERMINATOR(x, y) \ 65 do { \ 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 82 DECLARE_TERMINATOR(group); 83 84 int __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap); 85 int __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap); 86 int __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap); 87 int __nss_compat_setgrent(void *retval, void *mdata, va_list ap); 88 int __nss_compat_endgrent(void *retval, void *mdata, va_list ap); 89 int __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap); 90 int __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap); 91 int __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap); 92 int __nss_compat_setpwent(void *retval, void *mdata, va_list ap); 93 int __nss_compat_endpwent(void *retval, void *mdata, va_list ap); 94 95 int 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 120 int 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 145 int 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 172 int 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 182 int 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 193 DECLARE_TERMINATOR(passwd); 194 195 196 int 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 221 int 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 246 int 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 273 int 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 283 int 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