5
/* caching getpwnam()/getpwuid()
9
/* struct mypasswd *mypwuid(uid)
12
/* struct mypasswd *mypwnam(name)
16
/* struct mypasswd *pwd;
18
/* This module maintains a reference-counted cache of password
19
/* database lookup results. The idea is to avoid surprises by
20
/* getpwnam() or getpwuid() overwriting a previous result, while
21
/* at the same time avoiding duplicate copies of password
22
/* information in memory, and to avoid making repeated getpwxxx()
23
/* calls for the same information.
25
/* mypwnam() and mypwuid() are wrappers that cache a private copy
26
/* of results from the getpwnam() and getpwuid() library routines.
27
/* Results are shared between calls with the same \fIname\fR
28
/* or \fIuid\fR argument, so changing results is verboten.
30
/* mypwfree() cleans up the result of mypwnam() and mypwuid().
32
/* This module is security sensitive and complex at the same
33
/* time, which is bad.
37
/* The Secure Mailer license must be distributed with this software.
40
/* IBM T.J. Watson Research
42
/* Yorktown Heights, NY 10598, USA
54
/* Utility library. */
66
* The private cache. One for lookups by name, one for lookups by uid, and
67
* one for the last looked up result.
69
static HTABLE *mypwcache_name = 0;
70
static BINHASH *mypwcache_uid = 0;
71
static struct mypasswd *last_pwd;
73
/* mypwenter - enter password info into cache */
75
static struct mypasswd *mypwenter(struct passwd * pwd)
77
struct mypasswd *mypwd;
80
* Initialize on the fly.
82
if (mypwcache_name == 0) {
83
mypwcache_name = htable_create(0);
84
mypwcache_uid = binhash_create(0);
86
mypwd = (struct mypasswd *) mymalloc(sizeof(*mypwd));
88
mypwd->pw_name = mystrdup(pwd->pw_name);
89
mypwd->pw_passwd = mystrdup(pwd->pw_passwd);
90
mypwd->pw_uid = pwd->pw_uid;
91
mypwd->pw_gid = pwd->pw_gid;
92
mypwd->pw_gecos = mystrdup(pwd->pw_gecos);
93
mypwd->pw_dir = mystrdup(pwd->pw_dir);
94
mypwd->pw_shell = mystrdup(*pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL);
95
htable_enter(mypwcache_name, mypwd->pw_name, (char *) mypwd);
96
binhash_enter(mypwcache_uid, (char *) &mypwd->pw_uid,
97
sizeof(mypwd->pw_uid), (char *) mypwd);
101
/* mypwuid - caching getpwuid() */
103
struct mypasswd *mypwuid(uid_t uid)
106
struct mypasswd *mypwd;
109
* See if this is the same user as last time.
112
if (last_pwd->pw_uid != uid) {
123
* Find the info in the cache or in the password database. Make a copy,
124
* so that repeated getpwnam() calls will not clobber our result.
126
if ((mypwd = (struct mypasswd *)
127
binhash_find(mypwcache_uid, (char *) &uid, sizeof(uid))) == 0) {
128
if ((pwd = getpwuid(uid)) == 0)
130
mypwd = mypwenter(pwd);
133
mypwd->refcount += 2;
137
/* mypwnam - caching getpwnam() */
139
struct mypasswd *mypwnam(const char *name)
142
struct mypasswd *mypwd;
145
* See if this is the same user as last time.
148
if (strcmp(last_pwd->pw_name, name) != 0) {
159
* Find the info in the cache or in the password database. Make a copy,
160
* so that repeated getpwnam() calls will not clobber our result.
162
if ((mypwd = (struct mypasswd *) htable_find(mypwcache_name, name)) == 0) {
163
if ((pwd = getpwnam(name)) == 0)
165
mypwd = mypwenter(pwd);
168
mypwd->refcount += 2;
172
/* mypwfree - destroy password info */
174
void mypwfree(struct mypasswd * mypwd)
176
if (mypwd->refcount < 1)
177
msg_panic("mypwfree: refcount %d", mypwd->refcount);
179
if (--mypwd->refcount == 0) {
180
htable_delete(mypwcache_name, mypwd->pw_name, (void (*) (char *)) 0);
181
binhash_delete(mypwcache_uid, (char *) &mypwd->pw_uid,
182
sizeof(mypwd->pw_uid), (void (*) (char *)) 0);
183
myfree(mypwd->pw_name);
184
myfree(mypwd->pw_passwd);
185
myfree(mypwd->pw_gecos);
186
myfree(mypwd->pw_dir);
187
myfree(mypwd->pw_shell);
188
myfree((char *) mypwd);
195
* Test program. Look up a couple users and/or uid values and see if the
196
* results will be properly free()d.
201
#include <msg_vstream.h>
203
int main(int argc, char **argv)
205
struct mypasswd **mypwd;
208
msg_vstream_init(argv[0], VSTREAM_ERR);
210
msg_fatal("usage: %s name or uid ...", argv[0]);
212
mypwd = (struct mypasswd **) mymalloc((argc + 1) * sizeof(*mypwd));
214
for (i = 1; i < argc; i++) {
215
if (ISDIGIT(argv[i][0]))
216
mypwd[i] = mypwuid(atoi(argv[i]));
218
mypwd[i] = mypwnam(argv[i]);
220
msg_fatal("%s: not found", argv[i]);
221
msg_info("+ %s link=%d used=%d used=%d", argv[i], mypwd[i]->refcount,
222
mypwcache_name->used, mypwcache_uid->used);
224
for (i = 1; i < argc; i++) {
225
msg_info("- %s link=%d used=%d used=%d", argv[i], mypwd[i]->refcount,
226
mypwcache_name->used, mypwcache_uid->used);
230
myfree((char *) mypwd);