GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/pax/cache.c Lines: 60 80 75.0 %
Date: 2017-11-07 Branches: 36 64 56.3 %

Line Branch Exec Source
1
/*	$OpenBSD: cache.c,v 1.23 2016/08/26 04:08:18 guenther 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/types.h>
38
#include <sys/stat.h>
39
#include <grp.h>
40
#include <pwd.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
45
#include "pax.h"
46
#include "extern.h"
47
48
/*
49
 * Constants and data structures used to implement group and password file
50
 * caches. Traditional passwd/group cache routines perform quite poorly with
51
 * archives. The chances of hitting a valid lookup with an archive is quite a
52
 * bit worse than with files already resident on the file system. These misses
53
 * create a MAJOR performance cost. To address this problem, these routines
54
 * cache both hits and misses.
55
 *
56
 * NOTE:  name lengths must be as large as those stored in ANY PROTOCOL and
57
 * as stored in the passwd and group files. CACHE SIZES MUST BE PRIME
58
 */
59
#define UNMLEN		32	/* >= user name found in any protocol */
60
#define GNMLEN		32	/* >= group name found in any protocol */
61
#define UNM_SZ		317	/* size of uid_name() cache */
62
#define GNM_SZ		317	/* size of gid_name() cache */
63
#define VALID		1	/* entry and name are valid */
64
#define INVALID		2	/* entry valid, name NOT valid */
65
66
/*
67
 * Node structures used in the user, group, uid, and gid caches.
68
 */
69
70
typedef struct uidc {
71
	int valid;		/* is this a valid or a miss entry */
72
	char name[UNMLEN];	/* uid name */
73
	uid_t uid;		/* cached uid */
74
} UIDC;
75
76
typedef struct gidc {
77
	int valid;		/* is this a valid or a miss entry */
78
	char name[GNMLEN];	/* gid name */
79
	gid_t gid;		/* cached gid */
80
} GIDC;
81
82
83
/*
84
 * routines that control user, group, uid and gid caches (for the archive
85
 * member print routine).
86
 * IMPORTANT:
87
 * these routines cache BOTH hits and misses, a major performance improvement
88
 */
89
90
static	int pwopn = 0;		/* is password file open */
91
static	int gropn = 0;		/* is group file open */
92
static UIDC **usrtb = NULL;	/* user name to uid cache */
93
static GIDC **grptb = NULL;	/* group name to gid cache */
94
95
/*
96
 * usrtb_start
97
 *	creates an empty usrtb
98
 * Return:
99
 *	0 if ok, -1 otherwise
100
 */
101
102
int
103
usrtb_start(void)
104
{
105
	static int fail = 0;
106
107
376
	if (usrtb != NULL)
108
		return(0);
109
188
	if (fail)
110
		return(-1);
111
188
	if ((usrtb = calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
112
		++fail;
113
		paxwarn(1, "Unable to allocate memory for user name cache table");
114
		return(-1);
115
	}
116
188
	return(0);
117
188
}
118
119
/*
120
 * grptb_start
121
 *	creates an empty grptb
122
 * Return:
123
 *	0 if ok, -1 otherwise
124
 */
125
126
int
127
grptb_start(void)
128
{
129
	static int fail = 0;
130
131
376
	if (grptb != NULL)
132
		return(0);
133
188
	if (fail)
134
		return(-1);
135
188
	if ((grptb = calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
136
		++fail;
137
		paxwarn(1,"Unable to allocate memory for group name cache table");
138
		return(-1);
139
	}
140
188
	return(0);
141
188
}
142
143
/*
144
 * uid_name()
145
 *	caches the uid for a given user name. We use a simple hash table.
146
 * Return
147
 *	the uid (if any) for a user name, or a -1 if no match can be found
148
 */
149
150
int
151
uid_name(char *name, uid_t *uid)
152
{
153
	struct passwd *pw;
154
	UIDC *ptr;
155
	int namelen;
156
157
	/*
158
	 * return -1 for mangled names
159
	 */
160

28346
	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
161
34
		return(-1);
162

9426
	if ((usrtb == NULL) && (usrtb_start() < 0))
163
		return(-1);
164
165
	/*
166
	 * look up in hash table, if found and valid return the uid,
167
	 * if found and invalid, return a -1
168
	 */
169
9426
	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
170

27936
	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
171
9255
		if (ptr->valid == INVALID)
172
9221
			return(-1);
173
34
		*uid = ptr->uid;
174
34
		return(0);
175
	}
176
177
171
	if (!pwopn) {
178
171
		setpassent(1);
179
171
		++pwopn;
180
171
	}
181
182
171
	if (ptr == NULL)
183
171
		ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
184
171
		  malloc(sizeof(UIDC));
185
186
	/*
187
	 * no match, look it up, if no match store it as an invalid entry,
188
	 * or store the matching uid
189
	 */
190
171
	if (ptr == NULL) {
191
		if ((pw = getpwnam(name)) == NULL)
192
			return(-1);
193
		*uid = pw->pw_uid;
194
		return(0);
195
	}
196
171
	(void)strlcpy(ptr->name, name, sizeof(ptr->name));
197
171
	if ((pw = getpwnam(name)) == NULL) {
198
35
		ptr->valid = INVALID;
199
35
		return(-1);
200
	}
201
136
	ptr->valid = VALID;
202
136
	*uid = ptr->uid = pw->pw_uid;
203
136
	return(0);
204
9460
}
205
206
/*
207
 * gid_name()
208
 *	caches the gid for a given group name. We use a simple hash table.
209
 * Return
210
 *	the gid (if any) for a group name, or a -1 if no match can be found
211
 */
212
213
int
214
gid_name(char *name, gid_t *gid)
215
{
216
	struct group *gr;
217
	GIDC *ptr;
218
	int namelen;
219
220
	/*
221
	 * return -1 for mangled names
222
	 */
223

28346
	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
224
34
		return(-1);
225

9426
	if ((grptb == NULL) && (grptb_start() < 0))
226
		return(-1);
227
228
	/*
229
	 * look up in hash table, if found and valid return the uid,
230
	 * if found and invalid, return a -1
231
	 */
232
9426
	ptr = grptb[st_hash(name, namelen, GNM_SZ)];
233

27936
	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
234
9255
		if (ptr->valid == INVALID)
235
9221
			return(-1);
236
34
		*gid = ptr->gid;
237
34
		return(0);
238
	}
239
240
171
	if (!gropn) {
241
171
		setgroupent(1);
242
171
		++gropn;
243
171
	}
244
171
	if (ptr == NULL)
245
171
		ptr = grptb[st_hash(name, namelen, GNM_SZ)] =
246
171
		  malloc(sizeof(GIDC));
247
248
	/*
249
	 * no match, look it up, if no match store it as an invalid entry,
250
	 * or store the matching gid
251
	 */
252
171
	if (ptr == NULL) {
253
		if ((gr = getgrnam(name)) == NULL)
254
			return(-1);
255
		*gid = gr->gr_gid;
256
		return(0);
257
	}
258
259
171
	(void)strlcpy(ptr->name, name, sizeof(ptr->name));
260
171
	if ((gr = getgrnam(name)) == NULL) {
261
35
		ptr->valid = INVALID;
262
35
		return(-1);
263
	}
264
136
	ptr->valid = VALID;
265
136
	*gid = ptr->gid = gr->gr_gid;
266
136
	return(0);
267
9460
}