⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pwsfile.cpp

📁 Password Safe Password Safe is a password database utility. Users can keep their passwords securely
💻 CPP
字号:
#include "PWSfile.h"#include <io.h>#include <fcntl.h>#include <sys/stat.h>#include <errno.h>bool PWSfile::FileExists(const CMyString &filename){  struct _stat statbuf;  int status;  status = ::_tstat(filename, &statbuf);  return (status == 0);}int PWSfile::RenameFile(const CMyString &oldname, const CMyString &newname){  int status = _trename(oldname, newname);  return (status == 0) ? SUCCESS : FAILURE;}PWSfile::PWSfile(const CMyString &filename, const CMyString &passkey)  : m_filename(filename), m_passkey(passkey),  m_defusername(_T("")),    m_curversion(UNKNOWN_VERSION), m_fd(NULL), m_prefString(_T("")){}PWSfile::~PWSfile(){  CloseFile(); // idempotent}// Used to warn pre-2.0 users, and to identify the database as 2.x:static const CMyString V2ItemName(" !!!Version 2 File Format!!! "				  "Please upgrade to PasswordSafe 2.0"				  " or later");// Used to specify the exact versionstatic const CMyString VersionString("2.0");int PWSfile::WriteV2Header(){  CItemData header;  // Fill out with V2-specific info  header.SetName(V2ItemName, _T(""));  header.SetPassword(VersionString);  header.SetNotes(m_prefString);  // need to fallback to V17, since the record  // won't be readable otherwise!  VERSION sv = m_curversion;  m_curversion = V17;  int status = WriteRecord(header);  // restore after writing V17-format header  m_curversion = sv;  return status;}int PWSfile::ReadV2Header(){  CItemData header;  // need to fallback to V17, since the header  // is always written in this format  VERSION sv = m_curversion;  m_curversion = V17;  int status = ReadRecord(header);  // restore after reading V17-format header  m_curversion = sv;  if (status == SUCCESS) {    const CMyString name = header.GetName();    // XXX Need to compare header.GetPassword() against VersionString    // XXX as well, for inter-2.x version checks    status = (name == V2ItemName) ? SUCCESS : WRONG_VERSION;  }  if (status == SUCCESS)    m_prefString = header.GetNotes();  return status;}int PWSfile::OpenWriteFile(VERSION v){  if (v != V17 && v != V20)    return UNSUPPORTED_VERSION;#ifdef UNICODE	m_fd = _wfopen((LPCTSTR)m_filename, _T("wb") );#else	m_fd = fopen((LPCTSTR)m_filename, _T("wb") );#endif  if (m_fd == NULL)    return CANT_OPEN_FILE;  m_curversion = v;    // Following used to verify passkey against file's passkey  unsigned char randstuff[StuffSize];  unsigned char randhash[20];   // HashSize  int x;  for (x=0; x<8; x++)    randstuff[x] = newrand();  randstuff[8] = randstuff[9] = '\0';  GenRandhash(m_passkey, randstuff, randhash);  fwrite(randstuff, 1, 8, m_fd);  fwrite(randhash, 1, 20, m_fd);  for (x=0; x<SaltLength; x++)    m_salt[x] = newrand();  fwrite(m_salt, 1, SaltLength, m_fd);	  for (x=0; x<8; x++)    m_ipthing[x] = newrand();  fwrite(m_ipthing, 1, 8, m_fd);  if (v == V20) {    int status = WriteV2Header();    if (status != SUCCESS)      return status;  }  return SUCCESS;}int PWSfile::OpenReadFile(VERSION v){  if (v != V17 && v != V20)    return UNSUPPORTED_VERSION;#ifdef UNICODE	  m_fd = _wfopen((LPCTSTR) m_filename, _T("rb"));#else	  m_fd = fopen((LPCTSTR) m_filename, _T("rb"));#endif  if (m_fd == NULL)    return CANT_OPEN_FILE;  m_curversion = v;  int status = CheckPassword();  if (status != SUCCESS) {    CloseFile();    return status;  }   fread(m_salt, 1, SaltLength, m_fd);   fread(m_ipthing, 1, 8, m_fd);   if (v == V20)     status = ReadV2Header();  return status;}void PWSfile::CloseFile(){  if (m_fd != NULL) {    fclose(m_fd);    m_fd = NULL;  }}PWSfile::VERSION PWSfile::GetFileVersion(){  VERSION v;  int status = OpenReadFile(V20);  CloseFile();  switch (status) {  case SUCCESS: v = V20; break;  case WRONG_VERSION: v = V17; break;  default: v = UNKNOWN_VERSION; break;  }  return v;}int PWSfile::CheckPassword(){  // if file was opened, leave it open,  // else open it for check, close when done  const bool was_open = (m_fd != NULL);  if (!was_open) {#ifdef UNICODE	  m_fd = _wfopen((LPCTSTR) m_filename, _T("rb"));#else	  m_fd = fopen((LPCTSTR) m_filename, _T("rb"));#endif    if (m_fd == NULL)      return CANT_OPEN_FILE;  }  unsigned char randstuff[StuffSize];  unsigned char randhash[20];   // HashSize   fread(randstuff, 1, 8, m_fd);   randstuff[8] = randstuff[9] = '\0'; // Gross fugbix   fread(randhash, 1, 20, m_fd);  if (!was_open)    CloseFile();  unsigned char temphash[20]; // HashSize  GenRandhash(m_passkey, randstuff, temphash);  if (0 != ::memcmp((char*)randhash,		    (char*)temphash,		    20)) {// HashSize    return WRONG_PASSWORD;  } else {    return SUCCESS;  }}int PWSfile::WriteCBC(unsigned char type, const CString &data){  // We do a double cast because the LPCSTR cast operator is overridden by the CString class  // to access the pointer we need,  // but we in fact need it as an unsigned char. Grrrr.  LPCSTR passstr = LPCSTR(m_passkey);  LPCSTR datastr = LPCSTR(data);  return _writecbc(m_fd, (const unsigned char *)datastr, data.GetLength(), type,		   (const unsigned char *)passstr, m_passkey.GetLength(),		   m_salt, SaltLength, m_ipthing);}int PWSfile::WriteCBC(unsigned char type, const unsigned char *data, unsigned int length){  // We do a double cast because the LPCSTR cast operator is overridden by the CString class  // to access the pointer we need,  // but we in fact need it as an unsigned char. Grrrr.  LPCSTR passstr = LPCSTR(m_passkey);  return _writecbc(m_fd, data, length, type,		   (const unsigned char *)passstr, m_passkey.GetLength(),		   m_salt, SaltLength, m_ipthing);}int PWSfile::WriteRecord(const CItemData &item){  ASSERT(m_fd != NULL);  ASSERT(m_curversion != UNKNOWN_VERSION);  switch (m_curversion) {  case V17: {    // 1.x programs totally ignore the type byte, hence safe to write it    // (no need for two WriteCBC functions)    CMyString name = item.GetName();    // If name field already ecists - use it. This is for the 2.0 header, as well as for files    // that were imported and re-exported.    if (name.IsEmpty()) {      // The name in 1.7 consists of title + SPLTCHR + username      // DEFUSERNAME was used in previous versions, but 2.0 converts this upon import      // so it is not an issue here.      // Prepend 2.0 group field to name, if not empty      // i.e. group "finances" name "broker" -> "finances.broker"      CMyString group = item.GetGroup();      CMyString title = item.GetTitle();      if (!group.IsEmpty()) {	group += _T(".");	group += title;	title = group;      }      name = title;      name += SPLTCHR;      name += item.GetUser();    }    WriteCBC(CItemData::NAME, name);    WriteCBC(CItemData::PASSWORD, item.GetPassword());    WriteCBC(CItemData::NOTES, item.GetNotes());    return SUCCESS;  }  break;  case V20: {    {      uuid_array_t uuid_array;      item.GetUUID(uuid_array);      WriteCBC(CItemData::UUID, uuid_array, sizeof(uuid_array));    }    WriteCBC(CItemData::GROUP, item.GetGroup());    WriteCBC(CItemData::TITLE, item.GetTitle());    WriteCBC(CItemData::USER, item.GetUser());    WriteCBC(CItemData::PASSWORD, item.GetPassword());    WriteCBC(CItemData::NOTES, item.GetNotes());    WriteCBC(CItemData::END, _T(""));    return SUCCESS;  }  default:    ASSERT(0);    return UNSUPPORTED_VERSION;  }  return SUCCESS;}intPWSfile::ReadCBC(unsigned char &type, CMyString &data){  // We do a double cast because the LPCSTR cast operator is overridden by the CString class  // to access the pointer we need,  // but we in fact need it as an unsigned char. Grrrr.  LPCSTR passstr = LPCSTR(m_passkey);  unsigned char *buffer = NULL;  unsigned int buffer_len = 0;  int retval;  retval = _readcbc(m_fd, buffer, buffer_len, type,		   (const unsigned char *)passstr, m_passkey.GetLength(),		   m_salt, SaltLength, m_ipthing);  if (buffer_len > 0) {    CMyString str(LPCSTR(buffer), buffer_len);    data = str;    trashMemory(buffer, buffer_len);    delete[] buffer;  } else {    data = _T("");    // no need to delete[] buffer, since _readcbc will not allocate if    // buffer_len is zero  }  return retval;}int PWSfile::ReadRecord(CItemData &item){  ASSERT(m_fd != NULL);  ASSERT(m_curversion != UNKNOWN_VERSION);  CMyString tempdata;    int numread = 0;  unsigned char type;  switch (m_curversion) {  case V17: {    // type is meaningless, but why write two versions of ReadCBC?    numread += ReadCBC(type, tempdata);    item.SetName(tempdata, m_defusername);    numread += ReadCBC(type, tempdata);    item.SetPassword(tempdata);    numread += ReadCBC(type, tempdata);    item.SetNotes(tempdata);    // No UUID, so we create one here    item.CreateUUID();    // No Group - currently leave empty    return (numread > 0) ? SUCCESS : END_OF_FILE;  }  case V20: {    int emergencyExit = 255; // to avoid endless loop.    int fieldLen; // zero means end of file reached    bool endFound = false; // set to true when record end detected - happy end    do {      fieldLen = ReadCBC(type, tempdata);      if (fieldLen > 0) {	numread += fieldLen;	switch (type) {	case CItemData::TITLE:	  item.SetTitle(tempdata); break;	case CItemData::USER:	  item.SetUser(tempdata); break;	case CItemData::PASSWORD:	  item.SetPassword(tempdata); break;	case CItemData::NOTES:	  item.SetNotes(tempdata); break;	case CItemData::END:	  endFound = true; break;	case CItemData::UUID: {	  LPCSTR ptr = LPCSTR(tempdata);	  uuid_array_t uuid_array;	  for (int i = 0; i < sizeof(uuid_array); i++)	    uuid_array[i] = ptr[i];	  item.SetUUID(uuid_array); break;	}	case CItemData::GROUP:	  item.SetGroup(tempdata); break;	  // just silently ignore fields we don't support.	  // this is forward compatability...	case CItemData::CTIME:	case CItemData::MTIME:	case CItemData::ATIME:	case CItemData::LTIME:	case CItemData::POLICY:	default:	  // XXX Set a flag here so user can be warned that	  // XXX we read a file format we don't fully support	  break;	} // switch      } // if (fieldLen > 0)    } while (!endFound && fieldLen > 0 && --emergencyExit > 0);    return (numread > 0) ? SUCCESS : END_OF_FILE;  }  default:    ASSERT(0);    return UNSUPPORTED_VERSION;  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -