The Question
When calling InitializeSecurityContext
, what value do i pass to the TargetName
parameter?
Revised Background
I'm calling the function InitializeSecurityContext
:
InitializeSecurityContextA(
@pAS.hcred, //[in] credentials
phContext, //[in] optional] Context handle structure
pszTargetName, //[in, optional] Target name
0, //[in] context requirements
0, //[in] reserved1, must be zero
SECURITY_NATIVE_DREP, //[in] target data representation
pInput, //[in] optional] SecBufferDescription
0, //[in] reserved2, must be zero
@pAS.hctxt, //[in, out] pointer to context handle structure
@OutBuffDesc, //[in, out] pointer to SecBufferDesc
ContextAttributes, //[out] context attributes
@lifetime); //[out] expiration timestamp
What do i pass to pszTargetName
?
I've tried
null
: InitializeSecurityContextA(@pAS.hcred, phContext, null, ...);
""
: InitializeSecurityContextA(@pAS.hcred, phContext, "", ...);
"spn/HOSTNAME"
: InitializeSecurityContextA(@pAS.hcred, phContext, "spn/HOSTNAME", ...);
spn/HOSTNAME.DOMAIN.COM
: InitializeSecurityContextA(@pAS.hcred, phContext, "spn/HOSTNAME.DOMAIN.COM", ...);
"cargocult/PROGRAMMING"
: InitializeSecurityContextA(@pAS.hcred, phContext, "cargocult/PROGRAMMING", ...);
"http/TFS.DOMAIN.COM"
: InitializeSecurityContextA(@pAS.hcred, phContext, "http/TFS.DOMAIN.COM", ...);
"http/HOSTNAME"
: InitializeSecurityContextA(@pAS.hcred, phContext, "http/HOSTNAME", ...);
"qwertyasdf"
: InitializeSecurityContextA(@pAS.hcred, phContext, "qwertyasdf", ...);
"AuthSamp"
: InitializeSecurityContextA(@pAS.hcred, phContext, "AuthSamp", ...);
They all either fail, or downgrade to NTLM.
Note: My machine is domain joined, but the domain is not named domain.com
, or even hostname.domain.com
, or even qwertyasdf
. So i'm not surprised that those attempts fail. But people said try things like http/HOSTNAME
, so i put in http/HOSTNAME
.
Background
The InitializeSecurityContext
(Negotiate) function has an optional TargetName
parameter:
pszTargetName [in, optional]
A pointer to a null-terminated string that indicates the service principal name (SPN) or the security context of the destination server.
Applications must supply a valid SPN to help mitigate replay attacks.
What is this supposed to be?
More Background
i am trying to validate a set of user's credentials, e.g.:
Boolean ValidateCredentials(String username, String password, String domain)
{
...
}
Validating a set of user's credentials requires using the SSPI API. The first function to call is InitializeSecurityContext
. One of the parameters to InitializeSecurityContext
is a "TargetName" string.
i've tried leaving it null, but the Application Verifier triggers a breakpoint, writing out the error:
VERIFIER STOP 00005003: pid 0xF08:
InitializeSecurityContext uses NULL target or malformed target for Kerberos service.
Please see pszTargetName for the value of the target.
00000000 : Not used.
00000000 : Not
At this point it would be helpful to remember that the Negotiate
provider will attempt to use Kerberos
, but fallback to NTLM
. In the case of Negotiate
, Kerberos
or NTLM
, the TargetName
parameter is documented to be:
Service principal name (SPN) or the security context of the destination server.
But then what should i pass?
i tried doing what the SSPI Knowledge Base article does, nothing (i.e. pass NULL
):
ss = _InitializeSecurityContext(
&pAS->hcred,
pAS->fInitialized ? &pAS->hctxt : NULL,
NULL, //<-------pszTargetName
0,
0,
SECURITY_NATIVE_DREP,
pAS->fInitialized ? &sbdIn : NULL,
0,
&pAS->hctxt,
&sbdOut,
&fContextAttr,
&tsExpiry);
But nothing (i.e. NULL
) doesn't work.
Note: The KB article was massivly rewritten in 2007. In its original 1999 incarnation they passed "AuthSamp"
as the target, but that also fails.
Bonus Chatter:
service principal name
(SPN) The name by which a client uniquely identifies an instance of a service. If you install multiple instances of a service on computers throughout a forest, each instance must have its own SPN. A given service instance can have multiple SPNs if there are multiple names that clients might use for authentication
security context
The security attributes or rules that are currently in effect. For example, the current user logged on to the computer or the personal identification number entered by the smart card user. For SSPI, a security context is an opaque data structure that contains security data relevant to a connection, such as a session key or an indication of the duration of the session.
Bonus Chatter 2
From the application verifier documentation:
The Verifier plug detects the following errors:
The NTLM package is directly specified in the call to AcquireCredentialsHandle (or higher level wrapper API).
The target name in the call to InitializeSecurityContext is NULL.
The target name in the call to InitializeSecurityContext is not a properly-formed SPN, UPN or NetBIOS-style domain name.
The latter two cases will force Negotiate to fall back to NTLM either directly (the first case) or indirectly (the domain controller will return a “principal not found” error in the second case causing Negotiate to fall back).
The plug-in also logs warnings when it detects downgrades to NTLM; for example, when an SPN is not found by the Domain Controller. These are only logged as warnings since they are often legitimate cases – for example, when authenticating to a system that is not domain-joined.
In my case the domain i am validating against is null
(since i don't know the machine's domain name, or even if there is a domain). But the results are the same if the hard-code my development machine's domain name.
Update 3
Values of pszTargetName that trigger AppVerifier error, but logon succeeds:
null
""
"AuthSamp"
"qwertyasdf"
- *the name of the domain i'm validating against (e.g.
"avatopia.com"
)
- *the name of the domain the machine is joined to (e.g.
"avatopia.com"
)
- *the name of the domain the user account is located in (e.g.
"avatopia.com"
)
Values of pszTargetName that do not trigger an AppVerifier error, but logon fails:
"http/HOSTNAME"
"http/TFS.DOMAIN.COM"
"frob/GROBBER"
"cargocult/PROGRAMMING"
"spn/HOSTNAME"
"spn/HOSTNAME.DOMAIN.COM"
Values of pszTargetname that do not trigger an AppVerifier error, and logon succeeds:
Update 4
What i'm trying to do: figure out if a username/password is valid.
- i have a username: e.g.
"ian"
- i have a password: e.g.
"pass1"
Now there's the further wrinkle that the account ian
could be a local account or a domain account. And you need to decide if ian
is a local or domain account before you can ask. This is because ian
can have two accounts:
ian
on domain stackoverflow.com
ian
on local machine
So i need to specify if i want to:
- ask a particular domain (e.g.
stackoverflow.com
), or
- ask the local machine (which i'll represent as
"."
)
Now we can come up with a cross reference:
Username Password Domain Machine on domain? Validate as
======== ======== ================= ================== ==============
iboyd pass1 . No Local account
iboyd pass1 (empty) No Local account
iboyd pass1 stackoverflow.com No Domain account
iboyd pass1 . Yes Local account
iboyd pass1 (empty) Yes Domain account
iboyd pass1 stackoverflow.com Yes Domain account
Update 5
It might help to explain what i'm trying to do, then maybe how to do it will become easier. Lets say i walk into a random office building downtown, walk into a random cubicle, and type in a random username and password:
i'm going t