Beispiel #1
0
TEST_F(ItemDataTest, PasswordHistory)
{
  size_t pwh_max, num_err;
  PWHistList pwhl;

  const StringX pw1(L"banana-0rchid");
  const StringX pw2(L"banana-1rchid");
  const StringX pw3(L"banana-2rchid");
  const StringX pw4(L"banana-5rchid");

  PWSprefs *prefs = PWSprefs::GetInstance();
  prefs->SetPref(PWSprefs::SavePasswordHistory, true);
  prefs->SetPref(PWSprefs::NumPWHistoryDefault, 3);

  CItemData di;
  di.SetCTime();
  di.SetPassword(pw1); // first time must be Set, not Update!
  di.UpdatePassword(pw2);
  EXPECT_FALSE(di.GetPWHistory().empty());

  EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err,
                                  pwhl, PWSUtil::TMC_ASC_UNKNOWN));
  EXPECT_EQ(0, num_err);
  EXPECT_EQ(3, pwh_max);
  EXPECT_EQ(1, pwhl.size());
  EXPECT_EQ(pw1, pwhl[0].password);

  di.UpdatePassword(pw3);

  EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err,
                                  pwhl, PWSUtil::TMC_ASC_UNKNOWN));
  EXPECT_EQ(0, num_err);
  EXPECT_EQ(3, pwh_max);
  EXPECT_EQ(2, pwhl.size());
  EXPECT_EQ(pw1, pwhl[0].password);
  EXPECT_EQ(pw2, pwhl[1].password);

  di.UpdatePassword(pw4);

  EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err,
                                  pwhl, PWSUtil::TMC_ASC_UNKNOWN));
  EXPECT_EQ(0, num_err);
  EXPECT_EQ(3, pwh_max);
  EXPECT_EQ(3, pwhl.size());
  EXPECT_EQ(pw1, pwhl[0].password);
  EXPECT_EQ(pw2, pwhl[1].password);
  EXPECT_EQ(pw3, pwhl[2].password);

  di.UpdatePassword(L"Last1");

  EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err,
                                  pwhl, PWSUtil::TMC_ASC_UNKNOWN));
  EXPECT_EQ(0, num_err);
  EXPECT_EQ(3, pwh_max);
  EXPECT_EQ(3, pwhl.size());
  EXPECT_EQ(pw2, pwhl[0].password);
  EXPECT_EQ(pw3, pwhl[1].password);
  EXPECT_EQ(pw4, pwhl[2].password);
}
Beispiel #2
0
inline wostream& print_field_value(wostream &os, wchar_t tag,
                                    const CItemData &item, CItemData::FieldType ft)
{
  StringX fieldValue;
  switch (ft) {
    case CItemData::DCA:
    case CItemData::SHIFTDCA:
    {
      int16 dca = -1;
      if (item.GetDCA(dca) != -1) {
        LoadAString(fieldValue, dca2str(dca));
      }
      break;
    }
    case CItemData::PWHIST:
    {
      const StringX pwh_str = item.GetPWHistory();
      if (!pwh_str.empty()) {
        StringXStream value_stream;
        size_t ignored;
        PWHistList pwhl;
        const bool save_pwhistory = CreatePWHistoryList(pwh_str, ignored, ignored, pwhl, PWSUtil::TMC_LOCALE);
        value_stream << L"Save: " << (save_pwhistory? L"Yes" : L"No");
        if ( !pwhl.empty() ) value_stream << endl;
        for( const auto &pwh: pwhl) value_stream << pwh.changedate << L": " << pwh.password << endl;
        fieldValue = value_stream.str();
      }
      break;
    }
    case CItemData::POLICY:
    {
        PWPolicy policy;
        item.GetPWPolicy(policy);
        fieldValue = policy.GetDisplayString();
        break;
    }
    default:
      fieldValue = item.GetFieldValue(ft);
      break;
  }
  const StringX sep1{L' '}, sep2{L": "};
  StringXStream tmpStream;
  tmpStream << tag << L' ' << item.FieldName(ft) << L": " << fieldValue;
  const auto offset = 1 /*tag*/ + sep1.size() + sep2.size() + item.FieldName(ft).size();
  lines_vec lines{ stream2vec(tmpStream)};
  if ( lines.size() > 1) {
    std::for_each( lines.begin()+1, lines.end(), [offset](StringX &line) { line.insert(0, offset, L' '); });
  }
  for( const auto &line: lines ) os << line << endl;
  return os;
}
Beispiel #3
0
bool CreatePWHistoryList(const StringX &pwh_str,
                         size_t &pwh_max, size_t &num_err,
                         PWHistList &pwhl, PWSUtil::TMC time_format)
{
  // Return boolean value stating if PWHistory status is active
  pwh_max = num_err = 0;
  pwhl.clear();
  StringX pwh_s = pwh_str;
  const size_t len = pwh_s.length();

  if (len < 5) {
    num_err = len != 0 ? 1 : 0;
    return false;
  }
  bool bStatus = pwh_s[0] != charT('0');

  int n;
  iStringXStream ism(StringX(pwh_s, 1, 2)); // max history 1 byte hex
  ism >> hex >> pwh_max;
  if (!ism)
    return false;

  iStringXStream isn(StringX(pwh_s, 3, 2)); // cur # entries 1 byte hex
  isn >> hex >> n;
  if (!isn)
    return false;

  // Sanity check: Each entry has at least 12 bytes representing
  // time + pw length
  // so if pwh_s isn't long enough check if it contains integral number of history records
  if (len - 5 < unsigned(12 * n)) {
    size_t offset = 5;
    bool err=false;
    while (offset < len) {
      offset += 8; //date
      if (offset + 4 >= len) { //passwd len
        err = true;
        break;
      }
      iStringXStream ispwlen(StringX(pwh_s, offset, 4)); // pw length 2 byte hex
      if (!ispwlen){
        err = true;
        break;
      }
      int ipwlen = 0;
      ispwlen >> hex >> ipwlen;
      if ( (ipwlen <= 0) || (offset + 4 + ipwlen > len) ) {
        err = true;
        break;
      }
      offset += 4 + ipwlen;
    }
    if ( err || (offset != len) ) {
      num_err = n;
      return false;
    }
    //number of errors will be counted later
  }
void PasswordSafeSearch::FindMatches(const StringX& searchText, bool fCaseSensitive, SearchPointer& searchPtr,
                                       const CItemData::FieldBits& bsFields, bool fUseSubgroups, const wxString& subgroupText,
                                       CItemData::FieldType subgroupObject, PWSMatch::MatchRule subgroupFunction,
                                       bool subgroupFunctionCaseSensitive, Iter begin, Iter end, Accessor afn)
{
  if (searchText.empty())
      return;

  searchPtr.Clear();

  typedef StringX (CItemData::*ItemDataFuncT)() const;

  struct {
      CItemData::FieldType type;
      ItemDataFuncT        func;
  } ItemDataFields[] = {  {CItemData::GROUP,     &CItemData::GetGroup},
                          {CItemData::TITLE,     &CItemData::GetTitle},
                          {CItemData::USER,      &CItemData::GetUser},
                          {CItemData::PASSWORD,  &CItemData::GetPassword},
//                        {CItemData::NOTES,     &CItemData::GetNotes},
                          {CItemData::URL,       &CItemData::GetURL},
                          {CItemData::EMAIL,     &CItemData::GetEmail},
                          {CItemData::RUNCMD,    &CItemData::GetRunCommand},
                          {CItemData::AUTOTYPE,  &CItemData::GetAutoType},
                          {CItemData::XTIME_INT, &CItemData::GetXTimeInt},

                      };

  for ( Iter itr = begin; itr != end; ++itr) {

    const int fn = (subgroupFunctionCaseSensitive? -subgroupFunction: subgroupFunction);
    if (fUseSubgroups && !afn(itr).Matches(stringT(subgroupText.c_str()), subgroupObject, fn))
        continue;

    bool found = false;
    for (size_t idx = 0; idx < NumberOf(ItemDataFields) && !found; ++idx) {
      if (bsFields.test(ItemDataFields[idx].type)) {
          const StringX str = (afn(itr).*ItemDataFields[idx].func)();
          found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str);
      }
    }

    if (!found && bsFields.test(CItemData::NOTES)) {
        StringX str = afn(itr).GetNotes();
        found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str);
    }

    if (!found && bsFields.test(CItemData::PWHIST)) {
        size_t pwh_max, err_num;
        PWHistList pwhistlist;
        CreatePWHistoryList(afn(itr).GetPWHistory(), pwh_max, err_num,
                            pwhistlist, PWSUtil::TMC_XML);
        for (PWHistList::iterator iter = pwhistlist.begin(); iter != pwhistlist.end(); iter++) {
          PWHistEntry pwshe = *iter;
          found = fCaseSensitive? pwshe.password.find(searchText) != StringX::npos: FindNoCase(searchText, pwshe.password );
          if (found)
            break;  // break out of for loop
        }
        pwhistlist.clear();
    }

    if (found) {
        uuid_array_t uuid;
        afn(itr).GetUUID(uuid);
        searchPtr.Add(pws_os::CUUID(uuid));
    }
  }
}
Beispiel #5
0
bool PWSFilterManager::PassesPWHFiltering(const CItemData *pci) const
{
  bool thistest_rc, bPresent;
  bool bValue(false);
  int iValue(0);

  size_t pwh_max, err_num;
  PWHistList pwhistlist;

  bool status = CreatePWHistoryList(pci->GetPWHistory(),
                                    pwh_max, err_num,
                                    pwhistlist, PWSUtil::TMC_EXPORT_IMPORT);

  bPresent = pwh_max > 0 || !pwhistlist.empty();

  for (auto group_iter = m_vHflgroups.begin();
       group_iter != m_vHflgroups.end(); group_iter++) {
    const vfiltergroup &group = *group_iter;

    int tests(0);
    bool thisgroup_rc = false;
    for (auto num_iter = group.begin();
         num_iter != group.end(); num_iter++) {
      const int &num = *num_iter;
      if (num == -1) // Padding for FT_PWHIST & FT_POLICY - shouldn't happen here
        continue;

      const st_FilterRow &st_fldata = m_currentfilter.vHfldata.at(num);
      thistest_rc = false;

      PWSMatch::MatchType mt(PWSMatch::MT_INVALID);
      const FieldType ft = st_fldata.ftype;

      switch (ft) {
        case HT_PRESENT:
          bValue = bPresent;
          mt = PWSMatch::MT_BOOL;
          break;
        case HT_ACTIVE:
          bValue = status == TRUE;
          mt = PWSMatch::MT_BOOL;
          break;
        case HT_NUM:
          iValue = (int)pwhistlist.size();
          mt = PWSMatch::MT_INTEGER;
          break;
        case HT_MAX:
          iValue = (int)pwh_max;
          mt = PWSMatch::MT_INTEGER;
          break;
        case HT_CHANGEDATE:
          mt = PWSMatch::MT_DATE;
          break;
        case HT_PASSWORDS:
          mt = PWSMatch::MT_STRING;
          break;
        default:
          ASSERT(0);
      }

      const int ifunction = (int)st_fldata.rule;
      switch (mt) {
        case PWSMatch::MT_STRING:
          for (auto pwshe_iter = pwhistlist.begin(); pwshe_iter != pwhistlist.end(); pwshe_iter++) {
            PWHistEntry pwshe = *pwshe_iter;
            thistest_rc = PWSMatch::Match(st_fldata.fstring, pwshe.password,
                                          st_fldata.fcase ? -ifunction : ifunction);
            tests++;
            if (thistest_rc)
              break;
          }
          break;
        case PWSMatch::MT_INTEGER:
          thistest_rc = PWSMatch::Match(st_fldata.fnum1, st_fldata.fnum2,
                                        iValue, ifunction);
          tests++;
          break;
        case PWSMatch::MT_DATE:
          for (auto pwshe_iter = pwhistlist.begin(); pwshe_iter != pwhistlist.end(); pwshe_iter++) {
            const PWHistEntry pwshe = *pwshe_iter;
            // Following throws away hours/min/sec from changetime, for proper date comparison
            time_t changetime = pwshe.changetttdate - (pwshe.changetttdate % (24*60*60));
            thistest_rc = PWSMatch::Match(st_fldata.fdate1, st_fldata.fdate2,
                                          changetime, ifunction);
            tests++;
            if (thistest_rc)
              break;
          }
          break;
        case PWSMatch::MT_BOOL:
          thistest_rc = PWSMatch::Match(bValue, ifunction);
          tests++;
          break;
        default:
          ASSERT(0);
      }

      if (tests <= 1)
        thisgroup_rc = thistest_rc;
      else {
        //Within groups, tests are always "AND" connected
        thisgroup_rc = thistest_rc && thisgroup_rc;
      }
    }
    // This group of tests completed -
    //   if 'thisgroup_rc == true', leave now; else go on to next group
    if (thisgroup_rc)
      return true;
  }

  // We finished all the groups and haven't found one that is true - exclude entry.
  return false;
}