~ubuntu-branches/ubuntu/dapper/postfix/dapper-security

« back to all changes in this revision

Viewing changes to src/global/mypwd.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-02-27 09:33:07 UTC
  • Revision ID: james.westby@ubuntu.com-20050227093307-cn789t27ibnlh6tf
Tags: upstream-2.1.5
ImportĀ upstreamĀ versionĀ 2.1.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      mypwd 3
 
4
/* SUMMARY
 
5
/*      caching getpwnam()/getpwuid()
 
6
/* SYNOPSIS
 
7
/*      #include <mypwd.h>
 
8
/*
 
9
/*      struct mypasswd *mypwuid(uid)
 
10
/*      uid_t   uid;
 
11
/*
 
12
/*      struct mypasswd *mypwnam(name)
 
13
/*      const char *name;
 
14
/*
 
15
/*      void    mypwfree(pwd)
 
16
/*      struct mypasswd *pwd;
 
17
/* DESCRIPTION
 
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.
 
24
/*
 
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.
 
29
/*
 
30
/*      mypwfree() cleans up the result of mypwnam() and mypwuid().
 
31
/* BUGS
 
32
/*      This module is security sensitive and complex at the same
 
33
/*      time, which is bad.
 
34
/* LICENSE
 
35
/* .ad
 
36
/* .fi
 
37
/*      The Secure Mailer license must be distributed with this software.
 
38
/* AUTHOR(S)
 
39
/*      Wietse Venema
 
40
/*      IBM T.J. Watson Research
 
41
/*      P.O. Box 704
 
42
/*      Yorktown Heights, NY 10598, USA
 
43
/*--*/
 
44
 
 
45
/* System library. */
 
46
 
 
47
#include <sys_defs.h>
 
48
#include <pwd.h>
 
49
#include <string.h>
 
50
#ifdef USE_PATHS_H
 
51
#include <paths.h>
 
52
#endif
 
53
 
 
54
/* Utility library. */
 
55
 
 
56
#include <mymalloc.h>
 
57
#include <htable.h>
 
58
#include <binhash.h>
 
59
#include <msg.h>
 
60
 
 
61
/* Global library. */
 
62
 
 
63
#include "mypwd.h"
 
64
 
 
65
 /*
 
66
  * The private cache. One for lookups by name, one for lookups by uid, and
 
67
  * one for the last looked up result.
 
68
  */
 
69
static HTABLE *mypwcache_name = 0;
 
70
static BINHASH *mypwcache_uid = 0;
 
71
static struct mypasswd *last_pwd;
 
72
 
 
73
/* mypwenter - enter password info into cache */
 
74
 
 
75
static struct mypasswd *mypwenter(struct passwd * pwd)
 
76
{
 
77
    struct mypasswd *mypwd;
 
78
 
 
79
    /*
 
80
     * Initialize on the fly.
 
81
     */
 
82
    if (mypwcache_name == 0) {
 
83
        mypwcache_name = htable_create(0);
 
84
        mypwcache_uid = binhash_create(0);
 
85
    }
 
86
    mypwd = (struct mypasswd *) mymalloc(sizeof(*mypwd));
 
87
    mypwd->refcount = 0;
 
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);
 
98
    return (mypwd);
 
99
}
 
100
 
 
101
/* mypwuid - caching getpwuid() */
 
102
 
 
103
struct mypasswd *mypwuid(uid_t uid)
 
104
{
 
105
    struct passwd *pwd;
 
106
    struct mypasswd *mypwd;
 
107
 
 
108
    /*
 
109
     * See if this is the same user as last time.
 
110
     */
 
111
    if (last_pwd != 0) {
 
112
        if (last_pwd->pw_uid != uid) {
 
113
            mypwfree(last_pwd);
 
114
            last_pwd = 0;
 
115
        } else {
 
116
            mypwd = last_pwd;
 
117
            mypwd->refcount++;
 
118
            return (mypwd);
 
119
        }
 
120
    }
 
121
 
 
122
    /*
 
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.
 
125
     */
 
126
    if ((mypwd = (struct mypasswd *)
 
127
         binhash_find(mypwcache_uid, (char *) &uid, sizeof(uid))) == 0) {
 
128
        if ((pwd = getpwuid(uid)) == 0)
 
129
            return (0);
 
130
        mypwd = mypwenter(pwd);
 
131
    }
 
132
    last_pwd = mypwd;
 
133
    mypwd->refcount += 2;
 
134
    return (mypwd);
 
135
}
 
136
 
 
137
/* mypwnam - caching getpwnam() */
 
138
 
 
139
struct mypasswd *mypwnam(const char *name)
 
140
{
 
141
    struct passwd *pwd;
 
142
    struct mypasswd *mypwd;
 
143
 
 
144
    /*
 
145
     * See if this is the same user as last time.
 
146
     */
 
147
    if (last_pwd != 0) {
 
148
        if (strcmp(last_pwd->pw_name, name) != 0) {
 
149
            mypwfree(last_pwd);
 
150
            last_pwd = 0;
 
151
        } else {
 
152
            mypwd = last_pwd;
 
153
            mypwd->refcount++;
 
154
            return (mypwd);
 
155
        }
 
156
    }
 
157
 
 
158
    /*
 
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.
 
161
     */
 
162
    if ((mypwd = (struct mypasswd *) htable_find(mypwcache_name, name)) == 0) {
 
163
        if ((pwd = getpwnam(name)) == 0)
 
164
            return (0);
 
165
        mypwd = mypwenter(pwd);
 
166
    }
 
167
    last_pwd = mypwd;
 
168
    mypwd->refcount += 2;
 
169
    return (mypwd);
 
170
}
 
171
 
 
172
/* mypwfree - destroy password info */
 
173
 
 
174
void    mypwfree(struct mypasswd * mypwd)
 
175
{
 
176
    if (mypwd->refcount < 1)
 
177
        msg_panic("mypwfree: refcount %d", mypwd->refcount);
 
178
 
 
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);
 
189
    }
 
190
}
 
191
 
 
192
#ifdef TEST
 
193
 
 
194
 /*
 
195
  * Test program. Look up a couple users and/or uid values and see if the
 
196
  * results will be properly free()d.
 
197
  */
 
198
#include <stdlib.h>
 
199
#include <ctype.h>
 
200
#include <vstream.h>
 
201
#include <msg_vstream.h>
 
202
 
 
203
int     main(int argc, char **argv)
 
204
{
 
205
    struct mypasswd **mypwd;
 
206
    int     i;
 
207
 
 
208
    msg_vstream_init(argv[0], VSTREAM_ERR);
 
209
    if (argc == 1)
 
210
        msg_fatal("usage: %s name or uid ...", argv[0]);
 
211
 
 
212
    mypwd = (struct mypasswd **) mymalloc((argc + 1) * sizeof(*mypwd));
 
213
 
 
214
    for (i = 1; i < argc; i++) {
 
215
        if (ISDIGIT(argv[i][0]))
 
216
            mypwd[i] = mypwuid(atoi(argv[i]));
 
217
        else
 
218
            mypwd[i] = mypwnam(argv[i]);
 
219
        if (mypwd[i] == 0)
 
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);
 
223
    }
 
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);
 
227
        mypwfree(mypwd[i]);
 
228
    }
 
229
 
 
230
    myfree((char *) mypwd);
 
231
}
 
232
 
 
233
#endif