]> andersk Git - nss_nonlocal.git/blame - nonlocal-passwd.c
Don't link with pthread.
[nss_nonlocal.git] / nonlocal-passwd.c
CommitLineData
f6903667
AK
1/*
2 * nonlocal-passwd.c
3 * passwd database for nss_nonlocal proxy.
4 *
5 * Copyright © 2007 Anders Kaseorg <andersk@mit.edu>
6 *
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:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
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
25 * SOFTWARE.
26 */
27
28
29#define _GNU_SOURCE
30#include <sys/types.h>
31#include <unistd.h>
32#include <stdlib.h>
33#include <stdint.h>
34#include <string.h>
35#include <dlfcn.h>
36#include <stdio.h>
37#include <syslog.h>
38#include <errno.h>
39#include <pwd.h>
40#include <grp.h>
41#include <nss.h>
42#include "nsswitch-internal.h"
43#include "nonlocal.h"
44
f7293a54
AK
45#define MAGIC_LOCAL_PW_BUFLEN (sysconf(_SC_GETPW_R_SIZE_MAX) + 7)
46
f6903667
AK
47
48static service_user *
49nss_passwd_nonlocal_database(void)
50{
51 static service_user *nip = NULL;
52 if (nip == NULL)
53 __nss_database_lookup("passwd_nonlocal", NULL, "", &nip);
54
55 return nip;
56}
57
58
f6903667
AK
59enum nss_status
60check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
61{
f7293a54
AK
62 enum nss_status status = NSS_STATUS_SUCCESS;
63 struct passwd pwbuf;
64 struct passwd *pwbufp = &pwbuf;
65 int ret;
66 int old_errno = errno;
67 int buflen = MAGIC_LOCAL_PW_BUFLEN;
68 char *buf = malloc(buflen);
69 if (buf == NULL) {
f6903667 70 *errnop = ENOMEM;
f7293a54 71 errno = old_errno;
f6903667
AK
72 return NSS_STATUS_TRYAGAIN;
73 }
f7293a54
AK
74 errno = 0;
75 ret = getpwuid_r(uid, pwbufp, buf, buflen, &pwbufp);
76 if (ret != 0) {
77 *errnop = errno;
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);
f6903667 81 status = NSS_STATUS_NOTFOUND;
f6903667 82 }
f7293a54
AK
83 free(buf);
84 errno = old_errno;
f6903667
AK
85 return status;
86}
87
88
89static service_user *pwent_nip = NULL;
90static void *pwent_fct_start;
91static union {
92 enum nss_status (*l)(struct passwd *pwd, char *buffer, size_t buflen,
93 int *errnop);
94 void *ptr;
95} pwent_fct;
96static const char *pwent_fct_name = "getpwent_r";
97
98enum nss_status
99_nss_nonlocal_setpwent(int stayopen)
100{
101 static const char *fct_name = "setpwent";
102 static void *fct_start = NULL;
103 enum nss_status status;
104 service_user *nip;
105 union {
106 enum nss_status (*l)(int stayopen);
107 void *ptr;
108 } fct;
109
110 nip = nss_passwd_nonlocal_database();
111 if (nip == NULL)
112 return NSS_STATUS_UNAVAIL;
113 if (fct_start == NULL)
114 fct_start = __nss_lookup_function(nip, fct_name);
115 fct.ptr = fct_start;
116 do {
117 if (fct.ptr == NULL)
118 status = NSS_STATUS_UNAVAIL;
119 else
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)
123 return status;
124
125 pwent_nip = nip;
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;
130}
131
132enum nss_status
133_nss_nonlocal_endpwent(void)
134{
135 static const char *fct_name = "endpwent";
136 static void *fct_start = NULL;
137 enum nss_status status;
138 service_user *nip;
139 union {
140 enum nss_status (*l)(void);
141 void *ptr;
142 } fct;
143
144 pwent_nip = NULL;
145
146 nip = nss_passwd_nonlocal_database();
147 if (nip == NULL)
148 return NSS_STATUS_UNAVAIL;
149 if (fct_start == NULL)
150 fct_start = __nss_lookup_function(nip, fct_name);
151 fct.ptr = fct_start;
152 do {
153 if (fct.ptr == NULL)
154 status = NSS_STATUS_UNAVAIL;
155 else
156 status = DL_CALL_FCT(fct.l, ());
157 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
158 return status;
159}
160
161enum nss_status
162_nss_nonlocal_getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
163 int *errnop)
164{
165 enum nss_status status;
166 if (pwent_nip == NULL) {
167 status = _nss_nonlocal_setpwent(0);
168 if (status != NSS_STATUS_SUCCESS)
169 return status;
170 }
171 do {
172 if (pwent_fct.ptr == NULL)
173 status = NSS_STATUS_UNAVAIL;
174 else {
175 int nonlocal_errno;
176 do
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);
180 }
181 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
182 return status;
183
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);
187
188 pwent_nip = NULL;
189 return NSS_STATUS_NOTFOUND;
190}
191
192
193enum nss_status
194_nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd,
195 char *buffer, size_t buflen, int *errnop)
196{
197 static const char *fct_name = "getpwnam_r";
198 static void *fct_start = NULL;
199 enum nss_status status;
200 service_user *nip;
201 union {
202 enum nss_status (*l)(const char *name, struct passwd *pwd,
203 char *buffer, size_t buflen, int *errnop);
204 void *ptr;
205 } fct;
206 int group_errno;
207
208 nip = nss_passwd_nonlocal_database();
209 if (nip == NULL)
210 return NSS_STATUS_UNAVAIL;
211 if (fct_start == NULL)
212 fct_start = __nss_lookup_function(nip, fct_name);
213 fct.ptr = fct_start;
214 do {
215 if (fct.ptr == NULL)
216 status = NSS_STATUS_UNAVAIL;
217 else
218 status = DL_CALL_FCT(fct.l, (name, pwd, buffer, buflen, errnop));
219 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
220 break;
221 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
222 if (status != NSS_STATUS_SUCCESS)
223 return status;
224
225 status = check_nonlocal_uid(name, pwd->pw_uid, errnop);
226 if (status != NSS_STATUS_SUCCESS)
227 return status;
228
229 if (check_nonlocal_gid(name, pwd->pw_gid, &group_errno) !=
230 NSS_STATUS_SUCCESS)
231 pwd->pw_gid = 65534 /* nogroup */;
232 return NSS_STATUS_SUCCESS;
233}
234
235enum nss_status
236_nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd,
237 char *buffer, size_t buflen, int *errnop)
238{
239 static const char *fct_name = "getpwuid_r";
240 static void *fct_start = NULL;
241 enum nss_status status;
242 service_user *nip;
243 union {
244 enum nss_status (*l)(uid_t uid, struct passwd *pwd,
245 char *buffer, size_t buflen, int *errnop);
246 void *ptr;
247 } fct;
248 int group_errno;
249
f7293a54 250 if (buflen == MAGIC_LOCAL_PW_BUFLEN)
f6903667
AK
251 return NSS_STATUS_UNAVAIL;
252
253 nip = nss_passwd_nonlocal_database();
254 if (nip == NULL)
255 return NSS_STATUS_UNAVAIL;
256 if (fct_start == NULL)
257 fct_start = __nss_lookup_function(nip, fct_name);
258 fct.ptr = fct_start;
259 do {
260 if (fct.ptr == NULL)
261 status = NSS_STATUS_UNAVAIL;
262 else
263 status = DL_CALL_FCT(fct.l, (uid, pwd, buffer, buflen, errnop));
264 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
265 break;
266 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
267 if (status != NSS_STATUS_SUCCESS)
268 return status;
269
270 status = check_nonlocal_uid(pwd->pw_name, pwd->pw_uid, errnop);
271 if (status != NSS_STATUS_SUCCESS)
272 return status;
273
274 if (check_nonlocal_gid(pwd->pw_name, pwd->pw_gid, &group_errno) !=
275 NSS_STATUS_SUCCESS)
276 pwd->pw_gid = 65534 /* nogroup */;
277 return NSS_STATUS_SUCCESS;
278}
This page took 0.18052 seconds and 5 git commands to generate.