3 * passwd database for nss_nonlocal proxy.
5 * Copyright © 2007 Anders Kaseorg <andersk@mit.edu>
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use, copy,
11 * modify, merge, publish, distribute, sublicense, and/or sell copies
12 * of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 #include <sys/types.h>
42 #include "nsswitch-internal.h"
47 nss_passwd_nonlocal_database(void)
49 static service_user *nip = NULL;
51 __nss_database_lookup("passwd_nonlocal", NULL, "", &nip);
57 static __thread int local_only = 0;
60 local_getpwuid_r(uid_t uid, struct passwd *pwd,
61 char *buffer, size_t buflen, int *errnop)
63 int old_local_only = local_only;
64 int old_errno = errno;
69 ret = getpwuid_r(uid, pwd, buffer, buflen, &pwd);
71 local_only = old_local_only;
76 return NSS_STATUS_SUCCESS;
78 return NSS_STATUS_NOTFOUND;
80 return NSS_STATUS_TRYAGAIN;
84 check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
86 struct passwd local_pwd;
87 int local_errno = errno;
88 enum nss_status local_status, status = NSS_STATUS_SUCCESS;
89 int local_buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
90 char *local_buffer = malloc(local_buflen);
91 if (local_buffer == NULL) {
94 return NSS_STATUS_TRYAGAIN;
97 local_status = local_getpwuid_r(uid, &local_pwd, local_buffer,
98 local_buflen, &local_errno);
99 if (local_status == NSS_STATUS_SUCCESS) {
100 syslog(LOG_ERR, "nss_nonlocal: possible spoofing attack: non-local user %s has same UID as local user %s!\n", user, local_pwd.pw_name);
101 status = NSS_STATUS_NOTFOUND;
102 } else if (local_status != NSS_STATUS_NOTFOUND &&
103 local_status != NSS_STATUS_UNAVAIL) {
104 *errnop = local_errno;
105 status = local_status;
112 static service_user *pwent_nip = NULL;
113 static void *pwent_fct_start;
115 enum nss_status (*l)(struct passwd *pwd, char *buffer, size_t buflen,
119 static const char *pwent_fct_name = "getpwent_r";
122 _nss_nonlocal_setpwent(int stayopen)
124 static const char *fct_name = "setpwent";
125 static void *fct_start = NULL;
126 enum nss_status status;
129 enum nss_status (*l)(int stayopen);
133 nip = nss_passwd_nonlocal_database();
135 return NSS_STATUS_UNAVAIL;
136 if (fct_start == NULL)
137 fct_start = __nss_lookup_function(nip, fct_name);
141 status = NSS_STATUS_UNAVAIL;
143 status = DL_CALL_FCT(fct.l, (stayopen));
144 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
145 if (status != NSS_STATUS_SUCCESS)
149 if (pwent_fct_start == NULL)
150 pwent_fct_start = __nss_lookup_function(nip, pwent_fct_name);
151 pwent_fct.ptr = pwent_fct_start;
152 return NSS_STATUS_SUCCESS;
156 _nss_nonlocal_endpwent(void)
158 static const char *fct_name = "endpwent";
159 static void *fct_start = NULL;
160 enum nss_status status;
163 enum nss_status (*l)(void);
169 nip = nss_passwd_nonlocal_database();
171 return NSS_STATUS_UNAVAIL;
172 if (fct_start == NULL)
173 fct_start = __nss_lookup_function(nip, fct_name);
177 status = NSS_STATUS_UNAVAIL;
179 status = DL_CALL_FCT(fct.l, ());
180 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
185 _nss_nonlocal_getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
188 enum nss_status status;
189 if (pwent_nip == NULL) {
190 status = _nss_nonlocal_setpwent(0);
191 if (status != NSS_STATUS_SUCCESS)
195 if (pwent_fct.ptr == NULL)
196 status = NSS_STATUS_UNAVAIL;
200 status = DL_CALL_FCT(pwent_fct.l, (pwd, buffer, buflen, errnop));
201 while (status == NSS_STATUS_SUCCESS &&
202 check_nonlocal_uid(pwd->pw_name, pwd->pw_uid, &nonlocal_errno) != NSS_STATUS_SUCCESS);
204 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
207 if (status == NSS_STATUS_SUCCESS)
208 return NSS_STATUS_SUCCESS;
209 } while (__nss_next(&pwent_nip, pwent_fct_name, &pwent_fct.ptr, status, 0) == 0);
212 return NSS_STATUS_NOTFOUND;
217 _nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
218 char *buffer, size_t buflen, int *errnop)
220 static const char *fct_name = "getpwnam_r";
221 static void *fct_start = NULL;
222 enum nss_status status;
225 enum nss_status (*l)(const char *name, struct passwd *pwd,
226 char *buffer, size_t buflen, int *errnop);
231 nip = nss_passwd_nonlocal_database();
233 return NSS_STATUS_UNAVAIL;
234 if (fct_start == NULL)
235 fct_start = __nss_lookup_function(nip, fct_name);
239 status = NSS_STATUS_UNAVAIL;
241 status = DL_CALL_FCT(fct.l, (name, pwd, buffer, buflen, errnop));
242 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
244 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
245 if (status != NSS_STATUS_SUCCESS)
248 status = check_nonlocal_uid(name, pwd->pw_uid, errnop);
249 if (status != NSS_STATUS_SUCCESS)
252 if (check_nonlocal_gid(name, pwd->pw_gid, &group_errno) !=
254 pwd->pw_gid = 65534 /* nogroup */;
255 return NSS_STATUS_SUCCESS;
259 _nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
260 char *buffer, size_t buflen, int *errnop)
262 static const char *fct_name = "getpwuid_r";
263 static void *fct_start = NULL;
264 enum nss_status status;
267 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
268 char *buffer, size_t buflen, int *errnop);
274 return NSS_STATUS_UNAVAIL;
276 nip = nss_passwd_nonlocal_database();
278 return NSS_STATUS_UNAVAIL;
279 if (fct_start == NULL)
280 fct_start = __nss_lookup_function(nip, fct_name);
284 status = NSS_STATUS_UNAVAIL;
286 status = DL_CALL_FCT(fct.l, (uid, pwd, buffer, buflen, errnop));
287 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
289 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
290 if (status != NSS_STATUS_SUCCESS)
293 status = check_nonlocal_uid(pwd->pw_name, pwd->pw_uid, errnop);
294 if (status != NSS_STATUS_SUCCESS)
297 if (check_nonlocal_gid(pwd->pw_name, pwd->pw_gid, &group_errno) !=
299 pwd->pw_gid = 65534 /* nogroup */;
300 return NSS_STATUS_SUCCESS;