| // Copyright 2016 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdint.h> |
| |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include <base/command_line.h> |
| #include <base/files/file_util.h> |
| #include <brillo/flag_helper.h> |
| |
| #include "biod/fake_biometrics_manager_common.h" |
| #include "biod/proto_bindings/constants.pb.h" |
| |
| #ifndef VCSID |
| #define VCSID "<not set>" |
| #endif |
| |
| int main(int argc, char* argv[]) { |
| DEFINE_string(fake_input, |
| "/tmp/fake_biometric", |
| "FIFO special file used to poke the fake biometric device"); |
| DEFINE_bool( |
| failure, false, "signal a general failure of the biometric device"); |
| DEFINE_int32(scan, -1, "signal a scan with the given scan result code"); |
| DEFINE_bool(scan_done, |
| false, |
| "when used with --scan, also causes the device to indicate " |
| "scanning is done"); |
| DEFINE_int32(attempt, |
| -1, |
| "signal an authentication attempt with the given scan result " |
| "code; user IDs and associated record IDs are specified with " |
| "the remaining arguments and each user ID/record ID set is " |
| "delimited with '-', for example '0001 Record1 - 0002 Record2 " |
| "Record3'."); |
| |
| brillo::FlagHelper::Init(argc, |
| argv, |
| "fake_biometric_tool, used to poke the fake " |
| "biometric device embedded in biod."); |
| |
| LOG(INFO) << "vcsid " << VCSID; |
| |
| int cmd_count = (FLAGS_failure ? 1 : 0) + (FLAGS_scan != -1 ? 1 : 0) + |
| (FLAGS_attempt != -1 ? 1 : 0); |
| if (cmd_count != 1) { |
| LOG(ERROR) << "Expected exactly one command to be given"; |
| return 1; |
| } |
| |
| base::ScopedFD fake_input = |
| base::ScopedFD(open(FLAGS_fake_input.c_str(), O_WRONLY | O_NONBLOCK)); |
| CHECK(fake_input.get() >= 0) << "Failed to open fake biometric input"; |
| |
| if (FLAGS_failure) { |
| uint8_t cmd[] = {FAKE_BIOMETRIC_MAGIC_BYTES, 'F'}; |
| CHECK(write(fake_input.get(), &cmd, sizeof(cmd)) == sizeof(cmd)); |
| } |
| |
| if (FLAGS_scan >= 0) { |
| // Biod EnrollScanDone signal cannot accept scan result outside the defined |
| // range. |
| CHECK_LT(FLAGS_scan, |
| static_cast<int32_t>(biod::ScanResult::SCAN_RESULT_MAX)); |
| uint8_t cmd[] = {FAKE_BIOMETRIC_MAGIC_BYTES, |
| 'S', |
| static_cast<uint8_t>(FLAGS_scan), |
| static_cast<uint8_t>(FLAGS_scan_done)}; |
| CHECK(write(fake_input.get(), &cmd, sizeof(cmd)) == sizeof(cmd)); |
| } |
| |
| if (FLAGS_attempt >= 0) { |
| std::unordered_map<std::string, std::vector<std::string>> matches; |
| bool new_match = true; |
| std::vector<std::string>* record_ids = nullptr; |
| for (const auto& arg : base::CommandLine::ForCurrentProcess()->GetArgs()) { |
| if (arg == "-") { |
| new_match = true; |
| record_ids = nullptr; |
| continue; |
| } |
| |
| if (new_match) { |
| if (matches.size() >= UINT8_MAX) { |
| LOG(WARNING) << "Only " << UINT8_MAX << " matches can be sent at " |
| << " once. The remaining matches will be truncated."; |
| break; |
| } |
| |
| auto emplace_result = matches.emplace(arg, std::vector<std::string>()); |
| if (!emplace_result.second) |
| LOG(WARNING) << "User ID " << arg << " was repeated."; |
| record_ids = &emplace_result.first->second; |
| new_match = false; |
| continue; |
| } |
| |
| if (!record_ids) |
| continue; |
| |
| if (record_ids->size() >= UINT8_MAX) { |
| LOG(WARNING) << "Only " << UINT8_MAX |
| << " record IDs per match can be sent. " |
| << "The remaining record IDs will be truncated."; |
| continue; |
| } |
| |
| record_ids->emplace_back(arg); |
| if (record_ids->back().size() > UINT8_MAX) { |
| LOG(WARNING) << "Record ID \"" << arg << "\" is longer than " |
| << UINT8_MAX << ". This Record ID will be truncated."; |
| record_ids->back().resize(UINT8_MAX); |
| } |
| } |
| std::vector<uint8_t> cmd = {FAKE_BIOMETRIC_MAGIC_BYTES, |
| 'A', |
| static_cast<uint8_t>(FLAGS_attempt), |
| static_cast<uint8_t>(matches.size())}; |
| for (const auto& match : matches) { |
| const std::string& user_id = match.first; |
| const std::vector<std::string>& record_ids = match.second; |
| cmd.push_back(static_cast<uint8_t>(user_id.size())); |
| cmd.insert(cmd.end(), user_id.begin(), user_id.end()); |
| cmd.push_back(static_cast<uint8_t>(record_ids.size())); |
| for (const auto& record_id : record_ids) { |
| cmd.push_back(static_cast<uint8_t>(record_id.size())); |
| cmd.insert(cmd.end(), record_id.begin(), record_id.end()); |
| } |
| } |
| CHECK(write(fake_input.get(), cmd.data(), cmd.size()) == |
| static_cast<int>(cmd.size())); |
| } |
| |
| return 0; |
| } |