blob: 744244a2fa147a4f161edb20365b9dc0c3bbf71f [file] [log] [blame]
// 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;
}