pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS

Difference between
modified post 46221e by Anonymous on Fri 24th May 2024 15:53
original post d5c2 by Anonymous on Fri 24th May 2024 15:28
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 <assert.h>
4141
#include <Lmcons.h>
4242
#include <process.h>
4343
4444
#if 0
4545
#define D(x) x
4646
#else
4747
#define D(x)
4848
#endif
4949
50+
#ifdef _WIN64
5057
/*
5158
 * Performance hack:
5259
 * GETTOKINFO_EXTRA_BUFFER - extra space for more data
5360
 * |GetTokenInformation()| for |TOKEN_USER| and |TOKEN_PRIMARY_GROUP|
5461
 * always fails in Win10 with |ERROR_INSUFFICIENT_BUFFER| if you
5562
 * just pass the |sizeof(TOKEN_*)| value. Instead of calling
5663
 * |GetTokenInformation()| with |NULL| arg to obtain the size to
5764
 * allocate we just provide 2048 bytes of extra space after the
5865
 * |TOKEN_*| size, and pray it is enough
5966
 */
6067
#define GETTOKINFO_EXTRA_BUFFER (2048)
6168
6269
D(
6370
static
6471
bool get_token_primarygroup_name(HANDLE tok, char *out_buffer)
6572
{
6673
    DWORD tokdatalen;
6774
    PTOKEN_PRIMARY_GROUP ptpgroup;
6875
    PSID pgsid;
6976
    DWORD namesize = GNLEN+1;
7077
    char domainbuffer[UNLEN+1];
7178
    DWORD domainbuffer_size = sizeof(domainbuffer);
7279
    SID_NAME_USE name_use;
7380
7481
    tokdatalen = sizeof(TOKEN_PRIMARY_GROUP)+GETTOKINFO_EXTRA_BUFFER;
7582
    ptpgroup = _alloca(tokdatalen);
7683
    if (!GetTokenInformation(tok, TokenPrimaryGroup, ptpgroup,
7784
        tokdatalen, &tokdatalen)) {
7885
        D((void)fprintf(stderr, "get_token_primarygroup_name: "
7986
            "GetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
8087
            "status=%d.\n",
8188
            (void *)tok, (int)GetLastError()));
8289
        return false;
8390
    }
8491
8592
    pgsid = ptpgroup->PrimaryGroup;
8693
8794
    if (!LookupAccountSidA(NULL, pgsid, out_buffer, &namesize,
8895
        domainbuffer, &domainbuffer_size, &name_use)) {
8996
        D((void)fprintf(stderr, "get_token_primarygroup_name: "
9097
            "LookupAccountSidA() failed, status=%d.\n",
9198
            (int)GetLastError()));
9299
        return false;
93100
    }
94101
95102
    return true;
96103
}
97104
)
98105
99106
static
100107
bool is_group_in_token(HANDLE tok, PSID qsid)
101108
{
102109
    DWORD tokdatalen;
103110
    PTOKEN_GROUPS ptgroups;
104111
105112
    tokdatalen = sizeof(TOKEN_GROUPS)+GETTOKINFO_EXTRA_BUFFER;
106113
    ptgroups = _alloca(tokdatalen);
107114
    if (!GetTokenInformation(tok, TokenGroups, ptgroups,
108115
        tokdatalen, &tokdatalen)) {
109116
        D((void)fprintf(stderr, "is_group_in_token: "
110117
            "GetTokenInformation(tok=0x%p, TokenGroups) failed, "
111118
            "status=%d.\n",
112119
            (void *)tok, (int)GetLastError()));
113120
        return false;
114121
    }
115122
116123
    int i;
117124
    D(
118125
        (void)fprintf(stderr, "is_group_in_token: got %d groups\n",
119126
        (int)ptgroups->GroupCount)
120127
    );
121128
    for (i = 0 ; i < ptgroups->GroupCount ; i++) {
122129
        if (EqualSid(qsid, ptgroups->Groups[i].Sid) &&
123130
            (ptgroups->Groups[i].Attributes & SE_GROUP_ENABLED)) {
124-
            D((void)puts("#match"));
131+
            D((void)puts("is_group_in_token: #match"));
125132
            return true;
126133
        }
127134
    }
128135
129-
    D((void)puts("#no match"));
136+
    D((void)puts("is_group_in_token: #no match"));
130137
131138
    return false;
132139
}
133140
134141
static
135142
bool get_group_sid(const char *groupname, PSID pgsid, PDWORD pgsid_size)
136143
{
137144
    char domainbuffer[UNLEN+1];
138145
    DWORD domainbuffer_size = sizeof(domainbuffer);
139146
    SID_NAME_USE name_use;
140147
141148
    if (!LookupAccountNameA(NULL, groupname,
142149
        pgsid, pgsid_size, domainbuffer, &domainbuffer_size, &name_use)) {
143150
        D((void)fprintf(stderr, "get_group_sid: "
144151
            "LookupAccountNameA() failed.\n"));
145152
        return false;
146153
    }
147154
148155
    return true;
149156
}
150157
151158
static
152159
bool set_token_primarygroup_sid(HANDLE tok, PSID pgsid)
153160
{
154161
    DWORD tokdatalen;
155162
    TOKEN_PRIMARY_GROUP tpgroup;
156163
157164
    tokdatalen = sizeof(TOKEN_PRIMARY_GROUP);
158165
    tpgroup.PrimaryGroup = pgsid;
159166
    if (!SetTokenInformation(tok, TokenPrimaryGroup,
160167
        &tpgroup, tokdatalen)) {
161168
        D((void)fprintf(stderr, "set_token_primarygroup_sid: "
162169
            "SetTokenInformation(tok=0x%p, TokenPrimaryGroup) failed, "
163170
            "status=%d\n",
164171
            (void *)tok, (int)GetLastError()));
165172
        return false;
166173
    }
167174
168175
    return true;
169176
}
170177
171178
static
172179
char *stpcpy (char *s1, const char *s2)
173180
{
174181
    size_t l = strlen(s2);
175182
    return memcpy(s1, s2, l+1) + l;
176183
}
177184
178185
static
179186
void win32cmd_quotearg(char *s1, const char *s2)
180187
{
181188
    int c;
182189
    *s1++ = '"';
183190
    while ((c = *s2) != '\0') {
184191
        switch(c) {
185192
            case '"':
186193
                *s1++='\\';
187194
                *s1 = c;
188195
                break;
189196
            default:
190197
                *s1 = c;
191198
                break;
192199
        }
193200
        s1++;
194201
        s2++;
195202
    }
196203
    *s1++ = '"';
197204
    *s1 = '\0';
198205
}
199206
200207
201208
enum shelltype {
202209
    SHELLTYPE_NOT_SET = 0,
203210
    SHELLTYPE_NONE,
204211
    SHELLTYPE_CMD,
205212
    SHELLTYPE_SYSTEM
206213
};
207214
208215
int main(int ac, char *av[])
209216
{
210217
    enum shelltype st = SHELLTYPE_NOT_SET;
211218
    int cmd_arg_index = -1;
212219
    const char *newgrpname = NULL;
213220
    int subcmdret = EXIT_FAILURE;
214221
215222
    int i;
216223
217224
    for (i=1 ; i < ac ; i++) {
218225
        D((void)fprintf(stderr, "# i=%d, av[i]='%s'\n", i, av[i]));
219226
220227
        if (!strcmp(av[i], "-")) {
221228
            (void)fprintf(stderr, "%s: "
222229
                "Run in new login not supported yet.\n", av[0]);
223230
            return 1;
224231
        }
225232
        else if (!strcmp(av[i], "-c")) {
226233
            /* -c can take zero or one argument */
227234
            if ((ac-i) > 2) {
228235
                (void)fprintf(stderr, "%s: "
229236
                    "Too many arguments for -c.\n", av[0]);
230237
                return 1;
231238
            }
232239
233240
            st = SHELLTYPE_SYSTEM;
234241
            cmd_arg_index = i+1;
235242
            break;
236243
        }
237244
        else if (!strcmp(av[i], "/C")) {
238245
            /* /C can take zero or one argument */
239246
            if ((ac-i) > 2) {
240247
                (void)fprintf(stderr, "%s: "
241248
                    "Too many arguments for /C.\n", av[0]);
242249
                return 1;
243250
            }
244251
245252
            st = SHELLTYPE_CMD;
246253
            cmd_arg_index = i+1;
247254
            break;
248255
        }
249256
        else if (!strcmp(av[i], "-g")) {
250257
            newgrpname = av[i+1];
251258
            i++;
252259
        }
253260
        else if ((av[i][0] == '-') || (av[i][0] == '/')) {
254261
            (void)fprintf(stderr, "%s: "
255262
                "Unsupported option '%s'.\n", av[0], av[i]);
256263
            return 1;
257264
        }
258265
        else {
259266
            if ((i == 1) && (*av[i] != '-')) {
260267
                newgrpname = av[i];
261268
                continue;
262269
            }
263270
264271
            cmd_arg_index = i+1;
265272
            st = SHELLTYPE_NONE;
266273
            break;
267274
        }
268275
    }
269276
270277
    /*
271278
     * Handle newgrp(1)-like behaviour (run new shell (in our
272279
     * case cmd.exe) with requested group), e.g. ...
273280
     * $ winsg -g cygwingrp1
274281
     * $ winsg cygwingrp1
275282
     */
276283
    if ((st == SHELLTYPE_NOT_SET) && (cmd_arg_index == -1)) {
277284
        st = SHELLTYPE_NONE;
278285
        /* set |cmd_arg_index| to the end of |av|, which is |NULL| */
279286
        cmd_arg_index = i;
280287
    }
281288
282289
    if (!newgrpname) {
283290
        (void)fprintf(stderr, "%s: No group name given.\n", av[0]);
284291
        return 1;
285292
    }
286293
287294
    D((void)fprintf(stderr,
288295
        "# shelltype=%d, cmd_arg_index=%d, "
289296
        "av[cmd_arg_index]='%s', "
290297
        "new group name '%s'\n",
291298
        (int)st, cmd_arg_index, av[cmd_arg_index], newgrpname));
292299
293300
    HANDLE tok;
294301
295302
    if (!OpenProcessToken(GetCurrentProcess(),
296303
        TOKEN_QUERY|TOKEN_ADJUST_DEFAULT|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,
297304
        &tok)) {
298305
        (void)fprintf(stderr, "%s: Cannot open token.\n", av[0]);
299306
        return 1;
300307
    }
301308
302309
    D(
303310
        char pgroupname[GNLEN+1];
304311
305312
        get_token_primarygroup_name(tok, pgroupname);
306313
        (void)printf("primary group name '%s'\n", pgroupname);
307314
    )
308315
309316
    char sidbuff[SECURITY_MAX_SID_SIZE+1];
310317
    PSID pgsid = (PSID)sidbuff;
311318
    DWORD pgsid_size = sizeof(sidbuff);
312319
313320
    if (!get_group_sid(newgrpname, pgsid, &pgsid_size)) {
314321
        (void)fprintf(stderr, "%s: Could not find group '%s'.\n",
315322
            av[0], newgrpname);
316323
        return 1;
317324
    }
318325
319326
    if (!is_group_in_token(tok, pgsid)) {
320327
        (void)fprintf(stderr, "%s: "
321328
            "Current user is not a member of group '%s'.\n",
322329
            av[0], newgrpname);
323330
        return 1;
324331
    }
325332
326333
    if (!set_token_primarygroup_sid(tok, pgsid)) {
327334
        (void)fprintf(stderr,
328335
            "%s: Could not switch to new primary group '%s'.\n",
329336
            av[0], newgrpname);
330337
        return 1;
331338
    }
332339
333340
    D(
334341
        get_token_primarygroup_name(tok, pgroupname);
335342
        (void)printf("primary group name '%s'\n", pgroupname);
336343
    )
337344
338345
    (void)_flushall();
339346
340347
    switch(st) {
341-
#define CYGWIN_BASH_PATH "C:\\cygwin64\\bin\\bash.exe"
342-
#define WIN32_CMDEXE_PATH "C:\\Windows\\system32\\cmd.exe"
343348
        case SHELLTYPE_SYSTEM:
344349
            if (av[cmd_arg_index] != NULL) {
345350
                size_t cmdbuff_size = strlen(CYGWIN_BASH_PATH)+
346351
                    16+
347352
                    strlen(av[cmd_arg_index])*2;
348353
                char *cmdbuff = alloca(cmdbuff_size);
349354
                char *s = cmdbuff;
350355
                s = stpcpy(s, CYGWIN_BASH_PATH);
351356
                s = stpcpy(s, " -c ");
352357
353358
                win32cmd_quotearg(s, av[cmd_arg_index]);
354-
                (void)fprintf(stderr, "# executing '%s'\n", cmdbuff);
359+
                D((void)fprintf(stderr, "# executing '%s'\n", cmdbuff));
355360
                subcmdret = system(cmdbuff);
356361
            }
357362
            else {
358363
                subcmdret = system(CYGWIN_BASH_PATH);
359364
            }
360365
            break;
361366
        case SHELLTYPE_CMD:
362367
            if (av[cmd_arg_index] != NULL) {
363368
                subcmdret = _spawnl(_P_WAIT,
364369
                    WIN32_CMDEXE_PATH, WIN32_CMDEXE_PATH,
365370
                    "/C", av[cmd_arg_index], NULL);
366371
            }
367372
            else {
368373
                subcmdret = _spawnl(_P_WAIT,
369374
                    WIN32_CMDEXE_PATH, WIN32_CMDEXE_PATH, NULL);
370375
            }
371376
            break;
372377
        case SHELLTYPE_NONE:
373378
            subcmdret = _spawnl(_P_WAIT,
374379
                WIN32_CMDEXE_PATH, WIN32_CMDEXE_PATH, NULL);
375380
            break;
376381
        default:
377382
            assert(0);
378383
            break;
379384
    }
380385
381386
    D((void)fprintf(stdout, "#mark winsg done, retval=%d\n", (int)subcmdret));
382387
    return 0;
383388
}
384389

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