Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Npgsql.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.DirectoryServices.AccountManagement" />
<Reference Include="System.Transactions" />
<Reference Include="System.Configuration" />
<Reference Include="System.Xml" />
Expand Down
7 changes: 7 additions & 0 deletions src/Npgsql/NpgsqlConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,13 @@ private void LoadConnectionStringBuilder(string connectionString)
cache[connectionString] = settings;
}

// Clone the settings, because if Integrated Security is enabled, user ID can be different
settings = settings.Clone();

// Set the UserName explicitly to freeze any Integrated Security-determined names
if(settings.IntegratedSecurity)
settings.UserName = settings.UserName;

RefreshConnectionString();
LogConnectionString();
}
Expand Down
34 changes: 30 additions & 4 deletions src/Npgsql/NpgsqlConnectionStringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.DirectoryServices.AccountManagement;
using System.Reflection;
using System.Resources;
using System.Text;
Expand Down Expand Up @@ -69,6 +70,7 @@ static NpgsqlConnectionStringBuilder()
defaults.Add(Keywords.PreloadReader, false);
defaults.Add(Keywords.UseExtendedTypes, false);
defaults.Add(Keywords.IntegratedSecurity, false);
defaults.Add(Keywords.IncludeRealm, false);
defaults.Add(Keywords.Compatible, THIS_VERSION);
defaults.Add(Keywords.ApplicationName, string.Empty);
}
Expand Down Expand Up @@ -276,9 +278,17 @@ public string UserName
{
if ((_integrated_security) && (String.IsNullOrEmpty(_username)))
{
System.Security.Principal.WindowsIdentity identity =
System.Security.Principal.WindowsIdentity.GetCurrent();
_username = identity.Name.Split('\\')[1];
string[] usernameParts = UserPrincipal.Current.UserPrincipalName.Split('@');

// With the realm split out, decide whether to add it back
if (_includeRealm)
{
_username = usernameParts[0] + "@" + usernameParts[1].ToUpperInvariant();
}
else
{
_username = usernameParts[0];
}
}
return _username;
}
Expand Down Expand Up @@ -402,6 +412,13 @@ public bool IntegratedSecurity
set { SetValue(GetKeyName(Keywords.IntegratedSecurity), value); }
}

private bool _includeRealm;
public bool IncludeRealm
{
get { return _includeRealm; }
set { SetValue(GetKeyName(Keywords.IncludeRealm), value); }
}

private Version _compatible;

private static readonly Version THIS_VERSION =
Expand Down Expand Up @@ -486,6 +503,8 @@ private static Keywords GetKey(string key)
return Keywords.UseExtendedTypes;
case "INTEGRATED SECURITY":
return Keywords.IntegratedSecurity;
case "INCLUDEREALM":
return Keywords.IncludeRealm;
case "COMPATIBLE":
return Keywords.Compatible;
case "APPLICATIONNAME":
Expand Down Expand Up @@ -543,6 +562,8 @@ internal static string GetKeyName(Keywords keyword)
return "USEEXTENDEDTYPES";
case Keywords.IntegratedSecurity:
return "INTEGRATED SECURITY";
case Keywords.IncludeRealm:
return "INCLUDEREALM";
case Keywords.Compatible:
return "COMPATIBLE";
default:
Expand Down Expand Up @@ -702,6 +723,9 @@ private void SetValue(Keywords keyword, object value)
case Keywords.IntegratedSecurity:
this._integrated_security = ToIntegratedSecurity(value);
break;
case Keywords.IncludeRealm:
this._includeRealm = ToBoolean(value);
break;
case Keywords.Compatible:
Version ver = new Version(value.ToString());
if (ver > THIS_VERSION)
Expand Down Expand Up @@ -731,6 +755,7 @@ private void SetValue(Keywords keyword, object value)
case Keywords.SSL:
case Keywords.Pooling:
case Keywords.SyncNotification:
case Keywords.IncludeRealm:
exception_template = resman.GetString("Exception_InvalidBooleanKeyVal");
break;
case Keywords.Protocol:
Expand Down Expand Up @@ -789,7 +814,8 @@ public enum Keywords
UseExtendedTypes,
IntegratedSecurity,
Compatible,
ApplicationName
ApplicationName,
IncludeRealm
}

