/***************************************************************************
* Copyright ( C ) 2012 by Timothy Pearson *
* kb9vqf @ pearsoncomputing . net *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the *
* Free Software Foundation , Inc . , *
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdlib.h>
# include <unistd.h>
# include <tqapplication.h>
# include <tqbuffer.h>
# include <tqeventloop.h>
# include <tqtimer.h>
# include <sasl.h>
# include <saslplug.h>
# include <saslutil.h>
# include <klocale.h>
# include "tdekrbserversocket.h"
# define NET_SEC_BUF_SIZE (2048)
// When control comes back from processEvents() my object may be completely gone! This attempts to mitigate the risk
# define SAFELY_PROCESS_EVENTS if (!m_canary) { \
m_canary = new bool ; \
* m_canary = false ; \
} \
bool * canary = m_canary ; \
tqApp - > eventLoop ( ) - > processEvents ( TQEventLoop : : ExcludeUserInput ) ; \
if ( * canary = = true ) { \
delete canary ; \
return - 1 ; \
} \
delete m_canary ; \
m_canary = NULL ;
static bool tde_krb_sasl_server_initialized = false ;
static TQString tde_krb_sasl_server_appname ;
static sasl_callback_t tde_krb_sasl_server_callbacks [ N_CALLBACKS ] ;
/* exception handling */
struct exit_exception {
int c ;
exit_exception ( int c ) : c ( c ) { }
} ;
class SASLDataPrivate
{
public :
sasl_conn_t * m_krbConnection ;
} ;
static const char * safe_sasl_errdetail ( sasl_conn_t * conn ) {
const char * str = sasl_errdetail ( conn ) ;
if ( str ) {
return str ;
}
else {
return " unknown error " ;
}
}
static int logSASLMessages ( void * context __attribute__ ( ( unused ) ) , int priority , const char * message ) {
const char * label ;
if ( ! message ) {
return SASL_BADPARAM ;
}
switch ( priority ) {
case SASL_LOG_ERR :
label = " Error " ;
break ;
case SASL_LOG_NOTE :
label = " Info " ;
break ;
default :
label = " Other " ;
break ;
}
printf ( " [SASL %s] %s \n \r " , label , message ) ;
return SASL_OK ;
}
TDEKerberosServerSocket : : TDEKerberosServerSocket ( TQObject * parent , const char * name ) : TQSocket ( parent , name ) , m_kerberosRequested ( false ) , m_criticalSection ( 0 ) , m_bufferLength ( 0 ) , m_bufferReadPointer ( 0 ) , m_krbInitRunning ( false ) , m_krbInitState ( - 1 ) , m_dataTimeout ( - 1 ) , kerberosInitLoopTimer ( NULL ) , m_canary ( NULL ) , m_negotiatedMaxBufferSize ( NET_SEC_BUF_SIZE ) {
saslData = new SASLDataPrivate ;
saslData - > m_krbConnection = NULL ;
m_buffer = new TQBuffer ( ) ;
m_buffer - > open ( IO_ReadWrite | IO_Truncate ) ;
}
TDEKerberosServerSocket : : ~ TDEKerberosServerSocket ( ) {
if ( m_canary ) {
* m_canary = true ;
}
if ( kerberosInitLoopTimer ) {
kerberosInitLoopTimer - > stop ( ) ;
delete kerberosInitLoopTimer ;
kerberosInitLoopTimer = NULL ;
}
setUsingKerberos ( false ) ;
m_buffer - > close ( ) ;
delete m_buffer ;
delete saslData ;
}
void TDEKerberosServerSocket : : setDataTimeout ( int timeoutms ) {
m_dataTimeout = timeoutms ;
}
bool TDEKerberosServerSocket : : open ( int mode ) {
setStatusMessage ( i18n ( " Opening socket " ) ) ;
bool ret = TQSocket : : open ( mode ) ;
if ( m_kerberosRequested ) {
initializeKerberosInterface ( ) ;
}
return ret ;
}
void TDEKerberosServerSocket : : close ( ) {
TQSocket : : close ( ) ;
setStatusMessage ( i18n ( " Socket closed " ) ) ;
}
void TDEKerberosServerSocket : : flush ( ) {
if ( m_kerberosRequested ) {
// FIXME
// If a write buffer is implemented, it will need to be flushed before the following call is made
TQSocket : : flush ( ) ;
}
else {
TQSocket : : flush ( ) ;
}
}
TQIODevice : : Offset TDEKerberosServerSocket : : size ( ) const {
TQIODevice : : Offset ret ;
if ( m_kerberosRequested ) {
ret = m_bufferLength ;
}
else {
ret = TQSocket : : size ( ) ;
}
return ret ;
}
TQIODevice : : Offset TDEKerberosServerSocket : : at ( ) const {
return TQSocket : : at ( ) ;
}
bool TDEKerberosServerSocket : : at ( TQIODevice : : Offset off , int hidebasehack ) {
long i ;
bool ret ;
Q_UNUSED ( hidebasehack ) ;
if ( m_kerberosRequested ) {
if ( off > 0 ) {
// Prevent overflow
if ( off > ( unsigned long ) m_bufferLength ) {
off = m_bufferLength ;
}
// Remove the specified bytes from the buffer
m_bufferLength = m_bufferLength - off ;
m_bufferReadPointer = m_bufferReadPointer + off ;
if ( m_bufferLength < 1 ) {
// Clear the buffer from memory
m_buffer - > close ( ) ;
m_buffer - > open ( IO_ReadWrite | IO_Truncate ) ;
m_bufferReadPointer = 0 ;
}
}
return true ;
}
else {
ret = TQSocket : : at ( off ) ;
}
return ret ;
}
bool TDEKerberosServerSocket : : atEnd ( ) const {
bool ret ;
if ( kerberosStatus ( ) = = KerberosInUse ) {
ret = ( ( m_bufferLength < 1 ) & & TQSocket : : atEnd ( ) ) ;
}
else {
ret = TQSocket : : atEnd ( ) ;
}
return ret ;
}
int TDEKerberosServerSocket : : getch ( ) {
int ret ;
if ( kerberosStatus ( ) = = KerberosInUse ) {
char data [ 1 ] ;
if ( readBlock ( data , 1 ) < 0 ) {
ret = - 1 ;
}
else {
ret = data [ 0 ] ;
}
}
else {
ret = TQSocket : : getch ( ) ;
}
return ret ;
}
int TDEKerberosServerSocket : : putch ( int ch ) {
int ret ;
if ( kerberosStatus ( ) = = KerberosInUse ) {
char data [ 1 ] ;
data [ 0 ] = ch ;
if ( writeBlock ( data , 1 ) < 1 ) {
ret = - 1 ;
}
else {
ret = ch ;
}
}
else {
ret = TQSocket : : putch ( ch ) ;
}
return ret ;
}
int TDEKerberosServerSocket : : ungetch ( int ch ) {
int ret ;
if ( kerberosStatus ( ) = = KerberosInUse ) {
// FIXME
// UNIMPLEMENTED
// This feature, if supported, will be very expensive, requiring a full allocation+copy/shift+deallocation of the buffer array,
// followed by insertion of the new character to the head of the array
ret = - 1 ;
}
else {
ret = TQSocket : : ungetch ( ch ) ;
}
return ret ;
}
TQ_ULONG TDEKerberosServerSocket : : bytesAvailable ( ) const {
TQ_ULONG ret ;
if ( kerberosStatus ( ) = = KerberosInUse ) {
ret = m_bufferLength ;
}
else {
ret = TQSocket : : bytesAvailable ( ) ;
}
return ret ;
}
int TDEKerberosServerSocket : : processPendingData ( ) {
if ( kerberosStatus ( ) = = KerberosInUse ) {
while ( TQSocket : : canReadLine ( ) & & ( TQSocket : : state ( ) = = TQSocket : : Connected ) ) {
int reclen ;
int wrlen ;
char * buf = ( char * ) malloc ( m_negotiatedMaxBufferSize ) ;
reclen = receiveEncryptedData ( buf , m_negotiatedMaxBufferSize , false ) ;
if ( reclen < 0 ) {
free ( buf ) ;
return - 1 ;
}
if ( reclen > 0 ) {
m_buffer - > at ( m_bufferLength + m_bufferReadPointer ) ;
wrlen = m_buffer - > writeBlock ( buf , reclen ) ;
if ( wrlen > 0 ) {
m_bufferLength = m_bufferLength + wrlen ;
emit ( newDataReceived ( ) ) ;
}
}
free ( buf ) ;
}
}
return 0 ;
}
int TDEKerberosServerSocket : : setUsingKerberos ( bool krbactive ) {
int ret = 0 ;
if ( ( m_serviceName = = " " ) | | ( tde_krb_sasl_server_appname = = " " ) ) {
printf ( " [ERROR] No service name set! \n \r " ) ; fflush ( stdout ) ;
return - 1 ;
}
if ( krbactive ) {
m_kerberosRequested = true ;
if ( ( ! saslData - > m_krbConnection ) & & ( state ( ) = = TQSocket : : Connected ) ) {
ret = initializeKerberosInterface ( ) ;
}
}
else {
m_kerberosRequested = false ;
if ( saslData - > m_krbConnection ) {
freeKerberosConnection ( ) ;
}
}
return ret ;
}
void TDEKerberosServerSocket : : setServiceName ( TQString name ) {
m_serviceName = name ;
if ( ! tde_krb_sasl_server_initialized ) {
tde_krb_sasl_server_appname = name ;
}
else {
if ( tde_krb_sasl_server_appname ! = name ) {
printf ( " [WARNING] Attempt was made to change application name after initial Kerberos connection was tried. Application name was NOT changed! \n \r " ) ; fflush ( stdout ) ;
}
}
}
void TDEKerberosServerSocket : : setServerFQDN ( TQString name ) {
m_serverFQDN = name ;
}
TQ_LONG TDEKerberosServerSocket : : readBlock ( char * data , TQ_ULONG maxlen ) {
long i ;
TQ_LONG ret ;
if ( m_kerberosRequested ) {
int reclen ;
int wrlen ;
if ( m_bufferLength < = 0 ) {
char * buf = ( char * ) malloc ( m_negotiatedMaxBufferSize ) ;
reclen = receiveEncryptedData ( buf , m_negotiatedMaxBufferSize , false ) ;
if ( reclen < 0 ) {
free ( buf ) ;
return - 1 ;
}
if ( reclen > 0 ) {
m_buffer - > at ( m_bufferLength + m_bufferReadPointer ) ;
wrlen = m_buffer - > writeBlock ( buf , reclen ) ;
if ( wrlen > 0 ) {
m_bufferLength = m_bufferLength + wrlen ;
emit ( newDataReceived ( ) ) ;
}
}
free ( buf ) ;
}
if ( maxlen > ( unsigned int ) m_bufferLength ) {
maxlen = m_bufferLength ;
}
m_buffer - > at ( m_bufferReadPointer ) ;
ret = m_buffer - > readBlock ( data , maxlen ) ;
if ( ret > 0 ) {
// Remove the read bytes from the buffer
m_bufferLength = m_bufferLength - ret ;
m_bufferReadPointer = m_bufferReadPointer + ret ;
if ( m_bufferLength < 1 ) {
// Clear the buffer from memory
m_buffer - > close ( ) ;
m_buffer - > open ( IO_ReadWrite | IO_Truncate ) ;
m_bufferReadPointer = 0 ;
}
}
}
else {
ret = TQSocket : : readBlock ( data , maxlen ) ;
}
return ret ;
}
TQ_LONG TDEKerberosServerSocket : : writeBlock ( const char * data , TQ_ULONG len ) {
TQ_LONG ret ;
if ( m_kerberosRequested ) {
ret = transmitEncryptedData ( data , len ) ;
}
else {
ret = TQSocket : : writeBlock ( data , len ) ;
}
return ret ;
}
TQ_LONG TDEKerberosServerSocket : : readLine ( char * data , TQ_ULONG maxlen ) {
long i ;
TQ_LONG ret ;
if ( m_kerberosRequested ) {
int reclen ;
int wrlen ;
if ( m_bufferLength < = 0 ) {
char * buf = ( char * ) malloc ( m_negotiatedMaxBufferSize ) ;
reclen = receiveEncryptedData ( buf , m_negotiatedMaxBufferSize , false ) ;
if ( reclen < 0 ) {
free ( buf ) ;
return - 1 ;
}
if ( reclen > 0 ) {
m_buffer - > at ( m_bufferLength + m_bufferReadPointer ) ;
wrlen = m_buffer - > writeBlock ( buf , reclen ) ;
if ( wrlen > 0 ) {
m_bufferLength = m_bufferLength + wrlen ;
emit ( newDataReceived ( ) ) ;
}
}
free ( buf ) ;
}
if ( maxlen > ( unsigned int ) m_bufferLength ) {
maxlen = m_bufferLength ;
}
m_buffer - > at ( m_bufferReadPointer ) ;
ret = m_buffer - > readLine ( data , maxlen ) ;
if ( ret > 0 ) {
// Remove the read bytes from the buffer
m_bufferLength = m_bufferLength - ret ;
m_bufferReadPointer = m_bufferReadPointer + ret ;
if ( m_bufferLength < 1 ) {
// Clear the buffer from memory
m_buffer - > close ( ) ;
m_buffer - > open ( IO_ReadWrite | IO_Truncate ) ;
m_bufferReadPointer = 0 ;
}
}
}
else {
ret = TQSocket : : readLine ( data , maxlen ) ;
}
return ret ;
}
TQString TDEKerberosServerSocket : : readLine ( ) {
long i ;
TQString ret ;
long maxlen ;
if ( m_kerberosRequested ) {
int reclen ;
int wrlen ;
int readlen ;
char * buf ;
maxlen = m_negotiatedMaxBufferSize ;
if ( m_bufferLength < = 0 ) {
buf = ( char * ) malloc ( m_negotiatedMaxBufferSize ) ;
reclen = receiveEncryptedData ( buf , m_negotiatedMaxBufferSize , false ) ;
if ( reclen < 0 ) {
free ( buf ) ;
return TQString : : null ;
}
if ( reclen > 0 ) {
m_buffer - > at ( m_bufferLength + m_bufferReadPointer ) ;
wrlen = m_buffer - > writeBlock ( buf , reclen ) ;
if ( wrlen > 0 ) {
m_bufferLength = m_bufferLength + wrlen ;
emit ( newDataReceived ( ) ) ;
}
}
free ( buf ) ;
}
if ( maxlen > m_bufferLength ) {
maxlen = m_bufferLength ;
}
m_buffer - > at ( m_bufferReadPointer ) ;
buf = ( char * ) malloc ( maxlen ) ;
readlen = m_buffer - > readLine ( buf , maxlen ) ;
if ( readlen > 0 ) {
// Remove the read bytes from the buffer
m_bufferLength = m_bufferLength - readlen ;
m_bufferReadPointer = m_bufferReadPointer + readlen ;
if ( m_bufferLength < 1 ) {
// Clear the buffer from memory
m_buffer - > close ( ) ;
m_buffer - > open ( IO_ReadWrite | IO_Truncate ) ;
m_bufferReadPointer = 0 ;
}
ret = TQString ( buf ) ;
}
else {
ret = = TQString : : null ;
}
free ( buf ) ;
}
else {
ret = TQSocket : : readLine ( ) ;
}
return ret ;
}
void TDEKerberosServerSocket : : writeLine ( TQString str ) {
if ( m_kerberosRequested ) {
transmitEncryptedData ( str . ascii ( ) , str . length ( ) ) ;
}
else {
TQSocket : : writeBlock ( str . ascii ( ) , str . length ( ) ) ;
}
}
void TDEKerberosServerSocket : : freeKerberosConnection ( void ) {
if ( saslData - > m_krbConnection ) {
sasl_dispose ( & saslData - > m_krbConnection ) ;
}
saslData - > m_krbConnection = 0 ;
}
void TDEKerberosServerSocket : : sendSASLDataToNetwork ( const char * buffer , unsigned length ) {
char * buf ;
unsigned len , alloclen ;
int result ;
alloclen = ( ( ( length / 3 ) + 1 ) * 4 ) + 1 ;
buf = ( char * ) malloc ( alloclen + 1 ) ;
if ( ! buf ) {
printf ( " [ERROR] Unable to malloc()! \n \r " ) ;
return ;
}
result = sasl_encode64 ( buffer , length , buf , alloclen , & len ) ;
if ( result ! = SASL_OK ) {
printf ( " [ERROR] Encoding data in base64 returned %s (%d) \n \r " , sasl_errstring ( result , NULL , NULL ) , result ) ;
return ;
}
len = strlen ( buf ) ;
buf [ len ] = ' \n ' ;
buf [ len + 1 ] = 0 ;
if ( TQSocket : : writeBlock ( buf , len + 1 ) < ( len + 1 ) ) {
printf ( " [WARNING] Transmitting data in base64 failed due to short write \n \r " ) ;
}
free ( buf ) ;
}
int TDEKerberosServerSocket : : getSASLDataFromNetwork ( char * buf , int trunclen , bool shouldblock ) {
m_criticalSection + + ;
try {
unsigned int len ;
int result ;
TQCString ba ;
if ( ! shouldblock ) {
if ( ( ! TQSocket : : canReadLine ( ) ) | | ( state ( ) ! = TQSocket : : Connected ) ) {
return 0 ;
}
}
len = 0 ;
TQTimer dataTimeoutTimer ;
if ( m_dataTimeout > 0 ) {
dataTimeoutTimer . start ( m_dataTimeout , TRUE ) ;
}
while ( dataTimeoutTimer . isActive ( ) | | ( m_dataTimeout < 0 ) ) {
if ( ! TQSocket : : canReadLine ( ) ) {
if ( ( shouldblock ) & & ( dataTimeoutTimer . isActive ( ) | | ( m_dataTimeout < 0 ) ) ) {
SAFELY_PROCESS_EVENTS
}
}
if ( state ( ) ! = TQSocket : : Connected ) {
m_criticalSection - - ;
return - 1 ;
}
if ( TQSocket : : canReadLine ( ) ) {
TQString base64string = TQSocket : : readLine ( ) ;
base64string . truncate ( base64string . length ( ) - 1 ) ;
ba = base64string ;
break ;
}
else {
if ( shouldblock ) {
usleep ( 1000 ) ;
}
else {
break ;
}
}
}
if ( ! ba . isNull ( ) ) {
len = strlen ( ba . data ( ) ) ;
result = sasl_decode64 ( ba . data ( ) , len , buf , trunclen , & len ) ;
if ( result ! = SASL_OK ) {
printf ( " [ERROR] Decoding data from base64 returned %s (%d) \n \r " , sasl_errstring ( result , NULL , NULL ) , result ) ;
m_criticalSection - - ;
return - 1 ;
}
buf [ len ] = ' \0 ' ;
}
else {
buf [ 0 ] = ' \0 ' ;
}
m_criticalSection - - ;
return len ;
}
catch ( exit_exception & e ) {
m_criticalSection - - ;
return - 1 ;
}
}
int TDEKerberosServerSocket : : transmitEncryptedData ( const char * readbuf , int cc ) {
int result = 0 ;
unsigned int len ;
const char * data ;
long data_remaining ;
long remnant_position ;
TQTimer dataTimeoutTimer ;
if ( m_dataTimeout > 0 ) {
dataTimeoutTimer . start ( m_dataTimeout , TRUE ) ;
}
data_remaining = cc ;
remnant_position = 0 ;
while ( ( data_remaining > 0 ) & & ( dataTimeoutTimer . isActive ( ) | | ( m_dataTimeout < 0 ) ) ) {
int data_to_write_len ;
if ( data_remaining > ( m_negotiatedMaxBufferSize / 2 ) ) {
data_to_write_len = m_negotiatedMaxBufferSize / 2 ;
}
else {
data_to_write_len = data_remaining ;
}
result = sasl_encode ( saslData - > m_krbConnection , readbuf + remnant_position , data_to_write_len , & data , & len ) ;
if ( result ! = SASL_OK ) {
printf ( " [ERROR] Encrypting data returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , result ) ;
return - 1 ;
}
sendSASLDataToNetwork ( data , len ) ;
data_remaining = data_remaining - data_to_write_len ;
remnant_position = remnant_position + data_to_write_len ;
if ( ( data_remaining > 0 ) & & ( dataTimeoutTimer . isActive ( ) | | ( m_dataTimeout < 0 ) ) ) {
SAFELY_PROCESS_EVENTS
}
}
return cc ;
}
int TDEKerberosServerSocket : : receiveEncryptedData ( char * buf , unsigned int trunclen , bool shouldblock ) {
unsigned int recv_len ;
const char * recv_data ;
int result ;
int len ;
char * encbuf = ( char * ) malloc ( m_negotiatedMaxBufferSize ) ;
len = getSASLDataFromNetwork ( encbuf , m_negotiatedMaxBufferSize , shouldblock ) ;
if ( len < 0 ) {
return - 1 ;
}
if ( len > = 0 ) {
result = sasl_decode ( saslData - > m_krbConnection , encbuf , len , & recv_data , & recv_len ) ;
if ( result ! = SASL_OK ) {
free ( encbuf ) ;
printf ( " [ERROR] Decrypting data returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , result ) ;
return - 1 ;
}
if ( recv_len > trunclen ) {
recv_len = trunclen ;
}
memcpy ( buf , recv_data , recv_len ) ;
}
free ( encbuf ) ;
return recv_len ;
}
TDEKerberosServerSocket : : KerberosStatus TDEKerberosServerSocket : : kerberosStatus ( ) const {
if ( ! m_kerberosRequested ) {
return KerberosNotRequested ;
}
if ( m_krbInitRunning ) {
return KerberosInitializing ;
}
if ( m_krbInitState < 0 ) {
return KerberosFailure ;
}
return KerberosInUse ;
}
bool TDEKerberosServerSocket : : canReadData ( ) {
return ( TQSocket : : canReadLine ( ) | | ( m_bufferLength > 0 ) ) ;
}
void TDEKerberosServerSocket : : clearIncomingData ( ) {
char data [ 64 ] ;
processPendingData ( ) ;
while ( canReadData ( ) ) {
readBlock ( data , 64 ) ;
}
}
int TDEKerberosServerSocket : : writeEndOfFrame ( ) {
char data [ 1 ] ;
data [ 0 ] = 255 ;
return writeBlock ( data , 1 ) ;
}
bool TDEKerberosServerSocket : : canReadFrame ( ) {
processPendingData ( ) ;
if ( m_bufferLength > 0 ) {
if ( m_buffer - > buffer ( ) . find ( 255 , m_bufferReadPointer ) > = 0 ) {
return true ;
}
else {
return false ;
}
}
else {
return false ;
}
}
void TDEKerberosServerSocket : : clearFrameTail ( ) {
int i ;
int eofLoc ;
if ( m_bufferLength > 0 ) {
eofLoc = m_buffer - > buffer ( ) . find ( 255 , m_bufferReadPointer ) + 1 ;
if ( ( eofLoc > 0 ) & & ( eofLoc < = ( m_bufferLength + m_bufferReadPointer ) ) ) {
// Remove the remaining frame bytes (including the End of Frame marker) from the buffer
m_bufferLength = m_bufferLength - ( eofLoc - m_bufferReadPointer ) ;
m_bufferReadPointer = m_bufferReadPointer + ( eofLoc - m_bufferReadPointer ) ;
if ( m_bufferLength < 1 ) {
// Clear the buffer from memory
m_buffer - > close ( ) ;
m_buffer - > open ( IO_ReadWrite | IO_Truncate ) ;
m_bufferReadPointer = 0 ;
}
}
}
}
void TDEKerberosServerSocket : : setStatusMessage ( TQString message ) {
if ( message ! = m_prevStatusMessage ) {
emit ( statusMessageUpdated ( message ) ) ;
m_prevStatusMessage = message ;
}
}
void TDEKerberosServerSocket : : continueKerberosInitialization ( ) {
int slen ;
char buf [ NET_SEC_BUF_SIZE ] ;
sasl_ssf_t * ssf ;
if ( m_krbInitRunning ) {
switch ( m_krbInitState ) {
case 0 :
if ( state ( ) = = TQSocket : : Connected ) {
setStatusMessage ( i18n ( " Waiting for client mechanism " ) ) ;
if ( canReadLine ( ) ) {
printf ( " [DEBUG] Waiting for client mechanism... \n \r " ) ;
slen = getSASLDataFromNetwork ( buf , NET_SEC_BUF_SIZE ) ;
if ( slen < 0 ) {
m_krbInitState = - 2 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
m_krbInitLastLen = slen ;
if ( strlen ( buf ) < m_krbInitLastLen ) {
printf ( " [DEBUG] Initial response received \n \r " ) ;
// An initial response is present
m_krbInitData = buf + strlen ( buf ) + 1 ;
m_krbInitLastLen = m_krbInitLastLen - ( unsigned ) strlen ( buf ) - 1 ;
}
else {
m_krbInitData = NULL ;
m_krbInitLastLen = 0 ;
}
m_krbInitResult = sasl_server_start ( saslData - > m_krbConnection , buf , m_krbInitData , m_krbInitLastLen , & m_krbInitData , & m_krbInitLastLen ) ;
if ( m_krbInitResult ! = SASL_OK & & m_krbInitResult ! = SASL_CONTINUE ) {
printf ( " [ERROR] Starting SASL negotiation returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , m_krbInitResult ) ;
freeKerberosConnection ( ) ;
m_krbInitState = - 1 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
m_krbInitState = 1 ;
}
}
else {
m_krbInitState = - 3 ;
m_krbInitRunning = false ;
}
break ;
case 1 :
if ( state ( ) = = TQSocket : : Connected ) {
if ( m_krbInitResult = = SASL_CONTINUE ) {
if ( m_krbInitData ) {
printf ( " [DEBUG] Sending response... \n \r " ) ;
sendSASLDataToNetwork ( m_krbInitData , m_krbInitLastLen ) ;
}
else {
printf ( " [ERROR] No data to send! \n \r " ) ;
freeKerberosConnection ( ) ;
m_krbInitState = - 1 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
m_krbInitState = 2 ;
}
else {
printf ( " [DEBUG] Negotiation complete \n \r " ) ;
m_krbInitState = 3 ;
}
}
else {
m_krbInitState = - 3 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
break ;
case 2 :
if ( state ( ) = = TQSocket : : Connected ) {
setStatusMessage ( i18n ( " Waiting for client reply " ) ) ;
if ( canReadLine ( ) ) {
printf ( " [DEBUG] Waiting for client reply... \n \r " ) ;
slen = getSASLDataFromNetwork ( buf , NET_SEC_BUF_SIZE ) ;
if ( slen < 0 ) {
m_krbInitState = - 2 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
m_krbInitLastLen = slen ;
m_krbInitData = NULL ;
m_krbInitResult = sasl_server_step ( saslData - > m_krbConnection , buf , m_krbInitLastLen , & m_krbInitData , & m_krbInitLastLen ) ;
if ( m_krbInitResult ! = SASL_OK & & m_krbInitResult ! = SASL_CONTINUE ) {
printf ( " [ERROR] Performing SASL negotiation returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , m_krbInitResult ) ;
freeKerberosConnection ( ) ;
m_krbInitState = - 1 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
m_krbInitState = 1 ;
}
}
else {
m_krbInitState = - 3 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
break ;
case 3 :
if ( state ( ) = = TQSocket : : Connected ) {
if ( m_krbInitServerLast & & m_krbInitData ) {
printf ( " [DEBUG] Additional information needed to be sent \n \r " ) ;
sendSASLDataToNetwork ( m_krbInitData , m_krbInitLastLen ) ;
}
m_krbInitResult = sasl_getprop ( saslData - > m_krbConnection , SASL_USERNAME , ( const void * * ) & m_krbInitData ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [WARNING] Unable to determine authenticated username! \n \r " ) ;
}
else {
m_authenticatedUserName = m_krbInitData ? m_krbInitData : " (NULL) " ;
printf ( " [DEBUG] Authenticated username: %s \n \r " , m_authenticatedUserName . ascii ( ) ) ;
}
#if 0
m_krbInitResult = sasl_getprop ( saslData - > m_krbConnection , SASL_DEFUSERREALM , ( const void * * ) & m_krbInitData ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [WARNING] Unable to determine authenticated realm! \n \r " ) ;
}
else {
m_authenticatedRealmName = m_krbInitData ? m_krbInitData : " (NULL) " ;
printf ( " [DEBUG] Authenticated realm: %s \n \r " , m_authenticatedRealmName . ascii ( ) ) ;
}
# else
m_authenticatedRealmName = " (NULL) " ;
# endif
m_krbInitResult = sasl_getprop ( saslData - > m_krbConnection , SASL_SSF , ( const void * * ) & ssf ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [WARNING] Unable to determine SSF! \n \r " ) ;
}
else {
printf ( " [DEBUG] Authenticated SSF: %d \n " , * ssf ) ;
}
m_krbInitResult = sasl_getprop ( saslData - > m_krbConnection , SASL_MAXOUTBUF , ( const void * * ) & m_negotiatedMaxBufferSize ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [WARNING] Unable to determine maximum buffer size! \n \r " ) ;
m_negotiatedMaxBufferSize = NET_SEC_BUF_SIZE ;
}
else {
// For some reason m_negotiatedMaxBufferSize can be set negative under certain circumstances
// Prevent that from happening!
if ( m_negotiatedMaxBufferSize < NET_SEC_BUF_SIZE ) {
m_negotiatedMaxBufferSize = NET_SEC_BUF_SIZE ;
}
printf ( " [DEBUG] Maximum buffer size: %d \n " , m_negotiatedMaxBufferSize ) ;
}
m_krbInitState = 4 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection established " ) ) ;
return ;
}
else {
m_krbInitState = - 3 ;
m_krbInitRunning = false ;
setStatusMessage ( i18n ( " Kerberos connection failed " ) ) ;
return ;
}
break ;
}
if ( kerberosInitLoopTimer ) kerberosInitLoopTimer - > start ( 0 , TRUE ) ;
}
}
int TDEKerberosServerSocket : : initializeKerberosInterface ( ) {
if ( state ( ) ! = TQSocket : : Connected ) {
freeKerberosConnection ( ) ;
return - 1 ;
}
sasl_callback_t * callback ;
m_krbInitResult = 0 ;
m_krbInitServerLast = 0 ;
sasl_security_properties_t secprops ;
const char * ext_authid = NULL ;
int count ;
// FIXME
// Populate these fields!
char * iplocal = NULL ;
char * ipremote = NULL ;
char * localdomain = NULL ;
char * userdomain = NULL ;
callback = tde_krb_sasl_server_callbacks ;
// log
callback - > id = SASL_CB_LOG ;
callback - > proc = ( sasl_callback_ft ) & logSASLMessages ;
callback - > context = NULL ;
+ + callback ;
// end of callback list
callback - > id = SASL_CB_LIST_END ;
callback - > proc = NULL ;
callback - > context = NULL ;
+ + callback ;
// Initialize default data structures
memset ( & secprops , 0L , sizeof ( secprops ) ) ;
secprops . maxbufsize = NET_SEC_BUF_SIZE ;
secprops . max_ssf = UINT_MAX ;
if ( ! tde_krb_sasl_server_initialized ) {
m_krbInitResult = sasl_server_init ( tde_krb_sasl_server_callbacks , tde_krb_sasl_server_appname . ascii ( ) ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [ERROR] Initializing libsasl returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , m_krbInitResult ) ;
return - 1 ;
}
tde_krb_sasl_server_initialized = true ;
}
m_krbInitResult = sasl_server_new ( m_serviceName . ascii ( ) , localdomain , userdomain , iplocal , ipremote , NULL , m_krbInitServerLast , & saslData - > m_krbConnection ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [ERROR] Allocating sasl connection state returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , m_krbInitResult ) ;
return - 1 ;
}
m_krbInitResult = sasl_setprop ( saslData - > m_krbConnection , SASL_SEC_PROPS , & secprops ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [ERROR] Setting security properties returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , m_krbInitResult ) ;
freeKerberosConnection ( ) ;
return - 1 ;
}
puts ( " [DEBUG] Generating client mechanism list... " ) ;
m_krbInitResult = sasl_listmech ( saslData - > m_krbConnection , ext_authid , NULL , " " , NULL , & m_krbInitData , & m_krbInitLastLen , & count ) ;
if ( m_krbInitResult ! = SASL_OK ) {
printf ( " [ERROR] Generating client mechanism list returned %s (%d) \n \r " , safe_sasl_errdetail ( saslData - > m_krbConnection ) , m_krbInitResult ) ;
freeKerberosConnection ( ) ;
return - 1 ;
}
printf ( " [DEBUG] Sending list of %d mechanism(s) \n \r " , count ) ;
sendSASLDataToNetwork ( m_krbInitData , m_krbInitLastLen ) ;
m_krbInitRunning = true ;
m_krbInitState = 0 ;
if ( ! kerberosInitLoopTimer ) {
kerberosInitLoopTimer = new TQTimer ( ) ;
connect ( kerberosInitLoopTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( continueKerberosInitialization ( ) ) ) ;
}
if ( kerberosInitLoopTimer ) kerberosInitLoopTimer - > start ( 0 , TRUE ) ;
return 0 ;
}