From 613c6d26bd42dd8c2dd0664315be9551475b8864 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Wed, 18 Dec 2013 12:16:16 -0500 Subject: [PATCH] Fix incorrect error message reported for non-existent users Previously, lookups of non-existent user names could return "Success"; it will now return "User does not exist" by resetting errno. This also centralizes the user name lookup code in libpgport. Report and analysis by Nicolas Marchildon; patch by me --- contrib/pg_upgrade/util.c | 23 ++++------ src/backend/libpq/auth.c | 15 +++---- src/backend/main/main.c | 37 +--------------- src/bin/initdb/initdb.c | 37 +++------------- src/bin/psql/command.c | 5 ++- src/bin/psql/help.c | 24 ++--------- src/bin/scripts/clusterdb.c | 2 +- src/bin/scripts/common.c | 33 -------------- src/bin/scripts/common.h | 2 - src/bin/scripts/createdb.c | 2 +- src/bin/scripts/createlang.c | 2 +- src/bin/scripts/createuser.c | 2 +- src/bin/scripts/droplang.c | 2 +- src/bin/scripts/reindexdb.c | 4 +- src/bin/scripts/vacuumdb.c | 2 +- src/include/port.h | 4 ++ src/port/Makefile | 2 +- src/port/username.c | 84 ++++++++++++++++++++++++++++++++++++ src/tools/msvc/Mkvcbuild.pm | 4 +- 19 files changed, 129 insertions(+), 157 deletions(-) create mode 100644 src/port/username.c diff --git a/contrib/pg_upgrade/util.c b/contrib/pg_upgrade/util.c index a67bd64043..c3d45237fd 100644 --- a/contrib/pg_upgrade/util.c +++ b/contrib/pg_upgrade/util.c @@ -203,32 +203,25 @@ quote_identifier(const char *s) /* * get_user_info() - * (copied from initdb.c) find the current user */ int get_user_info(char **user_name) { int user_id; + char *errstr; #ifndef WIN32 - struct passwd *pw = getpwuid(geteuid()); - user_id = geteuid(); -#else /* the windows code */ - struct passwd_win32 - { - int pw_uid; - char pw_name[128]; - } pass_win32; - struct passwd_win32 *pw = &pass_win32; - DWORD pwname_size = sizeof(pass_win32.pw_name) - 1; - - GetUserName(pw->pw_name, &pwname_size); - +#else user_id = 1; #endif - *user_name = pg_strdup(pw->pw_name); + *user_name = get_user_name(&errstr); + if (!*user_name) + pg_fatal("%s\n", errstr); + + /* make a copy */ + *user_name = pg_strdup(*user_name); return user_id; } diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 2dbf7e53a1..6d11e576a4 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -1771,7 +1771,8 @@ auth_peer(hbaPort *port) char ident_user[IDENT_USERNAME_MAX + 1]; uid_t uid; gid_t gid; - struct passwd *pass; + const char *user_name; + char *errstr; errno = 0; if (getpeereid(port->sock, &uid, &gid) != 0) @@ -1788,17 +1789,15 @@ auth_peer(hbaPort *port) return STATUS_ERROR; } - pass = getpwuid(uid); - - if (pass == NULL) + user_name = get_user_name(&errstr); + if (!user_name) { - ereport(LOG, - (errmsg("local user with ID %d does not exist", - (int) uid))); + ereport(LOG, (errmsg_internal("%s", errstr))); + pfree(errstr); return STATUS_ERROR; } - strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1); + strlcpy(ident_user, user_name, IDENT_USERNAME_MAX + 1); return check_usermap(port->hba->usermap, port->user_name, ident_user, false); } diff --git a/src/backend/main/main.c b/src/backend/main/main.c index d71885dba9..376aa39a98 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -20,7 +20,6 @@ */ #include "postgres.h" -#include #include #if defined(__alpha) && defined(__osf__) /* no __alpha__ ? */ @@ -49,7 +48,6 @@ const char *progname; static void startup_hacks(const char *progname); static void help(const char *progname); static void check_root(const char *progname); -static char *get_current_username(const char *progname); /* @@ -191,7 +189,7 @@ main(int argc, char *argv[]) else if (argc > 1 && strcmp(argv[1], "--single") == 0) PostgresMain(argc, argv, NULL, /* no dbname */ - get_current_username(progname)); /* does not return */ + strdup(get_user_name_or_exit(progname))); /* does not return */ else PostmasterMain(argc, argv); /* does not return */ abort(); /* should not get here */ @@ -372,36 +370,3 @@ check_root(const char *progname) } #endif /* WIN32 */ } - - - -static char * -get_current_username(const char *progname) -{ -#ifndef WIN32 - struct passwd *pw; - - pw = getpwuid(geteuid()); - if (pw == NULL) - { - write_stderr("%s: invalid effective UID: %d\n", - progname, (int) geteuid()); - exit(1); - } - /* Allocate new memory because later getpwuid() calls can overwrite it. */ - return strdup(pw->pw_name); -#else - unsigned long namesize = 256 /* UNLEN */ + 1; - char *name; - - name = malloc(namesize); - if (!GetUserName(name, &namesize)) - { - write_stderr("%s: could not determine user name (GetUserName failed)\n", - progname); - exit(1); - } - - return name; -#endif -} diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index e6bb132bea..964d284bb6 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -770,15 +770,14 @@ exit_nicely(void) /* * find the current user * - * on unix make sure it isn't really root + * on unix make sure it isn't root */ static char * get_id(void) { + const char *username; + #ifndef WIN32 - - struct passwd *pw; - if (geteuid() == 0) /* 0 is root's uid */ { fprintf(stderr, @@ -789,35 +788,11 @@ get_id(void) progname); exit(1); } - - pw = getpwuid(geteuid()); - if (!pw) - { - fprintf(stderr, - _("%s: could not obtain information about current user: %s\n"), - progname, strerror(errno)); - exit(1); - } -#else /* the windows code */ - - struct passwd_win32 - { - int pw_uid; - char pw_name[128]; - } pass_win32; - struct passwd_win32 *pw = &pass_win32; - DWORD pwname_size = sizeof(pass_win32.pw_name) - 1; - - pw->pw_uid = 1; - if (!GetUserName(pw->pw_name, &pwname_size)) - { - fprintf(stderr, _("%s: could not get current user name: %s\n"), - progname, strerror(errno)); - exit(1); - } #endif - return pg_strdup(pw->pw_name); + username = get_user_name_or_exit(progname); + + return pg_strdup(username); } static char * diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 638d8cb5c3..d60a661543 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -265,10 +265,13 @@ exec_command(const char *cmd, #ifndef WIN32 struct passwd *pw; + errno = 0; /* clear errno before call */ pw = getpwuid(geteuid()); if (!pw) { - psql_error("could not get home directory: %s\n", strerror(errno)); + psql_error("could not get home directory for user id %d: %s\n", + (int) geteuid(), errno ? + strerror(errno) : "user does not exist"); exit(EXIT_FAILURE); } dir = pw->pw_dir; diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 30530f2e37..80b1ec0dfc 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -8,9 +8,6 @@ #include "postgres_fe.h" #ifndef WIN32 -#ifdef HAVE_PWD_H -#include /* for getpwuid() */ -#endif #include /* (ditto) */ #include /* for geteuid() */ #else @@ -52,31 +49,18 @@ usage(void) { const char *env; const char *user; - -#ifndef WIN32 - struct passwd *pw = NULL; -#endif + char *errstr; /* Find default user, in case we need it. */ user = getenv("PGUSER"); if (!user) { -#if !defined(WIN32) && !defined(__OS2__) - pw = getpwuid(geteuid()); - if (pw) - user = pw->pw_name; - else + user = get_user_name(&errstr); + if (!user) { - psql_error("could not get current user name: %s\n", strerror(errno)); + psql_error("%s\n", errstr); exit(EXIT_FAILURE); } -#else /* WIN32 */ - char buf[128]; - DWORD bufsize = sizeof(buf) - 1; - - if (GetUserName(buf, &bufsize)) - user = buf; -#endif /* WIN32 */ } printf(_("psql is the PostgreSQL interactive terminal.\n\n")); diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c index cd54e8f47f..e7065ce5df 100644 --- a/src/bin/scripts/clusterdb.c +++ b/src/bin/scripts/clusterdb.c @@ -160,7 +160,7 @@ main(int argc, char *argv[]) else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else - dbname = get_user_name(progname); + dbname = get_user_name_or_exit(progname); } if (tables.head != NULL) diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c index 4645bc137f..e57e5207c6 100644 --- a/src/bin/scripts/common.c +++ b/src/bin/scripts/common.c @@ -14,7 +14,6 @@ #include "postgres_fe.h" -#include #include #include @@ -29,38 +28,6 @@ static PGcancel *volatile cancelConn = NULL; static CRITICAL_SECTION cancelConnLock; #endif -/* - * Returns the current user name. - */ -const char * -get_user_name(const char *progname) -{ -#ifndef WIN32 - struct passwd *pw; - - pw = getpwuid(geteuid()); - if (!pw) - { - fprintf(stderr, _("%s: could not obtain information about current user: %s\n"), - progname, strerror(errno)); - exit(1); - } - return pw->pw_name; -#else - static char username[128]; /* remains after function exit */ - DWORD len = sizeof(username) - 1; - - if (!GetUserName(username, &len)) - { - fprintf(stderr, _("%s: could not get current user name: %s\n"), - progname, strerror(errno)); - exit(1); - } - return username; -#endif -} - - /* * Provide strictly harmonized handling of --help and --version * options. diff --git a/src/bin/scripts/common.h b/src/bin/scripts/common.h index 6cf490f748..a8a81f66b4 100644 --- a/src/bin/scripts/common.h +++ b/src/bin/scripts/common.h @@ -22,8 +22,6 @@ enum trivalue typedef void (*help_handler) (const char *progname); -extern const char *get_user_name(const char *progname); - extern void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp); diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c index 14cd128490..856a04d648 100644 --- a/src/bin/scripts/createdb.c +++ b/src/bin/scripts/createdb.c @@ -174,7 +174,7 @@ main(int argc, char *argv[]) else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else - dbname = get_user_name(progname); + dbname = get_user_name_or_exit(progname); } initPQExpBuffer(&sql); diff --git a/src/bin/scripts/createlang.c b/src/bin/scripts/createlang.c index ff544a803d..5cfba8e3d5 100644 --- a/src/bin/scripts/createlang.c +++ b/src/bin/scripts/createlang.c @@ -127,7 +127,7 @@ main(int argc, char *argv[]) else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else - dbname = get_user_name(progname); + dbname = get_user_name_or_exit(progname); } initPQExpBuffer(&sql); diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index 6180591770..e3ce0dc455 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -193,7 +193,7 @@ main(int argc, char *argv[]) if (getenv("PGUSER")) newuser = getenv("PGUSER"); else - newuser = get_user_name(progname); + newuser = get_user_name_or_exit(progname); } } diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c index de20317343..b9664a9185 100644 --- a/src/bin/scripts/droplang.c +++ b/src/bin/scripts/droplang.c @@ -126,7 +126,7 @@ main(int argc, char *argv[]) else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else - dbname = get_user_name(progname); + dbname = get_user_name_or_exit(progname); } initPQExpBuffer(&sql); diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index f7c09bebf8..4e762ea56f 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -188,7 +188,7 @@ main(int argc, char *argv[]) else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else - dbname = get_user_name(progname); + dbname = get_user_name_or_exit(progname); } reindex_system_catalogs(dbname, host, port, username, prompt_password, @@ -203,7 +203,7 @@ main(int argc, char *argv[]) else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else - dbname = get_user_name(progname); + dbname = get_user_name_or_exit(progname); } if (indexes.head != NULL) diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index 616d9339e1..8970ec6ad2 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -202,7 +202,7 @@ main(int argc, char *argv[]) else if (getenv("PGUSER")) dbname = getenv("PGUSER"); else - dbname = get_user_name(progname); + dbname = get_user_name_or_exit(progname); } if (tables.head != NULL) diff --git a/src/include/port.h b/src/include/port.h index 5ef4b0a0b1..473c4f6a7b 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -473,6 +473,10 @@ extern pqsigfunc pqsignal(int signo, pqsigfunc func); /* port/quotes.c */ extern char *escape_single_quotes_ascii(const char *src); +/* port/username.c */ +extern const char *get_user_name(char **errstr); +extern const char *get_user_name_or_exit(const char *progname); + /* port/wait_error.c */ extern char *wait_result_to_str(int exit_status); diff --git a/src/port/Makefile b/src/port/Makefile index 1be4ff57a2..a50e0af214 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -33,7 +33,7 @@ LIBS += $(PTHREAD_LIBS) OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o fls.o inet_net_ntop.o \ noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \ pgstrcasecmp.o pqsignal.o \ - qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o + qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o username.o # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND OBJS_SRV = $(OBJS:%.o=%_srv.o) diff --git a/src/port/username.c b/src/port/username.c new file mode 100644 index 0000000000..25dc9391c4 --- /dev/null +++ b/src/port/username.c @@ -0,0 +1,84 @@ +/*------------------------------------------------------------------------- + * + * username.c + * get user name + * + * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/port/username.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include +#include +#include +#include + + +/* + * Returns the current user name in a static buffer, or NULL on error and + * sets errstr + */ +const char * +get_user_name(char **errstr) +{ +#ifndef WIN32 + struct passwd *pw; + uid_t user_id = geteuid(); + + *errstr = NULL; + + errno = 0; /* clear errno before call */ + pw = getpwuid(user_id); + if (!pw) + { + *errstr = psprintf(_("failed to look up effective user id %d: %s"), + (int) user_id, errno ? strerror(errno) : + _("user does not exist")); + return NULL; + } + + return pw->pw_name; +#else + /* UNLEN = 256, 'static' variable remains after function exit */ + static char username[256 + 1]; + DWORD len = sizeof(username) - 1; + + if (!GetUserName(username, &len)) + { + *errstr = psprintf(_("user name lookup failure: %s"), strerror(errno)); + return NULL; + } + + return username; +#endif +} + + +/* + * Returns the current user name in a static buffer or exits + */ +const char * +get_user_name_or_exit(const char *progname) +{ + const char *user_name; + char *errstr; + + user_name = get_user_name(&errstr); + + if (!user_name) + { + fprintf(stderr, "%s: %s\n", progname, errstr); + exit(1); + } + return user_name; +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index bc7f4496e0..d6b6eaf158 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -70,8 +70,8 @@ sub mkvcbuild erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c pgcheckdir.c pg_crc.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c qsort.c qsort_arg.c quotes.c - sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c rint.c win32env.c - win32error.c win32setlocale.c); + sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c rint.c username.c + win32env.c win32error.c win32setlocale.c); our @pgcommonallfiles = qw( exec.c pgfnames.c psprintf.c relpath.c rmtree.c wait_error.c);