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.
9
* This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE).
10
* For details, see <http://munge.googlecode.com/>.
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.
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.
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
*****************************************************************************/
33
#endif /* HAVE_CONFIG_H */
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
40
#define _XOPEN_SOURCE_EXTENDED 1
41
#elif HAVE_GETPWNAM_R_SUN
42
#undef _POSIX_PTHREAD_SEMANTICS
46
#error "getpwnam() not supported"
59
/*****************************************************************************
61
*****************************************************************************/
64
#define _UNUSED_ __attribute__ ((unused))
70
/*****************************************************************************
72
*****************************************************************************/
74
#define MINIMUM_PW_BUF_SIZE 4096
77
/*****************************************************************************
79
*****************************************************************************/
81
static int _xgetpwnam_get_buf_size (void);
83
static int _xgetpwnam_copy (const struct passwd *src, struct passwd *dst,
84
char *buf, size_t buflen) _UNUSED_;
86
static int _xgetpwnam_copy_str (const char *src, char **dst_p,
87
char **buf_p, size_t *buflen_p) _UNUSED_;
90
/*****************************************************************************
92
*****************************************************************************/
95
xgetpwnam_buf_create (char **buf_p, int *buflen_p)
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).
101
static int pw_buf_size = -1;
104
if ((buf_p == NULL) || (buflen_p == NULL)) {
108
if (pw_buf_size < 0) {
109
pw_buf_size = _xgetpwnam_get_buf_size ();
111
buf = malloc (pw_buf_size);
116
*buflen_p = pw_buf_size;
122
xgetpwnam_buf_destroy (char *buf)
124
/* Destroys the buffer [buf].
134
xgetpwnam (const char *user, struct passwd *pw, char *buf, size_t buflen)
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.
142
#if HAVE_GETPWNAM_R_POSIX
144
struct passwd *pw_ptr;
145
#elif HAVE_GETPWNAM_R_AIX
147
#elif HAVE_GETPWNAM_R_SUN
148
struct passwd *pw_ptr;
150
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
153
struct passwd *pw_ptr;
158
if ((user == NULL) || (*user == '\0') || (pw == NULL)
159
|| (buf == NULL) || (buflen <= 0)) {
165
#if HAVE_GETPWNAM_R_POSIX
166
rv = getpwnam_r (user, pw, buf, buflen, &pw_ptr);
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".
177
if (pw_ptr == NULL) {
179
&& ( (errno == EINTR)
184
|| (errno == ERANGE) )) {
191
#elif HAVE_GETPWNAM_R_AIX
192
rv = getpwnam_r (user, pw, buf, buflen);
194
if (errno == ESRCH) {
201
#elif HAVE_GETPWNAM_R_SUN
202
pw_ptr = getpwnam_r (user, pw, buf, buflen);
203
if (pw_ptr == NULL) {
212
if ((rv_mutex = pthread_mutex_lock (&mutex)) != 0) {
214
log_errno (EMUNGE_SNAFU, LOG_ERR, "Unable to lock xgetpwnam mutex");
216
pw_ptr = getpwnam (user);
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.
224
if (pw_ptr == NULL) {
226
&& ( (errno == EINTR)
231
|| (errno == ERANGE) )) {
239
rv_copy = _xgetpwnam_copy (pw_ptr, pw, buf, buflen);
241
if ((rv_mutex = pthread_mutex_unlock (&mutex)) != 0) {
243
log_errno (EMUNGE_SNAFU, LOG_ERR, "Unable to unlock xgetpwnam mutex");
261
/*****************************************************************************
263
*****************************************************************************/
266
_xgetpwnam_get_buf_size (void)
268
/* Returns the recommended size of the getpwnam_r() caller-provided buffer.
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 */
280
if (n <= MINIMUM_PW_BUF_SIZE) {
281
n = MINIMUM_PW_BUF_SIZE;
283
log_msg (LOG_DEBUG, "Using pw buf size of %d", n);
290
_xgetpwnam_copy (const struct passwd *src, struct passwd *dst,
291
char *buf, size_t buflen)
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).
298
size_t nleft = buflen;
300
assert (src != NULL);
301
assert (dst != NULL);
302
assert (buf != NULL);
305
if (_xgetpwnam_copy_str
306
(src->pw_name, &(dst->pw_name), &p, &nleft) < 0) {
309
if (_xgetpwnam_copy_str
310
(src->pw_passwd, &(dst->pw_passwd), &p, &nleft) < 0) {
313
if (_xgetpwnam_copy_str
314
(src->pw_gecos, &(dst->pw_gecos), &p, &nleft) < 0) {
317
if (_xgetpwnam_copy_str
318
(src->pw_dir, &(dst->pw_dir), &p, &nleft) < 0) {
321
if (_xgetpwnam_copy_str
322
(src->pw_shell, &(dst->pw_shell), &p, &nleft) < 0) {
325
dst->pw_uid = src->pw_uid;
326
dst->pw_gid = src->pw_gid;
328
assert (p <= buf + buflen);
338
_xgetpwnam_copy_str (const char *src, char **dst_p,
339
char **buf_p, size_t *buflen_p)
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.
349
assert (dst_p != NULL);
350
assert (buf_p != NULL);
351
assert (*buf_p != NULL);
352
assert (buflen_p != NULL);
358
n = strlen (src) + 1;
362
(void) strcpy (*buf_p, src);