pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


winsg.c - run Win32 or Cygwin program with a different group
Posted by Anonymous on Fri 24th May 2024 13:38
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)

  1.  
  2. /*
  3.  * MIT License
  4.  *
  5.  * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  8.  * of this software and associated documentation files (the "Software"), to deal
  9.  * in the Software without restriction, including without limitation the rights
  10.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11.  * copies of the Software, and to permit persons to whom the Software is
  12.  * furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included in all
  15.  * copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23.  * SOFTWARE.
  24.  */
  25.  
  26. /*
  27.  * winsg.c - run Win32 or Cygwin program with a different group
  28.  *
  29.  * Written by Roland Mainz <roland.mainz@nrubsig.org>
  30.  */
  31.  
  32. #include <windows.h>
  33. #include <stdio.h>
  34. #include <stdbool.h>
  35. #include <Lmcons.h>
  36. #include <process.h>
  37.  
  38. /*
  39.  * Performance hack:
  40.  * GETTOKINFO_EXTRA_BUFFER - extra space for more data
  41.  * |GetTokenInformation()| for |TOKEN_USER| and |TOKEN_PRIMARY_GROUP|
  42.  * always fails in Win10 with |ERROR_INSUFFICIENT_BUFFER| if you
  43.  * just pass the |sizeof(TOKEN_*)| value. Instead of calling
  44.  * |GetTokenInformation()| with |NULL| arg to obtain the size to
  45.  * allocate we just provide 2048 bytes of extra space after the
  46.  * |TOKEN_*| size, and pray it is enough
  47.  */
  48. #define GETTOKINFO_EXTRA_BUFFER (2048)
  49.  
  50. bool get_token_primarygroup_name(HANDLE tok, char *out_buffer)
  51. {
  52.     DWORD tokdatalen;
  53.     PTOKEN_PRIMARY_GROUP ptpgroup;
  54.     PSID pgsid;
  55.     DWORD namesize = GNLEN+1;
  56.     char domainbuffer[UNLEN+1];
  57.     DWORD domainbuffer_size = sizeof(domainbuffer);
  58.     SID_NAME_USE name_use;
  59.  
  60.     tokdatalen = sizeof(TOKEN_PRIMARY_GROUP)+GETTOKINFO_EXTRA_BUFFER;
  61.     ptpgroup = _alloca(tokdatalen);
  62.     if (!GetTokenInformation(tok, TokenPrimaryGroup, ptpgroup,
  63.         tokdatalen, &tokdatalen)) {
  64.         (void)fprintf(stderr, "get_token_primarygroup_name: "
  65.             "GetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
  66.             "status=%d\n",
  67.             (void *)tok, (int)GetLastError());
  68.         return false;
  69.     }
  70.  
  71.     pgsid = ptpgroup->PrimaryGroup;
  72.  
  73.     if (!LookupAccountSidA(NULL, pgsid, out_buffer, &namesize,
  74.         domainbuffer, &domainbuffer_size, &name_use)) {
  75.         (void)fprintf(stderr, "get_token_primarygroup_name: "
  76.             "LookupAccountSidA() failed, status=%d\n",
  77.             (int)GetLastError());
  78.         return false;
  79.     }
  80.  
  81.     return true;
  82. }
  83.  
  84. bool is_group_in_token(HANDLE tok, PSID qsid)
  85. {
  86.     DWORD tokdatalen;
  87.     PTOKEN_GROUPS ptgroups;
  88.  
  89.     tokdatalen = sizeof(TOKEN_GROUPS)+GETTOKINFO_EXTRA_BUFFER;
  90.     ptgroups = _alloca(tokdatalen);
  91.     if (!GetTokenInformation(tok, TokenGroups, ptgroups,
  92.         tokdatalen, &tokdatalen)) {
  93.         (void)fprintf(stderr, "is_group_in_token: "
  94.             "GetTokenInformation(tok=0x%p, TokenGroups) failed, "
  95.             "status=%d\n",
  96.             (void *)tok, (int)GetLastError());
  97.         return false;
  98.     }
  99.  
  100.     int i;
  101.     (void)fprintf(stderr, "is_group_in_token: got %d groups\n", (int)ptgroups->GroupCount);
  102.     for (i = 0 ; i < ptgroups->GroupCount ; i++) {
  103.         if (EqualSid(qsid, ptgroups->Groups[i].Sid) &&
  104.             (ptgroups->Groups[i].Attributes & SE_GROUP_ENABLED)) {
  105.             (void)puts("#match");
  106.             return true;
  107.         }
  108.     }
  109.  
  110.     (void)puts("#no match");
  111.  
  112.     return false;
  113. }
  114.  
  115. bool set_token_primarygroup_name(HANDLE tok, const char *new_groupname)
  116. {
  117.     DWORD tokdatalen;
  118.     TOKEN_PRIMARY_GROUP tpgroup;
  119.     char sidbuff[SECURITY_MAX_SID_SIZE+1];
  120.     PSID pgsid = (PSID)sidbuff;
  121.     DWORD pgsid_size = sizeof(sidbuff);
  122.     char domainbuffer[UNLEN+1];
  123.     DWORD domainbuffer_size = sizeof(domainbuffer);
  124.     SID_NAME_USE name_use;
  125.  
  126.     if (!LookupAccountNameA(NULL, new_groupname,
  127.         pgsid, &pgsid_size, domainbuffer, &domainbuffer_size, &name_use)) {
  128.         (void)fprintf(stderr, "set_token_primarygroup_name: "
  129.             "LookupAccountNameA() failed.\n");
  130.         return false;
  131.     }
  132.  
  133. #if 1
  134.     if (!is_group_in_token(tok, pgsid)) {
  135.         (void)fprintf(stderr, "set_token_primarygroup_name: "
  136.             "group '%s' is not a member.\n", new_groupname);
  137.         return false;
  138.     }
  139. #else
  140.     BOOL is_member = FALSE;
  141.     if (!CheckTokenMembership(tok, pgsid, &is_member)) {
  142.         (void)fprintf(stderr, "set_token_primarygroup_name: "
  143.             "CheckTokenMembership() failed, status=%d.\n", (int)GetLastError());
  144.         return false;
  145.     }
  146.  
  147.     if (!is_member) {
  148.         (void)fprintf(stderr, "set_token_primarygroup_name: "
  149.             "group '%s' is not a member.\n", new_groupname);
  150.         return false;
  151.     }
  152. #endif
  153.  
  154.     tokdatalen = sizeof(TOKEN_PRIMARY_GROUP);
  155.     tpgroup.PrimaryGroup = pgsid;
  156.     if (!SetTokenInformation(tok, TokenPrimaryGroup,
  157.         &tpgroup, tokdatalen)) {
  158.         (void)fprintf(stderr, "set_token_primarygroup_name: "
  159.             "SetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
  160.             "status=%d\n",
  161.             (void *)tok, (int)GetLastError());
  162.         return false;
  163.     }
  164.  
  165.     return true;
  166. }
  167.  
  168. enum shelltype {
  169.     SHELLTYPE_NOT_SET = 0,
  170.     SHELLTYPE_NONE,
  171.     SHELLTYPE_CMD,
  172.     SHELLTYPE_SYSTEM
  173. };
  174.  
  175. int main(int ac, char *av[])
  176. {
  177.     char pgroupname[GNLEN+1];
  178.     enum shelltype st = SHELLTYPE_NOT_SET;
  179.     int cmd_arg_index = -1;
  180.     const char *newgrpname = NULL;
  181.     int subcmdret = EXIT_FAILURE;
  182.  
  183.     int i;
  184.  
  185.     for (i=1 ; i < ac ; i++) {
  186.         (void)fprintf(stderr, "# i=%d, av[i]='%s'\n", i, av[i]);
  187.  
  188.         if (!strcmp(av[i], "-")) {
  189.             (void)fprintf(stderr, "%s: Run in new login not supported yet.\n", av[0]);
  190.             return 1;
  191.         }
  192.         else if (!strcmp(av[i], "-c")) {
  193.             st = SHELLTYPE_SYSTEM;
  194.             cmd_arg_index = i+1;
  195.             break;
  196.         }
  197.         else if (!strcmp(av[i], "/C")) {
  198.             st = SHELLTYPE_CMD;
  199.             cmd_arg_index = i+1;
  200.             break;
  201.         }
  202.         else if (!strcmp(av[i], "-g")) {
  203.             newgrpname = av[i+1];
  204.             i++;
  205.         }
  206.         else {
  207.             if ((i == 1) && (*av[i] != '-')) {
  208.                 newgrpname = av[i];
  209.                 continue;
  210.             }
  211.  
  212.             cmd_arg_index = i+1;
  213.             st = SHELLTYPE_NONE;
  214.             break;
  215.         }
  216.     }
  217.  
  218.     if ((st == SHELLTYPE_NOT_SET) && (cmd_arg_index == -1)) {
  219.         st = SHELLTYPE_NONE;
  220.         cmd_arg_index = 2;
  221.     }
  222.  
  223.     if (!newgrpname) {
  224.         (void)fprintf(stderr, "%s: No group name given.\n", av[0]);
  225.         return 1;
  226.     }
  227.  
  228.     (void)fprintf(stderr, "# shelltype=%d, cmd_arg_index=%d, av[cmd_arg_index]='%s', new group name '%s'\n",
  229.         (int)st, cmd_arg_index, av[cmd_arg_index], newgrpname);
  230.  
  231.     HANDLE tok;
  232.  
  233.     if (!OpenProcessToken(GetCurrentProcess(),
  234.         TOKEN_ALL_ACCESS/*TOKEN_QUERY|TOKEN_ADJUST_DEFAULT|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY*/,
  235.         &tok)) {
  236.         (void)fprintf(stderr, "OpenThreadToken failed.\n");
  237.         return 1;
  238.     }
  239.  
  240.     get_token_primarygroup_name(tok, pgroupname);
  241.     (void)printf("primary group name '%s'\n", pgroupname);
  242.  
  243.     if (!set_token_primarygroup_name(tok, newgrpname)) {
  244.         (void)fprintf(stderr, "%s: Could not switch to new primary group '%s'.\n",
  245.             av[0], newgrpname);
  246.         return 1;
  247.     }
  248.  
  249.     get_token_primarygroup_name(tok, pgroupname);
  250.     (void)printf("primary group name '%s'\n", pgroupname);
  251.  
  252.     (void)_flushall();
  253.  
  254.     switch(st) {
  255. #define CYGWIN_BASH_PATH "C:\\cygwin64\\bin\\bash.exe"
  256. #define WIN32_CMD_PATH "C:\\Windows\\system32\\cmd.exe"
  257.         case SHELLTYPE_SYSTEM:
  258.             if (av[cmd_arg_index] != NULL) {
  259.                 char cmdbuff[4096];
  260.                 snprintf(cmdbuff, sizeof(cmdbuff), "%s -c %s", "C:\\cygwin64\\bin\\bash.exe", av[cmd_arg_index]);
  261.                 subcmdret = system(cmdbuff);
  262.             }
  263.             else {
  264.                 subcmdret = system("C:\\cygwin64\\bin\\bash.exe");
  265.             }
  266.             break;
  267.         case SHELLTYPE_CMD:
  268.             if (av[cmd_arg_index] != NULL) {
  269.                 subcmdret = _spawnl(_P_WAIT, WIN32_CMD_PATH, WIN32_CMD_PATH, "/C", av[cmd_arg_index], NULL);
  270.             }
  271.             else {
  272.                 subcmdret = _spawnl(_P_WAIT, WIN32_CMD_PATH, WIN32_CMD_PATH, NULL);
  273.             }
  274.             break;
  275.         case SHELLTYPE_NONE:
  276.             if (av[cmd_arg_index] != NULL) {
  277.                 subcmdret = _spawnv(_P_WAIT, av[cmd_arg_index], (const char *const *)&av[cmd_arg_index]);
  278.             }
  279.             else {
  280.                 subcmdret = _spawnl(_P_WAIT, WIN32_CMD_PATH, WIN32_CMD_PATH, NULL);
  281.             }
  282.             break;
  283.         default:
  284.             break;
  285.     }
  286.  
  287.     (void)fprintf(stdout, "#mark winsg done, retval=%d\n", (int)subcmdret);
  288.     return 0;
  289. }

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.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at