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 
  36 static BOOL debug = FALSE;
  37 
  38 BOOL getToken(PHANDLE);
  39 BOOL getUser(HANDLE tokenHandle, LPTSTR *userName,
  40         LPTSTR *domainName, LPTSTR *userSid, LPTSTR *domainSid);
  41 BOOL getPrimaryGroup(HANDLE tokenHandle, LPTSTR *primaryGroup);
  42 BOOL getGroups(HANDLE tokenHandle, PDWORD numGroups, LPTSTR **groups);
  43 BOOL getImpersonationToken(PHANDLE impersonationToken);
  44 BOOL getTextualSid(PSID pSid, LPTSTR TextualSid, LPDWORD lpdwBufferLen);
  45 void DisplayErrorText(DWORD dwLastError);
  46 
  47 static 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  */
  56 DEF_STATIC_JNI_OnLoad
  57 
  58 JNIEXPORT jlong JNICALL
  59 Java_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 
  71 JNIEXPORT void JNICALL
  72 Java_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 
 240 cleanup:
 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 
 269 BOOL 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 
 301 BOOL 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 
 419 cleanup:
 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 
 435 BOOL 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 
 478 cleanup:
 479     if (tokenGroupInfo != NULL) {
 480         HeapFree(GetProcessHeap(), 0, tokenGroupInfo);
 481     }
 482     if (error) {
 483         return FALSE;
 484     }
 485     return TRUE;
 486 }
 487 
 488 BOOL 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 
 542 cleanup:
 543     if (tokenGroupInfo != NULL) {
 544         HeapFree(GetProcessHeap(), 0, tokenGroupInfo);
 545     }
 546     if (error) {
 547         return FALSE;
 548     }
 549     return TRUE;
 550 }
 551 
 552 BOOL 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 
 592 BOOL 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 
 655 void 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 /*
 724 void 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 /*
 804 void 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 */