PSOpenAD icon indicating copy to clipboard operation
PSOpenAD copied to clipboard

gss_init_sec_context failed - Ticket expired

Open krzydoug opened this issue 10 months ago • 4 comments

Hello Jordan, I'm back. After a certain amount of idle time I came back to show off your awesome module to a colleague and ran into this error.

gss_init_sec_context failed (Major Status 851968 - Unspecified GSS failure.  Minor code may provide m
ore information) (Minor Status 100001 - Ticket expired)

I saw on issue 43 you said PR 45 resolved an issue where the connection timed out. I thought this might be similar. Here is the output of Get-Error

Exception             :
    Type        : PSOpenAD.Native.GSSAPIException
    MajorStatus : 851968
    MinorStatus : 100001
    TargetSite  :
        Name          : InitSecContext
        DeclaringType : PSOpenAD.Native.GSSAPI, PSOpenAD, Version=0.5.0.0, Culture=neutral, PublicKeyToken=null
        MemberType    : Method
        Module        : PSOpenAD.dll
    Message     : gss_init_sec_context failed (Major Status 851968 - Unspecified GSS failure.  Minor code may provide m
ore information) (Minor Status 100001 - Ticket expired)
    Source      : PSOpenAD
    HResult     : -2146233087
    StackTrace  :
   at PSOpenAD.Native.GSSAPI.InitSecContext(SafeGssapiCred cred, SafeGssapiSecContext context, SafeGssapiName targetNam
e, Byte[] mechType, GssapiContextFlags reqFlags, Int32 ttl, ChannelBindings chanBindings, Byte[] inputToken) in /_/src/
PSOpenAD/Native/GSSAPI.cs:line 504
   at PSOpenAD.GssapiContext.Step(Byte[] inputToken) in /_/src/PSOpenAD/Authentication.cs:line 194
   at PSOpenAD.Module.OpenADSessionFactory.SaslAuth(IADConnection connection, SecurityContext context, String saslMech,
 Boolean integrity, Boolean confidentiality, CancellationToken cancelToken) in /_/src/PSOpenAD.Module/OpenADSessionFact
ory.cs:line 487
   at PSOpenAD.Module.OpenADSessionFactory.Authenticate(IADConnection connection, Uri uri, AuthenticationMethod auth, P
SCredential credential, ChannelBindings channelBindings, Boolean transportIsTls, OpenADSessionOptions sessionOptions, C
ancellationToken cancelToken, PSCmdlet cmdlet, Boolean& signed, Boolean& encrypted) in /_/src/PSOpenAD.Module/OpenADSes
sionFactory.cs:line 423
   at PSOpenAD.Module.OpenADSessionFactory.Create(Uri uri, PSCredential credential, AuthenticationMethod auth, Boolean
startTls, OpenADSessionOptions sessionOptions, CancellationToken cancelToken, PSCmdlet cmdlet) in /_/src/PSOpenAD.Modul
e/OpenADSessionFactory.cs:line 151
   at PSOpenAD.Module.OpenADSessionFactory.CreateOrUseDefault(String server, PSCredential credential, AuthenticationMet
hod auth, Boolean startTls, OpenADSessionOptions sessionOptions, CancellationToken cancelToken, PSCmdlet cmdlet, Boolea
n skipCache) in /_/src/PSOpenAD.Module/OpenADSessionFactory.cs:line 84
CategoryInfo          : AuthenticationError: (:) [Get-OpenADComputer], GSSAPIException
FullyQualifiedErrorId : AuthError,PSOpenAD.Module.Commands.GetOpenADComputer
InvocationInfo        :
    MyCommand        : Get-OpenADComputer
    ScriptLineNumber : 1
    OffsetInLine     : 1
    HistoryId        : 1
    Line             : Get-OpenADComputer | ft
    Statement        : Get-OpenADComputer
    PositionMessage  : At line:1 char:1
                       + Get-OpenADComputer | ft
                       + ~~~~~~~~~~~~~~~~~~
    InvocationName   : Get-OpenADComputer
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo :

Restarting powershell did not have any effect. The commands Get/New-OpenADSession received the same error without explicit credentials. I was able to create a session with explicit credentials. The cmdlets still gave the same gss error with or without specifying the server (name/fqdn) but with explicit credentials they work fine. Restarting the ubuntu wsl app and completing shutting down wsl (wsl --shutdown) has not made a difference. My uneducated guess is it seems the anonymous "session" is broken?

krzydoug avatar Mar 28 '24 00:03 krzydoug

GSSAPI (in reality Kerberos here) is very susceptible to time skew but based on the error I can see 2 possible issues

  • The cached Kerberos TGT in the ccache is expired, this is what would have been retrieved through kinit
  • The time on the client differs from the time on the target server or the KDC (which is likely the target server in this scenario)

