From cb7fb3ca958ec8bd5a14e740c067f1d096af3454 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 17 Apr 2003 22:26:02 +0000 Subject: [PATCH] First phase of FE/BE protocol modifications: new StartupPacket layout with variable-width fields. No more truncation of long user names. Also, libpq can now send its environment-variable-driven SET commands as part of the startup packet, saving round trips to server. --- doc/src/sgml/libpq.sgml | 19 +- src/backend/libpq/auth.c | 17 +- src/backend/libpq/crypt.c | 16 +- src/backend/libpq/hba.c | 27 +-- src/backend/postmaster/postmaster.c | 261 +++++++++++++++++-------- src/backend/tcop/postgres.c | 24 ++- src/include/libpq/auth.h | 4 +- src/include/libpq/hba.h | 4 +- src/include/libpq/libpq-be.h | 33 ++-- src/include/libpq/password.h | 6 - src/include/libpq/pqcomm.h | 54 ++--- src/interfaces/libpq/fe-auth.c | 4 +- src/interfaces/libpq/fe-connect.c | 253 +++++++++++++----------- src/interfaces/libpq/libpq-int.h | 10 +- src/test/regress/expected/interval.out | 2 +- src/test/regress/sql/interval.sql | 2 +- 16 files changed, 436 insertions(+), 300 deletions(-) delete mode 100644 src/include/libpq/password.h diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 4d9c249c83..a1f8d6b5f6 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,5 +1,5 @@ @@ -193,7 +193,7 @@ PGconn *PQconnectdb(const char *conninfo); tty - A file or TTY for optional debug output from the server. + Ignored (formerly, this specified where to send server debug output). @@ -669,6 +669,9 @@ char *PQport(const PGconn *conn); Returns the debug TTY of the connection. + (This is obsolete, since the server no longer pays attention + to the TTY setting, but the function remains + for backwards compatibility.) char *PQtty(const PGconn *conn); @@ -2365,12 +2368,6 @@ the PostgreSQL server. -PGTTY sets the file or TTY on which debugging -messages from the server are displayed. - - - - PGREQUIRESSL sets whether or not the connection must be made over SSL. If set to 1, libpq @@ -2678,7 +2675,7 @@ main() pgport = NULL; /* port of the backend server */ pgoptions = NULL; /* special options to start up the backend * server */ - pgtty = NULL; /* debugging tty for the backend server */ + pgtty = NULL; /* unused */ dbName = "template1"; /* make a connection to the database */ @@ -2826,7 +2823,7 @@ main() pgport = NULL; /* port of the backend server */ pgoptions = NULL; /* special options to start up the backend * server */ - pgtty = NULL; /* debugging tty for the backend server */ + pgtty = NULL; /* unused */ dbName = getenv("USER"); /* change this to the name of your test * database */ @@ -2950,7 +2947,7 @@ main() pgport = NULL; /* port of the backend server */ pgoptions = NULL; /* special options to start up the backend * server */ - pgtty = NULL; /* debugging tty for the backend server */ + pgtty = NULL; /* unused */ dbName = getenv("USER"); /* change this to the name of your test * database */ diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index e6edef6b67..5396cc47c1 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.97 2003/02/14 14:05:00 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.98 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,6 @@ #include "libpq/crypt.h" #include "libpq/hba.h" #include "libpq/libpq.h" -#include "libpq/password.h" #include "libpq/pqcomm.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -378,7 +377,7 @@ auth_failed(Port *port, int status) } elog(FATAL, "%s authentication failed for user \"%s\"", - authmethod, port->user); + authmethod, port->user_name); /* doesn't return */ } @@ -427,7 +426,7 @@ ClientAuthentication(Port *port) elog(FATAL, "No pg_hba.conf entry for host %s, user %s, database %s", - hostinfo, port->user, port->database); + hostinfo, port->user_name, port->database_name); break; } @@ -638,10 +637,12 @@ CheckPAMAuth(Port *port, char *user, char *password) * not allocated */ /* Optionally, one can set the service name in pg_hba.conf */ - if (port->auth_arg[0] == '\0') - retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@", &pam_passw_conv, &pamh); + if (port->auth_arg && port->auth_arg[0] != '\0') + retval = pam_start(port->auth_arg, "pgsql@", + &pam_passw_conv, &pamh); else - retval = pam_start(port->auth_arg, "pgsql@", &pam_passw_conv, &pamh); + retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@", + &pam_passw_conv, &pamh); if (retval != PAM_SUCCESS) { @@ -741,7 +742,7 @@ recv_and_check_password_packet(Port *port) /* Do not echo password to logs, for security. */ elog(DEBUG5, "received password packet"); - result = md5_crypt_verify(port, port->user, buf.data); + result = md5_crypt_verify(port, port->user_name, buf.data); pfree(buf.data); return result; diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index ac11ce98ef..728d5eb049 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.51 2002/12/05 18:52:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.52 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -87,15 +87,19 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass) /* pg_shadow plain, double-encrypt */ char *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1); - if (!EncryptMD5(shadow_pass, port->user, strlen(port->user), + if (!EncryptMD5(shadow_pass, + port->user_name, + strlen(port->user_name), crypt_pwd2)) { pfree(crypt_pwd); pfree(crypt_pwd2); return STATUS_ERROR; } - if (!EncryptMD5(crypt_pwd2 + strlen("md5"), port->md5Salt, - sizeof(port->md5Salt), crypt_pwd)) + if (!EncryptMD5(crypt_pwd2 + strlen("md5"), + port->md5Salt, + sizeof(port->md5Salt), + crypt_pwd)) { pfree(crypt_pwd); pfree(crypt_pwd2); @@ -117,7 +121,9 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass) { /* Encrypt user-supplied password to match MD5 in pg_shadow */ crypt_client_pass = palloc(MD5_PASSWD_LEN + 1); - if (!EncryptMD5(client_pass, port->user, strlen(port->user), + if (!EncryptMD5(client_pass, + port->user_name, + strlen(port->user_name), crypt_client_pass)) { pfree(crypt_client_pass); diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 2988ade443..f607167b6e 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.98 2003/04/13 04:07:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.99 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -471,15 +471,17 @@ check_db(char *dbname, char *user, char *param_str) /* * Scan the rest of a host record (after the mask field) - * and return the interpretation of it as *userauth_p, auth_arg, and + * and return the interpretation of it as *userauth_p, *auth_arg_p, and * *error_p. line points to the next token of the line. */ static void -parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg, +parse_hba_auth(List *line, UserAuth *userauth_p, char **auth_arg_p, bool *error_p) { char *token; + *auth_arg_p = NULL; + if (!line) *error_p = true; else @@ -514,11 +516,10 @@ parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg, if (!*error_p) { /* Get the authentication argument token, if any */ - if (!line) - auth_arg[0] = '\0'; - else + if (line) { - StrNCpy(auth_arg, lfirst(line), MAX_AUTH_ARG - 1); + token = lfirst(line); + *auth_arg_p = pstrdup(token); /* If there is more on the line, it is an error */ if (lnext(line)) *error_p = true; @@ -570,7 +571,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) goto hba_syntax; /* Read the rest of the line. */ - parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p); + parse_hba_auth(line, &port->auth_method, &port->auth_arg, error_p); if (*error_p) goto hba_syntax; @@ -642,7 +643,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) line = lnext(line); if (!line) goto hba_syntax; - parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p); + parse_hba_auth(line, &port->auth_method, &port->auth_arg, error_p); if (*error_p) goto hba_syntax; @@ -654,9 +655,9 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) else goto hba_syntax; - if (!check_db(port->database, port->user, db)) + if (!check_db(port->database_name, port->user_name, db)) return; - if (!check_user(port->user, user)) + if (!check_user(port->user_name, user)) return; /* Success */ @@ -946,7 +947,7 @@ check_ident_usermap(const char *usermap_name, bool found_entry = false, error = false; - if (usermap_name[0] == '\0') + if (usermap_name == NULL || usermap_name[0] == '\0') { elog(LOG, "check_ident_usermap: hba configuration file does not " "have the usermap field filled in in the entry that pertains " @@ -1387,7 +1388,7 @@ authident(hbaPort *port) return STATUS_ERROR; } - if (check_ident_usermap(port->auth_arg, port->user, ident_user)) + if (check_ident_usermap(port->auth_arg, port->user_name, ident_user)) return STATUS_OK; else return STATUS_ERROR; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 0221c64773..e9df82a147 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.310 2003/04/06 22:45:22 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.311 2003/04/17 22:26:01 tgl Exp $ * * NOTES * @@ -105,11 +105,10 @@ #include "utils/memutils.h" #include "utils/ps_status.h" #include "bootstrap/bootstrap.h" - #include "pgstat.h" + #define INVALID_SOCK (-1) -#define ARGV_SIZE 64 #ifdef HAVE_SIGPROCMASK sigset_t UnBlockSig, @@ -1114,10 +1113,11 @@ initMasks(fd_set *rmask, fd_set *wmask) static int ProcessStartupPacket(Port *port, bool SSLdone) { - StartupPacket *packet; enum CAC_state cac; int32 len; void *buf; + ProtocolVersion proto; + MemoryContext oldcontext; if (pq_getbytes((char *) &len, 4) == EOF) { @@ -1128,11 +1128,20 @@ ProcessStartupPacket(Port *port, bool SSLdone) len = ntohl(len); len -= 4; - if (len < sizeof(ProtocolVersion) || len > sizeof(StartupPacket)) + if (len < (int32) sizeof(ProtocolVersion) || + len > MAX_STARTUP_PACKET_LENGTH) elog(FATAL, "invalid length of startup packet"); - /* Ensure we see zeroes for any bytes not sent */ - buf = palloc0(sizeof(StartupPacket)); + /* + * Allocate at least the size of an old-style startup packet, plus one + * extra byte, and make sure all are zeroes. This ensures we will have + * null termination of all strings, in both fixed- and variable-length + * packet layouts. + */ + if (len <= (int32) sizeof(StartupPacket)) + buf = palloc0(sizeof(StartupPacket) + 1); + else + buf = palloc0(len + 1); if (pq_getbytes(buf, len) == EOF) { @@ -1140,21 +1149,19 @@ ProcessStartupPacket(Port *port, bool SSLdone) return STATUS_ERROR; } - packet = buf; - /* * The first field is either a protocol version number or a special * request code. */ - port->proto = ntohl(packet->protoVersion); + port->proto = proto = ntohl(*((ProtocolVersion *) buf)); - if (port->proto == CANCEL_REQUEST_CODE) + if (proto == CANCEL_REQUEST_CODE) { - processCancelRequest(port, packet); + processCancelRequest(port, buf); return 127; /* XXX */ } - if (port->proto == NEGOTIATE_SSL_CODE && !SSLdone) + if (proto == NEGOTIATE_SSL_CODE && !SSLdone) { char SSLok; @@ -1187,39 +1194,113 @@ ProcessStartupPacket(Port *port, bool SSLdone) /* Check we can handle the protocol the frontend is using. */ - if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) || - PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) || - (PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) && - PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))) - elog(FATAL, "unsupported frontend protocol"); + if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) || + PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) || + (PG_PROTOCOL_MAJOR(proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) && + PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))) + elog(FATAL, "unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u", + PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto), + PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST), + PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST), + PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)); /* - * Get the parameters from the startup packet as C strings. The - * packet destination was cleared first so a short packet has zeros - * silently added. + * XXX temporary for 3.0 protocol development: we are using the minor + * number as a test-version number. Insist it match exactly so people + * don't get burnt by using yesterday's libpq with today's server. + * XXX this must go away before release!!! */ - StrNCpy(port->database, packet->database, sizeof(port->database)); - StrNCpy(port->user, packet->user, sizeof(port->user)); - StrNCpy(port->options, packet->options, sizeof(port->options)); - StrNCpy(port->tty, packet->tty, sizeof(port->tty)); - - /* The database defaults to the user name. */ - if (port->database[0] == '\0') - StrNCpy(port->database, packet->user, sizeof(port->database)); + if (PG_PROTOCOL_MAJOR(proto) == 3 && + PG_PROTOCOL_MINOR(proto) != PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)) + elog(FATAL, "Your development libpq is out of sync with the server"); /* - * Truncate given database and user names to length of a Postgres - * name. This avoids lookup failures when overlength names are given. + * Now fetch parameters out of startup packet and save them into the + * Port structure. All data structures attached to the Port struct + * must be allocated in TopMemoryContext so that they won't disappear + * when we pass them to PostgresMain (see DoBackend). We need not worry + * about leaking this storage on failure, since we aren't in the postmaster + * process anymore. */ - if ((int) sizeof(port->database) >= NAMEDATALEN) - port->database[NAMEDATALEN - 1] = '\0'; - if ((int) sizeof(port->user) >= NAMEDATALEN) - port->user[NAMEDATALEN - 1] = '\0'; + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + + if (PG_PROTOCOL_MAJOR(proto) >= 3) + { + int32 offset = sizeof(ProtocolVersion); + + /* + * Scan packet body for name/option pairs. We can assume any + * string beginning within the packet body is null-terminated, + * thanks to zeroing extra byte above. + */ + port->guc_options = NIL; + + while (offset < len) + { + char *nameptr = ((char *) buf) + offset; + int32 valoffset; + char *valptr; + + if (*nameptr == '\0') + break; /* found packet terminator */ + valoffset = offset + strlen(nameptr) + 1; + if (valoffset >= len) + break; /* missing value, will complain below */ + valptr = ((char *) buf) + valoffset; + + if (strcmp(nameptr, "database") == 0) + port->database_name = pstrdup(valptr); + else if (strcmp(nameptr, "user") == 0) + port->user_name = pstrdup(valptr); + else if (strcmp(nameptr, "options") == 0) + port->cmdline_options = pstrdup(valptr); + else + { + /* Assume it's a generic GUC option */ + port->guc_options = lappend(port->guc_options, + pstrdup(nameptr)); + port->guc_options = lappend(port->guc_options, + pstrdup(valptr)); + } + offset = valoffset + strlen(valptr) + 1; + } + /* + * If we didn't find a packet terminator exactly at the end of the + * given packet length, complain. + */ + if (offset != len-1) + elog(FATAL, "invalid startup packet layout: expected terminator as last byte"); + } + else + { + /* + * Get the parameters from the old-style, fixed-width-fields startup + * packet as C strings. The packet destination was cleared first so a + * short packet has zeros silently added. We have to be prepared to + * truncate the pstrdup result for oversize fields, though. + */ + StartupPacket *packet = (StartupPacket *) buf; + + port->database_name = pstrdup(packet->database); + if (strlen(port->database_name) > sizeof(packet->database)) + port->database_name[sizeof(packet->database)] = '\0'; + port->user_name = pstrdup(packet->user); + if (strlen(port->user_name) > sizeof(packet->user)) + port->user_name[sizeof(packet->user)] = '\0'; + port->cmdline_options = pstrdup(packet->options); + if (strlen(port->cmdline_options) > sizeof(packet->options)) + port->cmdline_options[sizeof(packet->options)] = '\0'; + port->guc_options = NIL; + } /* Check a user name was given. */ - if (port->user[0] == '\0') + if (port->user_name == NULL || port->user_name[0] == '\0') elog(FATAL, "no PostgreSQL user name specified in startup packet"); + /* The database defaults to the user name. */ + if (port->database_name == NULL || port->database_name[0] == '\0') + port->database_name = pstrdup(port->user_name); + if (Db_user_namespace) { /* @@ -1228,19 +1309,35 @@ ProcessStartupPacket(Port *port, bool SSLdone) * string or they may fake as a local user of another database * attaching to this database. */ - if (strchr(port->user, '@') == port->user + strlen(port->user) - 1) - *strchr(port->user, '@') = '\0'; + if (strchr(port->user_name, '@') == + port->user_name + strlen(port->user_name) - 1) + *strchr(port->user_name, '@') = '\0'; else { /* Append '@' and dbname */ - char hold_user[SM_DATABASE_USER + 1]; + char *db_user; - snprintf(hold_user, SM_DATABASE_USER + 1, "%s@%s", port->user, - port->database); - strcpy(port->user, hold_user); + db_user = palloc(strlen(port->user_name) + + strlen(port->database_name) + 2); + sprintf(db_user, "%s@%s", port->user_name, port->database_name); + port->user_name = db_user; } } + /* + * Truncate given database and user names to length of a Postgres + * name. This avoids lookup failures when overlength names are given. + */ + if (strlen(port->database_name) >= NAMEDATALEN) + port->database_name[NAMEDATALEN - 1] = '\0'; + if (strlen(port->user_name) >= NAMEDATALEN) + port->user_name[NAMEDATALEN - 1] = '\0'; + + /* + * Done putting stuff in TopMemoryContext. + */ + MemoryContextSwitchTo(oldcontext); + /* * If we're going to reject the connection due to database state, say * so now instead of wasting cycles on an authentication exchange. @@ -2076,13 +2173,11 @@ static int DoBackend(Port *port) { char *remote_host; - char *av[ARGV_SIZE * 2]; - int ac = 0; - char debugbuf[ARGV_SIZE]; - char protobuf[ARGV_SIZE]; - char dbbuf[ARGV_SIZE]; - char optbuf[ARGV_SIZE]; - char ttybuf[ARGV_SIZE]; + char **av; + int maxac; + int ac; + char debugbuf[32]; + char protobuf[32]; int i; int status; struct timeval now; @@ -2225,7 +2320,7 @@ DoBackend(Port *port) * title for ps. It's good to do this as early as possible in * startup. */ - init_ps_display(port->user, port->database, remote_host); + init_ps_display(port->user_name, port->database_name, remote_host); set_ps_display("authentication"); /* @@ -2243,7 +2338,7 @@ DoBackend(Port *port) if (Log_connections) elog(LOG, "connection authorized: user=%s database=%s", - port->user, port->database); + port->user_name, port->database_name); /* * Don't want backend to be able to see the postmaster random number @@ -2260,8 +2355,20 @@ DoBackend(Port *port) * The layout of the command line is * postgres [secure switches] -p databasename [insecure switches] * where the switches after -p come from the client request. + * + * The maximum possible number of commandline arguments that could come + * from ExtraOptions or port->cmdline_options is (strlen + 1) / 2; see + * split_opts(). * ---------------- */ + maxac = 10; /* for fixed args supplied below */ + maxac += (strlen(ExtraOptions) + 1) / 2; + if (port->cmdline_options) + maxac += (strlen(port->cmdline_options) + 1) / 2; + + av = (char **) MemoryContextAlloc(TopMemoryContext, + maxac * sizeof(char *)); + ac = 0; av[ac++] = "postgres"; @@ -2270,7 +2377,7 @@ DoBackend(Port *port) */ if (debug_flag > 0) { - sprintf(debugbuf, "-d%d", debug_flag); + snprintf(debugbuf, sizeof(debugbuf), "-d%d", debug_flag); av[ac++] = debugbuf; } @@ -2283,7 +2390,7 @@ DoBackend(Port *port) split_opts(av, &ac, ExtraOptions); /* Tell the backend what protocol the frontend is using. */ - sprintf(protobuf, "-v%u", port->proto); + snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto); av[ac++] = protobuf; /* @@ -2291,38 +2398,25 @@ DoBackend(Port *port) * database to use. -p marks the end of secure switches. */ av[ac++] = "-p"; - - StrNCpy(dbbuf, port->database, ARGV_SIZE); - av[ac++] = dbbuf; + av[ac++] = port->database_name; /* * Pass the (insecure) option switches from the connection request. + * (It's OK to mangle port->cmdline_options now.) */ - StrNCpy(optbuf, port->options, ARGV_SIZE); - split_opts(av, &ac, optbuf); - - /* - * Pass the (insecure) debug output file request. - * - * NOTE: currently, this is useless code, since the backend will not - * honor an insecure -o switch. I left it here since the backend - * could be modified to allow insecure -o, given adequate checking - * that the specified filename is something safe to write on. - */ - if (port->tty[0]) - { - StrNCpy(ttybuf, port->tty, ARGV_SIZE); - av[ac++] = "-o"; - av[ac++] = ttybuf; - } + if (port->cmdline_options) + split_opts(av, &ac, port->cmdline_options); av[ac] = (char *) NULL; + Assert(ac < maxac); + /* * Release postmaster's working memory context so that backend can * recycle the space. Note this does not trash *MyProcPort, because * ConnCreate() allocated that space with malloc() ... else we'd need - * to copy the Port data here. + * to copy the Port data here. Also, subsidiary data such as the + * username isn't lost either; see ProcessStartupPacket(). */ MemoryContextSwitchTo(TopMemoryContext); MemoryContextDelete(PostmasterContext); @@ -2339,7 +2433,7 @@ DoBackend(Port *port) ClientAuthInProgress = false; /* client_min_messages is active * now */ - return (PostgresMain(ac, av, port->user)); + return (PostgresMain(ac, av, port->user_name)); } /* @@ -2578,11 +2672,10 @@ SSDataBase(int xlop) if ((pid = fork()) == 0) /* child */ { const char *statmsg; - char *av[ARGV_SIZE * 2]; + char *av[10]; int ac = 0; - char nbbuf[ARGV_SIZE]; - char dbbuf[ARGV_SIZE]; - char xlbuf[ARGV_SIZE]; + char nbbuf[32]; + char xlbuf[32]; #ifdef LINUX_PROFILE setitimer(ITIMER_PROF, &prof_itimer, NULL); @@ -2626,19 +2719,19 @@ SSDataBase(int xlop) /* Set up command-line arguments for subprocess */ av[ac++] = "postgres"; - sprintf(nbbuf, "-B%d", NBuffers); + snprintf(nbbuf, sizeof(nbbuf), "-B%d", NBuffers); av[ac++] = nbbuf; - sprintf(xlbuf, "-x%d", xlop); + snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop); av[ac++] = xlbuf; av[ac++] = "-p"; - - StrNCpy(dbbuf, "template1", ARGV_SIZE); - av[ac++] = dbbuf; + av[ac++] = "template1"; av[ac] = (char *) NULL; + Assert(ac < lengthof(av)); + BootstrapMain(ac, av); ExitPostmaster(0); } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index bbfa4695a3..1048d2fa1c 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.320 2003/03/24 18:33:52 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.321 2003/04/17 22:26:01 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -1611,6 +1611,26 @@ PostgresMain(int argc, char *argv[], const char *username) if (debug_flag >= 5) SetConfigOption("debug_print_rewritten", "true", ctx, gucsource); + /* + * Process any additional GUC variable settings passed in startup packet. + */ + if (MyProcPort != NULL) + { + List *gucopts = MyProcPort->guc_options; + + while (gucopts) + { + char *name, + *value; + + name = lfirst(gucopts); + gucopts = lnext(gucopts); + value = lfirst(gucopts); + gucopts = lnext(gucopts); + SetConfigOption(name, value, PGC_BACKEND, PGC_S_CLIENT); + } + } + /* * Post-processing for command line options. */ @@ -1795,7 +1815,7 @@ PostgresMain(int argc, char *argv[], const char *username) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.320 $ $Date: 2003/03/24 18:33:52 $\n"); + puts("$Revision: 1.321 $ $Date: 2003/04/17 22:26:01 $\n"); } /* diff --git a/src/include/libpq/auth.h b/src/include/libpq/auth.h index 4418adb5c9..f99e6d0373 100644 --- a/src/include/libpq/auth.h +++ b/src/include/libpq/auth.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: auth.h,v 1.21 2002/06/20 20:29:49 momjian Exp $ + * $Id: auth.h,v 1.22 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +21,7 @@ *---------------------------------------------------------------- */ -void ClientAuthentication(Port *port); +extern void ClientAuthentication(Port *port); #define PG_KRB4_VERSION "PGVER4.1" /* at most KRB_SENDAUTH_VLEN chars */ #define PG_KRB5_VERSION "PGVER5.1" diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h index b9daf985f5..9a7e355ff3 100644 --- a/src/include/libpq/hba.h +++ b/src/include/libpq/hba.h @@ -4,7 +4,7 @@ * Interface to hba.c * * - * $Id: hba.h,v 1.32 2002/04/04 04:25:54 momjian Exp $ + * $Id: hba.h,v 1.33 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,8 +26,6 @@ #define IDENT_PORT 113 /* Standard TCP port number for Ident service. Assigned by IANA */ -#define MAX_AUTH_ARG 80 /* Max size of an authentication arg */ - typedef enum UserAuth { uaReject, diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index e9d906d06a..19ac0402d3 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -11,15 +11,13 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-be.h,v 1.34 2002/08/29 03:22:01 tgl Exp $ + * $Id: libpq-be.h,v 1.35 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef LIBPQ_BE_H #define LIBPQ_BE_H -#include - #include "libpq/hba.h" #include "libpq/pqcomm.h" @@ -32,29 +30,36 @@ /* * This is used by the postmaster in its communication with frontends. It * contains all state information needed during this communication before the - * backend is run. + * backend is run. The Port structure is kept in malloc'd memory and is + * still available when a backend is running (see MyProcPort). The data + * it points to must also be malloc'd, or else palloc'd in TopMemoryContext, + * so that it survives into PostgresMain execution! */ typedef struct Port { int sock; /* File descriptor */ + ProtocolVersion proto; /* FE/BE protocol version */ SockAddr laddr; /* local addr (postmaster) */ SockAddr raddr; /* remote addr (client) */ - char md5Salt[4]; /* Password salt */ - char cryptSalt[2]; /* Password salt */ /* - * Information that needs to be held during the fe/be authentication - * handshake. + * Information that needs to be saved from the startup packet and passed + * into backend execution. "char *" fields are NULL if not set. + * guc_options points to a List of alternating option names and values. */ + char *database_name; + char *user_name; + char *cmdline_options; + List *guc_options; - ProtocolVersion proto; - char database[SM_DATABASE + 1]; - char user[SM_DATABASE_USER + 1]; - char options[SM_OPTIONS + 1]; - char tty[SM_TTY + 1]; - char auth_arg[MAX_AUTH_ARG]; + /* + * Information that needs to be held during the authentication cycle. + */ UserAuth auth_method; + char *auth_arg; + char md5Salt[4]; /* Password salt */ + char cryptSalt[2]; /* Password salt */ /* * SSL structures diff --git a/src/include/libpq/password.h b/src/include/libpq/password.h deleted file mode 100644 index c704edeb34..0000000000 --- a/src/include/libpq/password.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PASSWORD_H -#define PASSWORD_H - -int verify_password(const Port *port, const char *user, const char *password); - -#endif diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 7c476699f0..fabfb0cb25 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -9,14 +9,13 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pqcomm.h,v 1.75 2003/01/06 09:58:36 petere Exp $ + * $Id: pqcomm.h,v 1.76 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef PQCOMM_H #define PQCOMM_H -#include #ifdef WIN32 #include /* workaround for clashing defines of "ERROR" */ @@ -93,7 +92,7 @@ typedef union SockAddr * functionality). * * If a backend supports version m.n of the protocol it must actually support - * versions m.0..n]. Backend support for version m-1 can be dropped after a + * versions m.[0..n]. Backend support for version m-1 can be dropped after a * `reasonable' length of time. * * A frontend isn't required to support anything other than the current @@ -107,27 +106,26 @@ typedef union SockAddr /* The earliest and latest frontend/backend protocol version supported. */ #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) -#define PG_PROTOCOL_LATEST PG_PROTOCOL(2,0) +#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,100) /* XXX temporary value */ + +typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ + +typedef ProtocolVersion MsgType; + /* - * All packets sent to the postmaster start with the length. This is omitted - * from the different packet definitions specified below. + * Packet lengths are 4 bytes in network byte order. + * + * The initial length is omitted from the packet layouts appearing below. */ typedef uint32 PacketLen; /* - * Startup message parameters sizes. These must not be changed without changing - * the protocol version. These are all strings that are '\0' terminated only if - * there is room. - */ - -/* - * FIXME: remove the fixed size limitations on the database name, user - * name, and options fields and use a variable length field instead. The - * actual limits on database & user name will then be NAMEDATALEN, which - * can be changed without changing the FE/BE protocol. -neilc,2002/08/27 + * Old-style startup packet layout with fixed-width fields. This is used in + * protocol 1.0 and 2.0, but not in later versions. Note that the fields + * in this layout are '\0' terminated only if there is room. */ #define SM_DATABASE 64 @@ -138,11 +136,6 @@ typedef uint32 PacketLen; #define SM_UNUSED 64 #define SM_TTY 64 -typedef uint32 ProtocolVersion; /* Fe/Be protocol version number */ - -typedef ProtocolVersion MsgType; - - typedef struct StartupPacket { ProtocolVersion protoVersion; /* Protocol version */ @@ -156,7 +149,16 @@ typedef struct StartupPacket extern bool Db_user_namespace; -/* These are the authentication requests sent by the backend. */ +/* + * In protocol 3.0 and later, the startup packet length is not fixed, but + * we set an arbitrary limit on it anyway. This is just to prevent simple + * denial-of-service attacks via sending enough data to run the server + * out of memory. + */ +#define MAX_STARTUP_PACKET_LENGTH 10000 + + +/* These are the authentication request codes sent by the backend. */ #define AUTH_REQ_OK 0 /* User is authenticated */ #define AUTH_REQ_KRB4 1 /* Kerberos V4 */ @@ -169,12 +171,12 @@ extern bool Db_user_namespace; typedef uint32 AuthRequest; -/* A client can also send a cancel-current-operation request to the postmaster. +/* + * A client can also send a cancel-current-operation request to the postmaster. * This is uglier than sending it directly to the client's backend, but it * avoids depending on out-of-band communication facilities. - */ - -/* The cancel request code must not match any protocol version number + * + * The cancel request code must not match any protocol version number * we're ever likely to use. This random choice should do. */ #define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678) diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 4ac99fd76a..fca2d2e303 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -10,7 +10,7 @@ * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes). * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.74 2003/03/10 22:28:21 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.75 2003/04/17 22:26:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -559,7 +559,7 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) default: return STATUS_ERROR; } - ret = pqPacketSend(conn, crypt_pwd, strlen(crypt_pwd) + 1); + ret = pqPacketSend(conn, 0, crypt_pwd, strlen(crypt_pwd) + 1); if (areq == AUTH_REQ_MD5) free(crypt_pwd); return ret; diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index f2e509e624..9f5c8714a6 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.231 2003/04/04 20:42:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.232 2003/04/17 22:26:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,9 +64,6 @@ inet_aton(const char *cp, struct in_addr * inp) #endif -#define NOTIFYLIST_INITIAL_SIZE 10 -#define NOTIFYLIST_GROWBY 10 - #define PGPASSFILE ".pgpass" /* ---------- @@ -128,6 +125,10 @@ static const PQconninfoOption PQconninfoOptions[] = { {"port", "PGPORT", DEF_PGPORT_STR, NULL, "Database-Port", "", 6}, + /* + * "tty" is no longer used either, but keep it present for backwards + * compatibility. + */ {"tty", "PGTTY", DefaultTty, NULL, "Backend-Debug-TTY", "D", 40}, @@ -182,12 +183,13 @@ static PQconninfoOption *conninfo_parse(const char *conninfo, PQExpBuffer errorMessage); static char *conninfo_getval(PQconninfoOption *connOptions, const char *keyword); +static int build_startup_packet(const PGconn *conn, char *packet); static void defaultNoticeProcessor(void *arg, const char *message); static int parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage); -char *pwdfMatchesString(char *buf, char *token); -char *PasswordFromFile(char *hostname, char *port, char *dbname, - char *username); +static char *pwdfMatchesString(char *buf, char *token); +static char *PasswordFromFile(char *hostname, char *port, char *dbname, + char *username); /* * Connecting to a Database @@ -396,7 +398,7 @@ PQconndefaults(void) * is NULL or a null string. * * PGTTY identifies tty to which to send messages if argument - * is NULL or a null string. + * is NULL or a null string. (No longer used by backend.) * * PGOPTIONS identifies connection options if argument is * NULL or a null string. @@ -792,10 +794,6 @@ connectDBStart(PGconn *conn) { int portnum; char portstr[64]; -#ifdef USE_SSL - StartupPacket np; /* Used to negotiate SSL connection */ - char SSLok; -#endif struct addrinfo *addrs = NULL; struct addrinfo *addr_cur = NULL; struct addrinfo hint; @@ -980,9 +978,11 @@ retry1: /* Attempt to negotiate SSL usage */ if (conn->allow_ssl_try) { - memset((char *) &np, 0, sizeof(np)); - np.protoVersion = htonl(NEGOTIATE_SSL_CODE); - if (pqPacketSend(conn, (char *) &np, sizeof(StartupPacket)) != STATUS_OK) + ProtocolVersion pv; + char SSLok; + + pv = htonl(NEGOTIATE_SSL_CODE); + if (pqPacketSend(conn, 0, &pv, sizeof(ProtocolVersion)) != STATUS_OK) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send SSL negotiation packet: %s\n"), @@ -1284,22 +1284,21 @@ keep_going: /* We will come back to here until there case CONNECTION_MADE: { - StartupPacket sp; + char *startpacket; + int packetlen; /* - * Initialize the startup packet. + * Build the startup packet. */ - - MemSet((char *) &sp, 0, sizeof(StartupPacket)); - - sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LIBPQ); - - strncpy(sp.user, conn->pguser, SM_USER); - strncpy(sp.database, conn->dbName, SM_DATABASE); - strncpy(sp.tty, conn->pgtty, SM_TTY); - - if (conn->pgoptions) - strncpy(sp.options, conn->pgoptions, SM_OPTIONS); + packetlen = build_startup_packet(conn, NULL); + startpacket = (char *) malloc(packetlen); + if (!startpacket) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory\n")); + goto error_return; + } + packetlen = build_startup_packet(conn, startpacket); /* * Send the startup packet. @@ -1307,16 +1306,17 @@ keep_going: /* We will come back to here until there * Theoretically, this could block, but it really shouldn't * since we only got here if the socket is write-ready. */ - - if (pqPacketSend(conn, (char *) &sp, - sizeof(StartupPacket)) != STATUS_OK) + if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send startup packet: %s\n"), SOCK_STRERROR(SOCK_ERRNO)); + free(startpacket); goto error_return; } + free(startpacket); + conn->status = CONNECTION_AWAITING_RESPONSE; return PGRES_POLLING_READING; } @@ -1576,7 +1576,6 @@ PQsetenvStart(PGconn *conn) return false; conn->setenv_state = SETENV_STATE_ENCODINGS_SEND; - conn->next_eo = EnvironmentOptions; return true; } @@ -1600,7 +1599,6 @@ PQsetenvPoll(PGconn *conn) { /* These are reading states */ case SETENV_STATE_ENCODINGS_WAIT: - case SETENV_STATE_OPTION_WAIT: { /* Load waiting data */ int n = pqReadData(conn); @@ -1615,7 +1613,6 @@ PQsetenvPoll(PGconn *conn) /* These are writing states, so we just proceed. */ case SETENV_STATE_ENCODINGS_SEND: - case SETENV_STATE_OPTION_SEND: break; /* Should we raise an error if called when not active? */ @@ -1669,7 +1666,7 @@ PQsetenvPoll(PGconn *conn) conn->client_encoding = encoding; /* Move on to setting the environment options */ - conn->setenv_state = SETENV_STATE_OPTION_SEND; + conn->setenv_state = SETENV_STATE_IDLE; } break; } @@ -1708,80 +1705,11 @@ PQsetenvPoll(PGconn *conn) * NULL result indicates that the query is * finished */ - /* Move on to setting the environment options */ - conn->setenv_state = SETENV_STATE_OPTION_SEND; - } - break; - } - - case SETENV_STATE_OPTION_SEND: - { - /* Send an Environment Option */ - char setQuery[100]; /* note length limits in - * sprintf's below */ - - if (conn->next_eo->envName) - { - const char *val; - - if ((val = getenv(conn->next_eo->envName))) - { - if (strcasecmp(val, "default") == 0) - sprintf(setQuery, "SET %s = %.60s", - conn->next_eo->pgName, val); - else - sprintf(setQuery, "SET %s = '%.60s'", - conn->next_eo->pgName, val); -#ifdef CONNECTDEBUG - printf("Use environment variable %s to send %s\n", - conn->next_eo->envName, setQuery); -#endif - if (!PQsendQuery(conn, setQuery)) - goto error_return; - - conn->setenv_state = SETENV_STATE_OPTION_WAIT; - } - else - conn->next_eo++; - } - else - { - /* No more options to send, so we are done. */ conn->setenv_state = SETENV_STATE_IDLE; } break; } - case SETENV_STATE_OPTION_WAIT: - { - if (PQisBusy(conn)) - return PGRES_POLLING_READING; - - res = PQgetResult(conn); - - if (res) - { - if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - PQclear(res); - goto error_return; - } - PQclear(res); - /* Keep reading until PQgetResult returns NULL */ - } - else - { - /* - * NULL result indicates that the query is - * finished - */ - /* Send the next option */ - conn->next_eo++; - conn->setenv_state = SETENV_STATE_OPTION_SEND; - } - break; - } - case SETENV_STATE_IDLE: return PGRES_POLLING_OK; @@ -2225,24 +2153,34 @@ cancel_errReturn: /* * pqPacketSend() -- send a single-packet message. - * this is like PacketSend(), defined in backend/libpq/pqpacket.c + * + * pack_type: the single-byte message type code. (Pass zero for startup + * packets, which have no message type code.) + * + * buf, buf_len: contents of message. The given length includes only what + * is in buf; the message type and message length fields are added here. * * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise. * SIDE_EFFECTS: may block. */ int -pqPacketSend(PGconn *conn, const char *buf, size_t len) +pqPacketSend(PGconn *conn, char pack_type, + const void *buf, size_t buf_len) { - /* Send the total packet size. */ - - if (pqPutInt(4 + len, 4, conn)) + /* Send the message type. */ + if (pack_type != 0) + if (pqPutc(pack_type, conn)) + return STATUS_ERROR; + + /* Send the (self-inclusive) message length word. */ + if (pqPutInt(buf_len + 4, 4, conn)) return STATUS_ERROR; - /* Send the packet itself. */ - - if (pqPutnchar(buf, len, conn)) + /* Send the message body. */ + if (pqPutnchar(buf, buf_len, conn)) return STATUS_ERROR; + /* Flush to ensure backend gets it. */ if (pqFlush(conn)) return STATUS_ERROR; @@ -2661,6 +2599,87 @@ PQconninfoFree(PQconninfoOption *connOptions) } +/* + * Build a startup packet given a filled-in PGconn structure. + * + * We need to figure out how much space is needed, then fill it in. + * To avoid duplicate logic, this routine is called twice: the first time + * (with packet == NULL) just counts the space needed, the second time + * (with packet == allocated space) fills it in. Return value is the number + * of bytes used. + */ +static int +build_startup_packet(const PGconn *conn, char *packet) +{ + int packet_len = 0; + const struct EnvironmentOptions *next_eo; + + /* Protocol version comes first. */ + if (packet) + { + ProtocolVersion pv = htonl(PG_PROTOCOL_LIBPQ); + + memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion)); + } + packet_len += sizeof(ProtocolVersion); + + /* Add user name, database name, options */ + if (conn->pguser) + { + if (packet) + strcpy(packet + packet_len, "user"); + packet_len += strlen("user") + 1; + if (packet) + strcpy(packet + packet_len, conn->pguser); + packet_len += strlen(conn->pguser) + 1; + } + if (conn->dbName) + { + if (packet) + strcpy(packet + packet_len, "database"); + packet_len += strlen("database") + 1; + if (packet) + strcpy(packet + packet_len, conn->dbName); + packet_len += strlen(conn->dbName) + 1; + } + if (conn->pgoptions) + { + if (packet) + strcpy(packet + packet_len, "options"); + packet_len += strlen("options") + 1; + if (packet) + strcpy(packet + packet_len, conn->pgoptions); + packet_len += strlen(conn->pgoptions) + 1; + } + + /* Add any environment-driven GUC settings needed */ + for (next_eo = EnvironmentOptions; next_eo->envName; next_eo++) + { + const char *val; + + if ((val = getenv(next_eo->envName)) != NULL) + { + if (strcasecmp(val, "default") != 0) + { + if (packet) + strcpy(packet + packet_len, next_eo->pgName); + packet_len += strlen(next_eo->pgName) + 1; + if (packet) + strcpy(packet + packet_len, val); + packet_len += strlen(val) + 1; + } + } + } + + /* Add trailing terminator */ + if (packet) + packet[packet_len] = '\0'; + packet_len++; + + return packet_len; +} + + /* =========== accessor functions for PGconn ========= */ char * PQdb(const PGconn *conn) @@ -2850,9 +2869,11 @@ defaultNoticeProcessor(void *arg, const char *message) fprintf(stderr, "%s", message); } -/* returns a pointer to the next token or NULL if the current - * token doesn't match */ -char * +/* + * returns a pointer to the next token or NULL if the current + * token doesn't match + */ +static char * pwdfMatchesString(char *buf, char *token) { char *tbuf, @@ -2889,7 +2910,7 @@ pwdfMatchesString(char *buf, char *token) } /* Get a password from the password file. Return value is malloc'd. */ -char * +static char * PasswordFromFile(char *hostname, char *port, char *dbname, char *username) { FILE *fp; diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index cde2b2d2b0..43c3bd11c5 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-int.h,v 1.60 2002/10/16 02:55:30 momjian Exp $ + * $Id: libpq-int.h,v 1.61 2003/04/17 22:26:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast * pqcomm.h describe what the backend knows, not what libpq knows. */ -#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(2,0) +#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,100) /* XXX temporary value */ /* * POSTGRES backend dependent Constants. @@ -181,8 +181,6 @@ typedef enum /* PGSetenvStatusType defines the state of the PQSetenv state machine */ typedef enum { - SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */ - SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */ SETENV_STATE_ENCODINGS_SEND, /* About to send an "encodings" query */ SETENV_STATE_ENCODINGS_WAIT, /* Waiting for query to complete */ SETENV_STATE_IDLE @@ -274,7 +272,6 @@ struct pg_conn /* Status for sending environment info. Used during PQSetenv only. */ PGSetenvStatusType setenv_state; - const struct EnvironmentOptions *next_eo; #ifdef USE_SSL bool allow_ssl_try; /* Allowed to try SSL negotiation */ @@ -312,7 +309,8 @@ extern char *const pgresStatus[]; /* === in fe-connect.c === */ -extern int pqPacketSend(PGconn *conn, const char *buf, size_t len); +extern int pqPacketSend(PGconn *conn, char pack_type, + const void *buf, size_t buf_len); /* === in fe-exec.c === */ diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out index ed16ada224..32120be541 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -1,7 +1,7 @@ -- -- INTERVAL -- -SET DATESTYLE = DEFAULT; +SET DATESTYLE = 'ISO'; -- check acceptance of "time zone style" SELECT INTERVAL '01:00' AS "One hour"; One hour diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql index aa14cd3b09..b6a6eb20ef 100644 --- a/src/test/regress/sql/interval.sql +++ b/src/test/regress/sql/interval.sql @@ -2,7 +2,7 @@ -- INTERVAL -- -SET DATESTYLE = DEFAULT; +SET DATESTYLE = 'ISO'; -- check acceptance of "time zone style" SELECT INTERVAL '01:00' AS "One hour";