3 * passwd database for nss_nonlocal proxy.
5 * Copyright © 2007 Anders Kaseorg <andersk@mit.edu> and Tim Abbott
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use, copy,
12 * modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 #include <sys/types.h>
43 #include "nsswitch-internal.h"
48 _nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
49 char *buffer, size_t buflen, int *errnop);
51 _nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
52 char *buffer, size_t buflen, int *errnop);
56 nss_passwd_nonlocal_database(void)
58 static service_user *nip = NULL;
60 __nss_database_lookup("passwd_nonlocal", NULL, "", &nip);
67 check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
69 static const char *fct_name = "getpwuid_r";
70 static service_user *startp = NULL;
71 static void *fct_start = NULL;
72 enum nss_status status;
75 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
76 char *buffer, size_t buflen, int *errnop);
80 int old_errno = errno;
82 int buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
83 char *buf = malloc(buflen);
87 return NSS_STATUS_TRYAGAIN;
90 if (fct_start == NULL &&
91 __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
93 return NSS_STATUS_UNAVAIL;
98 if (fct.l == _nss_nonlocal_getpwuid_r)
99 status = NSS_STATUS_NOTFOUND;
101 status = DL_CALL_FCT(fct.l, (uid, &pwbuf, buf, buflen, errnop));
102 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
104 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
106 if (status == NSS_STATUS_SUCCESS) {
107 syslog(LOG_ERR, "nss_nonlocal: possible spoofing attack: non-local user %s has same UID as local user %s!\n", user, pwbuf.pw_name);
108 status = NSS_STATUS_NOTFOUND;
109 } else if (status != NSS_STATUS_TRYAGAIN) {
110 status = NSS_STATUS_SUCCESS;
118 check_nonlocal_user(const char *user, int *errnop)
120 static const char *fct_name = "getpwnam_r";
121 static service_user *startp = NULL;
122 static void *fct_start = NULL;
123 enum nss_status status;
126 enum nss_status (*l)(const char *name, struct passwd *pwd,
127 char *buffer, size_t buflen, int *errnop);
131 int old_errno = errno;
133 int buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
134 char *buf = malloc(buflen);
138 return NSS_STATUS_TRYAGAIN;
141 if (fct_start == NULL &&
142 __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
144 return NSS_STATUS_UNAVAIL;
149 if (fct.l == _nss_nonlocal_getpwnam_r)
150 status = NSS_STATUS_NOTFOUND;
152 status = DL_CALL_FCT(fct.l, (user, &pwbuf, buf, buflen, errnop));
153 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
155 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
157 if (status == NSS_STATUS_SUCCESS)
158 status = NSS_STATUS_NOTFOUND;
159 else if (status != NSS_STATUS_TRYAGAIN)
160 status = NSS_STATUS_SUCCESS;
167 static service_user *pwent_nip = NULL;
168 static void *pwent_fct_start;
170 enum nss_status (*l)(struct passwd *pwd, char *buffer, size_t buflen,
174 static const char *pwent_fct_name = "getpwent_r";
177 _nss_nonlocal_setpwent(int stayopen)
179 static const char *fct_name = "setpwent";
180 static void *fct_start = NULL;
181 enum nss_status status;
184 enum nss_status (*l)(int stayopen);
188 nip = nss_passwd_nonlocal_database();
190 return NSS_STATUS_UNAVAIL;
191 if (fct_start == NULL)
192 fct_start = __nss_lookup_function(nip, fct_name);
196 status = NSS_STATUS_UNAVAIL;
198 status = DL_CALL_FCT(fct.l, (stayopen));
199 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
200 if (status != NSS_STATUS_SUCCESS)
204 if (pwent_fct_start == NULL)
205 pwent_fct_start = __nss_lookup_function(nip, pwent_fct_name);
206 pwent_fct.ptr = pwent_fct_start;
207 return NSS_STATUS_SUCCESS;
211 _nss_nonlocal_endpwent(void)
213 static const char *fct_name = "endpwent";
214 static void *fct_start = NULL;
215 enum nss_status status;
218 enum nss_status (*l)(void);
224 nip = nss_passwd_nonlocal_database();
226 return NSS_STATUS_UNAVAIL;
227 if (fct_start == NULL)
228 fct_start = __nss_lookup_function(nip, fct_name);
232 status = NSS_STATUS_UNAVAIL;
234 status = DL_CALL_FCT(fct.l, ());
235 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
240 _nss_nonlocal_getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
243 enum nss_status status;
245 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
246 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
247 return NSS_STATUS_UNAVAIL;
249 if (pwent_nip == NULL) {
250 status = _nss_nonlocal_setpwent(0);
251 if (status != NSS_STATUS_SUCCESS)
255 if (pwent_fct.ptr == NULL)
256 status = NSS_STATUS_UNAVAIL;
260 status = DL_CALL_FCT(pwent_fct.l, (pwd, buffer, buflen, errnop));
261 while (status == NSS_STATUS_SUCCESS &&
262 check_nonlocal_uid(pwd->pw_name, pwd->pw_uid, &nonlocal_errno) != NSS_STATUS_SUCCESS);
264 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
267 if (status == NSS_STATUS_SUCCESS)
268 return NSS_STATUS_SUCCESS;
269 } while (__nss_next(&pwent_nip, pwent_fct_name, &pwent_fct.ptr, status, 0) == 0);
272 return NSS_STATUS_NOTFOUND;
277 _nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
278 char *buffer, size_t buflen, int *errnop)
280 static const char *fct_name = "getpwnam_r";
281 static void *fct_start = NULL;
282 enum nss_status status;
285 enum nss_status (*l)(const char *name, struct passwd *pwd,
286 char *buffer, size_t buflen, int *errnop);
291 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
292 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
293 return NSS_STATUS_UNAVAIL;
295 nip = nss_passwd_nonlocal_database();
297 return NSS_STATUS_UNAVAIL;
298 if (fct_start == NULL)
299 fct_start = __nss_lookup_function(nip, fct_name);
303 status = NSS_STATUS_UNAVAIL;
305 status = DL_CALL_FCT(fct.l, (name, pwd, buffer, buflen, errnop));
306 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
308 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
309 if (status != NSS_STATUS_SUCCESS)
312 status = check_nonlocal_uid(name, pwd->pw_uid, errnop);
313 if (status != NSS_STATUS_SUCCESS)
316 if (check_nonlocal_gid(name, pwd->pw_gid, &group_errno) !=
318 pwd->pw_gid = 65534 /* nogroup */;
319 return NSS_STATUS_SUCCESS;
323 _nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
324 char *buffer, size_t buflen, int *errnop)
326 static const char *fct_name = "getpwuid_r";
327 static void *fct_start = NULL;
328 enum nss_status status;
331 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
332 char *buffer, size_t buflen, int *errnop);
337 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
338 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
339 return NSS_STATUS_UNAVAIL;
341 nip = nss_passwd_nonlocal_database();
343 return NSS_STATUS_UNAVAIL;
344 if (fct_start == NULL)
345 fct_start = __nss_lookup_function(nip, fct_name);
349 status = NSS_STATUS_UNAVAIL;
351 status = DL_CALL_FCT(fct.l, (uid, pwd, buffer, buflen, errnop));
352 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
354 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
355 if (status != NSS_STATUS_SUCCESS)
358 status = check_nonlocal_uid(pwd->pw_name, pwd->pw_uid, errnop);
359 if (status != NSS_STATUS_SUCCESS)
362 if (check_nonlocal_gid(pwd->pw_name, pwd->pw_gid, &group_errno) !=
364 pwd->pw_gid = 65534 /* nogroup */;
365 return NSS_STATUS_SUCCESS;