LCOV - code coverage report
Current view: top level - src/common - exec.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 87 141 61.7 %
Date: 2020-05-29 00:07:09 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * exec.c
       4             :  *      Functions for finding and validating executable files
       5             :  *
       6             :  *
       7             :  * Portions Copyright (c) 1996-2020, 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             : #ifndef FRONTEND
      18             : #include "postgres.h"
      19             : #else
      20             : #include "postgres_fe.h"
      21             : #endif
      22             : 
      23             : #include <signal.h>
      24             : #include <sys/stat.h>
      25             : #include <sys/wait.h>
      26             : #include <unistd.h>
      27             : 
      28             : /*
      29             :  * Hacky solution to allow expressing both frontend and backend error reports
      30             :  * in one macro call.  First argument of log_error is an errcode() call of
      31             :  * some sort (ignored if FRONTEND); the rest are errmsg_internal() arguments,
      32             :  * i.e. message string and any parameters for it.
      33             :  *
      34             :  * Caller must provide the gettext wrapper around the message string, if
      35             :  * appropriate, so that it gets translated in the FRONTEND case; this
      36             :  * motivates using errmsg_internal() not errmsg().  We handle appending a
      37             :  * newline, if needed, inside the macro, so that there's only one translatable
      38             :  * string per call not two.
      39             :  */
      40             : #ifndef FRONTEND
      41             : #define log_error(errcodefn, ...) \
      42             :     ereport(LOG, (errcodefn, errmsg_internal(__VA_ARGS__)))
      43             : #else
      44             : #define log_error(errcodefn, ...) \
      45             :     (fprintf(stderr, __VA_ARGS__), fputc('\n', stderr))
      46             : #endif
      47             : 
      48             : #ifdef _MSC_VER
      49             : #define getcwd(cwd,len)  GetCurrentDirectory(len, cwd)
      50             : #endif
      51             : 
      52             : static int  validate_exec(const char *path);
      53             : static int  resolve_symlinks(char *path);
      54             : 
      55             : #ifdef WIN32
      56             : static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser);
      57             : #endif
      58             : 
      59             : /*
      60             :  * validate_exec -- validate "path" as an executable file
      61             :  *
      62             :  * returns 0 if the file is found and no error is encountered.
      63             :  *        -1 if the regular file "path" does not exist or cannot be executed.
      64             :  *        -2 if the file is otherwise valid but cannot be read.
      65             :  */
      66             : static int
      67       16274 : validate_exec(const char *path)
      68             : {
      69             :     struct stat buf;
      70             :     int         is_r;
      71             :     int         is_x;
      72             : 
      73             : #ifdef WIN32
      74             :     char        path_exe[MAXPGPATH + sizeof(".exe") - 1];
      75             : 
      76             :     /* Win32 requires a .exe suffix for stat() */
      77             :     if (strlen(path) >= strlen(".exe") &&
      78             :         pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
      79             :     {
      80             :         strlcpy(path_exe, path, sizeof(path_exe) - 4);
      81             :         strcat(path_exe, ".exe");
      82             :         path = path_exe;
      83             :     }
      84             : #endif
      85             : 
      86             :     /*
      87             :      * Ensure that the file exists and is a regular file.
      88             :      *
      89             :      * XXX if you have a broken system where stat() looks at the symlink
      90             :      * instead of the underlying file, you lose.
      91             :      */
      92       16274 :     if (stat(path, &buf) < 0)
      93           0 :         return -1;
      94             : 
      95       16274 :     if (!S_ISREG(buf.st_mode))
      96           0 :         return -1;
      97             : 
      98             :     /*
      99             :      * Ensure that the file is both executable and readable (required for
     100             :      * dynamic loading).
     101             :      */
     102             : #ifndef WIN32
     103       16274 :     is_r = (access(path, R_OK) == 0);
     104       16274 :     is_x = (access(path, X_OK) == 0);
     105             : #else
     106             :     is_r = buf.st_mode & S_IRUSR;
     107             :     is_x = buf.st_mode & S_IXUSR;
     108             : #endif
     109       16274 :     return is_x ? (is_r ? 0 : -2) : -1;
     110             : }
     111             : 
     112             : 
     113             : /*
     114             :  * find_my_exec -- find an absolute path to a valid executable
     115             :  *
     116             :  *  argv0 is the name passed on the command line
     117             :  *  retpath is the output area (must be of size MAXPGPATH)
     118             :  *  Returns 0 if OK, -1 if error.
     119             :  *
     120             :  * The reason we have to work so hard to find an absolute path is that
     121             :  * on some platforms we can't do dynamic loading unless we know the
     122             :  * executable's location.  Also, we need a full path not a relative
     123             :  * path because we will later change working directory.  Finally, we want
     124             :  * a true path not a symlink location, so that we can locate other files
     125             :  * that are part of our installation relative to the executable.
     126             :  */
     127             : int
     128       15182 : find_my_exec(const char *argv0, char *retpath)
     129             : {
     130             :     char        cwd[MAXPGPATH],
     131             :                 test_path[MAXPGPATH];
     132             :     char       *path;
     133             : 
     134       15182 :     if (!getcwd(cwd, MAXPGPATH))
     135             :     {
     136           0 :         log_error(errcode_for_file_access(),
     137             :                   _("could not identify current directory: %m"));
     138           0 :         return -1;
     139             :     }
     140             : 
     141             :     /*
     142             :      * If argv0 contains a separator, then PATH wasn't used.
     143             :      */
     144       15182 :     if (first_dir_separator(argv0) != NULL)
     145             :     {
     146       10612 :         if (is_absolute_path(argv0))
     147       10218 :             StrNCpy(retpath, argv0, MAXPGPATH);
     148             :         else
     149         394 :             join_path_components(retpath, cwd, argv0);
     150       10612 :         canonicalize_path(retpath);
     151             : 
     152       10612 :         if (validate_exec(retpath) == 0)
     153       10612 :             return resolve_symlinks(retpath);
     154             : 
     155           0 :         log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
     156             :                   _("invalid binary \"%s\""), retpath);
     157           0 :         return -1;
     158             :     }
     159             : 
     160             : #ifdef WIN32
     161             :     /* Win32 checks the current directory first for names without slashes */
     162             :     join_path_components(retpath, cwd, argv0);
     163             :     if (validate_exec(retpath) == 0)
     164             :         return resolve_symlinks(retpath);
     165             : #endif
     166             : 
     167             :     /*
     168             :      * Since no explicit path was supplied, the user must have been relying on
     169             :      * PATH.  We'll search the same PATH.
     170             :      */
     171        4570 :     if ((path = getenv("PATH")) && *path)
     172             :     {
     173        4570 :         char       *startp = NULL,
     174        4570 :                    *endp = NULL;
     175             : 
     176             :         do
     177             :         {
     178        4570 :             if (!startp)
     179        4570 :                 startp = path;
     180             :             else
     181           0 :                 startp = endp + 1;
     182             : 
     183        4570 :             endp = first_path_var_separator(startp);
     184        4570 :             if (!endp)
     185           0 :                 endp = startp + strlen(startp); /* point to end */
     186             : 
     187        4570 :             StrNCpy(test_path, startp, Min(endp - startp + 1, MAXPGPATH));
     188             : 
     189        4570 :             if (is_absolute_path(test_path))
     190        4570 :                 join_path_components(retpath, test_path, argv0);
     191             :             else
     192             :             {
     193           0 :                 join_path_components(retpath, cwd, test_path);
     194           0 :                 join_path_components(retpath, retpath, argv0);
     195             :             }
     196        4570 :             canonicalize_path(retpath);
     197             : 
     198        4570 :             switch (validate_exec(retpath))
     199             :             {
     200        4570 :                 case 0:         /* found ok */
     201        4570 :                     return resolve_symlinks(retpath);
     202           0 :                 case -1:        /* wasn't even a candidate, keep looking */
     203           0 :                     break;
     204           0 :                 case -2:        /* found but disqualified */
     205           0 :                     log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
     206             :                               _("could not read binary \"%s\""),
     207             :                               retpath);
     208           0 :                     break;
     209             :             }
     210           0 :         } while (*endp);
     211             :     }
     212             : 
     213           0 :     log_error(errcode(ERRCODE_UNDEFINED_FILE),
     214             :               _("could not find a \"%s\" to execute"), argv0);
     215           0 :     return -1;
     216             : }
     217             : 
     218             : 
     219             : /*
     220             :  * resolve_symlinks - resolve symlinks to the underlying file
     221             :  *
     222             :  * Replace "path" by the absolute path to the referenced file.
     223             :  *
     224             :  * Returns 0 if OK, -1 if error.
     225             :  *
     226             :  * Note: we are not particularly tense about producing nice error messages
     227             :  * because we are not really expecting error here; we just determined that
     228             :  * the symlink does point to a valid executable.
     229             :  */
     230             : static int
     231       15182 : resolve_symlinks(char *path)
     232             : {
     233             : #ifdef HAVE_READLINK
     234             :     struct stat buf;
     235             :     char        orig_wd[MAXPGPATH],
     236             :                 link_buf[MAXPGPATH];
     237             :     char       *fname;
     238             : 
     239             :     /*
     240             :      * To resolve a symlink properly, we have to chdir into its directory and
     241             :      * then chdir to where the symlink points; otherwise we may fail to
     242             :      * resolve relative links correctly (consider cases involving mount
     243             :      * points, for example).  After following the final symlink, we use
     244             :      * getcwd() to figure out where the heck we're at.
     245             :      *
     246             :      * One might think we could skip all this if path doesn't point to a
     247             :      * symlink to start with, but that's wrong.  We also want to get rid of
     248             :      * any directory symlinks that are present in the given path. We expect
     249             :      * getcwd() to give us an accurate, symlink-free path.
     250             :      */
     251       15182 :     if (!getcwd(orig_wd, MAXPGPATH))
     252             :     {
     253           0 :         log_error(errcode_for_file_access(),
     254             :                   _("could not identify current directory: %m"));
     255           0 :         return -1;
     256             :     }
     257             : 
     258             :     for (;;)
     259           0 :     {
     260             :         char       *lsep;
     261             :         int         rllen;
     262             : 
     263       15182 :         lsep = last_dir_separator(path);
     264       15182 :         if (lsep)
     265             :         {
     266       15182 :             *lsep = '\0';
     267       15182 :             if (chdir(path) == -1)
     268             :             {
     269           0 :                 log_error(errcode_for_file_access(),
     270             :                           _("could not change directory to \"%s\": %m"), path);
     271           0 :                 return -1;
     272             :             }
     273       15182 :             fname = lsep + 1;
     274             :         }
     275             :         else
     276           0 :             fname = path;
     277             : 
     278       15182 :         if (lstat(fname, &buf) < 0 ||
     279       15182 :             !S_ISLNK(buf.st_mode))
     280             :             break;
     281             : 
     282           0 :         errno = 0;
     283           0 :         rllen = readlink(fname, link_buf, sizeof(link_buf));
     284           0 :         if (rllen < 0 || rllen >= sizeof(link_buf))
     285             :         {
     286           0 :             log_error(errcode_for_file_access(),
     287             :                       _("could not read symbolic link \"%s\": %m"), fname);
     288           0 :             return -1;
     289             :         }
     290           0 :         link_buf[rllen] = '\0';
     291           0 :         strcpy(path, link_buf);
     292             :     }
     293             : 
     294             :     /* must copy final component out of 'path' temporarily */
     295       15182 :     strlcpy(link_buf, fname, sizeof(link_buf));
     296             : 
     297       15182 :     if (!getcwd(path, MAXPGPATH))
     298             :     {
     299           0 :         log_error(errcode_for_file_access(),
     300             :                   _("could not identify current directory: %m"));
     301           0 :         return -1;
     302             :     }
     303       15182 :     join_path_components(path, path, link_buf);
     304       15182 :     canonicalize_path(path);
     305             : 
     306       15182 :     if (chdir(orig_wd) == -1)
     307             :     {
     308           0 :         log_error(errcode_for_file_access(),
     309             :                   _("could not change directory to \"%s\": %m"), orig_wd);
     310           0 :         return -1;
     311             :     }
     312             : #endif                          /* HAVE_READLINK */
     313             : 
     314       15182 :     return 0;
     315             : }
     316             : 
     317             : 
     318             : /*
     319             :  * Find another program in our binary's directory,
     320             :  * then make sure it is the proper version.
     321             :  */
     322             : int
     323        1092 : find_other_exec(const char *argv0, const char *target,
     324             :                 const char *versionstr, char *retpath)
     325             : {
     326             :     char        cmd[MAXPGPATH];
     327             :     char        line[MAXPGPATH];
     328             : 
     329        1092 :     if (find_my_exec(argv0, retpath) < 0)
     330           0 :         return -1;
     331             : 
     332             :     /* Trim off program name and keep just directory */
     333        1092 :     *last_dir_separator(retpath) = '\0';
     334        1092 :     canonicalize_path(retpath);
     335             : 
     336             :     /* Now append the other program's name */
     337        1092 :     snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
     338             :              "/%s%s", target, EXE);
     339             : 
     340        1092 :     if (validate_exec(retpath) != 0)
     341           0 :         return -1;
     342             : 
     343        1092 :     snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath);
     344             : 
     345        1092 :     if (!pipe_read_line(cmd, line, sizeof(line)))
     346           0 :         return -1;
     347             : 
     348        1092 :     if (strcmp(line, versionstr) != 0)
     349           0 :         return -2;
     350             : 
     351        1092 :     return 0;
     352             : }
     353             : 
     354             : 
     355             : /*
     356             :  * Execute a command in a pipe and read the first line from it.
     357             :  */
     358             : char *
     359        1094 : pipe_read_line(char *cmd, char *line, int maxsize)
     360             : {
     361             :     FILE       *pgver;
     362             : 
     363             :     /* flush output buffers in case popen does not... */
     364        1094 :     fflush(stdout);
     365        1094 :     fflush(stderr);
     366             : 
     367        1094 :     errno = 0;
     368        1094 :     if ((pgver = popen(cmd, "r")) == NULL)
     369             :     {
     370           0 :         perror("popen failure");
     371           0 :         return NULL;
     372             :     }
     373             : 
     374        1094 :     errno = 0;
     375        1094 :     if (fgets(line, maxsize, pgver) == NULL)
     376             :     {
     377           0 :         if (feof(pgver))
     378           0 :             fprintf(stderr, "no data was returned by command \"%s\"\n", cmd);
     379             :         else
     380           0 :             perror("fgets failure");
     381           0 :         pclose(pgver);          /* no error checking */
     382           0 :         return NULL;
     383             :     }
     384             : 
     385        1094 :     if (pclose_check(pgver))
     386           0 :         return NULL;
     387             : 
     388        1094 :     return line;
     389             : }
     390             : 
     391             : 
     392             : /*
     393             :  * pclose() plus useful error reporting
     394             :  */
     395             : int
     396        1810 : pclose_check(FILE *stream)
     397             : {
     398             :     int         exitstatus;
     399             :     char       *reason;
     400             : 
     401        1810 :     exitstatus = pclose(stream);
     402             : 
     403        1810 :     if (exitstatus == 0)
     404        1810 :         return 0;               /* all is well */
     405             : 
     406           0 :     if (exitstatus == -1)
     407             :     {
     408             :         /* pclose() itself failed, and hopefully set errno */
     409           0 :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
     410             :                   _("pclose failed: %m"));
     411             :     }
     412             :     else
     413             :     {
     414           0 :         reason = wait_result_to_str(exitstatus);
     415           0 :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
     416             :                   "%s", reason);
     417           0 :         pfree(reason);
     418             :     }
     419           0 :     return exitstatus;
     420             : }
     421             : 
     422             : /*
     423             :  *  set_pglocale_pgservice
     424             :  *
     425             :  *  Set application-specific locale and service directory
     426             :  *
     427             :  *  This function takes the value of argv[0] rather than a full path.
     428             :  *
     429             :  * (You may be wondering why this is in exec.c.  It requires this module's
     430             :  * services and doesn't introduce any new dependencies, so this seems as
     431             :  * good as anyplace.)
     432             :  */
     433             : void
     434       11766 : set_pglocale_pgservice(const char *argv0, const char *app)
     435             : {
     436             :     char        path[MAXPGPATH];
     437             :     char        my_exec_path[MAXPGPATH];
     438             :     char        env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")];    /* longer than
     439             :                                                                  * PGLOCALEDIR */
     440             :     char       *dup_path;
     441             : 
     442             :     /* don't set LC_ALL in the backend */
     443       11766 :     if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
     444             :     {
     445        8688 :         setlocale(LC_ALL, "");
     446             : 
     447             :         /*
     448             :          * One could make a case for reproducing here PostmasterMain()'s test
     449             :          * for whether the process is multithreaded.  Unlike the postmaster,
     450             :          * no frontend program calls sigprocmask() or otherwise provides for
     451             :          * mutual exclusion between signal handlers.  While frontends using
     452             :          * fork(), if multithreaded, are formally exposed to undefined
     453             :          * behavior, we have not witnessed a concrete bug.  Therefore,
     454             :          * complaining about multithreading here may be mere pedantry.
     455             :          */
     456             :     }
     457             : 
     458       11766 :     if (find_my_exec(argv0, my_exec_path) < 0)
     459           0 :         return;
     460             : 
     461             : #ifdef ENABLE_NLS
     462       11766 :     get_locale_path(my_exec_path, path);
     463       11766 :     bindtextdomain(app, path);
     464       11766 :     textdomain(app);
     465             : 
     466       11766 :     if (getenv("PGLOCALEDIR") == NULL)
     467             :     {
     468             :         /* set for libpq to use */
     469        6044 :         snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path);
     470        6044 :         canonicalize_path(env_path + 12);
     471        6044 :         dup_path = strdup(env_path);
     472        6044 :         if (dup_path)
     473        6044 :             putenv(dup_path);
     474             :     }
     475             : #endif
     476             : 
     477       11766 :     if (getenv("PGSYSCONFDIR") == NULL)
     478             :     {
     479        6044 :         get_etc_path(my_exec_path, path);
     480             : 
     481             :         /* set for libpq to use */
     482        6044 :         snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path);
     483        6044 :         canonicalize_path(env_path + 13);
     484        6044 :         dup_path = strdup(env_path);
     485        6044 :         if (dup_path)
     486        6044 :             putenv(dup_path);
     487             :     }
     488             : }
     489             : 
     490             : #ifdef WIN32
     491             : 
     492             : /*
     493             :  * AddUserToTokenDacl(HANDLE hToken)
     494             :  *
     495             :  * This function adds the current user account to the restricted
     496             :  * token used when we create a restricted process.
     497             :  *
     498             :  * This is required because of some security changes in Windows
     499             :  * that appeared in patches to XP/2K3 and in Vista/2008.
     500             :  *
     501             :  * On these machines, the Administrator account is not included in
     502             :  * the default DACL - you just get Administrators + System. For
     503             :  * regular users you get User + System. Because we strip Administrators
     504             :  * when we create the restricted token, we are left with only System
     505             :  * in the DACL which leads to access denied errors for later CreatePipe()
     506             :  * and CreateProcess() calls when running as Administrator.
     507             :  *
     508             :  * This function fixes this problem by modifying the DACL of the
     509             :  * token the process will use, and explicitly re-adding the current
     510             :  * user account.  This is still secure because the Administrator account
     511             :  * inherits its privileges from the Administrators group - it doesn't
     512             :  * have any of its own.
     513             :  */
     514             : BOOL
     515             : AddUserToTokenDacl(HANDLE hToken)
     516             : {
     517             :     int         i;
     518             :     ACL_SIZE_INFORMATION asi;
     519             :     ACCESS_ALLOWED_ACE *pace;
     520             :     DWORD       dwNewAclSize;
     521             :     DWORD       dwSize = 0;
     522             :     DWORD       dwTokenInfoLength = 0;
     523             :     PACL        pacl = NULL;
     524             :     PTOKEN_USER pTokenUser = NULL;
     525             :     TOKEN_DEFAULT_DACL tddNew;
     526             :     TOKEN_DEFAULT_DACL *ptdd = NULL;
     527             :     TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl;
     528             :     BOOL        ret = FALSE;
     529             : 
     530             :     /* Figure out the buffer size for the DACL info */
     531             :     if (!GetTokenInformation(hToken, tic, (LPVOID) NULL, dwTokenInfoLength, &dwSize))
     532             :     {
     533             :         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
     534             :         {
     535             :             ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize);
     536             :             if (ptdd == NULL)
     537             :             {
     538             :                 log_error(errcode(ERRCODE_OUT_OF_MEMORY),
     539             :                           _("out of memory"));
     540             :                 goto cleanup;
     541             :             }
     542             : 
     543             :             if (!GetTokenInformation(hToken, tic, (LPVOID) ptdd, dwSize, &dwSize))
     544             :             {
     545             :                 log_error(errcode(ERRCODE_SYSTEM_ERROR),
     546             :                           "could not get token information: error code %lu",
     547             :                           GetLastError());
     548             :                 goto cleanup;
     549             :             }
     550             :         }
     551             :         else
     552             :         {
     553             :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
     554             :                       "could not get token information buffer size: error code %lu",
     555             :                       GetLastError());
     556             :             goto cleanup;
     557             :         }
     558             :     }
     559             : 
     560             :     /* Get the ACL info */
     561             :     if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID) &asi,
     562             :                            (DWORD) sizeof(ACL_SIZE_INFORMATION),
     563             :                            AclSizeInformation))
     564             :     {
     565             :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
     566             :                   "could not get ACL information: error code %lu",
     567             :                   GetLastError());
     568             :         goto cleanup;
     569             :     }
     570             : 
     571             :     /* Get the current user SID */
     572             :     if (!GetTokenUser(hToken, &pTokenUser))
     573             :         goto cleanup;           /* callee printed a message */
     574             : 
     575             :     /* Figure out the size of the new ACL */
     576             :     dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) +
     577             :         GetLengthSid(pTokenUser->User.Sid) - sizeof(DWORD);
     578             : 
     579             :     /* Allocate the ACL buffer & initialize it */
     580             :     pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize);
     581             :     if (pacl == NULL)
     582             :     {
     583             :         log_error(errcode(ERRCODE_OUT_OF_MEMORY),
     584             :                   _("out of memory"));
     585             :         goto cleanup;
     586             :     }
     587             : 
     588             :     if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION))
     589             :     {
     590             :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
     591             :                   "could not initialize ACL: error code %lu", GetLastError());
     592             :         goto cleanup;
     593             :     }
     594             : 
     595             :     /* Loop through the existing ACEs, and build the new ACL */
     596             :     for (i = 0; i < (int) asi.AceCount; i++)
     597             :     {
     598             :         if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *) &pace))
     599             :         {
     600             :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
     601             :                       "could not get ACE: error code %lu", GetLastError());
     602             :             goto cleanup;
     603             :         }
     604             : 
     605             :         if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER) pace)->AceSize))
     606             :         {
     607             :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
     608             :                       "could not add ACE: error code %lu", GetLastError());
     609             :             goto cleanup;
     610             :         }
     611             :     }
     612             : 
     613             :     /* Add the new ACE for the current user */
     614             :     if (!AddAccessAllowedAceEx(pacl, ACL_REVISION, OBJECT_INHERIT_ACE, GENERIC_ALL, pTokenUser->User.Sid))
     615             :     {
     616             :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
     617             :                   "could not add access allowed ACE: error code %lu",
     618             :                   GetLastError());
     619             :         goto cleanup;
     620             :     }
     621             : 
     622             :     /* Set the new DACL in the token */
     623             :     tddNew.DefaultDacl = pacl;
     624             : 
     625             :     if (!SetTokenInformation(hToken, tic, (LPVOID) &tddNew, dwNewAclSize))
     626             :     {
     627             :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
     628             :                   "could not set token information: error code %lu",
     629             :                   GetLastError());
     630             :         goto cleanup;
     631             :     }
     632             : 
     633             :     ret = TRUE;
     634             : 
     635             : cleanup:
     636             :     if (pTokenUser)
     637             :         LocalFree((HLOCAL) pTokenUser);
     638             : 
     639             :     if (pacl)
     640             :         LocalFree((HLOCAL) pacl);
     641             : 
     642             :     if (ptdd)
     643             :         LocalFree((HLOCAL) ptdd);
     644             : 
     645             :     return ret;
     646             : }
     647             : 
     648             : /*
     649             :  * GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser)
     650             :  *
     651             :  * Get the users token information from a process token.
     652             :  *
     653             :  * The caller of this function is responsible for calling LocalFree() on the
     654             :  * returned TOKEN_USER memory.
     655             :  */
     656             : static BOOL
     657             : GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser)
     658             : {
     659             :     DWORD       dwLength;
     660             : 
     661             :     *ppTokenUser = NULL;
     662             : 
     663             :     if (!GetTokenInformation(hToken,
     664             :                              TokenUser,
     665             :                              NULL,
     666             :                              0,
     667             :                              &dwLength))
     668             :     {
     669             :         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
     670             :         {
     671             :             *ppTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwLength);
     672             : 
     673             :             if (*ppTokenUser == NULL)
     674             :             {
     675             :                 log_error(errcode(ERRCODE_OUT_OF_MEMORY),
     676             :                           _("out of memory"));
     677             :                 return FALSE;
     678             :             }
     679             :         }
     680             :         else
     681             :         {
     682             :             log_error(errcode(ERRCODE_SYSTEM_ERROR),
     683             :                       "could not get token information buffer size: error code %lu",
     684             :                       GetLastError());
     685             :             return FALSE;
     686             :         }
     687             :     }
     688             : 
     689             :     if (!GetTokenInformation(hToken,
     690             :                              TokenUser,
     691             :                              *ppTokenUser,
     692             :                              dwLength,
     693             :                              &dwLength))
     694             :     {
     695             :         LocalFree(*ppTokenUser);
     696             :         *ppTokenUser = NULL;
     697             : 
     698             :         log_error(errcode(ERRCODE_SYSTEM_ERROR),
     699             :                   "could not get token information: error code %lu",
     700             :                   GetLastError());
     701             :         return FALSE;
     702             :     }
     703             : 
     704             :     /* Memory in *ppTokenUser is LocalFree():d by the caller */
     705             :     return TRUE;
     706             : }
     707             : 
     708             : #endif

Generated by: LCOV version 1.13