1 /*-
2 * Copyright (c) 1992 Keith Muller.
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Keith Muller of the University of California, San Diego.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
37 #endif
38 #endif /* not lint */
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <pwd.h>
47 #include <grp.h>
48 #include <stdlib.h>
49 #include "pax.h"
50 #include "cache.h"
51 #include "extern.h"
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 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 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 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 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 an 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 setpassent(1);
198 ++pwopn;
199 }
200 if (ptr == NULL)
201 ptr = uidtb[uid % UID_SZ] = (UIDC *)malloc(sizeof(UIDC));
202
203 if ((pw = getpwuid(uid)) == NULL) {
204 /*
205 * no match for this uid in the local password file
206 * a string that is the uid in numeric format
207 */
208 if (ptr == NULL)
209 return("");
210 ptr->uid = uid;
211 ptr->valid = INVALID;
212 # ifdef NET2_STAT
213 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
214 # else
215 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
216 (unsigned long)uid);
217 # endif
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)strncpy(ptr->name, pw->pw_name, UNMLEN - 1);
228 ptr->name[UNMLEN-1] = '\0';
229 ptr->valid = VALID;
230 }
231 return(ptr->name);
232 }
233
234 /*
235 * name_gid()
236 * caches the name (if any) for the gid. If frc set, we always return the
237 * the stored name (if valid or invalid match). We use a simple hash table.
238 * Return
239 * Pointer to stored name (or an empty string).
240 */
241
242 const char *
name_gid(gid_t gid,int frc)243 name_gid(gid_t gid, int frc)
244 {
245 struct group *gr;
246 GIDC *ptr;
247
248 if ((gidtb == NULL) && (gidtb_start() < 0))
249 return("");
250
251 /*
252 * see if we have this gid cached
253 */
254 ptr = gidtb[gid % GID_SZ];
255 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
256 /*
257 * have an entry for this gid
258 */
259 if (frc || (ptr->valid == VALID))
260 return(ptr->name);
261 return("");
262 }
263
264 /*
265 * No entry for this gid, we will add it
266 */
267 if (!gropn) {
268 setgroupent(1);
269 ++gropn;
270 }
271 if (ptr == NULL)
272 ptr = gidtb[gid % GID_SZ] = (GIDC *)malloc(sizeof(GIDC));
273
274 if ((gr = getgrgid(gid)) == NULL) {
275 /*
276 * no match for this gid in the local group file, put in
277 * a string that is the gid in numeric format
278 */
279 if (ptr == NULL)
280 return("");
281 ptr->gid = gid;
282 ptr->valid = INVALID;
283 # ifdef NET2_STAT
284 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
285 # else
286 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
287 (unsigned long)gid);
288 # endif
289 if (frc == 0)
290 return("");
291 } else {
292 /*
293 * there is an entry for this group in the group file
294 */
295 if (ptr == NULL)
296 return(gr->gr_name);
297 ptr->gid = gid;
298 (void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1);
299 ptr->name[GNMLEN-1] = '\0';
300 ptr->valid = VALID;
301 }
302 return(ptr->name);
303 }
304
305 /*
306 * uid_name()
307 * caches the uid for a given user name. We use a simple hash table.
308 * Return
309 * the uid (if any) for a user name, or a -1 if no match can be found
310 */
311
312 int
uid_name(char * name,uid_t * uid)313 uid_name(char *name, uid_t *uid)
314 {
315 struct passwd *pw;
316 UIDC *ptr;
317 int namelen;
318
319 /*
320 * return -1 for mangled names
321 */
322 if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
323 return(-1);
324 if ((usrtb == NULL) && (usrtb_start() < 0))
325 return(-1);
326
327 /*
328 * look up in hash table, if found and valid return the uid,
329 * if found and invalid, return a -1
330 */
331 ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
332 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
333 if (ptr->valid == INVALID)
334 return(-1);
335 *uid = ptr->uid;
336 return(0);
337 }
338
339 if (!pwopn) {
340 setpassent(1);
341 ++pwopn;
342 }
343
344 if (ptr == NULL)
345 ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
346 (UIDC *)malloc(sizeof(UIDC));
347
348 /*
349 * no match, look it up, if no match store it as an invalid entry,
350 * or store the matching uid
351 */
352 if (ptr == NULL) {
353 if ((pw = getpwnam(name)) == NULL)
354 return(-1);
355 *uid = pw->pw_uid;
356 return(0);
357 }
358 (void)strncpy(ptr->name, name, UNMLEN - 1);
359 ptr->name[UNMLEN-1] = '\0';
360 if ((pw = getpwnam(name)) == NULL) {
361 ptr->valid = INVALID;
362 return(-1);
363 }
364 ptr->valid = VALID;
365 *uid = ptr->uid = pw->pw_uid;
366 return(0);
367 }
368
369 /*
370 * gid_name()
371 * caches the gid for a given group name. We use a simple hash table.
372 * Return
373 * the gid (if any) for a group name, or a -1 if no match can be found
374 */
375
376 int
gid_name(char * name,gid_t * gid)377 gid_name(char *name, gid_t *gid)
378 {
379 struct group *gr;
380 GIDC *ptr;
381 int namelen;
382
383 /*
384 * return -1 for mangled names
385 */
386 if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
387 return(-1);
388 if ((grptb == NULL) && (grptb_start() < 0))
389 return(-1);
390
391 /*
392 * look up in hash table, if found and valid return the uid,
393 * if found and invalid, return a -1
394 */
395 ptr = grptb[st_hash(name, namelen, GID_SZ)];
396 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
397 if (ptr->valid == INVALID)
398 return(-1);
399 *gid = ptr->gid;
400 return(0);
401 }
402
403 if (!gropn) {
404 setgroupent(1);
405 ++gropn;
406 }
407 if (ptr == NULL)
408 ptr = grptb[st_hash(name, namelen, GID_SZ)] =
409 (GIDC *)malloc(sizeof(GIDC));
410
411 /*
412 * no match, look it up, if no match store it as an invalid entry,
413 * or store the matching gid
414 */
415 if (ptr == NULL) {
416 if ((gr = getgrnam(name)) == NULL)
417 return(-1);
418 *gid = gr->gr_gid;
419 return(0);
420 }
421
422 (void)strncpy(ptr->name, name, GNMLEN - 1);
423 ptr->name[GNMLEN-1] = '\0';
424 if ((gr = getgrnam(name)) == NULL) {
425 ptr->valid = INVALID;
426 return(-1);
427 }
428 ptr->valid = VALID;
429 *gid = ptr->gid = gr->gr_gid;
430 return(0);
431 }
432