]> andersk Git - nss_nonlocal.git/blame - nonlocal-passwd.c
Add copyright notice to nonlocal.h
[nss_nonlocal.git] / nonlocal-passwd.c
CommitLineData
f6903667
AK
1/*
2 * nonlocal-passwd.c
3 * passwd database for nss_nonlocal proxy.
4 *
96a1ee0f
AK
5 * Copyright © 2007–2010 Anders Kaseorg <andersk@mit.edu> and Tim
6 * Abbott <tabbott@mit.edu>
f6903667 7 *
96a1ee0f 8 * This file is part of nss_nonlocal.
f6903667 9 *
96a1ee0f
AK
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.
f6903667 14 *
96a1ee0f
AK
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.
19 *
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
23 * 02110-1301 USA
f6903667
AK
24 */
25
26
27#define _GNU_SOURCE
28#include <sys/types.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <stdint.h>
32#include <string.h>
33#include <dlfcn.h>
34#include <stdio.h>
35#include <syslog.h>
36#include <errno.h>
37#include <pwd.h>
38#include <grp.h>
39#include <nss.h>
40#include "nsswitch-internal.h"
41#include "nonlocal.h"
42
c1812233
AK
43
44enum nss_status
45_nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
46 char *buffer, size_t buflen, int *errnop);
47enum nss_status
48_nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
49 char *buffer, size_t buflen, int *errnop);
f7293a54 50
f6903667
AK
51
52static service_user *
53nss_passwd_nonlocal_database(void)
54{
55 static service_user *nip = NULL;
56 if (nip == NULL)
57 __nss_database_lookup("passwd_nonlocal", NULL, "", &nip);
58
59 return nip;
60}
61
62
f6903667
AK
63enum nss_status
64check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
65{
30fb3957
AK
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;
70 service_user *nip;
71 union {
72 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
73 char *buffer, size_t buflen, int *errnop);
74 void *ptr;
75 } fct;
f7293a54 76 struct passwd pwbuf;
f7293a54 77 int old_errno = errno;
c1812233 78
8870ee9c 79 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
f7293a54
AK
80 char *buf = malloc(buflen);
81 if (buf == NULL) {
f6903667 82 *errnop = ENOMEM;
f7293a54 83 errno = old_errno;
f6903667
AK
84 return NSS_STATUS_TRYAGAIN;
85 }
30fb3957
AK
86
87 if (fct_start == NULL &&
88 __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
89 free(buf);
90 return NSS_STATUS_UNAVAIL;
91 }
92 nip = startp;
93 fct.ptr = fct_start;
94 do {
d905b369 95 morebuf:
c1812233
AK
96 if (fct.l == _nss_nonlocal_getpwuid_r)
97 status = NSS_STATUS_NOTFOUND;
98 else
99 status = DL_CALL_FCT(fct.l, (uid, &pwbuf, buf, buflen, errnop));
d905b369
AK
100 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) {
101 free(buf);
102 buflen *= 2;
103 buf = malloc(buflen);
104 if (buf == NULL) {
105 *errnop = ENOMEM;
106 errno = old_errno;
107 return NSS_STATUS_TRYAGAIN;
108 }
109 goto morebuf;
110 }
30fb3957
AK
111 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
112
113 if (status == NSS_STATUS_SUCCESS) {
f7293a54 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);
f6903667 115 status = NSS_STATUS_NOTFOUND;
30fb3957
AK
116 } else if (status != NSS_STATUS_TRYAGAIN) {
117 status = NSS_STATUS_SUCCESS;
f6903667 118 }
30fb3957 119
f7293a54 120 free(buf);
f6903667
AK
121 return status;
122}
123
cf338316
AK
124enum nss_status
125check_nonlocal_passwd(const char *user, struct passwd *pwd, int *errnop)
126{
a07a7616
AK
127 enum nss_status status = NSS_STATUS_SUCCESS;
128 int old_errno = errno;
129 char *end;
130 unsigned long uid;
131
132 errno = 0;
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);
136 errno = old_errno;
137 if (status != NSS_STATUS_SUCCESS)
138 return status;
139
cf338316
AK
140 return check_nonlocal_uid(user, pwd->pw_uid, errnop);
141}
142
48479fc7
TA
143enum nss_status
144check_nonlocal_user(const char *user, int *errnop)
145{
30fb3957
AK
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;
150 service_user *nip;
151 union {
152 enum nss_status (*l)(const char *name, struct passwd *pwd,
153 char *buffer, size_t buflen, int *errnop);
154 void *ptr;
155 } fct;
48479fc7 156 struct passwd pwbuf;
48479fc7 157 int old_errno = errno;
c1812233 158
8870ee9c 159 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
48479fc7
TA
160 char *buf = malloc(buflen);
161 if (buf == NULL) {
162 *errnop = ENOMEM;
163 errno = old_errno;
164 return NSS_STATUS_TRYAGAIN;
165 }
30fb3957
AK
166
167 if (fct_start == NULL &&
168 __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
169 free(buf);
170 return NSS_STATUS_UNAVAIL;
48479fc7 171 }
30fb3957
AK
172 nip = startp;
173 fct.ptr = fct_start;
174 do {
d905b369 175 morebuf:
c1812233
AK
176 if (fct.l == _nss_nonlocal_getpwnam_r)
177 status = NSS_STATUS_NOTFOUND;
178 else
179 status = DL_CALL_FCT(fct.l, (user, &pwbuf, buf, buflen, errnop));
d905b369
AK
180 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) {
181 free(buf);
182 buflen *= 2;
183 buf = malloc(buflen);
184 if (buf == NULL) {
185 *errnop = ENOMEM;
186 errno = old_errno;
187 return NSS_STATUS_TRYAGAIN;
188 }
189 goto morebuf;
190 }
30fb3957
AK
191 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
192
193 if (status == NSS_STATUS_SUCCESS)
194 status = NSS_STATUS_NOTFOUND;
195 else if (status != NSS_STATUS_TRYAGAIN)
196 status = NSS_STATUS_SUCCESS;
197
48479fc7 198 free(buf);
48479fc7
TA
199 return status;
200}
f6903667 201
1e78305d 202
f6903667
AK
203static service_user *pwent_nip = NULL;
204static void *pwent_fct_start;
205static union {
206 enum nss_status (*l)(struct passwd *pwd, char *buffer, size_t buflen,
207 int *errnop);
208 void *ptr;
209} pwent_fct;
210static const char *pwent_fct_name = "getpwent_r";
211
212enum nss_status
213_nss_nonlocal_setpwent(int stayopen)
214{
215 static const char *fct_name = "setpwent";
216 static void *fct_start = NULL;
217 enum nss_status status;
218 service_user *nip;
219 union {
220 enum nss_status (*l)(int stayopen);
221 void *ptr;
222 } fct;
223
224 nip = nss_passwd_nonlocal_database();
225 if (nip == NULL)
226 return NSS_STATUS_UNAVAIL;
227 if (fct_start == NULL)
228 fct_start = __nss_lookup_function(nip, fct_name);
229 fct.ptr = fct_start;
230 do {
231 if (fct.ptr == NULL)
232 status = NSS_STATUS_UNAVAIL;
233 else
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)
237 return status;
238
239 pwent_nip = nip;
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;
244}
245
246enum nss_status
247_nss_nonlocal_endpwent(void)
248{
249 static const char *fct_name = "endpwent";
250 static void *fct_start = NULL;
251 enum nss_status status;
252 service_user *nip;
253 union {
254 enum nss_status (*l)(void);
255 void *ptr;
256 } fct;
257
258 pwent_nip = NULL;
259
260 nip = nss_passwd_nonlocal_database();
261 if (nip == NULL)
262 return NSS_STATUS_UNAVAIL;
263 if (fct_start == NULL)
264 fct_start = __nss_lookup_function(nip, fct_name);
265 fct.ptr = fct_start;
266 do {
267 if (fct.ptr == NULL)
268 status = NSS_STATUS_UNAVAIL;
269 else
270 status = DL_CALL_FCT(fct.l, ());
271 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
272 return status;
273}
274
275enum nss_status
276_nss_nonlocal_getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
277 int *errnop)
278{
279 enum nss_status status;
a360549e
TA
280
281 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
c1812233 282 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
a360549e
TA
283 return NSS_STATUS_UNAVAIL;
284
f6903667
AK
285 if (pwent_nip == NULL) {
286 status = _nss_nonlocal_setpwent(0);
287 if (status != NSS_STATUS_SUCCESS)
288 return status;
289 }
290 do {
291 if (pwent_fct.ptr == NULL)
292 status = NSS_STATUS_UNAVAIL;
293 else {
294 int nonlocal_errno;
295 do
a360549e 296 status = DL_CALL_FCT(pwent_fct.l, (pwd, buffer, buflen, errnop));
f6903667 297 while (status == NSS_STATUS_SUCCESS &&
cf338316 298 check_nonlocal_passwd(pwd->pw_name, pwd, &nonlocal_errno) != NSS_STATUS_SUCCESS);
f6903667
AK
299 }
300 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
301 return status;
302
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);
306
307 pwent_nip = NULL;
308 return NSS_STATUS_NOTFOUND;
309}
310
311
312enum nss_status
313_nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
314 char *buffer, size_t buflen, int *errnop)
315{
316 static const char *fct_name = "getpwnam_r";
317 static void *fct_start = NULL;
318 enum nss_status status;
319 service_user *nip;
320 union {
321 enum nss_status (*l)(const char *name, struct passwd *pwd,
322 char *buffer, size_t buflen, int *errnop);
323 void *ptr;
324 } fct;
325 int group_errno;
326
a360549e 327 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
c1812233 328 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
48479fc7
TA
329 return NSS_STATUS_UNAVAIL;
330
f6903667
AK
331 nip = nss_passwd_nonlocal_database();
332 if (nip == NULL)
333 return NSS_STATUS_UNAVAIL;
334 if (fct_start == NULL)
335 fct_start = __nss_lookup_function(nip, fct_name);
336 fct.ptr = fct_start;
337 do {
338 if (fct.ptr == NULL)
339 status = NSS_STATUS_UNAVAIL;
340 else
341 status = DL_CALL_FCT(fct.l, (name, pwd, buffer, buflen, errnop));
342 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
343 break;
344 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
345 if (status != NSS_STATUS_SUCCESS)
346 return status;
347
22562df0
AK
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;
351 }
352
cf338316 353 status = check_nonlocal_passwd(name, pwd, errnop);
f6903667
AK
354 if (status != NSS_STATUS_SUCCESS)
355 return status;
356
357 if (check_nonlocal_gid(name, pwd->pw_gid, &group_errno) !=
358 NSS_STATUS_SUCCESS)
359 pwd->pw_gid = 65534 /* nogroup */;
360 return NSS_STATUS_SUCCESS;
361}
362
363enum nss_status
364_nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
365 char *buffer, size_t buflen, int *errnop)
366{
367 static const char *fct_name = "getpwuid_r";
368 static void *fct_start = NULL;
369 enum nss_status status;
370 service_user *nip;
371 union {
372 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
373 char *buffer, size_t buflen, int *errnop);
374 void *ptr;
375 } fct;
376 int group_errno;
377
a360549e 378 char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV);
c1812233 379 if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0')
f6903667
AK
380 return NSS_STATUS_UNAVAIL;
381
382 nip = nss_passwd_nonlocal_database();
383 if (nip == NULL)
384 return NSS_STATUS_UNAVAIL;
385 if (fct_start == NULL)
386 fct_start = __nss_lookup_function(nip, fct_name);
387 fct.ptr = fct_start;
388 do {
389 if (fct.ptr == NULL)
390 status = NSS_STATUS_UNAVAIL;
391 else
392 status = DL_CALL_FCT(fct.l, (uid, pwd, buffer, buflen, errnop));
393 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
394 break;
395 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
396 if (status != NSS_STATUS_SUCCESS)
397 return status;
398
8027fdc4
AK
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;
402 }
403
cf338316 404 status = check_nonlocal_passwd(pwd->pw_name, pwd, errnop);
f6903667
AK
405 if (status != NSS_STATUS_SUCCESS)
406 return status;
407
408 if (check_nonlocal_gid(pwd->pw_name, pwd->pw_gid, &group_errno) !=
409 NSS_STATUS_SUCCESS)
410 pwd->pw_gid = 65534 /* nogroup */;
411 return NSS_STATUS_SUCCESS;
412}
This page took 0.896933 seconds and 5 git commands to generate.