#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <pwd.h>
#include <unistd.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
+#include <pwd.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h> /* for write() */
#define PG_PORT_H
#include <ctype.h>
-#include <netdb.h>
-#include <pwd.h>
/*
* Windows has enough specialized port stuff that we push most of it off
#define RTLD_GLOBAL 0
#endif
-/* thread.h */
+/* thread.c */
#ifndef WIN32
-extern int pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
- size_t buflen, struct passwd **result);
+extern bool pg_get_user_name(uid_t user_id, char *buffer, size_t buflen);
+extern bool pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen);
#endif
-extern int pqGethostbyname(const char *name,
- struct hostent *resultbuf,
- char *buffer, size_t buflen,
- struct hostent **result,
- int *herrno);
-
extern void pg_qsort(void *base, size_t nel, size_t elsize,
int (*cmp) (const void *, const void *));
extern int pg_qsort_strcmp(const void *a, const void *b);
#ifndef MAXHOSTNAMELEN
#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
-#include <pwd.h>
#endif
#include "common/md5.h"
/*
- * pg_fe_getauthname
+ * pg_fe_getusername
*
- * Returns a pointer to malloc'd space containing whatever name the user
- * has authenticated to the system. If there is an error, return NULL,
- * and append a suitable error message to *errorMessage if that's not NULL.
+ * Returns a pointer to malloc'd space containing the name of the
+ * specified user_id. If there is an error, return NULL, and append
+ * a suitable error message to *errorMessage if that's not NULL.
+ *
+ * Caution: on Windows, the user_id argument is ignored, and we always
+ * fetch the current user's name.
*/
char *
-pg_fe_getauthname(PQExpBuffer errorMessage)
+pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage)
{
char *result = NULL;
const char *name = NULL;
char username[256 + 1];
DWORD namesize = sizeof(username);
#else
- uid_t user_id = geteuid();
char pwdbuf[BUFSIZ];
- struct passwd pwdstr;
- struct passwd *pw = NULL;
- int pwerr;
#endif
/*
* Some users are using configure --enable-thread-safety-force, so we
* might as well do the locking within our library to protect
- * pqGetpwuid(). In fact, application developers can use getpwuid() in
+ * getpwuid(). In fact, application developers can use getpwuid() in
* their application if they use the locking call we provide, or install
* their own locking function using PQregisterThreadLock().
*/
libpq_gettext("user name lookup failure: error code %lu\n"),
GetLastError());
#else
- pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
- if (pw != NULL)
- name = pw->pw_name;
+ if (pg_get_user_name(user_id, pwdbuf, sizeof(pwdbuf)))
+ name = pwdbuf;
else if (errorMessage)
- {
- if (pwerr != 0)
- appendPQExpBuffer(errorMessage,
- libpq_gettext("could not look up local user ID %d: %s\n"),
- (int) user_id,
- strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
- else
- appendPQExpBuffer(errorMessage,
- libpq_gettext("local user with ID %d does not exist\n"),
- (int) user_id);
- }
+ appendPQExpBuffer(errorMessage, "%s\n", pwdbuf);
#endif
if (name)
return result;
}
+/*
+ * pg_fe_getauthname
+ *
+ * Returns a pointer to malloc'd space containing whatever name the user
+ * has authenticated to the system. If there is an error, return NULL,
+ * and append a suitable error message to *errorMessage if that's not NULL.
+ */
+char *
+pg_fe_getauthname(PQExpBuffer errorMessage)
+{
+#ifdef WIN32
+ return pg_fe_getusername(0, errorMessage);
+#else
+ return pg_fe_getusername(geteuid(), errorMessage);
+#endif
+}
+
/*
* PQencryptPassword -- exported routine to encrypt a password with MD5
/* Prototypes for functions in fe-auth.c */
extern int pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn);
+extern char *pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage);
extern char *pg_fe_getauthname(PQExpBuffer errorMessage);
/* Mechanisms in fe-auth-scram.c */
IS_AF_UNIX(conn->raddr.addr.ss_family))
{
#ifndef WIN32
- char pwdbuf[BUFSIZ];
- struct passwd pass_buf;
- struct passwd *pass;
- int passerr;
+ char *remote_username;
#endif
uid_t uid;
gid_t gid;
}
#ifndef WIN32
- passerr = pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
- if (pass == NULL)
- {
- if (passerr != 0)
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not look up local user ID %d: %s\n"),
- (int) uid,
- strerror_r(passerr, sebuf, sizeof(sebuf)));
- else
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("local user with ID %d does not exist\n"),
- (int) uid);
- goto error_return;
- }
+ remote_username = pg_fe_getusername(uid,
+ &conn->errorMessage);
+ if (remote_username == NULL)
+ goto error_return; /* message already logged */
- if (strcmp(pass->pw_name, conn->requirepeer) != 0)
+ if (strcmp(remote_username, conn->requirepeer) != 0)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("requirepeer specifies \"%s\", but actual peer user name is \"%s\"\n"),
- conn->requirepeer, pass->pw_name);
+ conn->requirepeer, remote_username);
+ free(remote_username);
goto error_return;
}
+ free(remote_username);
#else /* WIN32 */
/* should have failed with ENOSYS above */
Assert(false);
home = getenv("HOME");
if (home == NULL || home[0] == '\0')
- {
- char pwdbuf[BUFSIZ];
- struct passwd pwdstr;
- struct passwd *pwd = NULL;
-
- (void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
- if (pwd == NULL)
- return false;
- home = pwd->pw_dir;
- }
+ return pg_get_user_home_dir(geteuid(), buf, bufsize);
strlcpy(buf, home, bufsize);
return true;
#else
rm -f $@
$(AR) $(AROPT) $@ $^
+# getaddrinfo.o and getaddrinfo_shlib.o need PTHREAD_CFLAGS (but getaddrinfo_srv.o does not)
+getaddrinfo.o: CFLAGS+=$(PTHREAD_CFLAGS)
+getaddrinfo_shlib.o: CFLAGS+=$(PTHREAD_CFLAGS)
+
# thread.o and thread_shlib.o need PTHREAD_CFLAGS (but thread_srv.o does not)
thread.o: CFLAGS+=$(PTHREAD_CFLAGS)
thread_shlib.o: CFLAGS+=$(PTHREAD_CFLAGS)
#include "port/pg_bswap.h"
+#ifdef FRONTEND
+static int pqGethostbyname(const char *name,
+ struct hostent *resultbuf,
+ char *buffer, size_t buflen,
+ struct hostent **result,
+ int *herrno);
+#endif
+
#ifdef WIN32
/*
* The native routines may or may not exist on the Windows platform we are on,
return 0;
}
+
+/*
+ * Wrapper around gethostbyname() or gethostbyname_r() to mimic
+ * POSIX gethostbyname_r() behaviour, if it is not available or required.
+ */
+#ifdef FRONTEND
+static int
+pqGethostbyname(const char *name,
+ struct hostent *resultbuf,
+ char *buffer, size_t buflen,
+ struct hostent **result,
+ int *herrno)
+{
+#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R)
+
+ /*
+ * broken (well early POSIX draft) gethostbyname_r() which returns 'struct
+ * hostent *'
+ */
+ *result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno);
+ return (*result == NULL) ? -1 : 0;
+#else
+
+ /* no gethostbyname_r(), just use gethostbyname() */
+ *result = gethostbyname(name);
+
+ if (*result != NULL)
+ *herrno = h_errno;
+
+ if (*result != NULL)
+ return 0;
+ else
+ return -1;
+#endif
+}
+#endif /* FRONTEND */
home = getenv("HOME");
if (home == NULL || home[0] == '\0')
- {
- char pwdbuf[BUFSIZ];
- struct passwd pwdstr;
- struct passwd *pwd = NULL;
-
- (void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
- if (pwd == NULL)
- return false;
- home = pwd->pw_dir;
- }
+ return pg_get_user_home_dir(geteuid(), ret_path, MAXPGPATH);
strlcpy(ret_path, home, MAXPGPATH);
return true;
#else
* use *_r function names if they exit
* (*_THREADSAFE=yes)
* use non-*_r functions if they are thread-safe
- *
- * One thread-safe solution for gethostbyname() might be to use getaddrinfo().
*/
+#ifndef WIN32
/*
* Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
* error during lookup: returns an errno code, *result is NULL
* (caller should *not* assume that the errno variable is set)
*/
-#ifndef WIN32
-int
+static int
pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
size_t buflen, struct passwd **result)
{
return (*result == NULL) ? errno : 0;
#endif
}
-#endif
/*
- * Wrapper around gethostbyname() or gethostbyname_r() to mimic
- * POSIX gethostbyname_r() behaviour, if it is not available or required.
- * This function is called _only_ by our getaddrinfo() portability function.
+ * pg_get_user_name - get the name of the user with the given ID
+ *
+ * On success, the user name is returned into the buffer (of size buflen),
+ * and "true" is returned. On failure, a localized error message is
+ * returned into the buffer, and "false" is returned.
*/
-#ifndef HAVE_GETADDRINFO
-int
-pqGethostbyname(const char *name,
- struct hostent *resultbuf,
- char *buffer, size_t buflen,
- struct hostent **result,
- int *herrno)
+bool
+pg_get_user_name(uid_t user_id, char *buffer, size_t buflen)
{
-#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R)
-
- /*
- * broken (well early POSIX draft) gethostbyname_r() which returns 'struct
- * hostent *'
- */
- *result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno);
- return (*result == NULL) ? -1 : 0;
-#else
+ char pwdbuf[BUFSIZ];
+ struct passwd pwdstr;
+ struct passwd *pw = NULL;
+ int pwerr;
- /* no gethostbyname_r(), just use gethostbyname() */
- *result = gethostbyname(name);
+ pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
+ if (pw != NULL)
+ {
+ strlcpy(buffer, pw->pw_name, buflen);
+ return true;
+ }
+ if (pwerr != 0)
+ snprintf(buffer, buflen,
+ _("could not look up local user ID %d: %s"),
+ (int) user_id,
+ strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
+ else
+ snprintf(buffer, buflen,
+ _("local user with ID %d does not exist"),
+ (int) user_id);
+ return false;
+}
- if (*result != NULL)
- *herrno = h_errno;
+/*
+ * pg_get_user_home_dir - get the home directory of the user with the given ID
+ *
+ * On success, the directory path is returned into the buffer (of size buflen),
+ * and "true" is returned. On failure, a localized error message is
+ * returned into the buffer, and "false" is returned.
+ *
+ * Note that this does not incorporate the common behavior of checking
+ * $HOME first, since it's independent of which user_id is queried.
+ */
+bool
+pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen)
+{
+ char pwdbuf[BUFSIZ];
+ struct passwd pwdstr;
+ struct passwd *pw = NULL;
+ int pwerr;
- if (*result != NULL)
- return 0;
+ pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
+ if (pw != NULL)
+ {
+ strlcpy(buffer, pw->pw_dir, buflen);
+ return true;
+ }
+ if (pwerr != 0)
+ snprintf(buffer, buflen,
+ _("could not look up local user ID %d: %s"),
+ (int) user_id,
+ strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
else
- return -1;
-#endif
+ snprintf(buffer, buflen,
+ _("local user with ID %d does not exist"),
+ (int) user_id);
+ return false;
}
-#endif
+#endif /* !WIN32 */
pread.c preadv.c pwrite.c pwritev.c pg_bitutils.c
pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
pqsignal.c mkdtemp.c qsort.c qsort_arg.c bsearch_arg.c quotes.c system.c
- strerror.c tar.c thread.c
+ strerror.c tar.c
win32env.c win32error.c win32ntdll.c
win32security.c win32setlocale.c win32stat.c);