]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - bin/pax/cache.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / bin / pax / cache.c
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
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
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
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
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 *
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 *
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
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
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 }