Exemple #1
0
        /// <summary>
        ///  returns the handle for the given credentials.
        ///  The method returns an invalid handle if the username is null or empty.
        /// </summary>
        public static SafeGssCredHandle Create(string username, string password, Interop.NetSecurityNative.PackageType packageType)
        {
            if (packageType == Interop.NetSecurityNative.PackageType.NTLM && !s_IsNtlmInstalled.Value)
            {
                throw new Interop.NetSecurityNative.GssApiException(
                          Interop.NetSecurityNative.Status.GSS_S_BAD_MECH,
                          0,
                          SR.net_gssapi_ntlm_missing_plugin);
            }

            if (string.IsNullOrEmpty(username))
            {
                return(new SafeGssCredHandle());
            }

            SafeGssCredHandle?retHandle = null;

            using (SafeGssNameHandle userHandle = SafeGssNameHandle.CreateUser(username))
            {
                Interop.NetSecurityNative.Status status;
                Interop.NetSecurityNative.Status minorStatus;
                if (string.IsNullOrEmpty(password))
                {
                    status = Interop.NetSecurityNative.InitiateCredSpNego(out minorStatus, userHandle, out retHandle);
                }
                else
                {
                    status = Interop.NetSecurityNative.InitiateCredWithPassword(out minorStatus, packageType, userHandle, password, Encoding.UTF8.GetByteCount(password), out retHandle);
                }

                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    retHandle.Dispose();
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }
            }

            return(retHandle);
        }
Exemple #2
0
        public SafeFreeNegoCredentials(Interop.NetSecurityNative.PackageType packageType, string username, string password, string domain)
            : base(IntPtr.Zero, true)
        {
            Debug.Assert(username != null && password != null, "Username and Password can not be null");
            const char At        = '@';
            const char Backwhack = '\\';

            // any invalid user format will not be manipulated and passed as it is.
            int index = username.IndexOf(Backwhack);

            if (index > 0 && username.IndexOf(Backwhack, index + 1) < 0 && string.IsNullOrEmpty(domain))
            {
                domain   = username.Substring(0, index);
                username = username.Substring(index + 1);
            }

            // remove any leading and trailing whitespace
            if (domain != null)
            {
                domain = domain.Trim();
            }

            username = username.Trim();

            if ((username.IndexOf(At) < 0) && !string.IsNullOrEmpty(domain))
            {
                username += At + domain;
            }

            bool ignore = false;

            _packageType = packageType;
            _userName    = username;
            _isDefault   = string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password);
            _credential  = SafeGssCredHandle.Create(username, password, packageType);
            _credential.DangerousAddRef(ref ignore);
        }
        private static SecurityStatusPal EstablishSecurityContext(
            SafeFreeNegoCredentials credential,
            ref SafeDeleteContext?context,
            ChannelBinding?channelBinding,
            string?targetName,
            ContextFlagsPal inFlags,
            ReadOnlySpan <byte> incomingBlob,
            out byte[]?resultBuffer,
            ref ContextFlagsPal outFlags)
        {
            Interop.NetSecurityNative.PackageType packageType = credential.PackageType;

            resultBuffer = null;

            if (context == null)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    string protocol = packageType switch {
                        Interop.NetSecurityNative.PackageType.NTLM => "NTLM",
                        Interop.NetSecurityNative.PackageType.Kerberos => "Kerberos",
                        _ => "SPNEGO"
                    };
                    NetEventSource.Info(context, $"requested protocol = {protocol}, target = {targetName}");
                }

                context = new SafeDeleteNegoContext(credential, targetName !);
            }

            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);
            Interop.NetSecurityNative.Status    status;
            Interop.NetSecurityNative.Status    minorStatus;
            SafeDeleteNegoContext negoContext   = (SafeDeleteNegoContext)context;
            SafeGssContextHandle  contextHandle = negoContext.GssContext;

            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags =
                    ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false);
                uint outputFlags;
                bool isNtlmUsed;

                if (channelBinding != null)
                {
                    // If a TLS channel binding token (cbt) is available then get the pointer
                    // to the application specific data.
                    int appDataOffset = Marshal.SizeOf <SecChannelBindings>();
                    Debug.Assert(appDataOffset < channelBinding.Size);
                    IntPtr cbtAppData     = channelBinding.DangerousGetHandle() + appDataOffset;
                    int    cbtAppDataSize = channelBinding.Size - appDataOffset;
                    status = Interop.NetSecurityNative.InitSecContext(out minorStatus,
                                                                      credential.GssCredential,
                                                                      ref contextHandle,
                                                                      packageType,
                                                                      cbtAppData,
                                                                      cbtAppDataSize,
                                                                      negoContext.TargetName,
                                                                      (uint)inputFlags,
                                                                      incomingBlob,
                                                                      ref token,
                                                                      out outputFlags,
                                                                      out isNtlmUsed);
                }
                else
                {
                    status = Interop.NetSecurityNative.InitSecContext(out minorStatus,
                                                                      credential.GssCredential,
                                                                      ref contextHandle,
                                                                      packageType,
                                                                      negoContext.TargetName,
                                                                      (uint)inputFlags,
                                                                      incomingBlob,
                                                                      ref token,
                                                                      out outputFlags,
                                                                      out isNtlmUsed);
                }

                if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) &&
                    (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED))
                {
                    if (negoContext.GssContext.IsInvalid)
                    {
                        context.Dispose();
                    }

                    Interop.NetSecurityNative.GssApiException gex = new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(null, gex);
                    }
                    resultBuffer = Array.Empty <byte>();
                    return(new SecurityStatusPal(GetErrorCode(gex), gex));
                }

                resultBuffer = token.ToByteArray();

                if (status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    if (NetEventSource.Log.IsEnabled())
                    {
                        string protocol = packageType switch {
                            Interop.NetSecurityNative.PackageType.NTLM => "NTLM",
                            Interop.NetSecurityNative.PackageType.Kerberos => "Kerberos",
                            _ => isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos"
                        };
                        NetEventSource.Info(context, $"actual protocol = {protocol}");
                    }

                    // Populate protocol used for authentication
                    negoContext.SetAuthenticationPackage(isNtlmUsed);
                }

                Debug.Assert(resultBuffer != null, "Unexpected null buffer returned by GssApi");
                outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(
                    (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false);

                SecurityStatusPalErrorCode errorCode = status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE ?
                                                       SecurityStatusPalErrorCode.OK :
                                                       SecurityStatusPalErrorCode.ContinueNeeded;
                return(new SecurityStatusPal(errorCode));
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(null, ex);
                }
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
            finally
            {
                token.Dispose();

                // Save the inner context handle for further calls to NetSecurity
                //
                // For the first call `negoContext.GssContext` is invalid and we expect the
                // inital handle to be returned from InitSecContext. For any subsequent
                // call the handle should stay the same or it can be destroyed by the native
                // InitSecContext call.
                Debug.Assert(
                    negoContext.GssContext == contextHandle ||
                    negoContext.GssContext.IsInvalid ||
                    contextHandle.IsInvalid);
                negoContext.SetGssContext(contextHandle);
            }
        }