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

Generated by: LCOV version 1.13