1 /* idcache.c -- map user and group IDs, cached for speed
2 Copyright (C) 1985, 1988, 1989, 1990, 1997, 1998, 2003 Free Software
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 #include <sys/types.h>
28 #if STDC_HEADERS || HAVE_STRING_H
40 #ifndef _POSIX_VERSION
41 struct passwd
*getpwuid ();
42 struct passwd
*getpwnam ();
43 struct group
*getgrgid ();
44 struct group
*getgrnam ();
48 static char digits
[] = "0123456789";
62 static struct userid
*user_alist
;
64 /* The members of this list have names not in the local passwd file. */
65 static struct userid
*nouser_alist
;
67 /* Translate UID to a login name, with cache, or NULL if unresolved. */
72 register struct userid
*tail
;
75 for (tail
= user_alist
; tail
; tail
= tail
->next
)
76 if (tail
->id
.u
== uid
)
79 pwent
= getpwuid (uid
);
80 tail
= (struct userid
*) xmalloc (sizeof (struct userid
));
82 tail
->name
= pwent
? xstrdup (pwent
->pw_name
) : NULL
;
84 /* Add to the head of the list, so most recently used is first. */
85 tail
->next
= user_alist
;
90 /* Translate USER to a UID, with cache.
91 Return NULL if there is no such user.
92 (We also cache which user names have no passwd entry,
93 so we don't keep looking them up.) */
96 getuidbyname (const char *user
)
98 register struct userid
*tail
;
101 for (tail
= user_alist
; tail
; tail
= tail
->next
)
102 /* Avoid a function call for the most common case. */
103 if (*tail
->name
== *user
&& !strcmp (tail
->name
, user
))
106 for (tail
= nouser_alist
; tail
; tail
= tail
->next
)
107 /* Avoid a function call for the most common case. */
108 if (*tail
->name
== *user
&& !strcmp (tail
->name
, user
))
111 pwent
= getpwnam (user
);
113 /* We need to pretend to be the user USER, to make
114 pwd functions know about an arbitrary user name. */
115 if (!pwent
&& strspn (user
, digits
) < strlen (user
))
117 setenv ("USER", user
, 1);
118 pwent
= getpwnam (user
); /* now it will succeed */
122 tail
= (struct userid
*) xmalloc (sizeof (struct userid
));
123 tail
->name
= xstrdup (user
);
125 /* Add to the head of the list, so most recently used is first. */
128 tail
->id
.u
= pwent
->pw_uid
;
129 tail
->next
= user_alist
;
134 tail
->next
= nouser_alist
;
139 /* Use the same struct as for userids. */
140 static struct userid
*group_alist
;
141 static struct userid
*nogroup_alist
;
143 /* Translate GID to a group name, with cache, or NULL if unresolved. */
148 register struct userid
*tail
;
151 for (tail
= group_alist
; tail
; tail
= tail
->next
)
152 if (tail
->id
.g
== gid
)
155 grent
= getgrgid (gid
);
156 tail
= (struct userid
*) xmalloc (sizeof (struct userid
));
158 tail
->name
= grent
? xstrdup (grent
->gr_name
) : NULL
;
160 /* Add to the head of the list, so most recently used is first. */
161 tail
->next
= group_alist
;
166 /* Translate GROUP to a GID, with cache.
167 Return NULL if there is no such group.
168 (We also cache which group names have no group entry,
169 so we don't keep looking them up.) */
172 getgidbyname (const char *group
)
174 register struct userid
*tail
;
177 for (tail
= group_alist
; tail
; tail
= tail
->next
)
178 /* Avoid a function call for the most common case. */
179 if (*tail
->name
== *group
&& !strcmp (tail
->name
, group
))
182 for (tail
= nogroup_alist
; tail
; tail
= tail
->next
)
183 /* Avoid a function call for the most common case. */
184 if (*tail
->name
== *group
&& !strcmp (tail
->name
, group
))
187 grent
= getgrnam (group
);
189 /* We need to pretend to belong to group GROUP, to make
190 grp functions know about any arbitrary group name. */
191 if (!grent
&& strspn (group
, digits
) < strlen (group
))
193 setenv ("GROUP", group
, 1);
194 grent
= getgrnam (group
); /* now it will succeed */
198 tail
= (struct userid
*) xmalloc (sizeof (struct userid
));
199 tail
->name
= xstrdup (group
);
201 /* Add to the head of the list, so most recently used is first. */
204 tail
->id
.g
= grent
->gr_gid
;
205 tail
->next
= group_alist
;
210 tail
->next
= nogroup_alist
;
211 nogroup_alist
= tail
;