~ubuntu-branches/ubuntu/vivid/munge/vivid

« back to all changes in this revision

Viewing changes to src/munged/xgetpwnam.c

  • Committer: Bazaar Package Importer
  • Author(s): Gennaro Oliva
  • Date: 2011-02-28 20:41:12 UTC
  • mfrom: (6.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20110228204112-2lc8ss9geeusv5uo
Tags: 0.5.10-1
* New upstream release 
* Updated copyright, homepage, watch thanks to Chris Dunlap
* Standards version upgraded to 3.9.1.0 (no changes) 
* Switch to dpkg-source 3.0 (quilt) format
* Added explicit dependency by the same version of libmunge for munge

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 *  $Id: xgetpwnam.c 921 2011-02-25 00:48:52Z chris.m.dunlap $
 
3
 *****************************************************************************
 
4
 *  Written by Chris Dunlap <cdunlap@llnl.gov>.
 
5
 *  Copyright (C) 2007-2011 Lawrence Livermore National Security, LLC.
 
6
 *  Copyright (C) 2002-2007 The Regents of the University of California.
 
7
 *  UCRL-CODE-155910.
 
8
 *
 
9
 *  This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE).
 
10
 *  For details, see <http://munge.googlecode.com/>.
 
11
 *
 
12
 *  MUNGE is free software: you can redistribute it and/or modify it under
 
13
 *  the terms of the GNU General Public License as published by the Free
 
14
 *  Software Foundation, either version 3 of the License, or (at your option)
 
15
 *  any later version.  Additionally for the MUNGE library (libmunge), you
 
16
 *  can redistribute it and/or modify it under the terms of the GNU Lesser
 
17
 *  General Public License as published by the Free Software Foundation,
 
18
 *  either version 3 of the License, or (at your option) any later version.
 
19
 *
 
20
 *  MUNGE is distributed in the hope that it will be useful, but WITHOUT
 
21
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
22
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
23
 *  and GNU Lesser General Public License for more details.
 
24
 *
 
25
 *  You should have received a copy of the GNU General Public License
 
26
 *  and GNU Lesser General Public License along with MUNGE.  If not, see
 
27
 *  <http://www.gnu.org/licenses/>.
 
28
 *****************************************************************************/
 
29
 
 
30
 
 
31
#if HAVE_CONFIG_H
 
32
#  include "config.h"
 
33
#endif /* HAVE_CONFIG_H */
 
34
 
 
35
#if   HAVE_GETPWNAM_R_POSIX
 
36
#define _POSIX_PTHREAD_SEMANTICS 1      /* for SunOS */
 
37
#elif HAVE_GETPWNAM_R_AIX
 
38
#define _THREAD_SAFE 1
 
39
#define _UNIX95 1
 
40
#define _XOPEN_SOURCE_EXTENDED 1
 
41
#elif HAVE_GETPWNAM_R_SUN
 
42
#undef _POSIX_PTHREAD_SEMANTICS
 
43
#elif HAVE_GETPWNAM
 
44
#include <pthread.h>
 
45
#else
 
46
#error "getpwnam() not supported"
 
47
#endif
 
48
 
 
49
#include <assert.h>
 
50
#include <errno.h>
 
51
#include <pwd.h>
 
52
#include <stdlib.h>
 
53
#include <string.h>
 
54
#include <unistd.h>
 
55
#include <munge.h>
 
56
#include "log.h"
 
57
 
 
58
 
 
59
/*****************************************************************************
 
60
 *  Compiler Fu
 
61
 *****************************************************************************/
 
62
 
 
63
#ifdef __GNUC__
 
64
#define _UNUSED_ __attribute__ ((unused))
 
65
#else
 
66
#define _UNUSED_
 
67
#endif
 
68
 
 
69
 
 
70
/*****************************************************************************
 
71
 *  Constants
 
72
 *****************************************************************************/
 
73
 
 
74
#define MINIMUM_PW_BUF_SIZE     4096
 
