diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/postmaster/postmaster.c | 116 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 228 | ||||
-rw-r--r-- | src/backend/utils/init/globals.c | 5 | ||||
-rw-r--r-- | src/backend/utils/init/miscinit.c | 3 | ||||
-rw-r--r-- | src/backend/utils/misc/trace.c | 8 |
5 files changed, 200 insertions, 160 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 281b95fe906..cf1271c7ec4 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.103 1999/02/21 01:41:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.104 1999/05/22 17:47:50 tgl Exp $ * * NOTES * @@ -191,7 +191,7 @@ static int ServerSock_UNIX = INVALID_SOCK; /* stream socket server */ /* * Set by the -o option */ -static char ExtraOptions[ARGV_SIZE] = ""; +static char ExtraOptions[MAXPATHLEN] = ""; /* * These globals control the behavior of the postmaster in case some @@ -1398,7 +1398,9 @@ BackendStartup(Port *port) } /* - * split_opts -- destructively load a string into an argv array + * split_opts -- split a string of options and append it to an argv array + * + * NB: the string is destructively modified! * * Since no current POSTGRES arguments require any quoting characters, * we can use the simple-minded tactic of assuming each set of space- @@ -1416,41 +1418,39 @@ split_opts(char **argv, int *argcp, char *s) { while (isspace(*s)) ++s; - if (*s) - argv[i++] = s; + if (*s == '\0') + break; + argv[i++] = s; while (*s && !isspace(*s)) ++s; - if (isspace(*s)) + if (*s) *s++ = '\0'; } + *argcp = i; } /* - * DoBackend -- set up the argument list and perform an execv system call + * DoBackend -- set up the backend's argument list and invoke backend main(). + * + * This used to perform an execv() but we no longer exec the backend; + * it's the same executable as the postmaster. * * returns: * Shouldn't return at all. - * If execv() fails, return status. + * If PostgresMain() fails, return status. */ static int DoBackend(Port *port) { + char *av[ARGV_SIZE * 2]; + int ac = 0; char execbuf[MAXPATHLEN]; - char portbuf[ARGV_SIZE]; char debugbuf[ARGV_SIZE]; - char ttybuf[ARGV_SIZE + 1]; - char protobuf[ARGV_SIZE + 1]; - char argbuf[(2 * ARGV_SIZE) + 1]; - - /* - * each argument takes at least three chars, so we can't have more - * than ARGV_SIZE arguments in (2 * ARGV_SIZE) chars (i.e., - * port->options plus ExtraOptions)... - */ - char *av[ARGV_SIZE]; - char dbbuf[ARGV_SIZE + 1]; - int ac = 0; + char protobuf[ARGV_SIZE]; + char dbbuf[ARGV_SIZE]; + char optbuf[ARGV_SIZE]; + char ttybuf[ARGV_SIZE]; int i; struct timeval now; struct timezone tz; @@ -1491,9 +1491,11 @@ DoBackend(Port *port) StreamClose(ServerSock_UNIX); #endif - /* Save port for ps status */ + /* Save port etc. for ps status */ MyProcPort = port; + MyProcPid = getpid(); + /* * Don't want backend to be able to see the postmaster random number * generator state. We have to clobber the static random_seed *and* @@ -1503,11 +1505,16 @@ DoBackend(Port *port) gettimeofday(&now, &tz); srandom(now.tv_usec); - /* Now, on to standard postgres stuff */ - - MyProcPid = getpid(); + /* ---------------- + * Now, build the argv vector that will be given to PostgresMain. + * + * The layout of the command line is + * postgres [secure switches] -p databasename [insecure switches] + * where the switches after -p come from the client request. + * ---------------- + */ - strncpy(execbuf, Execfile, MAXPATHLEN - 1); + StrNCpy(execbuf, Execfile, MAXPATHLEN); av[ac++] = execbuf; /* @@ -1528,9 +1535,6 @@ DoBackend(Port *port) real_argv[0] = Execfile; #endif - /* Tell the backend it is being called from the postmaster */ - av[ac++] = "-p"; - /* * Pass the requested debugging level along to the backend. We * decrement by one; level one debugging in the postmaster traces @@ -1538,38 +1542,54 @@ DoBackend(Port *port) * passed along to the backend. This allows us to watch only the * postmaster or the postmaster and the backend. */ - if (DebugLvl > 1) { sprintf(debugbuf, "-d%d", DebugLvl); av[ac++] = debugbuf; } - /* Pass the requested debugging output file */ - if (port->tty[0]) - { - strncpy(ttybuf, port->tty, ARGV_SIZE); - av[ac++] = "-o"; - av[ac++] = ttybuf; - } - - /* Tell the backend the descriptor of the fe/be socket */ - sprintf(portbuf, "-P%d", port->sock); - av[ac++] = portbuf; - - StrNCpy(argbuf, port->options, ARGV_SIZE); - strncat(argbuf, ExtraOptions, ARGV_SIZE); - argbuf[(2 * ARGV_SIZE)] = '\0'; - split_opts(av, &ac, argbuf); + /* + * Pass any backend switches specified with -o in the postmaster's + * own command line. We assume these are secure. + * (It's OK to mangle ExtraOptions since we are now in the child process; + * this won't change the postmaster's copy.) + */ + split_opts(av, &ac, ExtraOptions); /* Tell the backend what protocol the frontend is using. */ - sprintf(protobuf, "-v%u", port->proto); av[ac++] = protobuf; + /* + * Tell the backend it is being called from the postmaster, + * and which database to use. -p marks the end of secure switches. + */ + av[ac++] = "-p"; + StrNCpy(dbbuf, port->database, ARGV_SIZE); av[ac++] = dbbuf; + /* + * Pass the (insecure) option switches from the connection request. + */ + 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; + } + av[ac] = (char *) NULL; if (DebugLvl > 1) @@ -1577,7 +1597,7 @@ DoBackend(Port *port) fprintf(stderr, "%s child[%d]: starting with (", progname, MyProcPid); for (i = 0; i < ac; ++i) - fprintf(stderr, "%s, ", av[i]); + fprintf(stderr, "%s ", av[i]); fprintf(stderr, ")\n"); } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index dbf0c0b9850..ab29054aa77 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.114 1999/05/22 02:55:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.115 1999/05/22 17:47:49 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -776,7 +776,7 @@ pg_exec_query_dest(char *query_string, /* string to execute */ * Some backend has bought the farm, * so we need to stop what we're doing and exit. * - * die() preforms an orderly cleanup via ExitPostgres() + * die() performs an orderly cleanup via ExitPostgres() * -------------------------------- */ @@ -832,7 +832,6 @@ QueryCancelHandler(SIGNAL_ARGS) void CancelQuery(void) { - /* * QueryCancel flag will be reset in main loop, which we reach by * longjmp from elog(). @@ -857,36 +856,42 @@ usage(char *progname) #ifdef LOCK_MGR_DEBUG fprintf(stderr, "\t-K lev\t\tset locking debug level [0|1|2]\n"); #endif + fprintf(stderr, "\t-L \t\tturn off locking\n"); + fprintf(stderr, "\t-N \t\tdon't use newline as interactive query delimiter\n"); fprintf(stderr, "\t-O \t\tallow system table structure changes\n"); - fprintf(stderr, "\t-P port\t\tset port file descriptor\n"); fprintf(stderr, "\t-Q \t\tsuppress informational messages\n"); - fprintf(stderr, "\t-S buffers\tset amount of sort memory available\n"); + fprintf(stderr, "\t-S kbytes\tset amount of memory for sorts (in kbytes)\n"); fprintf(stderr, "\t-T options\tspecify pg_options\n"); fprintf(stderr, "\t-W sec\t\twait N seconds to allow attach from a debugger\n"); fprintf(stderr, "\t-d [1|2|3]\tset debug level\n"); fprintf(stderr, "\t-e \t\tturn on European date format\n"); fprintf(stderr, "\t-f [s|i|n|m|h]\tforbid use of some plan types\n"); - fprintf(stderr, "\t-o file\t\tsend stdout and stderr to given filename \n"); + fprintf(stderr, "\t-i \t\tdon't execute queries\n"); + fprintf(stderr, "\t-o file\t\tsend stdout and stderr to given filename\n"); + fprintf(stderr, "\t-p database\tbackend is started under a postmaster\n"); fprintf(stderr, "\t-s \t\tshow stats after each query\n"); + fprintf(stderr, "\t-t [pa|pl|ex]\tshow timings after each query\n"); fprintf(stderr, "\t-v version\tset protocol version being used by frontend\n"); } /* ---------------------------------------------------------------- - * PostgresMain - * postgres main loop + * PostgresMain + * postgres main loop * all backends, interactive or otherwise start here + * + * argc/argv are the command line arguments to be used. When being forked + * by the postmaster, these are not the original argv array of the process. + * real_argc/real_argv point to the original argv array, which is needed by + * PS_INIT_STATUS on some platforms. * ---------------------------------------------------------------- */ int PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) { - bool flagC = false, - flagQ = false, - flagE = false, - flagEu = false; int flag; char *DBName = NULL; + bool secure = true; int errs = 0; char firstchar; @@ -903,25 +908,18 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) extern char *optarg; extern short DebugLvl; - /* ---------------- - * parse command line arguments - * ---------------- - */ - /* - * Set default values. + * Set default values for command-line options. */ + IsUnderPostmaster = false; ShowStats = 0; ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0; DeadlockCheckTimer = DEADLOCK_CHECK_TIMER; + Noversion = false; + EchoQuery = false; #ifdef LOCK_MGR_DEBUG LockDebug = 0; #endif - - /* - * get hostname is either the environment variable PGHOST or NULL NULL - * means Unix-socket only - */ DataDir = getenv("PGDATA"); /* @@ -943,8 +941,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) DateStyle = USE_GERMAN_DATES; EuroDates = TRUE; } - - if (strcasecmp(DBDate, "NONEURO") == 0) + else if (strcasecmp(DBDate, "NONEURO") == 0) EuroDates = FALSE; else if (strcasecmp(DBDate, "EURO") == 0) EuroDates = TRUE; @@ -953,14 +950,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) /* * Read default pg_options from file $DATADIR/pg_options. */ - if(DataDir) { + if (DataDir) read_pg_options(0); - } - optind = 1; /* reset after postmaster usage */ + /* ---------------- + * parse command line arguments + * + * There are now two styles of command line layout for the backend: + * + * For interactive use (not started from postmaster) the format is + * postgres [switches] [databasename] + * If the databasename is omitted it is taken to be the user name. + * + * When started from the postmaster, the format is + * postgres [secure switches] -p databasename [insecure switches] + * Switches appearing after -p came from the client (via "options" + * field of connection request). For security reasons we restrict + * what these switches can do. + * ---------------- + */ + + optind = 1; /* reset after postmaster's usage */ while ((flag = getopt(argc, argv, - "A:B:CD:d:EeFf:iK:LMm:NOo:P:pQS:sT:t:v:W:x:")) + "A:B:CD:d:EeFf:iK:LNOo:p:QS:sT:t:v:W:x:")) != EOF) switch (flag) { @@ -981,28 +994,32 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * specify the size of buffer pool * ---------------- */ - NBuffers = atoi(optarg); + if (secure) + NBuffers = atoi(optarg); break; case 'C': /* ---------------- - * don't print version string (don't know why this is 'C' --mao) + * don't print version string * ---------------- */ - flagC = true; + Noversion = true; break; case 'D': /* PGDATA directory */ - if (!DataDir) { - DataDir = optarg; - /* must be done after DataDir is defined */ - read_pg_options(0); + if (secure) + { + if (!DataDir) + { + DataDir = optarg; + /* must be done after DataDir is defined */ + read_pg_options(0); + } + DataDir = optarg; } - DataDir = optarg; break; case 'd': /* debug level */ - flagQ = false; DebugLvl = (short) atoi(optarg); if (DebugLvl >= 1) Verbose = DebugLvl; @@ -1029,7 +1046,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * E - echo the query the user entered * ---------------- */ - flagE = true; + EchoQuery = true; break; case 'e': @@ -1037,7 +1054,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * Use european date formats. * -------------------------- */ - flagEu = true; + EuroDates = true; break; case 'F': @@ -1045,7 +1062,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * turn off fsync * -------------------- */ - disableFsync = true; + if (secure) + disableFsync = true; break; case 'f': @@ -1092,15 +1110,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * turn off locking * -------------------- */ - lockingOff = 1; - break; - - case 'M': - exit(PostmasterMain(argc, argv)); - break; - - case 'm': - /* Multiplexed backends are no longer supported. */ + if (secure) + lockingOff = 1; break; case 'N': @@ -1116,7 +1127,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * allow system table structure modifications * -------------------- */ - allowSystemTableMods = true; + if (secure) /* XXX safe to allow from client??? */ + allowSystemTableMods = true; break; case 'o': @@ -1124,26 +1136,22 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * o - send output (stdout and stderr) to the given file * ---------------- */ - StrNCpy(OutputFileName, optarg, MAXPGPATH); + if (secure) + StrNCpy(OutputFileName, optarg, MAXPGPATH); break; - case 'p': /* started by postmaster */ + case 'p': /* ---------------- * p - special flag passed if backend was forked * by a postmaster. * ---------------- */ - IsUnderPostmaster = true; - break; - - case 'P': - /* ---------------- - * P - Use the passed file descriptor number as the port - * on which to communicate with the user. This is ONLY - * useful for debugging when fired up by the postmaster. - * ---------------- - */ - Portfd = atoi(optarg); + if (secure) + { + IsUnderPostmaster = true; + DBName = optarg; + secure = false; /* subsequent switches are NOT secure */ + } break; case 'Q': @@ -1151,7 +1159,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * Q - set Quiet mode (reduce debugging output) * ---------------- */ - flagQ = true; Verbose = 0; break; @@ -1179,7 +1186,11 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) break; case 'T': - parse_options(optarg); + /* ---------------- + * T - tracing options + * ---------------- + */ + parse_options(optarg, secure); break; case 't': @@ -1214,7 +1225,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) break; case 'v': - FrontendProtocol = (ProtocolVersion) atoi(optarg); + if (secure) + FrontendProtocol = (ProtocolVersion) atoi(optarg); break; case 'W': @@ -1268,32 +1280,38 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) } /* ---------------- - * get user name and pathname and check command line validity + * get user name (needed now in case it is the default database name) + * and check command line validity * ---------------- */ SetPgUserName(); userName = GetPgUserName(); -#ifdef CYR_RECODE - SetCharSet(); -#endif - - if (FindExec(pg_pathname, argv[0], "postgres") < 0) - elog(FATAL, "%s: could not locate executable, bailing out...", - argv[0]); - - if (errs || argc - optind > 1) + if (IsUnderPostmaster) { - usage(argv[0]); - proc_exit(1); + /* noninteractive case: nothing should be left after switches */ + if (errs || argc != optind || DBName == NULL) + { + usage(argv[0]); + proc_exit(1); + } } - else if (argc - optind == 1) - DBName = argv[optind]; - else if ((DBName = userName) == NULL) + else { - fprintf(stderr, "%s: USER undefined and no database specified\n", - argv[0]); - proc_exit(1); + /* interactive case: database name can be last arg on command line */ + if (errs || argc - optind > 1) + { + usage(argv[0]); + proc_exit(1); + } + else if (argc - optind == 1) + DBName = argv[optind]; + else if ((DBName = userName) == NULL) + { + fprintf(stderr, "%s: USER undefined and no database specified\n", + argv[0]); + proc_exit(1); + } } if (ShowStats && @@ -1308,14 +1326,22 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) fprintf(stderr, "%s does not know where to find the database system " "data. You must specify the directory that contains the " "database system either by specifying the -D invocation " - "option or by setting the PGDATA environment variable.\n\n", + "option or by setting the PGDATA environment variable.\n\n", argv[0]); proc_exit(1); } - Noversion = flagC; - EchoQuery = flagE; - EuroDates = flagEu; + /* + * Set up additional info. + */ + +#ifdef CYR_RECODE + SetCharSet(); +#endif + + if (FindExec(pg_pathname, argv[0], "postgres") < 0) + elog(FATAL, "%s: could not locate executable, bailing out...", + argv[0]); /* * Find remote host name or address. @@ -1398,30 +1424,23 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) } /* ---------------- - * initialize portal file descriptors + * initialize I/O * ---------------- */ if (IsUnderPostmaster) { - if (Portfd < 0) - { - fprintf(stderr, - "Postmaster flag set: no port number specified, use /dev/null\n"); -#ifndef __CYGWIN32__ - Portfd = open(NULL_DEV, O_RDWR, 0666); -#else - Portfd = open(NULL_DEV, O_RDWR | O_BINARY, 0666); -#endif - } - pq_init(); /* reset libpq */ + pq_init(); /* initialize libpq at backend startup */ whereToSendOutput = Remote; } else whereToSendOutput = Debug; + /* ---------------- + * general initialization + * ---------------- + */ SetProcessingMode(InitProcessing); - /* initialize */ if (Verbose) TPRINTF(TRACE_VERBOSE, "InitPostgres"); @@ -1485,7 +1504,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.114 $ $Date: 1999/05/22 02:55:58 $\n"); + puts("$Revision: 1.115 $ $Date: 1999/05/22 17:47:49 $\n"); } /* ---------------- @@ -1493,9 +1512,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) * * if an exception is encountered, processing resumes here * so we abort the current transaction and start a new one. - * This must be done after we initialize the slave backends - * so that the slaves signal the master to abort the transaction - * rather than calling AbortCurrentTransaction() themselves. * * Note: elog(ERROR) does a siglongjmp() to transfer control here. * ---------------- diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 344193ab529..588cb060fdf 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.28 1999/03/17 22:53:19 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.29 1999/05/22 17:47:46 tgl Exp $ * * NOTES * Globals used all over the place should be declared here and not @@ -36,7 +36,6 @@ #include "catalog/catname.h" ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST; -int Portfd = -1; bool Noversion = false; bool Quiet = false; @@ -47,11 +46,11 @@ struct Port *MyProcPort; long MyCancelKey; char *DataDir = NULL; - /* * The PGDATA directory user says to use, or defaults to via environment * variable. NULL if no option given and no environment variable set */ + Relation reldesc; /* current relation descriptor */ char OutputFileName[MAXPGPATH] = ""; diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index dfbca1c7e1c..ce6c4ca3210 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.27 1999/05/09 00:54:30 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.28 1999/05/22 17:47:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ #include "utils/syscache.h" #include "storage/fd.h" /* for O_ */ +#include "storage/ipc.h" /* for proc_exit */ /* * EnableAbortEnvVarName diff --git a/src/backend/utils/misc/trace.c b/src/backend/utils/misc/trace.c index 1f96065c9ef..871e1d436a0 100644 --- a/src/backend/utils/misc/trace.c +++ b/src/backend/utils/misc/trace.c @@ -257,9 +257,13 @@ set_option_flag(int flag, int value) /* * Parse an option string like "name,name+,name-,name=value". * Single options are delimited by ',',space,tab,newline or cr. + * + * If 'secure' is false, the option string came from a remote client via + * connection "debug options" field --- do not obey any requests that + * might potentially be security loopholes. */ void -parse_options(char *str) +parse_options(char *str, bool secure) { char *s, *name; @@ -384,7 +388,7 @@ read_pg_options(SIGNAL_ARGS) p--; *p = '\0'; verbose = pg_options[TRACE_VERBOSE]; - parse_options(buffer); + parse_options(buffer, true); verbose |= pg_options[TRACE_VERBOSE]; if (verbose || postgres_signal_arg == SIGHUP) tprintf(TRACE_ALL, "read_pg_options: %s", buffer); |