BOOL PackageConnectLookup( HANDLE *pLogonHandle, ULONG *pPackageId ) { LSA_STRING Name; NTSTATUS Status; Status = LsaConnectUntrusted( pLogonHandle ); if (!LSA_SUCCESS(Status)) { ShowNTError("LsaConnectUntrusted", Status); return FALSE; } Name.Buffer = MICROSOFT_KERBEROS_NAME_A; Name.Length = (USHORT)strlen(Name.Buffer); Name.MaximumLength = Name.Length + 1; Status = LsaLookupAuthenticationPackage( *pLogonHandle, &Name, pPackageId ); if (!LSA_SUCCESS(Status)) { ShowNTError("LsaLookupAuthenticationPackage", Status); return FALSE; } return TRUE; }
NTSTATUS NTAPI LsaApLogonUserEx (PLSA_CLIENT_REQUEST request, SECURITY_LOGON_TYPE logon_type, PVOID auth, PVOID client_auth_base, ULONG auth_len, PVOID *pbuf, PULONG pbuf_len, PLUID logon_id, PNTSTATUS sub_stat, PLSA_TOKEN_INFORMATION_TYPE tok_type, PVOID *tok, PUNICODE_STRING *account, PUNICODE_STRING *authority, PUNICODE_STRING *machine) { DWORD checksum, i; PDWORD csp, csp_end; NTSTATUS stat; SECPKG_CLIENT_INFO clinf; PLSA_TOKEN_INFORMATION_V2 tokinf; cyglsa_t *authinf = (cyglsa_t *) auth; /* Check if the caller has the SeTcbPrivilege, otherwise refuse service. */ stat = funcs->GetClientInfo (&clinf); if (stat != STATUS_SUCCESS) { cyglsa_printf ("GetClientInfo failed: 0x%08lx\n", stat); return stat; } if (!clinf.HasTcbPrivilege) { cyglsa_printf ("Client has no TCB privilege. Access denied.\n"); return STATUS_ACCESS_DENIED; } /* Make a couple of validity checks. */ if (auth_len < sizeof *authinf || authinf->magic != CYG_LSA_MAGIC || !authinf->username[0] || !authinf->domain[0]) { cyglsa_printf ("Invalid authentication parameter.\n"); return STATUS_INVALID_PARAMETER; } checksum = CYG_LSA_MAGIC; csp = (PDWORD) &authinf->username; csp_end = (PDWORD) ((PBYTE) authinf + auth_len); while (csp < csp_end) checksum += *csp++; if (authinf->checksum != checksum) { cyglsa_printf ("Invalid checksum.\n"); return STATUS_INVALID_PARAMETER_3; } /* Set account to username and authority to domain resp. machine name. The name of the logon account name as returned by LookupAccountSid is created from here as "authority\account". */ authinf->username[UNLEN] = '\0'; authinf->domain[MAX_DOMAIN_NAME_LEN] = '\0'; if (account && !(*account = uni_alloc (authinf->username, wcslen (authinf->username)))) { cyglsa_printf ("No memory trying to create account.\n"); return STATUS_NO_MEMORY; } if (authority && !(*authority = uni_alloc (authinf->domain, wcslen (authinf->domain)))) { cyglsa_printf ("No memory trying to create authority.\n"); return STATUS_NO_MEMORY; } if (machine) { WCHAR mach[MAX_COMPUTERNAME_LENGTH + 1]; DWORD msize = MAX_COMPUTERNAME_LENGTH + 1; if (!GetComputerNameW (mach, &msize)) wcscpy (mach, L"UNKNOWN"); if (!(*machine = uni_alloc (mach, wcslen (mach)))) { cyglsa_printf ("No memory trying to create machine.\n"); return STATUS_NO_MEMORY; } } /* Create a fake buffer in pbuf which is free'd again in the client. Windows 2000 tends to crash when setting this pointer to NULL. */ if (pbuf) { #ifdef JUST_ANOTHER_NONWORKING_SOLUTION cygprf_t prf; WCHAR sam_username[MAX_DOMAIN_NAME_LEN + UNLEN + 2]; SECURITY_STRING sam_user, prefix; PUCHAR user_auth; ULONG user_auth_size; WCHAR flatname[UNLEN + 1]; UNICODE_STRING flatnm; TOKEN_SOURCE ts; HANDLE token; #endif /* JUST_ANOTHER_NONWORKING_SOLUTION */ stat = funcs->AllocateClientBuffer (request, 64UL, pbuf); if (!LSA_SUCCESS (stat)) { cyglsa_printf ("AllocateClientBuffer failed: 0x%08lx\n", stat); return stat; } #ifdef JUST_ANOTHER_NONWORKING_SOLUTION prf.magic_pre = MAGIC_PRE; prf.token = NULL; prf.magic_post = MAGIC_POST; #if 0 /* That's how it was supposed to work according to MSDN... */ wcscpy (sam_username, authinf->domain); wcscat (sam_username, L"\\"); wcscat (sam_username, authinf->username); #else /* That's the only solution which worked, and then it only worked for machine local accounts. No domain authentication possible. STATUS_NO_SUCH_USER galore! */ wcscpy (sam_username, authinf->username); #endif RtlInitUnicodeString (&sam_user, sam_username); RtlInitUnicodeString (&prefix, L""); RtlInitEmptyUnicodeString (&flatnm, flatname, (UNLEN + 1) * sizeof (WCHAR)); stat = funcs->GetAuthDataForUser (&sam_user, SecNameSamCompatible, NULL, &user_auth, &user_auth_size, &flatnm); if (!NT_SUCCESS (stat)) { char sam_u[MAX_DOMAIN_NAME_LEN + UNLEN + 2]; wcstombs (sam_u, sam_user.Buffer, sizeof (sam_u)); cyglsa_printf ("GetAuthDataForUser (%u,%u,%s) failed: 0x%08lx\n", sam_user.Length, sam_user.MaximumLength, sam_u, stat); return stat; } memcpy (ts.SourceName, "Cygwin.1", 8); ts.SourceIdentifier.HighPart = 0; ts.SourceIdentifier.LowPart = 0x0104; RtlInitEmptyUnicodeString (&flatnm, flatname, (UNLEN + 1) * sizeof (WCHAR)); stat = funcs->ConvertAuthDataToToken (user_auth, user_auth_size, SecurityDelegation, &ts, Interactive, *authority, &token, logon_id, &flatnm, sub_stat); if (!NT_SUCCESS (stat)) { cyglsa_printf ("ConvertAuthDataToToken failed: 0x%08lx\n", stat); return stat; } stat = funcs->DuplicateHandle (token, &prf.token); if (!NT_SUCCESS (stat)) { cyglsa_printf ("DuplicateHandle failed: 0x%08lx\n", stat); return stat; } stat = funcs->CopyToClientBuffer (request, sizeof prf, *pbuf, &prf); if (!NT_SUCCESS (stat)) { cyglsa_printf ("CopyToClientBuffer failed: 0x%08lx\n", stat); return stat; } funcs->FreeLsaHeap (user_auth); #endif /* JUST_ANOTHER_NONWORKING_SOLUTION */ } if (pbuf_len) *pbuf_len = 64UL; /* A PLSA_TOKEN_INFORMATION_V2 is allocated in one piece, so... */ #if defined (__x86_64__) || defined (_M_AMD64) { /* ...on 64 bit systems we have to convert the incoming 32 bit offsets into 64 bit pointers. That requires to re-evaluate the size of the outgoing tokinf structure and a somewhat awkward procedure to copy the information over. */ LONG_PTR base; PBYTE tptr; DWORD size, newsize; PSID src_sid; PCYG_TOKEN_GROUPS src_grps; PTOKEN_GROUPS grps; PTOKEN_PRIVILEGES src_privs; PACL src_acl; base = (LONG_PTR) &authinf->inf; newsize = authinf->inf_size; newsize += sizeof (TOKEN_USER) - sizeof (CYG_TOKEN_USER); /* User SID */ newsize += sizeof (PTOKEN_GROUPS) - sizeof (OFFSET); /* Groups */ src_grps = (PCYG_TOKEN_GROUPS) (base + authinf->inf.Groups); newsize += src_grps->GroupCount /* Group SIDs */ * (sizeof (SID_AND_ATTRIBUTES) - sizeof (CYG_SID_AND_ATTRIBUTES)); newsize += sizeof (PSID) - sizeof (OFFSET); /* Primary Group SID */ newsize += sizeof (PTOKEN_PRIVILEGES) - sizeof (OFFSET); /* Privileges */ newsize += 0; /* Owner SID */ newsize += sizeof (PACL) - sizeof (OFFSET); /* Default DACL */ if (!(tokinf = funcs->AllocateLsaHeap (newsize))) return STATUS_NO_MEMORY; tptr = (PBYTE)(tokinf + 1); tokinf->ExpirationTime = authinf->inf.ExpirationTime; /* User SID */ src_sid = (PSID) (base + authinf->inf.User.User.Sid); size = RtlLengthSid (src_sid); RtlCopySid (size, (PSID) tptr, src_sid); tokinf->User.User.Sid = (PSID) tptr; tptr += size; tokinf->User.User.Attributes = authinf->inf.User.User.Attributes; /* Groups */ grps = (PTOKEN_GROUPS) tptr; tokinf->Groups = grps; grps->GroupCount = src_grps->GroupCount; tptr += sizeof grps->GroupCount + grps->GroupCount * sizeof (SID_AND_ATTRIBUTES); /* Group SIDs */ for (i = 0; i < src_grps->GroupCount; ++i) { src_sid = (PSID) (base + src_grps->Groups[i].Sid); size = RtlLengthSid (src_sid); RtlCopySid (size, (PSID) tptr, src_sid); tokinf->Groups->Groups[i].Sid = (PSID) tptr; tptr += size; tokinf->Groups->Groups[i].Attributes = src_grps->Groups[i].Attributes; } /* Primary Group SID */ src_sid = (PSID) (base + authinf->inf.PrimaryGroup.PrimaryGroup); size = RtlLengthSid (src_sid); RtlCopySid (size, (PSID) tptr, src_sid); tokinf->PrimaryGroup.PrimaryGroup = (PSID) tptr; tptr += size; /* Privileges */ src_privs = (PTOKEN_PRIVILEGES) (base + authinf->inf.Privileges); size = sizeof src_privs->PrivilegeCount + src_privs->PrivilegeCount * sizeof (LUID_AND_ATTRIBUTES); memcpy (tptr, src_privs, size); tokinf->Privileges = (PTOKEN_PRIVILEGES) tptr; tptr += size; /* Owner */ tokinf->Owner.Owner = NULL; /* Default DACL */ src_acl = (PACL) (base + authinf->inf.DefaultDacl.DefaultDacl); size = src_acl->AclSize; memcpy (tptr, src_acl, size); tokinf->DefaultDacl.DefaultDacl = (PACL) tptr; } #else { /* ...on 32 bit systems we just allocate tokinf with the same size as we get, copy the whole structure and convert offsets into pointers. */ /* Allocate LUID for usage in the logon SID on Windows 2000. This is not done in the 64 bit code above for hopefully obvious reasons... */ LUID logon_sid_id; if (must_create_logon_sid && !NT_SUCCESS (NtAllocateLocallyUniqueId (&logon_sid_id))) return STATUS_INSUFFICIENT_RESOURCES; if (!(tokinf = funcs->AllocateLsaHeap (authinf->inf_size))) return STATUS_NO_MEMORY; memcpy (tokinf, &authinf->inf, authinf->inf_size); /* User SID */ tokinf->User.User.Sid = (PSID) ((PBYTE) tokinf + (LONG_PTR) tokinf->User.User.Sid); /* Groups */ tokinf->Groups = (PTOKEN_GROUPS) ((PBYTE) tokinf + (LONG_PTR) tokinf->Groups); /* Group SIDs */ for (i = 0; i < tokinf->Groups->GroupCount; ++i) { tokinf->Groups->Groups[i].Sid = (PSID) ((PBYTE) tokinf + (LONG_PTR) tokinf->Groups->Groups[i].Sid); if (must_create_logon_sid && tokinf->Groups->Groups[i].Attributes & SE_GROUP_LOGON_ID && *RtlSubAuthorityCountSid (tokinf->Groups->Groups[i].Sid) == 3 && *RtlSubAuthoritySid (tokinf->Groups->Groups[i].Sid, 0) == SECURITY_LOGON_IDS_RID) { *RtlSubAuthoritySid (tokinf->Groups->Groups[i].Sid, 1) = logon_sid_id.HighPart; *RtlSubAuthoritySid (tokinf->Groups->Groups[i].Sid, 2) = logon_sid_id.LowPart; } } /* Primary Group SID */ tokinf->PrimaryGroup.PrimaryGroup = (PSID) ((PBYTE) tokinf + (LONG_PTR) tokinf->PrimaryGroup.PrimaryGroup); /* Privileges */ tokinf->Privileges = (PTOKEN_PRIVILEGES) ((PBYTE) tokinf + (LONG_PTR) tokinf->Privileges); /* Owner SID */ tokinf->Owner.Owner = NULL; /* Default DACL */ tokinf->DefaultDacl.DefaultDacl = (PACL) ((PBYTE) tokinf + (LONG_PTR) tokinf->DefaultDacl.DefaultDacl); } #endif *tok = (PVOID) tokinf; *tok_type = LsaTokenInformationV2; print_tokinf (tokinf, authinf->inf_size, authinf, &authinf->inf, (PVOID)((LONG_PTR) &authinf->inf + authinf->inf_size)); /* Create logon session. */ stat = NtAllocateLocallyUniqueId (logon_id); if (!NT_SUCCESS (stat)) { funcs->FreeLsaHeap (*tok); *tok = NULL; cyglsa_printf ("NtAllocateLocallyUniqueId status 0x%08lx\n", stat); return STATUS_INSUFFICIENT_RESOURCES; } stat = funcs->CreateLogonSession (logon_id); if (stat != STATUS_SUCCESS) { funcs->FreeLsaHeap (*tok); *tok = NULL; cyglsa_printf ("CreateLogonSession failed: 0x%08lx\n", stat); return stat; } cyglsa_printf ("BINGO!!!\n", stat); return STATUS_SUCCESS; }
/* * Class: sun_security_krb5_Credentials * Method: acquireDefaultNativeCreds * Signature: ()Lsun/security/krb5/Credentials; */ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds( JNIEnv *env, jclass krbcredsClass) { KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL; PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL; PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL; NTSTATUS Status, SubStatus; ULONG requestSize = 0; ULONG responseSize = 0; ULONG rspSize = 0; HANDLE LogonHandle = NULL; ULONG PackageId; jobject ticket, clientPrincipal, targetPrincipal, encryptionKey; jobject ticketFlags, startTime, endTime, krbCreds = NULL; jobject authTime, renewTillTime, hostAddresses = NULL; KERB_EXTERNAL_TICKET *msticket; int ignore_cache = 0; FILETIME Now, EndTime, LocalEndTime; while (TRUE) { if (krbcredsConstructor == 0) { krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>", "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V"); if (krbcredsConstructor == 0) { printf("Couldn't find sun.security.krb5.Credentials constructor\n"); break; } } #ifdef DEBUG printf("Found KrbCreds constructor\n"); #endif // // Get the logon handle and package ID from the // Kerberos package // if (!PackageConnectLookup(&LogonHandle, &PackageId)) break; #ifdef DEBUG printf("Got handle to Kerberos package\n"); #endif /* DEBUG */ // Get the MS TGT from cache CacheRequest.MessageType = KerbRetrieveTicketMessage; CacheRequest.LogonId.LowPart = 0; CacheRequest.LogonId.HighPart = 0; Status = LsaCallAuthenticationPackage( LogonHandle, PackageId, &CacheRequest, sizeof(CacheRequest), &TktCacheResponse, &rspSize, &SubStatus ); #ifdef DEBUG printf("Response size is %d\n", rspSize); #endif if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) { if (!LSA_SUCCESS(Status)) { ShowNTError("LsaCallAuthenticationPackage", Status); } else { ShowNTError("Protocol status", SubStatus); } break; } // got the native MS TGT msticket = &(TktCacheResponse->Ticket); // check TGT validity switch (msticket->SessionKey.KeyType) { case KERB_ETYPE_DES_CBC_CRC: case KERB_ETYPE_DES_CBC_MD5: case KERB_ETYPE_NULL: case KERB_ETYPE_RC4_HMAC_NT: GetSystemTimeAsFileTime(&Now); EndTime.dwLowDateTime = msticket->EndTime.LowPart; EndTime.dwHighDateTime = msticket->EndTime.HighPart; FileTimeToLocalFileTime(&EndTime, &LocalEndTime); if (CompareFileTime(&Now, &LocalEndTime) >= 0) { ignore_cache = 1; } if (msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) { ignore_cache = 1; } break; case KERB_ETYPE_RC4_MD4: default: // not supported ignore_cache = 1; break; } if (ignore_cache) { #ifdef DEBUG printf("MS TGT in cache is invalid/not supported; request new ticket\n"); #endif /* DEBUG */ // use domain to request Ticket Status = ConstructTicketRequest(msticket->TargetDomainName, &pTicketRequest, &requestSize); if (!LSA_SUCCESS(Status)) { ShowNTError("ConstructTicketRequest status", Status); break; } pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage; pTicketRequest->EncryptionType = KERB_ETYPE_DES_CBC_MD5; pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE; Status = LsaCallAuthenticationPackage( LogonHandle, PackageId, pTicketRequest, requestSize, &pTicketResponse, &responseSize, &SubStatus ); #ifdef DEBUG printf("Response size is %d\n", responseSize); #endif /* DEBUG */ if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) { if (!LSA_SUCCESS(Status)) { ShowNTError("LsaCallAuthenticationPackage", Status); } else { ShowNTError("Protocol status", SubStatus); } break; } // got the native MS Kerberos TGT msticket = &(pTicketResponse->Ticket); } /* typedef struct _KERB_RETRIEVE_TKT_RESPONSE { KERB_EXTERNAL_TICKET Ticket; } KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE; typedef struct _KERB_EXTERNAL_TICKET { PKERB_EXTERNAL_NAME ServiceName; PKERB_EXTERNAL_NAME TargetName; PKERB_EXTERNAL_NAME ClientName; UNICODE_STRING DomainName; UNICODE_STRING TargetDomainName; UNICODE_STRING AltTargetDomainName; KERB_CRYPTO_KEY SessionKey; ULONG TicketFlags; ULONG Flags; LARGE_INTEGER KeyExpirationTime; LARGE_INTEGER StartTime; LARGE_INTEGER EndTime; LARGE_INTEGER RenewUntil; LARGE_INTEGER TimeSkew; ULONG EncodedTicketSize; PUCHAR EncodedTicket; <========== Here's the good stuff } KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET; typedef struct _KERB_EXTERNAL_NAME { SHORT NameType; USHORT NameCount; UNICODE_STRING Names[ANYSIZE_ARRAY]; } KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME; typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING; typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING; typedef struct KERB_CRYPTO_KEY { LONG KeyType; ULONG Length; PUCHAR Value; } KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY; */ // Build a com.sun.security.krb5.Ticket ticket = BuildTicket(env, msticket->EncodedTicket, msticket->EncodedTicketSize); if (ticket == NULL) { break; } // OK, have a Ticket, now need to get the client name clientPrincipal = BuildPrincipal(env, msticket->ClientName, msticket->TargetDomainName); // mdu if (clientPrincipal == NULL) { break; } // and the "name" of tgt targetPrincipal = BuildPrincipal(env, msticket->ServiceName, msticket->DomainName); if (targetPrincipal == NULL) { break; } // Get the encryption key encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey)); if (encryptionKey == NULL) { break; } // and the ticket flags ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags)); if (ticketFlags == NULL) { break; } // Get the start time startTime = BuildKerberosTime(env, &(msticket->StartTime)); if (startTime == NULL) { break; } /* * mdu: No point storing the eky expiration time in the auth * time field. Set it to be same as startTime. Looks like * windows does not have post-dated tickets. */ authTime = startTime; // and the end time endTime = BuildKerberosTime(env, &(msticket->EndTime)); if (endTime == NULL) { break; } // Get the renew till time renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil)); if (renewTillTime == NULL) { break; } // and now go build a KrbCreds object krbCreds = (*env)->NewObject( env, krbcredsClass, krbcredsConstructor, ticket, clientPrincipal, targetPrincipal, encryptionKey, ticketFlags, authTime, // mdu startTime, endTime, renewTillTime, //mdu hostAddresses); break; } // end of WHILE // clean up resources if (TktCacheResponse != NULL) { LsaFreeReturnBuffer(TktCacheResponse); } if (pTicketRequest) { LocalFree(pTicketRequest); } if (pTicketResponse != NULL) { LsaFreeReturnBuffer(pTicketResponse); } return krbCreds; }
/* * Class: sun_security_krb5_Credentials * Method: acquireDefaultNativeCreds * Signature: ()Lsun/security/krb5/Credentials; */ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds( JNIEnv *env, jclass krbcredsClass) { HANDLE LogonHandle = NULL; ULONG PackageId; PKERB_RETRIEVE_TKT_REQUEST CacheRequest = NULL; PKERB_RETRIEVE_TKT_RESPONSE CacheResponse = NULL; ULONG rspSize = 0; DWORD errorCode; NTSTATUS Status,SubStatus; PUCHAR pEncodedTicket = NULL; jobject ticket, clientPrincipal, targetPrincipal, encryptionKey; jobject ticketFlags, startTime, endTime, krbCreds = NULL; jobject authTime, renewTillTime, hostAddresses = NULL; UNICODE_STRING Target = {0}; UNICODE_STRING Target2 = {0}; PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL; WCHAR *tgtName = L"krbtgt"; WCHAR *fullName; while (TRUE) { if (krbcredsConstructor == 0) { krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>", "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V"); if (krbcredsConstructor == 0) { printf("Couldn't find com.ibm.security.krb5.Credentials constructor\n"); break; } } //printf("Found KrbCreds constructor\n"); // // Get the logon handle and package ID from the // Kerberos package // if(!PackageConnectLookup(&LogonHandle, &PackageId)) break; #ifdef DEBUG printf("Got handle to Kerberos package\n"); #endif /* DEBUG */ //InitUnicodeString(&Target2, L"krbtgt"); // this doesn't work 'cause I need the domain name too // OK, I don't give up that easily // Go get the current domain name errorCode = DsGetDcName( (LPCTSTR) NULL, // machine name (LPCTSTR) NULL, // DomainName, if NULL, I'm asking what it is (GUID *) NULL, // DomainGuid, (LPCTSTR) NULL, // SiteName, DS_GC_SERVER_REQUIRED, //Flags &DomainControllerInfo); if (errorCode != NO_ERROR) { printf("DsGetDcName returned %d\n", errorCode); break; } #ifdef DEBUG printf("The domain name is %S\n", DomainControllerInfo->DomainName); #endif /* DEBUG */ // Build a fully-qualified name fullName = (WCHAR *) LocalAlloc(LMEM_ZEROINIT,((wcslen(tgtName)+wcslen(L"/")+wcslen(DomainControllerInfo->DomainName)) * sizeof(WCHAR) + sizeof(UNICODE_NULL))); wcscat(fullName, tgtName); wcscat(fullName, L"/"); wcscat(fullName, DomainControllerInfo->DomainName); #ifdef DEBUG printf("The fully-qualified name is %S\n", fullName); #endif /* DEBUG */ InitUnicodeString(&Target2, fullName); CacheRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST)); CacheRequest->MessageType = KerbRetrieveEncodedTicketMessage ; Target.Buffer = (LPWSTR) (CacheRequest + 1); Target.Length = Target2.Length; Target.MaximumLength = Target2.MaximumLength; CopyMemory( Target.Buffer, Target2.Buffer, Target2.Length ); CacheRequest->TargetName = Target; CacheRequest->EncryptionType = KERB_ETYPE_DES_CBC_MD5; // mdu Status = LsaCallAuthenticationPackage( LogonHandle, PackageId, CacheRequest, Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST), (PVOID *) &CacheResponse, &rspSize, &SubStatus ); #ifdef DEBUG printf("Response size is %d\n", rspSize); #endif /* DEBUG */ LocalFree(fullName); if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) { if (!LSA_SUCCESS(Status)) { ShowNTError("LsaCallAuthenticationPackage", Status); } else { ShowNTError("Protocol status", SubStatus); } break; } // Now we need to skip over most of the junk in the buffer to get to the ticket // Here's what we're looking at... /* typedef struct _KERB_RETRIEVE_TKT_RESPONSE { KERB_EXTERNAL_TICKET Ticket; } KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE; typedef struct _KERB_EXTERNAL_TICKET { PKERB_EXTERNAL_NAME ServiceName; PKERB_EXTERNAL_NAME TargetName; PKERB_EXTERNAL_NAME ClientName; UNICODE_STRING DomainName; UNICODE_STRING TargetDomainName; UNICODE_STRING AltTargetDomainName; KERB_CRYPTO_KEY SessionKey; ULONG TicketFlags; ULONG Flags; LARGE_INTEGER KeyExpirationTime; LARGE_INTEGER StartTime; LARGE_INTEGER EndTime; LARGE_INTEGER RenewUntil; LARGE_INTEGER TimeSkew; ULONG EncodedTicketSize; PUCHAR EncodedTicket; <========== Here's the good stuff } KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET; typedef struct _KERB_EXTERNAL_NAME { SHORT NameType; USHORT NameCount; UNICODE_STRING Names[ANYSIZE_ARRAY]; } KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME; typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING; typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING; typedef struct KERB_CRYPTO_KEY { LONG KeyType; ULONG Length; PUCHAR Value; } KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY; */ // Build a com.ibm.security.krb5.Ticket ticket = BuildTicket(env, CacheResponse->Ticket.EncodedTicket, CacheResponse->Ticket.EncodedTicketSize); if (ticket == NULL) { break; } // OK, have a Ticket, now need to get the client name clientPrincipal = BuildClientPrincipal(env, CacheResponse->Ticket.ClientName); // mdu if (clientPrincipal == NULL) break; // and the "name" of tgt targetPrincipal = BuildTGSPrincipal(env, CacheResponse->Ticket.TargetDomainName); // mdu if (targetPrincipal == NULL) break; // Get the encryption key encryptionKey = BuildEncryptionKey(env, &(CacheResponse->Ticket.SessionKey)); if (encryptionKey == NULL) break; // and the ticket flags ticketFlags = BuildTicketFlags(env, &(CacheResponse->Ticket.TicketFlags)); if (ticketFlags == NULL) break; // Get the start time startTime = BuildKerberosTime(env, &(CacheResponse->Ticket.StartTime)); if (startTime == NULL) break; /* * mdu: No point storing the eky expiration time in the auth * time field. Set it to be same as startTime. Looks like * windows does not have post-dated tickets. */ authTime = startTime; // and the end time endTime = BuildKerberosTime(env, &(CacheResponse->Ticket.EndTime)); if (endTime == NULL) break; // Get the renew till time renewTillTime = BuildKerberosTime(env, &(CacheResponse->Ticket.RenewUntil)); if (renewTillTime == NULL) break; // and now go build a KrbCreds object krbCreds = (*env)->NewObject( env, krbcredsClass, krbcredsConstructor, ticket, clientPrincipal, targetPrincipal, encryptionKey, ticketFlags, authTime, // mdu startTime, endTime, renewTillTime, //mdu hostAddresses); break; } // end of WHILE if (DomainControllerInfo != NULL) { NetApiBufferFree(DomainControllerInfo); } if (CacheResponse != NULL) { LsaFreeReturnBuffer(CacheResponse); } if (CacheRequest) { LocalFree(CacheRequest); } return krbCreds; }