Merge branch 'vendor/OPENSSL'
[dragonfly.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  * 3. 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  * @(#)cache.c  8.1 (Berkeley) 5/31/93
34  * $FreeBSD: src/bin/pax/cache.c,v 1.12.2.1 2001/08/01 05:03:11 obrien Exp $
35  * $DragonFly: src/bin/pax/cache.c,v 1.7 2006/09/27 21:58:08 pavalos Exp $
36  */
37
38 #include <sys/types.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 {
74         static int fail = 0;
75
76         if (uidtb != NULL)
77                 return(0);
78         if (fail)
79                 return(-1);
80         if ((uidtb = (UIDC **)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         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 {
98         static int fail = 0;
99
100         if (gidtb != NULL)
101                 return(0);
102         if (fail)
103                 return(-1);
104         if ((gidtb = (GIDC **)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         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 {
122         static int fail = 0;
123
124         if (usrtb != NULL)
125                 return(0);
126         if (fail)
127                 return(-1);
128         if ((usrtb = (UIDC **)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         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 {
146         static int fail = 0;
147
148         if (grptb != NULL)
149                 return(0);
150         if (fail)
151                 return(-1);
152         if ((grptb = (GIDC **)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         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 {
171         struct passwd *pw;
172         UIDC *ptr;
173
174         if ((uidtb == NULL) && (uidtb_start() < 0))
175                 return("");
176
177         /*
178          * see if we have this uid cached
179          */
180         ptr = uidtb[uid % UID_SZ];
181         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         if (!pwopn) {
194                 setpassent(1);
195                 ++pwopn;
196         }
197         if (ptr == NULL)
198                 ptr = (UIDC *)malloc(sizeof(UIDC));
199
200         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                 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                 if (ptr == NULL)
218                         return(pw->pw_name);
219                 ptr->uid = uid;
220                 strncpy(ptr->name, pw->pw_name, UNMLEN - 1);
221                 ptr->name[UNMLEN-1] = '\0';
222                 ptr->valid = VALID;
223         }
224         return(ptr->name);
225 }
226
227 /*
228  * name_gid()
229  *      caches the name (if any) for the gid. If frc set, we always return the
230  *      the stored name (if valid or invalid match). We use a simple hash table.
231  * Return
232  *      Pointer to stored name (or a empty string)
233  */
234
235 char *
236 name_gid(gid_t gid, int frc)
237 {
238         struct group *gr;
239         GIDC *ptr;
240
241         if ((gidtb == NULL) && (gidtb_start() < 0))
242                 return("");
243
244         /*
245          * see if we have this gid cached
246          */
247         ptr = gidtb[gid % GID_SZ];
248         if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
249                 /*
250                  * have an entry for this gid
251                  */
252                 if (frc || (ptr->valid == VALID))
253                         return(ptr->name);
254                 return("");
255         }
256
257         /*
258          * No entry for this gid, we will add it
259          */
260         if (!gropn) {
261                 setgroupent(1);
262                 ++gropn;
263         }
264         if (ptr == NULL)
265                 ptr = (GIDC *)malloc(sizeof(GIDC));
266
267         if ((gr = getgrgid(gid)) == NULL) {
268                 /*
269                  * no match for this gid in the local group file, put in
270                  * a string that is the gid in numeric format
271                  */
272                 if (ptr == NULL)
273                         return("");
274                 ptr->gid = gid;
275                 ptr->valid = INVALID;
276                 snprintf(ptr->name, sizeof(ptr->name), "%lu",
277                                (unsigned long)gid);
278                 if (frc == 0)
279                         return("");
280         } else {
281                 /*
282                  * there is an entry for this group in the group file
283                  */
284                 if (ptr == NULL)
285                         return(gr->gr_name);
286                 ptr->gid = gid;
287                 strncpy(ptr->name, gr->gr_name, GNMLEN - 1);
288                 ptr->name[GNMLEN-1] = '\0';
289                 ptr->valid = VALID;
290         }
291         return(ptr->name);
292 }
293
294 /*
295  * uid_name()
296  *      caches the uid for a given user name. We use a simple hash table.
297  * Return
298  *      the uid (if any) for a user name, or a -1 if no match can be found
299  */
300
301 int
302 uid_name(char *name, uid_t *uid)
303 {
304         struct passwd *pw;
305         UIDC *ptr;
306         int namelen;
307
308         /*
309          * return -1 for mangled names
310          */
311         if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
312                 return(-1);
313         if ((usrtb == NULL) && (usrtb_start() < 0))
314                 return(-1);
315
316         /*
317          * look up in hash table, if found and valid return the uid,
318          * if found and invalid, return a -1
319          */
320         ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
321         if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
322                 if (ptr->valid == INVALID)
323                         return(-1);
324                 *uid = ptr->uid;
325                 return(0);
326         }
327
328         if (!pwopn) {
329                 setpassent(1);
330                 ++pwopn;
331         }
332
333         if (ptr == NULL)
334                 ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
335                   (UIDC *)malloc(sizeof(UIDC));
336
337         /*
338          * no match, look it up, if no match store it as an invalid entry,
339          * or store the matching uid
340          */
341         if (ptr == NULL) {
342                 if ((pw = getpwnam(name)) == NULL)
343                         return(-1);
344                 *uid = pw->pw_uid;
345                 return(0);
346         }
347         strncpy(ptr->name, name, UNMLEN - 1);
348         ptr->name[UNMLEN-1] = '\0';
349         if ((pw = getpwnam(name)) == NULL) {
350                 ptr->valid = INVALID;
351                 return(-1);
352         }
353         ptr->valid = VALID;
354         *uid = ptr->uid = pw->pw_uid;
355         return(0);
356 }
357
358 /*
359  * gid_name()
360  *      caches the gid for a given group name. We use a simple hash table.
361  * Return
362  *      the gid (if any) for a group name, or a -1 if no match can be found
363  */
364
365 int
366 gid_name(char *name, gid_t *gid)
367 {
368         struct group *gr;
369         GIDC *ptr;
370         int namelen;
371
372         /*
373          * return -1 for mangled names
374          */
375         if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
376                 return(-1);
377         if ((grptb == NULL) && (grptb_start() < 0))
378                 return(-1);
379
380         /*
381          * look up in hash table, if found and valid return the uid,
382          * if found and invalid, return a -1
383          */
384         ptr = grptb[st_hash(name, namelen, GID_SZ)];
385         if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
386                 if (ptr->valid == INVALID)
387                         return(-1);
388                 *gid = ptr->gid;
389                 return(0);
390         }
391
392         if (!gropn) {
393                 setgroupent(1);
394                 ++gropn;
395         }
396         if (ptr == NULL)
397                 ptr = grptb[st_hash(name, namelen, GID_SZ)] =
398                   (GIDC *)malloc(sizeof(GIDC));
399
400         /*
401          * no match, look it up, if no match store it as an invalid entry,
402          * or store the matching gid
403          */
404         if (ptr == NULL) {
405                 if ((gr = getgrnam(name)) == NULL)
406                         return(-1);
407                 *gid = gr->gr_gid;
408                 return(0);
409         }
410
411         strncpy(ptr->name, name, GNMLEN - 1);
412         ptr->name[GNMLEN-1] = '\0';
413         if ((gr = getgrnam(name)) == NULL) {
414                 ptr->valid = INVALID;
415                 return(-1);
416         }
417         ptr->valid = VALID;
418         *gid = ptr->gid = gr->gr_gid;
419         return(0);
420 }