Based on the error id I would say it's the first problem as I believe the error returned for the latter specifically say clock skew. Running klist can show the expiration time of the TGT

$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: [email protected]

Valid starting     Expires            Service principal
28/03/24 20:36:58  29/03/24 06:36:58  krbtgt/[email protected]
        renew until 29/03/24 20:36:52
28/03/24 20:37:46  29/03/24 06:36:58  ldap/dc01.domain.test@
        renew until 29/03/24 20:36:52
        Ticket server: ldap/[email protected]

The krbtgt/* ticket is the TGT ticket retrieved by kinit and is used to get the subsequent service tickets. The ldap/* ticket is the service ticket specifically for the LDAP host that is retrieved through the TGT. If there is no service ticket for the host then gss_init_sec_context is going to use your TGT to get that service ticket. If either are expired I would expect this error, personally I would expect if the service ticket is expired it would automatically retrieve a new one but I've never tested that assertion.

jborean93 avatar Mar 28 '24 00:03 jborean93

OK I'm thinking maybe I'm confused about how it should work. After successfully querying with

$cred = Get-Credential domainuser
Get-OpenADComputer -Server dc01.domain.com -Credential $cred

Then the following commands work

Get-OpenADComputer -Server dc01 -AuthType Anonymous
Get-OpenADComputer -Server dc01
Get-OpenADComputer -Server dc01.domain.com -AuthType Anonymous
Get-OpenADComputer -Server dc01.domain.com

When querying another dc, I got this error

Get-OpenADComputer: Operations error - 000004DC: LdapErr: DSID-0C090ACD, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4563

Interestingly, this command succeeded

Get-OpenADComputer -Server dc02.domain.com -Credential $cred

While this one does not

Get-OpenADComputer -Server dc02 -Credential $cred

Afterwards these work

Get-OpenADComputer -Server dc02.domain.com
Get-OpenADComputer -Server dc02.domain.com -AuthType Anonymous

while these end with the same bind must be completed error

Get-OpenADComputer -Server dc02 -AuthType Anonymous
Get-OpenADComputer -Server dc02 -Credential $cred
Get-OpenADComputer -Server dc02

What makes the short/fqdn work with dc01 but not allow the short name to work with dc02? If it matters, currently all FSMO roles are held by dc02.

krzydoug avatar Mar 28 '24 00:03 krzydoug

The time on the client and server are just a few seconds off, so should be good there. (I also assume the kdc is the same as the target server, but both dcs time are practically the same)

image image

Here is the output of klist, and it does show expired.

PS /home/doug> klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: [email protected]

Valid starting     Expires            Service principal
03/26/24 16:45:11  03/27/24 02:45:11  krbtgt/[email protected]
        renew until 03/27/24 16:45:07
03/26/24 20:12:59  03/27/24 02:45:11  ldap/[email protected]
        renew until 03/27/24 16:45:07

If connecting back with a session/explicit credentials doesn't refresh this ticket and it doesn't refresh automatically, how can I manually refresh it? I assume you desire this to work when picked back up like the AD module does? I'm pretty sure I've seen the ad cmdlets after a certain amount of time have to start up the AD psdrive. Is there some similar functionality we can add to make this easier for noobs like me. :)

BTW I have to say, your quick responses and extreme willingness to share your knowledge across many platforms is very much appreciated.

krzydoug avatar Mar 28 '24 00:03 krzydoug

If connecting back with a session/explicit credentials doesn't refresh this ticket and it doesn't refresh automatically, how can I manually refresh it?

If the TGT ticket (krbtgt) is expired then there's not much I can do AFAIK. It requires the caller to either provide explicit credentials or run kinit again to get a new TGT. If the service ticket is expired I would have hoped GSSAPI would be automatically ignoring it and getting a new one. I'll definitely have to test out this scenario a bit more to see what's happening and what I could potentially do to improve the scenario. As for cleaning existing sessions you should be able to do Get-OpenADSession | Remove-OpenADSession to get and clear all existing sessions.

I definitely need to look into the whole session setup part a bit more. It's been a while since I've last checked how it works and how the module selects the session to use if one wasn't explicitly provided. There's definitely some more work that needs to be done there on the module side.

BTW I have to say, your quick responses and extreme willingness to share your knowledge across many platforms is very much appreciated.

Thanks, it definitely can be a bit hairy especially when it comes to Kerberos. I can also sometimes assume people have knowledge about some things here so it's nice when those assumptions are challenged. It might be information overload but if you start pwsh like KRB5_TRACE=/dev/stdout pwsh you'll also see verbose logging from the Kerberos library. You can set it to any path if you don't want to see it on the console.

jborean93 avatar Mar 28 '24 01:03 jborean93