/// <summary> /// It is called when SQL batch request arrives /// </summary> public virtual TDSMessageCollection OnSQLBatchRequest(ITDSServerSession session, TDSMessage message) { // Delegate to the query engine TDSMessageCollection responseMessage = Engine.ExecuteBatch(session, message); // Check if session packet size is different than the engine packet size if (session.PacketSize != Arguments.PacketSize) { // Get the first message TDSMessage firstMessage = responseMessage[0]; // Find DONE token in it int indexOfDone = firstMessage.IndexOf(firstMessage.Where(t => t is TDSDoneToken).First()); // Create new packet size environment change token TDSEnvChangeToken envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.PacketSize, Arguments.PacketSize.ToString(), session.PacketSize.ToString()); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Insert env change before done token firstMessage.Insert(indexOfDone, envChange); // Update session with the new packet size session.PacketSize = (uint)Arguments.PacketSize; } return(responseMessage); }
/// <summary> /// Handler for pre-login request /// </summary> public override TDSMessageCollection OnPreLoginRequest(ITDSServerSession session, TDSMessage request) { // Delegate to the base class TDSMessageCollection response = base.OnPreLoginRequest(session, request); // Check if arguments are of the routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments serverArguments = Arguments as RoutingTDSServerArguments; // Check if routing is configured during login if (serverArguments.RouteOnPacket == TDSMessageType.TDS7Login) { // Check if pre-login response is contained inside the first message if (response.Count > 0 && response[0].Any(t => t is TDSPreLoginToken)) { // Find the first prelogin token TDSPreLoginToken preLoginResponse = (TDSPreLoginToken)response[0].Where(t => t is TDSPreLoginToken).First(); // Inflate pre-login request from the message TDSPreLoginToken preLoginRequest = request[0] as TDSPreLoginToken; // Update MARS with the requested value preLoginResponse.IsMARS = preLoginRequest.IsMARS; } } } return(response); }
/// <summary> /// Handler for pre-login request /// </summary> public override TDSMessageCollection OnPreLoginRequest(ITDSServerSession session, TDSMessage request) { // Delegate to the base class TDSMessageCollection response = base.OnPreLoginRequest(session, request); // Check if arguments are of the routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments serverArguments = Arguments as RoutingTDSServerArguments; // Check if routing is configured during login if (serverArguments.RouteOnPacket == TDSMessageType.TDS7Login) { // Check if pre-login response is contained inside the first message if (response.Count > 0 && response[0].Any(t => t is TDSPreLoginToken)) { // Find the first prelogin token TDSPreLoginToken preLoginResponse = (TDSPreLoginToken)response[0].Where(t => t is TDSPreLoginToken).First(); // Inflate pre-login request from the message TDSPreLoginToken preLoginRequest = request[0] as TDSPreLoginToken; // Update MARS with the requested value preLoginResponse.IsMARS = preLoginRequest.IsMARS; } } } return response; }
public virtual TDSMessageCollection OnFederatedAuthenticationTokenMessage(ITDSServerSession session, TDSMessage message) { // Get the FedAuthToken TDSFedAuthToken fedauthToken = message[0] as TDSFedAuthToken; // Log TDSUtilities.Log(Arguments.Log, "Request", fedauthToken); return(OnFederatedAuthenticationCompleted(session, fedauthToken.Token)); }
/// <summary> /// Handler for SSPI request /// </summary> public virtual TDSMessageCollection OnSSPIRequest(ITDSServerSession session, TDSMessage request) { // Get the SSPI token TDSSSPIClientToken sspiRequest = request[0] as TDSSSPIClientToken; // Log request TDSUtilities.Log(Arguments.Log, "Request", sspiRequest.Payload); // Delegate to SSPI routine return(ContinueSSPIAuthentication(session, sspiRequest.Payload)); }
protected override TDSMessageCollection CreateQueryResponse(ITDSServerSession session, TDSSQLBatchToken batchRequest) { string lowerBatchText = batchRequest.Text.ToLowerInvariant().Trim(); var result = TryGet(lowerBatchText, null); if (null != result) { List <TDSPacketToken> tokens = new List <TDSPacketToken>(); TDSColMetadataToken metadataToken = new TDSColMetadataToken(); tokens.Add(metadataToken); if (String.IsNullOrWhiteSpace(result.Table)) { TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.IntN; column.DataTypeSpecific = (byte)4; column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; column.Flags.IsComputed = true; column.Flags.IsNullable = true; // TODO: Must be nullable, otherwise something is wrong with SqlClient // Add a column to the response metadataToken.Columns.Add(column); TDSRowToken rowToken = new TDSRowToken(metadataToken); rowToken.Data.Add(result.Scalar); tokens.Add(rowToken); TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); tokens.Add(doneToken); } else { tokens.AddRange(ReturnTable(result)); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken( TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, (ulong)result.GetRecords().Count()); tokens.Add(doneToken); } return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, tokens.ToArray()))); } else { PrintMissignQuery(lowerBatchText, null); } return(base.CreateQueryResponse(session, batchRequest)); }
/// <summary> /// Ensure that federated authentication option is valid /// </summary> protected virtual TDSMessageCollection CheckFederatedAuthenticationOption(ITDSServerSession session, TDSLogin7FedAuthOptionToken federatedAuthenticationOption) { // Check if server's prelogin response for FedAuthRequired prelogin option is echoed back correctly in FedAuth Feature Extenion Echo if (federatedAuthenticationOption.Echo != (session as GenericTDSServerSession).FedAuthRequiredPreLoginServerResponse) { // Create Error message string message = string.Format("FEDAUTHREQUIRED option in the prelogin response is not echoed back correctly: in prelogin response, it is {0} and in login, it is {1}: ", (session as GenericTDSServerSession).FedAuthRequiredPreLoginServerResponse, federatedAuthenticationOption.Echo); // Create errorToken token TDSErrorToken errorToken = new TDSErrorToken(3456, 34, 23, message); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Build a collection with a single message of two tokens return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken))); } // Check if the nonce exists if ((federatedAuthenticationOption.Nonce == null && federatedAuthenticationOption.Library == TDSFedAuthLibraryType.IDCRL) || !AreEqual((session as GenericTDSServerSession).ServerNonce, federatedAuthenticationOption.Nonce)) { // Error message string message = string.Format("Unexpected NONCEOPT specified in the Federated authentication feature extension"); // Create errorToken token TDSErrorToken errorToken = new TDSErrorToken(5672, 32, 87, message); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Build a collection with a single message of two tokens return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken))); } // We're good return(null); }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Check if arguments are of the routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments ServerArguments = Arguments as RoutingTDSServerArguments; // Check filter if (ServerArguments.RequireReadOnly && (loginRequest.TypeFlags.ReadOnlyIntent != TDSLogin7TypeFlagsReadOnlyIntent.ReadOnly)) { // Log request TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application intent: " + loginRequest.TypeFlags.ReadOnlyIntent.ToString(), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Read-Only application intent is required for routing", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return a single message in the collection return(new TDSMessageCollection(responseMessage)); } } // Delegate to the base class return(base.OnLogin7Request(session, request)); }
/// <summary> /// Handler for pre-login request /// </summary> public virtual TDSMessageCollection OnPreLoginRequest(ITDSServerSession session, TDSMessage request) { // Inflate pre-login request from the message TDSPreLoginToken preLoginRequest = request[0] as TDSPreLoginToken; // Log request TDSUtilities.Log(Arguments.Log, "Request", preLoginRequest); // Generate server response for encryption TDSPreLoginTokenEncryptionType serverResponse = TDSUtilities.GetEncryptionResponse(preLoginRequest.Encryption, Arguments.Encryption); // Update client state with encryption resolution session.Encryption = TDSUtilities.ResolveEncryption(preLoginRequest.Encryption, serverResponse); // Create TDS prelogin packet TDSPreLoginToken preLoginToken = new TDSPreLoginToken(Arguments.ServerVersion, serverResponse, false); // TDS server doesn't support MARS // Cache the recieved Nonce into the session (session as GenericTDSServerSession).ClientNonce = preLoginRequest.Nonce; // Check if the server has been started up as requiring FedAuth when choosing between SSPI and FedAuth if (Arguments.FedAuthRequiredPreLoginOption == TdsPreLoginFedAuthRequiredOption.FedAuthRequired) { if (preLoginRequest.FedAuthRequired == TdsPreLoginFedAuthRequiredOption.FedAuthRequired) { // Set the FedAuthRequired option preLoginToken.FedAuthRequired = TdsPreLoginFedAuthRequiredOption.FedAuthRequired; } // Keep the federated authentication required flag in the server session (session as GenericTDSServerSession).FedAuthRequiredPreLoginServerResponse = preLoginToken.FedAuthRequired; if (preLoginRequest.Nonce != null) { // Generate Server Nonce preLoginToken.Nonce = _GenerateRandomBytes(32); } } // Cache the server Nonce in a session (session as GenericTDSServerSession).ServerNonce = preLoginToken.Nonce; // Log response TDSUtilities.Log(Arguments.Log, "Response", preLoginToken); // Reset authentication information session.SQLUserID = null; session.NTUserAuthenticationContext = null; // Respond with a single message that contains only one token return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, preLoginToken))); }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Check if arguments are of the routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments ServerArguments = Arguments as RoutingTDSServerArguments; // Check filter if (ServerArguments.RequireReadOnly && (loginRequest.TypeFlags.ReadOnlyIntent != TDSLogin7TypeFlagsReadOnlyIntent.ReadOnly)) { // Log request TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application intent: " + loginRequest.TypeFlags.ReadOnlyIntent.ToString(), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Read-Only application intent is required for routing", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return a single message in the collection return new TDSMessageCollection(responseMessage); } } // Delegate to the base class return base.OnLogin7Request(session, request); }
/// <summary> /// Server TDS parser initialization constructor /// </summary> public TDSServerParser(ITDSServer server, ITDSServerSession session, Stream stream) : base(stream) { // Save TDS server Server = server; // Save session Session = session; // Configure TDS server Transport.PacketSize = session.PacketSize; Transport.OutgoingSessionID = (ushort)session.SessionID; }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Get the collection from the normal behavior On Login7 Request TDSMessageCollection login7Collection = base.OnLogin7Request(session, request); // Check if arguments are of the Federated Authentication server if (Arguments is FederatedAuthenticationNegativeTDSServerArguments) { // Cast to federated authentication server arguments FederatedAuthenticationNegativeTDSServerArguments ServerArguments = Arguments as FederatedAuthenticationNegativeTDSServerArguments; // Get the Federated Authentication ExtAck from Login 7 TDSFeatureExtAckFederatedAuthenticationOption fedAutExtAct = GetFeatureExtAckFederatedAuthenticationOptionFromLogin7(login7Collection); // If not found, return the base collection intact if (fedAutExtAct != null) { switch (ServerArguments.Scenario) { case FederatedAuthenticationNegativeTDSScenarioType.NonceMissingInFedAuthFEATUREXTACK: { // Delete the nonce from the Token fedAutExtAct.ClientNonce = null; break; } case FederatedAuthenticationNegativeTDSScenarioType.FedAuthMissingInFEATUREEXTACK: { // Remove the Fed Auth Ext Ack from the options list in the FeatureExtAckToken GetFeatureExtAckTokenFromLogin7(login7Collection).Options.Remove(fedAutExtAct); break; } case FederatedAuthenticationNegativeTDSScenarioType.SignatureMissingInFedAuthFEATUREXTACK: { // Delete the signature from the Token fedAutExtAct.Signature = null; break; } } } } // Return the collection return(login7Collection); }
protected override TDSMessageCollection CreateQueryResponse(ITDSServerSession session, TDSSQLBatchToken batchRequest) { string lowerBatchText = batchRequest.Text.ToLowerInvariant(); if (lowerBatchText.Contains("1 / 0")) // SELECT 1/0 { TDSErrorToken errorToken = new TDSErrorToken(8134, 1, 1, "Divide by zero error encountered."); TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); return(new TDSMessageCollection(responseMessage)); } else { return(base.CreateQueryResponse(session, batchRequest)); } }
/// <summary> /// It is called when SQL batch request arrives /// </summary> /// <param name="message">TDS message recieved</param> /// <returns>TDS message to respond with</returns> public override TDSMessageCollection OnSQLBatchRequest(ITDSServerSession session, TDSMessage request) { // Delegate to the base class to produce the response first TDSMessageCollection batchResponse = base.OnSQLBatchRequest(session, request); // Check if arguments are of routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments ServerArguments = Arguments as RoutingTDSServerArguments; // Check routing condition if (ServerArguments.RouteOnPacket == TDSMessageType.SQLBatch) { // Construct routing token TDSPacketToken routingToken = CreateRoutingToken(); // Log response TDSUtilities.Log(Arguments.Log, "Response", routingToken); // Insert the routing token at the beginning of the response batchResponse[0].Insert(0, routingToken); } else { // Get the first response message TDSMessage responseMessage = batchResponse[0]; // Reset the content of the first message responseMessage.Clear(); // Prepare ERROR token with the denial details responseMessage.Add(new TDSErrorToken(11111, 1, 14, "Client should have been routed by now", Arguments.ServerName)); // Log response TDSUtilities.Log(Arguments.Log, "Response", responseMessage[0]); // Prepare DONE token responseMessage.Add(new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error)); // Log response TDSUtilities.Log(Arguments.Log, "Response", responseMessage[1]); } } // Register only one message with the collection return(batchResponse); }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Get the collection from the normal behavior On Login7 Request TDSMessageCollection login7Collection = base.OnLogin7Request(session, request); // Check if arguments are of the Federated Authentication server if (Arguments is FederatedAuthenticationNegativeTDSServerArguments) { // Cast to federated authentication server arguments FederatedAuthenticationNegativeTDSServerArguments ServerArguments = Arguments as FederatedAuthenticationNegativeTDSServerArguments; // Get the Federated Authentication ExtAck from Login 7 TDSFeatureExtAckFederatedAuthenticationOption fedAutExtAct = GetFeatureExtAckFederatedAuthenticationOptionFromLogin7(login7Collection); // If not found, return the base collection intact if (fedAutExtAct != null) { switch (ServerArguments.Scenario) { case FederatedAuthenticationNegativeTDSScenarioType.NonceMissingInFedAuthFEATUREXTACK: { // Delete the nonce from the Token fedAutExtAct.ClientNonce = null; break; } case FederatedAuthenticationNegativeTDSScenarioType.FedAuthMissingInFEATUREEXTACK: { // Remove the Fed Auth Ext Ack from the options list in the FeatureExtAckToken GetFeatureExtAckTokenFromLogin7(login7Collection).Options.Remove(fedAutExtAct); break; } case FederatedAuthenticationNegativeTDSScenarioType.SignatureMissingInFedAuthFEATUREXTACK: { // Delete the signature from the Token fedAutExtAct.Signature = null; break; } } } } // Return the collection return login7Collection; }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnPreLoginRequest(ITDSServerSession session, TDSMessage request) { // Get the collection from a valid On PreLogin Request TDSMessageCollection preLoginCollection = base.OnPreLoginRequest(session, request); // Check if arguments are of the Federated Authentication server if (Arguments is FederatedAuthenticationNegativeTDSServerArguments) { // Cast to federated authentication server arguments FederatedAuthenticationNegativeTDSServerArguments ServerArguments = Arguments as FederatedAuthenticationNegativeTDSServerArguments; // Find the is token carrying on TDSPreLoginToken TDSPreLoginToken preLoginToken = preLoginCollection.Find(message => message.Exists(packetToken => packetToken is TDSPreLoginToken)). Find(packetToken => packetToken is TDSPreLoginToken) as TDSPreLoginToken; switch (ServerArguments.Scenario) { case FederatedAuthenticationNegativeTDSScenarioType.NonceMissingInFedAuthPreLogin: { // If we have the prelogin token if (preLoginToken != null && preLoginToken.Nonce != null) { // Nullify the nonce from the Token preLoginToken.Nonce = null; } break; } case FederatedAuthenticationNegativeTDSScenarioType.InvalidB_FEDAUTHREQUIREDResponse: { // If we have the prelogin token if (preLoginToken != null) { // Set an illegal value for B_FEDAUTHREQURED preLoginToken.FedAuthRequired = TdsPreLoginFedAuthRequiredOption.Illegal; } break; } } } // Return the collection return(preLoginCollection); }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnPreLoginRequest(ITDSServerSession session, TDSMessage request) { // Get the collection from a valid On PreLogin Request TDSMessageCollection preLoginCollection = base.OnPreLoginRequest(session, request); // Check if arguments are of the Federated Authentication server if (Arguments is FederatedAuthenticationNegativeTDSServerArguments) { // Cast to federated authentication server arguments FederatedAuthenticationNegativeTDSServerArguments ServerArguments = Arguments as FederatedAuthenticationNegativeTDSServerArguments; // Find the is token carrying on TDSPreLoginToken TDSPreLoginToken preLoginToken = preLoginCollection.Find(message => message.Exists(packetToken => packetToken is TDSPreLoginToken)). Find(packetToken => packetToken is TDSPreLoginToken) as TDSPreLoginToken; switch (ServerArguments.Scenario) { case FederatedAuthenticationNegativeTDSScenarioType.NonceMissingInFedAuthPreLogin: { // If we have the prelogin token if (preLoginToken != null && preLoginToken.Nonce != null) { // Nullify the nonce from the Token preLoginToken.Nonce = null; } break; } case FederatedAuthenticationNegativeTDSScenarioType.InvalidB_FEDAUTHREQUIREDResponse: { // If we have the prelogin token if (preLoginToken != null) { // Set an illegal value for B_FEDAUTHREQURED preLoginToken.FedAuthRequired = TdsPreLoginFedAuthRequiredOption.Illegal; } break; } } } // Return the collection return preLoginCollection; }
/// <summary> /// Complete login sequence /// </summary> protected override TDSMessageCollection OnAuthenticationCompleted(ITDSServerSession session) { // Delegate to the base class TDSMessageCollection responseMessageCollection = base.OnAuthenticationCompleted(session); // Check if arguments are of routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments serverArguments = Arguments as RoutingTDSServerArguments; // Check routing condition if (serverArguments.RouteOnPacket == TDSMessageType.TDS7Login) { // Construct routing token TDSPacketToken routingToken = CreateRoutingToken(); // Log response TDSUtilities.Log(Arguments.Log, "Response", routingToken); // Get the first message TDSMessage targetMessage = responseMessageCollection[0]; // Index at which to insert the routing token int insertIndex = targetMessage.Count - 1; // VSTS# 1021027 - Read-Only Routing yields TDS protocol error // Resolution: Send TDS FeatureExtAct token before TDS ENVCHANGE token with routing information TDSPacketToken featureExtAckToken = targetMessage.Find(t => t is TDSFeatureExtAckToken); // Check if found if (featureExtAckToken != null) { // Find token position insertIndex = targetMessage.IndexOf(featureExtAckToken); } // Insert right before the done token targetMessage.Insert(insertIndex, routingToken); } } return(responseMessageCollection); }
protected virtual TDSMessageCollection OnFederatedAuthenticationInfoRequest(ITDSServerSession session) { TDSFedAuthInfoToken infoToken = new TDSFedAuthInfoToken(); // Make fake info options TDSFedAuthInfoOptionSPN spn = new TDSFedAuthInfoOptionSPN(Arguments.ServerPrincipalName); TDSFedAuthInfoOptionSTSURL stsurl = new TDSFedAuthInfoOptionSTSURL(Arguments.StsUrl); infoToken.Options.Add(0, spn); infoToken.Options.Add(1, stsurl); // Log response TDSUtilities.Log(Arguments.Log, "Response", spn); TDSUtilities.Log(Arguments.Log, "Response", stsurl); TDSMessage infoMessage = new TDSMessage(TDSMessageType.FederatedAuthenticationInfo, infoToken); return(new TDSMessageCollection(infoMessage)); }
/// <summary> /// Checks the TDS version /// </summary> /// <param name="session">Server session</param> /// <returns>Null if the TDS version is supported, errorToken message otherwise</returns> protected virtual TDSMessageCollection CheckTDSVersion(ITDSServerSession session) { // Check if version is supported if (TDSVersion.IsSupported(session.TDSVersion)) { return(null); } // Prepare ERROR token TDSErrorToken errorToken = new TDSErrorToken(12345, 1, 16, "Unsupported TDS client version", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Wrap with message collection return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken))); }
/// <summary> /// Prepare response for server instance name query /// </summary> private TDSMessage _PrepareInstanceNameResponse(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Start first column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.DataTypeSpecific = new TDSShilohVarCharColumnSpecific(256, new TDSColumnDataCollation(13632521, 52)); column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Start with server name string value = ServerArguments.ServerName; // Check if server name contains a slash if (value.Contains("\\")) { // Take everything after the slash value = value.Substring(value.IndexOf('\\') + 1); } else { // Instance is unnamed value = null; } // Add row rowToken.Data.Add(value); // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }
protected virtual TDSMessageCollection OnAuthenticationCompleted(ITDSServerSession session) { // Create new database environment change token TDSEnvChangeToken envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.Database, session.Database, "master"); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, envChange); // Create information token on the change TDSInfoToken infoToken = new TDSInfoToken(5701, 2, 0, string.Format("Changed database context to '{0}'", envChange.NewValue), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", infoToken); // Serialize the login token into the response packet responseMessage.Add(infoToken); // Create new collation change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.SQLCollation, (session as GenericTDSServerSession).Collation); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Create new language change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.Language, LanguageString.ToString((session as GenericTDSServerSession).Language)); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Create information token on the change infoToken = new TDSInfoToken(5703, 1, 0, string.Format("Changed language setting to {0}", envChange.NewValue), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", infoToken); // Serialize the login token into the response packet responseMessage.Add(infoToken); // Create new packet size environment change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.PacketSize, Arguments.PacketSize.ToString(), Arguments.PacketSize.ToString()); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Update session packet size session.PacketSize = (uint)Arguments.PacketSize; // Create login acknowledgement packet TDSLoginAckToken loginResponseToken = new TDSLoginAckToken(Arguments.ServerVersion, session.TDSVersion, TDSLogin7TypeFlagsSQL.SQL, "Microsoft SQL Server"); // Otherwise SNAC yields E_FAIL // Log response TDSUtilities.Log(Arguments.Log, "Response", loginResponseToken); // Serialize the login token into the response packet responseMessage.Add(loginResponseToken); // Check if session recovery is enabled if (session.IsSessionRecoveryEnabled) { // Create Feature extension Ack token TDSFeatureExtAckToken featureExtActToken = new TDSFeatureExtAckToken(new TDSFeatureExtAckSessionStateOption((session as GenericTDSServerSession).Deflate())); // Log response TDSUtilities.Log(Arguments.Log, "Response", featureExtActToken); // Serialize feature extnesion token into the response responseMessage.Add(featureExtActToken); } // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Wrap a single message in a collection return(new TDSMessageCollection(responseMessage)); }
/// <summary> /// It is called when attention arrives /// </summary> public virtual TDSMessageCollection OnAttention(ITDSServerSession session, TDSMessage message) { // Delegate into the query engine return(Engine.ExecuteAttention(session, message)); }
/// <summary> /// Prepare response for query whether this is a SQL Azure instance /// </summary> private TDSMessage _PrepareIsAzure(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Start a new column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.IntN; column.DataTypeSpecific = (byte)4; column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; column.Flags.IsComputed = true; column.Flags.IsNullable = true; // TODO: Must be nullable, otherwise something is wrong with SqlClient // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Per http://msdn.microsoft.com/en-us/library/ms174396.aspx // 4 = Express (This is returned for Express, Express with Advanced Services, and Windows Embedded SQL.) rowToken.Data.Add(4); // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }
/// <summary> /// Handler for login request /// </summary> public virtual TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Log request TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Update server context session.Database = string.IsNullOrEmpty(loginRequest.Database) ? "master" : loginRequest.Database; // Resolve TDS version session.TDSVersion = TDSVersion.Resolve(TDSVersion.GetTDSVersion(Arguments.ServerVersion), loginRequest.TDSVersion); // Check for the TDS version TDSMessageCollection collection = CheckTDSVersion(session); // Check if any errors are posted if (collection != null) { // Version check needs to send own message hence we can't proceed return(collection); } // Indicates federated authentication bool bIsFedAuthConnection = false; // Federated authentication option to be used later TDSLogin7FedAuthOptionToken federatedAuthenticationOption = null; // Check if feature extension block is available if (loginRequest.FeatureExt != null) { // Go over the feature extension data foreach (TDSLogin7FeatureOptionToken option in loginRequest.FeatureExt) { // Check option type switch (option.FeatureID) { case TDSFeatureID.SessionRecovery: { // Enable session recovery session.IsSessionRecoveryEnabled = true; // Cast to session state options TDSLogin7SessionRecoveryOptionToken sessionStateOption = option as TDSLogin7SessionRecoveryOptionToken; // Inflate session state (session as GenericTDSServerSession).Inflate(sessionStateOption.Initial, sessionStateOption.Current); break; } case TDSFeatureID.FederatedAuthentication: { // Cast to federated authentication option federatedAuthenticationOption = option as TDSLogin7FedAuthOptionToken; // Mark authentication as federated bIsFedAuthConnection = true; // Validate federated authentication option collection = CheckFederatedAuthenticationOption(session, option as TDSLogin7FedAuthOptionToken); if (collection != null) { // Version error happened. return(collection); } // Save the fed auth library to be used (session as GenericTDSServerSession).FederatedAuthenticationLibrary = federatedAuthenticationOption.Library; break; } default: { // Do nothing break; } } } } // Check if SSPI authentication is requested if (loginRequest.OptionalFlags2.IntegratedSecurity == TDSLogin7OptionalFlags2IntSecurity.On) { // Delegate to SSPI authentication return(ContinueSSPIAuthentication(session, loginRequest.SSPI)); } // If it is not a FedAuth connection or the server has been started up as not supporting FedAuth, just ignore the FeatureExtension // Yes unfortunately for the fake server, supporting FedAuth = Requiring FedAuth if (!bIsFedAuthConnection || Arguments.FedAuthRequiredPreLoginOption == TdsPreLoginFedAuthRequiredOption.FedAuthNotRequired) { // We use SQL authentication session.SQLUserID = loginRequest.UserID; // Process with the SQL login. return(OnSqlAuthenticationCompleted(session)); } else { // Fedauth feature extension is present and server has been started up as Requiring (or Supporting) FedAuth if (federatedAuthenticationOption.IsRequestingAuthenticationInfo) { // Must provide client with more info before completing authentication return(OnFederatedAuthenticationInfoRequest(session)); } else { return(OnFederatedAuthenticationCompleted(session, federatedAuthenticationOption.Token)); } } }
/// <summary> /// Notify server of the session termination /// </summary> public virtual void CloseSession(ITDSServerSession session) { // Do nothing }
protected virtual TDSMessageCollection OnFederatedAuthenticationInfoRequest(ITDSServerSession session) { TDSFedAuthInfoToken infoToken = new TDSFedAuthInfoToken(); // Make fake info options TDSFedAuthInfoOptionSPN spn = new TDSFedAuthInfoOptionSPN(Arguments.ServerPrincipalName); TDSFedAuthInfoOptionSTSURL stsurl = new TDSFedAuthInfoOptionSTSURL(Arguments.StsUrl); infoToken.Options.Add(0, spn); infoToken.Options.Add(1, stsurl); // Log response TDSUtilities.Log(Arguments.Log, "Response", spn); TDSUtilities.Log(Arguments.Log, "Response", stsurl); TDSMessage infoMessage = new TDSMessage(TDSMessageType.FederatedAuthenticationInfo, infoToken); return new TDSMessageCollection(infoMessage); }
public override TDSMessageCollection ExecuteRPC(ITDSServerSession session, TDSMessage message) { TDSRPCRequestToken rpc = message[0] as TDSRPCRequestToken; TDSDoneToken done = new TDSDoneToken(TDSDoneTokenStatusType.Final, TDSDoneTokenCommandType.Done, 0); if (String.IsNullOrEmpty(rpc.ProcName)) { if (rpc.ProcID == TDSRPCRequestTokenProcID.Sp_ExecuteSql) { var sqlQuery = rpc.Parameters.First(); if (sqlQuery.DataType == TDSDataType.NVarChar) { var sql = sqlQuery.Value.ToString(); var result = TryGet(sql, rpc.Parameters); if (null != result) { if (result.GetRecords().Any()) { var tokens = ReturnTable(result); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, (ulong)result.GetRecords().Count()); tokens.Add(doneToken); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, tokens.ToArray()))); } else if (result.ReturnValue.HasValue) { var retVal = new TDSReturnValueToken(); retVal.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; retVal.DataType = TDSDataType.IntN; retVal.DataTypeSpecific = (byte)4; retVal.Flags.IsComputed = true; retVal.Flags.IsNullable = true; // TODO: Must be nullable, otherwise something is wrong with SqlClient retVal.ParamName = "@RETURN_VALUE"; retVal.Value = (int)result.ReturnValue.Value; retVal.Status = TDSReturnValueStatus.Output; TDSDoneInProcToken doneInRpc = new TDSDoneInProcToken(TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.DoneInProc, 1); return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, retVal, doneInRpc))); } else { TDSDoneInProcToken doneInRpc = new TDSDoneInProcToken(TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.DoneInProc, result.Scalar); return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, doneInRpc))); } } else { PrintMissignQuery(sql, rpc.Parameters); } } } } else { var text = rpc.ProcName.ToLowerInvariant(); var result = TryGet(text, rpc.Parameters); if (null != result) { if (result.GetRecords().Any()) { var tokens = ReturnTable(result); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, (ulong)result.GetRecords().Count()); tokens.Add(doneToken); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, tokens.ToArray()))); } else { TDSDoneInProcToken doneIn = new TDSDoneInProcToken(TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.DoneInProc, result.Scalar); return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, doneIn))); } } else { PrintMissignQuery(text, rpc.Parameters); } } return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, done))); }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Check if arguments are of the authenticating TDS server if (Arguments is AuthenticatingTDSServerArguments) { // Cast to authenticating TDS server arguments AuthenticatingTDSServerArguments ServerArguments = Arguments as AuthenticatingTDSServerArguments; // Check if we're still processing normal login if (ServerArguments.ApplicationIntentFilter != ApplicationIntentFilterType.All) { // Check filter if ((ServerArguments.ApplicationIntentFilter == ApplicationIntentFilterType.ReadOnly && loginRequest.TypeFlags.ReadOnlyIntent != TDSLogin7TypeFlagsReadOnlyIntent.ReadOnly) || (ServerArguments.ApplicationIntentFilter == ApplicationIntentFilterType.None)) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application intent: " + loginRequest.TypeFlags.ReadOnlyIntent.ToString(), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by application intent filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Put a single message into the collection and return it return new TDSMessageCollection(responseMessage); } } // Check if we're still processing normal login and there's a filter to check if (ServerArguments.ServerNameFilterType != ServerNameFilterType.None) { // Check each algorithm if ((ServerArguments.ServerNameFilterType == ServerNameFilterType.Equals && string.Compare(ServerArguments.ServerNameFilter, loginRequest.ServerName, true) != 0) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.StartsWith && !loginRequest.ServerName.StartsWith(ServerArguments.ServerNameFilter)) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.EndsWith && !loginRequest.ServerName.EndsWith(ServerArguments.ServerNameFilter)) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.Contains && !loginRequest.ServerName.Contains(ServerArguments.ServerNameFilter))) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, string.Format("Received server name \"{0}\", expected \"{1}\" using \"{2}\" algorithm", loginRequest.ServerName, ServerArguments.ServerNameFilter, ServerArguments.ServerNameFilterType), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by server name filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return only a single message with the collection return new TDSMessageCollection(responseMessage); } } // Check if packet size filter is applied if (ServerArguments.PacketSizeFilter != null) { // Check if requested packet size is the same as the filter specified if (loginRequest.PacketSize != ServerArguments.PacketSizeFilter.Value) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(1919, 1, 14, string.Format("Received packet size \"{0}\", expected \"{1}\"", loginRequest.PacketSize, ServerArguments.PacketSizeFilter.Value), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(1919, 1, 14, "Connection is denied by packet size filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return only a single message with the collection return new TDSMessageCollection(responseMessage); } } // If we have an application name filter if (ServerArguments.ApplicationNameFilter != null) { // If we are supposed to block this connection attempt if (loginRequest.ApplicationName.Equals(ServerArguments.ApplicationNameFilter, System.StringComparison.OrdinalIgnoreCase)) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application name: " + loginRequest.ApplicationName, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by application name filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Put a single message into the collection and return it return new TDSMessageCollection(responseMessage); } } } // Return login response from the base class return base.OnLogin7Request(session, request); }
/// <summary> /// Checks the TDS version /// </summary> /// <param name="session">Server session</param> /// <returns>Null if the TDS version is supported, errorToken message otherwise</returns> protected virtual TDSMessageCollection CheckTDSVersion(ITDSServerSession session) { // Check if version is supported if (TDSVersion.IsSupported(session.TDSVersion)) { return null; } // Prepare ERROR token TDSErrorToken errorToken = new TDSErrorToken(12345, 1, 16, "Unsupported TDS client version", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Wrap with message collection return new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken)); }
/// <summary> /// Ensure that federated authentication option is valid /// </summary> protected virtual TDSMessageCollection CheckFederatedAuthenticationOption(ITDSServerSession session, TDSLogin7FedAuthOptionToken federatedAuthenticationOption) { // Check if server's prelogin response for FedAuthRequired prelogin option is echoed back correctly in FedAuth Feature Extenion Echo if (federatedAuthenticationOption.Echo != (session as GenericTDSServerSession).FedAuthRequiredPreLoginServerResponse) { // Create Error message string message = string.Format("FEDAUTHREQUIRED option in the prelogin response is not echoed back correctly: in prelogin response, it is {0} and in login, it is {1}: ", (session as GenericTDSServerSession).FedAuthRequiredPreLoginServerResponse, federatedAuthenticationOption.Echo); // Create errorToken token TDSErrorToken errorToken = new TDSErrorToken(3456, 34, 23, message); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Build a collection with a single message of two tokens return new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken)); } // Check if the nonce exists if ((federatedAuthenticationOption.Nonce == null && federatedAuthenticationOption.Library == TDSFedAuthLibraryType.IDCRL) || !AreEqual((session as GenericTDSServerSession).ServerNonce, federatedAuthenticationOption.Nonce)) { // Error message string message = string.Format("Unexpected NONCEOPT specified in the Federated authentication feature extension"); // Create errorToken token TDSErrorToken errorToken = new TDSErrorToken(5672, 32, 87, message); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Build a collection with a single message of two tokens return new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken)); } // We're good return null; }
/// <summary> /// Complete the Federated Login /// </summary> /// <param name="session">Server session</param> /// <returns>Federated Login message collection</returns> protected virtual TDSMessageCollection OnFederatedAuthenticationCompleted(ITDSServerSession session, byte[] ticket) { // Delegate to successful authentication routine TDSMessageCollection responseMessageCollection = OnAuthenticationCompleted(session); // Get the last message TDSMessage targetMessage = responseMessageCollection.Last(); IFederatedAuthenticationTicket decryptedTicket = null; try { // Get the Federated Authentication ticket using RPS decryptedTicket = FederatedAuthenticationTicketService.DecryptTicket((session as GenericTDSServerSession).FederatedAuthenticationLibrary, ticket); if (decryptedTicket is RpsTicket) { TDSUtilities.Log(Arguments.Log, "RPS ticket session key: ", (decryptedTicket as RpsTicket).sessionKey); } else if (decryptedTicket is JwtTicket) { TDSUtilities.Log(Arguments.Log, "JWT Ticket Received", null); } } catch (Exception ex) { // Prepare ERROR token TDSErrorToken errorToken = new TDSErrorToken(54879, 1, 20, "Authentication error in Federated Authentication Ticket Service: " + ex.Message, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Return the message and stop processing request return new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken)); } // Create federated authentication extension option TDSFeatureExtAckFederatedAuthenticationOption federatedAuthenticationOption; if ((session as GenericTDSServerSession).FederatedAuthenticationLibrary == TDSFedAuthLibraryType.ADAL) { // For the time being, fake fedauth tokens are used for ADAL, so decryptedTicket is null. federatedAuthenticationOption = new TDSFeatureExtAckFederatedAuthenticationOption((session as GenericTDSServerSession).ClientNonce, null); } else { federatedAuthenticationOption = new TDSFeatureExtAckFederatedAuthenticationOption((session as GenericTDSServerSession).ClientNonce, decryptedTicket.GetSignature((session as GenericTDSServerSession).ClientNonce)); } // Look for feature extension token TDSFeatureExtAckToken featureExtActToken = (TDSFeatureExtAckToken)targetMessage.Where(t => t is TDSFeatureExtAckToken).FirstOrDefault(); // Check if response already contains federated authentication if (featureExtActToken == null) { // Create Feature extension Ack token featureExtActToken = new TDSFeatureExtAckToken(federatedAuthenticationOption); // Serialize feature extension token into the response // The last token is Done token, so we should put feautureextack token before done token targetMessage.Insert(targetMessage.Count - 1, featureExtActToken); } else { // Update featureExtActToken.Options.Add(federatedAuthenticationOption); } // Log response TDSUtilities.Log(Arguments.Log, "Response", federatedAuthenticationOption); // Wrap a message with a collection return responseMessageCollection; }
/// <summary> /// Prepare response to server ping /// </summary> private TDSMessage _PreparePingResponse(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Start the first column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.IntN; column.DataTypeSpecific = (byte)4; column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; column.Flags.IsNullable = true; // TODO: Must be nullable, otherwise something is wrong with SqlClient column.Flags.IsComputed = true; // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Add row rowToken.Data.Add((int)1); // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }
protected virtual TDSMessageCollection OnAuthenticationCompleted(ITDSServerSession session) { // Create new database environment change token TDSEnvChangeToken envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.Database, session.Database, "master"); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, envChange); // Create information token on the change TDSInfoToken infoToken = new TDSInfoToken(5701, 2, 0, string.Format("Changed database context to '{0}'", envChange.NewValue), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", infoToken); // Serialize the login token into the response packet responseMessage.Add(infoToken); // Create new collation change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.SQLCollation, (session as GenericTDSServerSession).Collation); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Create new language change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.Language, LanguageString.ToString((session as GenericTDSServerSession).Language)); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Create information token on the change infoToken = new TDSInfoToken(5703, 1, 0, string.Format("Changed language setting to {0}", envChange.NewValue), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", infoToken); // Serialize the login token into the response packet responseMessage.Add(infoToken); // Create new packet size environment change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.PacketSize, Arguments.PacketSize.ToString(), Arguments.PacketSize.ToString()); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Update session packet size session.PacketSize = (uint)Arguments.PacketSize; // Create login acknowledgnment packet TDSLoginAckToken loginResponseToken = new TDSLoginAckToken(Arguments.ServerVersion, session.TDSVersion, TDSLogin7TypeFlagsSQL.SQL, "Microsoft SQL Server"); // Otherwise SNAC yields E_FAIL // Log response TDSUtilities.Log(Arguments.Log, "Response", loginResponseToken); // Serialize the login token into the response packet responseMessage.Add(loginResponseToken); // Check if session recovery is enabled if (session.IsSessionRecoveryEnabled) { // Create Feature extension Ack token TDSFeatureExtAckToken featureExtActToken = new TDSFeatureExtAckToken(new TDSFeatureExtAckSessionStateOption((session as GenericTDSServerSession).Deflate())); // Log response TDSUtilities.Log(Arguments.Log, "Response", featureExtActToken); // Serialize feature extnesion token into the response responseMessage.Add(featureExtActToken); } // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Wrap a single message in a collection return new TDSMessageCollection(responseMessage); }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Check if arguments are of the authenticating TDS server if (Arguments is AuthenticatingTDSServerArguments) { // Cast to authenticating TDS server arguments AuthenticatingTDSServerArguments ServerArguments = Arguments as AuthenticatingTDSServerArguments; // Check if we're still processing normal login if (ServerArguments.ApplicationIntentFilter != ApplicationIntentFilterType.All) { // Check filter if ((ServerArguments.ApplicationIntentFilter == ApplicationIntentFilterType.ReadOnly && loginRequest.TypeFlags.ReadOnlyIntent != TDSLogin7TypeFlagsReadOnlyIntent.ReadOnly) || (ServerArguments.ApplicationIntentFilter == ApplicationIntentFilterType.None)) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application intent: " + loginRequest.TypeFlags.ReadOnlyIntent.ToString(), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by application intent filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Put a single message into the collection and return it return(new TDSMessageCollection(responseMessage)); } } // Check if we're still processing normal login and there's a filter to check if (ServerArguments.ServerNameFilterType != ServerNameFilterType.None) { // Check each algorithm if ((ServerArguments.ServerNameFilterType == ServerNameFilterType.Equals && string.Compare(ServerArguments.ServerNameFilter, loginRequest.ServerName, true) != 0) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.StartsWith && !loginRequest.ServerName.StartsWith(ServerArguments.ServerNameFilter)) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.EndsWith && !loginRequest.ServerName.EndsWith(ServerArguments.ServerNameFilter)) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.Contains && !loginRequest.ServerName.Contains(ServerArguments.ServerNameFilter))) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, string.Format("Received server name \"{0}\", expected \"{1}\" using \"{2}\" algorithm", loginRequest.ServerName, ServerArguments.ServerNameFilter, ServerArguments.ServerNameFilterType), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by server name filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return only a single message with the collection return(new TDSMessageCollection(responseMessage)); } } // Check if packet size filter is applied if (ServerArguments.PacketSizeFilter != null) { // Check if requested packet size is the same as the filter specified if (loginRequest.PacketSize != ServerArguments.PacketSizeFilter.Value) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(1919, 1, 14, string.Format("Received packet size \"{0}\", expected \"{1}\"", loginRequest.PacketSize, ServerArguments.PacketSizeFilter.Value), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(1919, 1, 14, "Connection is denied by packet size filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return only a single message with the collection return(new TDSMessageCollection(responseMessage)); } } // If we have an application name filter if (ServerArguments.ApplicationNameFilter != null) { // If we are supposed to block this connection attempt if (loginRequest.ApplicationName.Equals(ServerArguments.ApplicationNameFilter, System.StringComparison.OrdinalIgnoreCase)) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application name: " + loginRequest.ApplicationName, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by application name filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Put a single message into the collection and return it return(new TDSMessageCollection(responseMessage)); } } } // Return login response from the base class return(base.OnLogin7Request(session, request)); }
/// <summary> /// Handler for pre-login request /// </summary> public virtual TDSMessageCollection OnPreLoginRequest(ITDSServerSession session, TDSMessage request) { // Inflate pre-login request from the message TDSPreLoginToken preLoginRequest = request[0] as TDSPreLoginToken; // Log request TDSUtilities.Log(Arguments.Log, "Request", preLoginRequest); // Generate server response for encryption TDSPreLoginTokenEncryptionType serverResponse = TDSUtilities.GetEncryptionResponse(preLoginRequest.Encryption, Arguments.Encryption); // Update client state with encryption resolution session.Encryption = TDSUtilities.ResolveEncryption(preLoginRequest.Encryption, serverResponse); // Create TDS prelogin packet TDSPreLoginToken preLoginToken = new TDSPreLoginToken(Arguments.ServerVersion, serverResponse, false); // TDS server doesn't support MARS // Cache the recieved Nonce into the session (session as GenericTDSServerSession).ClientNonce = preLoginRequest.Nonce; // Check if the server has been started up as requiring FedAuth when choosing between SSPI and FedAuth if (Arguments.FedAuthRequiredPreLoginOption == TdsPreLoginFedAuthRequiredOption.FedAuthRequired) { if (preLoginRequest.FedAuthRequired == TdsPreLoginFedAuthRequiredOption.FedAuthRequired) { // Set the FedAuthRequired option preLoginToken.FedAuthRequired = TdsPreLoginFedAuthRequiredOption.FedAuthRequired; } // Keep the federated authentication required flag in the server session (session as GenericTDSServerSession).FedAuthRequiredPreLoginServerResponse = preLoginToken.FedAuthRequired; if (preLoginRequest.Nonce != null) { // Generate Server Nonce preLoginToken.Nonce = _GenerateRandomBytes(32); } } // Cache the server Nonce in a session (session as GenericTDSServerSession).ServerNonce = preLoginToken.Nonce; // Log response TDSUtilities.Log(Arguments.Log, "Response", preLoginToken); // Reset authentication information session.SQLUserID = null; session.NTUserAuthenticationContext = null; // Respond with a single message that contains only one token return new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, preLoginToken)); }
/// <summary> /// It is called when SQL batch request arrives /// </summary> /// <param name="message">TDS message recieved</param> /// <returns>TDS message to respond with</returns> public override TDSMessageCollection OnSQLBatchRequest(ITDSServerSession session, TDSMessage request) { // Delegate to the base class to produce the response first TDSMessageCollection batchResponse = base.OnSQLBatchRequest(session, request); // Check if arguments are of routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments ServerArguments = Arguments as RoutingTDSServerArguments; // Check routing condition if (ServerArguments.RouteOnPacket == TDSMessageType.SQLBatch) { // Construct routing token TDSPacketToken routingToken = CreateRoutingToken(); // Log response TDSUtilities.Log(Arguments.Log, "Response", routingToken); // Insert the routing token at the beginning of the response batchResponse[0].Insert(0, routingToken); } else { // Get the first response message TDSMessage responseMessage = batchResponse[0]; // Reset the content of the first message responseMessage.Clear(); // Prepare ERROR token with the denial details responseMessage.Add(new TDSErrorToken(11111, 1, 14, "Client should have been routed by now", Arguments.ServerName)); // Log response TDSUtilities.Log(Arguments.Log, "Response", responseMessage[0]); // Prepare DONE token responseMessage.Add(new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error)); // Log response TDSUtilities.Log(Arguments.Log, "Response", responseMessage[1]); } } // Register only one message with the collection return batchResponse; }
/// <summary> /// Prepare response for query of class of the SQL Server instance /// </summary> private TDSMessage _PrepareTestSQLServerClassResponse(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Start first column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.DataTypeSpecific = new TDSShilohVarCharColumnSpecific(256, new TDSColumnDataCollation(13632521, 52)); column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Get the server class rowToken.Data.Add(session.Server.GetType().FullName); // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }
/// <summary> /// Advances one step in SSPI authentication sequence /// </summary> protected virtual TDSMessageCollection ContinueSSPIAuthentication(ITDSServerSession session, byte[] payload) { // Response to send to the client SSPIResponse response; try { // Check if we have an SSPI context if (session.NTUserAuthenticationContext == null) { // This is the first step so we need to create a server context and initialize it session.NTUserAuthenticationContext = SSPIContext.CreateServer(); // Run the first step of authentication response = session.NTUserAuthenticationContext.StartServerAuthentication(payload); } else { // Process SSPI request from the client response = session.NTUserAuthenticationContext.ContinueServerAuthentication(payload); } } catch (Exception e) { // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(12345, 1, 15, "Failed to accept security SSPI context", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseErrorMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(12345, 1, 15, e.Message, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseErrorMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseErrorMessage.Add(doneToken); // Respond with a single message return new TDSMessageCollection(responseErrorMessage); } // Message collection to respond with TDSMessageCollection responseMessages = new TDSMessageCollection(); // Check if there's a response if (response != null) { // Check if there's a payload if (response.Payload != null) { // Create SSPI token TDSSSPIToken sspiToken = new TDSSSPIToken(response.Payload); // Log response TDSUtilities.Log(Arguments.Log, "Response", sspiToken); // Prepare response message with a single response token responseMessages.Add(new TDSMessage(TDSMessageType.Response, sspiToken)); // Check if we can complete login if (!response.IsFinal) { // Send the message to the client return responseMessages; } } } // Reset SQL user identifier since we're using NT authentication session.SQLUserID = null; // Append successfully authentication response responseMessages.AddRange(OnAuthenticationCompleted(session)); // Return the message with SSPI token return responseMessages; }
/// <summary> /// Prepare response for user nane query that OLE DB stack dispatches upon connection /// </summary> private TDSMessage _PrepareOleDbReadOnlyUserName(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Start first column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.BigVarChar; column.DataTypeSpecific = new TDSShilohVarCharColumnSpecific(1, new TDSColumnDataCollation(13632521, 52)); column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; // Add a column to the response metadataToken.Columns.Add(column); // Start second column column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.DataTypeSpecific = new TDSShilohVarCharColumnSpecific(128, new TDSColumnDataCollation(13632521, 52)); column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Add row rowToken.Data.Add("N"); rowToken.Data.Add("dbo"); // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }
/// <summary> /// Prepare response to the query about connection encryption /// </summary> private TDSMessage _PrepareEncryptionInfoResponse(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Start the first column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.DataTypeSpecific = new TDSShilohVarCharColumnSpecific(40, new TDSColumnDataCollation(13632521, 52)); column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; column.Name = "encrypt_option"; // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Check if encryption is enabled if (session.Encryption == TDSEncryptionType.Full) { // Add row rowToken.Data.Add("TRUE"); } else { // Add row rowToken.Data.Add("FALSE"); } // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }
/// <summary> /// Advances one step in SSPI authentication sequence /// </summary> protected virtual TDSMessageCollection ContinueSSPIAuthentication(ITDSServerSession session, byte[] payload) { // Response to send to the client SSPIResponse response; try { // Check if we have an SSPI context if (session.NTUserAuthenticationContext == null) { // This is the first step so we need to create a server context and initialize it session.NTUserAuthenticationContext = SSPIContext.CreateServer(); // Run the first step of authentication response = session.NTUserAuthenticationContext.StartServerAuthentication(payload); } else { // Process SSPI request from the client response = session.NTUserAuthenticationContext.ContinueServerAuthentication(payload); } } catch (Exception e) { // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(12345, 1, 15, "Failed to accept security SSPI context", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseErrorMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(12345, 1, 15, e.Message, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseErrorMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseErrorMessage.Add(doneToken); // Respond with a single message return(new TDSMessageCollection(responseErrorMessage)); } // Message collection to respond with TDSMessageCollection responseMessages = new TDSMessageCollection(); // Check if there's a response if (response != null) { // Check if there's a payload if (response.Payload != null) { // Create SSPI token TDSSSPIToken sspiToken = new TDSSSPIToken(response.Payload); // Log response TDSUtilities.Log(Arguments.Log, "Response", sspiToken); // Prepare response message with a single response token responseMessages.Add(new TDSMessage(TDSMessageType.Response, sspiToken)); // Check if we can complete login if (!response.IsFinal) { // Send the message to the client return(responseMessages); } } } // Reset SQL user identifier since we're using NT authentication session.SQLUserID = null; // Append successfully authentication response responseMessages.AddRange(OnAuthenticationCompleted(session)); // Return the message with SSPI token return(responseMessages); }
/// <summary> /// It is called when attention arrives /// </summary> public virtual TDSMessageCollection OnAttention(ITDSServerSession session, TDSMessage message) { // Delegate into the query engine return Engine.ExecuteAttention(session, message); }
/// <summary> /// Called by OnLogin7Request when client is using SQL auth. Overridden by subclasses to easily detect when SQL auth is used. /// </summary> protected virtual TDSMessageCollection OnSqlAuthenticationCompleted(ITDSServerSession session) { return(OnAuthenticationCompleted(session)); }
/// <summary> /// It is called when SQL batch request arrives /// </summary> public virtual TDSMessageCollection OnSQLBatchRequest(ITDSServerSession session, TDSMessage message) { // Delegate to the query engine TDSMessageCollection responseMessage = Engine.ExecuteBatch(session, message); // Check if session packet size is different than the engine packet size if (session.PacketSize != Arguments.PacketSize) { // Get the first message TDSMessage firstMessage = responseMessage[0]; // Find DONE token in it int indexOfDone = firstMessage.IndexOf(firstMessage.Where(t => t is TDSDoneToken).First()); // Create new packet size environment change token TDSEnvChangeToken envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.PacketSize, Arguments.PacketSize.ToString(), session.PacketSize.ToString()); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Insert env change before done token firstMessage.Insert(indexOfDone, envChange); // Update session with the new packet size session.PacketSize = (uint)Arguments.PacketSize; } return responseMessage; }
/// <summary> /// Complete the Federated Login /// </summary> /// <param name="session">Server session</param> /// <returns>Federated Login message collection</returns> protected virtual TDSMessageCollection OnFederatedAuthenticationCompleted(ITDSServerSession session, byte[] ticket) { // Delegate to successful authentication routine TDSMessageCollection responseMessageCollection = OnAuthenticationCompleted(session); // Get the last message TDSMessage targetMessage = responseMessageCollection.Last(); IFederatedAuthenticationTicket decryptedTicket = null; try { // Get the Federated Authentication ticket using RPS decryptedTicket = FederatedAuthenticationTicketService.DecryptTicket((session as GenericTDSServerSession).FederatedAuthenticationLibrary, ticket); if (decryptedTicket is RpsTicket) { TDSUtilities.Log(Arguments.Log, "RPS ticket session key: ", (decryptedTicket as RpsTicket).sessionKey); } else if (decryptedTicket is JwtTicket) { TDSUtilities.Log(Arguments.Log, "JWT Ticket Received", null); } } catch (Exception ex) { // Prepare ERROR token TDSErrorToken errorToken = new TDSErrorToken(54879, 1, 20, "Authentication error in Federated Authentication Ticket Service: " + ex.Message, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Return the message and stop processing request return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken))); } // Create federated authentication extension option TDSFeatureExtAckFederatedAuthenticationOption federatedAuthenticationOption; if ((session as GenericTDSServerSession).FederatedAuthenticationLibrary == TDSFedAuthLibraryType.MSAL) { // For the time being, fake fedauth tokens are used for ADAL, so decryptedTicket is null. federatedAuthenticationOption = new TDSFeatureExtAckFederatedAuthenticationOption((session as GenericTDSServerSession).ClientNonce, null); } else { federatedAuthenticationOption = new TDSFeatureExtAckFederatedAuthenticationOption((session as GenericTDSServerSession).ClientNonce, decryptedTicket.GetSignature((session as GenericTDSServerSession).ClientNonce)); } // Look for feature extension token TDSFeatureExtAckToken featureExtActToken = (TDSFeatureExtAckToken)targetMessage.Where(t => t is TDSFeatureExtAckToken).FirstOrDefault(); // Check if response already contains federated authentication if (featureExtActToken == null) { // Create Feature extension Ack token featureExtActToken = new TDSFeatureExtAckToken(federatedAuthenticationOption); // Serialize feature extension token into the response // The last token is Done token, so we should put feautureextack token before done token targetMessage.Insert(targetMessage.Count - 1, featureExtActToken); } else { // Update featureExtActToken.Options.Add(federatedAuthenticationOption); } // Log response TDSUtilities.Log(Arguments.Log, "Response", federatedAuthenticationOption); // Wrap a message with a collection return(responseMessageCollection); }
/// <summary> /// Handler for SSPI request /// </summary> public virtual TDSMessageCollection OnSSPIRequest(ITDSServerSession session, TDSMessage request) { // Get the SSPI token TDSSSPIClientToken sspiRequest = request[0] as TDSSSPIClientToken; // Log request TDSUtilities.Log(Arguments.Log, "Request", sspiRequest.Payload); // Delegate to SSPI routine return ContinueSSPIAuthentication(session, sspiRequest.Payload); }
public virtual TDSMessageCollection OnFederatedAuthenticationTokenMessage(ITDSServerSession session, TDSMessage message) { // Get the FedAuthToken TDSFedAuthToken fedauthToken = message[0] as TDSFedAuthToken; // Log TDSUtilities.Log(Arguments.Log, "Request", fedauthToken); return OnFederatedAuthenticationCompleted(session, fedauthToken.Token); }
/// <summary> /// Handler for login request /// </summary> public virtual TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Log request TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Update server context session.Database = string.IsNullOrEmpty(loginRequest.Database) ? "master" : loginRequest.Database; // Resolve TDS version session.TDSVersion = TDSVersion.Resolve(TDSVersion.GetTDSVersion(Arguments.ServerVersion), loginRequest.TDSVersion); // Check for the TDS version TDSMessageCollection collection = CheckTDSVersion(session); // Check if any errors are posted if (collection != null) { // Version check needs to send own message hence we can't proceed return collection; } // Indicates federated authentication bool bIsFedAuthConnection = false; // Federated authentication option to be used later TDSLogin7FedAuthOptionToken federatedAuthenticationOption = null; // Check if feature extension block is available if (loginRequest.FeatureExt != null) { // Go over the feature extension data foreach (TDSLogin7FeatureOptionToken option in loginRequest.FeatureExt) { // Check option type switch (option.FeatureID) { case TDSFeatureID.SessionRecovery: { // Enable session recovery session.IsSessionRecoveryEnabled = true; // Cast to session state options TDSLogin7SessionRecoveryOptionToken sessionStateOption = option as TDSLogin7SessionRecoveryOptionToken; // Inflate session state (session as GenericTDSServerSession).Inflate(sessionStateOption.Initial, sessionStateOption.Current); break; } case TDSFeatureID.FederatedAuthentication: { // Cast to federated authentication option federatedAuthenticationOption = option as TDSLogin7FedAuthOptionToken; // Mark authentication as federated bIsFedAuthConnection = true; // Validate federated authentication option collection = CheckFederatedAuthenticationOption(session, option as TDSLogin7FedAuthOptionToken); if (collection != null) { // Version error happened. return collection; } // Save the fed auth library to be used (session as GenericTDSServerSession).FederatedAuthenticationLibrary = federatedAuthenticationOption.Library; break; } default: { // Do nothing break; } } } } // Check if SSPI authentication is requested if (loginRequest.OptionalFlags2.IntegratedSecurity == TDSLogin7OptionalFlags2IntSecurity.On) { // Delegate to SSPI authentication return ContinueSSPIAuthentication(session, loginRequest.SSPI); } // If it is not a FedAuth connection or the server has been started up as not supporting FedAuth, just ignore the FeatureExtension // Yes unfortunately for the fake server, supporting FedAuth = Requiring FedAuth if (!bIsFedAuthConnection || Arguments.FedAuthRequiredPreLoginOption == TdsPreLoginFedAuthRequiredOption.FedAuthNotRequired) { // We use SQL authentication session.SQLUserID = loginRequest.UserID; // Process with the SQL login. return OnSqlAuthenticationCompleted(session); } else { // Fedauth feature extension is present and server has been started up as Requiring (or Supporting) FedAuth if (federatedAuthenticationOption.IsRequestingAuthenticationInfo) { // Must provide client with more info before completing authentication return OnFederatedAuthenticationInfoRequest(session); } else { return OnFederatedAuthenticationCompleted(session, federatedAuthenticationOption.Token); } } }
/// <summary> /// Complete login sequence /// </summary> protected override TDSMessageCollection OnAuthenticationCompleted(ITDSServerSession session) { // Delegate to the base class TDSMessageCollection responseMessageCollection = base.OnAuthenticationCompleted(session); // Check if arguments are of routing server if (Arguments is RoutingTDSServerArguments) { // Cast to routing server arguments RoutingTDSServerArguments serverArguments = Arguments as RoutingTDSServerArguments; // Check routing condition if (serverArguments.RouteOnPacket == TDSMessageType.TDS7Login) { // Construct routing token TDSPacketToken routingToken = CreateRoutingToken(); // Log response TDSUtilities.Log(Arguments.Log, "Response", routingToken); // Get the first message TDSMessage targetMessage = responseMessageCollection[0]; // Index at which to insert the routing token int insertIndex = targetMessage.Count - 1; // VSTS# 1021027 - Read-Only Routing yields TDS protocol error // Resolution: Send TDS FeatureExtAct token before TDS ENVCHANGE token with routing information TDSPacketToken featureExtAckToken = targetMessage.Find(t => t is TDSFeatureExtAckToken); // Check if found if (featureExtAckToken != null) { // Find token position insertIndex = targetMessage.IndexOf(featureExtAckToken); } // Insert right before the done token targetMessage.Insert(insertIndex, routingToken); } } return responseMessageCollection; }
/// <summary> /// Called by OnLogin7Request when client is using SQL auth. Overridden by subclasses to easily detect when SQL auth is used. /// </summary> protected virtual TDSMessageCollection OnSqlAuthenticationCompleted(ITDSServerSession session) { return OnAuthenticationCompleted(session); }
/// <summary> /// Prepare response for session user name query /// </summary> private TDSMessage _PrepareSessionUserResponse(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Prepare column type-specific data TDSShilohVarCharColumnSpecific nVarChar = new TDSShilohVarCharColumnSpecific(256, new TDSColumnDataCollation(13632521, 52)); // Prepare the first column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.Flags.Updatable = TDSColumnDataUpdatableFlag.Unknown; column.Flags.IsNullable = true; column.DataTypeSpecific = nVarChar; column.Name = "nt_user_name"; // Add a column to the response metadataToken.Columns.Add(column); // Prepare the second column column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.Flags.Updatable = TDSColumnDataUpdatableFlag.Unknown; column.Flags.IsNullable = true; column.DataTypeSpecific = nVarChar; column.Name = "nt_domain"; // Add a column to the response metadataToken.Columns.Add(column); // Prepare the third column column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.Flags.Updatable = TDSColumnDataUpdatableFlag.Unknown; column.DataTypeSpecific = nVarChar; column.Name = "login_name"; // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Check user type if (session.SQLUserID != null) { // Add row rowToken.Data.Add(null); // nt_user_name rowToken.Data.Add(null); // nt_domain rowToken.Data.Add(session.SQLUserID); // login_name } else if (session.NTUserAuthenticationContext != null) { // Get user identifier string userID = session.NTUserAuthenticationContext.GetRemoteIdentity().Name; // Look for traditional separator for form "<domain>\<user>" int indexOfSeparator = userID.IndexOf('\\'); string domain = null; string user = null; // Parse domain and user out of the entry if (indexOfSeparator != -1) { // Extract parts domain = userID.Substring(0, indexOfSeparator); user = userID.Substring(indexOfSeparator + 1); } else { // Look for a different type of separator for form "<user>@<domain>" indexOfSeparator = userID.IndexOf('@'); // Check if found if (indexOfSeparator != -1) { // Extract parts domain = userID.Substring(indexOfSeparator + 1); user = userID.Substring(0, indexOfSeparator); } else { // We don't recognize this user so don't parse it domain = null; user = userID; } } // Add row rowToken.Data.Add(user); // nt_user_name rowToken.Data.Add(domain); // nt_domain rowToken.Data.Add(userID); // login_name } else { // We don't have a user, which is very strange since we're in query engine already rowToken.Data.Add(null); // nt_user_name rowToken.Data.Add(null); // nt_domain rowToken.Data.Add(null); // login_name } // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }
/// <summary> /// Prepare response to the query about connection end-point /// </summary> private TDSMessage _PrepareConnectionInfoResponse(ITDSServerSession session) { // Prepare result metadata TDSColMetadataToken metadataToken = new TDSColMetadataToken(); // Start the first column TDSColumnData column = new TDSColumnData(); column.DataType = TDSDataType.NVarChar; column.DataTypeSpecific = new TDSShilohVarCharColumnSpecific(40, new TDSColumnDataCollation(13632521, 52)); column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; column.Name = "net_transport"; // Add a column to the response metadataToken.Columns.Add(column); // Start the second column column = new TDSColumnData(); column.DataType = TDSDataType.BigVarChar; column.DataTypeSpecific = new TDSShilohVarCharColumnSpecific(48, new TDSColumnDataCollation(13632521, 52)); column.Flags.IsNullable = true; column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; column.Name = "local_net_address"; // Add a column to the response metadataToken.Columns.Add(column); // Start the third column column = new TDSColumnData(); column.DataType = TDSDataType.IntN; column.DataTypeSpecific = (byte)4; column.Flags.IsNullable = true; column.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; column.Name = "local_tcp_port"; // Add a column to the response metadataToken.Columns.Add(column); // Log response TDSUtilities.Log(Log, "Response", metadataToken); // Prepare result data TDSRowToken rowToken = new TDSRowToken(metadataToken); // Add row rowToken.Data.Add(session.ServerEndPointInfo.Transport.ToString()); rowToken.Data.Add(session.ServerEndPointInfo.Address.ToString()); rowToken.Data.Add(session.ServerEndPointInfo.Port); // Log response TDSUtilities.Log(Log, "Response", rowToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, 1); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return new TDSMessage(TDSMessageType.Response, metadataToken, rowToken, doneToken); }