diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c index 91b7958c48e..5a884e29049 100644 --- a/contrib/oid2name/oid2name.c +++ b/contrib/oid2name/oid2name.c @@ -12,6 +12,7 @@ #include "catalog/pg_class_d.h" #include "common/connect.h" #include "common/logging.h" +#include "common/string.h" #include "getopt_long.h" #include "libpq-fe.h" #include "pg_getopt.h" @@ -293,8 +294,7 @@ PGconn * sql_conn(struct options *my_opts) { PGconn *conn; - bool have_password = false; - char password[100]; + char *password = NULL; bool new_pass; PGresult *res; @@ -316,7 +316,7 @@ sql_conn(struct options *my_opts) keywords[2] = "user"; values[2] = my_opts->username; keywords[3] = "password"; - values[3] = have_password ? password : NULL; + values[3] = password; keywords[4] = "dbname"; values[4] = my_opts->dbname; keywords[5] = "fallback_application_name"; @@ -336,11 +336,10 @@ sql_conn(struct options *my_opts) if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - !have_password) + !password) { PQfinish(conn); - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + password = simple_prompt("Password: ", false); new_pass = true; } } while (new_pass); diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c index e4019fafaa9..532cc596c41 100644 --- a/contrib/vacuumlo/vacuumlo.c +++ b/contrib/vacuumlo/vacuumlo.c @@ -24,6 +24,7 @@ #include "catalog/pg_class_d.h" #include "common/connect.h" #include "common/logging.h" +#include "common/string.h" #include "getopt_long.h" #include "libpq-fe.h" #include "pg_getopt.h" @@ -69,15 +70,11 @@ vacuumlo(const char *database, const struct _param *param) int i; bool new_pass; bool success = true; - static bool have_password = false; - static char password[100]; + static char *password = NULL; /* Note: password can be carried over from a previous call */ - if (param->pg_prompt == TRI_YES && !have_password) - { - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; - } + if (param->pg_prompt == TRI_YES && !password) + password = simple_prompt("Password: ", false); /* * Start the connection. Loop until we have a password if requested by @@ -97,7 +94,7 @@ vacuumlo(const char *database, const struct _param *param) keywords[2] = "user"; values[2] = param->pg_user; keywords[3] = "password"; - values[3] = have_password ? password : NULL; + values[3] = password; keywords[4] = "dbname"; values[4] = database; keywords[5] = "fallback_application_name"; @@ -115,12 +112,11 @@ vacuumlo(const char *database, const struct _param *param) if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - !have_password && + !password && param->pg_prompt != TRI_NO) { PQfinish(conn); - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + password = simple_prompt("Password: ", false); new_pass = true; } } while (new_pass); diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 02b6c3f127c..36565df4fc1 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -698,7 +698,7 @@ recv_password_packet(Port *port) } initStringInfo(&buf); - if (pq_getmessage(&buf, 1000)) /* receive password */ + if (pq_getmessage(&buf, 0)) /* receive password */ { /* EOF - pq_getmessage already logged a suitable message */ pfree(buf.data); diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 786672b1b65..73ddf408654 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -67,6 +67,7 @@ #include "common/file_utils.h" #include "common/logging.h" #include "common/restricted_token.h" +#include "common/string.h" #include "common/username.h" #include "fe_utils/string_utils.h" #include "getaddrinfo.h" @@ -1481,23 +1482,25 @@ setup_auth(FILE *cmdfd) static void get_su_pwd(void) { - char pwd1[100]; - char pwd2[100]; + char *pwd1; if (pwprompt) { /* * Read password from terminal */ + char *pwd2; + printf("\n"); fflush(stdout); - simple_prompt("Enter new superuser password: ", pwd1, sizeof(pwd1), false); - simple_prompt("Enter it again: ", pwd2, sizeof(pwd2), false); + pwd1 = simple_prompt("Enter new superuser password: ", false); + pwd2 = simple_prompt("Enter it again: ", false); if (strcmp(pwd1, pwd2) != 0) { fprintf(stderr, _("Passwords didn't match.\n")); exit(1); } + free(pwd2); } else { @@ -1510,7 +1513,6 @@ get_su_pwd(void) * for now. */ FILE *pwf = fopen(pwfilename, "r"); - int i; if (!pwf) { @@ -1518,7 +1520,8 @@ get_su_pwd(void) pwfilename); exit(1); } - if (!fgets(pwd1, sizeof(pwd1), pwf)) + pwd1 = pg_get_line(pwf); + if (!pwd1) { if (ferror(pwf)) pg_log_error("could not read password from file \"%s\": %m", @@ -1530,12 +1533,10 @@ get_su_pwd(void) } fclose(pwf); - i = strlen(pwd1); - while (i > 0 && (pwd1[i - 1] == '\r' || pwd1[i - 1] == '\n')) - pwd1[--i] = '\0'; + (void) pg_strip_crlf(pwd1); } - superuser_password = pg_strdup(pwd1); + superuser_password = pwd1; } /* diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c index c08003e7f2c..be653ebb2d9 100644 --- a/src/bin/pg_basebackup/streamutil.c +++ b/src/bin/pg_basebackup/streamutil.c @@ -22,6 +22,7 @@ #include "common/fe_memutils.h" #include "common/file_perm.h" #include "common/logging.h" +#include "common/string.h" #include "datatype/timestamp.h" #include "port/pg_bswap.h" #include "pqexpbuffer.h" @@ -49,8 +50,7 @@ char *dbuser = NULL; char *dbport = NULL; char *dbname = NULL; int dbgetpassword = 0; /* 0=auto, -1=never, 1=always */ -static bool have_password = false; -static char password[100]; +static char *password = NULL; PGconn *conn = NULL; /* @@ -150,20 +150,21 @@ GetConnection(void) } /* If -W was given, force prompt for password, but only the first time */ - need_password = (dbgetpassword == 1 && !have_password); + need_password = (dbgetpassword == 1 && !password); do { /* Get a new password if appropriate */ if (need_password) { - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + if (password) + free(password); + password = simple_prompt("Password: ", false); need_password = false; } /* Use (or reuse, on a subsequent connection) password if we have it */ - if (have_password) + if (password) { keywords[i] = "password"; values[i] = password; diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c index 94af11b80a3..12899e26e29 100644 --- a/src/bin/pg_dump/pg_backup_db.c +++ b/src/bin/pg_dump/pg_backup_db.c @@ -18,6 +18,7 @@ #endif #include "common/connect.h" +#include "common/string.h" #include "dumputils.h" #include "fe_utils/string_utils.h" #include "parallel.h" @@ -122,7 +123,6 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) const char *newdb; const char *newuser; char *password; - char passbuf[100]; bool new_pass; if (!reqdb) @@ -141,10 +141,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) password = AH->savedPassword; if (AH->promptPassword == TRI_YES && password == NULL) - { - simple_prompt("Password: ", passbuf, sizeof(passbuf), false); - password = passbuf; - } + password = simple_prompt("Password: ", false); initPQExpBuffer(&connstr); appendPQExpBufferStr(&connstr, "dbname="); @@ -191,8 +188,9 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) if (AH->promptPassword != TRI_NO) { - simple_prompt("Password: ", passbuf, sizeof(passbuf), false); - password = passbuf; + if (password && password != AH->savedPassword) + free(password); + password = simple_prompt("Password: ", false); } else fatal("connection needs password"); @@ -201,6 +199,9 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) } } while (new_pass); + if (password && password != AH->savedPassword) + free(password); + /* * We want to remember connection's actual password, whether or not we got * it by prompting. So we don't just store the password variable. @@ -242,7 +243,6 @@ ConnectDatabase(Archive *AHX, { ArchiveHandle *AH = (ArchiveHandle *) AHX; char *password; - char passbuf[100]; bool new_pass; if (AH->connection) @@ -251,10 +251,8 @@ ConnectDatabase(Archive *AHX, password = AH->savedPassword; if (prompt_password == TRI_YES && password == NULL) - { - simple_prompt("Password: ", passbuf, sizeof(passbuf), false); - password = passbuf; - } + password = simple_prompt("Password: ", false); + AH->promptPassword = prompt_password; /* @@ -293,8 +291,7 @@ ConnectDatabase(Archive *AHX, prompt_password != TRI_NO) { PQfinish(AH->connection); - simple_prompt("Password: ", passbuf, sizeof(passbuf), false); - password = passbuf; + password = simple_prompt("Password: ", false); new_pass = true; } } while (new_pass); @@ -309,6 +306,9 @@ ConnectDatabase(Archive *AHX, PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH, ALWAYS_SECURE_SEARCH_PATH_SQL)); + if (password && password != AH->savedPassword) + free(password); + /* * We want to remember connection's actual password, whether or not we got * it by prompting. So we don't just store the password variable. diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 2c82b39af0d..97d2b8dac1c 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -21,6 +21,7 @@ #include "common/connect.h" #include "common/file_utils.h" #include "common/logging.h" +#include "common/string.h" #include "dumputils.h" #include "fe_utils/string_utils.h" #include "getopt_long.h" @@ -1643,14 +1644,10 @@ connectDatabase(const char *dbname, const char *connection_string, const char **keywords = NULL; const char **values = NULL; PQconninfoOption *conn_opts = NULL; - static bool have_password = false; - static char password[100]; + static char *password = NULL; - if (prompt_password == TRI_YES && !have_password) - { - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; - } + if (prompt_password == TRI_YES && !password) + password = simple_prompt("Password: ", false); /* * Start the connection. Loop until we have a password if requested by @@ -1730,7 +1727,7 @@ connectDatabase(const char *dbname, const char *connection_string, values[i] = pguser; i++; } - if (have_password) + if (password) { keywords[i] = "password"; values[i] = password; @@ -1757,12 +1754,11 @@ connectDatabase(const char *dbname, const char *connection_string, if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - !have_password && + !password && prompt_password != TRI_NO) { PQfinish(conn); - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + password = simple_prompt("Password: ", false); new_pass = true; } } while (new_pass); diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 08a5947a9e6..332eabf6379 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -59,6 +59,7 @@ #include "common/int.h" #include "common/logging.h" +#include "common/string.h" #include "fe_utils/cancel.h" #include "fe_utils/conditional.h" #include "getopt_long.h" @@ -1174,8 +1175,7 @@ doConnect(void) { PGconn *conn; bool new_pass; - static bool have_password = false; - static char password[100]; + static char *password = NULL; /* * Start the connection. Loop until we have a password if requested by @@ -1195,7 +1195,7 @@ doConnect(void) keywords[2] = "user"; values[2] = login; keywords[3] = "password"; - values[3] = have_password ? password : NULL; + values[3] = password; keywords[4] = "dbname"; values[4] = dbName; keywords[5] = "fallback_application_name"; @@ -1215,11 +1215,10 @@ doConnect(void) if (PQstatus(conn) == CONNECTION_BAD && PQconnectionNeedsPassword(conn) && - !have_password) + !password) { PQfinish(conn); - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + password = simple_prompt("Password: ", false); new_pass = true; } } while (new_pass); diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 9902a4a2ba8..d4aa0976b5b 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -26,6 +26,7 @@ #include "command.h" #include "common.h" #include "common/logging.h" +#include "common/string.h" #include "copy.h" #include "crosstabview.h" #include "describe.h" @@ -1964,11 +1965,11 @@ exec_command_password(PsqlScanState scan_state, bool active_branch) { char *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true); - char pw1[100]; - char pw2[100]; + char *pw1; + char *pw2; - simple_prompt("Enter new password: ", pw1, sizeof(pw1), false); - simple_prompt("Enter it again: ", pw2, sizeof(pw2), false); + pw1 = simple_prompt("Enter new password: ", false); + pw2 = simple_prompt("Enter it again: ", false); if (strcmp(pw1, pw2) != 0) { @@ -2013,6 +2014,8 @@ exec_command_password(PsqlScanState scan_state, bool active_branch) if (opt0) free(opt0); + free(pw1); + free(pw2); } else ignore_slash_options(scan_state); @@ -2058,8 +2061,7 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch, if (!pset.inputfile) { - result = (char *) pg_malloc(4096); - simple_prompt(prompt_text, result, 4096, true); + result = simple_prompt(prompt_text, true); } else { @@ -2982,19 +2984,19 @@ copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf) static char * prompt_for_password(const char *username) { - char buf[100]; + char *result; if (username == NULL || username[0] == '\0') - simple_prompt("Password: ", buf, sizeof(buf), false); + result = simple_prompt("Password: ", false); else { char *prompt_text; prompt_text = psprintf(_("Password for user %s: "), username); - simple_prompt(prompt_text, buf, sizeof(buf), false); + result = simple_prompt(prompt_text, false); free(prompt_text); } - return pg_strdup(buf); + return result; } static bool diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 3302bd4dd32..8232a0143bc 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -17,6 +17,7 @@ #include "command.h" #include "common.h" #include "common/logging.h" +#include "common/string.h" #include "describe.h" #include "fe_utils/print.h" #include "getopt_long.h" @@ -119,8 +120,7 @@ main(int argc, char *argv[]) { struct adhoc_opts options; int successResult; - bool have_password = false; - char password[100]; + char *password = NULL; bool new_pass; pg_logging_init(argv[0]); @@ -233,8 +233,7 @@ main(int argc, char *argv[]) * offer a potentially wrong one. Typical uses of this option are * noninteractive anyway. */ - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + password = simple_prompt("Password: ", false); } /* loop until we have a password if requested by backend */ @@ -251,7 +250,7 @@ main(int argc, char *argv[]) keywords[2] = "user"; values[2] = options.username; keywords[3] = "password"; - values[3] = have_password ? password : NULL; + values[3] = password; keywords[4] = "dbname"; /* see do_connect() */ values[4] = (options.list_dbs && options.dbname == NULL) ? "postgres" : options.dbname; @@ -269,7 +268,7 @@ main(int argc, char *argv[]) if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && - !have_password && + !password && pset.getPassword != TRI_NO) { /* @@ -287,9 +286,8 @@ main(int argc, char *argv[]) password_prompt = pg_strdup(_("Password: ")); PQfinish(pset.db); - simple_prompt(password_prompt, password, sizeof(password), false); + password = simple_prompt(password_prompt, false); free(password_prompt); - have_password = true; new_pass = true; } } while (new_pass); diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c index 420d0d11a5a..e987eef2343 100644 --- a/src/bin/scripts/common.c +++ b/src/bin/scripts/common.c @@ -20,6 +20,7 @@ #include "common.h" #include "common/connect.h" #include "common/logging.h" +#include "common/string.h" #include "fe_utils/cancel.h" #include "fe_utils/string_utils.h" @@ -68,18 +69,17 @@ connectDatabase(const char *dbname, const char *pghost, { PGconn *conn; bool new_pass; - static bool have_password = false; - static char password[100]; + static char *password = NULL; - if (!allow_password_reuse) - have_password = false; - - if (!have_password && prompt_password == TRI_YES) + if (!allow_password_reuse && password) { - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + free(password); + password = NULL; } + if (!password && prompt_password == TRI_YES) + password = simple_prompt("Password: ", false); + /* * Start the connection. Loop until we have a password if requested by * backend. @@ -96,7 +96,7 @@ connectDatabase(const char *dbname, const char *pghost, keywords[2] = "user"; values[2] = pguser; keywords[3] = "password"; - values[3] = have_password ? password : NULL; + values[3] = password; keywords[4] = "dbname"; values[4] = dbname; keywords[5] = "fallback_application_name"; @@ -122,8 +122,9 @@ connectDatabase(const char *dbname, const char *pghost, prompt_password != TRI_NO) { PQfinish(conn); - simple_prompt("Password: ", password, sizeof(password), false); - have_password = true; + if (password) + free(password); + password = simple_prompt("Password: ", false); new_pass = true; } } while (new_pass); @@ -444,14 +445,21 @@ yesno_prompt(const char *question) for (;;) { - char resp[10]; + char *resp; - simple_prompt(prompt, resp, sizeof(resp), true); + resp = simple_prompt(prompt, true); if (strcmp(resp, _(PG_YESLETTER)) == 0) + { + free(resp); return true; + } if (strcmp(resp, _(PG_NOLETTER)) == 0) + { + free(resp); return false; + } + free(resp); printf(_("Please answer \"%s\" or \"%s\".\n"), _(PG_YESLETTER), _(PG_NOLETTER)); diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index 9ced079ac75..6179199563c 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -13,6 +13,7 @@ #include "postgres_fe.h" #include "common.h" #include "common/logging.h" +#include "common/string.h" #include "fe_utils/simple_list.h" #include "fe_utils/string_utils.h" @@ -63,8 +64,6 @@ main(int argc, char *argv[]) int conn_limit = -2; /* less than minimum valid value */ bool pwprompt = false; char *newpassword = NULL; - char newuser_buf[128]; - char newpassword_buf[100]; /* Tri-valued variables. */ enum trivalue createdb = TRI_DEFAULT, @@ -191,9 +190,7 @@ main(int argc, char *argv[]) { if (interactive) { - simple_prompt("Enter name of role to add: ", - newuser_buf, sizeof(newuser_buf), true); - newuser = newuser_buf; + newuser = simple_prompt("Enter name of role to add: ", true); } else { @@ -206,17 +203,16 @@ main(int argc, char *argv[]) if (pwprompt) { - char pw2[100]; + char *pw2; - simple_prompt("Enter password for new role: ", - newpassword_buf, sizeof(newpassword_buf), false); - simple_prompt("Enter it again: ", pw2, sizeof(pw2), false); - if (strcmp(newpassword_buf, pw2) != 0) + newpassword = simple_prompt("Enter password for new role: ", false); + pw2 = simple_prompt("Enter it again: ", false); + if (strcmp(newpassword, pw2) != 0) { fprintf(stderr, _("Passwords didn't match.\n")); exit(1); } - newpassword = newpassword_buf; + free(pw2); } if (superuser == 0) diff --git a/src/bin/scripts/dropuser.c b/src/bin/scripts/dropuser.c index fee270d4f6d..f7ddd1402db 100644 --- a/src/bin/scripts/dropuser.c +++ b/src/bin/scripts/dropuser.c @@ -13,6 +13,7 @@ #include "postgres_fe.h" #include "common.h" #include "common/logging.h" +#include "common/string.h" #include "fe_utils/string_utils.h" @@ -47,7 +48,6 @@ main(int argc, char *argv[]) enum trivalue prompt_password = TRI_DEFAULT; bool echo = false; bool interactive = false; - char dropuser_buf[128]; PQExpBufferData sql; @@ -112,9 +112,7 @@ main(int argc, char *argv[]) { if (interactive) { - simple_prompt("Enter name of role to drop: ", - dropuser_buf, sizeof(dropuser_buf), true); - dropuser = dropuser_buf; + dropuser = simple_prompt("Enter name of role to drop: ", true); } else { diff --git a/src/common/Makefile b/src/common/Makefile index 16619e4ba88..ad8fd9e41c4 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -63,6 +63,7 @@ OBJS_COMMON = \ kwlookup.o \ link-canary.o \ md5.o \ + pg_get_line.o \ pg_lzcompress.o \ pgfnames.o \ psprintf.o \ @@ -92,7 +93,8 @@ OBJS_FRONTEND = \ fe_memutils.o \ file_utils.o \ logging.o \ - restricted_token.o + restricted_token.o \ + sprompt.o # foo.o, foo_shlib.o, and foo_srv.o are all built from foo.c OBJS_SHLIB = $(OBJS_FRONTEND:%.o=%_shlib.o) diff --git a/src/common/pg_get_line.c b/src/common/pg_get_line.c new file mode 100644 index 00000000000..38433675d43 --- /dev/null +++ b/src/common/pg_get_line.c @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------- + * + * pg_get_line.c + * fgets() with an expansible result buffer + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/pg_get_line.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/string.h" +#include "lib/stringinfo.h" + + +/* + * pg_get_line() + * + * This is meant to be equivalent to fgets(), except that instead of + * reading into a caller-supplied, fixed-size buffer, it reads into + * a palloc'd (in frontend, really malloc'd) string, which is resized + * as needed to handle indefinitely long input lines. The caller is + * responsible for pfree'ing the result string when appropriate. + * + * As with fgets(), returns NULL if there is a read error or if no + * characters are available before EOF. The caller can distinguish + * these cases by checking ferror(stream). + * + * Since this is meant to be equivalent to fgets(), the trailing newline + * (if any) is not stripped. Callers may wish to apply pg_strip_crlf(). + * + * Note that while I/O errors are reflected back to the caller to be + * dealt with, an OOM condition for the palloc'd buffer will not be; + * there'll be an ereport(ERROR) or exit(1) inside stringinfo.c. + */ +char * +pg_get_line(FILE *stream) +{ + StringInfoData buf; + + initStringInfo(&buf); + + /* Read some data, appending it to whatever we already have */ + while (fgets(buf.data + buf.len, buf.maxlen - buf.len, stream) != NULL) + { + buf.len += strlen(buf.data + buf.len); + + /* Done if we have collected a newline */ + if (buf.len > 0 && buf.data[buf.len - 1] == '\n') + return buf.data; + + /* Make some more room in the buffer, and loop to read more data */ + enlargeStringInfo(&buf, 128); + } + + /* Did fgets() fail because of an I/O error? */ + if (ferror(stream)) + { + /* ensure that free() doesn't mess up errno */ + int save_errno = errno; + + pfree(buf.data); + errno = save_errno; + return NULL; + } + + /* If we read no data before reaching EOF, we should return NULL */ + if (buf.len == 0) + { + pfree(buf.data); + return NULL; + } + + /* No newline at EOF ... so return what we have */ + return buf.data; +} diff --git a/src/common/saslprep.c b/src/common/saslprep.c index 2dedf6b0fb6..d60452f75f2 100644 --- a/src/common/saslprep.c +++ b/src/common/saslprep.c @@ -29,12 +29,6 @@ #include "common/unicode_norm.h" #include "mb/pg_wchar.h" -/* - * Limit on how large password's we will try to process. A password - * larger than this will be treated the same as out-of-memory. - */ -#define MAX_PASSWORD_LENGTH 1024 - /* * In backend, we will use palloc/pfree. In frontend, use malloc, and * return SASLPREP_OOM on out-of-memory. @@ -1078,18 +1072,6 @@ pg_saslprep(const char *input, char **output) /* Ensure we return *output as NULL on failure */ *output = NULL; - /* Check that the password isn't stupendously long */ - if (strlen(input) > MAX_PASSWORD_LENGTH) - { -#ifndef FRONTEND - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("password too long"))); -#else - return SASLPREP_OOM; -#endif - } - /* * Quick check if the input is pure ASCII. An ASCII string requires no * further processing. diff --git a/src/port/sprompt.c b/src/common/sprompt.c similarity index 81% rename from src/port/sprompt.c rename to src/common/sprompt.c index 6d8a8b2609f..0ec75da5bfe 100644 --- a/src/port/sprompt.c +++ b/src/common/sprompt.c @@ -8,12 +8,15 @@ * * * IDENTIFICATION - * src/port/sprompt.c + * src/common/sprompt.c * *------------------------------------------------------------------------- */ #include "c.h" +#include "common/fe_memutils.h" +#include "common/string.h" + #ifdef HAVE_TERMIOS_H #include #endif @@ -26,20 +29,17 @@ * passwords interactively. Reads from /dev/tty or stdin/stderr. * * prompt: The prompt to print, or NULL if none (automatically localized) - * destination: buffer in which to store result - * destlen: allocated length of destination * echo: Set to false if you want to hide what is entered (for passwords) * - * The input (without trailing newline) is returned in the destination buffer, - * with a '\0' appended. + * The input (without trailing newline) is returned as a malloc'd string. + * Caller is responsible for freeing it when done. */ -void -simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo) +char * +simple_prompt(const char *prompt, bool echo) { - int length; + char *result; FILE *termin, *termout; - #if defined(HAVE_TERMIOS_H) struct termios t_orig, t; @@ -126,29 +126,14 @@ simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo) fflush(termout); } - if (fgets(destination, destlen, termin) == NULL) - destination[0] = '\0'; + result = pg_get_line(termin); - length = strlen(destination); - if (length > 0 && destination[length - 1] != '\n') - { - /* eat rest of the line */ - char buf[128]; - int buflen; - - do - { - if (fgets(buf, sizeof(buf), termin) == NULL) - break; - buflen = strlen(buf); - } while (buflen > 0 && buf[buflen - 1] != '\n'); - } + /* If we failed to read anything, just return an empty string */ + if (result == NULL) + result = pg_strdup(""); /* strip trailing newline, including \r in case we're on Windows */ - while (length > 0 && - (destination[length - 1] == '\n' || - destination[length - 1] == '\r')) - destination[--length] = '\0'; + (void) pg_strip_crlf(result); if (!echo) { @@ -169,4 +154,6 @@ simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo) fclose(termin); fclose(termout); } + + return result; } diff --git a/src/include/common/string.h b/src/include/common/string.h index 5113c04434c..18aa1dc5aa5 100644 --- a/src/include/common/string.h +++ b/src/include/common/string.h @@ -10,10 +10,17 @@ #ifndef COMMON_STRING_H #define COMMON_STRING_H +/* functions in src/common/string.c */ extern bool pg_str_endswith(const char *str, const char *end); extern int strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base); extern void pg_clean_ascii(char *str); extern int pg_strip_crlf(char *str); +/* functions in src/common/pg_get_line.c */ +extern char *pg_get_line(FILE *stream); + +/* functions in src/common/sprompt.c */ +extern char *simple_prompt(const char *prompt, bool echo); + #endif /* COMMON_STRING_H */ diff --git a/src/include/port.h b/src/include/port.h index 271ff0d00bc..84bf2c363f5 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -213,10 +213,6 @@ extern char *pg_strerror_r(int errnum, char *buf, size_t buflen); /* Wrap strsignal(), or provide our own version if necessary */ extern const char *pg_strsignal(int signum); -/* Portable prompt handling */ -extern void simple_prompt(const char *prompt, char *destination, size_t destlen, - bool echo); - extern int pclose_check(FILE *stream); /* Global variable holding time zone information. */ diff --git a/src/port/Makefile b/src/port/Makefile index 8defa1257bb..e41b005c4f1 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -35,6 +35,8 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS) LIBS += $(PTHREAD_LIBS) +# If you add objects here, see also src/tools/msvc/Mkvcbuild.pm + OBJS = \ $(LIBOBJS) \ $(PG_CRC32C_OBJS) \ @@ -55,7 +57,6 @@ OBJS = \ qsort_arg.o \ quotes.o \ snprintf.o \ - sprompt.o \ strerror.o \ tar.o \ thread.o diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 20da7985c10..536df5a92e7 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -102,7 +102,7 @@ sub mkvcbuild pread.c pwrite.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 quotes.c system.c - sprompt.c strerror.c tar.c thread.c + strerror.c tar.c thread.c win32env.c win32error.c win32security.c win32setlocale.c); push(@pgportfiles, 'strtof.c') if ($vsVersion < '14.00'); @@ -123,7 +123,7 @@ sub mkvcbuild config_info.c controldata_utils.c d2s.c encnames.c exec.c f2s.c file_perm.c hashfn.c ip.c jsonapi.c keywords.c kwlookup.c link-canary.c md5.c - pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c + pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c wait_error.c wchar.c); @@ -139,7 +139,7 @@ sub mkvcbuild our @pgcommonfrontendfiles = ( @pgcommonallfiles, qw(fe_memutils.c file_utils.c - logging.c restricted_token.c)); + logging.c restricted_token.c sprompt.c)); our @pgcommonbkndfiles = @pgcommonallfiles;