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 int __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap); 83 int __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap); 84 int __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap); 85 int __nss_compat_setgrent(void *retval, void *mdata, va_list ap); 86 int __nss_compat_endgrent(void *retval, void *mdata, va_list ap); 87 int __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap); 88 int __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap); 89 int __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap); 90 int __nss_compat_setpwent(void *retval, void *mdata, va_list ap); 91 int __nss_compat_endpwent(void *retval, void *mdata, va_list ap); 92 93 int 94 __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap) 95 { 96 int (*fn)(const char *, struct group *, char *, size_t, int *); 97 const char *name; 98 struct group *grp; 99 char *buffer; 100 int *errnop, ns_status; 101 size_t bufsize; 102 enum nss_status nss_status; 103 104 fn = mdata; 105 name = va_arg(ap, const char *); 106 grp = va_arg(ap, struct group *); 107 buffer = va_arg(ap, char *); 108 bufsize = va_arg(ap, size_t); 109 errnop = va_arg(ap, int *); 110 nss_status = fn(name, grp, buffer, bufsize, errnop); 111 ns_status = __nss_compat_result(nss_status, *errnop); 112 if (ns_status == NS_SUCCESS) 113 *(struct group **)retval = grp; 114 return (ns_status); 115 } 116 117 118 int 119 __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap) 120 { 121 int (*fn)(gid_t, struct group *, char *, size_t, int *); 122 gid_t gid; 123 struct group *grp; 124 char *buffer; 125 int *errnop, ns_status; 126 size_t bufsize; 127 enum nss_status nss_status; 128 129 fn = mdata; 130 gid = va_arg(ap, gid_t); 131 grp = va_arg(ap, struct group *); 132 buffer = va_arg(ap, char *); 133 bufsize = va_arg(ap, size_t); 134 errnop = va_arg(ap, int *); 135 nss_status = fn(gid, grp, buffer, bufsize, errnop); 136 ns_status = __nss_compat_result(nss_status, *errnop); 137 if (ns_status == NS_SUCCESS) 138 *(struct group **)retval = grp; 139 return (ns_status); 140 } 141 142 143 int 144 __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap) 145 { 146 int (*fn)(struct group *, char *, size_t, int *); 147 struct group *grp; 148 char *buffer; 149 int *errnop, ns_status; 150 size_t bufsize; 151 enum nss_status nss_status; 152 153 if (CHECK_TERMINATOR(group)) 154 return (NS_NOTFOUND); 155 fn = mdata; 156 grp = va_arg(ap, struct group *); 157 buffer = va_arg(ap, char *); 158 bufsize = va_arg(ap, size_t); 159 errnop = va_arg(ap, int *); 160 nss_status = fn(grp, buffer, bufsize, errnop); 161 ns_status = __nss_compat_result(nss_status, *errnop); 162 if (ns_status == NS_SUCCESS) 163 *(struct group **)retval = grp; 164 else if (ns_status != NS_RETURN) 165 SET_TERMINATOR(group, &terminator); 166 return (ns_status); 167 } 168 169 170 int 171 __nss_compat_setgrent(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 int 181 __nss_compat_endgrent(void *retval, void *mdata, va_list ap) 182 { 183 184 SET_TERMINATOR(group, NULL); 185 ((int (*)(void))mdata)(); 186 return (NS_UNAVAIL); 187 } 188 189 190 191 DECLARE_TERMINATOR(passwd); 192 193 194 int 195 __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap) 196 { 197 int (*fn)(const char *, struct passwd *, char *, size_t, int *); 198 const char *name; 199 struct passwd *pwd; 200 char *buffer; 201 int *errnop, ns_status; 202 size_t bufsize; 203 enum nss_status nss_status; 204 205 fn = mdata; 206 name = va_arg(ap, const char *); 207 pwd = va_arg(ap, struct passwd *); 208 buffer = va_arg(ap, char *); 209 bufsize = va_arg(ap, size_t); 210 errnop = va_arg(ap, int *); 211 nss_status = fn(name, pwd, buffer, bufsize, errnop); 212 ns_status = __nss_compat_result(nss_status, *errnop); 213 if (ns_status == NS_SUCCESS) 214 *(struct passwd **)retval = pwd; 215 return (ns_status); 216 } 217 218 219 int 220 __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap) 221 { 222 int (*fn)(uid_t, struct passwd *, char *, size_t, int *); 223 uid_t uid; 224 struct passwd *pwd; 225 char *buffer; 226 int *errnop, ns_status; 227 size_t bufsize; 228 enum nss_status nss_status; 229 230 fn = mdata; 231 uid = va_arg(ap, uid_t); 232 pwd = va_arg(ap, struct passwd *); 233 buffer = va_arg(ap, char *); 234 bufsize = va_arg(ap, size_t); 235 errnop = va_arg(ap, int *); 236 nss_status = fn(uid, pwd, buffer, bufsize, errnop); 237 ns_status = __nss_compat_result(nss_status, *errnop); 238 if (ns_status == NS_SUCCESS) 239 *(struct passwd **)retval = pwd; 240 return (ns_status); 241 } 242 243 244 int 245 __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap) 246 { 247 int (*fn)(struct passwd *, char *, size_t, int *); 248 struct passwd *pwd; 249 char *buffer; 250 int *errnop, ns_status; 251 size_t bufsize; 252 enum nss_status nss_status; 253 254 if (CHECK_TERMINATOR(passwd)) 255 return (NS_NOTFOUND); 256 fn = mdata; 257 pwd = va_arg(ap, struct passwd *); 258 buffer = va_arg(ap, char *); 259 bufsize = va_arg(ap, size_t); 260 errnop = va_arg(ap, int *); 261 nss_status = fn(pwd, buffer, bufsize, errnop); 262 ns_status = __nss_compat_result(nss_status, *errnop); 263 if (ns_status == NS_SUCCESS) 264 *(struct passwd **)retval = pwd; 265 else if (ns_status != NS_RETURN) 266 SET_TERMINATOR(passwd, &terminator); 267 return (ns_status); 268 } 269 270 271 int 272 __nss_compat_setpwent(void *retval, void *mdata, va_list ap) 273 { 274 275 SET_TERMINATOR(passwd, NULL); 276 ((int (*)(void))mdata)(); 277 return (NS_UNAVAIL); 278 } 279 280 281 int 282 __nss_compat_endpwent(void *retval, void *mdata, va_list ap) 283 { 284 285 SET_TERMINATOR(passwd, NULL); 286 ((int (*)(void))mdata)(); 287 return (NS_UNAVAIL); 288 } 289