3 * passwd database for nss_nonlocal proxy.
5 * Copyright © 2007–2010 Anders Kaseorg <andersk@mit.edu> and Tim
6 * Abbott <tabbott@mit.edu>
8 * This file is part of nss_nonlocal.
10 * nss_nonlocal is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1 of
13 * the License, or (at your option) any later version.
15 * nss_nonlocal is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with nss_nonlocal; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 #include <sys/types.h>
40 #include "nsswitch-internal.h"
45 _nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
46 char *buffer, size_t buflen, int *errnop);
48 _nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
49 char *buffer, size_t buflen, int *errnop);
53 nss_passwd_nonlocal_database(void)
55 static service_user *nip = NULL;
57 __nss_database_lookup("passwd_nonlocal", NULL, "", &nip);
64 check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
66 static const char *fct_name = "getpwuid_r";
67 static service_user *startp = NULL;
68 static void *fct_start = NULL;
69 enum nss_status status;
72 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
73 char *buffer, size_t buflen, int *errnop);
77 int old_errno = errno;
79 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
80 char *buf = malloc(buflen);
84 return NSS_STATUS_TRYAGAIN;
87 if (fct_start == NULL &&
88 __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
90 return NSS_STATUS_UNAVAIL;
96 if (fct.l == _nss_nonlocal_getpwuid_r)
97 status = NSS_STATUS_NOTFOUND;
99 status = DL_CALL_FCT(fct.l, (uid, &pwbuf, buf, buflen, errnop));
100 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) {
103 buf = malloc(buflen);
107 return NSS_STATUS_TRYAGAIN;
111 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
113 if (status == NSS_STATUS_SUCCESS) {
114 syslog(LOG_ERR, "nss_nonlocal: possible spoofing attack: non-local user %s has same UID as local user %s!\n", user, pwbuf.pw_name);
115 status = NSS_STATUS_NOTFOUND;
116 } else if (status != NSS_STATUS_TRYAGAIN) {
117 status = NSS_STATUS_SUCCESS;
125 check_nonlocal_passwd(const char *user, struct passwd *pwd, int *errnop)
127 enum nss_status status = NSS_STATUS_SUCCESS;
128 int old_errno = errno;
133 uid = strtoul(pwd->pw_name, &end, 10);
134 if (errno == 0 && *end == '\0' && (uid_t)uid == uid)
135 status = check_nonlocal_uid(user, uid, errnop);
137 if (status != NSS_STATUS_SUCCESS)
140 return check_nonlocal_uid(user, pwd->pw_uid, errnop);
144 check_nonlocal_user(const char *user, int *errnop)
146 static const char *fct_name = "getpwnam_r";
147 static service_user *startp = NULL;
148 static void *fct_start = NULL;
149 enum nss_status status;
152 enum nss_status (*l)(const char *name, struct passwd *pwd,
153 char *buffer, size_t buflen, int *errnop);
157 int old_errno = errno;
159 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
160 char *buf = malloc(buflen);
164 return NSS_STATUS_TRYAGAIN;
167 if (fct_start == NULL &&
168 __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
170 return NSS_STATUS_UNAVAIL;
176 if (fct.l == _nss_nonlocal_getpwnam_r)
177 status = NSS_STATUS_NOTFOUND;
179 status = DL_CALL_FCT(fct.l, (user, &pwbuf, buf, buflen, errnop));
180 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) {
183 buf = malloc(buflen);
187 return NSS_STATUS_TRYAGAIN;
191 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
193 if (status == NSS_STATUS_SUCCESS)
194 status = NSS_STATUS_NOTFOUND;
195 else if (status != NSS_STATUS_TRYAGAIN)
196 status = NSS_STATUS_SUCCESS;
203 static service_user *pwent_nip = NULL;
204 static void *pwent_fct_start;
206 enum nss_status (*l)(struct passwd *pwd, char *buffer, size_t buflen,
210 static const char *pwent_fct_name = "getpwent_r";
213 _nss_nonlocal_setpwent(int stayopen)
215 static const char *fct_name = "setpwent";
216 static void *fct_start = NULL;
217 enum nss_status status;
220 enum nss_status (*l)(int stayopen);
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, (stayopen));
235 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
236 if (status != NSS_STATUS_SUCCESS)
240 if (pwent_fct_start == NULL)
241 pwent_fct_start = __nss_lookup_function(nip, pwent_fct_name);
242 pwent_fct.ptr = pwent_fct_start;
243 return NSS_STATUS_SUCCESS;
247 _nss_nonlocal_endpwent(void)
249 static const char *fct_name = "endpwent";
250 static void *fct_start = NULL;
251 enum nss_status status;
254 enum nss_status (*l)(void);
260 nip = nss_passwd_nonlocal_database();
262 return NSS_STATUS_UNAVAIL;
263 if (fct_start == NULL)
264 fct_start = __nss_lookup_function(nip, fct_name);
268 status = NSS_STATUS_UNAVAIL;
270 status = DL_CALL_FCT(fct.l, ());
271 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
276 _nss_nonlocal_getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
279 enum nss_status status;
281 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
282 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
283 return NSS_STATUS_UNAVAIL;
285 if (pwent_nip == NULL) {
286 status = _nss_nonlocal_setpwent(0);
287 if (status != NSS_STATUS_SUCCESS)
291 if (pwent_fct.ptr == NULL)
292 status = NSS_STATUS_UNAVAIL;
296 status = DL_CALL_FCT(pwent_fct.l, (pwd, buffer, buflen, errnop));
297 while (status == NSS_STATUS_SUCCESS &&
298 check_nonlocal_passwd(pwd->pw_name, pwd, &nonlocal_errno) != NSS_STATUS_SUCCESS);
300 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
303 if (status == NSS_STATUS_SUCCESS)
304 return NSS_STATUS_SUCCESS;
305 } while (__nss_next(&pwent_nip, pwent_fct_name, &pwent_fct.ptr, status, 0) == 0);
308 return NSS_STATUS_NOTFOUND;
313 _nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
314 char *buffer, size_t buflen, int *errnop)
316 static const char *fct_name = "getpwnam_r";
317 static void *fct_start = NULL;
318 enum nss_status status;
321 enum nss_status (*l)(const char *name, struct passwd *pwd,
322 char *buffer, size_t buflen, int *errnop);
327 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
328 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
329 return NSS_STATUS_UNAVAIL;
331 nip = nss_passwd_nonlocal_database();
333 return NSS_STATUS_UNAVAIL;
334 if (fct_start == NULL)
335 fct_start = __nss_lookup_function(nip, fct_name);
339 status = NSS_STATUS_UNAVAIL;
341 status = DL_CALL_FCT(fct.l, (name, pwd, buffer, buflen, errnop));
342 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
344 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
345 if (status != NSS_STATUS_SUCCESS)
348 if (strcmp(name, pwd->pw_name) != 0) {
349 syslog(LOG_ERR, "nss_nonlocal: discarding user %s from lookup for user %s\n", pwd->pw_name, name);
350 return NSS_STATUS_NOTFOUND;
353 status = check_nonlocal_passwd(name, pwd, errnop);
354 if (status != NSS_STATUS_SUCCESS)
357 if (check_nonlocal_gid(name, pwd->pw_gid, &group_errno) !=
359 pwd->pw_gid = 65534 /* nogroup */;
360 return NSS_STATUS_SUCCESS;
364 _nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
365 char *buffer, size_t buflen, int *errnop)
367 static const char *fct_name = "getpwuid_r";
368 static void *fct_start = NULL;
369 enum nss_status status;
372 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
373 char *buffer, size_t buflen, int *errnop);
378 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
379 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
380 return NSS_STATUS_UNAVAIL;
382 nip = nss_passwd_nonlocal_database();
384 return NSS_STATUS_UNAVAIL;
385 if (fct_start == NULL)
386 fct_start = __nss_lookup_function(nip, fct_name);
390 status = NSS_STATUS_UNAVAIL;
392 status = DL_CALL_FCT(fct.l, (uid, pwd, buffer, buflen, errnop));
393 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
395 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
396 if (status != NSS_STATUS_SUCCESS)
399 if (uid != pwd->pw_uid) {
400 syslog(LOG_ERR, "nss_nonlocal: discarding uid %d from lookup for uid %d\n", pwd->pw_uid, uid);
401 return NSS_STATUS_NOTFOUND;
404 status = check_nonlocal_passwd(pwd->pw_name, pwd, errnop);
405 if (status != NSS_STATUS_SUCCESS)
408 if (check_nonlocal_gid(pwd->pw_name, pwd->pw_gid, &group_errno) !=
410 pwd->pw_gid = 65534 /* nogroup */;
411 return NSS_STATUS_SUCCESS;