COSIGNSTATUS CookieDatabase::UpdateCookie( std::wstring& cookie ) { FILETIME curTime; HANDLE hcf; DWORD err; COSIGNSTATUS status = COSIGNOK; std::wstring cookiePath = L"\\\\?\\" + path + cookie; hcf = CreateFile( cookiePath.c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hcf == INVALID_HANDLE_VALUE ) { err = GetLastError(); CosignLog( L"Could not update cookie time, CreateFile failed with 0x%x", err ); //throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); return( COSIGNERROR ); } GetSystemTimeAsFileTime( &curTime ); if ( !SetFileTime( hcf, NULL, NULL, &curTime ) ) { err = GetLastError(); CosignLog( L"Could not update cookie time for %s, SetFileTime failed with 0x%x", cookiePath.c_str(), err ); status = COSIGNERROR; } if ( !CloseHandle( hcf ) ) { err = GetLastError(); CosignLog( L"Could not CloseHandle for file %s, CloseHandle failed with 0x%x", cookiePath.c_str(), err ); status = COSIGNERROR; } return( status ); }
bool ConnectionList::getProxyCookies() { CosignLog( L"proxyCookiesDirectory is set to %s", proxyCookiesDirectory.c_str() ); CosignLog( L"proxyCookiesDirector.empty() = %s", (proxyCookiesDirectory.empty() ? L"true" : L"false" ) ); if ( proxyCookiesDirectory == L"\\\\?\\" || proxyCookiesDirectory.empty() ) { if ( proxyCookiesDirectory == L"\\\\?\\" ) { CosignLog( L"proxyCookiesDirectory == \\\\?\\" ); } if ( proxyCookiesDirectory.empty() ) { CosignLog( L"proxyCookiesDirectory.empty()" ); } return( false ); } return( true ); }
int StringToWString( std::string& str, std::wstring& wstr ) { DWORD bufferSize = (DWORD)((str.length() + 1)*2); PWCHAR buffer = new WCHAR[ bufferSize ]; size_t charsConverted; errno_t err; err = mbstowcs_s( &charsConverted, buffer, bufferSize, str.c_str(), bufferSize - 1); if ( err != 0 ) { CosignLog( "mbstowcs_s( %s ) failed with %d", str.c_str(), err ); return( -1 ); } wstr = buffer; delete buffer; return( 0 ); }
int ConnectionList::Populate() { if ( numServers > 0 ) { /// Probably throw some sort of error if already populated? /// Or, assume caller wants to "repopulate" and should destroy all current connections before making new ones? return( 0 ); } if ( certificateContext == NULL ) { CosignLog( L"Certificate context is NULL." ); throw( CosignError( -1, __LINE__ -1, __FUNCTION__ ) ); } PADDRINFOW aiList = NULL; int err = GetAddrInfo( server.c_str(), NULL, NULL, &aiList ); if ( err != 0 ) { CosignLog( L"GetAddrInfo %s failed, error code %d", server.c_str(), (DWORD)WSAGetLastError()); return( 0 ); } PADDRINFOW aiCur = NULL; SOCKET s; struct sockaddr_in sin; memset( &sin, 0, sizeof( struct sockaddr_in ) ); sin.sin_port = htons( port ); sin.sin_family = AF_INET; Snet* snet; for ( aiCur = aiList, numServers = 0; aiCur != NULL; aiCur = aiCur->ai_next, s = INVALID_SOCKET ) { if ( aiCur->ai_family != AF_INET ) { CosignLog( L"Skipping non-IPv4 address for %s", server.c_str()); continue; } CosignTrace1( "aiCur->ai_addr: %s\n", inet_ntoa( ((struct sockaddr_in*)(aiCur->ai_addr))->sin_addr ) ); if ( (s = socket( AF_INET, SOCK_STREAM, NULL )) == INVALID_SOCKET ) { CosignLog( L"socket creation to %s failed, error code %d", inet_ntoa( ((struct sockaddr_in*)(aiCur->ai_addr))->sin_addr ), (DWORD)WSAGetLastError()); continue; } sin.sin_addr.S_un = ((struct sockaddr_in*)(aiCur->ai_addr))->sin_addr.S_un; if ( connect( s, (struct sockaddr*)&sin, sizeof(struct sockaddr_in) ) == SOCKET_ERROR ) { CosignLog( "connect to %s failed, error code %d", inet_ntoa( ((struct sockaddr_in*)(aiCur->ai_addr))->sin_addr ), (DWORD)WSAGetLastError()); continue; } snet = new Snet(); snet->attach( s ); snet->getLine(); CosignTrace1( "<< %s", snet->data.c_str() ); Add( snet ); // only increment if we actually added a server to the connection list. numServers++; } return( numServers ); }
void ConnectionList::RetrieveKerberosTicket() { CosignLog( L"Kerberos ticket retrievel not yet implemented." ); }
void ConnectionList::RetrieveProxyCookies( std::string& cookie ) { if ( curConnection == NULL ) { CosignLog( L"Current connection is not set. Could not retrieve proxy cookies." ); return; } HANDLE hpf = INVALID_HANDLE_VALUE; DWORD bytesWritten = 0; DWORD err; DWORD success = 0; std::string in; std::basic_string <char>::size_type index; std::basic_string <char>::size_type last; std::string crlf = "\r\n"; std::string line; std::string status; try { // Create file to hold proxy cookie data WCHAR tempFileName[ 32768 ]; CosignTrace1( L"proxy Cookies Diretory path = %s", proxyCookiesDirectory.c_str() ); if ( GetTempFileName( proxyCookiesDirectory.c_str(), L"pck", 0, tempFileName ) == 0 ) { err = GetLastError(); CosignLog( L"GetTempFileName failed with 0x%x", err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } CosignTrace1( L"tempFileName = %s", tempFileName ); hpf = CreateFile( tempFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL ); if ( hpf == INVALID_HANDLE_VALUE ) { err = GetLastError(); CosignLog( L"CreateFile failed with 0x%x", err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } // Retrieve proxy cookies and store Snet* snet = curConnection; std::string out = "RETR " + cookie + " cookies\r\n"; CosignTrace1( ">> %s", out.c_str() ); if ( snet->write( out ) == -1 ) { CosignLog( "Error writing data to socket \"%s\"\n", out.c_str() ); goto done; } while(1) { if ( snet->getLine() == -1 ) { CosignLog( L"Error reading data from socket" ); goto done; } in = snet->data; for ( index = 0; index < in.length(); index += 2 ) { last = index; index = in.find( crlf, index ); line = in.substr( last, index - last ); CosignTrace1( "Parsed line << %s", line.c_str() ); if ( line.length() < 4 ) { CosignTrace1( "Error RETR cookies. Expected more data: %s", in.c_str() ); goto done; } status = line.substr( 0, 4 ); if ( status[ 0 ] != '2' || !isdigit( status[ 1 ] ) || !isdigit( status[ 2 ] ) ) { CosignTrace1( "Error RETR cookies. Server replied: %s", in.c_str() ); goto done; } if ( status[ 3 ] == '-' ) { // Write cookie to file bytesWritten = 0; line.replace( 0, 4, "" ); line += "\r\n"; const char* szLine = line.c_str(); CosignTrace1( "Writing to file: %s", line.c_str() ); if ( !WriteFile( hpf, line.c_str(), (DWORD)line.length(), &bytesWritten, NULL ) ) { err = GetLastError(); CosignLog( L"WriteFile(%s) failed with 0x%x", out.c_str(), err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } } } if ( status.length() >= 4 && status[ 3 ] != '-' ) { CosignTrace0( L"Breaking out of RETR loop" ); success = 1; break; } } done: if ( hpf != INVALID_HANDLE_VALUE ) { if ( !CloseHandle( hpf ) ) { CosignLog( L"CloseHandle( proxyTmpFile ) failed with 0x%x", GetLastError() ); } } if ( !success ) { CosignLog( L"Failed to retrieve proxy cookies" ); return; } std::wstring wcookie; StringToWString( cookie, wcookie ); index = wcookie.find( L'=' ); index++; if ( index != std::wstring::npos ) { wcookie.replace( 0, index, L"" ); } std::wstring proxyCookiePath = this->proxyCookiesDirectory + wcookie; CosignTrace2( L"Copying %s to %s", tempFileName, proxyCookiePath.c_str() ); if ( !CopyFileEx( tempFileName, proxyCookiePath.c_str(), NULL, NULL, FALSE, 0 ) ) { err = GetLastError(); CosignLog( L"Could not copy file %s to %s: 0x%x", tempFileName, proxyCookiePath.c_str(), err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } if ( !DeleteFile( tempFileName ) ) { err = GetLastError(); CosignLog( L"Could not delete temp file %s: 0x%x", tempFileName, err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } } catch ( CosignError ce ) { if ( hpf != INVALID_HANDLE_VALUE ) { if ( !CloseHandle( hpf ) ) { CosignLog( L"CloseHandle( proxyTmpFile ) failed with 0x%x", GetLastError() ); } } ce.showError(); } }
COSIGNSTATUS ConnectionList::CheckCookie( std::string* cookie, CosignServiceInfo* csi, BOOL tryAgain ) { Snet* snet; std::string out; std::string in; int goodConnections = 0; COSIGNSTATUS status = COSIGNRETRY; CosignTrace1( L"connections.size() = %d", connections.size() ); for( unsigned int i = 0; i < connections.size() && status == COSIGNRETRY; i++ ) { curConnection = snet = connections[ i ]; CosignTrace1( L"CheckCookie iter %d", i ); if ( !snet->tlsStarted() ) { out = "STARTTLS 2\r\n"; CosignTrace1( ">> %s", out.c_str() ); if ( snet->write( out ) == -1 ) { /// xxx on errors, delete connection? Mark it as bad? CosignLog( L"Error writing data to socket %d\n", i ); continue; } if ( snet->getLine() == -1 ) { CosignLog( L"Error reading data from socket %d\n", i ); continue; } CosignTrace1( "<< %s", snet->data.c_str() ); if ( snet->startTls( certificateContext, (WCHAR*)server.c_str() ) != 0 ) { CosignLog( L"Error starting TLS on socket %d\n", i ); snet->close(); continue; } if ( snet->getLine() == -1 ) { CosignLog( L"Error reading data(3) from socket %d\n", i ); continue; } CosignTrace1( "<< %s\n", snet->data.c_str() ); } out = "CHECK " + *cookie + "\r\n"; CosignTrace1( ">> %s", out.c_str() ); if ( snet->write( out ) == -1 ) { CosignLog( L"Error writing data(2) to socket %d\n", i ); continue; } if ( snet->getLine() == -1 ) { CosignLog( L"Error reading data(4) from socket %d\n", i ); continue; } CosignTrace1( "<< %s", snet->data.c_str() ); in = snet->data; switch( in[ 0 ] ) { case '2': // Success! CosignTrace1( "Server returned 2xx: %s", in.c_str() ); status = COSIGNLOGGEDIN; break; case '4': // Logged out CosignTrace1( "User is logged out: %s", in.c_str() ); status = COSIGNLOGGEDOUT; break; case '5' : // Choose another connection CosignTrace1( "Trying a different server: %s", in.c_str() ); status = COSIGNRETRY; break; default : CosignLog( "Server returned unexpected response: %s", in.c_str() ); status = COSIGNERROR; break; } goodConnections++; } if (( connections.size() == 0 || goodConnections < connections.size() ) && tryAgain ) { /// repopulate and try again CosignTrace0( L"Repopulating and trying again..." ); Depopulate(); if ( Populate() <= 0 ) { CosignLog( L"Failed to repopulate the connection list" ); status = COSIGNRETRY; } else { status = CheckCookie( cookie, csi, FALSE ); } } /* * DAP UPENN: If status is COSIGNLOGGEDIN but goodConnnections is 0, * that means we repopulated and tried again successfully above and, * therefore, this block shouldn't run */ if ( status == COSIGNLOGGEDIN && goodConnections != 0) { CosignTrace0( L"Putting values into csi" ); std::vector<std::string> authData; std::stringstream cookieParser( in ); copy( std::istream_iterator<std::string>(cookieParser), std::istream_iterator<std::string>(), std::back_inserter(authData) ); if ( authData.size() < 4 ) { CosignLog( L"Incorrect number of arguments. Expected at least 4, received %d", (int)authData.size() ); return( COSIGNERROR ); } csi->ipAddr = authData[ 1 ]; csi->user = authData[ 2 ]; csi->strFactors = csi->realm = authData[ 3 ]; csi->factors.push_back( authData[ 3 ] ); for ( unsigned int i = 4; i < authData.size(); i++ ) { csi->strFactors += " " + authData[i]; csi->factors.push_back( authData[i] ); } csi->krb5TicketPath.clear(); } return( status ); }
COSIGNSTATUS CookieDatabase::CheckCookie( std::wstring& cookie, CosignServiceInfo* csi ) { HANDLE hcf = INVALID_HANDLE_VALUE; std::wstring cookiePath = L"\\\\?\\" + path + cookie; COSIGNSTATUS status = COSIGNOK; CosignLog( L"cookiePath = %s", cookiePath.c_str() ); try { hcf = CreateFile( cookiePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hcf == INVALID_HANDLE_VALUE ) { /// xxx should check for a fatal error /// in particular, if the error is something like "file does not exist", that is ok CosignLog( L"Could not obtain file handle for %s: 0x%x", cookiePath.c_str(), GetLastError() ); return( COSIGNOK ); } FILETIME fileTime; FILETIME currentTime; if ( !GetFileTime( hcf, NULL, NULL, &fileTime ) ) { CosignLog( L"Could not obtain file write time for %s", cookiePath.c_str() ); throw( CosignError( GetLastError(), __LINE__ -2, __FUNCTION__ ) ); } GetSystemTimeAsFileTime( ¤tTime ); ULARGE_INTEGER uliFt; ULARGE_INTEGER uliCt; uliFt.HighPart = fileTime.dwHighDateTime; uliFt.LowPart = fileTime.dwLowDateTime; uliCt.HighPart = currentTime.dwHighDateTime; uliCt.LowPart = currentTime.dwLowDateTime; ULONGLONG diff = uliCt.QuadPart - uliFt.QuadPart; ULONGLONG seconds = diff / 10000000; ULONGLONG minutes; minutes = seconds / 60; seconds = seconds % 60; CosignLog( L"Local cookie cache is %u minutes and %u seconds stale", (unsigned int)minutes, (unsigned int)seconds ); /// xxx sanity check? Make sure currenttime is later than filetime? if ( diff > expireTime ) { CloseHandle( hcf ); CosignLog( L"Cookie is too old." ); return( COSIGNLOGGEDOUT ); } /// xxx retrieve login info from local cookie file char readBuffer[ READBUFFERSIZE ]; DWORD bytesRead; std::string data = ""; while( ReadFile( hcf, readBuffer, READBUFFERSIZE, &bytesRead, NULL ) ) { if ( bytesRead == 0 ) { // EOF break; } data.append( readBuffer, bytesRead ); } CloseHandle( hcf ); hcf = INVALID_HANDLE_VALUE; // extract lines from cookie file data and put them into a vector for processing. std::string::size_type start = 0, end; std::vector<std::string> lines; std::string line; size_t found; while (( end = data.find( '\n', start )) != data.npos ) { line = data.substr( start, end - start ); found = line.find_last_not_of( "\r\n" ); if ( found != line.npos ) { line.erase( found + 1 ); } lines.push_back( line ); start = end + 1; } // walk the vector looking for key lines. // // i: initial client IP address // p: user name (i.e., a user principal, in Kerberos terms) // r: realm (i.e., primary authenticating factor, often a Kerberos realm) // f: all authenticated factors, separated by whitespace. for ( std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); iter++ ) { switch( (*iter)[ 0 ] ) { case 'i': csi->ipAddr = iter->substr( 1, iter->length() ); break; case 'p': csi->user = iter->substr( 1, iter->length() ); break; case 'r': csi->realm = iter->substr( 1, iter->length() ); break; case 'f': csi->strFactors = iter->substr( 1, iter->length()); // we split the whitespace-separated factor string into a vector below break; default: CosignLog( L"Cookie file contained unknown identifer %s", iter ); break; } } std::stringstream factorSplitter( csi->strFactors ); copy( std::istream_iterator<std::string>( factorSplitter ), std::istream_iterator<std::string>(), std::back_inserter( csi->factors )); if ( csi->factors.size() < 1 ) { CosignLog( L"Incorrect number of arguments. Expected at least 1, received %d", (int)csi->factors.size() ); return( COSIGNERROR ); } status = COSIGNLOGGEDIN; } catch ( CosignError ce ) { ce.showError(); status = COSIGNERROR; } if ( hcf != INVALID_HANDLE_VALUE ) { CloseHandle( hcf ); } CosignLog( L"Closed file handle." ); return( status ); }
COSIGNSTATUS CookieDatabase::StoreCookie( std::wstring& cookie, CosignServiceInfo* csi ) { DWORD err; WCHAR tempFileName[ 32768 ]; HANDLE hcf; COSIGNSTATUS status = COSIGNOK; try { CosignLog( L"path = %s", path.c_str() ); if ( GetTempFileName( path.c_str(), L"cck", 0, tempFileName ) == 0 ) { err = GetLastError(); CosignLog( L"GetTempFileName failed with 0x%x", err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } CosignLog( L"tempFileName = %s", tempFileName ); hcf = CreateFile( tempFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL ); if ( hcf == INVALID_HANDLE_VALUE ) { err = GetLastError(); CosignLog( L"CreateFile failed with 0x%x", err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } std::string out = "i" + csi->ipAddr + "\r\n"; DWORD bytesWritten = 0; if ( !WriteFile( hcf, out.c_str(), (DWORD)out.length(), &bytesWritten, NULL ) ) { err = GetLastError(); CosignLog( L"WriteFile(%s) failed with 0x%x", out.c_str(), err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } out = "p" + csi->user + "\r\n"; bytesWritten = 0; if ( !WriteFile( hcf, out.c_str(), (DWORD)out.length(), &bytesWritten, NULL ) ) { err = GetLastError(); CosignLog( L"WriteFile(%s) failed with 0x%x", out.c_str(), err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } out = "r" + csi->realm + "\r\n"; bytesWritten = 0; if ( !WriteFile( hcf, out.c_str(), (DWORD)out.length(), &bytesWritten, NULL ) ) { err = GetLastError(); CosignLog( L"WriteFile(%s) failed with 0x%x", out.c_str(), err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } out = "f" + csi->strFactors + "\r\n"; bytesWritten = 0; if ( !WriteFile( hcf, out.c_str(), (DWORD)out.length(), &bytesWritten, NULL ) ) { err = GetLastError(); CosignLog( L"WriteFile(%s) failed with 0x%x", out.c_str(), err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } if ( hcf != INVALID_HANDLE_VALUE ) { CloseHandle( hcf ); hcf = INVALID_HANDLE_VALUE; } std::wstring cookiePath = path + cookie; if ( !CopyFileEx( tempFileName, cookiePath.c_str(), NULL, NULL, FALSE, 0 ) ) { err = GetLastError(); CosignLog( L"Could not copy file %s to %s: 0x%x", tempFileName, cookiePath.c_str(), err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } if ( !DeleteFile( tempFileName ) ) { err = GetLastError(); CosignLog( L"Could not delete temp file %s: 0x%x", tempFileName, err ); throw( CosignError( err, __LINE__ - 2, __FUNCTION__ ) ); } } catch ( CosignError ce ) { ce.showError(); if ( hcf != INVALID_HANDLE_VALUE ) { CloseHandle( hcf ); } return( COSIGNERROR ); } return( status ); }