- /*
 - * MIT License
 - *
 - * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
 - *
 - * Permission is hereby granted, free of charge, to any person obtaining a copy
 - * of this software and associated documentation files (the "Software"), to deal
 - * in the Software without restriction, including without limitation the rights
 - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 - * copies of the Software, and to permit persons to whom the Software is
 - * furnished to do so, subject to the following conditions:
 - *
 - * The above copyright notice and this permission notice shall be included in all
 - * copies or substantial portions of the Software.
 - *
 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 - * SOFTWARE.
 - */
 - /*
 - * winsg.c - run Win32 or Cygwin program with a different (primary) group
 - *
 - * Written by Roland Mainz <roland.mainz@nrubsig.org>
 - */
 - #include <windows.h>
 - #include <stdio.h>
 - #include <stdbool.h>
 - #include <Lmcons.h>
 - #include <process.h>
 - #if 0
 - #define D(x) x
 - #else
 - #define D(x)
 - #endif
 - /*
 - * Performance hack:
 - * GETTOKINFO_EXTRA_BUFFER - extra space for more data
 - * |GetTokenInformation()| for |TOKEN_USER| and |TOKEN_PRIMARY_GROUP|
 - * always fails in Win10 with |ERROR_INSUFFICIENT_BUFFER| if you
 - * just pass the |sizeof(TOKEN_*)| value. Instead of calling
 - * |GetTokenInformation()| with |NULL| arg to obtain the size to
 - * allocate we just provide 2048 bytes of extra space after the
 - * |TOKEN_*| size, and pray it is enough
 - */
 - #define GETTOKINFO_EXTRA_BUFFER (2048)
 - bool get_token_primarygroup_name(HANDLE tok, char *out_buffer)
 - {
 - DWORD tokdatalen;
 - PTOKEN_PRIMARY_GROUP ptpgroup;
 - PSID pgsid;
 - DWORD namesize = GNLEN+1;
 - char domainbuffer[UNLEN+1];
 - DWORD domainbuffer_size = sizeof(domainbuffer);
 - SID_NAME_USE name_use;
 - tokdatalen = sizeof(TOKEN_PRIMARY_GROUP)+GETTOKINFO_EXTRA_BUFFER;
 - ptpgroup = _alloca(tokdatalen);
 - if (!GetTokenInformation(tok, TokenPrimaryGroup, ptpgroup,
 - tokdatalen, &tokdatalen)) {
 - "GetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
 - "status=%d\n",
 - (void *)tok, (int)GetLastError()));
 - return false;
 - }
 - pgsid = ptpgroup->PrimaryGroup;
 - if (!LookupAccountSidA(NULL, pgsid, out_buffer, &namesize,
 - domainbuffer, &domainbuffer_size, &name_use)) {
 - "LookupAccountSidA() failed, status=%d\n",
 - (int)GetLastError()));
 - return false;
 - }
 - return true;
 - }
 - bool is_group_in_token(HANDLE tok, PSID qsid)
 - {
 - DWORD tokdatalen;
 - PTOKEN_GROUPS ptgroups;
 - tokdatalen = sizeof(TOKEN_GROUPS)+GETTOKINFO_EXTRA_BUFFER;
 - ptgroups = _alloca(tokdatalen);
 - if (!GetTokenInformation(tok, TokenGroups, ptgroups,
 - tokdatalen, &tokdatalen)) {
 - "GetTokenInformation(tok=0x%p, TokenGroups) failed, "
 - "status=%d\n",
 - (void *)tok, (int)GetLastError()));
 - return false;
 - }
 - int i;
 - for (i = 0 ; i < ptgroups->GroupCount ; i++) {
 - if (EqualSid(qsid, ptgroups->Groups[i].Sid) &&
 - (ptgroups->Groups[i].Attributes & SE_GROUP_ENABLED)) {
 - return true;
 - }
 - }
 - return false;
 - }
 - bool set_token_primarygroup_name(HANDLE tok, const char *new_groupname)
 - {
 - DWORD tokdatalen;
 - TOKEN_PRIMARY_GROUP tpgroup;
 - char sidbuff[SECURITY_MAX_SID_SIZE+1];
 - PSID pgsid = (PSID)sidbuff;
 - DWORD pgsid_size = sizeof(sidbuff);
 - char domainbuffer[UNLEN+1];
 - DWORD domainbuffer_size = sizeof(domainbuffer);
 - SID_NAME_USE name_use;
 - if (!LookupAccountNameA(NULL, new_groupname,
 - pgsid, &pgsid_size, domainbuffer, &domainbuffer_size, &name_use)) {
 - "LookupAccountNameA() failed.\n"));
 - return false;
 - }
 - if (!is_group_in_token(tok, pgsid)) {
 - "group '%s' is not a member.\n", new_groupname));
 - return false;
 - }
 - tokdatalen = sizeof(TOKEN_PRIMARY_GROUP);
 - tpgroup.PrimaryGroup = pgsid;
 - if (!SetTokenInformation(tok, TokenPrimaryGroup,
 - &tpgroup, tokdatalen)) {
 - "SetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
 - "status=%d\n",
 - (void *)tok, (int)GetLastError()));
 - return false;
 - }
 - return true;
 - }
 - enum shelltype {
 - SHELLTYPE_NOT_SET = 0,
 - SHELLTYPE_NONE,
 - SHELLTYPE_CMD,
 - SHELLTYPE_SYSTEM
 - };
 - int main(int ac, char *av[])
 - {
 - enum shelltype st = SHELLTYPE_NOT_SET;
 - int cmd_arg_index = -1;
 - const char *newgrpname = NULL;
 - int subcmdret = EXIT_FAILURE;
 - int i;
 - for (i=1 ; i < ac ; i++) {
 - return 1;
 - }
 - st = SHELLTYPE_SYSTEM;
 - cmd_arg_index = i+1;
 - break;
 - }
 - st = SHELLTYPE_CMD;
 - cmd_arg_index = i+1;
 - break;
 - }
 - newgrpname = av[i+1];
 - i++;
 - }
 - else {
 - if ((i == 1) && (*av[i] != '-')) {
 - newgrpname = av[i];
 - continue;
 - }
 - cmd_arg_index = i+1;
 - st = SHELLTYPE_NONE;
 - break;
 - }
 - }
 - /*
 - * Handle newgrp(1)-like behaviour (run new shell/cmd.exe
 - * with requested group), e.g.
 - * $ winsg -g cygwingrp1
 - * $ winsg cygwingrp1
 - */
 - if ((st == SHELLTYPE_NOT_SET) && (cmd_arg_index == -1)) {
 - st = SHELLTYPE_NONE;
 - cmd_arg_index = 2;
 - }
 - if (!newgrpname) {
 - return 1;
 - }
 - "# shelltype=%d, cmd_arg_index=%d, "
 - "av[cmd_arg_index]='%s', "
 - "new group name '%s'\n",
 - (int)st, cmd_arg_index, av[cmd_arg_index], newgrpname));
 - HANDLE tok;
 - if (!OpenProcessToken(GetCurrentProcess(),
 - TOKEN_QUERY|TOKEN_ADJUST_DEFAULT|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,
 - &tok)) {
 - return 1;
 - }
 - D(
 - char pgroupname[GNLEN+1];
 - get_token_primarygroup_name(tok, pgroupname);
 - )
 - if (!set_token_primarygroup_name(tok, newgrpname)) {
 - "%s: Could not switch to new primary group '%s'.\n",
 - av[0], newgrpname);
 - return 1;
 - }
 - D(
 - get_token_primarygroup_name(tok, pgroupname);
 - )
 - (void)_flushall();
 - switch(st) {
 - #define CYGWIN_BASH_PATH "C:\\cygwin64\\bin\\bash.exe"
 - #define WIN32_CMD_PATH "C:\\Windows\\system32\\cmd.exe"
 - case SHELLTYPE_SYSTEM:
 - if (av[cmd_arg_index] != NULL) {
 - 16+
 - char *cmdbuff = alloca(cmdbuff_size);
 - "%s -c '%s'", CYGWIN_BASH_PATH,
 - av[cmd_arg_index]);
 - }
 - else {
 - }
 - break;
 - case SHELLTYPE_CMD:
 - if (av[cmd_arg_index] != NULL) {
 - subcmdret = _spawnl(_P_WAIT,
 - WIN32_CMD_PATH, WIN32_CMD_PATH,
 - "/C", av[cmd_arg_index], NULL);
 - }
 - else {
 - subcmdret = _spawnl(_P_WAIT,
 - WIN32_CMD_PATH, WIN32_CMD_PATH, NULL);
 - }
 - break;
 - case SHELLTYPE_NONE:
 - if (av[cmd_arg_index] != NULL) {
 - subcmdret = _spawnv(_P_WAIT,
 - av[cmd_arg_index],
 - (const char *const *)&av[cmd_arg_index]);
 - }
 - else {
 - subcmdret = _spawnl(_P_WAIT,
 - WIN32_CMD_PATH, WIN32_CMD_PATH, NULL);
 - }
 - break;
 - default:
 - break;
 - }
 - return 0;
 - }
 
winsg.c - run Win32 or Cygwin program with a different group
Posted by Anonymous on Fri 24th May 2024 14:03
raw | new post
view followups (newest first): winsg.c - run Win32 or Cygwin program with a different group by Anonymous
modification of post by Anonymous (view diff)
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.
 nrubsig.kpaste.net RSS