75
 
 
76
 
 
77
/*****************************************************************************
 
78
 *  Private Prototypes
 
79
 *****************************************************************************/
 
80
 
 
81
static int _xgetpwnam_get_buf_size (void);
 
82
 
 
83
static int _xgetpwnam_copy (const struct passwd *src, struct passwd *dst,
 
84
    char *buf, size_t buflen) _UNUSED_;
 
85
 
 
86
static int _xgetpwnam_copy_str (const char *src, char **dst_p,
 
87
    char **buf_p, size_t *buflen_p) _UNUSED_;
 
88
 
 
89
 
 
90
/*****************************************************************************
 
91
 *  Public Functions
 
92
 *****************************************************************************/
 
93
 
 
94
int
 
95
xgetpwnam_buf_create (char **buf_p, int *buflen_p)
 
96
{
 
97
/*  Allocates a buffer for xgetpwnam(), storing the result in [buf_p];
 
98
 *    the size of the buffer is returned in [buflen_p].
 
99
 *  Returns 0 on success, or -1 on error (with errno).
 
100
 */
 
101
    static int  pw_buf_size = -1;
 
102
    char       *buf;
 
103
 
 
104
    if ((buf_p == NULL) || (buflen_p == NULL)) {
 
105
        errno = EINVAL;
 
106
        return (-1);
 
107
    }
 
108
    if (pw_buf_size < 0) {
 
109
        pw_buf_size = _xgetpwnam_get_buf_size ();
 
110
    }
 
111
    buf = malloc (pw_buf_size);
 
112
    if (buf == NULL) {
 
113
        return (-1);
 
114
    }
 
115
    *buf_p = buf;
 
116
    *buflen_p = pw_buf_size;
 
117
    return (0);
 
118
}
 
119
 
 
120
 
 
121
void
 
122
xgetpwnam_buf_destroy (char *buf)
 
123
{
 
124
/*  Destroys the buffer [buf].
 
125
 */
 
126
    if (buf != NULL) {
 
127
        free (buf);
 
128
    }
 
129
    return;
 
130
}
 
131
 
 
132
 
 
133
int
 
134
xgetpwnam (const char *user, struct passwd *pw, char *buf, size_t buflen)
 
