60301d88d2d35004486052b8ef468b0bcfdc7db1
[debian/pax] / cache.c
1 /*      $OpenBSD: cache.c,v 1.6 1997/07/25 18:58:27 mickey 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. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by the University of
23  *      California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)cache.c     8.1 (Berkeley) 5/31/93";
44 #else
45 static char rcsid[] = "$OpenBSD: cache.c,v 1.6 1997/07/25 18:58:27 mickey Exp $";
46 #endif
47 #endif /* not lint */
48
49 #include <sys/types.h>
50 #include <sys/time.h>
51 #include <sys/stat.h>
52 #include <sys/param.h>
53 #include <string.h>
54 #include <stdio.h>
55 #include <pwd.h>
56 #include <grp.h>
57 #include <unistd.h>
58 #include <stdlib.h>
59 #include "pax.h"
60 #include "cache.h"
61 #include "extern.h"
62
63 /*
64  * routines that control user, group, uid and gid caches (for the archive
65  * member print routine).
66  * IMPORTANT:
67  * these routines cache BOTH hits and misses, a major performance improvement
68  */
69
70 static  int pwopn = 0;          /* is password file open */
71 static  int gropn = 0;          /* is group file open */
72 static UIDC **uidtb = NULL;     /* uid to name cache */
73 static GIDC **gidtb = NULL;     /* gid to name cache */
74 static UIDC **usrtb = NULL;     /* user name to uid cache */
75 static GIDC **grptb = NULL;     /* group name to gid cache */
76
77 /*
78  * uidtb_start
79  *      creates an an empty uidtb
80  * Return:
81  *      0 if ok, -1 otherwise
82  */
83
84 #ifdef __STDC__
85 int
86 uidtb_start(void)
87 #else
88 int
89 uidtb_start()
90 #endif
91 {
92         static int fail = 0;
93
94         if (uidtb != NULL)
95                 return(0);
96         if (fail)
97                 return(-1);
98         if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
99                 ++fail;
100                 paxwarn(1, "Unable to allocate memory for user id cache table");
101                 return(-1);
102         }
103         return(0);
104 }
105
106 /*
107  * gidtb_start
108  *      creates an an empty gidtb
109  * Return:
110  *      0 if ok, -1 otherwise
111  */
112
113 #ifdef __STDC__
114 int
115 gidtb_start(void)
116 #else
117 int
118 gidtb_start()
119 #endif
120 {
121         static int fail = 0;
122
123         if (gidtb != NULL)
124                 return(0);
125         if (fail)
126                 return(-1);
127         if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
128                 ++fail;
129                 paxwarn(1, "Unable to allocate memory for group id cache table");
130                 return(-1);
131         }
132         return(0);
133 }
134
135 /*
136  * usrtb_start
137  *      creates an an empty usrtb
138  * Return:
139  *      0 if ok, -1 otherwise
140  */
141
142 #ifdef __STDC__
143 int
144 usrtb_start(void)
145 #else
146 int
147 usrtb_start()
148 #endif
149 {
150         static int fail = 0;
151
152         if (usrtb != NULL)
153                 return(0);
154         if (fail)
155                 return(-1);
156         if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
157                 ++fail;
158                 paxwarn(1, "Unable to allocate memory for user name cache table");
159                 return(-1);
160         }
161         return(0);
162 }
163
164 /*
165  * grptb_start
166  *      creates an an empty grptb
167  * Return:
168  *      0 if ok, -1 otherwise
169  */
170
171 #ifdef __STDC__
172 int
173 grptb_start(void)
174 #else
175 int
176 grptb_start()
177 #endif
178 {
179         static int fail = 0;
180
181         if (grptb != NULL)
182                 return(0);
183         if (fail)
184                 return(-1);
185         if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
186                 ++fail;
187                 paxwarn(1,"Unable to allocate memory for group name cache table");
188                 return(-1);
189         }
190         return(0);
191 }
192
193 /*
194  * name_uid()
195  *      caches the name (if any) for the uid. If frc set, we always return the
196  *      the stored name (if valid or invalid match). We use a simple hash table.
197  * Return
198  *      Pointer to stored name (or a empty string)
199  */
200
201 #ifdef __STDC__
202 char *
203 name_uid(uid_t uid, int frc)
204 #else
205 char *
206 name_uid(uid, frc)
207         uid_t uid;
208         int frc;
209 #endif
210 {
211         register struct passwd *pw;
212         register UIDC *ptr;
213
214         if ((uidtb == NULL) && (uidtb_start() < 0))
215                 return("");
216
217         /*
218          * see if we have this uid cached
219          */
220         ptr = uidtb[uid % UID_SZ];
221         if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
222                 /*
223                  * have an entry for this uid
224                  */
225                 if (frc || (ptr->valid == VALID))
226                         return(ptr->name);
227                 return("");
228         }
229
230         /*
231          * No entry for this uid, we will add it
232          */
233         if (!pwopn) {
234                 setpassent(1);
235                 ++pwopn;
236         }
237         if (ptr == NULL)
238                 ptr = (UIDC *)malloc(sizeof(UIDC));
239
240         if ((pw = getpwuid(uid)) == NULL) {
241                 /*
242                  * no match for this uid in the local password file
243                  * a string that is the uid in numberic format
244                  */
245                 if (ptr == NULL)
246                         return("");
247                 ptr->uid = uid;
248                 ptr->valid = INVALID;
249 #               ifdef NET2_STAT
250                 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
251 #               else
252                 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
253                                (unsigned long)uid);
254 #               endif
255                 if (frc == 0)
256                         return("");
257         } else {
258                 /*
259                  * there is an entry for this uid in the password file
260                  */
261                 if (ptr == NULL)
262                         return(pw->pw_name);
263                 ptr->uid = uid;
264                 (void)strncpy(ptr->name, pw->pw_name, UNMLEN-1);
265                 ptr->name[UNMLEN-1] = '\0';
266                 ptr->valid = VALID;
267         }
268         return(ptr->name);
269 }
270
271 /*
272  * name_gid()
273  *      caches the name (if any) for the gid. If frc set, we always return the
274  *      the stored name (if valid or invalid match). We use a simple hash table.
275  * Return
276  *      Pointer to stored name (or a empty string)
277  */
278
279 #ifdef __STDC__
280 char *
281 name_gid(gid_t gid, int frc)
282 #else
283 char *
284 name_gid(gid, frc)
285         gid_t gid;
286         int frc;
287 #endif
288 {
289         register struct group *gr;
290         register GIDC *ptr;
291
292         if ((gidtb == NULL) && (gidtb_start() < 0))
293                 return("");
294
295         /*
296          * see if we have this gid cached
297          */
298         ptr = gidtb[gid % GID_SZ];
299         if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
300                 /*
301                  * have an entry for this gid
302                  */
303                 if (frc || (ptr->valid == VALID))
304                         return(ptr->name);
305                 return("");
306         }
307
308         /*
309          * No entry for this gid, we will add it
310          */
311         if (!gropn) {
312                 setgroupent(1);
313                 ++gropn;
314         }
315         if (ptr == NULL)
316                 ptr = (GIDC *)malloc(sizeof(GIDC));
317
318         if ((gr = getgrgid(gid)) == NULL) {
319                 /*
320                  * no match for this gid in the local group file, put in
321                  * a string that is the gid in numberic format
322                  */
323                 if (ptr == NULL)
324                         return("");
325                 ptr->gid = gid;
326                 ptr->valid = INVALID;
327 #               ifdef NET2_STAT
328                 (void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
329 #               else
330                 (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
331                                (unsigned long)gid);
332 #               endif
333                 if (frc == 0)
334                         return("");
335         } else {
336                 /*
337                  * there is an entry for this group in the group file
338                  */
339                 if (ptr == NULL)
340                         return(gr->gr_name);
341                 ptr->gid = gid;
342                 (void)strncpy(ptr->name, gr->gr_name, GNMLEN-1);
343                 ptr->name[GNMLEN-1] = '\0';
344                 ptr->valid = VALID;
345         }
346         return(ptr->name);
347 }
348
349 /*
350  * uid_name()
351  *      caches the uid for a given user name. We use a simple hash table.
352  * Return
353  *      the uid (if any) for a user name, or a -1 if no match can be found
354  */
355
356 #ifdef __STDC__
357 int
358 uid_name(char *name, uid_t *uid)
359 #else
360 int
361 uid_name(name, uid)
362         char *name;
363         uid_t *uid;
364 #endif
365 {
366         register struct passwd *pw;
367         register UIDC *ptr;
368         register int namelen;
369
370         /*
371          * return -1 for mangled names
372          */
373         if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
374                 return(-1);
375         if ((usrtb == NULL) && (usrtb_start() < 0))
376                 return(-1);
377
378         /*
379          * look up in hash table, if found and valid return the uid,
380          * if found and invalid, return a -1
381          */
382         ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
383         if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
384                 if (ptr->valid == INVALID)
385                         return(-1);
386                 *uid = ptr->uid;
387                 return(0);
388         }
389
390         if (!pwopn) {
391                 setpassent(1);
392                 ++pwopn;
393         }
394
395         if (ptr == NULL)
396                 ptr = (UIDC *)malloc(sizeof(UIDC));
397
398         /*
399          * no match, look it up, if no match store it as an invalid entry,
400          * or store the matching uid
401          */
402         if (ptr == NULL) {
403                 if ((pw = getpwnam(name)) == NULL)
404                         return(-1);
405                 *uid = pw->pw_uid;
406                 return(0);
407         }
408         (void)strncpy(ptr->name, name, UNMLEN-1);
409         ptr->name[UNMLEN-1] = '\0';
410         if ((pw = getpwnam(name)) == NULL) {
411                 ptr->valid = INVALID;
412                 return(-1);
413         }
414         ptr->valid = VALID;
415         *uid = ptr->uid = pw->pw_uid;
416         return(0);
417 }
418
419 /*
420  * gid_name()
421  *      caches the gid for a given group name. We use a simple hash table.
422  * Return
423  *      the gid (if any) for a group name, or a -1 if no match can be found
424  */
425
426 #ifdef __STDC__
427 int
428 gid_name(char *name, gid_t *gid)
429 #else
430 int
431 gid_name(name, gid)
432         char *name;
433         gid_t *gid;
434 #endif
435 {
436         register struct group *gr;
437         register GIDC *ptr;
438         register int namelen;
439
440         /*
441          * return -1 for mangled names
442          */
443         if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
444                 return(-1);
445         if ((grptb == NULL) && (grptb_start() < 0))
446                 return(-1);
447
448         /*
449          * look up in hash table, if found and valid return the uid,
450          * if found and invalid, return a -1
451          */
452         ptr = grptb[st_hash(name, namelen, GID_SZ)];
453         if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
454                 if (ptr->valid == INVALID)
455                         return(-1);
456                 *gid = ptr->gid;
457                 return(0);
458         }
459
460         if (!gropn) {
461                 setgroupent(1);
462                 ++gropn;
463         }
464         if (ptr == NULL)
465                 ptr = (GIDC *)malloc(sizeof(GIDC));
466
467         /*
468          * no match, look it up, if no match store it as an invalid entry,
469          * or store the matching gid
470          */
471         if (ptr == NULL) {
472                 if ((gr = getgrnam(name)) == NULL)
473                         return(-1);
474                 *gid = gr->gr_gid;
475                 return(0);
476         }
477
478         (void)strncpy(ptr->name, name, GNMLEN-1);
479         ptr->name[GNMLEN-1] = '\0';
480         if ((gr = getgrnam(name)) == NULL) {
481                 ptr->valid = INVALID;
482                 return(-1);
483         }
484         ptr->valid = VALID;
485         *gid = ptr->gid = gr->gr_gid;
486         return(0);
487 }