cache.c revision 331722
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
36static char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
37#endif
38#endif /* not lint */
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: stable/11/bin/pax/cache.c 331722 2018-03-29 02:50:57Z eadler $");
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
60static	int pwopn = 0;		/* is password file open */
61static	int gropn = 0;		/* is group file open */
62static UIDC **uidtb = NULL;	/* uid to name cache */
63static GIDC **gidtb = NULL;	/* gid to name cache */
64static UIDC **usrtb = NULL;	/* user name to uid cache */
65static 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
74int
75uidtb_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
98int
99gidtb_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
122int
123usrtb_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
146int
147grptb_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
171const char *
172name_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
242const char *
243name_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
312int
313uid_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
376int
377gid_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