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