]>
Commit | Line | Data |
---|---|---|
32c075e1 | 1 | /* Copyright (C) 1997, 1999, 2001, 2002, 2003, 2005, 2006, 2007 |
c8e82b4a | 2 | Free Software Foundation, Inc. |
e61abf83 UD |
3 | This file is part of the GNU C Library. |
4 | Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
e61abf83 UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
e61abf83 | 15 | |
41bdb6e2 AJ |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 02111-1307 USA. */ | |
e61abf83 | 20 | |
48b29391 | 21 | #include <atomic.h> |
e61abf83 UD |
22 | #include <nss.h> |
23 | #include <errno.h> | |
24 | #include <pwd.h> | |
25 | #include <string.h> | |
5107cf1d | 26 | #include <bits/libc-lock.h> |
e61abf83 | 27 | #include <rpcsvc/nis.h> |
e61abf83 UD |
28 | |
29 | #include "nss-nisplus.h" | |
7d1de115 | 30 | #include "nisplus-parser.h" |
d08a1d40 | 31 | #include <libnsl.h> |
a17fa610 UD |
32 | #include <nis_intern.h> |
33 | #include <nis_xdr.h> | |
d08a1d40 | 34 | |
e61abf83 UD |
35 | |
36 | __libc_lock_define_initialized (static, lock) | |
37 | ||
a17fa610 UD |
38 | /* Connection information. */ |
39 | static ib_request *ibreq; | |
40 | static directory_obj *dir; | |
41 | static dir_binding bptr; | |
42 | static char *tablepath; | |
43 | static char *tableptr; | |
44 | /* Cursor. */ | |
45 | static netobj cursor; | |
d08a1d40 | 46 | |
d08a1d40 | 47 | |
48b29391 UD |
48 | nis_name pwd_tablename_val attribute_hidden; |
49 | size_t pwd_tablename_len attribute_hidden; | |
0ecb606c | 50 | |
48b29391 UD |
51 | enum nss_status |
52 | _nss_pwd_create_tablename (int *errnop) | |
e61abf83 | 53 | { |
48b29391 | 54 | if (pwd_tablename_val == NULL) |
e61abf83 | 55 | { |
48b29391 UD |
56 | const char *local_dir = nis_local_directory (); |
57 | size_t local_dir_len = strlen (local_dir); | |
58 | static const char prefix[] = "passwd.org_dir."; | |
2d7da676 | 59 | |
48b29391 | 60 | char *p = malloc (sizeof (prefix) + local_dir_len); |
c8e82b4a | 61 | if (p == NULL) |
d71b808a UD |
62 | { |
63 | *errnop = errno; | |
64 | return NSS_STATUS_TRYAGAIN; | |
65 | } | |
48b29391 UD |
66 | |
67 | memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); | |
68 | ||
69 | pwd_tablename_len = sizeof (prefix) - 1 + local_dir_len; | |
70 | ||
71 | atomic_write_barrier (); | |
72 | ||
8e64faef UD |
73 | if (atomic_compare_and_exchange_bool_acq (&pwd_tablename_val, p, NULL)) |
74 | { | |
75 | /* Another thread already installed the value. */ | |
76 | free (p); | |
77 | pwd_tablename_len = strlen (pwd_tablename_val); | |
78 | } | |
e61abf83 | 79 | } |
48b29391 | 80 | |
2d7da676 | 81 | return NSS_STATUS_SUCCESS; |
e61abf83 UD |
82 | } |
83 | ||
2d7da676 | 84 | |
d08a1d40 UD |
85 | static void |
86 | internal_nisplus_endpwent (void) | |
e61abf83 | 87 | { |
a17fa610 UD |
88 | __nisbind_destroy (&bptr); |
89 | memset (&bptr, '\0', sizeof (bptr)); | |
e61abf83 | 90 | |
a17fa610 UD |
91 | nis_free_directory (dir); |
92 | dir = NULL; | |
93 | ||
94 | nis_free_request (ibreq); | |
95 | ibreq = NULL; | |
96 | ||
97 | xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); | |
98 | memset (&cursor, '\0', sizeof (cursor)); | |
99 | ||
100 | free (tablepath); | |
101 | tableptr = tablepath = NULL; | |
d08a1d40 UD |
102 | } |
103 | ||
104 | ||
105 | static enum nss_status | |
106 | internal_nisplus_setpwent (int *errnop) | |
107 | { | |
a17fa610 | 108 | enum nss_status status = NSS_STATUS_SUCCESS; |
d08a1d40 | 109 | |
a17fa610 UD |
110 | if (pwd_tablename_val == NULL) |
111 | status = _nss_pwd_create_tablename (errnop); | |
d08a1d40 | 112 | |
a17fa610 | 113 | if (status == NSS_STATUS_SUCCESS) |
d08a1d40 | 114 | { |
a17fa610 UD |
115 | ibreq = __create_ib_request (pwd_tablename_val, 0); |
116 | if (ibreq == NULL) | |
117 | { | |
118 | *errnop = errno; | |
119 | return NSS_STATUS_TRYAGAIN; | |
120 | } | |
121 | ||
122 | nis_error retcode = __prepare_niscall (pwd_tablename_val, &dir, | |
123 | &bptr, 0); | |
124 | if (retcode != NIS_SUCCESS) | |
125 | { | |
126 | nis_free_request (ibreq); | |
127 | ibreq = NULL; | |
128 | status = niserr2nss (retcode); | |
129 | } | |
d08a1d40 UD |
130 | } |
131 | ||
132 | return status; | |
133 | } | |
134 | ||
135 | ||
136 | enum nss_status | |
137 | _nss_nisplus_setpwent (int stayopen) | |
138 | { | |
a17fa610 | 139 | enum nss_status status; |
d08a1d40 UD |
140 | |
141 | __libc_lock_lock (lock); | |
142 | ||
143 | internal_nisplus_endpwent (); | |
2d7da676 | 144 | |
a17fa610 UD |
145 | // XXX We need to be able to set errno. Pass in new parameter. |
146 | int err; | |
147 | status = internal_nisplus_setpwent (&err); | |
d08a1d40 | 148 | |
e61abf83 UD |
149 | __libc_lock_unlock (lock); |
150 | ||
2d7da676 | 151 | return status; |
e61abf83 UD |
152 | } |
153 | ||
d08a1d40 | 154 | |
e61abf83 UD |
155 | enum nss_status |
156 | _nss_nisplus_endpwent (void) | |
157 | { | |
158 | __libc_lock_lock (lock); | |
159 | ||
d08a1d40 | 160 | internal_nisplus_endpwent (); |
e61abf83 UD |
161 | |
162 | __libc_lock_unlock (lock); | |
163 | ||
164 | return NSS_STATUS_SUCCESS; | |
165 | } | |
166 | ||
d08a1d40 | 167 | |
e61abf83 | 168 | static enum nss_status |
d71b808a UD |
169 | internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen, |
170 | int *errnop) | |
e61abf83 | 171 | { |
d08a1d40 | 172 | int parse_res = -1; |
a17fa610 | 173 | enum nss_status retval = NSS_STATUS_SUCCESS; |
e61abf83 UD |
174 | |
175 | /* Get the next entry until we found a correct one. */ | |
176 | do | |
177 | { | |
a17fa610 UD |
178 | nis_error status; |
179 | nis_result result; | |
180 | memset (&result, '\0', sizeof (result)); | |
181 | ||
182 | if (cursor.n_bytes == NULL) | |
e61abf83 | 183 | { |
a17fa610 UD |
184 | if (ibreq == NULL) |
185 | { | |
186 | retval = internal_nisplus_setpwent (errnop); | |
187 | if (retval != NSS_STATUS_SUCCESS) | |
188 | return retval; | |
189 | } | |
190 | ||
191 | status = __do_niscall3 (&bptr, NIS_IBFIRST, | |
192 | (xdrproc_t) _xdr_ib_request, | |
193 | (caddr_t) ibreq, | |
194 | (xdrproc_t) _xdr_nis_result, | |
195 | (caddr_t) &result, | |
196 | 0, NULL); | |
e61abf83 UD |
197 | } |
198 | else | |
199 | { | |
a17fa610 UD |
200 | ibreq->ibr_cookie.n_bytes = cursor.n_bytes; |
201 | ibreq->ibr_cookie.n_len = cursor.n_len; | |
202 | ||
203 | status = __do_niscall3 (&bptr, NIS_IBNEXT, | |
204 | (xdrproc_t) _xdr_ib_request, | |
205 | (caddr_t) ibreq, | |
206 | (xdrproc_t) _xdr_nis_result, | |
207 | (caddr_t) &result, | |
208 | 0, NULL); | |
209 | ||
210 | ibreq->ibr_cookie.n_bytes = NULL; | |
211 | ibreq->ibr_cookie.n_len = 0; | |
212 | } | |
d08a1d40 | 213 | |
a17fa610 UD |
214 | if (status != NIS_SUCCESS) |
215 | return niserr2nss (status); | |
216 | ||
217 | if (NIS_RES_STATUS (&result) == NIS_NOTFOUND) | |
218 | { | |
219 | /* No more entries on this server. This means we have to go | |
220 | to the next server on the path. */ | |
221 | status = __follow_path (&tablepath, &tableptr, ibreq, &bptr); | |
222 | if (status != NIS_SUCCESS) | |
223 | return niserr2nss (status); | |
224 | ||
225 | directory_obj *newdir = NULL; | |
226 | dir_binding newbptr; | |
227 | status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0); | |
228 | if (status != NIS_SUCCESS) | |
229 | return niserr2nss (status); | |
230 | ||
231 | nis_free_directory (dir); | |
232 | dir = newdir; | |
233 | __nisbind_destroy (&bptr); | |
234 | bptr = newbptr; | |
235 | ||
236 | xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie); | |
237 | result.cookie.n_bytes = NULL; | |
238 | result.cookie.n_len = 0; | |
239 | parse_res = 0; | |
240 | goto next; | |
e61abf83 | 241 | } |
a17fa610 UD |
242 | else if (NIS_RES_STATUS (&result) != NIS_SUCCESS) |
243 | return niserr2nss (NIS_RES_STATUS (&result)); | |
244 | ||
245 | parse_res = _nss_nisplus_parse_pwent (&result, pw, buffer, | |
246 | buflen, errnop); | |
e61abf83 | 247 | |
48b29391 | 248 | if (__builtin_expect (parse_res == -1, 0)) |
60c96635 | 249 | { |
d71b808a | 250 | *errnop = ERANGE; |
a17fa610 UD |
251 | retval = NSS_STATUS_TRYAGAIN; |
252 | goto freeres; | |
60c96635 | 253 | } |
48b29391 | 254 | |
a17fa610 UD |
255 | next: |
256 | /* Free the old cursor. */ | |
257 | xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); | |
258 | /* Remember the new one. */ | |
259 | cursor.n_bytes = result.cookie.n_bytes; | |
260 | cursor.n_len = result.cookie.n_len; | |
261 | /* Free the result structure. NB: we do not remove the cookie. */ | |
262 | result.cookie.n_bytes = NULL; | |
263 | result.cookie.n_len = 0; | |
264 | freeres: | |
265 | xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result); | |
266 | memset (&result, '\0', sizeof (result)); | |
48b29391 UD |
267 | } |
268 | while (!parse_res); | |
e61abf83 | 269 | |
a17fa610 | 270 | return retval; |
e61abf83 UD |
271 | } |
272 | ||
273 | enum nss_status | |
d71b808a UD |
274 | _nss_nisplus_getpwent_r (struct passwd *result, char *buffer, size_t buflen, |
275 | int *errnop) | |
e61abf83 UD |
276 | { |
277 | int status; | |
278 | ||
279 | __libc_lock_lock (lock); | |
280 | ||
d71b808a | 281 | status = internal_nisplus_getpwent_r (result, buffer, buflen, errnop); |
e61abf83 UD |
282 | |
283 | __libc_lock_unlock (lock); | |
284 | ||
285 | return status; | |
286 | } | |
287 | ||
288 | enum nss_status | |
289 | _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw, | |
d71b808a | 290 | char *buffer, size_t buflen, int *errnop) |
e61abf83 UD |
291 | { |
292 | int parse_res; | |
293 | ||
48b29391 | 294 | if (pwd_tablename_val == NULL) |
d71b808a | 295 | { |
48b29391 UD |
296 | enum nss_status status = _nss_pwd_create_tablename (errnop); |
297 | ||
d71b808a UD |
298 | if (status != NSS_STATUS_SUCCESS) |
299 | return status; | |
300 | } | |
2d7da676 | 301 | |
ac9f45cf UD |
302 | if (name == NULL) |
303 | { | |
304 | *errnop = EINVAL; | |
305 | return NSS_STATUS_UNAVAIL; | |
306 | } | |
e61abf83 | 307 | |
48b29391 UD |
308 | nis_result *result; |
309 | char buf[strlen (name) + 9 + pwd_tablename_len]; | |
310 | int olderr = errno; | |
e61abf83 | 311 | |
48b29391 | 312 | snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val); |
e61abf83 | 313 | |
32c075e1 | 314 | result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); |
e61abf83 | 315 | |
48b29391 UD |
316 | if (result == NULL) |
317 | { | |
318 | *errnop = ENOMEM; | |
319 | return NSS_STATUS_TRYAGAIN; | |
320 | } | |
34816665 | 321 | |
48b29391 UD |
322 | if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) |
323 | { | |
324 | enum nss_status status = niserr2nss (result->status); | |
e61abf83 | 325 | |
48b29391 | 326 | __set_errno (olderr); |
e61abf83 UD |
327 | |
328 | nis_freeresult (result); | |
48b29391 UD |
329 | return status; |
330 | } | |
331 | ||
a17fa610 | 332 | parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); |
e61abf83 | 333 | |
48b29391 UD |
334 | nis_freeresult (result); |
335 | ||
336 | if (__builtin_expect (parse_res < 1, 0)) | |
337 | { | |
338 | if (parse_res == -1) | |
0ecb606c | 339 | { |
48b29391 UD |
340 | *errnop = ERANGE; |
341 | return NSS_STATUS_TRYAGAIN; | |
342 | } | |
343 | else | |
344 | { | |
345 | __set_errno (olderr); | |
346 | return NSS_STATUS_NOTFOUND; | |
d71b808a | 347 | } |
e61abf83 | 348 | } |
48b29391 UD |
349 | |
350 | return NSS_STATUS_SUCCESS; | |
e61abf83 UD |
351 | } |
352 | ||
353 | enum nss_status | |
354 | _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw, | |
d71b808a | 355 | char *buffer, size_t buflen, int *errnop) |
e61abf83 | 356 | { |
48b29391 | 357 | if (pwd_tablename_val == NULL) |
d71b808a | 358 | { |
48b29391 UD |
359 | enum nss_status status = _nss_pwd_create_tablename (errnop); |
360 | ||
d71b808a UD |
361 | if (status != NSS_STATUS_SUCCESS) |
362 | return status; | |
363 | } | |
364 | ||
48b29391 UD |
365 | int parse_res; |
366 | nis_result *result; | |
367 | char buf[8 + 3 * sizeof (unsigned long int) + pwd_tablename_len]; | |
368 | int olderr = errno; | |
e61abf83 | 369 | |
48b29391 UD |
370 | snprintf (buf, sizeof (buf), "[uid=%lu],%s", |
371 | (unsigned long int) uid, pwd_tablename_val); | |
e61abf83 | 372 | |
32c075e1 | 373 | result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); |
e61abf83 | 374 | |
48b29391 UD |
375 | if (result == NULL) |
376 | { | |
377 | *errnop = ENOMEM; | |
378 | return NSS_STATUS_TRYAGAIN; | |
379 | } | |
e61abf83 | 380 | |
48b29391 UD |
381 | if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) |
382 | { | |
383 | enum nss_status status = niserr2nss (result->status); | |
34816665 | 384 | |
48b29391 UD |
385 | __set_errno (olderr); |
386 | ||
387 | nis_freeresult (result); | |
388 | return status; | |
389 | } | |
390 | ||
a17fa610 | 391 | parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); |
48b29391 UD |
392 | |
393 | nis_freeresult (result); | |
394 | ||
395 | if (__builtin_expect (parse_res < 1, 0)) | |
396 | { | |
397 | if (parse_res == -1) | |
398 | { | |
399 | *errnop = ERANGE; | |
400 | return NSS_STATUS_TRYAGAIN; | |
401 | } | |
402 | else | |
403 | { | |
404 | __set_errno (olderr); | |
405 | return NSS_STATUS_NOTFOUND; | |
406 | } | |
407 | } | |
408 | ||
409 | return NSS_STATUS_SUCCESS; | |
e61abf83 | 410 | } |