Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / mypwd.c
blobe999d5a46f91b1e3638b28d1d78b120e6b08e179
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* mypwd 3
6 /* SUMMARY
7 /* caching getpwnam()/getpwuid()
8 /* SYNOPSIS
9 /* #include <mypwd.h>
11 /* struct mypasswd *mypwuid(uid)
12 /* uid_t uid;
14 /* struct mypasswd *mypwnam(name)
15 /* const char *name;
17 /* void mypwfree(pwd)
18 /* struct mypasswd *pwd;
19 /* DESCRIPTION
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().
33 /* BUGS
34 /* This module is security sensitive and complex at the same
35 /* time, which is bad.
36 /* LICENSE
37 /* .ad
38 /* .fi
39 /* The Secure Mailer license must be distributed with this software.
40 /* AUTHOR(S)
41 /* Wietse Venema
42 /* IBM T.J. Watson Research
43 /* P.O. Box 704
44 /* Yorktown Heights, NY 10598, USA
45 /*--*/
47 /* System library. */
49 #include <sys_defs.h>
50 #include <pwd.h>
51 #include <string.h>
52 #ifdef USE_PATHS_H
53 #include <paths.h>
54 #endif
56 /* Utility library. */
58 #include <mymalloc.h>
59 #include <htable.h>
60 #include <binhash.h>
61 #include <msg.h>
63 /* Global library. */
65 #include "mypwd.h"
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));
89 mypwd->refcount = 0;
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);
100 return (mypwd);
103 /* mypwuid - caching getpwuid() */
105 struct mypasswd *mypwuid(uid_t uid)
107 struct passwd *pwd;
108 struct mypasswd *mypwd;
111 * See if this is the same user as last time.
113 if (last_pwd != 0) {
114 if (last_pwd->pw_uid != uid) {
115 mypwfree(last_pwd);
116 last_pwd = 0;
117 } else {
118 mypwd = last_pwd;
119 mypwd->refcount++;
120 return (mypwd);
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)
131 return (0);
132 mypwd = mypwenter(pwd);
134 last_pwd = mypwd;
135 mypwd->refcount += 2;
136 return (mypwd);
139 /* mypwnam - caching getpwnam() */
141 struct mypasswd *mypwnam(const char *name)
143 struct passwd *pwd;
144 struct mypasswd *mypwd;
147 * See if this is the same user as last time.
149 if (last_pwd != 0) {
150 if (strcmp(last_pwd->pw_name, name) != 0) {
151 mypwfree(last_pwd);
152 last_pwd = 0;
153 } else {
154 mypwd = last_pwd;
155 mypwd->refcount++;
156 return (mypwd);
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)
166 return (0);
167 mypwd = mypwenter(pwd);
169 last_pwd = mypwd;
170 mypwd->refcount += 2;
171 return (mypwd);
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);
194 #ifdef TEST
197 * Test program. Look up a couple users and/or uid values and see if the
198 * results will be properly free()d.
200 #include <stdlib.h>
201 #include <ctype.h>
202 #include <vstream.h>
203 #include <msg_vstream.h>
205 int main(int argc, char **argv)
207 struct mypasswd **mypwd;
208 int i;
210 msg_vstream_init(argv[0], VSTREAM_ERR);
211 if (argc == 1)
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]));
219 else
220 mypwd[i] = mypwnam(argv[i]);
221 if (mypwd[i] == 0)
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);
229 mypwfree(mypwd[i]);
232 myfree((char *) mypwd);
233 return (0);
236 #endif