GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/pax/cache.c Lines: 96 150 64.0 %
Date: 2016-12-06 Branches: 56 128 43.8 %

Line Branch Exec Source
1
/*	$OpenBSD: cache.c,v 1.21 2014/05/24 18:51:00 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/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 "pax.h"
47
#include "cache.h"
48
#include "extern.h"
49
50
/*
51
 * routines that control user, group, uid and gid caches (for the archive
52
 * member print routine).
53
 * IMPORTANT:
54
 * these routines cache BOTH hits and misses, a major performance improvement
55
 */
56
57
static	int pwopn = 0;		/* is password file open */
58
static	int gropn = 0;		/* is group file open */
59
static UIDC **uidtb = NULL;	/* uid to name cache */
60
static GIDC **gidtb = NULL;	/* gid to name cache */
61
static UIDC **usrtb = NULL;	/* user name to uid cache */
62
static GIDC **grptb = NULL;	/* group name to gid cache */
63
64
/*
65
 * uidtb_start
66
 *	creates an empty uidtb
67
 * Return:
68
 *	0 if ok, -1 otherwise
69
 */
70
71
int
72
uidtb_start(void)
73
6
{
74
	static int fail = 0;
75
76
6
	if (uidtb != NULL)
77
		return(0);
78
6
	if (fail)
79
		return(-1);
80
6
	if ((uidtb = calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
81
		++fail;
82
		paxwarn(1, "Unable to allocate memory for user id cache table");
83
		return(-1);
84
	}
85
6
	return(0);
86
}
87
88
/*
89
 * gidtb_start
90
 *	creates an empty gidtb
91
 * Return:
92
 *	0 if ok, -1 otherwise
93
 */
94
95
int
96
gidtb_start(void)
97
6
{
98
	static int fail = 0;
99
100
6
	if (gidtb != NULL)
101
		return(0);
102
6
	if (fail)
103
		return(-1);
104
6
	if ((gidtb = calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
105
		++fail;
106
		paxwarn(1, "Unable to allocate memory for group id cache table");
107
		return(-1);
108
	}
109
6
	return(0);
110
}
111
112
/*
113
 * usrtb_start
114
 *	creates an empty usrtb
115
 * Return:
116
 *	0 if ok, -1 otherwise
117
 */
118
119
int
120
usrtb_start(void)
121
22
{
122
	static int fail = 0;
123
124
22
	if (usrtb != NULL)
125
		return(0);
126
22
	if (fail)
127
		return(-1);
128
22
	if ((usrtb = calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
129
		++fail;
130
		paxwarn(1, "Unable to allocate memory for user name cache table");
131
		return(-1);
132
	}
133
22
	return(0);
134
}
135
136
/*
137
 * grptb_start
138
 *	creates an empty grptb
139
 * Return:
140
 *	0 if ok, -1 otherwise
141
 */
142
143
int
144
grptb_start(void)
145
22
{
146
	static int fail = 0;
147
148
22
	if (grptb != NULL)
149
		return(0);
150
22
	if (fail)
151
		return(-1);
152
22
	if ((grptb = calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
153
		++fail;
154
		paxwarn(1,"Unable to allocate memory for group name cache table");
155
		return(-1);
156
	}
157
22
	return(0);
158
}
159
160
/*
161
 * name_uid()
162
 *	caches the name (if any) for the uid. If frc set, we always return the
163
 *	the stored name (if valid or invalid match). We use a simple hash table.
164
 * Return
165
 *	Pointer to stored name (or a empty string)
166
 */
167
168
char *
169
name_uid(uid_t uid, int frc)
170
4
{
171
	struct passwd *pw;
172
	UIDC *ptr;
173
174

4
	if ((uidtb == NULL) && (uidtb_start() < 0))
175
		return("");
176
177
	/*
178
	 * see if we have this uid cached
179
	 */
180
4
	ptr = uidtb[uid % UID_SZ];
181

4
	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
182
		/*
183
		 * have an entry for this uid
184
		 */
185
		if (frc || (ptr->valid == VALID))
186
			return(ptr->name);
187
		return("");
188
	}
189
190
	/*
191
	 * No entry for this uid, we will add it
192
	 */
193
4
	if (!pwopn) {
194
2
		setpassent(1);
195
2
		++pwopn;
196
	}
197
4
	if (ptr == NULL)
198
4
		ptr = uidtb[uid % UID_SZ] = malloc(sizeof(UIDC));
199
200
4
	if ((pw = getpwuid(uid)) == NULL) {
201
		/*
202
		 * no match for this uid in the local password file
203
		 * a string that is the uid in numeric format
204
		 */
205
		if (ptr == NULL)
206
			return("");
207
		ptr->uid = uid;
208
		ptr->valid = INVALID;
209
		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
210
			       (unsigned long)uid);
211
		if (frc == 0)
212
			return("");
213
	} else {
214
		/*
215
		 * there is an entry for this uid in the password file
216
		 */
217
4
		if (ptr == NULL)
218
			return(pw->pw_name);
219
4
		ptr->uid = uid;
220
4
		(void)strlcpy(ptr->name, pw->pw_name, sizeof(ptr->name));
221
4
		ptr->valid = VALID;
222
	}
223
4
	return(ptr->name);
224
}
225
226
/*
227
 * name_gid()
228
 *	caches the name (if any) for the gid. If frc set, we always return the
229
 *	the stored name (if valid or invalid match). We use a simple hash table.
230
 * Return
231
 *	Pointer to stored name (or a empty string)
232
 */
233
234
char *
235
name_gid(gid_t gid, int frc)
236
4
{
237
	struct group *gr;
238
	GIDC *ptr;
239
240

4
	if ((gidtb == NULL) && (gidtb_start() < 0))
241
		return("");
242
243
	/*
244
	 * see if we have this gid cached
245
	 */
246
4
	ptr = gidtb[gid % GID_SZ];
247

4
	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
248
		/*
249
		 * have an entry for this gid
250
		 */
251
		if (frc || (ptr->valid == VALID))
252
			return(ptr->name);
253
		return("");
254
	}
255
256
	/*
257
	 * No entry for this gid, we will add it
258
	 */
259
4
	if (!gropn) {
260
2
		setgroupent(1);
261
2
		++gropn;
262
	}
263
4
	if (ptr == NULL)
264
4
		ptr = gidtb[gid % GID_SZ] = malloc(sizeof(GIDC));
265
266
4
	if ((gr = getgrgid(gid)) == NULL) {
267
		/*
268
		 * no match for this gid in the local group file, put in
269
		 * a string that is the gid in numeric format
270
		 */
271
		if (ptr == NULL)
272
			return("");
273
		ptr->gid = gid;
274
		ptr->valid = INVALID;
275
		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
276
			       (unsigned long)gid);
277
		if (frc == 0)
278
			return("");
279
	} else {
280
		/*
281
		 * there is an entry for this group in the group file
282
		 */
283
4
		if (ptr == NULL)
284
			return(gr->gr_name);
285
4
		ptr->gid = gid;
286
4
		(void)strlcpy(ptr->name, gr->gr_name, sizeof(ptr->name));
287
4
		ptr->valid = VALID;
288
	}
289
4
	return(ptr->name);
290
}
291
292
/*
293
 * uid_name()
294
 *	caches the uid for a given user name. We use a simple hash table.
295
 * Return
296
 *	the uid (if any) for a user name, or a -1 if no match can be found
297
 */
