#include "SignonManager.h" SignonManager::SignonManager() { signonFile = NULL; } SignonManager::~SignonManager() { } void SignonManager::SetupFunctions(void *funList[]) { cryptManager.SetupFunctions(funList); } int SignonManager::OpenSignonFile(char *firefoxProfileDir, char *fileName, char *accessType ) { char *signonFilePath = NULL; signonFilePath = (char*) malloc( strlen(firefoxProfileDir) + strlen(fileName) + 3 ); if( signonFilePath == NULL ) { PrintMessage(MESG_ERROR, "\n Insufficient memory ...."); return FPM_INSUFFICIENT_MEMORY; } strcpy(signonFilePath, firefoxProfileDir); strcat(signonFilePath, "/"); strcat(signonFilePath, fileName); PrintMessage(MESG_DEBUG, "\n Final signon filename is = %s ", signonFilePath); // Open the signon file signonFile = fopen(signonFilePath, accessType); if( signonFile == NULL ) { PrintMessage(MESG_ERROR, "\n SignonManager : Error opening signon file %s", signonFilePath); free(signonFilePath); return FPM_SIGNON_FILE_NOT_PRESENT; } // cleanup free(signonFilePath); return FPM_TRUE; } int SignonManager::CloseSignonFile() { if( signonFile ) fclose(signonFile); return FPM_TRUE; } int SignonManager::ReadLine(char *buffer, int size) { Unichar c; int strLength = 0, i=0; buffer[0] = 0; while(1) { c = ReadCharUTF8(); /* note that eof is not set until we read past the end of the file */ if ( c == FPM_FALSE ) // || feof(file) ) return FPM_FALSE; if (c == '\n') { buffer[strLength++] = 0; break; } if (c != '\r') { for(i=0; i < 4 && ( (c & 0xff) != 0 ) ; i++) { if( strLength >= size ) { // Increase the capacity dynamically PrintMessage(MESG_ERROR, "SignonManager : Buffer is insufficient to store data"); return FPM_FALSE; } buffer[strLength++] = (char)c; c = c >> 8; } } } // PrintMessage(MESG_DEBUG,"SignonManager : ReadLine = %s ",buffer); return FPM_TRUE; } Unichar SignonManager::ReadCharUTF8() { Unichar c = ReadChar(); if ((c & 0x80) == 0x00) { return c; } else if ((c & 0xE0) == 0xC0) { return (((c & 0x1F)<<6) + (ReadChar() & 0x3F)); } else if ((c & 0xF0) == 0xE0) { return (((c & 0x0F)<<12) + ((ReadChar() & 0x3F)<<6) + (ReadChar() & 0x3F)); } return FPM_FALSE; // 0 => not a utf8 character... } // This does buffered reading... // char SignonManager::ReadChar() { const int buflen = 1000; static char buf[buflen+1]; static int last = 0; static int next = 0; if (next >= last) { next = 0; last = fread(buf, 1, buflen, signonFile); PrintMessage(MESG_DEBUG,"\n SignonManager : ReadChar = Read %d bytes ",last); if (last <= 0) // || feof(file) { /* note that eof is not set until we read past the end of the file */ PrintMessage(MESG_DEBUG,"\n SignonManager : ReadChar = End of file..! "); return FPM_FALSE; } } return (buf[next++]); } int SignonManager::WriteCharUTF8(Unichar c) { if (c <= 0x7F) { if( fputc((char)c, signonFile) == EOF ) return FPM_SIGNON_FILE_WRITE_ERROR; } else if (c <= 0x7FF) { if( fputc( ((Unichar)0xC0) | ((c>>6) & 0x1F), signonFile) == EOF ) return FPM_SIGNON_FILE_WRITE_ERROR; if( fputc( ((Unichar)0x80) | (c & 0x3F), signonFile ) == EOF ) return FPM_SIGNON_FILE_WRITE_ERROR; } else { if( fputc( ((Unichar)0xE0) | ((c>>12) & 0xF), signonFile) == EOF ) return FPM_SIGNON_FILE_WRITE_ERROR; if( fputc( ((Unichar)0x80) | ((c>>6) & 0x3F), signonFile) == EOF) return FPM_SIGNON_FILE_WRITE_ERROR; if( fputc( ((Unichar)0x80) | (c & 0x3F), signonFile) == EOF) return FPM_SIGNON_FILE_WRITE_ERROR; } return FPM_TRUE; } int SignonManager::WriteLine(char *line) { for(int i=0; i < strlen(line); i++) { if( WriteCharUTF8(line[i]) != FPM_TRUE ) return FPM_SIGNON_FILE_WRITE_ERROR; } if( WriteCharUTF8('\n') != FPM_TRUE ) return FPM_SIGNON_FILE_WRITE_ERROR; return FPM_TRUE; } /* * Load the signon data from firefox signon file..... * * */ int SignonManager::LoadSignonData(char *firefoxProfileDir ) { char header[256]; char buffer[4096]; char hostName[4096]; char name[1024]; int bufferLength = 4095; int retValue; char *clearData = NULL; int count = 0; // open the signon file if( (retValue = OpenSignonFile(firefoxProfileDir, SIGNON_FILE_NAME, "r")) != FPM_TRUE ) { return retValue; } // Clean up any previously loaded data... dataManager.RemoveAllData(); // read the signon header information if( ReadLine(header, 256) != FPM_TRUE ) { PrintMessage(MESG_ERROR, "\n SignonManager : Error in reading signon format header %s", header); CloseSignonFile(); return FPM_SIGNON_FILE_READ_ERROR; } // check if the format is right... if( strcmp(header, HEADER_VERSION) != 0) { PrintMessage(MESG_ERROR, "\n SignonManager : Header version information is not proper"); CloseSignonFile(); return FPM_SIGNON_FILE_INVALID_DATA; } PrintMessage(MESG_DEBUG, "\n\n ****** Reject Host List *******"); // read the reject list while ( ReadLine(buffer, bufferLength) == FPM_TRUE) { // Check for end of reject list i.e full stop if (strlen(buffer) != 0 && buffer[0] == '.') { break; // end of reject list } if( (retValue = dataManager.AddRejectHost(buffer) ) != FPM_TRUE ) { CloseSignonFile(); dataManager.RemoveAllData(); // clean up any partial loaded data return retValue; } PrintMessage(MESG_DEBUG, "\n Reject Host : %s ", buffer); } PrintMessage(MESG_DEBUG, "\n\n ****** Host list with username / password ****** "); while (ReadLine(hostName, bufferLength) == FPM_TRUE) { // a blank line is perfectly valid here -- corresponds to a local file if (strlen(hostName) < 1) { PrintMessage(MESG_ERROR, "\n SignonManager : Host URL is not proper"); CloseSignonFile(); dataManager.RemoveAllData(); // clean up partial loaded data return FPM_ILLEGAL_HOSTNAME; } if( ( retValue = dataManager.AddHost(hostName) ) != FPM_TRUE ) { CloseSignonFile(); dataManager.RemoveAllData(); // clean up partial loaded data return retValue; } PrintMessage(MESG_DEBUG, "\n\n Host : %s ", hostName); // prepare to read the name/value pairs while( ReadLine(buffer, bufferLength) == FPM_TRUE ) { // line starting with . terminates the pairs for this URL entry if (buffer[0] == '.') { break; // end of URL entry } // save the name part and determine if it is a password unsigned char isPassword = 0; if (buffer[0] == '*') { isPassword = 1; strcpy(name,&buffer[1]); retValue = ReadLine(buffer, bufferLength); } else { isPassword = 0; strcpy(name, buffer); retValue = ReadLine(buffer, bufferLength); } PrintMessage(MESG_DEBUG, "\n\n name = %s and value = %s ", name, buffer); // read in and save the value part if ( retValue != FPM_TRUE ) { // error in input file so give up PrintMessage(MESG_ERROR, "\n SignonManager : Error occured while reading VALUE for : %s ", name); CloseSignonFile(); dataManager.RemoveAllData(); // clean up partial loaded data return FPM_SIGNON_FILE_READ_ERROR; } // Decrypt the encrypted value.... retValue = FPM_FALSE; if( ((retValue = cryptManager.DecryptString(buffer, &clearData)) == FPM_TRUE) && (clearData != NULL) ) { // Add the name/value pair to the existing store.... retValue = dataManager.AddHostElement(hostName, name, clearData, isPassword); if( retValue != FPM_TRUE ) { CloseSignonFile(); dataManager.RemoveAllData(); // clean up partial loaded data return retValue; } } else { CloseSignonFile(); dataManager.RemoveAllData(); // clean up partial loaded data return retValue; } } } // Now close the signon file CloseSignonFile(); // Print data for cross checking #ifdef DEBUG dataManager.PrintAllRejectHosts(); dataManager.PrintAllHosts(); #endif return FPM_TRUE; } int SignonManager::WriteSignonData(char *firefoxProfileDir) { int retValue; char *cryptData = NULL; char *signonFilePath = NULL; char *tempFilePath = NULL; char fileName[256]; Host *t; HostElement *h; RejectHost *r; // TODO : If signon data has not changed since last write then return... /* // There may be requirement to write empty data... if( dataManager.hostList == NULL ) { PrintMessage(MESG_ERROR, "\n WriteSignonData : Signon data is empty..."); return FPM_SIGNON_DATASTORE_EMPTY; } */ // Generate random file name srand( (unsigned)time( NULL ) ); sprintf(fileName,"signon_fpm_%d.txt", rand()); // Setup the signon and temp filename.. signonFilePath = (char*) malloc( strlen(firefoxProfileDir) + strlen(SIGNON_FILE_NAME) + 3); tempFilePath =(char*) malloc( strlen(firefoxProfileDir) + strlen(fileName) + 3); if( signonFilePath == NULL || tempFilePath == NULL) { PrintMessage(MESG_ERROR, "\n WriteSignonData : Insufficient memory ...."); return FPM_INSUFFICIENT_MEMORY; } strcpy(signonFilePath, firefoxProfileDir); strcat(signonFilePath, "/"); strcat(signonFilePath, SIGNON_FILE_NAME); strcpy(tempFilePath, firefoxProfileDir); strcat(tempFilePath, "/"); strcat(tempFilePath, fileName); // Open signon file if( (retValue = OpenSignonFile(firefoxProfileDir, fileName, "w")) != FPM_TRUE ) { PrintMessage(MESG_ERROR, "\nWriteSignonData : Failed to create temp signon file : %s.", fileName); return retValue; } // write out the format revision number if( (retValue = WriteLine(HEADER_VERSION)) != FPM_TRUE) goto write_signon_error; // write out reject host list for(r=dataManager.rejectHostList; r ; r=r->next) { if( (retValue = WriteLine(r->hostName)) != FPM_TRUE ) goto write_signon_error; } // End of reject host list if( (retValue = WriteLine(".")) != FPM_TRUE ) goto write_signon_error; /* format for cached logins shall be: * url LINEBREAK {name LINEBREAK value LINEBREAK}* . LINEBREAK * if type is password, name is preceded by an asterisk (*) */ // write out each URL node for(t=dataManager.hostList; t ; t=t->next) { PrintMessage(MESG_DEBUG, "\n\nWriteSignonData : Adding name/value pairs for host %s", t->hostName); if( (retValue = WriteLine(t->hostName)) != FPM_TRUE ) goto write_signon_error; for(h=t->child; h ; h= h->next) { PrintMessage(MESG_DEBUG, "\n nWriteSignonData : %s : %s ", h->name, h->value); if( h->isPassword) { if( (retValue = WriteCharUTF8('*')) != FPM_TRUE ) goto write_signon_error; } if( (retValue = WriteLine(h->name)) != FPM_TRUE ) goto write_signon_error; // encrypt the value retValue = FPM_FALSE; retValue = cryptManager.EncryptString(h->value, &cryptData); if( (retValue == FPM_TRUE) && (cryptData != NULL )) { if( (retValue = WriteLine(cryptData)) != FPM_TRUE ) goto write_signon_error; } else { PrintMessage(MESG_ERROR, "\n nWriteSignonData : Encryption of value %s failed ", h->value); goto write_signon_error; } } if( (retValue = WriteLine(".")) != FPM_TRUE ) goto write_signon_error; } // close this temporary file... CloseSignonFile(); PrintMessage(MESG_DEBUG, "\n WriteSignonData : Removing previous signon file %s ", signonFilePath); // Delete previous signon file if( remove(signonFilePath) != 0 ) { // Either file not present or file is locked... PrintMessage(MESG_ERROR, "\n WriteSignonData : Failed to delete signon file : %s ", signonFilePath); FILE *sfile= NULL; if( (sfile = fopen(signonFilePath,"r") ) != NULL ) { // we are able to open signon file in read only mode => file is present fclose(sfile); remove(tempFilePath); // delete temporary signon file PrintMessage(MESG_ERROR, "\nWriteSignonData : Signon file is locked "); return FPM_SIGNON_FILE_LOCKED; } // File is not present ..that's good news , so continue... } PrintMessage(MESG_DEBUG, "success \n WriteSignonData : Renaming temp file %s back to signon file %s ", tempFilePath, signonFilePath); // Rename temp file back to signon file if( ( retValue = rename(tempFilePath, signonFilePath) ) != 0 ) { PrintMessage(MESG_ERROR, "\n WriteSignonData : Failed to rename the temp file %s back to signon file %s ", tempFilePath, signonFilePath); PrintMessage(MESG_ERROR, "\n WriteSignonData : Following error has occured : %d ", retValue); return FPM_FALSE; } PrintMessage(MESG_DEBUG, "\n WriteSignonData : Successfully written new signon data ..."); return FPM_TRUE; write_signon_error: CloseSignonFile(); remove(tempFilePath); // remove the temporary signon file.... return retValue; } int SignonManager::RemoveSignonData() { return dataManager.RemoveAllData(); } int SignonManager::AddHost(struct Host *host) { return dataManager.AddHost(host); } int SignonManager::ModifyHost(struct Host *host) { return dataManager.ModifyHost(host); } int SignonManager::RemoveHost(char *hostName) { return dataManager.RemoveHost(hostName); } struct Host * SignonManager::GetHostInfo() { return dataManager.hostList; }