aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/username.c12
-rw-r--r--src/include/port.h2
-rw-r--r--src/interfaces/libpq/fe-auth.c50
-rw-r--r--src/interfaces/libpq/fe-auth.h2
-rw-r--r--src/interfaces/libpq/fe-connect.c54
-rw-r--r--src/port/path.c3
-rw-r--r--src/port/thread.c17
7 files changed, 97 insertions, 43 deletions
diff --git a/src/common/username.c b/src/common/username.c
index ee5ef1c0727..686a6a43c51 100644
--- a/src/common/username.c
+++ b/src/common/username.c
@@ -26,8 +26,8 @@
#include "common/username.h"
/*
- * Returns the current user name in a static buffer, or NULL on error and
- * sets errstr
+ * Returns the current user name in a static buffer
+ * On error, returns NULL and sets *errstr to point to a palloc'd message
*/
const char *
get_user_name(char **errstr)
@@ -50,15 +50,17 @@ get_user_name(char **errstr)
return pw->pw_name;
#else
- /* UNLEN = 256, 'static' variable remains after function exit */
+ /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
+ /* "static" variable remains after function exit */
static char username[256 + 1];
- DWORD len = sizeof(username) - 1;
+ DWORD len = sizeof(username);
*errstr = NULL;
if (!GetUserName(username, &len))
{
- *errstr = psprintf(_("user name lookup failure: %s"), strerror(errno));
+ *errstr = psprintf(_("user name lookup failure: error code %lu"),
+ GetLastError());
return NULL;
}
diff --git a/src/include/port.h b/src/include/port.h
index 1d53e4ec0b8..26d7fcd6721 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -433,7 +433,7 @@ extern void srandom(unsigned int seed);
/* thread.h */
extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen);
-#if !defined(WIN32) || defined(__CYGWIN__)
+#ifndef WIN32
extern int pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer,
size_t buflen, struct passwd ** result);
#endif
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 179793e2a0e..8927df4f064 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -714,22 +714,26 @@ pg_fe_sendauth(AuthRequest areq, PGconn *conn)
/*
* pg_fe_getauthname
*
- * Returns a pointer to dynamic space containing whatever name the user
- * has authenticated to the system. If there is an error, return NULL.
+ * 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 put a suitable error message in *errorMessage if that's not NULL.
*/
char *
-pg_fe_getauthname(void)
+pg_fe_getauthname(PQExpBuffer errorMessage)
{
+ char *result = NULL;
const char *name = NULL;
- char *authn;
#ifdef WIN32
- char username[128];
- DWORD namesize = sizeof(username) - 1;
+ /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
+ 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
/*
@@ -741,24 +745,42 @@ pg_fe_getauthname(void)
*/
pglock_thread();
- /*
- * We document PQconndefaults() to return NULL for a memory allocation
- * failure. We don't have an API to return a user name lookup failure, so
- * we just assume it always succeeds.
- */
#ifdef WIN32
if (GetUserName(username, &namesize))
name = username;
+ else if (errorMessage)
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("user name lookup failure: error code %lu\n"),
+ GetLastError());
#else
- if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pw) == 0)
+ pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
+ if (pw != NULL)
name = pw->pw_name;
+ else if (errorMessage)
+ {
+ if (pwerr != 0)
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("could not look up local user ID %d: %s\n"),
+ (int) user_id,
+ pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf)));
+ else
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("local user with ID %d does not exist\n"),
+ (int) user_id);
+ }
#endif
- authn = name ? strdup(name) : NULL;
+ if (name)
+ {
+ result = strdup(name);
+ if (result == NULL && errorMessage)
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("out of memory\n"));
+ }
pgunlock_thread();
- return authn;
+ return result;
}
diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h
index 59b6c16a6d4..8d35767f7a0 100644
--- a/src/interfaces/libpq/fe-auth.h
+++ b/src/interfaces/libpq/fe-auth.h
@@ -19,6 +19,6 @@
extern int pg_fe_sendauth(AuthRequest areq, PGconn *conn);
-extern char *pg_fe_getauthname(void);
+extern char *pg_fe_getauthname(PQExpBuffer errorMessage);
#endif /* FE_AUTH_H */
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index b2f556c1c30..25961b1f10d 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -765,10 +765,26 @@ static bool
connectOptions2(PGconn *conn)
{
/*
+ * If user name was not given, fetch it. (Most likely, the fetch will
+ * fail, since the only way we get here is if pg_fe_getauthname() failed
+ * during conninfo_add_defaults(). But now we want an error message.)
+ */
+ if (conn->pguser == NULL || conn->pguser[0] == '\0')
+ {
+ if (conn->pguser)
+ free(conn->pguser);
+ conn->pguser = pg_fe_getauthname(&conn->errorMessage);
+ if (!conn->pguser)
+ {
+ conn->status = CONNECTION_BAD;
+ return false;
+ }
+ }
+
+ /*
* If database name was not given, default it to equal user name
*/
- if ((conn->dbName == NULL || conn->dbName[0] == '\0')
- && conn->pguser != NULL)
+ if (conn->dbName == NULL || conn->dbName[0] == '\0')
{
if (conn->dbName)
free(conn->dbName);
@@ -1967,6 +1983,7 @@ keep_going: /* We will come back to here until there is
char pwdbuf[BUFSIZ];
struct passwd pass_buf;
struct passwd *pass;
+ int passerr;
uid_t uid;
gid_t gid;
@@ -1987,13 +2004,18 @@ keep_going: /* We will come back to here until there is
goto error_return;
}
- pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
-
+ passerr = pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
if (pass == NULL)
{
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("local user with ID %d does not exist\n"),
- (int) uid);
+ if (passerr != 0)
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not look up local user ID %d: %s\n"),
+ (int) uid,
+ pqStrerror(passerr, sebuf, sizeof(sebuf)));
+ else
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("local user with ID %d does not exist\n"),
+ (int) uid);
goto error_return;
}
@@ -4605,18 +4627,15 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage)
}
/*
- * Special handling for "user" option
+ * Special handling for "user" option. Note that if pg_fe_getauthname
+ * fails, we just leave the value as NULL; there's no need for this to
+ * be an error condition if the caller provides a user name. The only
+ * reason we do this now at all is so that callers of PQconndefaults
+ * will see a correct default (barring error, of course).
*/
if (strcmp(option->keyword, "user") == 0)
{
- option->val = pg_fe_getauthname();
- if (!option->val)
- {
- if (errorMessage)
- printfPQExpBuffer(errorMessage,
- libpq_gettext("out of memory\n"));
- return false;
- }
+ option->val = pg_fe_getauthname(NULL);
continue;
}
}
@@ -5843,7 +5862,8 @@ pqGetHomeDirectory(char *buf, int bufsize)
struct passwd pwdstr;
struct passwd *pwd = NULL;
- if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
+ (void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
+ if (pwd == NULL)
return false;
strlcpy(buf, pwd->pw_dir, bufsize);
return true;
diff --git a/src/port/path.c b/src/port/path.c
index e8faac3a260..d0f72df29c2 100644
--- a/src/port/path.c
+++ b/src/port/path.c
@@ -777,7 +777,8 @@ get_home_path(char *ret_path)
struct passwd pwdstr;
struct passwd *pwd = NULL;
- if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
+ (void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
+ if (pwd == NULL)
return false;
strlcpy(ret_path, pwd->pw_dir, MAXPGPATH);
return true;
diff --git a/src/port/thread.c b/src/port/thread.c
index 1568803d626..aab74516ac9 100644
--- a/src/port/thread.c
+++ b/src/port/thread.c
@@ -83,6 +83,12 @@ pqStrerror(int errnum, char *strerrbuf, size_t buflen)
/*
* Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
* behaviour, if it is not available or required.
+ *
+ * Per POSIX, the possible cases are:
+ * success: returns zero, *result is non-NULL
+ * uid not found: returns zero, *result is NULL
+ * error during lookup: returns an errno code, *result is NULL
+ * (caller should *not* assume that the errno variable is set)
*/
#ifndef WIN32
int
@@ -93,22 +99,25 @@ pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer,
#ifdef GETPWUID_R_5ARG
/* POSIX version */
- getpwuid_r(uid, resultbuf, buffer, buflen, result);
+ return getpwuid_r(uid, resultbuf, buffer, buflen, result);
#else
/*
* Early POSIX draft of getpwuid_r() returns 'struct passwd *'.
* getpwuid_r(uid, resultbuf, buffer, buflen)
*/
+ errno = 0;
*result = getpwuid_r(uid, resultbuf, buffer, buflen);
+ /* paranoia: ensure we return zero on success */
+ return (*result == NULL) ? errno : 0;
#endif
#else
-
/* no getpwuid_r() available, just use getpwuid() */
+ errno = 0;
*result = getpwuid(uid);
+ /* paranoia: ensure we return zero on success */
+ return (*result == NULL) ? errno : 0;
#endif
-
- return (*result == NULL) ? -1 : 0;
}
#endif