root/maint/gnulib/lib/idcache.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. getuser
  2. getuidbyname
  3. getgroup
  4. getgidbyname

   1 /* idcache.c -- map user and group IDs, cached for speed
   2 
   3    Copyright (C) 1985, 1988-1990, 1997-1998, 2003, 2005-2007, 2009-2021 Free
   4    Software Foundation, Inc.
   5 
   6    This program is free software: you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10 
  11    This program 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
  14    GNU General Public License for more details.
  15 
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  18 
  19 #include <config.h>
  20 
  21 #include "idcache.h"
  22 #include <stddef.h>
  23 #include <stdio.h>
  24 #include <string.h>
  25 #include <pwd.h>
  26 #include <grp.h>
  27 
  28 #include <unistd.h>
  29 
  30 #include "flexmember.h"
  31 #include "xalloc.h"
  32 
  33 #ifdef __DJGPP__
  34 static char digits[] = "0123456789";
  35 #endif
  36 
  37 struct userid
  38 {
  39   union
  40     {
  41       uid_t u;
  42       gid_t g;
  43     } id;
  44   struct userid *next;
  45   char name[FLEXIBLE_ARRAY_MEMBER];
  46 };
  47 
  48 /* FIXME: provide a function to free any malloc'd storage and reset lists,
  49    so that an application can use code like this just before exiting:
  50    #if defined GCC_LINT || defined lint
  51      idcache_clear ();
  52    #endif
  53 */
  54 
  55 static struct userid *user_alist;
  56 
  57 /* Each entry on list is a user name for which the first lookup failed.  */
  58 static struct userid *nouser_alist;
  59 
  60 /* Use the same struct as for userids.  */
  61 static struct userid *group_alist;
  62 
  63 /* Each entry on list is a group name for which the first lookup failed.  */
  64 static struct userid *nogroup_alist;
  65 
  66 /* Translate UID to a login name, with cache, or NULL if unresolved.  */
  67 
  68 char *
  69 getuser (uid_t uid)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71   struct userid *tail;
  72   struct userid *match = NULL;
  73 
  74   for (tail = user_alist; tail; tail = tail->next)
  75     {
  76       if (tail->id.u == uid)
  77         {
  78           match = tail;
  79           break;
  80         }
  81     }
  82 
  83   if (match == NULL)
  84     {
  85       struct passwd *pwent = getpwuid (uid);
  86       char const *name = pwent ? pwent->pw_name : "";
  87       match = xmalloc (FLEXSIZEOF (struct userid, name, strlen (name) + 1));
  88       match->id.u = uid;
  89       strcpy (match->name, name);
  90 
  91       /* Add to the head of the list, so most recently used is first.  */
  92       match->next = user_alist;
  93       user_alist = match;
  94     }
  95 
  96   return match->name[0] ? match->name : NULL;
  97 }
  98 
  99 /* Translate USER to a UID, with cache.
 100    Return NULL if there is no such user.
 101    (We also cache which user names have no passwd entry,
 102    so we don't keep looking them up.)  */
 103 
 104 uid_t *
 105 getuidbyname (const char *user)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107   struct userid *tail;
 108   struct passwd *pwent;
 109 
 110   for (tail = user_alist; tail; tail = tail->next)
 111     /* Avoid a function call for the most common case.  */
 112     if (*tail->name == *user && !strcmp (tail->name, user))
 113       return &tail->id.u;
 114 
 115   for (tail = nouser_alist; tail; tail = tail->next)
 116     /* Avoid a function call for the most common case.  */
 117     if (*tail->name == *user && !strcmp (tail->name, user))
 118       return NULL;
 119 
 120   pwent = getpwnam (user);
 121 #ifdef __DJGPP__
 122   /* We need to pretend to be the user USER, to make
 123      pwd functions know about an arbitrary user name.  */
 124   if (!pwent && strspn (user, digits) < strlen (user))
 125     {
 126       setenv ("USER", user, 1);
 127       pwent = getpwnam (user);  /* now it will succeed */
 128     }
 129 #endif
 130 
 131   tail = xmalloc (FLEXSIZEOF (struct userid, name, strlen (user) + 1));
 132   strcpy (tail->name, user);
 133 
 134   /* Add to the head of the list, so most recently used is first.  */
 135   if (pwent)
 136     {
 137       tail->id.u = pwent->pw_uid;
 138       tail->next = user_alist;
 139       user_alist = tail;
 140       return &tail->id.u;
 141     }
 142 
 143   tail->next = nouser_alist;
 144   nouser_alist = tail;
 145   return NULL;
 146 }
 147 
 148 /* Translate GID to a group name, with cache, or NULL if unresolved.  */
 149 
 150 char *
 151 getgroup (gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153   struct userid *tail;
 154   struct userid *match = NULL;
 155 
 156   for (tail = group_alist; tail; tail = tail->next)
 157     {
 158       if (tail->id.g == gid)
 159         {
 160           match = tail;
 161           break;
 162         }
 163     }
 164 
 165   if (match == NULL)
 166     {
 167       struct group *grent = getgrgid (gid);
 168       char const *name = grent ? grent->gr_name : "";
 169       match = xmalloc (FLEXSIZEOF (struct userid, name, strlen (name) + 1));
 170       match->id.g = gid;
 171       strcpy (match->name, name);
 172 
 173       /* Add to the head of the list, so most recently used is first.  */
 174       match->next = group_alist;
 175       group_alist = match;
 176     }
 177 
 178   return match->name[0] ? match->name : NULL;
 179 }
 180 
 181 /* Translate GROUP to a GID, with cache.
 182    Return NULL if there is no such group.
 183    (We also cache which group names have no group entry,
 184    so we don't keep looking them up.)  */
 185 
 186 gid_t *
 187 getgidbyname (const char *group)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189   struct userid *tail;
 190   struct group *grent;
 191 
 192   for (tail = group_alist; tail; tail = tail->next)
 193     /* Avoid a function call for the most common case.  */
 194     if (*tail->name == *group && !strcmp (tail->name, group))
 195       return &tail->id.g;
 196 
 197   for (tail = nogroup_alist; tail; tail = tail->next)
 198     /* Avoid a function call for the most common case.  */
 199     if (*tail->name == *group && !strcmp (tail->name, group))
 200       return NULL;
 201 
 202   grent = getgrnam (group);
 203 #ifdef __DJGPP__
 204   /* We need to pretend to belong to group GROUP, to make
 205      grp functions know about an arbitrary group name.  */
 206   if (!grent && strspn (group, digits) < strlen (group))
 207     {
 208       setenv ("GROUP", group, 1);
 209       grent = getgrnam (group); /* now it will succeed */
 210     }
 211 #endif
 212 
 213   tail = xmalloc (FLEXSIZEOF (struct userid, name, strlen (group) + 1));
 214   strcpy (tail->name, group);
 215 
 216   /* Add to the head of the list, so most recently used is first.  */
 217   if (grent)
 218     {
 219       tail->id.g = grent->gr_gid;
 220       tail->next = group_alist;
 221       group_alist = tail;
 222       return &tail->id.g;
 223     }
 224 
 225   tail->next = nogroup_alist;
 226   nogroup_alist = tail;
 227   return NULL;
 228 }

/* [previous][next][first][last][top][bottom][index][help] */