1 /* $OpenBSD: cache.c,v 1.19 2009/12/22 12:09:36 jasper Exp $ */
2 /* $NetBSD: cache.c,v 1.4 1995/03/21 09:07:10 cgd Exp $ */
3
4 /*-
5 * Copyright (c) 1992 Keith Muller.
6 * Copyright (c) 1992, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Keith Muller of the University of California, San Diego.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/stat.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <pwd.h>
43 #include <grp.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <time.h>
47 #include "pax.h"
48 #include "cache.h"
49 #include "extern.h"
50
51 __RCSID("$MirOS: src/bin/pax/cache.c,v 1.8 2012/06/08 14:52:47 tg Exp $");
52
53 /*
54 * routines that control user, group, uid and gid caches (for the archive
55 * member print routine).
56 * IMPORTANT:
57 * these routines cache BOTH hits and misses, a major performance improvement
58 */
59
60 static int pwopn = 0; /* is password file open */
61 static int gropn = 0; /* is group file open */
62 static UIDC **uidtb = NULL; /* uid to name cache */
63 static GIDC **gidtb = NULL; /* gid to name cache */
64 static UIDC **usrtb = NULL; /* user name to uid cache */
65 static GIDC **grptb = NULL; /* group name to gid cache */
66
67 /*
68 * uidtb_start
69 * creates an empty uidtb
70 * Return:
71 * 0 if ok, -1 otherwise
72 */
73
74 int
uidtb_start(void)75 uidtb_start(void)
76 {
77 static int fail = 0;
78
79 if (uidtb != NULL)
80 return(0);
81 if (fail)
82 return(-1);
83 if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
84 ++fail;
85 paxwarn(1, "Unable to allocate memory for user id cache table");
86 return(-1);
87 }
88 return(0);
89 }
90
91 /*
92 * gidtb_start
93 * creates an empty gidtb
94 * Return:
95 * 0 if ok, -1 otherwise
96 */
97
98 int
gidtb_start(void)99 gidtb_start(void)
100 {
101 static int fail = 0;
102
103 if (gidtb != NULL)
104 return(0);
105 if (fail)
106 return(-1);
107 if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
108 ++fail;
109 paxwarn(1, "Unable to allocate memory for group id cache table");
110 return(-1);
111 }
112 return(0);
113 }
114
115 /*
116 * usrtb_start
117 * creates an empty usrtb
118 * Return:
119 * 0 if ok, -1 otherwise
120 */
121
122 int
usrtb_start(void)123 usrtb_start(void)
124 {
125 static int fail = 0;
126
127 if (usrtb != NULL)
128 return(0);
129 if (fail)
130 return(-1);
131 if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
132 ++fail;
133 paxwarn(1, "Unable to allocate memory for user name cache table");
134 return(-1);
135 }
136 return(0);
137 }
138
139 /*
140 * grptb_start
141 * creates an empty grptb
142 * Return:
143 * 0 if ok, -1 otherwise
144 */
145
146 int
grptb_start(void)147 grptb_start(void)
148 {
149 static int fail = 0;
150
151 if (grptb != NULL)
152 return(0);
153 if (fail)
154 return(-1);
155 if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
156 ++fail;
157 paxwarn(1,"Unable to allocate memory for group name cache table");
158 return(-1);
159 }
160 return(0);
161 }
162
163 /*
164 * name_uid()
165 * caches the name (if any) for the uid. If frc set, we always return the
166 * the stored name (if valid or invalid match). We use a simple hash table.
167 * Return
168 * Pointer to stored name (or a empty string)
169 */
170
171 const char *
name_uid(uid_t uid,int frc)172 name_uid(uid_t uid, int frc)
173 {
174 struct passwd *pw;
175 UIDC *ptr;
176
177 if ((uidtb == NULL) && (uidtb_start() < 0))
178 return("");
179
180 /*
181 * see if we have this uid cached
182 */
183 ptr = uidtb[uid % UID_SZ];
184 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
185 /*
186 * have an entry for this uid
187 */
188 if (frc || (ptr->valid == VALID))
189 return(ptr->name);
190 return("");
191 }
192
193 /*
194 * No entry for this uid, we will add it
195 */
196 if (!pwopn) {
197 #if defined(__GLIBC__)
198 setpwent();
199 #elif !defined(__INTERIX)
200 setpassent(1);
201 #endif
202 ++pwopn;
203 }
204 if (ptr == NULL)
205 ptr = uidtb[uid % UID_SZ] = malloc(sizeof(UIDC));
206
207 if ((pw = getpwuid(uid)) == NULL) {
208 /*
209 * no match for this uid in the local password file
210 * a string that is the uid in numeric format
211 */
212 if (ptr == NULL)
213 return("");
214 ptr->uid = uid;
215 ptr->valid = INVALID;
216 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
217 (unsigned long)uid);
218 if (frc == 0)
219 return("");
220 } else {
221 /*
222 * there is an entry for this uid in the password file
223 */
224 if (ptr == NULL)
225 return(pw->pw_name);
226 ptr->uid = uid;
227 (void)strlcpy(ptr->name, pw->pw_name, sizeof(ptr->name));
228 ptr->valid = VALID;
229 }
230 return(ptr->name);
231 }
232
233 /*
234 * name_gid()
235 * caches the name (if any) for the gid. If frc set, we always return the
236 * the stored name (if valid or invalid match). We use a simple hash table.
237 * Return
238 * Pointer to stored name (or a empty string)
239 */
240
241 const char *
name_gid(gid_t gid,int frc)242 name_gid(gid_t gid, int frc)
243 {
244 struct group *gr;
245 GIDC *ptr;
246
247 if ((gidtb == NULL) && (gidtb_start() < 0))
248 return("");
249
250 /*
251 * see if we have this gid cached
252 */
253 ptr = gidtb[gid % GID_SZ];
254 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
255 /*
256 * have an entry for this gid
257 */
258 if (frc || (ptr->valid == VALID))
259 return(ptr->name);
260 return("");
261 }
262
263 /*
264 * No entry for this gid, we will add it
265 */
266 if (!gropn) {
267 #if defined(__GLIBC__)
268 setgrent();
269 #elif !defined(__INTERIX) && !defined(__CYGWIN__)
270 setgroupent(1);
271 #endif
272 ++gropn;
273 }
274 if (ptr == NULL)
275 ptr = gidtb[gid % GID_SZ] = malloc(sizeof(GIDC));
276
277 if ((gr = getgrgid(gid)) == NULL) {
278 /*
279 * no match for this gid in the local group file, put in
280 * a string that is the gid in numeric format
281 */
282 if (ptr == NULL)
283 return("");
284 ptr->gid = gid;
285 ptr->valid = INVALID;
286 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
287 (unsigned long)gid);
288 if (frc == 0)
289 return("");
290 } else {
291 /*
292 * there is an entry for this group in the group file
293 */
294 if (ptr == NULL)
295 return(gr->gr_name);
296 ptr->gid = gid;
297 (void)strlcpy(ptr->name, gr->gr_name, sizeof(ptr->name));
298 ptr->valid = VALID;
299 }
300 return(ptr->name);
301 }
302
303 /*
304 * uid_name()
305 * caches the uid for a given user name. We use a simple hash table.
306 * Return
307 * the uid (if any) for a user name, or a -1 if no match can be found
308 */
309
310 int
uid_name(const char * name,uid_t * uid)311 uid_name(const char *name, uid_t *uid)
312 {
313 struct passwd *pw;
314 UIDC *ptr;
315 int namelen;
316
317 /*
318 * return -1 for mangled names
319 */
320 if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
321 return(-1);
322 if ((usrtb == NULL) && (usrtb_start() < 0))
323 return(-1);
324
325 /*
326 * look up in hash table, if found and valid return the uid,
327 * if found and invalid, return a -1
328 */
329 ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
330 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
331 if (ptr->valid == INVALID)
332 return(-1);
333 *uid = ptr->uid;
334 return(0);
335 }
336
337 if (!pwopn) {
338 #if defined(__GLIBC__)
339 setpwent();
340 #elif !defined(__INTERIX)
341 setpassent(1);
342 #endif
343 ++pwopn;
344 }
345
346 if (ptr == NULL)
347 ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
348 (UIDC *)malloc(sizeof(UIDC));
349
350 /*
351 * no match, look it up, if no match store it as an invalid entry,
352 * or store the matching uid
353 */
354 if (ptr == NULL) {
355 if ((pw = getpwnam(name)) == NULL)
356 return(-1);
357 *uid = pw->pw_uid;
358 return(0);
359 }
360 (void)strlcpy(ptr->name, name, sizeof(ptr->name));
361 if ((pw = getpwnam(name)) == NULL) {
362 ptr->valid = INVALID;
363 return(-1);
364 }
365 ptr->valid = VALID;
366 *uid = ptr->uid = pw->pw_uid;
367 return(0);
368 }
369
370 /*
371 * gid_name()
372 * caches the gid for a given group name. We use a simple hash table.
373 * Return
374 * the gid (if any) for a group name, or a -1 if no match can be found
375 */
376
377 int
gid_name(const char * name,gid_t * gid)378 gid_name(const char *name, gid_t *gid)
379 {
380 struct group *gr;
381 GIDC *ptr;
382 int namelen;
383
384 /*
385 * return -1 for mangled names
386 */
387 if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
388 return(-1);
389 if ((grptb == NULL) && (grptb_start() < 0))
390 return(-1);
391
392 /*
393 * look up in hash table, if found and valid return the uid,
394 * if found and invalid, return a -1
395 */
396 ptr = grptb[st_hash(name, namelen, GID_SZ)];
397 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
398 if (ptr->valid == INVALID)
399 return(-1);
400 *gid = ptr->gid;
401 return(0);
402 }
403
404 if (!gropn) {
405 #if defined(__GLIBC__)
406 setgrent();
407 #elif !defined(__INTERIX) && !defined(__CYGWIN__)
408 setgroupent(1);
409 #endif
410 ++gropn;
411 }
412 if (ptr == NULL)
413 ptr = grptb[st_hash(name, namelen, GID_SZ)] =
414 (GIDC *)malloc(sizeof(GIDC));
415
416 /*
417 * no match, look it up, if no match store it as an invalid entry,
418 * or store the matching gid
419 */
420 if (ptr == NULL) {
421 if ((gr = getgrnam(name)) == NULL)
422 return(-1);
423 *gid = gr->gr_gid;
424 return(0);
425 }
426
427 (void)strlcpy(ptr->name, name, sizeof(ptr->name));
428 if ((gr = getgrnam(name)) == NULL) {
429 ptr->valid = INVALID;
430 return(-1);
431 }
432 ptr->valid = VALID;
433 *gid = ptr->gid = gr->gr_gid;
434 return(0);
435 }
436