diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/libpq/auth.c | 27 | ||||
-rw-r--r-- | src/backend/postmaster/postmaster.c | 153 |
2 files changed, 64 insertions, 116 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 0ba85301149..44b2212b1da 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -45,6 +45,12 @@ static void auth_failed(Port *port, int status, char *logdetail); static char *recv_password_packet(Port *port); static int recv_and_check_password_packet(Port *port, char **logdetail); +/*---------------------------------------------------------------- + * MD5 authentication + *---------------------------------------------------------------- + */ +static int CheckMD5Auth(Port *port, char **logdetail); + /*---------------------------------------------------------------- * Ident authentication @@ -535,9 +541,7 @@ ClientAuthentication(Port *port) ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"))); - /* include the salt to use for computing the response */ - sendAuthRequest(port, AUTH_REQ_MD5, port->md5Salt, 4); - status = recv_and_check_password_packet(port, &logdetail); + status = CheckMD5Auth(port, &logdetail); break; case uaPassword: @@ -692,10 +696,25 @@ recv_password_packet(Port *port) /*---------------------------------------------------------------- - * MD5 authentication + * MD5 and password authentication *---------------------------------------------------------------- */ +static int +CheckMD5Auth(Port *port, char **logdetail) +{ + /* include the salt to use for computing the response */ + if (!pg_strong_random(port->md5Salt, sizeof(port->md5Salt))) + { + *logdetail = psprintf(_("Could not generate random salt")); + return STATUS_ERROR; + } + + sendAuthRequest(port, AUTH_REQ_MD5, port->md5Salt, 4); + return recv_and_check_password_packet(port, logdetail); +} + + /* * Called when we have sent an authorization request for a password. * Get the response and check it. diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 2d43506cd0e..44201386733 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -358,14 +358,6 @@ static volatile bool avlauncher_needs_signal = false; static volatile bool StartWorkerNeeded = true; static volatile bool HaveCrashedWorker = false; -/* - * State for assigning random salts and cancel keys. - * Also, the global MyCancelKey passes the cancel key assigned to a given - * backend from the postmaster to that backend (via fork). - */ -static unsigned int random_seed = 0; -static struct timeval random_start_time; - #ifdef USE_BONJOUR static DNSServiceRef bonjour_sdref = NULL; #endif @@ -403,8 +395,6 @@ static void processCancelRequest(Port *port, void *pkt); static int initMasks(fd_set *rmask); static void report_fork_failure_to_client(Port *port, int errnum); static CAC_state canAcceptConnections(void); -static long PostmasterRandom(void); -static void RandomSalt(char *salt, int len); static void signal_child(pid_t pid, int signal); static bool SignalSomeChildren(int signal, int targets); static void TerminateChildren(int signal); @@ -579,9 +569,11 @@ PostmasterMain(int argc, char *argv[]) * Initialize random(3) so we don't get the same values in every run. * * Note: the seed is pretty predictable from externally-visible facts such - * as postmaster start time, so avoid using random() for security-critical - * random values during postmaster startup. At the time of first - * connection, PostmasterRandom will select a hopefully-more-random seed. + * as postmaster start time, so don't use random() for security-critical + * random values (use pg_strong_random() instead). Backends select a + * somewhat more random seed after forking, in BackendRun(), based on the + * PID and session start timestamp, but that is still not suitable for + * security-critical values. */ srandom((unsigned int) (MyProcPid ^ MyStartTime)); @@ -1292,8 +1284,6 @@ PostmasterMain(int argc, char *argv[]) * Remember postmaster startup time */ PgStartTime = GetCurrentTimestamp(); - /* PostmasterRandom wants its own copy */ - gettimeofday(&random_start_time, NULL); /* * We're ready to rock and roll... @@ -2344,15 +2334,6 @@ ConnCreate(int serverFd) } /* - * Precompute password salt values to use for this connection. It's - * slightly annoying to do this long in advance of knowing whether we'll - * need 'em or not, but we must do the random() calls before we fork, not - * after. Else the postmaster's random sequence won't get advanced, and - * all backends would end up using the same salt... - */ - RandomSalt(port->md5Salt, sizeof(port->md5Salt)); - - /* * Allocate GSSAPI specific state struct */ #ifndef EXEC_BACKEND @@ -3904,7 +3885,12 @@ BackendStartup(Port *port) * backend will have its own copy in the forked-off process' value of * MyCancelKey, so that it can transmit the key to the frontend. */ - MyCancelKey = PostmasterRandom(); + if (!pg_strong_random(&MyCancelKey, sizeof(MyCancelKey))) + { + ereport(LOG, + (errmsg("could not generate random query cancel key"))); + return STATUS_ERROR; + } bn->cancel_key = MyCancelKey; /* Pass down canAcceptConnections state */ @@ -4212,13 +4198,6 @@ BackendRun(Port *port) int usecs; int i; - /* - * Don't want backend to be able to see the postmaster random number - * generator state. We have to clobber the static random_seed *and* start - * a new random sequence in the random() library function. - */ - random_seed = 0; - random_start_time.tv_usec = 0; /* slightly hacky way to convert timestamptz into integers */ TimestampDifference(0, port->SessionStartTime, &secs, &usecs); srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs)); @@ -5067,66 +5046,6 @@ StartupPacketTimeoutHandler(void) /* - * RandomSalt - */ -static void -RandomSalt(char *salt, int len) -{ - long rand; - int i; - - /* - * We use % 255, sacrificing one possible byte value, so as to ensure that - * all bits of the random() value participate in the result. While at it, - * add one to avoid generating any null bytes. - */ - for (i = 0; i < len; i++) - { - rand = PostmasterRandom(); - salt[i] = (rand % 255) + 1; - } -} - -/* - * PostmasterRandom - * - * Caution: use this only for values needed during connection-request - * processing. Otherwise, the intended property of having an unpredictable - * delay between random_start_time and random_stop_time will be broken. - */ -static long -PostmasterRandom(void) -{ - /* - * Select a random seed at the time of first receiving a request. - */ - if (random_seed == 0) - { - do - { - struct timeval random_stop_time; - - gettimeofday(&random_stop_time, NULL); - - /* - * We are not sure how much precision is in tv_usec, so we swap - * the high and low 16 bits of 'random_stop_time' and XOR them - * with 'random_start_time'. On the off chance that the result is - * 0, we loop until it isn't. - */ - random_seed = random_start_time.tv_usec ^ - ((random_stop_time.tv_usec << 16) | - ((random_stop_time.tv_usec >> 16) & 0xffff)); - } - while (random_seed == 0); - - srandom(random_seed); - } - - return random(); -} - -/* * Count up number of child processes of specified types (dead_end chidren * are always excluded). */ @@ -5303,31 +5222,37 @@ StartAutovacuumWorker(void) * we'd better have something random in the field to prevent * unfriendly people from sending cancels to them. */ - MyCancelKey = PostmasterRandom(); - bn->cancel_key = MyCancelKey; + if (pg_strong_random(&MyCancelKey, sizeof(MyCancelKey))) + { + bn->cancel_key = MyCancelKey; - /* Autovac workers are not dead_end and need a child slot */ - bn->dead_end = false; - bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); - bn->bgworker_notify = false; + /* Autovac workers are not dead_end and need a child slot */ + bn->dead_end = false; + bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); + bn->bgworker_notify = false; - bn->pid = StartAutoVacWorker(); - if (bn->pid > 0) - { - bn->bkend_type = BACKEND_TYPE_AUTOVAC; - dlist_push_head(&BackendList, &bn->elem); + bn->pid = StartAutoVacWorker(); + if (bn->pid > 0) + { + bn->bkend_type = BACKEND_TYPE_AUTOVAC; + dlist_push_head(&BackendList, &bn->elem); #ifdef EXEC_BACKEND - ShmemBackendArrayAdd(bn); + ShmemBackendArrayAdd(bn); #endif - /* all OK */ - return; + /* all OK */ + return; + } + + /* + * fork failed, fall through to report -- actual error message + * was logged by StartAutoVacWorker + */ + (void) ReleasePostmasterChildSlot(bn->child_slot); } + else + ereport(LOG, + (errmsg("could not generate random query cancel key"))); - /* - * fork failed, fall through to report -- actual error message was - * logged by StartAutoVacWorker - */ - (void) ReleasePostmasterChildSlot(bn->child_slot); free(bn); } else @@ -5615,7 +5540,11 @@ assign_backendlist_entry(RegisteredBgWorker *rw) * have something random in the field to prevent unfriendly people from * sending cancels to them. */ - MyCancelKey = PostmasterRandom(); + if (!pg_strong_random(&MyCancelKey, sizeof(MyCancelKey))) + { + rw->rw_crashed_at = GetCurrentTimestamp(); + return false; + } bn->cancel_key = MyCancelKey; bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot(); |