Back to index

glibc  2.9
nisplus-grp.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2006
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <atomic.h>
00022 #include <nss.h>
00023 #include <grp.h>
00024 #include <ctype.h>
00025 #include <errno.h>
00026 #include <string.h>
00027 #include <bits/libc-lock.h>
00028 #include <rpcsvc/nis.h>
00029 
00030 #include "nss-nisplus.h"
00031 #include "nisplus-parser.h"
00032 #include <libnsl.h>
00033 #include <nis_intern.h>
00034 #include <nis_xdr.h>
00035 
00036 
00037 __libc_lock_define_initialized (static, lock);
00038 
00039 /* Connection information.  */
00040 static ib_request *ibreq;
00041 static directory_obj *dir;
00042 static dir_binding bptr;
00043 static char *tablepath;
00044 static char *tableptr;
00045 /* Cursor.  */
00046 static netobj cursor;
00047 
00048 
00049 nis_name grp_tablename_val attribute_hidden;
00050 size_t grp_tablename_len attribute_hidden;
00051 
00052 enum nss_status
00053 _nss_grp_create_tablename (int *errnop)
00054 {
00055   if (grp_tablename_val == NULL)
00056     {
00057       const char *local_dir = nis_local_directory ();
00058       size_t local_dir_len = strlen (local_dir);
00059       static const char prefix[] = "group.org_dir.";
00060 
00061       char *p = malloc (sizeof (prefix) + local_dir_len);
00062       if (p == NULL)
00063        {
00064          *errnop = errno;
00065          return NSS_STATUS_TRYAGAIN;
00066        }
00067 
00068       memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
00069 
00070       grp_tablename_len = sizeof (prefix) - 1 + local_dir_len;
00071 
00072       atomic_write_barrier ();
00073 
00074       if (atomic_compare_and_exchange_bool_acq (&grp_tablename_val, p, NULL))
00075        {
00076          /* Another thread already installed the value.  */
00077          free (p);
00078          grp_tablename_len = strlen (grp_tablename_val);
00079        }
00080     }
00081 
00082   return NSS_STATUS_SUCCESS;
00083 }
00084 
00085 
00086 static void
00087 internal_endgrent (void)
00088 {
00089   __nisbind_destroy (&bptr);
00090   memset (&bptr, '\0', sizeof (bptr));
00091 
00092   nis_free_directory (dir);
00093   dir = NULL;
00094 
00095   nis_free_request (ibreq);
00096   ibreq = NULL;
00097 
00098   xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
00099   memset (&cursor, '\0', sizeof (cursor));
00100 
00101   free (tablepath);
00102   tableptr = tablepath = NULL;
00103 }
00104 
00105 
00106 static enum nss_status
00107 internal_setgrent (int *errnop)
00108 {
00109   enum nss_status status = NSS_STATUS_SUCCESS;
00110 
00111   if (grp_tablename_val == NULL)
00112     status = _nss_grp_create_tablename (errnop);
00113 
00114   if (status == NSS_STATUS_SUCCESS)
00115     {
00116       ibreq = __create_ib_request (grp_tablename_val, 0);
00117       if (ibreq == NULL)
00118        {
00119          *errnop = errno;
00120          return NSS_STATUS_TRYAGAIN;
00121        }
00122 
00123       nis_error retcode = __prepare_niscall (grp_tablename_val, &dir, &bptr, 0);
00124       if (retcode != NIS_SUCCESS)
00125        {
00126          nis_free_request (ibreq);
00127          ibreq = NULL;
00128          status = niserr2nss (retcode);
00129        }
00130     }
00131 
00132   return status;
00133 }
00134 
00135 
00136 enum nss_status
00137 _nss_nisplus_setgrent (int stayopen)
00138 {
00139   enum nss_status status;
00140 
00141   __libc_lock_lock (lock);
00142 
00143   internal_endgrent ();
00144 
00145   // XXX We need to be able to set errno.  Pass in new parameter.
00146   int err;
00147   status = internal_setgrent (&err);
00148 
00149   __libc_lock_unlock (lock);
00150 
00151   return status;
00152 }
00153 
00154 
00155 enum nss_status
00156 _nss_nisplus_endgrent (void)
00157 {
00158   __libc_lock_lock (lock);
00159 
00160   internal_endgrent ();
00161 
00162   __libc_lock_unlock (lock);
00163 
00164   return NSS_STATUS_SUCCESS;
00165 }
00166 
00167 
00168 static enum nss_status
00169 internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen,
00170                           int *errnop)
00171 {
00172   int parse_res = -1;
00173   enum nss_status retval = NSS_STATUS_SUCCESS;
00174 
00175   /* Get the next entry until we found a correct one. */
00176   do
00177     {
00178       nis_error status;
00179       nis_result result;
00180       memset (&result, '\0', sizeof (result));
00181 
00182       if (cursor.n_bytes == NULL)
00183        {
00184          if (ibreq == NULL)
00185            {
00186              retval = internal_setgrent (errnop);
00187              if (retval != NSS_STATUS_SUCCESS)
00188               return retval;
00189            }
00190 
00191          status = __do_niscall3 (&bptr, NIS_IBFIRST,
00192                               (xdrproc_t) _xdr_ib_request,
00193                               (caddr_t) ibreq,
00194                               (xdrproc_t) _xdr_nis_result,
00195                               (caddr_t) &result,
00196                               0, NULL);
00197        }
00198       else
00199        {
00200          ibreq->ibr_cookie.n_bytes = cursor.n_bytes;
00201          ibreq->ibr_cookie.n_len = cursor.n_len;
00202 
00203          status = __do_niscall3 (&bptr, NIS_IBNEXT,
00204                               (xdrproc_t) _xdr_ib_request,
00205                               (caddr_t) ibreq,
00206                               (xdrproc_t) _xdr_nis_result,
00207                               (caddr_t) &result,
00208                               0, NULL);
00209 
00210          ibreq->ibr_cookie.n_bytes = NULL;
00211          ibreq->ibr_cookie.n_len = 0;
00212        }
00213 
00214       if (status != NIS_SUCCESS)
00215        return niserr2nss (status);
00216 
00217       if (NIS_RES_STATUS (&result) == NIS_NOTFOUND)
00218        {
00219          /* No more entries on this server.  This means we have to go
00220             to the next server on the path.  */
00221          status = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
00222          if (status != NIS_SUCCESS)
00223            return niserr2nss (status);
00224 
00225          directory_obj *newdir = NULL;
00226          dir_binding newbptr;
00227          status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0);
00228          if (status != NIS_SUCCESS)
00229            return niserr2nss (status);
00230 
00231          nis_free_directory (dir);
00232          dir = newdir;
00233          __nisbind_destroy (&bptr);
00234          bptr = newbptr;
00235 
00236          xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie);
00237          result.cookie.n_bytes = NULL;
00238          result.cookie.n_len = 0;
00239          parse_res = 0;
00240          goto next;
00241        }
00242       else if (NIS_RES_STATUS (&result) != NIS_SUCCESS)
00243        return niserr2nss (NIS_RES_STATUS (&result));
00244 
00245       parse_res = _nss_nisplus_parse_grent (&result, gr,
00246                                        buffer, buflen, errnop);
00247       if (__builtin_expect (parse_res == -1, 0))
00248        {
00249          *errnop = ERANGE;
00250          retval = NSS_STATUS_TRYAGAIN;
00251          goto freeres;
00252        }
00253 
00254     next:
00255       /* Free the old cursor.  */
00256       xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
00257       /* Remember the new one.  */
00258       cursor.n_bytes = result.cookie.n_bytes;
00259       cursor.n_len = result.cookie.n_len;
00260       /* Free the result structure.  NB: we do not remove the cookie.  */
00261       result.cookie.n_bytes = NULL;
00262       result.cookie.n_len = 0;
00263     freeres:
00264       xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result);
00265       memset (&result, '\0', sizeof (result));
00266     }
00267   while (!parse_res);
00268 
00269   return retval;
00270 }
00271 
00272 enum nss_status
00273 _nss_nisplus_getgrent_r (struct group *result, char *buffer, size_t buflen,
00274                       int *errnop)
00275 {
00276   int status;
00277 
00278   __libc_lock_lock (lock);
00279 
00280   status = internal_nisplus_getgrent_r (result, buffer, buflen, errnop);
00281 
00282   __libc_lock_unlock (lock);
00283 
00284   return status;
00285 }
00286 
00287 enum nss_status
00288 _nss_nisplus_getgrnam_r (const char *name, struct group *gr,
00289                       char *buffer, size_t buflen, int *errnop)
00290 {
00291   int parse_res;
00292 
00293   if (grp_tablename_val == NULL)
00294     {
00295       enum nss_status status = _nss_grp_create_tablename (errnop);
00296 
00297       if (status != NSS_STATUS_SUCCESS)
00298        return status;
00299     }
00300 
00301   if (name == NULL)
00302     {
00303       *errnop = EINVAL;
00304       return NSS_STATUS_NOTFOUND;
00305     }
00306 
00307   nis_result *result;
00308   char buf[strlen (name) + 9 + grp_tablename_len];
00309   int olderr = errno;
00310 
00311   snprintf (buf, sizeof (buf), "[name=%s],%s", name, grp_tablename_val);
00312 
00313   result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
00314 
00315   if (result == NULL)
00316     {
00317       *errnop = ENOMEM;
00318       return NSS_STATUS_TRYAGAIN;
00319     }
00320 
00321   if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
00322     {
00323       enum nss_status status = niserr2nss (result->status);
00324 
00325       nis_freeresult (result);
00326       return status;
00327     }
00328 
00329   parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop);
00330   nis_freeresult (result);
00331   if (__builtin_expect (parse_res < 1, 0))
00332     {
00333       if (parse_res == -1)
00334        {
00335          *errnop = ERANGE;
00336          return NSS_STATUS_TRYAGAIN;
00337        }
00338       else
00339        {
00340          __set_errno (olderr);
00341          return NSS_STATUS_NOTFOUND;
00342        }
00343     }
00344 
00345   return NSS_STATUS_SUCCESS;
00346 }
00347 
00348 enum nss_status
00349 _nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr,
00350                       char *buffer, size_t buflen, int *errnop)
00351 {
00352   if (grp_tablename_val == NULL)
00353     {
00354       enum nss_status status = _nss_grp_create_tablename (errnop);
00355 
00356       if (status != NSS_STATUS_SUCCESS)
00357        return status;
00358     }
00359 
00360   int parse_res;
00361   nis_result *result;
00362   char buf[8 + 3 * sizeof (unsigned long int) + grp_tablename_len];
00363   int olderr = errno;
00364 
00365   snprintf (buf, sizeof (buf), "[gid=%lu],%s",
00366            (unsigned long int) gid, grp_tablename_val);
00367 
00368   result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
00369 
00370   if (result == NULL)
00371     {
00372       *errnop = ENOMEM;
00373       return NSS_STATUS_TRYAGAIN;
00374     }
00375 
00376   if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
00377     {
00378       enum nss_status status = niserr2nss (result->status);
00379 
00380       __set_errno (olderr);
00381 
00382       nis_freeresult (result);
00383       return status;
00384     }
00385 
00386   parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop);
00387 
00388   nis_freeresult (result);
00389   if (__builtin_expect (parse_res < 1, 0))
00390     {
00391       __set_errno (olderr);
00392 
00393       if (parse_res == -1)
00394        {
00395          *errnop = ERANGE;
00396          return NSS_STATUS_TRYAGAIN;
00397        }
00398       else
00399        return NSS_STATUS_NOTFOUND;
00400     }
00401 
00402   return NSS_STATUS_SUCCESS;
00403 }