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 );
	}
Exemple #3
0
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( &currentTime );
		
		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 );
}