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