135
{
 
136
/*  Portable encapsulation of getpwnam_r().
 
137
 *  Queries the password database for [user], storing the struct passwd result
 
138
 *    in [pw] and additional strings in buffer [buf] of length [buflen].
 
139
 *  Returns 0 on success, or -1 on error (with errno).
 
140
 *    Returns -1 with ENOENT when [user] is not found.
 
141
 */
 
142
#if   HAVE_GETPWNAM_R_POSIX
 
143
    int                     rv;
 
144
    struct passwd          *pw_ptr;
 
145
#elif HAVE_GETPWNAM_R_AIX
 
146
    int                     rv;
 
147
#elif HAVE_GETPWNAM_R_SUN
 
148
    struct passwd          *pw_ptr;
 
149
#elif HAVE_GETPWNAM
 
150
    static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
 
151
    int                     rv_mutex;
 
152
    int                     rv_copy;
 
153
    struct passwd          *pw_ptr;
 
154
#endif
 
155
    int                     got_err = 0;
 
156
    int                     got_none = 0;
 
157
 
 
158
    if ((user == NULL) || (*user == '\0') || (pw == NULL)
 
159
            || (buf == NULL) || (buflen <= 0)) {
 
160
        errno = EINVAL;
 
161
        return (-1);
 
162
    }
 
163
    errno = 0;
 
164
 
 
165
#if   HAVE_GETPWNAM_R_POSIX
 
166
    rv = getpwnam_r (user, pw, buf, buflen, &pw_ptr);
 
167
    /*
 
168
     *  POSIX.1-2001 does not call "user not found" an error, so the
 
169
     *    return value of getpwnam_r() is of limited value.  For example,
 
170
     *    "user not found" can be returned in the following ways:
 
171
     *    - Linux and SunOS: rv=0 and errno=0
 
172
     *    - OpenBSD: rv=1 and errno=EACCESS
 
173
     *    - AIX: rv=-1 and errno=ESRCH
 
174
     *  Strangely, the list of known errors is better defined; so these errors
 
175
     *    are tested for, and anything else is assumed to be "user not found".
 
176
     */
 
177
    if (pw_ptr == NULL) {
 
178
        if ((rv != 0)
 
179
            &&   ( (errno == EINTR)
 
180
                || (errno == EIO)
 
181
                || (errno == EMFILE)
 
182
                || (errno == ENFILE)
 
183
                || (errno == ENOMEM)
 
184
                || (errno == ERANGE) )) {
 
185
            got_err = 1;
 
186
        }
 
187
        else {
 
188
            got_none = 1;
 
189
        }
 
190
    }
 
191
#elif HAVE_GETPWNAM_R_AIX
 
192
    rv = getpwnam_r (user, pw, buf, buflen);
 
193
    if (rv != 0) {
 
194
        if (errno == ESRCH) {
 
195
            got_none = 1;
 
196
        }
 
197
        else {
 
198
            got_err = 1;
 
199
        }
 
200
    }
 
201
#elif HAVE_GETPWNAM_R_SUN
 
202
    pw_ptr = getpwnam_r (user, pw, buf, buflen);
 
203
    if (pw_ptr == NULL) {
 
204
        if (errno == 0) {
 
205
            got_none = 1;
 
206
        }
 
207
        else {
 
208
            got_err = 1;
 
209
        }
 
210
    }
 
211
#elif HAVE_GETPWNAM
 
212
    if ((rv_mutex = pthread_mutex_lock (&mutex)) != 0) {
 
213
        errno = rv_mutex;
 
214
        log_errno (EMUNGE_SNAFU, LOG_ERR, "Unable to lock xgetpwnam mutex");
 
215
    }
 
216
    pw_ptr = getpwnam (user);
 
217
    /*
 
218
     *  Refer to the HAVE_GETPWNAM_R_POSIX case regarding the "user not found"
 
219
     *    return value conundrum.
 
220
     *  The initial test for (errno != 0), while redundant, allows for the
 
221
     *    "user not found" case to short-circuit the rest of the if-condition
 
222
     *    on Linux / SunOS / Darwin.
 
223
     */
 
224
    if (pw_ptr == NULL) {
 
225
        if ((errno != 0)
 
226
            &&   ( (errno == EINTR)
 
227
                || (errno == EIO)
 
228
                || (errno == EMFILE)
 
229
                || (errno == ENFILE)
 
230
                || (errno == ENOMEM)
 
231
                || (errno == ERANGE) )) {
 
232
            got_err = 1;
 
233
        }
 
234
        else {
 
235
            got_none = 1;
 
236
        }
 
237
    }
 
238
    else {
 
239
        rv_copy = _xgetpwnam_copy (pw_ptr, pw, buf, buflen);
 
240
    }
 
241
    if ((rv_mutex = pthread_mutex_unlock (&mutex)) != 0) {
 
242
        errno = rv_mutex;
 
243
        log_errno (EMUNGE_SNAFU, LOG_ERR, "Unable to unlock xgetpwnam mutex");
 
244
    }
 
245
    if (rv_copy < 0) {
 
246
        return (-1);
 
247
    }
 
248
#endif
 
249
 
 
250
    if (got_none) {
 
251
        errno = ENOENT;
 
252
        return (-1);
 
253
    }
 
254
    if (got_err) {
 
255
        return (-1);
 
256
    }
 
257
    return (0);
 
258
}
 
259
 
 
260
 
 
261
/*****************************************************************************
 
262
 *  Private Functions
 
263
 *****************************************************************************/
 
264
 
 
265
static int
 
266
_xgetpwnam_get_buf_size (void)
 
