Back to index

glibc  2.9
files-XXX.c
Go to the documentation of this file.
00001 /* Common code for file-based databases in nss_files module.
00002    Copyright (C) 1996-1999,2001,2002,2004,2007,2008
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
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 <stdio.h>
00022 #include <ctype.h>
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <bits/libc-lock.h>
00026 #include "nsswitch.h"
00027 
00028 #include <kernel-features.h>
00029 
00030 /* These symbols are defined by the including source file:
00031 
00032    ENTNAME -- database name of the structure and functions (hostent, pwent).
00033    STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
00034    DATABASE -- string of the database file's name ("hosts", "passwd").
00035 
00036    NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
00037 
00038    Also see files-parse.c.
00039 */
00040 
00041 #define ENTNAME_r    CONCAT(ENTNAME,_r)
00042 
00043 #define DATAFILE     "/etc/" DATABASE
00044 
00045 #ifdef NEED_H_ERRNO
00046 # include <netdb.h>
00047 # define H_ERRNO_PROTO      , int *herrnop
00048 # define H_ERRNO_ARG , herrnop
00049 # define H_ERRNO_SET(val) (*herrnop = (val))
00050 #else
00051 # define H_ERRNO_PROTO
00052 # define H_ERRNO_ARG
00053 # define H_ERRNO_SET(val) ((void) 0)
00054 #endif
00055 
00056 #ifndef EXTRA_ARGS
00057 # define EXTRA_ARGS
00058 # define EXTRA_ARGS_DECL
00059 # define EXTRA_ARGS_VALUE
00060 #endif
00061 
00062 /* Locks the static variables in this file.  */
00063 __libc_lock_define_initialized (static, lock)
00064 
00065 /* Maintenance of the shared stream open on the database file.  */
00066 
00067 static FILE *stream;
00068 static fpos_t position;
00069 static enum { nouse, getent, getby } last_use;
00070 static int keep_stream;
00071 
00072 /* Open database file if not already opened.  */
00073 static enum nss_status
00074 internal_setent (int stayopen)
00075 {
00076   enum nss_status status = NSS_STATUS_SUCCESS;
00077 
00078   if (stream == NULL)
00079     {
00080       stream = fopen (DATAFILE, "re");
00081 
00082       if (stream == NULL)
00083        status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
00084       else
00085        {
00086 #if !defined O_CLOEXEC || !defined __ASSUME_O_CLOEXEC
00087 # ifdef O_CLOEXEC
00088          if (__have_o_cloexec <= 0)
00089 # endif
00090            {
00091              /* We have to make sure the file is  `closed on exec'.  */
00092              int result;
00093              int flags;
00094 
00095              result = flags = fcntl (fileno (stream), F_GETFD, 0);
00096              if (result >= 0)
00097               {
00098 # ifdef O_CLOEXEC
00099                 if (__have_o_cloexec == 0)
00100                   __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
00101                 if (__have_o_cloexec < 0)
00102 # endif
00103                   {
00104                     flags |= FD_CLOEXEC;
00105                     result = fcntl (fileno (stream), F_SETFD, flags);
00106                   }
00107               }
00108              if (result < 0)
00109               {
00110                 /* Something went wrong.  Close the stream and return a
00111                    failure.  */
00112                 fclose (stream);
00113                 stream = NULL;
00114                 status = NSS_STATUS_UNAVAIL;
00115               }
00116            }
00117 #endif
00118        }
00119     }
00120   else
00121     rewind (stream);
00122 
00123   /* Remember STAYOPEN flag.  */
00124   if (stream != NULL)
00125     keep_stream |= stayopen;
00126 
00127   return status;
00128 }
00129 
00130 
00131 /* Thread-safe, exported version of that.  */
00132 enum nss_status
00133 CONCAT(_nss_files_set,ENTNAME) (int stayopen)
00134 {
00135   enum nss_status status;
00136 
00137   __libc_lock_lock (lock);
00138 
00139   status = internal_setent (stayopen);
00140 
00141   if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
00142     {
00143       fclose (stream);
00144       stream = NULL;
00145       status = NSS_STATUS_UNAVAIL;
00146     }
00147 
00148   last_use = getent;
00149 
00150   __libc_lock_unlock (lock);
00151 
00152   return status;
00153 }
00154 
00155 
00156 /* Close the database file.  */
00157 static void
00158 internal_endent (void)
00159 {
00160   if (stream != NULL)
00161     {
00162       fclose (stream);
00163       stream = NULL;
00164     }
00165 }
00166 
00167 
00168 /* Thread-safe, exported version of that.  */
00169 enum nss_status
00170 CONCAT(_nss_files_end,ENTNAME) (void)
00171 {
00172   __libc_lock_lock (lock);
00173 
00174   internal_endent ();
00175 
00176   /* Reset STAYOPEN flag.  */
00177   keep_stream = 0;
00178 
00179   __libc_lock_unlock (lock);
00180 
00181   return NSS_STATUS_SUCCESS;
00182 }
00183 
00184 /* Parsing the database file into `struct STRUCTURE' data structures.  */
00185 
00186 static enum nss_status
00187 internal_getent (struct STRUCTURE *result,
00188                char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
00189                EXTRA_ARGS_DECL)
00190 {
00191   char *p;
00192   struct parser_data *data = (void *) buffer;
00193   int linebuflen = buffer + buflen - data->linebuffer;
00194   int parse_result;
00195 
00196   if (buflen < sizeof *data + 2)
00197     {
00198       *errnop = ERANGE;
00199       H_ERRNO_SET (NETDB_INTERNAL);
00200       return NSS_STATUS_TRYAGAIN;
00201     }
00202 
00203   do
00204     {
00205       /* Terminate the line so that we can test for overflow.  */
00206       ((unsigned char *) data->linebuffer)[linebuflen - 1] = '\xff';
00207 
00208       p = fgets_unlocked (data->linebuffer, linebuflen, stream);
00209       if (p == NULL)
00210        {
00211          /* End of file or read error.  */
00212          H_ERRNO_SET (HOST_NOT_FOUND);
00213          return NSS_STATUS_NOTFOUND;
00214        }
00215       else if (((unsigned char *) data->linebuffer)[linebuflen - 1] != 0xff)
00216        {
00217          /* The line is too long.  Give the user the opportunity to
00218             enlarge the buffer.  */
00219          *errnop = ERANGE;
00220          H_ERRNO_SET (NETDB_INTERNAL);
00221          return NSS_STATUS_TRYAGAIN;
00222        }
00223 
00224       /* Skip leading blanks.  */
00225       while (isspace (*p))
00226        ++p;
00227     }
00228   while (*p == '\0' || *p == '#' /* Ignore empty and comment lines.  */
00229         /* Parse the line.  If it is invalid, loop to get the next
00230            line of the file to parse.  */
00231         || ! (parse_result = parse_line (p, result, data, buflen, errnop
00232                                      EXTRA_ARGS)));
00233 
00234   if (__builtin_expect (parse_result == -1, 0))
00235     {
00236       H_ERRNO_SET (NETDB_INTERNAL);
00237       return NSS_STATUS_TRYAGAIN;
00238     }
00239 
00240   /* Filled in RESULT with the next entry from the database file.  */
00241   return NSS_STATUS_SUCCESS;
00242 }
00243 
00244 
00245 /* Return the next entry from the database file, doing locking.  */
00246 enum nss_status
00247 CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
00248                               size_t buflen, int *errnop H_ERRNO_PROTO)
00249 {
00250   /* Return next entry in host file.  */
00251   enum nss_status status = NSS_STATUS_SUCCESS;
00252 
00253   __libc_lock_lock (lock);
00254 
00255   /* Be prepared that the set*ent function was not called before.  */
00256   if (stream == NULL)
00257     {
00258       int save_errno = errno;
00259 
00260       status = internal_setent (0);
00261 
00262       __set_errno (save_errno);
00263 
00264       if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
00265        {
00266          fclose (stream);
00267          stream = NULL;
00268          status = NSS_STATUS_UNAVAIL;
00269        }
00270     }
00271 
00272   if (status == NSS_STATUS_SUCCESS)
00273     {
00274       /* If the last use was not by the getent function we need the
00275         position the stream.  */
00276       if (last_use != getent)
00277        {
00278          if (fsetpos (stream, &position) < 0)
00279            status = NSS_STATUS_UNAVAIL;
00280          else
00281            last_use = getent;
00282        }
00283 
00284       if (status == NSS_STATUS_SUCCESS)
00285        {
00286          status = internal_getent (result, buffer, buflen, errnop
00287                                 H_ERRNO_ARG EXTRA_ARGS_VALUE);
00288 
00289          /* Remember this position if we were successful.  If the
00290             operation failed we give the user a chance to repeat the
00291             operation (perhaps the buffer was too small).  */
00292          if (status == NSS_STATUS_SUCCESS)
00293            fgetpos (stream, &position);
00294          else
00295            /* We must make sure we reposition the stream the next call.  */
00296            last_use = nouse;
00297        }
00298     }
00299 
00300   __libc_lock_unlock (lock);
00301 
00302   return status;
00303 }
00304 
00305 /* Macro for defining lookup functions for this file-based database.
00306 
00307    NAME is the name of the lookup; e.g. `hostbyname'.
00308 
00309    KEYSIZE and KEYPATTERN are ignored here but used by ../nss_db/db-XXX.c.
00310 
00311    PROTO describes the arguments for the lookup key;
00312    e.g. `const char *hostname'.
00313 
00314    BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
00315    to the lookup key arguments and does `break;' if they match.  */
00316 
00317 #define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)             \
00318 enum nss_status                                                             \
00319 _nss_files_get##name##_r (proto,                                     \
00320                        struct STRUCTURE *result, char *buffer,       \
00321                        size_t buflen, int *errnop H_ERRNO_PROTO)            \
00322 {                                                                    \
00323   enum nss_status status;                                            \
00324                                                                      \
00325   __libc_lock_lock (lock);                                           \
00326                                                                      \
00327   /* Reset file pointer to beginning or open file.  */                      \
00328   status = internal_setent (keep_stream);                            \
00329                                                                      \
00330   if (status == NSS_STATUS_SUCCESS)                                         \
00331     {                                                                \
00332       /* Tell getent function that we have repositioned the file pointer.  */ \
00333       last_use = getby;                                                     \
00334                                                                      \
00335       while ((status = internal_getent (result, buffer, buflen, errnop             \
00336                                    H_ERRNO_ARG EXTRA_ARGS_VALUE))           \
00337             == NSS_STATUS_SUCCESS)                                   \
00338        { break_if_match }                                            \
00339                                                                      \
00340       if (! keep_stream)                                             \
00341        internal_endent ();                                           \
00342     }                                                                \
00343                                                                      \
00344   __libc_lock_unlock (lock);                                                \
00345                                                                      \
00346   return status;                                                     \
00347 }