LCOV - code coverage report
Current view: top level - src/backend/libpq - be-secure-common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 25 53 47.2 %
Date: 2019-09-19 02:07:14 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * be-secure-common.c
       4             :  *
       5             :  * common implementation-independent SSL support code
       6             :  *
       7             :  * While be-secure.c contains the interfaces that the rest of the
       8             :  * communications code calls, this file contains support routines that are
       9             :  * used by the library-specific implementations such as be-secure-openssl.c.
      10             :  *
      11             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      12             :  * Portions Copyright (c) 1994, Regents of the University of California
      13             :  *
      14             :  * IDENTIFICATION
      15             :  *    src/backend/libpq/be-secure-common.c
      16             :  *
      17             :  *-------------------------------------------------------------------------
      18             :  */
      19             : 
      20             : #include "postgres.h"
      21             : 
      22             : #include <sys/stat.h>
      23             : #include <unistd.h>
      24             : 
      25             : #include "common/string.h"
      26             : #include "libpq/libpq.h"
      27             : #include "storage/fd.h"
      28             : 
      29             : /*
      30             :  * Run ssl_passphrase_command
      31             :  *
      32             :  * prompt will be substituted for %p.  is_server_start determines the loglevel
      33             :  * of error messages.
      34             :  *
      35             :  * The result will be put in buffer buf, which is of size size.  The return
      36             :  * value is the length of the actual result.
      37             :  */
      38             : int
      39           4 : run_ssl_passphrase_command(const char *prompt, bool is_server_start, char *buf, int size)
      40             : {
      41           4 :     int         loglevel = is_server_start ? ERROR : LOG;
      42             :     StringInfoData command;
      43             :     char       *p;
      44             :     FILE       *fh;
      45             :     int         pclose_rc;
      46           4 :     size_t      len = 0;
      47             : 
      48             :     Assert(prompt);
      49             :     Assert(size > 0);
      50           4 :     buf[0] = '\0';
      51             : 
      52           4 :     initStringInfo(&command);
      53             : 
      54          64 :     for (p = ssl_passphrase_command; *p; p++)
      55             :     {
      56          60 :         if (p[0] == '%')
      57             :         {
      58           0 :             switch (p[1])
      59             :             {
      60             :                 case 'p':
      61           0 :                     appendStringInfoString(&command, prompt);
      62           0 :                     p++;
      63           0 :                     break;
      64             :                 case '%':
      65           0 :                     appendStringInfoChar(&command, '%');
      66           0 :                     p++;
      67           0 :                     break;
      68             :                 default:
      69           0 :                     appendStringInfoChar(&command, p[0]);
      70             :             }
      71             :         }
      72             :         else
      73          60 :             appendStringInfoChar(&command, p[0]);
      74             :     }
      75             : 
      76           4 :     fh = OpenPipeStream(command.data, "r");
      77           4 :     if (fh == NULL)
      78             :     {
      79           0 :         ereport(loglevel,
      80             :                 (errcode_for_file_access(),
      81             :                  errmsg("could not execute command \"%s\": %m",
      82             :                         command.data)));
      83           0 :         goto error;
      84             :     }
      85             : 
      86           4 :     if (!fgets(buf, size, fh))
      87             :     {
      88           0 :         if (ferror(fh))
      89             :         {
      90           0 :             explicit_bzero(buf, size);
      91           0 :             ereport(loglevel,
      92             :                     (errcode_for_file_access(),
      93             :                      errmsg("could not read from command \"%s\": %m",
      94             :                             command.data)));
      95           0 :             goto error;
      96             :         }
      97             :     }
      98             : 
      99           4 :     pclose_rc = ClosePipeStream(fh);
     100           4 :     if (pclose_rc == -1)
     101             :     {
     102           0 :         explicit_bzero(buf, size);
     103           0 :         ereport(loglevel,
     104             :                 (errcode_for_file_access(),
     105             :                  errmsg("could not close pipe to external command: %m")));
     106           0 :         goto error;
     107             :     }
     108           4 :     else if (pclose_rc != 0)
     109             :     {
     110           0 :         explicit_bzero(buf, size);
     111           0 :         ereport(loglevel,
     112             :                 (errcode_for_file_access(),
     113             :                  errmsg("command \"%s\" failed",
     114             :                         command.data),
     115             :                  errdetail_internal("%s", wait_result_to_str(pclose_rc))));
     116           0 :         goto error;
     117             :     }
     118             : 
     119             :     /* strip trailing newline and carriage return */
     120           4 :     len = pg_strip_crlf(buf);
     121             : 
     122             : error:
     123           4 :     pfree(command.data);
     124           4 :     return len;
     125             : }
     126             : 
     127             : 
     128             : /*
     129             :  * Check permissions for SSL key files.
     130             :  */
     131             : bool
     132          20 : check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
     133             : {
     134          20 :     int         loglevel = isServerStart ? FATAL : LOG;
     135             :     struct stat buf;
     136             : 
     137          20 :     if (stat(ssl_key_file, &buf) != 0)
     138             :     {
     139           0 :         ereport(loglevel,
     140             :                 (errcode_for_file_access(),
     141             :                  errmsg("could not access private key file \"%s\": %m",
     142             :                         ssl_key_file)));
     143           0 :         return false;
     144             :     }
     145             : 
     146          20 :     if (!S_ISREG(buf.st_mode))
     147             :     {
     148           0 :         ereport(loglevel,
     149             :                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
     150             :                  errmsg("private key file \"%s\" is not a regular file",
     151             :                         ssl_key_file)));
     152           0 :         return false;
     153             :     }
     154             : 
     155             :     /*
     156             :      * Refuse to load key files owned by users other than us or root.
     157             :      *
     158             :      * XXX surely we can check this on Windows somehow, too.
     159             :      */
     160             : #if !defined(WIN32) && !defined(__CYGWIN__)
     161          20 :     if (buf.st_uid != geteuid() && buf.st_uid != 0)
     162             :     {
     163           0 :         ereport(loglevel,
     164             :                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
     165             :                  errmsg("private key file \"%s\" must be owned by the database user or root",
     166             :                         ssl_key_file)));
     167           0 :         return false;
     168             :     }
     169             : #endif
     170             : 
     171             :     /*
     172             :      * Require no public access to key file. If the file is owned by us,
     173             :      * require mode 0600 or less. If owned by root, require 0640 or less to
     174             :      * allow read access through our gid, or a supplementary gid that allows
     175             :      * to read system-wide certificates.
     176             :      *
     177             :      * XXX temporarily suppress check when on Windows, because there may not
     178             :      * be proper support for Unix-y file permissions.  Need to think of a
     179             :      * reasonable check to apply on Windows.  (See also the data directory
     180             :      * permission check in postmaster.c)
     181             :      */
     182             : #if !defined(WIN32) && !defined(__CYGWIN__)
     183          40 :     if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
     184          20 :         (buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
     185             :     {
     186           0 :         ereport(loglevel,
     187             :                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
     188             :                  errmsg("private key file \"%s\" has group or world access",
     189             :                         ssl_key_file),
     190             :                  errdetail("File must have permissions u=rw (0600) or less if owned by the database user, or permissions u=rw,g=r (0640) or less if owned by root.")));
     191           0 :         return false;
     192             :     }
     193             : #endif
     194             : 
     195          20 :     return true;
     196             : }

Generated by: LCOV version 1.13