]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/nss_nisplus/nisplus-pwd.c
.
[thirdparty/glibc.git] / nis / nss_nisplus / nisplus-pwd.c
CommitLineData
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. */
39static ib_request *ibreq;
40static directory_obj *dir;
41static dir_binding bptr;
42static char *tablepath;
43static char *tableptr;
44/* Cursor. */
45static netobj cursor;
d08a1d40 46
d08a1d40 47
48b29391
UD
48nis_name pwd_tablename_val attribute_hidden;
49size_t pwd_tablename_len attribute_hidden;
0ecb606c 50
48b29391
UD
51enum 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
85static void
86internal_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
105static enum nss_status
106internal_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
136enum 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
155enum 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 168static enum nss_status
d71b808a
UD
169internal_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
273enum 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
288enum 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
353enum 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}