- /*
- * 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.