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"
45 #define MAGIC_LOCAL_PW_BUFLEN (sysconf(_SC_GETPW_R_SIZE_MAX) + 7)
49 nss_passwd_nonlocal_database(void)
51 static service_user *nip = NULL;
53 __nss_database_lookup("passwd_nonlocal", NULL, "", &nip);
60 check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
62 enum nss_status status = NSS_STATUS_SUCCESS;
64 struct passwd *pwbufp = &pwbuf;
66 int old_errno = errno;
67 int buflen = MAGIC_LOCAL_PW_BUFLEN;
68 char *buf = malloc(buflen);
72 return NSS_STATUS_TRYAGAIN;
75 ret = getpwuid_r(uid, pwbufp, buf, buflen, &pwbufp);
78 status = NSS_STATUS_TRYAGAIN;
79 } else if (pwbufp != NULL) {
80 syslog(LOG_ERR, "nss_nonlocal: possible spoofing attack: non-local user %s has same UID as local user %s!\n", user, pwbuf.pw_name);
81 status = NSS_STATUS_NOTFOUND;
89 static service_user *pwent_nip = NULL;
90 static void *pwent_fct_start;
92 enum nss_status (*l)(struct passwd *pwd, char *buffer, size_t buflen,
96 static const char *pwent_fct_name = "getpwent_r";
99 _nss_nonlocal_setpwent(int stayopen)
101 static const char *fct_name = "setpwent";
102 static void *fct_start = NULL;
103 enum nss_status status;
106 enum nss_status (*l)(int stayopen);
110 nip = nss_passwd_nonlocal_database();
112 return NSS_STATUS_UNAVAIL;
113 if (fct_start == NULL)
114 fct_start = __nss_lookup_function(nip, fct_name);
118 status = NSS_STATUS_UNAVAIL;
120 status = DL_CALL_FCT(fct.l, (stayopen));
121 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
122 if (status != NSS_STATUS_SUCCESS)
126 if (pwent_fct_start == NULL)
127 pwent_fct_start = __nss_lookup_function(nip, pwent_fct_name);
128 pwent_fct.ptr = pwent_fct_start;
129 return NSS_STATUS_SUCCESS;
133 _nss_nonlocal_endpwent(void)
135 static const char *fct_name = "endpwent";
136 static void *fct_start = NULL;
137 enum nss_status status;
140 enum nss_status (*l)(void);
146 nip = nss_passwd_nonlocal_database();
148 return NSS_STATUS_UNAVAIL;
149 if (fct_start == NULL)
150 fct_start = __nss_lookup_function(nip, fct_name);
154 status = NSS_STATUS_UNAVAIL;
156 status = DL_CALL_FCT(fct.l, ());
157 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
162 _nss_nonlocal_getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
165 enum nss_status status;
166 if (pwent_nip == NULL) {
167 status = _nss_nonlocal_setpwent(0);
168 if (status != NSS_STATUS_SUCCESS)
172 if (pwent_fct.ptr == NULL)
173 status = NSS_STATUS_UNAVAIL;
177 status = DL_CALL_FCT(pwent_fct.l, (pwd, buffer, buflen, errnop));
178 while (status == NSS_STATUS_SUCCESS &&
179 check_nonlocal_uid(pwd->pw_name, pwd->pw_uid, &nonlocal_errno) != NSS_STATUS_SUCCESS);
181 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
184 if (status == NSS_STATUS_SUCCESS)
185 return NSS_STATUS_SUCCESS;
186 } while (__nss_next(&pwent_nip, pwent_fct_name, &pwent_fct.ptr, status, 0) == 0);
189 return NSS_STATUS_NOTFOUND;
194 _nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
195 char *buffer, size_t buflen, int *errnop)
197 static const char *fct_name = "getpwnam_r";
198 static void *fct_start = NULL;
199 enum nss_status status;
202 enum nss_status (*l)(const char *name, struct passwd *pwd,
203 char *buffer, size_t buflen, int *errnop);
208 nip = nss_passwd_nonlocal_database();
210 return NSS_STATUS_UNAVAIL;
211 if (fct_start == NULL)
212 fct_start = __nss_lookup_function(nip, fct_name);
216 status = NSS_STATUS_UNAVAIL;
218 status = DL_CALL_FCT(fct.l, (name, pwd, buffer, buflen, errnop));
219 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
221 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
222 if (status != NSS_STATUS_SUCCESS)
225 status = check_nonlocal_uid(name, pwd->pw_uid, errnop);
226 if (status != NSS_STATUS_SUCCESS)
229 if (check_nonlocal_gid(name, pwd->pw_gid, &group_errno) !=
231 pwd->pw_gid = 65534 /* nogroup */;
232 return NSS_STATUS_SUCCESS;
236 _nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
237 char *buffer, size_t buflen, int *errnop)
239 static const char *fct_name = "getpwuid_r";
240 static void *fct_start = NULL;
241 enum nss_status status;
244 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
245 char *buffer, size_t buflen, int *errnop);
250 if (buflen == MAGIC_LOCAL_PW_BUFLEN)
251 return NSS_STATUS_UNAVAIL;
253 nip = nss_passwd_nonlocal_database();
255 return NSS_STATUS_UNAVAIL;
256 if (fct_start == NULL)
257 fct_start = __nss_lookup_function(nip, fct_name);
261 status = NSS_STATUS_UNAVAIL;
263 status = DL_CALL_FCT(fct.l, (uid, pwd, buffer, buflen, errnop));
264 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
266 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
267 if (status != NSS_STATUS_SUCCESS)
270 status = check_nonlocal_uid(pwd->pw_name, pwd->pw_uid, errnop);
271 if (status != NSS_STATUS_SUCCESS)
274 if (check_nonlocal_gid(pwd->pw_name, pwd->pw_gid, &group_errno) !=
276 pwd->pw_gid = 65534 /* nogroup */;
277 return NSS_STATUS_SUCCESS;