LCOV - differential code coverage report
Current view: top level - src/common - exec.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 66.7 % 111 74 5 32 7 67 7 5
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 8 8 2 6 1
Baseline: 16@8cea358b128 Branches: 35.0 % 80 28 11 41 3 25
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 0.0 % 2 0 2
(60,120] days: 70.0 % 10 7 3 7
(240..) days: 67.7 % 99 67 32 67
Function coverage date bins:
(60,120] days: 100.0 % 1 1 1
(240..) days: 100.0 % 7 7 1 6
Branch coverage date bins:
[..60] days: 0.0 % 4 0 4
(60,120] days: 30.0 % 10 3 7 3
(240..) days: 37.9 % 66 25 41 25

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * exec.c
                                  4                 :                :  *      Functions for finding and validating executable files
                                  5                 :                :  *
                                  6                 :                :  *
                                  7                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  8                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  9                 :                :  *
                                 10                 :                :  *
                                 11                 :                :  * IDENTIFICATION
                                 12                 :                :  *    src/common/exec.c
                                 13                 :                :  *
                                 14                 :                :  *-------------------------------------------------------------------------
                                 15                 :                :  */
                                 16                 :                : 
                                 17                 :                : /*
                                 18                 :                :  * On macOS, "man realpath" avers:
                                 19                 :                :  *    Defining _DARWIN_C_SOURCE or _DARWIN_BETTER_REALPATH before including
                                 20                 :                :  *    stdlib.h will cause the provided implementation of realpath() to use
                                 21                 :                :  *    F_GETPATH from fcntl(2) to discover the path.
                                 22                 :                :  * This should be harmless everywhere else.
                                 23                 :                :  */
                                 24                 :                : #define _DARWIN_BETTER_REALPATH
                                 25                 :                : 
                                 26                 :                : #ifndef FRONTEND
                                 27                 :                : #include "postgres.h"
                                 28                 :                : #else
                                 29                 :                : #include "postgres_fe.h"
                                 30                 :                : #endif
                                 31                 :                : 
                                 32                 :                : #include <signal.h>
                                 33                 :                : #include <sys/stat.h>
                                 34                 :                : #include <sys/wait.h>
                                 35                 :                : #include <unistd.h>
                                 36                 :                : 
                                 37                 :                : #ifdef EXEC_BACKEND
                                 38                 :                : #if defined(HAVE_SYS_PERSONALITY_H)
                                 39                 :                : #include <sys/personality.h>
                                 40                 :                : #elif defined(HAVE_SYS_PROCCTL_H)
                                 41                 :                : #include <sys/procctl.h>
                                 42                 :                : #endif
                                 43                 :                : #endif
                                 44                 :                : 
                                 45                 :                : #include "common/string.h"
                                 46                 :                : 
                                 47                 :                : /* Inhibit mingw CRT's auto-globbing of command line arguments */
                                 48                 :                : #if defined(WIN32) && !defined(_MSC_VER)
                                 49                 :                : extern int  _CRT_glob = 0;      /* 0 turns off globbing; 1 turns it on */
                                 50                 :                : #endif
                                 51                 :                : 
                                 52                 :                : /*
                                 53                 :                :  * Hacky solution to allow expressing both frontend and backend error reports
                                 54                 :                :  * in one macro call.  First argument of log_error is an errcode() call of
                                 55                 :                :  * some sort (ignored if FRONTEND); the rest are errmsg_internal() arguments,
                                 56                 :                :  * i.e. message string and any parameters for it.
                                 57                 :                :  *
                                 58                 :                :  * Caller must provide the gettext wrapper around the message string, if
                                 59                 :                :  * appropriate, so that it gets translated in the FRONTEND case; this
                                 60                 :                :  * motivates using errmsg_internal() not errmsg().  We handle appending a
                                 61                 :                :  * newline, if needed, inside the macro, so that there's only one translatable
                                 62                 :                :  * string per call not two.
                                 63                 :                :  */
                                 64                 :                : #ifndef FRONTEND
                                 65                 :                : #define log_error(errcodefn, ...) \
                                 66                 :                :     ereport(LOG, (errcodefn, errmsg_internal(__VA_ARGS__)))
                                 67                 :                : #else
                                 68                 :                : #define log_error(errcodefn, ...) \
                                 69                 :                :     (fprintf(stderr, __VA_ARGS__), fputc('\n', stderr))
                                 70                 :                : #endif
                                 71                 :                : 
                                 72                 :                : static int  normalize_exec_path(char *path);
                                 73                 :                : static char *pg_realpath(const char *fname);
                                 74                 :                : 
                                 75                 :                : #ifdef WIN32
                                 76                 :                : static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser);
                                 77                 :                : #endif
                                 78                 :                : 
                                 79                 :                : /*
                                 80                 :                :  * validate_exec -- validate "path" as an executable file
                                 81                 :                :  *
                                 82                 :                :  * returns 0 if the file is found and no error is encountered.
                                 83                 :                :  *        -1 if the regular file "path" does not exist or cannot be executed.
                                 84                 :                :  *        -2 if the file is otherwise valid but cannot be read.
                                 85                 :                :  * in the failure cases, errno is set appropriately
                                 86                 :                :  */
                                 87                 :                : int
 7265 bruce@momjian.us           88                 :CBC       16687 : validate_exec(const char *path)
                                 89                 :                : {
                                 90                 :                :     struct stat buf;
                                 91                 :                :     int         is_r;
                                 92                 :                :     int         is_x;
                                 93                 :                : 
                                 94                 :                : #ifdef WIN32
                                 95                 :                :     char        path_exe[MAXPGPATH + sizeof(".exe") - 1];
                                 96                 :                : 
                                 97                 :                :     /* Win32 requires a .exe suffix for stat() */
                                 98                 :                :     if (strlen(path) < strlen(".exe") ||
                                 99                 :                :         pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
                                100                 :                :     {
                                101                 :                :         strlcpy(path_exe, path, sizeof(path_exe) - 4);
                                102                 :                :         strcat(path_exe, ".exe");
                                103                 :                :         path = path_exe;
                                104                 :                :     }
                                105                 :                : #endif
                                106                 :                : 
                                107                 :                :     /*
                                108                 :                :      * Ensure that the file exists and is a regular file.
                                109                 :                :      *
                                110                 :                :      * XXX if you have a broken system where stat() looks at the symlink
                                111                 :                :      * instead of the underlying file, you lose.
                                112                 :                :      */
 9716                           113         [ -  + ]:          16687 :     if (stat(path, &buf) < 0)
 9357 bruce@momjian.us          114                 :UBC           0 :         return -1;
                                115                 :                : 
 5858 tgl@sss.pgh.pa.us         116         [ -  + ]:CBC       16687 :     if (!S_ISREG(buf.st_mode))
                                117                 :                :     {
                                118                 :                :         /*
                                119                 :                :          * POSIX offers no errno code that's simply "not a regular file".  If
                                120                 :                :          * it's a directory we can use EISDIR.  Otherwise, it's most likely a
                                121                 :                :          * device special file, and EPERM (Operation not permitted) isn't too
                                122                 :                :          * horribly off base.
                                123                 :                :          */
  642 tgl@sss.pgh.pa.us         124         [ #  # ]:UBC           0 :         errno = S_ISDIR(buf.st_mode) ? EISDIR : EPERM;
 9357 bruce@momjian.us          125                 :              0 :         return -1;
                                126                 :                :     }
                                127                 :                : 
                                128                 :                :     /*
                                129                 :                :      * Ensure that the file is both executable and readable (required for
                                130                 :                :      * dynamic loading).
                                131                 :                :      */
                                132                 :                : #ifndef WIN32
 5204 tgl@sss.pgh.pa.us         133                 :CBC       16687 :     is_r = (access(path, R_OK) == 0);
                                134                 :          16687 :     is_x = (access(path, X_OK) == 0);
                                135                 :                :     /* access() will set errno if it returns -1 */
                                136                 :                : #else
                                137                 :                :     is_r = buf.st_mode & S_IRUSR;
                                138                 :                :     is_x = buf.st_mode & S_IXUSR;
                                139                 :                :     errno = EACCES;             /* appropriate thing if we return nonzero */
                                140                 :                : #endif
                                141   [ +  -  +  - ]:          16687 :     return is_x ? (is_r ? 0 : -2) : -1;
                                142                 :                : }
                                143                 :                : 
                                144                 :                : 
                                145                 :                : /*
                                146                 :                :  * find_my_exec -- find an absolute path to this program's executable
                                147                 :                :  *
                                148                 :                :  *  argv0 is the name passed on the command line
                                149                 :                :  *  retpath is the output area (must be of size MAXPGPATH)
                                150                 :                :  *  Returns 0 if OK, -1 if error.
                                151                 :                :  *
                                152                 :                :  * The reason we have to work so hard to find an absolute path is that
                                153                 :                :  * on some platforms we can't do dynamic loading unless we know the
                                154                 :                :  * executable's location.  Also, we need an absolute path not a relative
                                155                 :                :  * path because we may later change working directory.  Finally, we want
                                156                 :                :  * a true path not a symlink location, so that we can locate other files
                                157                 :                :  * that are part of our installation relative to the executable.
                                158                 :                :  */
                                159                 :                : int
 7269 bruce@momjian.us          160                 :          15795 : find_my_exec(const char *argv0, char *retpath)
                                161                 :                : {
                                162                 :                :     char       *path;
                                163                 :                : 
                                164                 :                :     /*
                                165                 :                :      * If argv0 contains a separator, then PATH wasn't used.
                                166                 :                :      */
  388 tgl@sss.pgh.pa.us         167                 :          15795 :     strlcpy(retpath, argv0, MAXPGPATH);
                                168         [ +  + ]:          15795 :     if (first_dir_separator(retpath) != NULL)
                                169                 :                :     {
 7269 bruce@momjian.us          170         [ +  - ]:          11754 :         if (validate_exec(retpath) == 0)
  388 tgl@sss.pgh.pa.us         171                 :          11754 :             return normalize_exec_path(retpath);
                                172                 :                : 
 2014 tgl@sss.pgh.pa.us         173         [ #  # ]:UBC           0 :         log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                174                 :                :                   _("invalid binary \"%s\": %m"), retpath);
 7099                           175                 :              0 :         return -1;
                                176                 :                :     }
                                177                 :                : 
                                178                 :                : #ifdef WIN32
                                179                 :                :     /* Win32 checks the current directory first for names without slashes */
                                180                 :                :     if (validate_exec(retpath) == 0)
                                181                 :                :         return normalize_exec_path(retpath);
                                182                 :                : #endif
                                183                 :                : 
                                184                 :                :     /*
                                185                 :                :      * Since no explicit path was supplied, the user must have been relying on
                                186                 :                :      * PATH.  We'll search the same PATH.
                                187                 :                :      */
 7265 bruce@momjian.us          188   [ +  -  +  - ]:CBC        4041 :     if ((path = getenv("PATH")) && *path)
                                189                 :                :     {
 7168                           190                 :           4041 :         char       *startp = NULL,
                                191                 :           4041 :                    *endp = NULL;
                                192                 :                : 
                                193                 :                :         do
                                194                 :                :         {
 7265                           195         [ +  - ]:           4041 :             if (!startp)
                                196                 :           4041 :                 startp = path;
                                197                 :                :             else
 7265 bruce@momjian.us          198                 :UBC           0 :                 startp = endp + 1;
                                199                 :                : 
 4820 bruce@momjian.us          200                 :CBC        4041 :             endp = first_path_var_separator(startp);
 7265                           201         [ -  + ]:           4041 :             if (!endp)
 7168 bruce@momjian.us          202                 :UBC           0 :                 endp = startp + strlen(startp); /* point to end */
                                203                 :                : 
  388 tgl@sss.pgh.pa.us         204                 :CBC        4041 :             strlcpy(retpath, startp, Min(endp - startp + 1, MAXPGPATH));
                                205                 :                : 
                                206                 :           4041 :             join_path_components(retpath, retpath, argv0);
 7269 bruce@momjian.us          207                 :           4041 :             canonicalize_path(retpath);
                                208                 :                : 
                                209   [ +  -  -  - ]:           4041 :             switch (validate_exec(retpath))
                                210                 :                :             {
 2489 tgl@sss.pgh.pa.us         211                 :           4041 :                 case 0:         /* found ok */
  388                           212                 :           4041 :                     return normalize_exec_path(retpath);
 9715 bruce@momjian.us          213                 :UBC           0 :                 case -1:        /* wasn't even a candidate, keep looking */
 7099 tgl@sss.pgh.pa.us         214                 :              0 :                     break;
 9715 bruce@momjian.us          215                 :              0 :                 case -2:        /* found but disqualified */
 2014 tgl@sss.pgh.pa.us         216         [ #  # ]:              0 :                     log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                217                 :                :                               _("could not read binary \"%s\": %m"),
                                218                 :                :                               retpath);
 7099                           219                 :              0 :                     break;
                                220                 :                :             }
 7265 bruce@momjian.us          221         [ #  # ]:              0 :         } while (*endp);
                                222                 :                :     }
                                223                 :                : 
 2014 tgl@sss.pgh.pa.us         224         [ #  # ]:              0 :     log_error(errcode(ERRCODE_UNDEFINED_FILE),
                                225                 :                :               _("could not find a \"%s\" to execute"), argv0);
 9357 bruce@momjian.us          226                 :              0 :     return -1;
                                227                 :                : }
                                228                 :                : 
                                229                 :                : 
                                230                 :                : /*
                                231                 :                :  * normalize_exec_path - resolve symlinks and convert to absolute path
                                232                 :                :  *
                                233                 :                :  * Given a path that refers to an executable, chase through any symlinks
                                234                 :                :  * to find the real file location; then convert that to an absolute path.
                                235                 :                :  *
                                236                 :                :  * On success, replaces the contents of "path" with the absolute path.
                                237                 :                :  * ("path" is assumed to be of size MAXPGPATH.)
                                238                 :                :  * Returns 0 if OK, -1 if error.
                                239                 :                :  */
                                240                 :                : static int
  388 tgl@sss.pgh.pa.us         241                 :CBC       15795 : normalize_exec_path(char *path)
                                242                 :                : {
                                243                 :                :     /*
                                244                 :                :      * We used to do a lot of work ourselves here, but now we just let
                                245                 :                :      * realpath(3) do all the heavy lifting.
                                246                 :                :      */
                                247                 :          15795 :     char       *abspath = pg_realpath(path);
                                248                 :                : 
                                249         [ -  + ]:          15795 :     if (abspath == NULL)
                                250                 :                :     {
 2014 tgl@sss.pgh.pa.us         251         [ #  # ]:UBC           0 :         log_error(errcode_for_file_access(),
                                252                 :                :                   _("could not resolve path \"%s\" to absolute form: %m"),
                                253                 :                :                   path);
 7099                           254                 :              0 :         return -1;
                                255                 :                :     }
  388 tgl@sss.pgh.pa.us         256                 :CBC       15795 :     strlcpy(path, abspath, MAXPGPATH);
                                257                 :          15795 :     free(abspath);
                                258                 :                : 
                                259                 :                : #ifdef WIN32
                                260                 :                :     /* On Windows, be sure to convert '\' to '/' */
                                261                 :                :     canonicalize_path(path);
                                262                 :                : #endif
                                263                 :                : 
                                264                 :          15795 :     return 0;
                                265                 :                : }
                                266                 :                : 
                                267                 :                : 
                                268                 :                : /*
                                269                 :                :  * pg_realpath() - realpath(3) with POSIX.1-2008 semantics
                                270                 :                :  *
                                271                 :                :  * This is equivalent to realpath(fname, NULL), in that it returns a
                                272                 :                :  * malloc'd buffer containing the absolute path equivalent to fname.
                                273                 :                :  * On error, returns NULL with errno set.
                                274                 :                :  *
                                275                 :                :  * On Windows, what you get is spelled per platform conventions,
                                276                 :                :  * so you probably want to apply canonicalize_path() to the result.
                                277                 :                :  *
                                278                 :                :  * For now, this is needed only here so mark it static.  If you choose to
                                279                 :                :  * move it into its own file, move the _DARWIN_BETTER_REALPATH #define too!
                                280                 :                :  */
                                281                 :                : static char *
                                282                 :          15795 : pg_realpath(const char *fname)
                                283                 :                : {
                                284                 :                :     char       *path;
                                285                 :                : 
                                286                 :                : #ifndef WIN32
                                287                 :          15795 :     path = realpath(fname, NULL);
                                288   [ -  +  -  - ]:          15795 :     if (path == NULL && errno == EINVAL)
                                289                 :                :     {
                                290                 :                :         /*
                                291                 :                :          * Cope with old-POSIX systems that require a user-provided buffer.
                                292                 :                :          * Assume MAXPGPATH is enough room on all such systems.
                                293                 :                :          */
  388 tgl@sss.pgh.pa.us         294                 :UBC           0 :         char       *buf = malloc(MAXPGPATH);
                                295                 :                : 
                                296         [ #  # ]:              0 :         if (buf == NULL)
                                297                 :              0 :             return NULL;        /* assume errno is set */
                                298                 :              0 :         path = realpath(fname, buf);
                                299         [ #  # ]:              0 :         if (path == NULL)       /* don't leak memory */
                                300                 :                :         {
                                301                 :              0 :             int         save_errno = errno;
                                302                 :                : 
                                303                 :              0 :             free(buf);
                                304                 :              0 :             errno = save_errno;
                                305                 :                :         }
                                306                 :                :     }
                                307                 :                : #else                           /* WIN32 */
                                308                 :                : 
                                309                 :                :     /*
                                310                 :                :      * Microsoft is resolutely non-POSIX, but _fullpath() does the same thing.
                                311                 :                :      * The documentation claims it reports errors by setting errno, which is a
                                312                 :                :      * bit surprising for Microsoft, but we'll believe that until it's proven
                                313                 :                :      * wrong.  Clear errno first, though, so we can at least tell if a failure
                                314                 :                :      * occurs and doesn't set it.
                                315                 :                :      */
                                316                 :                :     errno = 0;
                                317                 :                :     path = _fullpath(NULL, fname, 0);
                                318                 :                : #endif
                                319                 :                : 
  388 tgl@sss.pgh.pa.us         320                 :CBC       15795 :     return path;
                                321                 :                : }
                                322                 :                : 
                                323                 :                : 
                                324                 :                : /*
                                325                 :                :  * Find another program in our binary's directory,
                                326                 :                :  * then make sure it is the proper version.
                                327                 :                :  */
                                328                 :                : int
 7099                           329                 :            766 : find_other_exec(const char *argv0, const char *target,
                                330                 :                :                 const char *versionstr, char *retpath)
                                331                 :                : {
                                332                 :                :     char        cmd[MAXPGPATH];
                                333                 :                :     char       *line;
                                334                 :                : 
                                335         [ -  + ]:            766 :     if (find_my_exec(argv0, retpath) < 0)
 7099 tgl@sss.pgh.pa.us         336                 :UBC           0 :         return -1;
                                337                 :                : 
                                338                 :                :     /* Trim off program name and keep just directory */
 7099 tgl@sss.pgh.pa.us         339                 :CBC         766 :     *last_dir_separator(retpath) = '\0';
                                340                 :            766 :     canonicalize_path(retpath);
                                341                 :                : 
                                342                 :                :     /* Now append the other program's name */
                                343                 :            766 :     snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
                                344                 :                :              "/%s%s", target, EXE);
                                345                 :                : 
                                346         [ -  + ]:            766 :     if (validate_exec(retpath) != 0)
 7099 tgl@sss.pgh.pa.us         347                 :UBC           0 :         return -1;
                                348                 :                : 
 4279 tgl@sss.pgh.pa.us         349                 :CBC         766 :     snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath);
                                350                 :                : 
   65 dgustafsson@postgres      351         [ -  + ]:GNC         766 :     if ((line = pipe_read_line(cmd)) == NULL)
 7099 tgl@sss.pgh.pa.us         352                 :UBC           0 :         return -1;
                                353                 :                : 
 7099 tgl@sss.pgh.pa.us         354         [ -  + ]:CBC         766 :     if (strcmp(line, versionstr) != 0)
                                355                 :                :     {
   65 dgustafsson@postgres      356                 :UNC           0 :         pfree(line);
 7099 tgl@sss.pgh.pa.us         357                 :UBC           0 :         return -2;
                                358                 :                :     }
                                359                 :                : 
   65 dgustafsson@postgres      360                 :GNC         766 :     pfree(line);
 7099 tgl@sss.pgh.pa.us         361                 :CBC         766 :     return 0;
                                362                 :                : }
                                363                 :                : 
                                364                 :                : 
                                365                 :                : /*
                                366                 :                :  * Execute a command in a pipe and read the first line from it. The returned
                                367                 :                :  * string is palloc'd (malloc'd in frontend code), the caller is responsible
                                368                 :                :  * for freeing.
                                369                 :                :  */
                                370                 :                : char *
   65 dgustafsson@postgres      371                 :GNC         893 : pipe_read_line(char *cmd)
                                372                 :                : {
                                373                 :                :     FILE       *pipe_cmd;
                                374                 :                :     char       *line;
                                375                 :                : 
  594 tgl@sss.pgh.pa.us         376                 :CBC         893 :     fflush(NULL);
                                377                 :                : 
 4279                           378                 :            893 :     errno = 0;
   65 dgustafsson@postgres      379         [ -  + ]:GNC         893 :     if ((pipe_cmd = popen(cmd, "r")) == NULL)
                                380                 :                :     {
   37 dgustafsson@postgres      381         [ #  # ]:UNC           0 :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                382                 :                :                   _("could not execute command \"%s\": %m"), cmd);
 7202 bruce@momjian.us          383                 :UBC           0 :         return NULL;
                                384                 :                :     }
                                385                 :                : 
                                386                 :                :     /* Make sure popen() didn't change errno */
 4279 tgl@sss.pgh.pa.us         387                 :CBC         893 :     errno = 0;
   65 dgustafsson@postgres      388                 :GNC         893 :     line = pg_get_line(pipe_cmd, NULL);
                                389                 :                : 
                                390         [ -  + ]:            893 :     if (line == NULL)
                                391                 :                :     {
   65 dgustafsson@postgres      392         [ #  # ]:UNC           0 :         if (ferror(pipe_cmd))
                                393         [ #  # ]:              0 :             log_error(errcode_for_file_access(),
                                394                 :                :                       _("could not read from command \"%s\": %m"), cmd);
                                395                 :                :         else
   37                           396         [ #  # ]:              0 :             log_error(errcode(ERRCODE_NO_DATA),
                                397                 :                :                       _("no data was returned by command \"%s\""), cmd);
                                398                 :                :     }
                                399                 :                : 
   65 dgustafsson@postgres      400                 :GNC         893 :     (void) pclose_check(pipe_cmd);
                                401                 :                : 
 7202 bruce@momjian.us          402                 :CBC         893 :     return line;
                                403                 :                : }
                                404                 :                : 
                                405                 :                : 
                                406                 :                : /*
                                407                 :                :  * pclose() plus useful error reporting
                                408                 :                :  */
                                409                 :                : int
 7271                           410                 :            972 : pclose_check(FILE *stream)
                                411                 :                : {
                                412                 :                :     int         exitstatus;
                                413                 :                :     char       *reason;
                                414                 :                : 
                                415                 :            972 :     exitstatus = pclose(stream);
                                416                 :                : 
                                417         [ +  + ]:            972 :     if (exitstatus == 0)
 7168                           418                 :            969 :         return 0;               /* all is well */
                                419                 :                : 
 7271                           420         [ -  + ]:              3 :     if (exitstatus == -1)
                                421                 :                :     {
                                422                 :                :         /* pclose() itself failed, and hopefully set errno */
 2014 tgl@sss.pgh.pa.us         423         [ #  # ]:UBC           0 :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                424                 :                :                   _("%s() failed: %m"), "pclose");
                                425                 :                :     }
                                426                 :                :     else
                                427                 :                :     {
 4064 heikki.linnakangas@i      428                 :CBC           3 :         reason = wait_result_to_str(exitstatus);
 2014 tgl@sss.pgh.pa.us         429         [ #  # ]:              3 :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                430                 :                :                   "%s", reason);
 4064 heikki.linnakangas@i      431                 :              3 :         pfree(reason);
                                432                 :                :     }
                                433                 :              3 :     return exitstatus;
                                434                 :                : }
                                435                 :                : 
                                436                 :                : /*
                                437                 :                :  *  set_pglocale_pgservice
                                438                 :                :  *
                                439                 :                :  *  Set application-specific locale and service directory
                                440                 :                :  *
                                441                 :                :  *  This function takes the value of argv[0] rather than a full path.
                                442                 :                :  *
                                443                 :                :  * (You may be wondering why this is in exec.c.  It requires this module's
                                444                 :                :  * services and doesn't introduce any new dependencies, so this seems as
                                445                 :                :  * good as anyplace.)
                                446                 :                :  */
                                447                 :                : void
 6425 tgl@sss.pgh.pa.us         448                 :          13638 : set_pglocale_pgservice(const char *argv0, const char *app)
                                449                 :                : {
                                450                 :                :     char        path[MAXPGPATH];
                                451                 :                :     char        my_exec_path[MAXPGPATH];
                                452                 :                : 
                                453                 :                :     /* don't set LC_ALL in the backend */
 5603 peter_e@gmx.net           454         [ +  + ]:          13638 :     if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
                                455                 :                :     {
 6425 tgl@sss.pgh.pa.us         456                 :          12076 :         setlocale(LC_ALL, "");
                                457                 :                : 
                                458                 :                :         /*
                                459                 :                :          * One could make a case for reproducing here PostmasterMain()'s test
                                460                 :                :          * for whether the process is multithreaded.  Unlike the postmaster,
                                461                 :                :          * no frontend program calls sigprocmask() or otherwise provides for
                                462                 :                :          * mutual exclusion between signal handlers.  While frontends using
                                463                 :                :          * fork(), if multithreaded, are formally exposed to undefined
                                464                 :                :          * behavior, we have not witnessed a concrete bug.  Therefore,
                                465                 :                :          * complaining about multithreading here may be mere pedantry.
                                466                 :                :          */
                                467                 :                :     }
                                468                 :                : 
                                469         [ -  + ]:          13638 :     if (find_my_exec(argv0, my_exec_path) < 0)
 6425 tgl@sss.pgh.pa.us         470                 :UBC           0 :         return;
                                471                 :                : 
                                472                 :                : #ifdef ENABLE_NLS
 6425 tgl@sss.pgh.pa.us         473                 :CBC       13638 :     get_locale_path(my_exec_path, path);
                                474                 :          13638 :     bindtextdomain(app, path);
                                475                 :          13638 :     textdomain(app);
                                476                 :                :     /* set for libpq to use, but don't override existing setting */
 1201                           477                 :          13638 :     setenv("PGLOCALEDIR", path, 0);
                                478                 :                : #endif
                                479                 :                : 
 6425                           480         [ +  + ]:          13638 :     if (getenv("PGSYSCONFDIR") == NULL)
                                481                 :                :     {
                                482                 :          10410 :         get_etc_path(my_exec_path, path);
                                483                 :                :         /* set for libpq to use */
 1201                           484                 :          10410 :         setenv("PGSYSCONFDIR", path, 0);
                                485                 :                :     }
                                486                 :                : }
                                487                 :                : 
                                488                 :                : #ifdef EXEC_BACKEND
                                489                 :                : /*
                                490                 :                :  * For the benefit of PostgreSQL developers testing EXEC_BACKEND on Unix
                                491                 :                :  * systems (code paths normally exercised only on Windows), provide a way to
                                492                 :                :  * disable address space layout randomization, if we know how on this platform.
                                493                 :                :  * Otherwise, backends may fail to attach to shared memory at the fixed address
                                494                 :                :  * chosen by the postmaster.  (See also the macOS-specific hack in
                                495                 :                :  * sysv_shmem.c.)
                                496                 :                :  */
                                497                 :                : int
                                498                 :                : pg_disable_aslr(void)
                                499                 :                : {
                                500                 :                : #if defined(HAVE_SYS_PERSONALITY_H)
                                501                 :                :     return personality(ADDR_NO_RANDOMIZE);
                                502                 :                : #elif defined(HAVE_SYS_PROCCTL_H) && defined(PROC_ASLR_FORCE_DISABLE)
                                503                 :                :     int         data = PROC_ASLR_FORCE_DISABLE;
                                504                 :                : 
                                505                 :                :     return procctl(P_PID, 0, PROC_ASLR_CTL, &data);
                                506                 :                : #else
                                507                 :                :     errno = ENOSYS;
                                508                 :                :     return -1;
                                509                 :                : #endif
                                510                 :                : }
                                511                 :                : #endif
                                512                 :                : 
                                513                 :                : #ifdef WIN32
                                514                 :                : 
                                515                 :                : /*
                                516                 :                :  * AddUserToTokenDacl(HANDLE hToken)
                                517                 :                :  *
                                518                 :                :  * This function adds the current user account to the restricted
                                519                 :                :  * token used when we create a restricted process.
                                520                 :                :  *
                                521                 :                :  * This is required because of some security changes in Windows
                                522                 :                :  * that appeared in patches to XP/2K3 and in Vista/2008.
                                523                 :                :  *
                                524                 :                :  * On these machines, the Administrator account is not included in
                                525                 :                :  * the default DACL - you just get Administrators + System. For
                                526                 :                :  * regular users you get User + System. Because we strip Administrators
                                527                 :                :  * when we create the restricted token, we are left with only System
                                528                 :                :  * in the DACL which leads to access denied errors for later CreatePipe()
                                529                 :                :  * and CreateProcess() calls when running as Administrator.
                                530                 :                :  *
                                531                 :                :  * This function fixes this problem by modifying the DACL of the
                                532                 :                :  * token the process will use, and explicitly re-adding the current
                                533                 :                :  * user account.  This is still secure because the Administrator account
                                534                 :                :  * inherits its privileges from the Administrators group - it doesn't
                                535                 :                :  * have any of its own.
                                536                 :                :  */
                                537                 :                : BOOL
                                538                 :                : AddUserToTokenDacl(HANDLE hToken)
                                539                 :                : {
                                540                 :                :     int         i;
                                541                 :                :     ACL_SIZE_INFORMATION asi;
                                542                 :                :     ACCESS_ALLOWED_ACE *pace;
                                543                 :                :     DWORD       dwNewAclSize;
                                544                 :                :     DWORD       dwSize = 0;
                                545                 :                :     DWORD       dwTokenInfoLength = 0;
                                546                 :                :     PACL        pacl = NULL;
                                547                 :                :     PTOKEN_USER pTokenUser = NULL;
                                548                 :                :     TOKEN_DEFAULT_DACL tddNew;
                                549                 :                :     TOKEN_DEFAULT_DACL *ptdd = NULL;
                                550                 :                :     TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl;
                                551                 :                :     BOOL        ret = FALSE;
                                552                 :                : 
                                553                 :                :     /* Figure out the buffer size for the DACL info */
                                554                 :                :     if (!GetTokenInformation(hToken, tic, (LPVOID) NULL, dwTokenInfoLength, &dwSize))
                                555                 :                :     {
                                556                 :                :         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                                557                 :                :         {
                                558                 :                :             ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize);
                                559                 :                :             if (ptdd == NULL)
                                560                 :                :             {
                                561                 :                :                 log_error(errcode(ERRCODE_OUT_OF_MEMORY),
                                562                 :                :                           _("out of memory"));
                                563                 :                :                 goto cleanup;
                                564                 :                :             }
                                565                 :                : 
                                566                 :                :             if (!GetTokenInformation(hToken, tic, (LPVOID) ptdd, dwSize, &dwSize))
                                567                 :                :             {
                                568                 :                :                 log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                569                 :                :                           "could not get token information: error code %lu",
                                570                 :                :                           GetLastError());
                                571                 :                :                 goto cleanup;
                                572                 :                :             }
                                573                 :                :         }
                                574                 :                :         else
                                575                 :                :         {
                                576                 :                :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                577                 :                :                       "could not get token information buffer size: error code %lu",
                                578                 :                :                       GetLastError());
                                579                 :                :             goto cleanup;
                                580                 :                :         }
                                581                 :                :     }
                                582                 :                : 
                                583                 :                :     /* Get the ACL info */
                                584                 :                :     if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID) &asi,
                                585                 :                :                            (DWORD) sizeof(ACL_SIZE_INFORMATION),
                                586                 :                :                            AclSizeInformation))
                                587                 :                :     {
                                588                 :                :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                589                 :                :                   "could not get ACL information: error code %lu",
                                590                 :                :                   GetLastError());
                                591                 :                :         goto cleanup;
                                592                 :                :     }
                                593                 :                : 
                                594                 :                :     /* Get the current user SID */
                                595                 :                :     if (!GetTokenUser(hToken, &pTokenUser))
                                596                 :                :         goto cleanup;           /* callee printed a message */
                                597                 :                : 
                                598                 :                :     /* Figure out the size of the new ACL */
                                599                 :                :     dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) +
                                600                 :                :         GetLengthSid(pTokenUser->User.Sid) - sizeof(DWORD);
                                601                 :                : 
                                602                 :                :     /* Allocate the ACL buffer & initialize it */
                                603                 :                :     pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize);
                                604                 :                :     if (pacl == NULL)
                                605                 :                :     {
                                606                 :                :         log_error(errcode(ERRCODE_OUT_OF_MEMORY),
                                607                 :                :                   _("out of memory"));
                                608                 :                :         goto cleanup;
                                609                 :                :     }
                                610                 :                : 
                                611                 :                :     if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION))
                                612                 :                :     {
                                613                 :                :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                614                 :                :                   "could not initialize ACL: error code %lu", GetLastError());
                                615                 :                :         goto cleanup;
                                616                 :                :     }
                                617                 :                : 
                                618                 :                :     /* Loop through the existing ACEs, and build the new ACL */
                                619                 :                :     for (i = 0; i < (int) asi.AceCount; i++)
                                620                 :                :     {
                                621                 :                :         if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *) &pace))
                                622                 :                :         {
                                623                 :                :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                624                 :                :                       "could not get ACE: error code %lu", GetLastError());
                                625                 :                :             goto cleanup;
                                626                 :                :         }
                                627                 :                : 
                                628                 :                :         if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER) pace)->AceSize))
                                629                 :                :         {
                                630                 :                :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                631                 :                :                       "could not add ACE: error code %lu", GetLastError());
                                632                 :                :             goto cleanup;
                                633                 :                :         }
                                634                 :                :     }
                                635                 :                : 
                                636                 :                :     /* Add the new ACE for the current user */
                                637                 :                :     if (!AddAccessAllowedAceEx(pacl, ACL_REVISION, OBJECT_INHERIT_ACE, GENERIC_ALL, pTokenUser->User.Sid))
                                638                 :                :     {
                                639                 :                :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                640                 :                :                   "could not add access allowed ACE: error code %lu",
                                641                 :                :                   GetLastError());
                                642                 :                :         goto cleanup;
                                643                 :                :     }
                                644                 :                : 
                                645                 :                :     /* Set the new DACL in the token */
                                646                 :                :     tddNew.DefaultDacl = pacl;
                                647                 :                : 
                                648                 :                :     if (!SetTokenInformation(hToken, tic, (LPVOID) &tddNew, dwNewAclSize))
                                649                 :                :     {
                                650                 :                :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                651                 :                :                   "could not set token information: error code %lu",
                                652                 :                :                   GetLastError());
                                653                 :                :         goto cleanup;
                                654                 :                :     }
                                655                 :                : 
                                656                 :                :     ret = TRUE;
                                657                 :                : 
                                658                 :                : cleanup:
                                659                 :                :     if (pTokenUser)
                                660                 :                :         LocalFree((HLOCAL) pTokenUser);
                                661                 :                : 
                                662                 :                :     if (pacl)
                                663                 :                :         LocalFree((HLOCAL) pacl);
                                664                 :                : 
                                665                 :                :     if (ptdd)
                                666                 :                :         LocalFree((HLOCAL) ptdd);
                                667                 :                : 
                                668                 :                :     return ret;
                                669                 :                : }
                                670                 :                : 
                                671                 :                : /*
                                672                 :                :  * GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser)
                                673                 :                :  *
                                674                 :                :  * Get the users token information from a process token.
                                675                 :                :  *
                                676                 :                :  * The caller of this function is responsible for calling LocalFree() on the
                                677                 :                :  * returned TOKEN_USER memory.
                                678                 :                :  */
                                679                 :                : static BOOL
                                680                 :                : GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser)
                                681                 :                : {
                                682                 :                :     DWORD       dwLength;
                                683                 :                : 
                                684                 :                :     *ppTokenUser = NULL;
                                685                 :                : 
                                686                 :                :     if (!GetTokenInformation(hToken,
                                687                 :                :                              TokenUser,
                                688                 :                :                              NULL,
                                689                 :                :                              0,
                                690                 :                :                              &dwLength))
                                691                 :                :     {
                                692                 :                :         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                                693                 :                :         {
                                694                 :                :             *ppTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwLength);
                                695                 :                : 
                                696                 :                :             if (*ppTokenUser == NULL)
                                697                 :                :             {
                                698                 :                :                 log_error(errcode(ERRCODE_OUT_OF_MEMORY),
                                699                 :                :                           _("out of memory"));
                                700                 :                :                 return FALSE;
                                701                 :                :             }
                                702                 :                :         }
                                703                 :                :         else
                                704                 :                :         {
                                705                 :                :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                706                 :                :                       "could not get token information buffer size: error code %lu",
                                707                 :                :                       GetLastError());
                                708                 :                :             return FALSE;
                                709                 :                :         }
                                710                 :                :     }
                                711                 :                : 
                                712                 :                :     if (!GetTokenInformation(hToken,
                                713                 :                :                              TokenUser,
                                714                 :                :                              *ppTokenUser,
                                715                 :                :                              dwLength,
                                716                 :                :                              &dwLength))
                                717                 :                :     {
                                718                 :                :         LocalFree(*ppTokenUser);
                                719                 :                :         *ppTokenUser = NULL;
                                720                 :                : 
                                721                 :                :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
                                722                 :                :                   "could not get token information: error code %lu",
                                723                 :                :                   GetLastError());
                                724                 :                :         return FALSE;
                                725                 :                :     }
                                726                 :                : 
                                727                 :                :     /* Memory in *ppTokenUser is LocalFree():d by the caller */
                                728                 :                :     return TRUE;
                                729                 :                : }
                                730                 :                : 
                                731                 :                : #endif
        

Generated by: LCOV version 2.1-beta2-3-g6141622