linuxOS_AP06/buildroot/package/android-adbd/0003-adb-daemon-Support-custom-auth-command.patch
2025-06-03 12:28:32 +08:00

343 lines
13 KiB
Diff

From 589859e57a265b70c1c8b5b9180b0e27d69797dd Mon Sep 17 00:00:00 2001
From: Jeffy Chen <jeffy.chen@rock-chips.com>
Date: Sun, 8 Oct 2023 12:07:33 +0800
Subject: [PATCH 3/7] adb: daemon: Support custom auth command
Run "adb shell" to trigger /usr/bin/adbd-auth.sh for custom
authentication.
Tested on RK3588 EVB with:
1/ echo true > /usr/bin/adbd-auth.sh
2/ chmod 755 /usr/bin/adbd-auth.sh
3/ echo ADB_SECURE=1 > /etc/profile.d/adbd.sh
4/ reboot
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
adb/adb.cpp | 38 +++++++++++++++++++++++++++++++++---
adb/adb_auth.h | 8 ++++++++
adb/daemon/auth.cpp | 20 +++++++++++++++++++
adb/daemon/services.cpp | 27 +++++++++++++++++++++++++
adb/daemon/shell_service.cpp | 25 +++++++++++++++++-------
adb/daemon/shell_service.h | 8 ++++++--
6 files changed, 114 insertions(+), 12 deletions(-)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 3dbf70f..e39b613 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -185,7 +185,7 @@ static void send_close(unsigned local, unsigned remote, atransport *t)
send_packet(p, t);
}
-std::string get_connection_string() {
+std::string get_connection_string(atransport* t) {
std::vector<std::string> connection_properties;
#if !ADB_HOST
@@ -201,8 +201,16 @@ std::string get_connection_string() {
}
#endif
+ FeatureSet features = supported_features();
+
+#ifndef __ANDROID__
+ /* Force using raw shell for authentication noticing */
+ if (auth_required && !t->has_feature(FEATURE_AUTHED))
+ features.erase(kFeatureShell2);
+#endif
+
connection_properties.push_back(android::base::StringPrintf(
- "features=%s", FeatureSetToString(supported_features()).c_str()));
+ "features=%s", FeatureSetToString(features).c_str()));
return android::base::StringPrintf(
"%s::%s", adb_device_banner,
@@ -219,7 +227,7 @@ void send_connect(atransport* t) {
cp->msg.arg0 = A_VERSION;
cp->msg.arg1 = t->get_max_payload();
- std::string connection_str = get_connection_string();
+ std::string connection_str = get_connection_string(t);
// Connect and auth packets are limited to MAX_PAYLOAD_V1 because we don't
// yet know how much data the other size is willing to accept.
if (connection_str.length() > MAX_PAYLOAD_V1) {
@@ -343,6 +351,10 @@ void handle_packet(apacket *p, atransport *t)
t->failed_auth_attempts = 0;
t->auth_key = auth_key;
adbd_notify_framework_connected_key(t);
+
+#ifndef __ANDROID__
+ t->SetFeatures(FEATURE_AUTHED);
+#endif
} else {
if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
send_auth_request(t);
@@ -371,7 +383,27 @@ void handle_packet(apacket *p, atransport *t)
// being interpreted as part of the string, unless we explicitly strip them.
address = StripTrailingNulls(address);
+#ifndef __ANDROID__
+ if (auth_required && !t->has_feature(FEATURE_AUTHED)) {
+ if (!adbd_auth_custom_supported()) {
+ /* Should not reach here */
+ t->SetConnectionState(kCsOffline);
+ handle_offline(t);
+ return;
+ }
+
+ /* Try custom authentication */
+ if (address.starts_with("shell:")) {
+ if (t->failed_auth_attempts++ > 3) std::this_thread::sleep_for(1s);
+ address = AUTH_CUSTOM;
+ } else if(!address.starts_with("reboot:")) {
+ address = AUTH_REQUIRED;
+ }
+ }
+#endif
+
asocket* s = create_local_service_socket(address, t);
+
if (s == nullptr) {
send_close(0, p->msg.arg0, t);
} else {
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 2be9a76..513d340 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -44,11 +44,19 @@ void send_auth_response(const char* token, size_t token_size, atransport* t);
#else // !ADB_HOST
+#define FEATURE_AUTHED "authed"
+
+#define AUTH_CUSTOM "auth:custom"
+#define AUTH_REQUIRED "auth:required"
+
extern bool auth_required;
+extern const char *auth_command;
void adbd_auth_init(void);
void adbd_auth_verified(atransport *t);
+bool adbd_auth_custom_supported(void);
+
void adbd_cloexec_auth_socket();
bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
std::string* auth_key);
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 553ac59..1266a48 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -171,6 +171,14 @@ void adbd_auth_confirm_key(atransport* t) {
t->AddDisconnect(&adb_disconnect);
}
+#ifndef __ANDROID__
+ /* Try custom authentication later */
+ if (adbd_auth_custom_supported()) {
+ adbd_auth_verified(t);
+ return;
+ }
+#endif
+
{
std::lock_guard<std::mutex> lock(framework_mutex);
if (framework_fd < 0) {
@@ -236,16 +244,28 @@ void adbd_notify_framework_connected_key(atransport* t) {
void adbd_cloexec_auth_socket() {
int fd = android_get_control_socket("adbd");
if (fd == -1) {
+#ifdef __ANDROID__
PLOG(ERROR) << "Failed to get adbd socket";
+#endif
return;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
}
+const char *auth_command = "/bin/false";
+
+bool adbd_auth_custom_supported(void) {
+ return access(auth_command, X_OK) == 0;
+}
+
void adbd_auth_init(void) {
+ auth_command = getenv("ADBD_AUTH_COMMAND") ?: "/usr/bin/adbd-auth.sh";
+
int fd = android_get_control_socket("adbd");
if (fd == -1) {
+#ifdef __ANDROID__
PLOG(ERROR) << "Failed to get adbd socket";
+#endif
return;
}
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index d92922e..c6b49d2 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -54,6 +54,8 @@
#include "sysdeps.h"
#include "transport.h"
+#include "adb_auth.h"
+
#include "daemon/file_sync_service.h"
#include "daemon/framebuffer_service.h"
#include "daemon/reboot_service.h"
@@ -247,6 +249,24 @@ asocket* daemon_service_to_socket(std::string_view name) {
}
#endif
+#ifndef __ANDROID__
+static void require_auth_service(unique_fd fd)
+{
+ WriteFdExactly(fd.get(), "login with \"adb shell\" to continue.\r\n");
+}
+
+void auth_finished(int exit_code, void *userdata)
+{
+ if (exit_code) return;
+
+ atransport *t = static_cast<atransport*>(userdata);
+ t->SetFeatures(FEATURE_AUTHED);
+
+ /* Update features to enable shell v2 */
+ send_connect(t);
+}
+#endif
+
unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
if (name.starts_with("abb:") || name.starts_with("abb_exec:")) {
@@ -303,6 +323,13 @@ unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
std::string arg(name);
return create_service_thread("reboot",
std::bind(reboot_service, std::placeholders::_1, arg));
+ } else if (ConsumePrefix(&name, AUTH_CUSTOM)) {
+ return StartSubprocess(auth_command, nullptr,
+ SubprocessType::kPty, SubprocessProtocol::kNone,
+ auth_finished,
+ reinterpret_cast<void*>(const_cast<atransport*>(transport)));
+ } else if (ConsumePrefix(&name, AUTH_REQUIRED)) {
+ return create_service_thread("auth-required", require_auth_service);
}
#endif
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index e72bf9d..2a017a7 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -147,7 +147,8 @@ bool CreateSocketpair(unique_fd* fd1, unique_fd* fd2) {
class Subprocess {
public:
Subprocess(std::string command, const char* terminal_type, SubprocessType type,
- SubprocessProtocol protocol, bool make_pty_raw);
+ SubprocessProtocol protocol, bool make_pty_raw,
+ exit_func exit_func = nullptr, void *userdata = nullptr);
~Subprocess();
const std::string& command() const { return command_; }
@@ -200,16 +201,22 @@ class Subprocess {
std::unique_ptr<ShellProtocol> input_, output_;
size_t input_bytes_left_ = 0;
+ exit_func exit_func_;
+ void *userdata_;
+
DISALLOW_COPY_AND_ASSIGN(Subprocess);
};
Subprocess::Subprocess(std::string command, const char* terminal_type, SubprocessType type,
- SubprocessProtocol protocol, bool make_pty_raw)
+ SubprocessProtocol protocol, bool make_pty_raw,
+ exit_func exit_func, void *userdata)
: command_(std::move(command)),
terminal_type_(terminal_type ? terminal_type : ""),
type_(type),
protocol_(protocol),
- make_pty_raw_(make_pty_raw) {}
+ make_pty_raw_(make_pty_raw),
+ exit_func_(exit_func),
+ userdata_(userdata) {}
Subprocess::~Subprocess() {
WaitForExit();
@@ -753,6 +760,9 @@ void Subprocess::WaitForExit() {
}
}
+ if (exit_func_)
+ exit_func_(exit_code, userdata_);
+
// If we have an open protocol FD send an exit packet.
if (protocol_sfd_ != -1) {
output_->data()[0] = exit_code;
@@ -798,7 +808,7 @@ unique_fd ReportError(SubprocessProtocol protocol, const std::string& message) {
}
unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
- SubprocessProtocol protocol) {
+ SubprocessProtocol protocol, exit_func exit_func, void *userdata) {
// If we aren't using the shell protocol we must allocate a PTY to properly close the
// subprocess. PTYs automatically send SIGHUP to the slave-side process when the master side
// of the PTY closes, which we rely on. If we use a raw pipe, processes that don't read/write,
@@ -815,7 +825,7 @@ unique_fd StartSubprocess(std::string name, const char* terminal_type, Subproces
unique_fd error_fd;
unique_fd fd = StartSubprocess(std::move(name), terminal_type, type, protocol, make_pty_raw,
- protocol, &error_fd);
+ protocol, &error_fd, exit_func, userdata);
if (fd == -1) {
return error_fd;
}
@@ -824,13 +834,14 @@ unique_fd StartSubprocess(std::string name, const char* terminal_type, Subproces
unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
SubprocessProtocol protocol, bool make_pty_raw,
- SubprocessProtocol error_protocol, unique_fd* error_fd) {
+ SubprocessProtocol error_protocol, unique_fd* error_fd,
+ exit_func exit_func, void *userdata) {
D("starting %s subprocess (protocol=%s, TERM=%s): '%s'",
type == SubprocessType::kRaw ? "raw" : "PTY",
protocol == SubprocessProtocol::kNone ? "none" : "shell", terminal_type, name.c_str());
auto subprocess = std::make_unique<Subprocess>(std::move(name), terminal_type, type, protocol,
- make_pty_raw);
+ make_pty_raw, exit_func, userdata);
if (!subprocess) {
LOG(ERROR) << "failed to allocate new subprocess";
*error_fd = ReportError(error_protocol, "failed to allocate new subprocess");
diff --git a/adb/daemon/shell_service.h b/adb/daemon/shell_service.h
index 3abd958..7a4a81c 100644
--- a/adb/daemon/shell_service.h
+++ b/adb/daemon/shell_service.h
@@ -32,17 +32,21 @@ enum class SubprocessProtocol {
kShell,
};
+typedef void (*exit_func)(int exit_code, void *userdata);
+
// Forks and starts a new shell subprocess. If |name| is empty an interactive
// shell is started, otherwise |name| is executed non-interactively.
//
// Returns an open FD connected to the subprocess or -1 on failure.
unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
- SubprocessProtocol protocol);
+ SubprocessProtocol protocol,
+ exit_func exit_func = nullptr, void *userdata = nullptr);
// The same as above but with more fined grained control and custom error handling.
unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
SubprocessProtocol protocol, bool make_pty_raw,
- SubprocessProtocol error_protocol, unique_fd* error_fd);
+ SubprocessProtocol error_protocol, unique_fd* error_fd,
+ exit_func exit_func = nullptr, void *userdata = nullptr);
// Executes |command| in a separate thread.
// Sets up in/out and error streams to emulate shell-like behavior.
--
2.20.1