xref: /csrg-svn/bin/pax/cache.c (revision 60676)
157194Smuller /*-
257194Smuller  * Copyright (c) 1992 Keith Muller.
3*60676Sbostic  * Copyright (c) 1992, 1993
4*60676Sbostic  *	The Regents of the University of California.  All rights reserved.
557194Smuller  *
657194Smuller  * This code is derived from software contributed to Berkeley by
757194Smuller  * Keith Muller of the University of California, San Diego.
857194Smuller  *
957194Smuller  * %sccs.include.redist.c%
1057194Smuller  */
1157194Smuller 
1257194Smuller #ifndef lint
13*60676Sbostic static char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 05/31/93";
1457194Smuller #endif /* not lint */
1557194Smuller 
1657194Smuller #include <sys/types.h>
1757194Smuller #include <sys/time.h>
1857194Smuller #include <sys/stat.h>
1957194Smuller #include <sys/param.h>
2057194Smuller #include <string.h>
2157194Smuller #include <stdio.h>
2257194Smuller #include <ctype.h>
2357194Smuller #include <pwd.h>
2457194Smuller #include <grp.h>
2557194Smuller #include <unistd.h>
2657194Smuller #include <stdlib.h>
2757194Smuller #include "pax.h"
2857194Smuller #include "cache.h"
2957194Smuller #include "extern.h"
3057194Smuller 
3157194Smuller /*
3257194Smuller  * routines that control user, group, uid and gid caches (for the archive
3357194Smuller  * member print routine).
3457194Smuller  * IMPORTANT:
3557194Smuller  * these routines cache BOTH hits and misses, a major performance improvement
3657194Smuller  */
3757194Smuller 
3857194Smuller static	int pwopn = 0;		/* is password file open */
3957194Smuller static	int gropn = 0;		/* is group file open */
4057194Smuller static UIDC **uidtb = NULL;	/* uid to name cache */
4157194Smuller static GIDC **gidtb = NULL;	/* gid to name cache */
4257194Smuller static UIDC **usrtb = NULL;	/* user name to uid cache */
4357194Smuller static GIDC **grptb = NULL;	/* group name to gid cache */
4457194Smuller 
4557194Smuller /*
4657194Smuller  * uidtb_start
4757194Smuller  *	creates an an empty uidtb
4857194Smuller  * Return:
4957194Smuller  *	0 if ok, -1 otherwise
5057194Smuller  */
5157194Smuller 
5257194Smuller #if __STDC__
5357194Smuller int
uidtb_start(void)5457194Smuller uidtb_start(void)
5557194Smuller #else
5657194Smuller int
5757194Smuller uidtb_start()
5857194Smuller #endif
5957194Smuller {
6057194Smuller 	static int fail = 0;
6157194Smuller 
6257194Smuller 	if (uidtb != NULL)
6357194Smuller 		return(0);
6457194Smuller 	if (fail)
6557194Smuller 		return(-1);
6657194Smuller 	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
6757194Smuller 		++fail;
6857194Smuller 		warn(1, "Unable to allocate memory for user id cache table");
6957194Smuller 		return(-1);
7057194Smuller 	}
7157194Smuller 	return(0);
7257194Smuller }
7357194Smuller 
7457194Smuller /*
7557194Smuller  * gidtb_start
7657194Smuller  *	creates an an empty gidtb
7757194Smuller  * Return:
7857194Smuller  *	0 if ok, -1 otherwise
7957194Smuller  */
8057194Smuller 
8157194Smuller #if __STDC__
8257194Smuller int
gidtb_start(void)8357194Smuller gidtb_start(void)
8457194Smuller #else
8557194Smuller int
8657194Smuller gidtb_start()
8757194Smuller #endif
8857194Smuller {
8957194Smuller 	static int fail = 0;
9057194Smuller 
9157194Smuller 	if (gidtb != NULL)
9257194Smuller 		return(0);
9357194Smuller 	if (fail)
9457194Smuller 		return(-1);
9557194Smuller 	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
9657194Smuller 		++fail;
9757194Smuller 		warn(1, "Unable to allocate memory for group id cache table");
9857194Smuller 		return(-1);
9957194Smuller 	}
10057194Smuller 	return(0);
10157194Smuller }
10257194Smuller 
10357194Smuller /*
10457194Smuller  * usrtb_start
10557194Smuller  *	creates an an empty usrtb
10657194Smuller  * Return:
10757194Smuller  *	0 if ok, -1 otherwise
10857194Smuller  */
10957194Smuller 
11057194Smuller #if __STDC__
11157194Smuller int
usrtb_start(void)11257194Smuller usrtb_start(void)
11357194Smuller #else
11457194Smuller int
11557194Smuller usrtb_start()
11657194Smuller #endif
11757194Smuller {
11857194Smuller 	static int fail = 0;
11957194Smuller 
12057194Smuller 	if (usrtb != NULL)
12157194Smuller 		return(0);
12257194Smuller 	if (fail)
12357194Smuller 		return(-1);
12457194Smuller 	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
12557194Smuller 		++fail;
12657194Smuller 		warn(1, "Unable to allocate memory for user name cache table");
12757194Smuller 		return(-1);
12857194Smuller 	}
12957194Smuller 	return(0);
13057194Smuller }
13157194Smuller 
13257194Smuller /*
13357194Smuller  * grptb_start
13457194Smuller  *	creates an an empty grptb
13557194Smuller  * Return:
13657194Smuller  *	0 if ok, -1 otherwise
13757194Smuller  */
13857194Smuller 
13957194Smuller #if __STDC__
14057194Smuller int
grptb_start(void)14157194Smuller grptb_start(void)
14257194Smuller #else
14357194Smuller int
14457194Smuller grptb_start()
14557194Smuller #endif
14657194Smuller {
14757194Smuller 	static int fail = 0;
14857194Smuller 
14957194Smuller 	if (grptb != NULL)
15057194Smuller 		return(0);
15157194Smuller 	if (fail)
15257194Smuller 		return(-1);
15357194Smuller 	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
15457194Smuller 		++fail;
15557194Smuller 		warn(1,"Unable to allocate memory for group name cache table");
15657194Smuller 		return(-1);
15757194Smuller 	}
15857194Smuller 	return(0);
15957194Smuller }
16057194Smuller 
16157194Smuller /*
16257194Smuller  * name_uid()
16357194Smuller  *	caches the name (if any) for the uid. If frc set, we always return the
16457194Smuller  *	the stored name (if valid or invalid match). We use a simple hash table.
16557194Smuller  * Return
16657194Smuller  *	Pointer to stored name (or a empty string)
16757194Smuller  */
16857194Smuller 
16957194Smuller #if __STDC__
17057194Smuller char *
name_uid(uid_t uid,int frc)17157194Smuller name_uid(uid_t uid, int frc)
17257194Smuller #else
17357194Smuller char *
17457194Smuller name_uid(uid, frc)
17557194Smuller 	uid_t uid;
17657194Smuller 	int frc;
17757194Smuller #endif
17857194Smuller {
17957194Smuller 	register struct passwd *pw;
18057194Smuller 	register UIDC *ptr;
18157194Smuller 
18257194Smuller 	if ((uidtb == NULL) && (uidtb_start() < 0))
18357194Smuller 		return("");
18457194Smuller 
18557194Smuller 	/*
18657194Smuller 	 * see if we have this uid cached
18757194Smuller 	 */
18857194Smuller 	ptr = uidtb[uid % UID_SZ];
18957194Smuller 	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
19057194Smuller 		/*
19157194Smuller 		 * have an entry for this uid
19257194Smuller 		 */
19357194Smuller 		if (frc || (ptr->valid == VALID))
19457194Smuller 			return(ptr->name);
19557194Smuller 		return("");
19657194Smuller 	}
19757194Smuller 
19857194Smuller 	/*
19957194Smuller 	 * No entry for this uid, we will add it
20057194Smuller 	 */
20157194Smuller 	if (!pwopn) {
20257194Smuller 		setpassent(1);
20357194Smuller 		++pwopn;
20457194Smuller 	}
20557194Smuller 	if (ptr == NULL)
20657194Smuller 		ptr = (UIDC *)malloc(sizeof(UIDC));
20757194Smuller 
20857194Smuller 	if ((pw = getpwuid(uid)) == NULL) {
20957194Smuller 		/*
21057194Smuller 		 * no match for this uid in the local password file
21157194Smuller 		 * a string that is the uid in numberic format
21257194Smuller 		 */
21357194Smuller 		if (ptr == NULL)
21457194Smuller 			return("");
21557194Smuller 		ptr->uid = uid;
21657194Smuller 		ptr->valid = INVALID;
21757194Smuller #		ifdef NET2_STAT
21857194Smuller 		(void)sprintf(ptr->name, "%u", uid);
21957194Smuller #		else
22057194Smuller 		(void)sprintf(ptr->name, "%lu", uid);
22157194Smuller #		endif
22257194Smuller 		if (frc == 0)
22357194Smuller 			return("");
22457194Smuller 	} else {
22557194Smuller 		/*
22657194Smuller 		 * there is an entry for this uid in the password file
22757194Smuller 		 */
22857194Smuller 		if (ptr == NULL)
22957194Smuller 			return(pw->pw_name);
23057194Smuller 		ptr->uid = uid;
23157194Smuller 		(void)strncpy(ptr->name, pw->pw_name, UNMLEN);
23257194Smuller 		ptr->name[UNMLEN-1] = '\0';
23357194Smuller 		ptr->valid = VALID;
23457194Smuller 	}
23557194Smuller 	return(ptr->name);
23657194Smuller }
23757194Smuller 
23857194Smuller /*
23957194Smuller  * name_gid()
24057194Smuller  *	caches the name (if any) for the gid. If frc set, we always return the
24157194Smuller  *	the stored name (if valid or invalid match). We use a simple hash table.
24257194Smuller  * Return
24357194Smuller  *	Pointer to stored name (or a empty string)
24457194Smuller  */
24557194Smuller 
24657194Smuller #if __STDC__
24757194Smuller char *
name_gid(gid_t gid,int frc)24857194Smuller name_gid(gid_t gid, int frc)
24957194Smuller #else
25057194Smuller char *
25157194Smuller name_gid(gid, frc)
25257194Smuller 	gid_t gid;
25357194Smuller 	int frc;
25457194Smuller #endif
25557194Smuller {
25657194Smuller 	register struct group *gr;
25757194Smuller 	register GIDC *ptr;
25857194Smuller 
25957194Smuller 	if ((gidtb == NULL) && (gidtb_start() < 0))
26057194Smuller 		return("");
26157194Smuller 
26257194Smuller 	/*
26357194Smuller 	 * see if we have this gid cached
26457194Smuller 	 */
26557194Smuller 	ptr = gidtb[gid % GID_SZ];
26657194Smuller 	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
26757194Smuller 		/*
26857194Smuller 		 * have an entry for this gid
26957194Smuller 		 */
27057194Smuller 		if (frc || (ptr->valid == VALID))
27157194Smuller 			return(ptr->name);
27257194Smuller 		return("");
27357194Smuller 	}
27457194Smuller 
27557194Smuller 	/*
27657194Smuller 	 * No entry for this gid, we will add it
27757194Smuller 	 */
27857194Smuller 	if (!gropn) {
27957194Smuller 		setgroupent(1);
28057194Smuller 		++gropn;
28157194Smuller 	}
28257194Smuller 	if (ptr == NULL)
28357194Smuller 		ptr = (GIDC *)malloc(sizeof(GIDC));
28457194Smuller 
28557194Smuller 	if ((gr = getgrgid(gid)) == NULL) {
28657194Smuller 		/*
28757194Smuller 		 * no match for this gid in the local group file, put in
28857194Smuller 		 * a string that is the gid in numberic format
28957194Smuller 		 */
29057194Smuller 		if (ptr == NULL)
29157194Smuller 			return("");
29257194Smuller 		ptr->gid = gid;
29357194Smuller 		ptr->valid = INVALID;
29457194Smuller #		ifdef NET2_STAT
29557194Smuller 		(void)sprintf(ptr->name, "%u", gid);
29657194Smuller #		else
29757194Smuller 		(void)sprintf(ptr->name, "%lu", gid);
29857194Smuller #		endif
29957194Smuller 		if (frc == 0)
30057194Smuller 			return("");
30157194Smuller 	} else {
30257194Smuller 		/*
30357194Smuller 		 * there is an entry for this group in the group file
30457194Smuller 		 */
30557194Smuller 		if (ptr == NULL)
30657194Smuller 			return(gr->gr_name);
30757194Smuller 		ptr->gid = gid;
30857194Smuller 		(void)strncpy(ptr->name, gr->gr_name, GNMLEN);
30957194Smuller 		ptr->name[GNMLEN-1] = '\0';
31057194Smuller 		ptr->valid = VALID;
31157194Smuller 	}
31257194Smuller 	return(ptr->name);
31357194Smuller }
31457194Smuller 
31557194Smuller /*
31657194Smuller  * uid_name()
31757194Smuller  *	caches the uid for a given user name. We use a simple hash table.
31857194Smuller  * Return
31957194Smuller  *	the uid (if any) for a user name, or a -1 if no match can be found
32057194Smuller  */
32157194Smuller 
32257194Smuller #if __STDC__
32357194Smuller int
uid_name(char * name,uid_t * uid)32457194Smuller uid_name(char *name, uid_t *uid)
32557194Smuller #else
32657194Smuller int
32757194Smuller uid_name(name, uid)
32857194Smuller 	char *name;
32957194Smuller 	uid_t *uid;
33057194Smuller #endif
33157194Smuller {
33257194Smuller 	register struct passwd *pw;
33357194Smuller 	register UIDC *ptr;
33457194Smuller 	register int namelen;
33557194Smuller 
33657194Smuller 	/*
33757194Smuller 	 * return -1 for mangled names
33857194Smuller 	 */
33957194Smuller 	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
34057194Smuller 		return(-1);
34157194Smuller 	if ((usrtb == NULL) && (usrtb_start() < 0))
34257194Smuller 		return(-1);
34357194Smuller 
34457194Smuller 	/*
34557194Smuller 	 * look up in hash table, if found and valid return the uid,
34657194Smuller 	 * if found and invalid, return a -1
34757194Smuller 	 */
34857194Smuller 	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
34957194Smuller 	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
35057194Smuller 		if (ptr->valid == INVALID)
35157194Smuller 			return(-1);
35257194Smuller 		*uid = ptr->uid;
35357194Smuller 		return(0);
35457194Smuller 	}
35557194Smuller 
35657194Smuller 	if (!pwopn) {
35757194Smuller 		setpassent(1);
35857194Smuller 		++pwopn;
35957194Smuller 	}
36057194Smuller 
36157194Smuller 	if (ptr == NULL)
36257194Smuller 		ptr = (UIDC *)malloc(sizeof(UIDC));
36357194Smuller 
36457194Smuller 	/*
36557194Smuller 	 * no match, look it up, if no match store it as an invalid entry,
36657194Smuller 	 * or store the matching uid
36757194Smuller 	 */
36857194Smuller 	if (ptr == NULL) {
36957194Smuller 		if ((pw = getpwnam(name)) == NULL)
37057194Smuller 			return(-1);
37157194Smuller 		*uid = pw->pw_uid;
37257194Smuller 		return(0);
37357194Smuller 	}
37457194Smuller 	(void)strncpy(ptr->name, name, UNMLEN);
37557194Smuller 	ptr->name[UNMLEN-1] = '\0';
37657194Smuller 	if ((pw = getpwnam(name)) == NULL) {
37757194Smuller 		ptr->valid = INVALID;
37857194Smuller 		return(-1);
37957194Smuller 	}
38057194Smuller 	ptr->valid = VALID;
38157194Smuller 	*uid = ptr->uid = pw->pw_uid;
38257194Smuller 	return(0);
38357194Smuller }
38457194Smuller 
38557194Smuller /*
38657194Smuller  * gid_name()
38757194Smuller  *	caches the gid for a given group name. We use a simple hash table.
38857194Smuller  * Return
38957194Smuller  *	the gid (if any) for a group name, or a -1 if no match can be found
39057194Smuller  */
39157194Smuller 
39257194Smuller #if __STDC__
39357194Smuller int
gid_name(char * name,gid_t * gid)39457194Smuller gid_name(char *name, gid_t *gid)
39557194Smuller #else
39657194Smuller int
39757194Smuller gid_name(name, gid)
39857194Smuller 	char *name;
39957194Smuller 	gid_t *gid;
40057194Smuller #endif
40157194Smuller {
40257194Smuller 	register struct group *gr;
40357194Smuller 	register GIDC *ptr;
40457194Smuller 	register int namelen;
40557194Smuller 
40657194Smuller 	/*
40757194Smuller 	 * return -1 for mangled names
40857194Smuller 	 */
40957194Smuller 	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
41057194Smuller 		return(-1);
41157194Smuller 	if ((grptb == NULL) && (grptb_start() < 0))
41257194Smuller 		return(-1);
41357194Smuller 
41457194Smuller 	/*
41557194Smuller 	 * look up in hash table, if found and valid return the uid,
41657194Smuller 	 * if found and invalid, return a -1
41757194Smuller 	 */
41857194Smuller 	ptr = grptb[st_hash(name, namelen, GID_SZ)];
41957194Smuller 	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
42057194Smuller 		if (ptr->valid == INVALID)
42157194Smuller 			return(-1);
42257194Smuller 		*gid = ptr->gid;
42357194Smuller 		return(0);
42457194Smuller 	}
42557194Smuller 
42657194Smuller 	if (!gropn) {
42757194Smuller 		setgroupent(1);
42857573Smuller 		++gropn;
42957194Smuller 	}
43057194Smuller 	if (ptr == NULL)
43157194Smuller 		ptr = (GIDC *)malloc(sizeof(GIDC));
43257194Smuller 
43357194Smuller 	/*
43457194Smuller 	 * no match, look it up, if no match store it as an invalid entry,
43557194Smuller 	 * or store the matching gid
43657194Smuller 	 */
43757194Smuller 	if (ptr == NULL) {
43857194Smuller 		if ((gr = getgrnam(name)) == NULL)
43957194Smuller 			return(-1);
44057194Smuller 		*gid = gr->gr_gid;
44157194Smuller 		return(0);
44257194Smuller 	}
44357194Smuller 
44457194Smuller 	(void)strncpy(ptr->name, name, GNMLEN);
44557194Smuller 	ptr->name[GNMLEN-1] = '\0';
44657194Smuller 	if ((gr = getgrnam(name)) == NULL) {
44757194Smuller 		ptr->valid = INVALID;
44857194Smuller 		return(-1);
44957194Smuller 	}
45057194Smuller 	ptr->valid = VALID;
45157194Smuller 	*gid = ptr->gid = gr->gr_gid;
45257194Smuller 	return(0);
45357194Smuller }
454