267
{
 
268
/*  Returns the recommended size of the getpwnam_r() caller-provided buffer.
 
269
 */
 
270
    static int n = -1;
 
271
 
 
272
    if (n < 0) {
 
273
 
 
274
#if HAVE_SYSCONF
 
275
#ifdef _SC_GETPW_R_SIZE_MAX
 
276
        n = sysconf (_SC_GETPW_R_SIZE_MAX);
 
277
#endif /* _SC_GETPW_R_SIZE_MAX */
 
278
#endif /* HAVE_SYSCONF */
 
279
 
 
280
        if (n <= MINIMUM_PW_BUF_SIZE) {
 
281
            n = MINIMUM_PW_BUF_SIZE;
 
282
        }
 
283
        log_msg (LOG_DEBUG, "Using pw buf size of %d", n);
 
284
    }
 
285
    return (n);
 
286
}
 
287
 
 
288
 
 
289
static int
 
290
_xgetpwnam_copy (const struct passwd *src, struct passwd *dst,
 
291
                 char *buf, size_t buflen)
 
292
{
 
293
/*  Copies the passwd entry [src] into [dst], placing additional strings
 
294
 *    and whatnot into buffer [buf] of length [buflen].
 
295
 *  Returns 0 on success, or -1 on error (with errno).
 
296
 */
 
297
    char   *p = buf;
 
298
    size_t  nleft = buflen;
 
299
 
 
300
    assert (src != NULL);
 
301
    assert (dst != NULL);
 
302
    assert (buf != NULL);
 
303
    assert (buflen > 0);
 
304
 
 
305
    if (_xgetpwnam_copy_str
 
306
            (src->pw_name, &(dst->pw_name), &p, &nleft) < 0) {
 
307
        goto err;
 
308
    }
 
309
    if (_xgetpwnam_copy_str
 
310
            (src->pw_passwd, &(dst->pw_passwd), &p, &nleft) < 0) {
 
311
        goto err;
 
312
    }
 
313
    if (_xgetpwnam_copy_str
 
314
            (src->pw_gecos, &(dst->pw_gecos), &p, &nleft) < 0) {
 
315
        goto err;
 
316
    }
 
317
    if (_xgetpwnam_copy_str
 
318
            (src->pw_dir, &(dst->pw_dir), &p, &nleft) < 0) {
 
319
        goto err;
 
320
    }
 
321
    if (_xgetpwnam_copy_str
 
322
            (src->pw_shell, &(dst->pw_shell), &p, &nleft) < 0) {
 
323
        goto err;
 
324
    }
 
325
    dst->pw_uid = src->pw_uid;
 
326
    dst->pw_gid = src->pw_gid;
 
327
 
 
328
    assert (p <= buf + buflen);
 
329
    return (0);
 
330
 
 
331
err:
 
332
    errno = ERANGE;
 
333
    return (-1);
 
334
}
 
335
 
 
336
 
 
337
static int
 
338
_xgetpwnam_copy_str (const char *src, char **dst_p,
 
339
                     char **buf_p, size_t *buflen_p)
 
340
{
 
341
/*  Copies the string [src] into the buffer [*buf_p] of size [*buflen_p],
 
342
 *    setting the pointer [*dst_p] to the newly-copied string.  The values
 
343
 *    for [buf_p] and [buflen_p] are adjusted for the remaining buffer space.
 
344
 *  Note that [dst_p], [buf_p], and [buflen_p] are all passed by reference.
 
345
 *  Returns the number of bytes copied, or -1 on error.
 
346
 */
 
347
    size_t n;
 
348
 
 
349
    assert (dst_p != NULL);
 
350
    assert (buf_p != NULL);
 
351
    assert (*buf_p != NULL);
 
352
    assert (buflen_p != NULL);
 
353
 
 
354
    if (src == NULL) {
 
355
        *dst_p = NULL;
 
356
        return (0);
 
357
    }
 
358
    n = strlen (src) + 1;
 
359
    if (*buflen_p < n) {
 
360
        return (-1);
 
361
    }
 
362
    (void) strcpy (*buf_p, src);
 
363
    *dst_p = *buf_p;
 
364
    *buf_p += n;
 
365
    *buflen_p -= n;
 
366
    return (n);
 
367
}