1 /* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2006
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
6 The GNU C Library is free software; you can redistribute it and/or
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.
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
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
26 #include <bits/libc-lock.h>
27 #include <rpcsvc/nis.h>
29 #include "nss-nisplus.h"
30 #include "nisplus-parser.h"
32 #include <nis_intern.h>
36 __libc_lock_define_initialized (static, lock
);
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
;
48 nis_name grp_tablename_val attribute_hidden
;
49 size_t grp_tablename_len attribute_hidden
;
52 _nss_grp_create_tablename (int *errnop
)
54 if (grp_tablename_val
== NULL
)
56 const char *local_dir
= nis_local_directory ();
57 size_t local_dir_len
= strlen (local_dir
);
58 static const char prefix
[] = "group.org_dir.";
60 char *p
= malloc (sizeof (prefix
) + local_dir_len
);
64 return NSS_STATUS_TRYAGAIN
;
67 memcpy (__stpcpy (p
, prefix
), local_dir
, local_dir_len
+ 1);
69 grp_tablename_len
= sizeof (prefix
) - 1 + local_dir_len
;
71 atomic_write_barrier ();
73 if (atomic_compare_and_exchange_bool_acq (&grp_tablename_val
, p
, NULL
))
75 /* Another thread already installed the value. */
77 grp_tablename_len
= strlen (grp_tablename_val
);
81 return NSS_STATUS_SUCCESS
;
86 internal_endgrent (void)
88 __nisbind_destroy (&bptr
);
89 memset (&bptr
, '\0', sizeof (bptr
));
91 nis_free_directory (dir
);
94 nis_free_request (ibreq
);
97 xdr_free ((xdrproc_t
) xdr_netobj
, (char *) &cursor
);
98 memset (&cursor
, '\0', sizeof (cursor
));
101 tableptr
= tablepath
= NULL
;
105 static enum nss_status
106 internal_setgrent (int *errnop
)
108 enum nss_status status
= NSS_STATUS_SUCCESS
;
110 if (grp_tablename_val
== NULL
)
111 status
= _nss_grp_create_tablename (errnop
);
113 if (status
== NSS_STATUS_SUCCESS
)
115 ibreq
= __create_ib_request (grp_tablename_val
, 0);
119 return NSS_STATUS_TRYAGAIN
;
122 nis_error retcode
= __prepare_niscall (grp_tablename_val
, &dir
, &bptr
, 0);
123 if (retcode
!= NIS_SUCCESS
)
125 nis_free_request (ibreq
);
127 status
= niserr2nss (retcode
);
136 _nss_nisplus_setgrent (int stayopen
)
138 enum nss_status status
;
140 __libc_lock_lock (lock
);
142 internal_endgrent ();
144 // XXX We need to be able to set errno. Pass in new parameter.
146 status
= internal_setgrent (&err
);
148 __libc_lock_unlock (lock
);
155 _nss_nisplus_endgrent (void)
157 __libc_lock_lock (lock
);
159 internal_endgrent ();
161 __libc_lock_unlock (lock
);
163 return NSS_STATUS_SUCCESS
;
167 static enum nss_status
168 internal_nisplus_getgrent_r (struct group
*gr
, char *buffer
, size_t buflen
,
172 enum nss_status retval
= NSS_STATUS_SUCCESS
;
174 /* Get the next entry until we found a correct one. */
179 memset (&result
, '\0', sizeof (result
));
181 if (cursor
.n_bytes
== NULL
)
185 retval
= internal_setgrent (errnop
);
186 if (retval
!= NSS_STATUS_SUCCESS
)
190 status
= __do_niscall3 (&bptr
, NIS_IBFIRST
,
191 (xdrproc_t
) _xdr_ib_request
,
193 (xdrproc_t
) _xdr_nis_result
,
199 ibreq
->ibr_cookie
.n_bytes
= cursor
.n_bytes
;
200 ibreq
->ibr_cookie
.n_len
= cursor
.n_len
;
202 status
= __do_niscall3 (&bptr
, NIS_IBNEXT
,
203 (xdrproc_t
) _xdr_ib_request
,
205 (xdrproc_t
) _xdr_nis_result
,
209 ibreq
->ibr_cookie
.n_bytes
= NULL
;
210 ibreq
->ibr_cookie
.n_len
= 0;
213 if (status
!= NIS_SUCCESS
)
214 return niserr2nss (status
);
216 if (NIS_RES_STATUS (&result
) == NIS_NOTFOUND
)
218 /* No more entries on this server. This means we have to go
219 to the next server on the path. */
220 status
= __follow_path (&tablepath
, &tableptr
, ibreq
, &bptr
);
221 if (status
!= NIS_SUCCESS
)
222 return niserr2nss (status
);
224 directory_obj
*newdir
= NULL
;
226 status
= __prepare_niscall (ibreq
->ibr_name
, &newdir
, &newbptr
, 0);
227 if (status
!= NIS_SUCCESS
)
228 return niserr2nss (status
);
230 nis_free_directory (dir
);
232 __nisbind_destroy (&bptr
);
235 xdr_free ((xdrproc_t
) xdr_netobj
, (char *) &result
.cookie
);
236 result
.cookie
.n_bytes
= NULL
;
237 result
.cookie
.n_len
= 0;
241 else if (NIS_RES_STATUS (&result
) != NIS_SUCCESS
)
242 return niserr2nss (NIS_RES_STATUS (&result
));
244 parse_res
= _nss_nisplus_parse_grent (&result
, gr
,
245 buffer
, buflen
, errnop
);
246 if (__builtin_expect (parse_res
== -1, 0))
249 retval
= NSS_STATUS_TRYAGAIN
;
254 /* Free the old cursor. */
255 xdr_free ((xdrproc_t
) xdr_netobj
, (char *) &cursor
);
256 /* Remember the new one. */
257 cursor
.n_bytes
= result
.cookie
.n_bytes
;
258 cursor
.n_len
= result
.cookie
.n_len
;
259 /* Free the result structure. NB: we do not remove the cookie. */
260 result
.cookie
.n_bytes
= NULL
;
261 result
.cookie
.n_len
= 0;
263 xdr_free ((xdrproc_t
) _xdr_nis_result
, (char *) &result
);
264 memset (&result
, '\0', sizeof (result
));
272 _nss_nisplus_getgrent_r (struct group
*result
, char *buffer
, size_t buflen
,
277 __libc_lock_lock (lock
);
279 status
= internal_nisplus_getgrent_r (result
, buffer
, buflen
, errnop
);
281 __libc_lock_unlock (lock
);
287 _nss_nisplus_getgrnam_r (const char *name
, struct group
*gr
,
288 char *buffer
, size_t buflen
, int *errnop
)
292 if (grp_tablename_val
== NULL
)
294 enum nss_status status
= _nss_grp_create_tablename (errnop
);
296 if (status
!= NSS_STATUS_SUCCESS
)
303 return NSS_STATUS_NOTFOUND
;
307 char buf
[strlen (name
) + 9 + grp_tablename_len
];
310 snprintf (buf
, sizeof (buf
), "[name=%s],%s", name
, grp_tablename_val
);
312 result
= nis_list (buf
, FOLLOW_LINKS
| FOLLOW_PATH
, NULL
, NULL
);
317 return NSS_STATUS_TRYAGAIN
;
320 if (__builtin_expect (niserr2nss (result
->status
) != NSS_STATUS_SUCCESS
, 0))
322 enum nss_status status
= niserr2nss (result
->status
);
324 nis_freeresult (result
);
328 parse_res
= _nss_nisplus_parse_grent (result
, gr
, buffer
, buflen
, errnop
);
329 nis_freeresult (result
);
330 if (__builtin_expect (parse_res
< 1, 0))
335 return NSS_STATUS_TRYAGAIN
;
339 __set_errno (olderr
);
340 return NSS_STATUS_NOTFOUND
;
344 return NSS_STATUS_SUCCESS
;
348 _nss_nisplus_getgrgid_r (const gid_t gid
, struct group
*gr
,
349 char *buffer
, size_t buflen
, int *errnop
)
351 if (grp_tablename_val
== NULL
)
353 enum nss_status status
= _nss_grp_create_tablename (errnop
);
355 if (status
!= NSS_STATUS_SUCCESS
)
361 char buf
[8 + 3 * sizeof (unsigned long int) + grp_tablename_len
];
364 snprintf (buf
, sizeof (buf
), "[gid=%lu],%s",
365 (unsigned long int) gid
, grp_tablename_val
);
367 result
= nis_list (buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
372 return NSS_STATUS_TRYAGAIN
;
375 if (__builtin_expect (niserr2nss (result
->status
) != NSS_STATUS_SUCCESS
, 0))
377 enum nss_status status
= niserr2nss (result
->status
);
379 __set_errno (olderr
);
381 nis_freeresult (result
);
385 parse_res
= _nss_nisplus_parse_grent (result
, gr
, buffer
, buflen
, errnop
);
387 nis_freeresult (result
);
388 if (__builtin_expect (parse_res
< 1, 0))
390 __set_errno (olderr
);
395 return NSS_STATUS_TRYAGAIN
;
398 return NSS_STATUS_NOTFOUND
;
401 return NSS_STATUS_SUCCESS
;