7 /* caching getpwnam()/getpwuid()
11 /* struct mypasswd *mypwuid(uid)
14 /* struct mypasswd *mypwnam(name)
18 /* struct mypasswd *pwd;
20 /* This module maintains a reference-counted cache of password
21 /* database lookup results. The idea is to avoid surprises by
22 /* getpwnam() or getpwuid() overwriting a previous result, while
23 /* at the same time avoiding duplicate copies of password
24 /* information in memory, and to avoid making repeated getpwxxx()
25 /* calls for the same information.
27 /* mypwnam() and mypwuid() are wrappers that cache a private copy
28 /* of results from the getpwnam() and getpwuid() library routines.
29 /* Results are shared between calls with the same \fIname\fR
30 /* or \fIuid\fR argument, so changing results is verboten.
32 /* mypwfree() cleans up the result of mypwnam() and mypwuid().
34 /* This module is security sensitive and complex at the same
35 /* time, which is bad.
39 /* The Secure Mailer license must be distributed with this software.
42 /* IBM T.J. Watson Research
44 /* Yorktown Heights, NY 10598, USA
56 /* Utility library. */
68 * The private cache. One for lookups by name, one for lookups by uid, and
69 * one for the last looked up result.
71 static HTABLE
*mypwcache_name
= 0;
72 static BINHASH
*mypwcache_uid
= 0;
73 static struct mypasswd
*last_pwd
;
75 /* mypwenter - enter password info into cache */
77 static struct mypasswd
*mypwenter(struct passwd
* pwd
)
79 struct mypasswd
*mypwd
;
82 * Initialize on the fly.
84 if (mypwcache_name
== 0) {
85 mypwcache_name
= htable_create(0);
86 mypwcache_uid
= binhash_create(0);
88 mypwd
= (struct mypasswd
*) mymalloc(sizeof(*mypwd
));
90 mypwd
->pw_name
= mystrdup(pwd
->pw_name
);
91 mypwd
->pw_passwd
= mystrdup(pwd
->pw_passwd
);
92 mypwd
->pw_uid
= pwd
->pw_uid
;
93 mypwd
->pw_gid
= pwd
->pw_gid
;
94 mypwd
->pw_gecos
= mystrdup(pwd
->pw_gecos
);
95 mypwd
->pw_dir
= mystrdup(pwd
->pw_dir
);
96 mypwd
->pw_shell
= mystrdup(*pwd
->pw_shell
? pwd
->pw_shell
: _PATH_BSHELL
);
97 htable_enter(mypwcache_name
, mypwd
->pw_name
, (char *) mypwd
);
98 binhash_enter(mypwcache_uid
, (char *) &mypwd
->pw_uid
,
99 sizeof(mypwd
->pw_uid
), (char *) mypwd
);
103 /* mypwuid - caching getpwuid() */
105 struct mypasswd
*mypwuid(uid_t uid
)
108 struct mypasswd
*mypwd
;
111 * See if this is the same user as last time.
114 if (last_pwd
->pw_uid
!= uid
) {
125 * Find the info in the cache or in the password database. Make a copy,
126 * so that repeated getpwnam() calls will not clobber our result.
128 if ((mypwd
= (struct mypasswd
*)
129 binhash_find(mypwcache_uid
, (char *) &uid
, sizeof(uid
))) == 0) {
130 if ((pwd
= getpwuid(uid
)) == 0)
132 mypwd
= mypwenter(pwd
);
135 mypwd
->refcount
+= 2;
139 /* mypwnam - caching getpwnam() */
141 struct mypasswd
*mypwnam(const char *name
)
144 struct mypasswd
*mypwd
;
147 * See if this is the same user as last time.
150 if (strcmp(last_pwd
->pw_name
, name
) != 0) {
161 * Find the info in the cache or in the password database. Make a copy,
162 * so that repeated getpwnam() calls will not clobber our result.
164 if ((mypwd
= (struct mypasswd
*) htable_find(mypwcache_name
, name
)) == 0) {
165 if ((pwd
= getpwnam(name
)) == 0)
167 mypwd
= mypwenter(pwd
);
170 mypwd
->refcount
+= 2;
174 /* mypwfree - destroy password info */
176 void mypwfree(struct mypasswd
* mypwd
)
178 if (mypwd
->refcount
< 1)
179 msg_panic("mypwfree: refcount %d", mypwd
->refcount
);
181 if (--mypwd
->refcount
== 0) {
182 htable_delete(mypwcache_name
, mypwd
->pw_name
, (void (*) (char *)) 0);
183 binhash_delete(mypwcache_uid
, (char *) &mypwd
->pw_uid
,
184 sizeof(mypwd
->pw_uid
), (void (*) (char *)) 0);
185 myfree(mypwd
->pw_name
);
186 myfree(mypwd
->pw_passwd
);
187 myfree(mypwd
->pw_gecos
);
188 myfree(mypwd
->pw_dir
);
189 myfree(mypwd
->pw_shell
);
190 myfree((char *) mypwd
);
197 * Test program. Look up a couple users and/or uid values and see if the
198 * results will be properly free()d.
203 #include <msg_vstream.h>
205 int main(int argc
, char **argv
)
207 struct mypasswd
**mypwd
;
210 msg_vstream_init(argv
[0], VSTREAM_ERR
);
212 msg_fatal("usage: %s name or uid ...", argv
[0]);
214 mypwd
= (struct mypasswd
**) mymalloc((argc
+ 1) * sizeof(*mypwd
));
216 for (i
= 1; i
< argc
; i
++) {
217 if (ISDIGIT(argv
[i
][0]))
218 mypwd
[i
] = mypwuid(atoi(argv
[i
]));
220 mypwd
[i
] = mypwnam(argv
[i
]);
222 msg_fatal("%s: not found", argv
[i
]);
223 msg_info("+ %s link=%d used=%d used=%d", argv
[i
], mypwd
[i
]->refcount
,
224 mypwcache_name
->used
, mypwcache_uid
->used
);
226 for (i
= 1; i
< argc
; i
++) {
227 msg_info("- %s link=%d used=%d used=%d", argv
[i
], mypwd
[i
]->refcount
,
228 mypwcache_name
->used
, mypwcache_uid
->used
);
232 myfree((char *) mypwd
);