pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS

Difference between
modified post d5c2 by Anonymous on Fri 24th May 2024 15:28
original post 59cd59 by Anonymous on Fri 24th May 2024 14:53
Download diff
Show old version | new version | both versions

    
11
22
/*
33
 * MIT License
44
 *
55
 * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
66
 *
77
 * Permission is hereby granted, free of charge, to any person obtaining a copy
88
 * of this software and associated documentation files (the "Software"), to deal
99
 * in the Software without restriction, including without limitation the rights
1010
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1111
 * copies of the Software, and to permit persons to whom the Software is
1212
 * furnished to do so, subject to the following conditions:
1313
 *
1414
 * The above copyright notice and this permission notice shall be included in all
1515
 * copies or substantial portions of the Software.
1616
 *
1717
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1818
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1919
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2020
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2121
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2222
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2323
 * SOFTWARE.
2424
 */
2525
2626
/*
2727
 * winsg.c - run Win32 or Cygwin program with a different (primary) group
2828
 *
2929
 * Written by Roland Mainz <roland.mainz@nrubsig.org>
3030
 */
3131
3232
/*
3333
 * Compile with:
3434
 * $ clang -target x86_64-pc-windows-gnu -Wall -DUNICODE=1 -D_UNICODE=1 -g winsg.c -o winsg.exe #
3535
 */
3636
3737
#include <windows.h>
3838
#include <stdio.h>
3939
#include <stdbool.h>
40+
#include <assert.h>
4041
#include <Lmcons.h>
4142
#include <process.h>
4243
4344
#if 0
4445
#define D(x) x
4546
#else
4647
#define D(x)
4748
#endif
4849
4950
/*
5051
 * Performance hack:
5152
 * GETTOKINFO_EXTRA_BUFFER - extra space for more data
5253
 * |GetTokenInformation()| for |TOKEN_USER| and |TOKEN_PRIMARY_GROUP|
5354
 * always fails in Win10 with |ERROR_INSUFFICIENT_BUFFER| if you
5455
 * just pass the |sizeof(TOKEN_*)| value. Instead of calling
5556
 * |GetTokenInformation()| with |NULL| arg to obtain the size to
5657
 * allocate we just provide 2048 bytes of extra space after the
5758
 * |TOKEN_*| size, and pray it is enough
5859
 */
