(linenum→info "unix/slp.c:2238")

glibc/2.7/nscd/nscd_getpw_r.c

    1: /* Copyright (C) 1998, 1999, 2003, 2004, 2005, 2007
    2:    Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
    5: 
    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.
   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
   14:    Lesser General Public License for more details.
   15: 
   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.  */
   20: 
   21: #include <assert.h>
   22: #include <errno.h>
   23: #include <pwd.h>
   24: #include <stdint.h>
   25: #include <stdio.h>
   26: #include <stdlib.h>
   27: #include <string.h>
   28: #include <unistd.h>
   29: #include <sys/mman.h>
   30: #include <sys/socket.h>
   31: #include <sys/uio.h>
   32: #include <sys/un.h>
   33: #include <not-cancel.h>
   34: #include <stdio-common/_itoa.h>
   35: 
   36: #include "nscd-client.h"
   37: #include "nscd_proto.h"
   38: 
   39: int __nss_not_use_nscd_passwd;
   40: 
   41: static int nscd_getpw_r (const char *key, size_t keylen, request_type type,
   42:                          struct passwd *resultbuf, char *buffer,
   43:                          size_t buflen, struct passwd **result)
   44:      internal_function;
   45: 
   46: int
   47: __nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer,
   48:                    size_t buflen, struct passwd **result)
   49: {
   50:   if (name == NULL)
   51:     return -1;
   52: 
   53:   return nscd_getpw_r (name, strlen (name) + 1, GETPWBYNAME, resultbuf,
   54:                        buffer, buflen, result);
   55: }
   56: 
   57: int
   58: __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
   59:                    size_t buflen, struct passwd **result)
   60: {
   61:   char buf[3 * sizeof (uid_t)];
   62:   buf[sizeof (buf) - 1] = '\0';
   63:   char *cp = _itoa_word (uid, buf + sizeof (buf) - 1, 10, 0);
   64: 
   65:   return nscd_getpw_r (cp, buf + sizeof (buf) - cp, GETPWBYUID, resultbuf,
   66:                        buffer, buflen, result);
   67: }
   68: 
   69: 
   70: libc_locked_map_ptr (static, map_handle);
   71: /* Note that we only free the structure if necessary.  The memory
   72:    mapping is not removed since it is not visible to the malloc
   73:    handling.  */
   74: libc_freeres_fn (pw_map_free)
   75: {
   76:   if (map_handle.mapped != NO_MAPPING)
   77:     {
   78:       void *p = map_handle.mapped;
   79:       map_handle.mapped = NO_MAPPING;
   80:       free (p);
   81:     }
   82: }
   83: 
   84: 
   85: static int
   86: internal_function
   87: nscd_getpw_r (const char *key, size_t keylen, request_type type,
   88:               struct passwd *resultbuf, char *buffer, size_t buflen,
   89:               struct passwd **result)
   90: {
   91:   int gc_cycle;
   92:   int nretries = 0;
   93: 
   94:   /* If the mapping is available, try to search there instead of
   95:      communicating with the nscd.  */
   96:   struct mapped_database *mapped;
   97:   mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
   98: 
   99:  retry:;
  100:   const char *pw_name = NULL;
  101:   int retval = -1;
  102:   const char *recend = (const char *) ~UINTMAX_C (0);
  103:   pw_response_header pw_resp;
  104: 
  105:   if (mapped != NO_MAPPING)
  106:     {
  107:       struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
  108:       if (found != NULL)
  109:         {
  110:           pw_name = (const char *) (&found->data[0].pwdata + 1);
  111:           pw_resp = found->data[0].pwdata;
  112:           recend = (const char *) found->data + found->recsize;
  113:           /* Now check if we can trust pw_resp fields.  If GC is
  114:              in progress, it can contain anything.  */
  115:           if (mapped->head->gc_cycle != gc_cycle)
  116:             {
  117:               retval = -2;
  118:               goto out;
  119:             }
  120:         }
  121:     }
  122: 
  123:   int sock = -1;
  124:   if (pw_name == NULL)
  125:     {
  126:       sock = __nscd_open_socket (key, keylen, type, &pw_resp,
  127:                                  sizeof (pw_resp));
  128:       if (sock == -1)
  129:         {
  130:           __nss_not_use_nscd_passwd = 1;
  131:           goto out;
  132:         }
  133:     }
  134: 
  135:   /* No value found so far.  */
  136:   *result = NULL;
  137: 
  138:   if (__builtin_expect (pw_resp.found == -1, 0))
  139:     {
  140:       /* The daemon does not cache this database.  */
  141:       __nss_not_use_nscd_passwd = 1;
  142:       goto out_close;
  143:     }
  144: 
  145:   if (pw_resp.found == 1)
  146:     {
  147:       /* Set the information we already have.  */
  148:       resultbuf->pw_uid = pw_resp.pw_uid;
  149:       resultbuf->pw_gid = pw_resp.pw_gid;
  150: 
  151:       char *p = buffer;
  152:       /* get pw_name */
  153:       resultbuf->pw_name = p;
  154:       p += pw_resp.pw_name_len;
  155:       /* get pw_passwd */
  156:       resultbuf->pw_passwd = p;
  157:       p += pw_resp.pw_passwd_len;
  158:       /* get pw_gecos */
  159:       resultbuf->pw_gecos = p;
  160:       p += pw_resp.pw_gecos_len;
  161:       /* get pw_dir */
  162:       resultbuf->pw_dir = p;
  163:       p += pw_resp.pw_dir_len;
  164:       /* get pw_pshell */
  165:       resultbuf->pw_shell = p;
  166:       p += pw_resp.pw_shell_len;
  167: 
  168:       ssize_t total = p - buffer;
  169:       if (__builtin_expect (pw_name + total > recend, 0))
  170:         goto out_close;
  171:       if (__builtin_expect (buflen < total, 0))
  172:         {
  173:           __set_errno (ERANGE);
  174:           retval = ERANGE;
  175:           goto out_close;
  176:         }
  177: 
  178:       retval = 0;
  179:       if (pw_name == NULL)
  180:         {
  181:           ssize_t nbytes = __readall (sock, buffer, total);
  182: 
  183:           if (__builtin_expect (nbytes != total, 0))
  184:             {
  185:               /* The `errno' to some value != ERANGE.  */
  186:               __set_errno (ENOENT);
  187:               retval = ENOENT;
  188:             }
  189:           else
  190:             *result = resultbuf;
  191:         }
  192:       else
  193:         {
  194:           /* Copy the various strings.  */
  195:           memcpy (resultbuf->pw_name, pw_name, total);
  196: 
  197:           /* Try to detect corrupt databases.  */
  198:           if (resultbuf->pw_name[pw_resp.pw_name_len - 1] != '\0'
  199:               || resultbuf->pw_passwd[pw_resp.pw_passwd_len - 1] != '\0'
  200:               || resultbuf->pw_gecos[pw_resp.pw_gecos_len - 1] != '\0'
  201:               || resultbuf->pw_dir[pw_resp.pw_dir_len - 1] != '\0'
  202:               || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0')
  203:             {
  204:               /* We cannot use the database.  */
  205:               retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
  206:               goto out_close;
  207:             }
  208: 
  209:           *result = resultbuf;
  210:         }
  211:     }
  212:   else
  213:     {
  214:       /* Set errno to 0 to indicate no error, just no found record.  */
  215:       __set_errno (0);
  216:       /* Even though we have not found anything, the result is zero.  */
  217:       retval = 0;
  218:     }
  219: 
  220:  out_close:
  221:   if (sock != -1)
  222:     close_not_cancel_no_status (sock);
  223:  out:
  224:   if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
  225:     {
  226:       /* When we come here this means there has been a GC cycle while we
  227:          were looking for the data.  This means the data might have been
  228:          inconsistent.  Retry if possible.  */
  229:       if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
  230:         {
  231:           /* nscd is just running gc now.  Disable using the mapping.  */
  232:           if (atomic_decrement_val (&mapped->counter) == 0)
  233:             __nscd_unmap (mapped);
  234:           mapped = NO_MAPPING;
  235:         }
  236: 
  237:       if (retval != -1)
  238:         goto retry;
  239:     }
  240: 
  241:   return retval;
  242: }
Syntax (Markdown)