blob: c3740ce2554c4d5b4f50fcb9a1c09ef0fd567301 [file] [log] [blame]
// Copyright 2017 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.
// Stub implementation of klist. Simply returns fixed responses to predefined
// input.
#include <string>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/strings/stringprintf.h>
#include "authpolicy/samba_helper.h"
#include "authpolicy/stub_common.h"
namespace authpolicy {
namespace {
const int kExitCodeTgtValid = 0;
const int kExitCodeTgtInvalid = 1;
const time_t kTenHours = 3600 * 10;
const time_t kSevenDays = 3600 * 24 * 7;
const char kDefaultKrb5CCPath[] = "/tmp/krb5cc_0";
const char kNoCredentialsCacheErrorFormat[] =
"klist: No credentials cache found (filename: %s)";
// Stub klist result format. Times to be filled in.
const char kStubListFormat[] = R"!!!(Ticket cache: FILE:/krb5cc
Default principal: TESTCOMP$@EXAMPLE.COM
Valid starting Expires Service principal
%s %s krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until %s
%s %s ldap/server.example.com@EXAMPLE.COM
renew until %s
)!!!";
// Formats |time_epoch| (e.g. from time()) as "mm/dd/yy HH:MM:SS".
std::string FormatDateTime(time_t time_epoch) {
char buffer[64] = {};
struct tm tm;
localtime_r(&time_epoch, &tm);
CHECK(strftime(buffer, sizeof(buffer), "%m/%d/%y %H:%M:%S", &tm));
return buffer;
}
// Fills in the times for kStubListFormat.
std::string FormatStubList(time_t valid_from,
time_t expires,
time_t renew_until) {
const std::string valid_from_str = FormatDateTime(valid_from);
const std::string expires_str = FormatDateTime(expires);
const std::string renew_until_str = FormatDateTime(renew_until);
return base::StringPrintf(kStubListFormat, valid_from_str.c_str(),
expires_str.c_str(), renew_until_str.c_str(),
valid_from_str.c_str(), expires_str.c_str(),
renew_until_str.c_str());
}
// Returns a stub klist result with valid tickets.
std::string GetValidStubList() {
// Note: The base/time.h methods cause a seccomp failure here.
time_t now = time(NULL);
return FormatStubList(now, now + kTenHours, now + kSevenDays);
}
// Reads the Kerberos credentials cache from the file path given by the
// kKrb5CCEnvKey environment variable. Returns an empty string on error.
std::string ReadKrb5CC(const std::string& krb5cc_path) {
std::string data;
if (!base::ReadFileToString(base::FilePath(krb5cc_path), &data))
data.clear();
return data;
}
int HandleCommandLine(const std::string& command_line,
const std::string& krb5cc_path) {
const std::string krb5cc_data = ReadKrb5CC(krb5cc_path);
if (krb5cc_data.empty()) {
const std::string no_credentials_cache_error =
base::StringPrintf(kNoCredentialsCacheErrorFormat, krb5cc_path.c_str());
WriteOutput("", no_credentials_cache_error);
return kExitCodeError;
}
// klist -s just returns 0 if the TGT is valid and 1 otherwise.
if (Contains(command_line, "-s")) {
if (krb5cc_data == kValidKrb5CCData)
return kExitCodeTgtValid;
else if (krb5cc_data == kExpiredKrb5CCData)
return kExitCodeTgtInvalid;
else
NOTREACHED() << "UNHANDLED KRB5CC DATA " << krb5cc_data;
}
if (krb5cc_data == kValidKrb5CCData) {
WriteOutput(GetValidStubList(), "");
return kExitCodeOk;
} else if (krb5cc_data == kExpiredKrb5CCData) {
NOTREACHED() << "klist -s should have prevented this code path";
}
NOTREACHED() << "UNHANDLED KRB5CC DATA " << krb5cc_data;
return kExitCodeError;
}
} // namespace
} // namespace authpolicy
int main(int argc, const char* const* argv) {
// Find Kerberos credentials cache path ("-c" argument).
std::string krb5cc_path = authpolicy::GetArgValue(argc, argv, "-c");
if (krb5cc_path.empty())
krb5cc_path = authpolicy::kDefaultKrb5CCPath;
std::string command_line = authpolicy::GetCommandLine(argc, argv);
return authpolicy::HandleCommandLine(command_line, krb5cc_path);
}