5960
#define GETTOKINFO_EXTRA_BUFFER (2048)
6061
62+
D(
6164
bool get_token_primarygroup_name(HANDLE tok, char *out_buffer)
6265
{
6366
    DWORD tokdatalen;
6467
    PTOKEN_PRIMARY_GROUP ptpgroup;
6568
    PSID pgsid;
6669
    DWORD namesize = GNLEN+1;
6770
    char domainbuffer[UNLEN+1];
6871
    DWORD domainbuffer_size = sizeof(domainbuffer);
6972
    SID_NAME_USE name_use;
7073
7174
    tokdatalen = sizeof(TOKEN_PRIMARY_GROUP)+GETTOKINFO_EXTRA_BUFFER;
7275
    ptpgroup = _alloca(tokdatalen);
7376
    if (!GetTokenInformation(tok, TokenPrimaryGroup, ptpgroup,
7477
        tokdatalen, &tokdatalen)) {
7578
        D((void)fprintf(stderr, "get_token_primarygroup_name: "
7679
            "GetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
7780
            "status=%d.\n",
7881
            (void *)tok, (int)GetLastError()));
7982
        return false;
8083
    }
8184
8285
    pgsid = ptpgroup->PrimaryGroup;
8386
8487
    if (!LookupAccountSidA(NULL, pgsid, out_buffer, &namesize,
8588
        domainbuffer, &domainbuffer_size, &name_use)) {
8689
        D((void)fprintf(stderr, "get_token_primarygroup_name: "
8790
            "LookupAccountSidA() failed, status=%d.\n",
8891
            (int)GetLastError()));
8992
        return false;
9093
    }
9194
9295
    return true;
9396
}
97+
)
9498
99+
static
95100
bool is_group_in_token(HANDLE tok, PSID qsid)
96101
{
97102
    DWORD tokdatalen;
98103
    PTOKEN_GROUPS ptgroups;
99104
100105
    tokdatalen = sizeof(TOKEN_GROUPS)+GETTOKINFO_EXTRA_BUFFER;
101106
    ptgroups = _alloca(tokdatalen);
102107
    if (!GetTokenInformation(tok, TokenGroups, ptgroups,
103108
        tokdatalen, &tokdatalen)) {
104109
        D((void)fprintf(stderr, "is_group_in_token: "
105110
            "GetTokenInformation(tok=0x%p, TokenGroups) failed, "
106111
            "status=%d.\n",
107112
            (void *)tok, (int)GetLastError()));
108113
        return false;
109114
    }
110115
111116
    int i;
112117
    D(
113118
        (void)fprintf(stderr, "is_group_in_token: got %d groups\n",
114119
        (int)ptgroups->GroupCount)
115120
    );
116121
    for (i = 0 ; i < ptgroups->GroupCount ; i++) {
117122
        if (EqualSid(qsid, ptgroups->Groups[i].Sid) &&
118123
            (ptgroups->Groups[i].Attributes & SE_GROUP_ENABLED)) {
119124
            D((void)puts("#match"));
120125
            return true;
121126
        }
122127
    }
123128
124129
    D((void)puts("#no match"));
125130
126131
    return false;
127132
}
128133
134+
static
129135
bool get_group_sid(const char *groupname, PSID pgsid, PDWORD pgsid_size)
130136
{
131137
    char domainbuffer[UNLEN+1];
132138
    DWORD domainbuffer_size = sizeof(domainbuffer);
133139
    SID_NAME_USE name_use;
134140
135141
    if (!LookupAccountNameA(NULL, groupname,
136142
        pgsid, pgsid_size, domainbuffer, &domainbuffer_size, &name_use)) {
137143
        D((void)fprintf(stderr, "get_group_sid: "
138144
            "LookupAccountNameA() failed.\n"));
139145
        return false;
140146
    }
141147
142148
    return true;
143149
}
144150
151+
static
145152
bool set_token_primarygroup_sid(HANDLE tok, PSID pgsid)
146153
{
147154
    DWORD tokdatalen;
148155
    TOKEN_PRIMARY_GROUP tpgroup;
149156
150157
    tokdatalen = sizeof(TOKEN_PRIMARY_GROUP);
151158
    tpgroup.PrimaryGroup = pgsid;
152159
    if (!SetTokenInformation(tok, TokenPrimaryGroup,
153160
        &tpgroup, tokdatalen)) {
154161
        D((void)fprintf(stderr, "set_token_primarygroup_sid: "
155162
            "SetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
156163
            "status=%d\n",
157164
            (void *)tok, (int)GetLastError()));
158165
        return false;
159166
    }
160167
161168
    return true;
162169
}
163170
164-
enum shelltype {
171+
static
165-
    SHELLTYPE_NOT_SET = 0,
172+
char *stpcpy (char *s1, const char *s2)
172173
{
173-
    enum shelltype st = SHELLTYPE_NOT_SET;
174+
    size_t l = strlen(s2);
174-
    int cmd_arg_index = -1;
175+
    return memcpy(s1, s2, l+1) + l;
175-
    const char *newgrpname = NULL;
176+
}
177177
178-
    int i;
178+
static
179-
179+
void win32cmd_quotearg(char *s1, const char *s2)
180-
    for (i=1 ; i < ac ; i++) {
180+
{
181-
        D((void)fprintf(stderr, "# i=%d, av[i]='%s'\n", i, av[i]));
181+
    int c;
182-
182+
    *s1++ = '"';
183-
        if (!strcmp(av[i], "-")) {
183+
    while ((c = *s2) != '\0') {
184-
            (void)fprintf(stderr, "%s: "
184+
        switch(c) {
185-
                "Run in new login not supported yet.\n", av[0]);
185+
            case '"':
186-
            return 1;
186+
                *s1++='\\';
187+
                *s1 = c;
187192
        }
188-
        else if (!strcmp(av[i], "-c")) {
193+
        s1++;
189-
            /* -c can take zero or one argument */
194+
        s2++;
194195
            }
196+
    *s1++ = '"';
195199
196-
            st = SHELLTYPE_SYSTEM;
200+
197-
            cmd_arg_index = i+1;
201+
enum shelltype {
198-
            break;
202+
    SHELLTYPE_NOT_SET = 0,
199-
        }
203+
    SHELLTYPE_NONE,
200-
        else if (!strcmp(av[i], "/C")) {
204+
    SHELLTYPE_CMD,
201-
            /* /C can take zero or one argument */
205+
    SHELLTYPE_SYSTEM
202-
            if ((ac-i) > 2) {
206+
};
207207
208-
            st = SHELLTYPE_CMD;
208+
int main(int ac, char *av[])
209-
            cmd_arg_index = i+1;
209+
{
210-
            break;
210+
    enum shelltype st = SHELLTYPE_NOT_SET;
211-
        }
211+
    int cmd_arg_index = -1;
212-
        else if (!strcmp(av[i], "-g")) {
212+
    const char *newgrpname = NULL;
213-
            newgrpname = av[i+1];
213+
    int subcmdret = EXIT_FAILURE;
221214
222-
            cmd_arg_index = i+1;
215+
    int i;
227216
228-
    /*
217+
    for (i=1 ; i < ac ; i++) {
229-
     * Handle newgrp(1)-like behaviour (run new shell (in our
218+
        D((void)fprintf(stderr, "# i=%d, av[i]='%s'\n", i, av[i]));
239219
240-
    if (!newgrpname) {
220+
        if (!strcmp(av[i], "-")) {
241-
        (void)fprintf(stderr, "%s: No group name given.\n", av[0]);
221+
            (void)fprintf(stderr, "%s: "
222+
                "Run in new login not supported yet.\n", av[0]);
242223
        return 1;
243224
    }
225+
        else if (!strcmp(av[i], "-c")) {
244232
245-
    D((void)fprintf(stderr,
233+
            st = SHELLTYPE_SYSTEM;
246-
        "# shelltype=%d, cmd_arg_index=%d, "
234+
            cmd_arg_index = i+1;
247-
        "av[cmd_arg_index]='%s', "
235+
            break;
248-
        "new group name '%s'\n",
236+
        }
249-
        (int)st, cmd_arg_index, av[cmd_arg_index], newgrpname));
237+
        else if (!strcmp(av[i], "/C")) {
238+
            /* /C can take zero or one argument */
250244
251-
    HANDLE tok;
245+
            st = SHELLTYPE_CMD;
252-
246+
            cmd_arg_index = i+1;
253-
    if (!OpenProcessToken(GetCurrentProcess(),
247+
            break;
258248
    }
259-
249+
        else if (!strcmp(av[i], "-g")) {
260-
    D(
250+
            newgrpname = av[i+1];
261-
        char pgroupname[GNLEN+1];
251+
            i++;
262-
252+
        }
263-
        get_token_primarygroup_name(tok, pgroupname);
253+
        else if ((av[i][0] == '-') || (av[i][0] == '/')) {
264-
        (void)printf("primary group name '%s'\n", pgroupname);
254+
            (void)fprintf(stderr, "%s: "
265-
    )
255+
                "Unsupported option '%s'.\n", av[0], av[i]);
256+
            return 1;
266263
267-
    char sidbuff[SECURITY_MAX_SID_SIZE+1];
264+
            cmd_arg_index = i+1;
268-
    PSID pgsid = (PSID)sidbuff;
265+
            st = SHELLTYPE_NONE;
269-
    DWORD pgsid_size = sizeof(sidbuff);
266+
            break;
267+
        }
270269
271-
    if (!get_group_sid(newgrpname, pgsid, &pgsid_size)) {
270+
    /*
272-
        (void)fprintf(stderr, "%s: Could not find group '%s'.\n",
271+
     * Handle newgrp(1)-like behaviour (run new shell (in our
273-
            av[0], newgrpname);
272+
     * case cmd.exe) with requested group), e.g. ...
274-
        return 1;
273+
     * $ winsg -g cygwingrp1
274+
     * $ winsg cygwingrp1
275280
    }
276281
277-
    if (!is_group_in_token(tok, pgsid)) {
282+
    if (!newgrpname) {
278-
        (void)fprintf(stderr, "%s: "
283+
        (void)fprintf(stderr, "%s: No group name given.\n", av[0]);
281284
        return 1;
282285
    }
283286
284-
    if (!set_token_primarygroup_sid(tok, pgsid)) {
287+
    D((void)fprintf(stderr,
285-
        (void)fprintf(stderr,
288+
        "# shelltype=%d, cmd_arg_index=%d, "
286-
            "%s: Could not switch to new primary group '%s'.\n",
289+
        "av[cmd_arg_index]='%s', "
287-
            av[0], newgrpname);
290+
        "new group name '%s'\n",
291+
        (int)st, cmd_arg_index, av[cmd_arg_index], newgrpname));
290292
293+
    HANDLE tok;
295294
296-
    (void)_flushall();
295+
    if (!OpenProcessToken(GetCurrentProcess(),
296+
        TOKEN_QUERY|TOKEN_ADJUST_DEFAULT|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,
297301
298-
    switch(st) {
302+
    D(
299-
#define CYGWIN_BASH_PATH "C:\\cygwin64\\bin\\bash.exe"
303+
        char pgroupname[GNLEN+1];
300-
#define WIN32_CMD_PATH "C:\\Windows\\system32\\cmd.exe"
304+
301-
        case SHELLTYPE_SYSTEM:
305+
        get_token_primarygroup_name(tok, pgroupname);
302-
            if (av[cmd_arg_index] != NULL) {
306+
        (void)printf("primary group name '%s'\n", pgroupname);
303-
                size_t cmdbuff_size = strlen(CYGWIN_BASH_PATH)+
307+
    )
304-
                    16+
308+
305-
                    strlen(av[cmd_arg_index]);
309+
    char sidbuff[SECURITY_MAX_SID_SIZE+1];
306-
                char *cmdbuff = alloca(cmdbuff_size);
310+
    PSID pgsid = (PSID)sidbuff;
307-
                (void)snprintf(cmdbuff, cmdbuff_size,
311+
    DWORD pgsid_size = sizeof(sidbuff);
308-
                    "%s -c '%s'", CYGWIN_BASH_PATH,
312+
309-
                    av[cmd_arg_index]);
313+
    if (!get_group_sid(newgrpname, pgsid, &pgsid_size)) {
310-
                subcmdret = system(cmdbuff);
314+
        (void)fprintf(stderr, "%s: Could not find group '%s'.\n",
315+
            av[0], newgrpname);
311317
            }
312-
            else {
318+
313-
                subcmdret = system(CYGWIN_BASH_PATH);
319+
    if (!is_group_in_token(tok, pgsid)) {
320+
        (void)fprintf(stderr, "%s: "
314324
            }
315-
            break;
325+
316-
        case SHELLTYPE_CMD:
326+
    if (!set_token_primarygroup_sid(tok, pgsid)) {
317-
            if (av[cmd_arg_index] != NULL) {
327+
        (void)fprintf(stderr,
318-
                subcmdret = _spawnl(_P_WAIT,
328+
            "%s: Could not switch to new primary group '%s'.\n",
319-
                    WIN32_CMD_PATH, WIN32_CMD_PATH,
329+
            av[0], newgrpname);
320-
                    "/C", av[cmd_arg_index], NULL);
330+
        return 1;
321331
            }
322-
            else {
332+
323-
                subcmdret = _spawnl(_P_WAIT,
333+
    D(
324-
                    WIN32_CMD_PATH, WIN32_CMD_PATH, NULL);
334+
        get_token_primarygroup_name(tok, pgroupname);
325-
            }
335+
        (void)printf("primary group name '%s'\n", pgroupname);
326-
            break;
336+
    )
327-
        case SHELLTYPE_NONE:
337+
338+
    (void)_flushall();
328344
            if (av[cmd_arg_index] != NULL) {
329-
                subcmdret = _spawnv(_P_WAIT,
345+
                size_t cmdbuff_size = strlen(CYGWIN_BASH_PATH)+
330-
                    av[cmd_arg_index],
346+
                    16+
331-
                    (const char *const *)&av[cmd_arg_index]);
347+
                    strlen(av[cmd_arg_index])*2;
348+
                char *cmdbuff = alloca(cmdbuff_size);
332356
            }
333357
            else {
358+
                subcmdret = system(CYGWIN_BASH_PATH);
336359
            }
337360
            break;
338-
        default:
361+
        case SHELLTYPE_CMD:
339-
            break;
362+
            if (av[cmd_arg_index] != NULL) {
363+
                subcmdret = _spawnl(_P_WAIT,
340366
    }
341-
367+
            else {
342-
    D((void)fprintf(stdout, "#mark winsg done, retval=%d\n", (int)subcmdret));
368+
                subcmdret = _spawnl(_P_WAIT,
343-
    return 0;
369+
                    WIN32_CMDEXE_PATH, WIN32_CMDEXE_PATH, NULL);
344370
}
345-
371+
            break;
346-
372+
        case SHELLTYPE_NONE:
347-
373+
            subcmdret = _spawnl(_P_WAIT,
348-
374+
                WIN32_CMDEXE_PATH, WIN32_CMDEXE_PATH, NULL);
349-
375+
            break;
350-
376+
        default:
351-
377+
            assert(0);
352-
378+
            break;
353-
379+
    }
354380
355-
381+
    D((void)fprintf(stdout, "#mark winsg done, retval=%d\n", (int)subcmdret));
356-
382+
    return 0;
357-
383+
}
358384

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