public enum SslMode
Expand Down
12 changes: 6 additions & 6 deletions src/Npgsql/NpgsqlPasswordPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,19 @@ public override void WriteToStream(Stream outputStream)
{
case ProtocolVersion.Version2:
// Write the size of the packet.
// 4 + (passwordlength + 1) -> Int32 + NULL terminated string.
// output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(4 + (password.Length + 1))), 0, 4);
// 4 + (passwordlength) -> Int32 + Byte string. Null termination is done before we get here.
// output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(4 + (password.Length))), 0, 4);
outputStream
.WriteInt32(4 + password.Length + 1)
.WriteBytesNullTerminated(password);
.WriteInt32(4 + password.Length)
.WriteBytes(password);

break;

case ProtocolVersion.Version3:
outputStream
.WriteBytes((Byte)ASCIIBytes.p)
.WriteInt32(4 + password.Length + 1)
.WriteBytesNullTerminated(password);
.WriteInt32(4 + password.Length)
.WriteBytes(password);

break;
}
Expand Down
34 changes: 29 additions & 5 deletions src/Npgsql/NpgsqlState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,13 @@ internal bool CheckForContextSocketAvailability (NpgsqlConnector context, Select
return socketPoolResponse || context.Socket.Poll (1000000 * secondsToWait, selectMode);
}

static byte[] NullTerminateArray(byte[] input) {
byte[] output = new byte[input.Length + 1];
input.CopyTo(output, 0);

return output;
}

protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_2(NpgsqlConnector context)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");
Expand Down Expand Up @@ -498,7 +505,7 @@ protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_2(Npgsq
NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
// Send the PasswordPacket.
ChangeState(context, NpgsqlStartupState.Instance);
context.Authenticate(context.Password);
context.Authenticate(NullTerminateArray(context.Password));
break;
case AuthenticationRequestType.AuthenticationMD5Password:
NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
Expand Down Expand Up @@ -547,7 +554,7 @@ protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_2(Npgsq
sb.Append(b.ToString("x2"));
}

context.Authenticate(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString()));
context.Authenticate(NullTerminateArray(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString())));

break;
default:
Expand Down Expand Up @@ -737,7 +744,7 @@ protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_3(Npgsq
// Send the PasswordPacket.

ChangeState(context, NpgsqlStartupState.Instance);
context.Authenticate(context.Password);
context.Authenticate(NullTerminateArray(context.Password));

break;
case AuthenticationRequestType.AuthenticationMD5Password:
Expand Down Expand Up @@ -784,18 +791,35 @@ protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_3(Npgsq
sb.Append(b.ToString("x2"));
}

context.Authenticate(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString()));
context.Authenticate(NullTerminateArray(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString())));

break;
#if WINDOWS && UNMANAGED

case AuthenticationRequestType.AuthenticationGSS:
{
if (context.IntegratedSecurity)
{
// For SSPI we have to get the IP-Address (hostname doesn't work)
context.SSPI = new SSPIHandler(context.Host, "POSTGRES", true);
ChangeState(context, NpgsqlStartupState.Instance);
context.Authenticate(context.SSPI.Continue(null));
break;
}
else
{
// TODO: correct exception
throw new Exception();
}
}

case AuthenticationRequestType.AuthenticationSSPI:
{
if (context.IntegratedSecurity)
{
// For SSPI we have to get the IP-Address (hostname doesn't work)
string ipAddressString = ((IPEndPoint)context.Socket.RemoteEndPoint).Address.ToString();
context.SSPI = new SSPIHandler(ipAddressString, "POSTGRES");
context.SSPI = new SSPIHandler(ipAddressString, "POSTGRES", false);
ChangeState(context, NpgsqlStartupState.Instance);
context.Authenticate(context.SSPI.Continue(null));
break;
Expand Down
4 changes: 2 additions & 2 deletions src/Npgsql/SSPIHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ ref SecHandle phContext
private SecHandle sspictx;
private bool sspictx_set;

public SSPIHandler(string pghost, string krbsrvname)
public SSPIHandler(string pghost, string krbsrvname, bool useGssapi)
{
if (pghost == null)
throw new ArgumentNullException("pghost");
Expand All @@ -129,7 +129,7 @@ public SSPIHandler(string pghost, string krbsrvname)
SecHandle expire;
int status = AcquireCredentialsHandle(
"",
"negotiate",
useGssapi ? "kerberos" : "negotiate",
SECPKG_CRED_OUTBOUND,
IntPtr.Zero,
IntPtr.Zero,
Expand Down