1/*
2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include <jni.h>
27#include "jni_util.h"
28#include "com_sun_security_auth_module_NTSystem.h"
29
30#include <windows.h>
31#include <stdio.h>
32#include <wchar.h>
33#include <ntsecapi.h>
34#include <lmerr.h>
35
36static BOOL debug = FALSE;
37
38BOOL getToken(PHANDLE);
39BOOL getUser(HANDLE tokenHandle, LPTSTR *userName,
40        LPTSTR *domainName, LPTSTR *userSid, LPTSTR *domainSid);
41BOOL getPrimaryGroup(HANDLE tokenHandle, LPTSTR *primaryGroup);
42BOOL getGroups(HANDLE tokenHandle, PDWORD numGroups, LPTSTR **groups);
43BOOL getImpersonationToken(PHANDLE impersonationToken);
44BOOL getTextualSid(PSID pSid, LPTSTR TextualSid, LPDWORD lpdwBufferLen);
45void DisplayErrorText(DWORD dwLastError);
46
47static void throwIllegalArgumentException(JNIEnv *env, const char *msg) {
48    jclass clazz = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
49    if (clazz != NULL)
50        (*env)->ThrowNew(env, clazz, msg);
51}
52
53/*
54 * Declare library specific JNI_Onload entry if static build
55 */
56DEF_STATIC_JNI_OnLoad
57
58JNIEXPORT jlong JNICALL
59Java_com_sun_security_auth_module_NTSystem_getImpersonationToken0
60        (JNIEnv *env, jobject obj) {
61    HANDLE impersonationToken = 0;      // impersonation token
62    if (debug) {
63        printf("getting impersonation token\n");
64    }
65    if (getImpersonationToken(&impersonationToken) == FALSE) {
66        return 0;
67    }
68    return (jlong)impersonationToken;
69}
70
71JNIEXPORT void JNICALL
72Java_com_sun_security_auth_module_NTSystem_getCurrent
73    (JNIEnv *env, jobject obj, jboolean debugNative) {
74
75    long i, j = 0;
76    HANDLE tokenHandle = INVALID_HANDLE_VALUE;
77
78    LPTSTR userName = NULL;             // user name
79    LPTSTR userSid = NULL;              // user sid
80    LPTSTR domainName = NULL;           // domain name
81    LPTSTR domainSid = NULL;            // domain sid
82    LPTSTR primaryGroup = NULL;         // primary group sid
83    DWORD numGroups = 0;                // num groups
84    LPTSTR *groups = NULL;              // groups array
85    long pIndex = -1;                   // index of primaryGroup in groups array
86
87    jfieldID fid;
88    jstring jstr;
89    jobjectArray jgroups;
90    jclass stringClass = 0;
91    jclass cls = (*env)->GetObjectClass(env, obj);
92
93    debug = debugNative;
94
95    // get NT information first
96
97    if (debug) {
98        printf("getting access token\n");
99    }
100    if (getToken(&tokenHandle) == FALSE) {
101        return;
102    }
103
104    if (debug) {
105        printf("getting user info\n");
106    }
107    if (getUser
108        (tokenHandle, &userName, &domainName, &userSid, &domainSid) == FALSE) {
109        return;
110    }
111
112    if (debug) {
113        printf("getting primary group\n");
114    }
115    if (getPrimaryGroup(tokenHandle, &primaryGroup) == FALSE) {
116        return;
117    }
118
119    if (debug) {
120        printf("getting supplementary groups\n");
121    }
122    if (getGroups(tokenHandle, &numGroups, &groups) == FALSE) {
123        return;
124    }
125
126    // then set values into NTSystem
127
128    fid = (*env)->GetFieldID(env, cls, "userName", "Ljava/lang/String;");
129    if (fid == 0) {
130        (*env)->ExceptionClear(env);
131        throwIllegalArgumentException(env, "invalid field: userName");
132        goto cleanup;
133    }
134    jstr = (*env)->NewStringUTF(env, userName);
135    if (jstr == NULL)
136        goto cleanup;
137    (*env)->SetObjectField(env, obj, fid, jstr);
138
139    fid = (*env)->GetFieldID(env, cls, "userSID", "Ljava/lang/String;");
140    if (fid == 0) {
141        (*env)->ExceptionClear(env);
142        throwIllegalArgumentException(env, "invalid field: userSID");
143        goto cleanup;
144    }
145    jstr = (*env)->NewStringUTF(env, userSid);
146    if (jstr == NULL)
147        goto cleanup;
148    (*env)->SetObjectField(env, obj, fid, jstr);
149
150    fid = (*env)->GetFieldID(env, cls, "domain", "Ljava/lang/String;");
151    if (fid == 0) {
152        (*env)->ExceptionClear(env);
153        throwIllegalArgumentException(env, "invalid field: domain");
154        goto cleanup;
155    }
156    jstr = (*env)->NewStringUTF(env, domainName);
157    if (jstr == NULL)
158        goto cleanup;
159    (*env)->SetObjectField(env, obj, fid, jstr);
160
161    if (domainSid != NULL) {
162        fid = (*env)->GetFieldID(env, cls, "domainSID", "Ljava/lang/String;");
163        if (fid == 0) {
164            (*env)->ExceptionClear(env);
165            throwIllegalArgumentException(env, "invalid field: domainSID");
166            goto cleanup;
167        }
168        jstr = (*env)->NewStringUTF(env, domainSid);
169        if (jstr == NULL)
170            goto cleanup;
171        (*env)->SetObjectField(env, obj, fid, jstr);
172    }
173
174    fid = (*env)->GetFieldID(env, cls, "primaryGroupID", "Ljava/lang/String;");
175    if (fid == 0) {
176        (*env)->ExceptionClear(env);
177        throwIllegalArgumentException(env, "invalid field: PrimaryGroupID");
178        goto cleanup;
179    }
180    jstr = (*env)->NewStringUTF(env, primaryGroup);
181    if (jstr == NULL)
182        goto cleanup;
183    (*env)->SetObjectField(env, obj, fid, jstr);
184
185    // primary group may or may not be part of supplementary groups
186    for (i = 0; i < (long)numGroups; i++) {
187        if (strcmp(primaryGroup, groups[i]) == 0) {
188            // found primary group in groups array
189            pIndex = i;
190            break;
191        }
192    }
193
194    if (numGroups == 0 || (pIndex == 0 && numGroups == 1)) {
195        // primary group is only group in groups array
196
197        if (debug) {
198            printf("no secondary groups\n");
199        }
200    } else {
201
202        // the groups array is non-empty,
203        // and may or may not contain the primary group
204
205        fid = (*env)->GetFieldID(env, cls, "groupIDs", "[Ljava/lang/String;");
206        if (fid == 0) {
207            (*env)->ExceptionClear(env);
208            throwIllegalArgumentException(env, "groupIDs");
209            goto cleanup;
210        }
211
212        stringClass = (*env)->FindClass(env, "java/lang/String");
213        if (stringClass == NULL)
214            goto cleanup;
215
216        if (pIndex == -1) {
217            // primary group not in groups array
218            jgroups = (*env)->NewObjectArray(env, numGroups, stringClass, 0);
219        } else {
220            // primary group in groups array -
221            // allocate one less array entry and do not add into new array
222            jgroups = (*env)->NewObjectArray(env, numGroups-1, stringClass, 0);
223        }
224        if (jgroups == NULL)
225            goto cleanup;
226
227        for (i = 0, j = 0; i < (long)numGroups; i++) {
228            if (pIndex == i) {
229                // continue if equal to primary group
230                continue;
231            }
232            jstr = (*env)->NewStringUTF(env, groups[i]);
233            if (jstr == NULL)
234                goto cleanup;
235            (*env)->SetObjectArrayElement(env, jgroups, j++, jstr);
236        }
237        (*env)->SetObjectField(env, obj, fid, jgroups);
238    }
239
240cleanup:
241    if (userName != NULL) {
242        HeapFree(GetProcessHeap(), 0, userName);
243    }
244    if (domainName != NULL) {
245        HeapFree(GetProcessHeap(), 0, domainName);
246    }
247    if (userSid != NULL) {
248        HeapFree(GetProcessHeap(), 0, userSid);
249    }
250    if (domainSid != NULL) {
251        HeapFree(GetProcessHeap(), 0, domainSid);
252    }
253    if (primaryGroup != NULL) {
254        HeapFree(GetProcessHeap(), 0, primaryGroup);
255    }
256    if (groups != NULL) {
257        for (i = 0; i < (long)numGroups; i++) {
258            if (groups[i] != NULL) {
259                HeapFree(GetProcessHeap(), 0, groups[i]);
260            }
261        }
262        HeapFree(GetProcessHeap(), 0, groups);
263    }
264    CloseHandle(tokenHandle);
265
266    return;
267}
268
269BOOL getToken(PHANDLE tokenHandle) {
270
271    // first try the thread token
272    if (OpenThreadToken(GetCurrentThread(),
273                        TOKEN_READ,
274                        FALSE,
275                        tokenHandle) == 0) {
276        if (debug) {
277            printf("  [getToken] OpenThreadToken error [%d]: ", GetLastError());
278            DisplayErrorText(GetLastError());
279        }
280
281        // next try the process token
282        if (OpenProcessToken(GetCurrentProcess(),
283                        TOKEN_READ,
284                        tokenHandle) == 0) {
285            if (debug) {
286                printf("  [getToken] OpenProcessToken error [%d]: ",
287                        GetLastError());
288                DisplayErrorText(GetLastError());
289            }
290            return FALSE;
291        }
292    }
293
294    if (debug) {
295        printf("  [getToken] got user access token\n");
296    }
297
298    return TRUE;
299}
300
301BOOL getUser(HANDLE tokenHandle, LPTSTR *userName,
302        LPTSTR *domainName, LPTSTR *userSid, LPTSTR *domainSid) {
303
304    BOOL error = FALSE;
305    DWORD bufSize = 0;
306    DWORD buf2Size = 0;
307    DWORD retBufSize = 0;
308    PTOKEN_USER tokenUserInfo = NULL;   // getTokenInformation
309    SID_NAME_USE nameUse;               // LookupAccountSid
310
311    PSID dSid = NULL;
312    LPTSTR domainSidName = NULL;
313
314    // get token information
315    GetTokenInformation(tokenHandle,
316                        TokenUser,
317                        NULL,   // TokenInformation - if NULL get buffer size
318                        0,      // since TokenInformation is NULL
319                        &bufSize);
320
321    tokenUserInfo = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, bufSize);
322    if (GetTokenInformation(tokenHandle,
323                        TokenUser,
324                        tokenUserInfo,
325                        bufSize,
326                        &retBufSize) == 0) {
327        if (debug) {
328            printf("  [getUser] GetTokenInformation error [%d]: ",
329                GetLastError());
330            DisplayErrorText(GetLastError());
331        }
332        error = TRUE;
333        goto cleanup;
334    }
335
336    if (debug) {
337        printf("  [getUser] Got TokenUser info\n");
338    }
339
340    // get userName
341    bufSize = 0;
342    buf2Size = 0;
343    LookupAccountSid(NULL,      // local host
344                tokenUserInfo->User.Sid,
345                NULL,
346                &bufSize,
347                NULL,
348                &buf2Size,
349                &nameUse);
350
351    *userName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize);
352    *domainName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, buf2Size);
353    if (LookupAccountSid(NULL,  // local host
354                tokenUserInfo->User.Sid,
355                *userName,
356                &bufSize,
357                *domainName,
358                &buf2Size,
359                &nameUse) == 0) {
360        if (debug) {
361            printf("  [getUser] LookupAccountSid error [%d]: ",
362                GetLastError());
363            DisplayErrorText(GetLastError());
364        }
365        error = TRUE;
366        goto cleanup;
367    }
368
369    if (debug) {
370        printf("  [getUser] userName: %s, domainName = %s\n",
371                *userName, *domainName);
372    }
373
374    bufSize = 0;
375    getTextualSid(tokenUserInfo->User.Sid, NULL, &bufSize);
376    *userSid = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize);
377    getTextualSid(tokenUserInfo->User.Sid, *userSid, &bufSize);
378    if (debug) {
379        printf("  [getUser] userSid: %s\n", *userSid);
380    }
381
382    // get domainSid
383    bufSize = 0;
384    buf2Size = 0;
385    LookupAccountName(NULL,     // local host
386                *domainName,
387                NULL,
388                &bufSize,
389                NULL,
390                &buf2Size,
391                &nameUse);
392
393    dSid = (PSID)HeapAlloc(GetProcessHeap(), 0, bufSize);
394    domainSidName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, buf2Size);
395    if (LookupAccountName(NULL, // local host
396                *domainName,
397                dSid,
398                &bufSize,
399                domainSidName,
400                &buf2Size,
401                &nameUse) == 0) {
402        if (debug) {
403            printf("  [getUser] LookupAccountName error [%d]: ",
404                GetLastError());
405            DisplayErrorText(GetLastError());
406        }
407        // ok not to have a domain SID (no error)
408        goto cleanup;
409    }
410
411    bufSize = 0;
412    getTextualSid(dSid, NULL, &bufSize);
413    *domainSid = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize);
414    getTextualSid(dSid, *domainSid, &bufSize);
415    if (debug) {
416        printf("  [getUser] domainSid: %s\n", *domainSid);
417    }
418
419cleanup:
420    if (tokenUserInfo != NULL) {
421        HeapFree(GetProcessHeap(), 0, tokenUserInfo);
422    }
423    if (dSid != NULL) {
424        HeapFree(GetProcessHeap(), 0, dSid);
425    }
426    if (domainSidName != NULL) {
427        HeapFree(GetProcessHeap(), 0, domainSidName);
428    }
429    if (error) {
430        return FALSE;
431    }
432    return TRUE;
433}
434
435BOOL getPrimaryGroup(HANDLE tokenHandle, LPTSTR *primaryGroup) {
436
437    BOOL error = FALSE;
438    DWORD bufSize = 0;
439    DWORD retBufSize = 0;
440
441    PTOKEN_PRIMARY_GROUP tokenGroupInfo = NULL;
442
443    // get token information
444    GetTokenInformation(tokenHandle,
445                        TokenPrimaryGroup,
446                        NULL,   // TokenInformation - if NULL get buffer size
447                        0,      // since TokenInformation is NULL
448                        &bufSize);
449
450    tokenGroupInfo = (PTOKEN_PRIMARY_GROUP)HeapAlloc
451                        (GetProcessHeap(), 0, bufSize);
452    if (GetTokenInformation(tokenHandle,
453                        TokenPrimaryGroup,
454                        tokenGroupInfo,
455                        bufSize,
456                        &retBufSize) == 0) {
457        if (debug) {
458            printf("  [getPrimaryGroup] GetTokenInformation error [%d]: ",
459                GetLastError());
460            DisplayErrorText(GetLastError());
461        }
462        error = TRUE;
463        goto cleanup;
464    }
465
466    if (debug) {
467        printf("  [getPrimaryGroup] Got TokenPrimaryGroup info\n");
468    }
469
470    bufSize = 0;
471    getTextualSid(tokenGroupInfo->PrimaryGroup, NULL, &bufSize);
472    *primaryGroup = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize);
473    getTextualSid(tokenGroupInfo->PrimaryGroup, *primaryGroup, &bufSize);
474    if (debug) {
475        printf("  [getPrimaryGroup] primaryGroup: %s\n", *primaryGroup);
476    }
477
478cleanup:
479    if (tokenGroupInfo != NULL) {
480        HeapFree(GetProcessHeap(), 0, tokenGroupInfo);
481    }
482    if (error) {
483        return FALSE;
484    }
485    return TRUE;
486}
487
488BOOL getGroups(HANDLE tokenHandle, PDWORD numGroups, LPTSTR **groups) {
489
490    BOOL error = FALSE;
491    DWORD bufSize = 0;
492    DWORD retBufSize = 0;
493    long i = 0;
494
495    PTOKEN_GROUPS tokenGroupInfo = NULL;
496
497    // get token information
498    GetTokenInformation(tokenHandle,
499                        TokenGroups,
500                        NULL,   // TokenInformation - if NULL get buffer size
501                        0,      // since TokenInformation is NULL
502                        &bufSize);
503
504    tokenGroupInfo = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, bufSize);
505    if (GetTokenInformation(tokenHandle,
506                        TokenGroups,
507                        tokenGroupInfo,
508                        bufSize,
509                        &retBufSize) == 0) {
510        if (debug) {
511            printf("  [getGroups] GetTokenInformation error [%d]: ",
512                GetLastError());
513            DisplayErrorText(GetLastError());
514        }
515        error = TRUE;
516        goto cleanup;
517    }
518
519    if (debug) {
520        printf("  [getGroups] Got TokenGroups info\n");
521    }
522
523    if (tokenGroupInfo->GroupCount == 0) {
524        // no groups
525        goto cleanup;
526    }
527
528    // return group info
529    *numGroups = tokenGroupInfo->GroupCount;
530    *groups = (LPTSTR *)HeapAlloc
531                (GetProcessHeap(), 0, (*numGroups) * sizeof(LPTSTR));
532    for (i = 0; i < (long)*numGroups; i++) {
533        bufSize = 0;
534        getTextualSid(tokenGroupInfo->Groups[i].Sid, NULL, &bufSize);
535        (*groups)[i] = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize);
536        getTextualSid(tokenGroupInfo->Groups[i].Sid, (*groups)[i], &bufSize);
537        if (debug) {
538            printf("  [getGroups] group %d: %s\n", i, (*groups)[i]);
539        }
540    }
541
542cleanup:
543    if (tokenGroupInfo != NULL) {
544        HeapFree(GetProcessHeap(), 0, tokenGroupInfo);
545    }
546    if (error) {
547        return FALSE;
548    }
549    return TRUE;
550}
551
552BOOL getImpersonationToken(PHANDLE impersonationToken) {
553
554    HANDLE dupToken;
555
556    if (OpenThreadToken(GetCurrentThread(),
557                        TOKEN_DUPLICATE,
558                        FALSE,
559                        &dupToken) == 0) {
560        if (OpenProcessToken(GetCurrentProcess(),
561                                TOKEN_DUPLICATE,
562                                &dupToken) == 0) {
563            if (debug) {
564                printf
565                    ("  [getImpersonationToken] OpenProcessToken error [%d]: ",
566                    GetLastError());
567                DisplayErrorText(GetLastError());
568            }
569            return FALSE;
570        }
571    }
572
573    if (DuplicateToken(dupToken,
574                        SecurityImpersonation,
575                        impersonationToken) == 0) {
576        if (debug) {
577            printf("  [getImpersonationToken] DuplicateToken error [%d]: ",
578                GetLastError());
579            DisplayErrorText(GetLastError());
580        }
581        return FALSE;
582    }
583    CloseHandle(dupToken);
584
585    if (debug) {
586        printf("  [getImpersonationToken] token = %p\n",
587            (void *)*impersonationToken);
588    }
589    return TRUE;
590}
591
592BOOL getTextualSid
593    (PSID pSid,                 // binary SID
594    LPTSTR TextualSid,          // buffer for Textual representation of SID
595    LPDWORD lpdwBufferLen) {    // required/provided TextualSid buffersize
596
597    PSID_IDENTIFIER_AUTHORITY psia;
598    DWORD dwSubAuthorities;
599    DWORD dwSidRev=SID_REVISION;
600    DWORD dwCounter;
601    DWORD dwSidSize;
602
603    // Validate the binary SID.
604    if(!IsValidSid(pSid)) return FALSE;
605
606    // Get the identifier authority value from the SID.
607    psia = GetSidIdentifierAuthority(pSid);
608
609    // Get the number of subauthorities in the SID.
610    dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
611
612    // Compute the buffer length.
613    // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
614    dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
615
616    // Check input buffer length.
617    // If too small, indicate the proper size and set last error.
618    if (*lpdwBufferLen < dwSidSize) {
619        *lpdwBufferLen = dwSidSize;
620        SetLastError(ERROR_INSUFFICIENT_BUFFER);
621        return FALSE;
622    }
623
624    // Add 'S' prefix and revision number to the string.
625    dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
626
627    // Add SID identifier authority to the string.
628    if ((psia->Value[0] != 0) || (psia->Value[1] != 0)) {
629        dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
630                TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
631                (USHORT)psia->Value[0],
632                (USHORT)psia->Value[1],
633                (USHORT)psia->Value[2],
634                (USHORT)psia->Value[3],
635                (USHORT)psia->Value[4],
636                (USHORT)psia->Value[5]);
637    } else {
638        dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
639                TEXT("%lu"),
640                (ULONG)(psia->Value[5]  )   +
641                (ULONG)(psia->Value[4] <<  8)   +
642                (ULONG)(psia->Value[3] << 16)   +
643                (ULONG)(psia->Value[2] << 24)   );
644    }
645
646    // Add SID subauthorities to the string.
647    for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++) {
648        dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
649                *GetSidSubAuthority(pSid, dwCounter) );
650    }
651
652    return TRUE;
653}
654
655void DisplayErrorText(DWORD dwLastError) {
656    HMODULE hModule = NULL; // default to system source
657    LPSTR MessageBuffer;
658    DWORD dwBufferLength;
659
660    DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
661                        FORMAT_MESSAGE_IGNORE_INSERTS |
662                        FORMAT_MESSAGE_FROM_SYSTEM ;
663
664    //
665    // If dwLastError is in the network range,
666    //  load the message source.
667    //
668
669    if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
670        hModule = LoadLibraryEx(TEXT("netmsg.dll"),
671                                NULL,
672                                LOAD_LIBRARY_AS_DATAFILE);
673
674        if(hModule != NULL)
675            dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
676    }
677
678    //
679    // Call FormatMessage() to allow for message
680    //  text to be acquired from the system
681    //  or from the supplied module handle.
682    //
683
684    if(dwBufferLength = FormatMessageA(dwFormatFlags,
685                hModule, // module to get message from (NULL == system)
686                dwLastError,
687                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
688                (LPSTR) &MessageBuffer,
689                0,
690                NULL)) {
691        DWORD dwBytesWritten;
692
693        //
694        // Output message string on stderr.
695        //
696        WriteFile(GetStdHandle(STD_ERROR_HANDLE),
697                MessageBuffer,
698                dwBufferLength,
699                &dwBytesWritten,
700                NULL);
701
702        //
703        // Free the buffer allocated by the system.
704        //
705        LocalFree(MessageBuffer);
706    }
707
708    //
709    // If we loaded a message source, unload it.
710    //
711    if(hModule != NULL)
712        FreeLibrary(hModule);
713}
714
715/**
716 * 1. comment out first two #includes
717 * 2. set 'debug' to TRUE
718 * 3. comment out 'getCurrent'
719 * 4. uncomment 'main'
720 * 5. cc -c nt.c
721 * 6. link nt.obj user32.lib advapi32.lib /out:nt.exe
722 */
723/*
724void main(int argc, char *argv[]) {
725
726    long i = 0;
727    HANDLE tokenHandle = INVALID_HANDLE_VALUE;
728
729    LPTSTR userName = NULL;
730    LPTSTR userSid = NULL;
731    LPTSTR domainName = NULL;
732    LPTSTR domainSid = NULL;
733    LPTSTR primaryGroup = NULL;
734    DWORD numGroups = 0;
735    LPTSTR *groups = NULL;
736    HANDLE impersonationToken = 0;
737
738    printf("getting access token\n");
739    if (getToken(&tokenHandle) == FALSE) {
740        exit(1);
741    }
742
743    printf("getting user info\n");
744    if (getUser
745        (tokenHandle, &userName, &domainName, &userSid, &domainSid) == FALSE) {
746        exit(1);
747    }
748
749    printf("getting primary group\n");
750    if (getPrimaryGroup(tokenHandle, &primaryGroup) == FALSE) {
751        exit(1);
752    }
753
754    printf("getting supplementary groups\n");
755    if (getGroups(tokenHandle, &numGroups, &groups) == FALSE) {
756        exit(1);
757    }
758
759    printf("getting impersonation token\n");
760    if (getImpersonationToken(&impersonationToken) == FALSE) {
761        exit(1);
762    }
763
764    printf("userName = %s, userSid = %s, domainName = %s, domainSid = %s\n",
765        userName, userSid, domainName, domainSid);
766    printf("primaryGroup = %s\n", primaryGroup);
767    for (i = 0; i < numGroups; i++) {
768        printf("Group[%d] = %s\n", i, groups[i]);
769    }
770    printf("impersonationToken = %ld\n", impersonationToken);
771
772    if (userName != NULL) {
773        HeapFree(GetProcessHeap(), 0, userName);
774    }
775    if (userSid != NULL) {
776        HeapFree(GetProcessHeap(), 0, userSid);
777    }
778    if (domainName != NULL) {
779        HeapFree(GetProcessHeap(), 0, domainName);
780    }
781    if (domainSid != NULL) {
782        HeapFree(GetProcessHeap(), 0, domainSid);
783    }
784    if (primaryGroup != NULL) {
785        HeapFree(GetProcessHeap(), 0, primaryGroup);
786    }
787    if (groups != NULL) {
788        for (i = 0; i < numGroups; i++) {
789            if (groups[i] != NULL) {
790                HeapFree(GetProcessHeap(), 0, groups[i]);
791            }
792        }
793        HeapFree(GetProcessHeap(), 0, groups);
794    }
795    CloseHandle(impersonationToken);
796    CloseHandle(tokenHandle);
797}
798*/
799
800/**
801 * extra main method for testing debug printing
802 */
803/*
804void main(int argc, char *argv[]) {
805    if(argc != 2) {
806        fprintf(stderr,"Usage: %s <error number>\n", argv[0]);
807    }
808
809    DisplayErrorText(atoi(argv[1]));
810}
811*/
812