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