Back to index

glibc  2.9
nisplus-pwd.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997, 1999, 2001, 2002, 2003, 2005, 2006, 2007
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 <errno.h>
00024 #include <pwd.h>
00025 #include <string.h>
00026 #include <bits/libc-lock.h>
00027 #include <rpcsvc/nis.h>
00028 
00029 #include "nss-nisplus.h"
00030 #include "nisplus-parser.h"
00031 #include <libnsl.h>
00032 #include <nis_intern.h>
00033 #include <nis_xdr.h>
00034 
00035 
00036 __libc_lock_define_initialized (static, lock)
00037 
00038 /* Connection information.  */
00039 static ib_request *ibreq;
00040 static directory_obj *dir;
00041 static dir_binding bptr;
00042 static char *tablepath;
00043 static char *tableptr;
00044 /* Cursor.  */
00045 static netobj cursor;
00046 
00047 
00048 nis_name pwd_tablename_val attribute_hidden;
00049 size_t pwd_tablename_len attribute_hidden;
00050 
00051 enum nss_status
00052 _nss_pwd_create_tablename (int *errnop)
00053 {
00054   if (pwd_tablename_val == NULL)
00055     {
00056       const char *local_dir = nis_local_directory ();
00057       size_t local_dir_len = strlen (local_dir);
00058       static const char prefix[] = "passwd.org_dir.";
00059 
00060       char *p = malloc (sizeof (prefix) + local_dir_len);
00061       if (p == NULL)
00062        {
00063          *errnop = errno;
00064          return NSS_STATUS_TRYAGAIN;
00065        }
00066 
00067       memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
00068 
00069       pwd_tablename_len = sizeof (prefix) - 1 + local_dir_len;
00070 
00071       atomic_write_barrier ();
00072 
00073       if (atomic_compare_and_exchange_bool_acq (&pwd_tablename_val, p, NULL))
00074        {
00075          /* Another thread already installed the value.  */
00076          free (p);
00077          pwd_tablename_len = strlen (pwd_tablename_val);
00078        }
00079     }
00080 
00081   return NSS_STATUS_SUCCESS;
00082 }
00083 
00084 
00085 static void
00086 internal_nisplus_endpwent (void)
00087 {
00088   __nisbind_destroy (&bptr);
00089   memset (&bptr, '\0', sizeof (bptr));
00090 
00091   nis_free_directory (dir);
00092   dir = NULL;
00093 
00094   nis_free_request (ibreq);
00095   ibreq = NULL;
00096 
00097   xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
00098   memset (&cursor, '\0', sizeof (cursor));
00099 
00100   free (tablepath);
00101   tableptr = tablepath = NULL;
00102 }
00103 
00104 
00105 static enum nss_status
00106 internal_nisplus_setpwent (int *errnop)
00107 {
00108   enum nss_status status = NSS_STATUS_SUCCESS;
00109 
00110   if (pwd_tablename_val == NULL)
00111     status = _nss_pwd_create_tablename (errnop);
00112 
00113   if (status == NSS_STATUS_SUCCESS)
00114     {
00115       ibreq = __create_ib_request (pwd_tablename_val, 0);
00116       if (ibreq == NULL)
00117        {
00118          *errnop = errno;
00119          return NSS_STATUS_TRYAGAIN;
00120        }
00121 
00122       nis_error retcode = __prepare_niscall (pwd_tablename_val, &dir,
00123                                         &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_setpwent (int stayopen)
00138 {
00139   enum nss_status status;
00140 
00141   __libc_lock_lock (lock);
00142 
00143   internal_nisplus_endpwent ();
00144 
00145   // XXX We need to be able to set errno.  Pass in new parameter.
00146   int err;
00147   status = internal_nisplus_setpwent (&err);
00148 
00149   __libc_lock_unlock (lock);
00150 
00151   return status;
00152 }
00153 
00154 
00155 enum nss_status
00156 _nss_nisplus_endpwent (void)
00157 {
00158   __libc_lock_lock (lock);
00159 
00160   internal_nisplus_endpwent ();
00161 
00162   __libc_lock_unlock (lock);
00163 
00164   return NSS_STATUS_SUCCESS;
00165 }
00166 
00167 
00168 static enum nss_status
00169 internal_nisplus_getpwent_r (struct passwd *pw, 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_nisplus_setpwent (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_pwent (&result, pw, buffer,
00246                                        buflen, errnop);
00247 
00248       if (__builtin_expect (parse_res == -1, 0))
00249        {
00250          *errnop = ERANGE;
00251          retval = NSS_STATUS_TRYAGAIN;
00252          goto freeres;
00253        }
00254 
00255     next:
00256       /* Free the old cursor.  */
00257       xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
00258       /* Remember the new one.  */
00259       cursor.n_bytes = result.cookie.n_bytes;
00260       cursor.n_len = result.cookie.n_len;
00261       /* Free the result structure.  NB: we do not remove the cookie.  */
00262       result.cookie.n_bytes = NULL;
00263       result.cookie.n_len = 0;
00264     freeres:
00265       xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result);
00266       memset (&result, '\0', sizeof (result));
00267     }
00268   while (!parse_res);
00269 
00270   return retval;
00271 }
00272 
00273 enum nss_status
00274 _nss_nisplus_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
00275                       int *errnop)
00276 {
00277   int status;
00278 
00279   __libc_lock_lock (lock);
00280 
00281   status = internal_nisplus_getpwent_r (result, buffer, buflen, errnop);
00282 
00283   __libc_lock_unlock (lock);
00284 
00285   return status;
00286 }
00287 
00288 enum nss_status
00289 _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw,
00290                       char *buffer, size_t buflen, int *errnop)
00291 {
00292   int parse_res;
00293 
00294   if (pwd_tablename_val == NULL)
00295     {
00296       enum nss_status status = _nss_pwd_create_tablename (errnop);
00297 
00298       if (status != NSS_STATUS_SUCCESS)
00299        return status;
00300     }
00301 
00302   if (name == NULL)
00303     {
00304       *errnop = EINVAL;
00305       return NSS_STATUS_UNAVAIL;
00306     }
00307 
00308   nis_result *result;
00309   char buf[strlen (name) + 9 + pwd_tablename_len];
00310   int olderr = errno;
00311 
00312   snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val);
00313 
00314   result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
00315 
00316   if (result == NULL)
00317     {
00318       *errnop = ENOMEM;
00319       return NSS_STATUS_TRYAGAIN;
00320     }
00321 
00322   if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
00323     {
00324       enum nss_status status =  niserr2nss (result->status);
00325 
00326       __set_errno (olderr);
00327 
00328       nis_freeresult (result);
00329       return status;
00330     }
00331 
00332   parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
00333 
00334   nis_freeresult (result);
00335 
00336   if (__builtin_expect (parse_res < 1, 0))
00337     {
00338       if (parse_res == -1)
00339        {
00340          *errnop = ERANGE;
00341          return NSS_STATUS_TRYAGAIN;
00342        }
00343       else
00344        {
00345          __set_errno (olderr);
00346          return NSS_STATUS_NOTFOUND;
00347        }
00348     }
00349 
00350   return NSS_STATUS_SUCCESS;
00351 }
00352 
00353 enum nss_status
00354 _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw,
00355                       char *buffer, size_t buflen, int *errnop)
00356 {
00357   if (pwd_tablename_val == NULL)
00358     {
00359       enum nss_status status = _nss_pwd_create_tablename (errnop);
00360 
00361       if (status != NSS_STATUS_SUCCESS)
00362        return status;
00363     }
00364 
00365   int parse_res;
00366   nis_result *result;
00367   char buf[8 + 3 * sizeof (unsigned long int) + pwd_tablename_len];
00368   int olderr = errno;
00369 
00370   snprintf (buf, sizeof (buf), "[uid=%lu],%s",
00371            (unsigned long int) uid, pwd_tablename_val);
00372 
00373   result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
00374 
00375   if (result == NULL)
00376     {
00377       *errnop = ENOMEM;
00378       return NSS_STATUS_TRYAGAIN;
00379     }
00380 
00381   if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
00382     {
00383       enum nss_status status = niserr2nss (result->status);
00384 
00385       __set_errno (olderr);
00386 
00387       nis_freeresult (result);
00388       return status;
00389     }
00390 
00391   parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
00392 
00393   nis_freeresult (result);
00394 
00395   if (__builtin_expect (parse_res < 1, 0))
00396     {
00397       if (parse_res == -1)
00398        {
00399          *errnop = ERANGE;
00400          return NSS_STATUS_TRYAGAIN;
00401        }
00402       else
00403        {
00404          __set_errno (olderr);
00405          return NSS_STATUS_NOTFOUND;
00406        }
00407     }
00408 
00409   return NSS_STATUS_SUCCESS;
00410 }