(root)/
glib-2.79.0/
gio/
gwin32sid.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   *
       3   * Copyright (C) 2018 Руслан Ижбулатов
       4   * Copyright (C) 2022 Red Hat, Inc.
       5   *
       6   * SPDX-License-Identifier: LGPL-2.1-or-later
       7   *
       8   * This library is free software; you can redistribute it and/or
       9   * modify it under the terms of the GNU Lesser General Public
      10   * License as published by the Free Software Foundation; either
      11   * version 2.1 of the License, or (at your option) any later version.
      12   *
      13   * This library is distributed in the hope that it will be useful,
      14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16   * Lesser General Public License for more details.
      17   *
      18   * You should have received a copy of the GNU Lesser General
      19   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      20   *
      21   * Author: Руслан Ижбулатов <lrn1986@gmail.com>
      22   */
      23  
      24  #include "config.h"
      25  
      26  #include "gwin32sid.h"
      27  #include "gioerror.h"
      28  
      29  #include <sddl.h>
      30  
      31  /**
      32   * _g_win32_sid_replace: (skip)
      33   * @dest: A pointer to a SID storage
      34   * @src: Existing SID
      35   * @error: return location for a #GError, or %NULL
      36   *
      37   * Creates a copy of the @src SID and puts that into @dest, after freeing
      38   * existing SID in @dest (if any).
      39   *
      40   * The @src SID must be valid (use IsValidSid() to ensure that).
      41   *
      42   * Returns: TRUE on success, FALSE otherwise
      43   */
      44  static gboolean
      45  _g_win32_sid_replace (SID **dest,
      46                        SID  *src,
      47                        GError **error)
      48  {
      49    DWORD sid_len;
      50    SID *new_sid;
      51  
      52    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
      53    g_return_val_if_fail (src != NULL, FALSE);
      54    g_return_val_if_fail (dest && *dest == NULL, FALSE);
      55  
      56    sid_len = GetLengthSid (src);
      57    new_sid = g_malloc (sid_len);
      58  
      59    if (!CopySid (sid_len, new_sid, src))
      60      {
      61        g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
      62                             "Failed to copy SID");
      63  
      64        g_free (new_sid);
      65        return FALSE;
      66      }
      67    else
      68      {
      69        g_free (*dest);
      70        *dest = g_steal_pointer (&new_sid);
      71  
      72        return TRUE;
      73      }
      74  }
      75  
      76  /**
      77   * _g_win32_token_get_sid: (skip)
      78   * @token: A handle of an access token
      79   * @error: return location for a #GError, or %NULL
      80   *
      81   * Gets user SID of the @token and returns a copy of that SID.
      82   *
      83   * Returns: A newly-allocated SID, or NULL in case of an error.
      84   *          Free the returned SID with g_free().
      85   */
      86  static SID *
      87  _g_win32_token_get_sid (HANDLE token,
      88                          GError **error)
      89  {
      90    TOKEN_USER *token_user = NULL;
      91    DWORD n;
      92    PSID psid;
      93    SID *result = NULL;
      94  
      95    g_return_val_if_fail (error == NULL || *error == NULL, NULL);
      96  
      97    if (!GetTokenInformation (token, TokenUser, NULL, 0, &n)
      98        && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
      99      {
     100        g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
     101                             "Failed to GetTokenInformation");
     102  
     103        return NULL;
     104      }
     105  
     106    token_user = g_alloca (n);
     107  
     108    if (!GetTokenInformation (token, TokenUser, token_user, n, &n))
     109      {
     110        g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
     111                             "Failed to GetTokenInformation");
     112  
     113        return NULL;
     114      }
     115  
     116    psid = token_user->User.Sid;
     117  
     118    if (!IsValidSid (psid))
     119      {
     120        g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
     121                             "Invalid SID token");
     122  
     123        return NULL;
     124      }
     125  
     126    _g_win32_sid_replace (&result, psid, error);
     127  
     128    return result;
     129  }
     130  
     131  /**
     132   * _g_win32_process_get_access_token_sid: (skip)
     133   * @process_id: Identifier of a process to get an access token of
     134   *              (use 0 to get a token of the current process)
     135   * @error: return location for a #GError, or %NULL
     136   *
     137   * Opens the process identified by @process_id and opens its token,
     138   * then retrieves SID of the token user and returns a copy of that SID.
     139   *
     140   * Returns: A newly-allocated SID, or NULL in case of an error.
     141   *          Free the returned SID with g_free().
     142   */
     143  SID *
     144  _g_win32_process_get_access_token_sid (DWORD process_id,
     145                                         GError **error)
     146  {
     147    HANDLE process_handle;
     148    HANDLE process_token;
     149    SID *result = NULL;
     150  
     151    g_return_val_if_fail (error == NULL || *error == NULL, NULL);
     152  
     153    if (process_id == 0)
     154      process_handle = GetCurrentProcess ();
     155    else
     156      process_handle = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);
     157  
     158    if (process_handle == NULL)
     159      {
     160        g_set_error (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
     161                     "%s failed", process_id == 0 ? "GetCurrentProcess" : "OpenProcess");
     162  
     163        return NULL;
     164      }
     165  
     166    if (!OpenProcessToken (process_handle, TOKEN_QUERY, &process_token))
     167      {
     168        g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
     169                             "OpenProcessToken failed");
     170  
     171        CloseHandle (process_handle);
     172        return NULL;
     173      }
     174  
     175    result = _g_win32_token_get_sid (process_token, error);
     176  
     177    CloseHandle (process_token);
     178    CloseHandle (process_handle);
     179  
     180    return result;
     181  }
     182  
     183  /**
     184   * _g_win32_sid_to_string: (skip)
     185   * @sid: a SID.
     186   * @error: return location for a #GError, or %NULL
     187   *
     188   * Convert a SID to its string form.
     189   *
     190   * Returns: A newly-allocated string, or NULL in case of an error.
     191   */
     192  gchar *
     193  _g_win32_sid_to_string (SID *sid, GError **error)
     194  {
     195    wchar_t *tmp = NULL;
     196    char *ret;
     197  
     198    g_return_val_if_fail (sid != NULL, NULL);
     199    g_return_val_if_fail (error == NULL || *error == NULL, NULL);
     200  
     201    if (!ConvertSidToStringSid (sid, &tmp))
     202      {
     203        g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
     204                             "Failed to ConvertSidToString");
     205        return NULL;
     206      }
     207  
     208    ret = g_utf16_to_utf8 (tmp, -1, NULL, NULL, NULL);
     209    LocalFree (tmp);
     210    return ret;
     211  }
     212  
     213  /**
     214   * _g_win32_current_process_sid_string: (skip)
     215   * @error: return location for a #GError, or %NULL
     216   *
     217   * Get the current process SID, as a string.
     218   *
     219   * Returns: A newly-allocated string, or NULL in case of an error.
     220   */
     221  gchar *
     222  _g_win32_current_process_sid_string (GError **error)
     223  {
     224    SID *sid;
     225    gchar *ret;
     226  
     227    g_return_val_if_fail (error == NULL || *error == NULL, NULL);
     228  
     229    sid = _g_win32_process_get_access_token_sid (0, error);
     230    if (!sid)
     231      return NULL;
     232  
     233    ret = _g_win32_sid_to_string (sid, error);
     234    g_free (sid);
     235    return ret;
     236  }