blob: 735be64b8a9428d3815c06847adb413267816ea7 [file] [log] [blame]
// Copyright (c) 2010 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 "chromeos_login.h" // NOLINT
#include <vector>
#include <base/basictypes.h>
#include <base/logging.h>
#include <base/string_util.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <chromeos/dbus/dbus.h>
#include <chromeos/dbus/service_constants.h>
#include <chromeos/glib/object.h>
#include <chromeos/string.h>
#include "chromeos_login_helpers.h" // NOLINT
#include "marshal.glibmarshal.h" // NOLINT
namespace chromeos { // NOLINT
// TODO(cmasone): do a bigger refactor, get rid of this copy-paste macro.
#define SCOPED_SAFE_MESSAGE(e) (e->message ? e->message : "unknown error")
class OpaqueSessionConnection {
public:
OpaqueSessionConnection(const SessionMonitor& monitor, void* object)
: monitor_(monitor),
object_(object) {
}
virtual ~OpaqueSessionConnection() {}
void Notify(OwnershipEvent event) {
monitor_(object_, event);
}
private:
SessionMonitor monitor_;
void* object_;
DISALLOW_COPY_AND_ASSIGN(OpaqueSessionConnection);
};
extern "C"
bool ChromeOSCheckWhitelist(const char* email,
std::vector<uint8>* signature) {
// TODO(cmasone): Enable NOTREACHED once Chrome is migrated.
// NOTREACHED() << "ChromeOSCheckWhitelist is deprecated";
DCHECK(signature);
GArray* sig;
if (!ChromeOSLoginHelpers::CheckWhitelistHelper(email, &sig))
return false;
bool rv = false;
signature->resize(sig->len);
if (signature->size() == sig->len) {
memcpy(&(signature->at(0)), static_cast<const void*>(sig->data), sig->len);
rv = true;
}
g_array_free(sig, false);
return rv;
}
extern "C"
bool ChromeOSCheckWhitelistSafe(const char* email,
CryptoBlob** OUT_signature) {
DCHECK(OUT_signature);
GArray* sig;
if (!ChromeOSLoginHelpers::CheckWhitelistHelper(email, &sig))
return false;
*OUT_signature = ChromeOSLoginHelpers::CreateCryptoBlob(sig);
g_array_free(sig, true);
return true;
}
extern "C"
bool ChromeOSEmitLoginPromptReady() {
chromeos::dbus::Proxy proxy = ChromeOSLoginHelpers::CreateProxy();
gboolean done = false;
chromeos::glib::ScopedError error;
if (!::dbus_g_proxy_call(proxy.gproxy(),
login_manager::kSessionManagerEmitLoginPromptReady,
&Resetter(&error).lvalue(),
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &done,
G_TYPE_INVALID)) {
LOG(WARNING) << login_manager::kSessionManagerEmitLoginPromptReady
<< " failed: " << SCOPED_SAFE_MESSAGE(error);
}
return done;
}
extern "C"
bool ChromeOSEnumerateWhitelisted(std::vector<std::string>* OUT_whitelisted) {
// TODO(cmasone): Enable NOTREACHED once Chrome is migrated.
// NOTREACHED() << "ChromeOSEnumerateWhitelisted is deprecated";
DCHECK(OUT_whitelisted);
gchar** whitelisted = NULL;
if (!ChromeOSLoginHelpers::EnumerateWhitelistedHelper(&whitelisted))
return false;
for (int i = 0; whitelisted[i] != NULL; ++i)
OUT_whitelisted->push_back(std::string(whitelisted[i]));
g_strfreev(whitelisted);
return true;
}
extern "C"
bool ChromeOSEnumerateWhitelistedSafe(UserList** OUT_whitelisted) {
DCHECK(OUT_whitelisted);
gchar** whitelisted = NULL;
if (!ChromeOSLoginHelpers::EnumerateWhitelistedHelper(&whitelisted))
return false;
*OUT_whitelisted = ChromeOSLoginHelpers::CreateUserList(whitelisted);
g_strfreev(whitelisted);
return true;
}
extern "C"
CryptoBlob* ChromeOSCreateCryptoBlob(const uint8* in, const int in_len) {
GArray* ary = ChromeOSLoginHelpers::CreateGArrayFromBytes(in, in_len);
CryptoBlob* blob = ChromeOSLoginHelpers::CreateCryptoBlob(ary);
g_array_free(ary, TRUE);
return blob;
}
extern "C"
Property* ChromeOSCreateProperty(const char* name, const char* value,
const uint8* sig, const int sig_len) {
GArray* ary = ChromeOSLoginHelpers::CreateGArrayFromBytes(sig, sig_len);
Property* prop = ChromeOSLoginHelpers::CreateProperty(name, value, ary);
g_array_free(ary, TRUE);
return prop;
}
extern "C"
UserList* ChromeOSCreateUserList(char** users) {
return ChromeOSLoginHelpers::CreateUserList(users);
}
// These Free* methods all use delete (as opposed to delete []) on purpose,
// following the pattern established by code that uses NewStringCopy.
extern "C"
void ChromeOSFreeCryptoBlob(CryptoBlob* blob) {
ChromeOSLoginHelpers::FreeCryptoBlob(blob);
}
extern "C"
void ChromeOSFreeProperty(Property* property) {
ChromeOSLoginHelpers::FreeProperty(property);
}
extern "C"
void ChromeOSFreeUserList(UserList* userlist) {
ChromeOSLoginHelpers::FreeUserList(userlist);
}
extern "C"
bool ChromeOSRestartJob(int pid, const char* command_line) {
chromeos::dbus::Proxy proxy = ChromeOSLoginHelpers::CreateProxy();
gboolean done = false;
chromeos::glib::ScopedError error;
if (!::dbus_g_proxy_call(proxy.gproxy(),
login_manager::kSessionManagerRestartJob,
&Resetter(&error).lvalue(),
G_TYPE_INT, pid,
G_TYPE_STRING, command_line,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &done,
G_TYPE_INVALID)) {
LOG(WARNING) << login_manager::kSessionManagerRestartJob << " failed: "
<< SCOPED_SAFE_MESSAGE(error);
}
return done;
}
extern "C"
bool ChromeOSRestartEntd() {
chromeos::dbus::Proxy proxy = ChromeOSLoginHelpers::CreateProxy();
::dbus_g_proxy_call_no_reply(proxy.gproxy(),
login_manager::kSessionManagerRestartEntd,
G_TYPE_INVALID,
G_TYPE_INVALID);
return true;
}
extern "C"
bool ChromeOSRetrieveProperty(const char* name,
std::string* out_value,
std::vector<uint8>* signature) {
// TODO(cmasone): Enable NOTREACHED once Chrome is migrated.
// NOTREACHED() << "ChromeOSRetrieveProperty is deprecated";
DCHECK(signature);
DCHECK(out_value);
GArray* sig;
gchar* value = NULL;
if (!ChromeOSLoginHelpers::RetrievePropertyHelper(name, &value, &sig))
return false;
bool rv = false;
signature->resize(sig->len);
if (signature->size() == sig->len) {
memcpy(&(signature->at(0)), static_cast<const void*>(sig->data), sig->len);
rv = true;
}
g_array_free(sig, false);
out_value->assign(value);
g_free(value);
return rv;
}
extern "C"
bool ChromeOSRetrievePropertySafe(const char* name, Property** OUT_property) {
DCHECK(OUT_property);
GArray* sig;
gchar* value = NULL;
if (!ChromeOSLoginHelpers::RetrievePropertyHelper(name, &value, &sig))
return false;
*OUT_property = ChromeOSLoginHelpers::CreateProperty(name, value, sig);
return true;
}
extern "C"
bool ChromeOSSetOwnerKey(const std::vector<uint8>& public_key_der) {
// TODO(cmasone): Enable NOTREACHED once Chrome is migrated.
// NOTREACHED() << "ChromeOSSetOwnerKey is deprecated";
GArray* key_der =
ChromeOSLoginHelpers::CreateGArrayFromBytes(&public_key_der[0],
public_key_der.size());
bool rv = ChromeOSLoginHelpers::SetOwnerKeyHelper(key_der);
g_array_free(key_der, TRUE);
return rv;
}
extern "C"
bool ChromeOSSetOwnerKeySafe(const CryptoBlob* public_key_der) {
GArray* key_der =
ChromeOSLoginHelpers::CreateGArrayFromBytes(public_key_der->data,
public_key_der->length);
bool rv = ChromeOSLoginHelpers::SetOwnerKeyHelper(key_der);
g_array_free(key_der, TRUE);
return rv;
}
extern "C"
bool ChromeOSStartSession(const char* user_email,
const char* unique_id /* unused */) {
chromeos::dbus::Proxy proxy = ChromeOSLoginHelpers::CreateProxy();
gboolean done = false;
chromeos::glib::ScopedError error;
if (!::dbus_g_proxy_call(proxy.gproxy(),
login_manager::kSessionManagerStartSession,
&Resetter(&error).lvalue(),
G_TYPE_STRING, user_email,
G_TYPE_STRING, unique_id,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &done,
G_TYPE_INVALID)) {
LOG(WARNING) << login_manager::kSessionManagerStartSession << " failed: "
<< SCOPED_SAFE_MESSAGE(error);
}
return done;
}
extern "C"
bool ChromeOSStopSession(const char* unique_id /* unused */) {
chromeos::dbus::Proxy proxy = ChromeOSLoginHelpers::CreateProxy();
// TODO(cmasone): clear up the now-defunct variables here.
gboolean unused = false;
::dbus_g_proxy_call_no_reply(proxy.gproxy(),
login_manager::kSessionManagerStopSession,
G_TYPE_STRING, unique_id,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &unused,
G_TYPE_INVALID);
return true;
}
extern "C"
bool ChromeOSStoreProperty(const char* name,
const char* value,
const std::vector<uint8>& signature) {
// TODO(cmasone): Enable NOTREACHED once Chrome is migrated.
// NOTREACHED() << "ChromeOSStoreProperty is deprecated!";
GArray* sig = ChromeOSLoginHelpers::CreateGArrayFromBytes(&signature[0],
signature.size());
bool rv = ChromeOSLoginHelpers::StorePropertyHelper(name, value, sig);
g_array_free(sig, TRUE);
return rv;
}
extern "C"
bool ChromeOSStorePropertySafe(const Property* prop) {
GArray* sig =
ChromeOSLoginHelpers::CreateGArrayFromBytes(prop->signature->data,
prop->signature->length);
bool rv = ChromeOSLoginHelpers::StorePropertyHelper(prop->name,
prop->value,
sig);
g_array_free(sig, TRUE);
return rv;
}
extern "C"
bool ChromeOSUnwhitelist(const char* email,
const std::vector<uint8>& signature) {
// TODO(cmasone): Enable NOTREACHED once Chrome is migrated.
// NOTREACHED() << "ChromeOSUnwhitelist is deprecated!";
return ChromeOSLoginHelpers::WhitelistOpHelper(
login_manager::kSessionManagerUnwhitelist,
email,
signature);
}
extern "C"
bool ChromeOSUnwhitelistSafe(const char* email, const CryptoBlob* signature) {
std::vector<uint8> sig(signature->data, signature->data + signature->length);
return ChromeOSLoginHelpers::WhitelistOpHelper(
login_manager::kSessionManagerUnwhitelist,
email,
sig);
}
extern "C"
bool ChromeOSWhitelist(const char* email,
const std::vector<uint8>& signature) {
// TODO(cmasone): Enable NOTREACHED once Chrome is migrated.
// NOTREACHED() << "ChromeOSWhitelist is deprecated!";
return ChromeOSLoginHelpers::WhitelistOpHelper(
login_manager::kSessionManagerWhitelist,
email,
signature);
}
extern "C"
bool ChromeOSWhitelistSafe(const char* email, const CryptoBlob* signature) {
std::vector<uint8> sig(signature->data, signature->data + signature->length);
return ChromeOSLoginHelpers::WhitelistOpHelper(
login_manager::kSessionManagerWhitelist,
email,
sig);
}
namespace {
#define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error")
bool IsSuccess(DBusMessage* message) {
char* out_string = NULL;
DBusError error;
dbus_error_init (&error);
bool unpack = dbus_message_get_args(message,
&error,
DBUS_TYPE_STRING,
&out_string,
DBUS_TYPE_INVALID);
if (!unpack) {
LOG(INFO) << "Couldn't get arg: " << SAFE_MESSAGE(error);
return false;
}
return strncmp("success", out_string, strlen("success")) == 0;
}
// A message filter to receive signals.
DBusHandlerResult Filter(DBusConnection* connection,
DBusMessage* message,
void* object) {
SessionConnection self =
static_cast<SessionConnection>(object);
if (dbus_message_is_signal(message, chromium::kChromiumInterface,
chromium::kOwnerKeySetSignal)) {
LOG(INFO) << "Filter:: OwnerKeySet signal received";
self->Notify(IsSuccess(message) ? SetKeySuccess : SetKeyFailure);
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_signal(message, chromium::kChromiumInterface,
chromium::kPropertyChangeCompleteSignal)) {
LOG(INFO) << "Filter:: PropertyChangeComplete signal received";
self->Notify(IsSuccess(message) ? PropertyOpSuccess : PropertyOpFailure);
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_signal(message, chromium::kChromiumInterface,
chromium::kWhitelistChangeCompleteSignal)) {
LOG(INFO) << "Filter:: WhitelistChangeComplete signal received";
self->Notify(IsSuccess(message) ? WhitelistOpSuccess : WhitelistOpFailure);
return DBUS_HANDLER_RESULT_HANDLED;
} else {
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}
} // namespace
extern "C"
SessionConnection
ChromeOSMonitorSession(SessionMonitor monitor, void* object) {
const std::string filter = StringPrintf("type='signal', interface='%s'",
chromium::kChromiumInterface);
DBusError error;
::dbus_error_init(&error);
DBusConnection* connection = ::dbus_g_connection_get_connection(
dbus::GetSystemBusConnection().g_connection());
CHECK(connection);
::dbus_bus_add_match(connection, filter.c_str(), &error);
if (::dbus_error_is_set(&error)) {
LOG(WARNING) << "Failed to add a filter:" << error.name << ", message="
<< SAFE_MESSAGE(error);
return NULL;
}
SessionConnection result = new OpaqueSessionConnection(monitor, object);
CHECK(dbus_connection_add_filter(connection, &Filter, result, NULL));
LOG(INFO) << "Ownership API status monitoring started";
return result;
}
extern "C"
void ChromeOSDisconnectSession(SessionConnection connection) {
DBusConnection *bus = ::dbus_g_connection_get_connection(
dbus::GetSystemBusConnection().g_connection());
::dbus_connection_remove_filter(bus, &Filter, connection);
delete connection;
LOG(INFO) << "Disconnected from session manager";
}
} // namespace chromeos