LCOV - differential code coverage report
Current view: top level - src/common - exec.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 64.9 % 111 72 9 6 18 6 5 40 16 11 17 36 11 19
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 8 8 6 2 5 3
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 66.7 % 24 16 8 1 15 1
Legend: Lines: hit not hit (180,240] days: 100.0 % 1 1 1
(240..) days: 64.0 % 86 55 1 6 18 6 5 39 11 17 35
Function coverage date bins:
[..60] days: 66.7 % 3 2 2 1
(240..) days: 60.0 % 10 6 6 4

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

Generated by: LCOV version v1.16-55-g56c0a2a