1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 "namespace.h" 37 #include <sys/param.h> 38 #include <errno.h> 39 #include <nss.h> 40 #include <pthread.h> 41 #include <pthread_np.h> 42 #include "un-namespace.h" 43 #include "libc_private.h" 44 45 46 struct group; 47 struct passwd; 48 49 static int terminator; 50 51 #define DECLARE_TERMINATOR(x) \ 52 static pthread_key_t _term_key_##x; \ 53 static void \ 54 _term_create_##x(void) \ 55 { \ 56 (void)_pthread_key_create(&_term_key_##x, NULL); \ 57 } \ 58 static void *_term_main_##x; \ 59 static pthread_once_t _term_once_##x = PTHREAD_ONCE_INIT 60 61 #define SET_TERMINATOR(x, y) \ 62 do { \ 63 if (!__isthreaded || _pthread_main_np()) \ 64 _term_main_##x = (y); \ 65 else { \ 66 (void)_pthread_once(&_term_once_##x, _term_create_##x); \ 67 (void)_pthread_setspecific(_term_key_##x, y); \ 68 } \ 69 } while (0) 70 71 #define CHECK_TERMINATOR(x) \ 72 (!__isthreaded || _pthread_main_np() ? \ 73 (_term_main_##x) : \ 74 ((void)_pthread_once(&_term_once_##x, _term_create_##x), \ 75 _pthread_getspecific(_term_key_##x))) 76 77 78 79 DECLARE_TERMINATOR(group); 80 81 int __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap); 82 int __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap); 83 int __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap); 84 int __nss_compat_setgrent(void *retval, void *mdata, va_list ap); 85 int __nss_compat_endgrent(void *retval, void *mdata, va_list ap); 86 int __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap); 87 int __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap); 88 int __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap); 89 int __nss_compat_setpwent(void *retval, void *mdata, va_list ap); 90 int __nss_compat_endpwent(void *retval, void *mdata, va_list ap); 91 92 int 93 __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap) 94 { 95 int (*fn)(const char *, struct group *, char *, size_t, int *); 96 const char *name; 97 struct group *grp; 98 char *buffer; 99 int *errnop, ns_status; 100 size_t bufsize; 101 enum nss_status nss_status; 102 103 fn = mdata; 104 name = va_arg(ap, const char *); 105 grp = va_arg(ap, struct group *); 106 buffer = va_arg(ap, char *); 107 bufsize = va_arg(ap, size_t); 108 errnop = va_arg(ap, int *); 109 nss_status = fn(name, grp, buffer, bufsize, errnop); 110 ns_status = __nss_compat_result(nss_status, *errnop); 111 if (ns_status == NS_SUCCESS) 112 *(struct group **)retval = grp; 113 return (ns_status); 114 } 115 116 117 int 118 __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap) 119 { 120 int (*fn)(gid_t, struct group *, char *, size_t, int *); 121 gid_t gid; 122 struct group *grp; 123 char *buffer; 124 int *errnop, ns_status; 125 size_t bufsize; 126 enum nss_status nss_status; 127 128 fn = mdata; 129 gid = va_arg(ap, gid_t); 130 grp = va_arg(ap, struct group *); 131 buffer = va_arg(ap, char *); 132 bufsize = va_arg(ap, size_t); 133 errnop = va_arg(ap, int *); 134 nss_status = fn(gid, grp, buffer, bufsize, errnop); 135 ns_status = __nss_compat_result(nss_status, *errnop); 136 if (ns_status == NS_SUCCESS) 137 *(struct group **)retval = grp; 138 return (ns_status); 139 } 140 141 142 int 143 __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap) 144 { 145 int (*fn)(struct group *, char *, size_t, int *); 146 struct group *grp; 147 char *buffer; 148 int *errnop, ns_status; 149 size_t bufsize; 150 enum nss_status nss_status; 151 152 if (CHECK_TERMINATOR(group)) 153 return (NS_NOTFOUND); 154 fn = mdata; 155 grp = va_arg(ap, struct group *); 156 buffer = va_arg(ap, char *); 157 bufsize = va_arg(ap, size_t); 158 errnop = va_arg(ap, int *); 159 nss_status = fn(grp, buffer, bufsize, errnop); 160 ns_status = __nss_compat_result(nss_status, *errnop); 161 if (ns_status == NS_SUCCESS) 162 *(struct group **)retval = grp; 163 else if (ns_status != NS_RETURN) 164 SET_TERMINATOR(group, &terminator); 165 return (ns_status); 166 } 167 168 169 int 170 __nss_compat_setgrent(void *retval, void *mdata, va_list ap) 171 { 172 173 SET_TERMINATOR(group, NULL); 174 ((int (*)(void))mdata)(); 175 return (NS_UNAVAIL); 176 } 177 178 179 int 180 __nss_compat_endgrent(void *retval, void *mdata, va_list ap) 181 { 182 183 SET_TERMINATOR(group, NULL); 184 ((int (*)(void))mdata)(); 185 return (NS_UNAVAIL); 186 } 187 188 189 190 DECLARE_TERMINATOR(passwd); 191 192 193 int 194 __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap) 195 { 196 int (*fn)(const char *, struct passwd *, char *, size_t, int *); 197 const char *name; 198 struct passwd *pwd; 199 char *buffer; 200 int *errnop, ns_status; 201 size_t bufsize; 202 enum nss_status nss_status; 203 204 fn = mdata; 205 name = va_arg(ap, const char *); 206 pwd = va_arg(ap, struct passwd *); 207 buffer = va_arg(ap, char *); 208 bufsize = va_arg(ap, size_t); 209 errnop = va_arg(ap, int *); 210 nss_status = fn(name, pwd, buffer, bufsize, errnop); 211 ns_status = __nss_compat_result(nss_status, *errnop); 212 if (ns_status == NS_SUCCESS) 213 *(struct passwd **)retval = pwd; 214 return (ns_status); 215 } 216 217 218 int 219 __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap) 220 { 221 int (*fn)(uid_t, struct passwd *, char *, size_t, int *); 222 uid_t uid; 223 struct passwd *pwd; 224 char *buffer; 225 int *errnop, ns_status; 226 size_t bufsize; 227 enum nss_status nss_status; 228 229 fn = mdata; 230 uid = va_arg(ap, uid_t); 231 pwd = va_arg(ap, struct passwd *); 232 buffer = va_arg(ap, char *); 233 bufsize = va_arg(ap, size_t); 234 errnop = va_arg(ap, int *); 235 nss_status = fn(uid, pwd, buffer, bufsize, errnop); 236 ns_status = __nss_compat_result(nss_status, *errnop); 237 if (ns_status == NS_SUCCESS) 238 *(struct passwd **)retval = pwd; 239 return (ns_status); 240 } 241 242 243 int 244 __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap) 245 { 246 int (*fn)(struct passwd *, char *, size_t, int *); 247 struct passwd *pwd; 248 char *buffer; 249 int *errnop, ns_status; 250 size_t bufsize; 251 enum nss_status nss_status; 252 253 if (CHECK_TERMINATOR(passwd)) 254 return (NS_NOTFOUND); 255 fn = mdata; 256 pwd = va_arg(ap, struct passwd *); 257 buffer = va_arg(ap, char *); 258 bufsize = va_arg(ap, size_t); 259 errnop = va_arg(ap, int *); 260 nss_status = fn(pwd, buffer, bufsize, errnop); 261 ns_status = __nss_compat_result(nss_status, *errnop); 262 if (ns_status == NS_SUCCESS) 263 *(struct passwd **)retval = pwd; 264 else if (ns_status != NS_RETURN) 265 SET_TERMINATOR(passwd, &terminator); 266 return (ns_status); 267 } 268 269 270 int 271 __nss_compat_setpwent(void *retval, void *mdata, va_list ap) 272 { 273 274 SET_TERMINATOR(passwd, NULL); 275 ((int (*)(void))mdata)(); 276 return (NS_UNAVAIL); 277 } 278 279 280 int 281 __nss_compat_endpwent(void *retval, void *mdata, va_list ap) 282 { 283 284 SET_TERMINATOR(passwd, NULL); 285 ((int (*)(void))mdata)(); 286 return (NS_UNAVAIL); 287 } 288