1 /* idcache.c -- map user and group IDs, cached for speed
2 Copyright (C) 1985, 1988-1990, 2004, 2007, 2010, 2014-2015, 2017 Free
3 Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public
16 License along with this program; if not, write to the Free
17 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA. */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <xalloc.h>
27
28 #include <system.h>
29
30 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
31 #include <string.h>
32 #else
33 #include <strings.h>
34 #endif
35
36 #include <unistd.h>
37
38 struct userid
39 {
40 union
41 {
42 uid_t u;
43 gid_t g;
44 } id;
45 char *name;
46 struct userid *next;
47 };
48
49 static struct userid *user_alist;
50
51 /* The members of this list have names not in the local passwd file. */
52 static struct userid *nouser_alist;
53
54 /* Translate UID to a login name or a stringified number,
55 with cache. */
56
57 char *
getuser(uid_t uid)58 getuser (uid_t uid)
59 {
60 register struct userid *tail;
61 struct passwd *pwent;
62 char usernum_string[20];
63
64 for (tail = user_alist; tail; tail = tail->next)
65 if (tail->id.u == uid)
66 return tail->name;
67
68 pwent = getpwuid (uid);
69 tail = (struct userid *) xmalloc (sizeof (struct userid));
70 tail->id.u = uid;
71 if (pwent == 0)
72 {
73 sprintf (usernum_string, "%u", (unsigned) uid);
74 tail->name = xstrdup (usernum_string);
75 }
76 else
77 tail->name = xstrdup (pwent->pw_name);
78
79 /* Add to the head of the list, so most recently used is first. */
80 tail->next = user_alist;
81 user_alist = tail;
82 return tail->name;
83 }
84
85 /* Translate USER to a UID, with cache.
86 Return NULL if there is no such user.
87 (We also cache which user names have no passwd entry,
88 so we don't keep looking them up.) */
89
90 uid_t *
getuidbyname(char * user)91 getuidbyname (char *user)
92 {
93 register struct userid *tail;
94 struct passwd *pwent;
95
96 for (tail = user_alist; tail; tail = tail->next)
97 /* Avoid a function call for the most common case. */
98 if (*tail->name == *user && !strcmp (tail->name, user))
99 return &tail->id.u;
100
101 for (tail = nouser_alist; tail; tail = tail->next)
102 /* Avoid a function call for the most common case. */
103 if (*tail->name == *user && !strcmp (tail->name, user))
104 return 0;
105
106 pwent = getpwnam (user);
107
108 tail = (struct userid *) xmalloc (sizeof (struct userid));
109 tail->name = xstrdup (user);
110
111 /* Add to the head of the list, so most recently used is first. */
112 if (pwent)
113 {
114 tail->id.u = pwent->pw_uid;
115 tail->next = user_alist;
116 user_alist = tail;
117 return &tail->id.u;
118 }
119
120 tail->next = nouser_alist;
121 nouser_alist = tail;
122 return 0;
123 }
124
125 /* Use the same struct as for userids. */
126 static struct userid *group_alist;
127 static struct userid *nogroup_alist;
128
129 /* Translate GID to a group name or a stringified number,
130 with cache. */
131
132 char *
getgroup(gid_t gid)133 getgroup (gid_t gid)
134 {
135 register struct userid *tail;
136 struct group *grent;
137 char groupnum_string[20];
138
139 for (tail = group_alist; tail; tail = tail->next)
140 if (tail->id.g == gid)
141 return tail->name;
142
143 grent = getgrgid (gid);
144 tail = (struct userid *) xmalloc (sizeof (struct userid));
145 tail->id.g = gid;
146 if (grent == 0)
147 {
148 sprintf (groupnum_string, "%u", (unsigned int) gid);
149 tail->name = xstrdup (groupnum_string);
150 }
151 else
152 tail->name = xstrdup (grent->gr_name);
153
154 /* Add to the head of the list, so most recently used is first. */
155 tail->next = group_alist;
156 group_alist = tail;
157 return tail->name;
158 }
159
160 /* Translate GROUP to a UID, with cache.
161 Return NULL if there is no such group.
162 (We also cache which group names have no group entry,
163 so we don't keep looking them up.) */
164
165 gid_t *
getgidbyname(char * group)166 getgidbyname (char *group)
167 {
168 register struct userid *tail;
169 struct group *grent;
170
171 for (tail = group_alist; tail; tail = tail->next)
172 /* Avoid a function call for the most common case. */
173 if (*tail->name == *group && !strcmp (tail->name, group))
174 return &tail->id.g;
175
176 for (tail = nogroup_alist; tail; tail = tail->next)
177 /* Avoid a function call for the most common case. */
178 if (*tail->name == *group && !strcmp (tail->name, group))
179 return 0;
180
181 grent = getgrnam (group);
182
183 tail = (struct userid *) xmalloc (sizeof (struct userid));
184 tail->name = xstrdup (group);
185
186 /* Add to the head of the list, so most recently used is first. */
187 if (grent)
188 {
189 tail->id.g = grent->gr_gid;
190 tail->next = group_alist;
191 group_alist = tail;
192 return &tail->id.g;
193 }
194
195 tail->next = nogroup_alist;
196 nogroup_alist = tail;
197 return 0;
198 }
199