pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS

Difference between
modified post 59cd59 by Anonymous on Fri 24th May 2024 14:53
original post f94e417c8 by Anonymous on Fri 24th May 2024 14:13
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>
4040
#include <Lmcons.h>
4141
#include <process.h>
4242
4343
#if 0
4444
#define D(x) x
4545
#else
4646
#define D(x)
4747
#endif
4848
4949
/*
5050
 * Performance hack:
5151
 * GETTOKINFO_EXTRA_BUFFER - extra space for more data
5252
 * |GetTokenInformation()| for |TOKEN_USER| and |TOKEN_PRIMARY_GROUP|
5353
 * always fails in Win10 with |ERROR_INSUFFICIENT_BUFFER| if you
5454
 * just pass the |sizeof(TOKEN_*)| value. Instead of calling
5555
 * |GetTokenInformation()| with |NULL| arg to obtain the size to
5656
 * allocate we just provide 2048 bytes of extra space after the
5757
 * |TOKEN_*| size, and pray it is enough
5858
 */
5959
#define GETTOKINFO_EXTRA_BUFFER (2048)
6060
6161
bool get_token_primarygroup_name(HANDLE tok, char *out_buffer)
6262
{
6363
    DWORD tokdatalen;
6464
    PTOKEN_PRIMARY_GROUP ptpgroup;
6565
    PSID pgsid;
6666
    DWORD namesize = GNLEN+1;
6767
    char domainbuffer[UNLEN+1];
6868
    DWORD domainbuffer_size = sizeof(domainbuffer);
6969
    SID_NAME_USE name_use;
7070
7171
    tokdatalen = sizeof(TOKEN_PRIMARY_GROUP)+GETTOKINFO_EXTRA_BUFFER;
7272
    ptpgroup = _alloca(tokdatalen);
7373
    if (!GetTokenInformation(tok, TokenPrimaryGroup, ptpgroup,
7474
        tokdatalen, &tokdatalen)) {
7575
        D((void)fprintf(stderr, "get_token_primarygroup_name: "
7676
            "GetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
77-
            "status=%d\n",
77+
            "status=%d.\n",
7878
            (void *)tok, (int)GetLastError()));
7979
        return false;
8080
    }
8181
8282
    pgsid = ptpgroup->PrimaryGroup;
8383
8484
    if (!LookupAccountSidA(NULL, pgsid, out_buffer, &namesize,
8585
        domainbuffer, &domainbuffer_size, &name_use)) {
8686
        D((void)fprintf(stderr, "get_token_primarygroup_name: "
87-
            "LookupAccountSidA() failed, status=%d\n",
87+
            "LookupAccountSidA() failed, status=%d.\n",
8888
            (int)GetLastError()));
8989
        return false;
9090
    }
9191
9292
    return true;
9393
}
9494
9595
bool is_group_in_token(HANDLE tok, PSID qsid)
9696
{
9797
    DWORD tokdatalen;
9898
    PTOKEN_GROUPS ptgroups;
9999
100100
    tokdatalen = sizeof(TOKEN_GROUPS)+GETTOKINFO_EXTRA_BUFFER;
101101
    ptgroups = _alloca(tokdatalen);
102102
    if (!GetTokenInformation(tok, TokenGroups, ptgroups,
103103
        tokdatalen, &tokdatalen)) {
104104
        D((void)fprintf(stderr, "is_group_in_token: "
105105
            "GetTokenInformation(tok=0x%p, TokenGroups) failed, "
106-
            "status=%d\n",
106+
            "status=%d.\n",
107107
            (void *)tok, (int)GetLastError()));
108108
        return false;
109109
    }
110110
111111
    int i;
112-
    D((void)fprintf(stderr, "is_group_in_token: got %d groups\n", (int)ptgroups->GroupCount));
112+
    D(
113+
        (void)fprintf(stderr, "is_group_in_token: got %d groups\n",
113116
    for (i = 0 ; i < ptgroups->GroupCount ; i++) {
114117
        if (EqualSid(qsid, ptgroups->Groups[i].Sid) &&
115118
            (ptgroups->Groups[i].Attributes & SE_GROUP_ENABLED)) {
116119
            D((void)puts("#match"));
117120
            return true;
118121
        }
119122
    }
120123
121124
    D((void)puts("#no match"));
122125
123126
    return false;
124127
}
125128
126-
bool set_token_primarygroup_name(HANDLE tok, const char *new_groupname)
129+
bool get_group_sid(const char *groupname, PSID pgsid, PDWORD pgsid_size)
127130
{
133131
    char domainbuffer[UNLEN+1];
134132
    DWORD domainbuffer_size = sizeof(domainbuffer);
135133
    SID_NAME_USE name_use;
136134
137-
    if (!LookupAccountNameA(NULL, new_groupname,
135+
    if (!LookupAccountNameA(NULL, groupname,
138-
        pgsid, &pgsid_size, domainbuffer, &domainbuffer_size, &name_use)) {
136+
        pgsid, pgsid_size, domainbuffer, &domainbuffer_size, &name_use)) {
139-
        D((void)fprintf(stderr, "set_token_primarygroup_name: "
137+
        D((void)fprintf(stderr, "get_group_sid: "
140138
            "LookupAccountNameA() failed.\n"));
141139
        return false;
142140
    }
143141
144-
    if (!is_group_in_token(tok, pgsid)) {
142+
    return true;
148143
    }
149144
145+
bool set_token_primarygroup_sid(HANDLE tok, PSID pgsid)
150150
    tokdatalen = sizeof(TOKEN_PRIMARY_GROUP);
151151
    tpgroup.PrimaryGroup = pgsid;
152152
    if (!SetTokenInformation(tok, TokenPrimaryGroup,
153153
        &tpgroup, tokdatalen)) {
154-
        D((void)fprintf(stderr, "set_token_primarygroup_name: "
154+
        D((void)fprintf(stderr, "set_token_primarygroup_sid: "
155155
            "SetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
156156
            "status=%d\n",
157157
            (void *)tok, (int)GetLastError()));
158158
        return false;
159159
    }
160160
161161
    return true;
162162
}
163163
164164
enum shelltype {
165165
    SHELLTYPE_NOT_SET = 0,
166166
    SHELLTYPE_NONE,
167167
    SHELLTYPE_CMD,
168168
    SHELLTYPE_SYSTEM
169169
};
170170
171171
int main(int ac, char *av[])
172172
{
173173
    enum shelltype st = SHELLTYPE_NOT_SET;
174174
    int cmd_arg_index = -1;
175175
    const char *newgrpname = NULL;
176176
    int subcmdret = EXIT_FAILURE;
177177
178178
    int i;
179179
180180
    for (i=1 ; i < ac ; i++) {
181181
        D((void)fprintf(stderr, "# i=%d, av[i]='%s'\n", i, av[i]));
182182
183183
        if (!strcmp(av[i], "-")) {
184-
            (void)fprintf(stderr, "%s: Run in new login not supported yet.\n", av[0]);
184+
            (void)fprintf(stderr, "%s: "
185+
                "Run in new login not supported yet.\n", av[0]);
185186
            return 1;
186187
        }
187188
        else if (!strcmp(av[i], "-c")) {
189+
            /* -c can take zero or one argument */
188196
            st = SHELLTYPE_SYSTEM;
189197
            cmd_arg_index = i+1;
190198
            break;
191199
        }
192200
        else if (!strcmp(av[i], "/C")) {
201+
            /* /C can take zero or one argument */
193208
            st = SHELLTYPE_CMD;
194209
            cmd_arg_index = i+1;
195210
            break;
196211
        }
197212
        else if (!strcmp(av[i], "-g")) {
198213
            newgrpname = av[i+1];
199214
            i++;
200215
        }
201216
        else {
202217
            if ((i == 1) && (*av[i] != '-')) {
203218
                newgrpname = av[i];
204219
                continue;
205220
            }
206221
207222
            cmd_arg_index = i+1;
208223
            st = SHELLTYPE_NONE;
209224
            break;
210225
        }
211226
    }
212227
213228
    /*
214229
     * Handle newgrp(1)-like behaviour (run new shell (in our
215230
     * case cmd.exe) with requested group), e.g. ...
216231
     * $ winsg -g cygwingrp1
217232
     * $ winsg cygwingrp1
218233
     */
219234
    if ((st == SHELLTYPE_NOT_SET) && (cmd_arg_index == -1)) {
220235
        st = SHELLTYPE_NONE;
221236
        /* set |cmd_arg_index| to the end of |av|, which is |NULL| */
222237
        cmd_arg_index = i;
223238
    }
224239
225240
    if (!newgrpname) {
226241
        (void)fprintf(stderr, "%s: No group name given.\n", av[0]);
227242
        return 1;
228243
    }
229244
230245
    D((void)fprintf(stderr,
231246
        "# shelltype=%d, cmd_arg_index=%d, "
232247
        "av[cmd_arg_index]='%s', "
233248
        "new group name '%s'\n",
234249
        (int)st, cmd_arg_index, av[cmd_arg_index], newgrpname));
235250
236251
    HANDLE tok;
237252
238253
    if (!OpenProcessToken(GetCurrentProcess(),
239254
        TOKEN_QUERY|TOKEN_ADJUST_DEFAULT|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,
240255
        &tok)) {
241256
        (void)fprintf(stderr, "%s: Cannot open token.\n", av[0]);
242257
        return 1;
243258
    }
244259
245260
    D(
246261
        char pgroupname[GNLEN+1];
247262
248263
        get_token_primarygroup_name(tok, pgroupname);
249264
        (void)printf("primary group name '%s'\n", pgroupname);
250265
    )
251266
252-
    if (!set_token_primarygroup_name(tok, newgrpname)) {
267+
    char sidbuff[SECURITY_MAX_SID_SIZE+1];
253-
        (void)fprintf(stderr,
268+
    PSID pgsid = (PSID)sidbuff;
254-
            "%s: Could not switch to new primary group '%s'.\n",
269+
    DWORD pgsid_size = sizeof(sidbuff);
258270
259-
    D(
271+
    if (!get_group_sid(newgrpname, pgsid, &pgsid_size)) {
260-
        get_token_primarygroup_name(tok, pgroupname);
272+
        (void)fprintf(stderr, "%s: Could not find group '%s'.\n",
261-
        (void)printf("primary group name '%s'\n", pgroupname);
273+
            av[0], newgrpname);
262-
    )
274+
        return 1;
275+
    }
263276
264-
    (void)_flushall();
277+
    if (!is_group_in_token(tok, pgsid)) {
278+
        (void)fprintf(stderr, "%s: "
265283
266-
    switch(st) {
284+
    if (!set_token_primarygroup_sid(tok, pgsid)) {
267-
#define CYGWIN_BASH_PATH "C:\\cygwin64\\bin\\bash.exe"
285+
        (void)fprintf(stderr,
268-
#define WIN32_CMD_PATH "C:\\Windows\\system32\\cmd.exe"
286+
            "%s: Could not switch to new primary group '%s'.\n",
269-
        case SHELLTYPE_SYSTEM:
287+
            av[0], newgrpname);
270-
            if (av[cmd_arg_index] != NULL) {
288+
        return 1;
279289
            }
280-
            else {
290+
281-
                subcmdret = system(CYGWIN_BASH_PATH);
291+
    D(
282-
            }
292+
        get_token_primarygroup_name(tok, pgroupname);
283-
            break;
293+
        (void)printf("primary group name '%s'\n", pgroupname);
284-
        case SHELLTYPE_CMD:
294+
    )
295+
285302
            if (av[cmd_arg_index] != NULL) {
286-
                subcmdret = _spawnl(_P_WAIT,
303+
                size_t cmdbuff_size = strlen(CYGWIN_BASH_PATH)+
287-
                    WIN32_CMD_PATH, WIN32_CMD_PATH,
304+
                    16+
288-
                    "/C", av[cmd_arg_index], NULL);
305+
                    strlen(av[cmd_arg_index]);
306+
                char *cmdbuff = alloca(cmdbuff_size);
289311
            }
290312
            else {
313+
                subcmdret = system(CYGWIN_BASH_PATH);
293314
            }
294315
            break;
295-
        case SHELLTYPE_NONE:
316+
        case SHELLTYPE_CMD:
296317
            if (av[cmd_arg_index] != NULL) {
302318
                subcmdret = _spawnl(_P_WAIT,
319+
                    WIN32_CMD_PATH, WIN32_CMD_PATH,
304321
            }
322+
            else {
305326
            break;
306-
        default:
327+
        case SHELLTYPE_NONE:
307-
            break;
328+
            if (av[cmd_arg_index] != NULL) {
329+
                subcmdret = _spawnv(_P_WAIT,
308332
    }
309-
333+
            else {
310-
    D((void)fprintf(stdout, "#mark winsg done, retval=%d\n", (int)subcmdret));
334+
                subcmdret = _spawnl(_P_WAIT,
311-
    return 0;
335+
                    WIN32_CMD_PATH, WIN32_CMD_PATH, NULL);
312336
}
313-
337+
            break;
314-
338+
        default:
315-
339+
            break;
316-
340+
    }
317341
318-
342+
    D((void)fprintf(stdout, "#mark winsg done, retval=%d\n", (int)subcmdret));
319-
343+
    return 0;
320-
344+
}
321345

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