298
299
int
300
uid_name(char *name, uid_t *uid)
301
92
{
302
	struct passwd *pw;
303
	UIDC *ptr;
304
	int namelen;
305
306
	/*
307
	 * return -1 for mangled names
308
	 */
309

92
	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
310
4
		return(-1);
311

88
	if ((usrtb == NULL) && (usrtb_start() < 0))
312
		return(-1);
313
314
	/*
315
	 * look up in hash table, if found and valid return the uid,
316
	 * if found and invalid, return a -1
317
	 */
318
88
	ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
319

88
	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
320
68
		if (ptr->valid == INVALID)
321
64
			return(-1);
322
4
		*uid = ptr->uid;
323
4
		return(0);
324
	}
325
326
20
	if (!pwopn) {
327
20
		setpassent(1);
328
20
		++pwopn;
329
	}
330
331
20
	if (ptr == NULL)
332
20
		ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
333
		  malloc(sizeof(UIDC));
334
335
	/*
336
	 * no match, look it up, if no match store it as an invalid entry,
337
	 * or store the matching uid
338
	 */
339
20
	if (ptr == NULL) {
340
		if ((pw = getpwnam(name)) == NULL)
341
			return(-1);
342
		*uid = pw->pw_uid;
343
		return(0);
344
	}
345
20
	(void)strlcpy(ptr->name, name, sizeof(ptr->name));
346
20
	if ((pw = getpwnam(name)) == NULL) {
347
4
		ptr->valid = INVALID;
348
4
		return(-1);
349
	}
350
16
	ptr->valid = VALID;
351
16
	*uid = ptr->uid = pw->pw_uid;
352
16
	return(0);
353
}
354
355
/*
356
 * gid_name()
357
 *	caches the gid for a given group name. We use a simple hash table.
358
 * Return
359
 *	the gid (if any) for a group name, or a -1 if no match can be found
360
 */
361
362
int
363
gid_name(char *name, gid_t *gid)
364
92
{
365
	struct group *gr;
366
	GIDC *ptr;
367
	int namelen;
368
369
	/*
370
	 * return -1 for mangled names
371
	 */
372

92
	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
373
4
		return(-1);
374

88
	if ((grptb == NULL) && (grptb_start() < 0))
375
		return(-1);
376
377
	/*
378
	 * look up in hash table, if found and valid return the uid,
379
	 * if found and invalid, return a -1
380
	 */
381
88
	ptr = grptb[st_hash(name, namelen, GID_SZ)];
382

88
	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
383
68
		if (ptr->valid == INVALID)
384
64
			return(-1);
385
4
		*gid = ptr->gid;
386
4
		return(0);
387
	}
388
389
20
	if (!gropn) {
390
20
		setgroupent(1);
391
20
		++gropn;
392
	}
393
20
	if (ptr == NULL)
394
20
		ptr = grptb[st_hash(name, namelen, GID_SZ)] =
395
		  malloc(sizeof(GIDC));
396
397
	/*
398
	 * no match, look it up, if no match store it as an invalid entry,
399
	 * or store the matching gid
400
	 */
401
20
	if (ptr == NULL) {
402
		if ((gr = getgrnam(name)) == NULL)
403
			return(-1);
404
		*gid = gr->gr_gid;
405
		return(0);
406
	}
407
408
20
	(void)strlcpy(ptr->name, name, sizeof(ptr->name));
409
20
	if ((gr = getgrnam(name)) == NULL) {
410
4
		ptr->valid = INVALID;
411
4
		return(-1);
412
	}
413
16
	ptr->valid = VALID;
414
16
	*gid = ptr->gid = gr->gr_gid;
415
16
	return(0);
416
}