forked from mirrors/gecko-dev
		
	 d91ccf6978
			
		
	
	
		d91ccf6978
		
	
	
	
	
		
			
			And do a more in-depth sanitization than what we were doing. Differential Revision: https://phabricator.services.mozilla.com/D145863
		
			
				
	
	
		
			188 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim:expandtab:shiftwidth=2:tabstop=8:
 | |
|  */
 | |
| /* vim:set ts=8 sw=2 et cindent: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "nsDBusRemoteClient.h"
 | |
| #include "RemoteUtils.h"
 | |
| #include "mozilla/XREAppData.h"
 | |
| #include "mozilla/Logging.h"
 | |
| #include "mozilla/Base64.h"
 | |
| #include "nsPrintfCString.h"
 | |
| 
 | |
| #include <dlfcn.h>
 | |
| #include <dbus/dbus-glib-lowlevel.h>
 | |
| 
 | |
| #undef LOG
 | |
| #ifdef MOZ_LOGGING
 | |
| static mozilla::LazyLogModule sRemoteLm("nsDBusRemoteClient");
 | |
| #  define LOG(str, ...) \
 | |
|     MOZ_LOG(sRemoteLm, mozilla::LogLevel::Debug, (str, ##__VA_ARGS__))
 | |
| #else
 | |
| #  define LOG(...)
 | |
| #endif
 | |
| 
 | |
| nsDBusRemoteClient::nsDBusRemoteClient() {
 | |
|   mConnection = nullptr;
 | |
|   LOG("nsDBusRemoteClient::nsDBusRemoteClient");
 | |
| }
 | |
| 
 | |
| nsDBusRemoteClient::~nsDBusRemoteClient() {
 | |
|   LOG("nsDBusRemoteClient::~nsDBusRemoteClient");
 | |
|   Shutdown();
 | |
| }
 | |
| 
 | |
| nsresult nsDBusRemoteClient::Init() {
 | |
|   LOG("nsDBusRemoteClient::Init");
 | |
| 
 | |
|   if (mConnection) return NS_OK;
 | |
| 
 | |
|   mConnection =
 | |
|       already_AddRefed<DBusConnection>(dbus_bus_get(DBUS_BUS_SESSION, nullptr));
 | |
|   if (!mConnection) {
 | |
|     LOG("  failed to get DBus session");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   dbus_connection_set_exit_on_disconnect(mConnection, false);
 | |
|   dbus_connection_setup_with_g_main(mConnection, nullptr);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void nsDBusRemoteClient::Shutdown(void) {
 | |
|   LOG("nsDBusRemoteClient::Shutdown");
 | |
|   // This connection is owned by libdbus and we don't need to close it
 | |
|   mConnection = nullptr;
 | |
| }
 | |
| 
 | |
| nsresult nsDBusRemoteClient::SendCommandLine(
 | |
|     const char* aProgram, const char* aProfile, int32_t argc, char** argv,
 | |
|     const char* aDesktopStartupID, char** aResponse, bool* aWindowFound) {
 | |
|   NS_ENSURE_TRUE(aProgram, NS_ERROR_INVALID_ARG);
 | |
| 
 | |
|   LOG("nsDBusRemoteClient::SendCommandLine");
 | |
| 
 | |
|   int commandLineLength;
 | |
|   char* commandLine =
 | |
|       ConstructCommandLine(argc, argv, aDesktopStartupID, &commandLineLength);
 | |
|   if (!commandLine) {
 | |
|     LOG("  failed to create command line");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsresult rv =
 | |
|       DoSendDBusCommandLine(aProgram, aProfile, commandLine, commandLineLength);
 | |
|   free(commandLine);
 | |
| 
 | |
|   *aWindowFound = NS_SUCCEEDED(rv);
 | |
| 
 | |
|   LOG("DoSendDBusCommandLine %s", NS_SUCCEEDED(rv) ? "OK" : "FAILED");
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| bool nsDBusRemoteClient::GetRemoteDestinationName(const char* aProgram,
 | |
|                                                   const char* aProfile,
 | |
|                                                   nsCString& aDestinationName) {
 | |
|   // We have a profile name - just create the destination.
 | |
|   // D-Bus names can contain only [a-z][A-Z][0-9]_
 | |
|   // characters so adjust the profile string properly.
 | |
|   nsAutoCString profileName;
 | |
|   nsresult rv = mozilla::Base64Encode(nsAutoCString(aProfile), profileName);
 | |
|   NS_ENSURE_SUCCESS(rv, false);
 | |
| 
 | |
|   mozilla::XREAppData::SanitizeNameForDBus(profileName);
 | |
| 
 | |
|   aDestinationName =
 | |
|       nsPrintfCString("org.mozilla.%s.%s", aProgram, profileName.get());
 | |
|   if (aDestinationName.Length() > DBUS_MAXIMUM_NAME_LENGTH)
 | |
|     aDestinationName.Truncate(DBUS_MAXIMUM_NAME_LENGTH);
 | |
| 
 | |
|   static auto sDBusValidateBusName = (bool (*)(const char*, DBusError*))dlsym(
 | |
|       RTLD_DEFAULT, "dbus_validate_bus_name");
 | |
|   if (!sDBusValidateBusName) {
 | |
|     LOG("  failed to get dbus_validate_bus_name()");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
 | |
|     // We don't have a valid busName yet - try to create a default one.
 | |
|     aDestinationName =
 | |
|         nsPrintfCString("org.mozilla.%s.%s", aProgram, "default");
 | |
|     if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
 | |
|       // We failed completelly to get a valid bus name - just quit
 | |
|       // to prevent crash at dbus_bus_request_name().
 | |
|       LOG("  failed to validate profile DBus name");
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| nsresult nsDBusRemoteClient::DoSendDBusCommandLine(const char* aProgram,
 | |
|                                                    const char* aProfile,
 | |
|                                                    const char* aBuffer,
 | |
|                                                    int aLength) {
 | |
|   LOG("nsDBusRemoteClient::DoSendDBusCommandLine()");
 | |
| 
 | |
|   nsAutoCString appName(aProgram);
 | |
|   mozilla::XREAppData::SanitizeNameForDBus(appName);
 | |
| 
 | |
|   nsAutoCString destinationName;
 | |
|   if (!GetRemoteDestinationName(appName.get(), aProfile, destinationName)) {
 | |
|     LOG("  failed to get remote destination name");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsAutoCString pathName;
 | |
|   pathName = nsPrintfCString("/org/mozilla/%s/Remote", appName.get());
 | |
| 
 | |
|   static auto sDBusValidatePathName = (bool (*)(const char*, DBusError*))dlsym(
 | |
|       RTLD_DEFAULT, "dbus_validate_path");
 | |
|   if (!sDBusValidatePathName ||
 | |
|       !sDBusValidatePathName(pathName.get(), nullptr)) {
 | |
|     LOG("  failed to validate path name");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsAutoCString remoteInterfaceName;
 | |
|   remoteInterfaceName = nsPrintfCString("org.mozilla.%s", appName.get());
 | |
| 
 | |
|   LOG("  DBus destination: %s\n", destinationName.get());
 | |
|   LOG("  DBus path: %s\n", pathName.get());
 | |
|   LOG("  DBus interface: %s\n", remoteInterfaceName.get());
 | |
| 
 | |
|   RefPtr<DBusMessage> msg =
 | |
|       already_AddRefed<DBusMessage>(dbus_message_new_method_call(
 | |
|           destinationName.get(),
 | |
|           pathName.get(),             // object to call on
 | |
|           remoteInterfaceName.get(),  // interface to call on
 | |
|           "OpenURL"));                // method name
 | |
|   if (!msg) {
 | |
|     LOG("  failed to create DBus message");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   // append arguments
 | |
|   if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &aBuffer,
 | |
|                                 aLength, DBUS_TYPE_INVALID)) {
 | |
|     LOG("  failed to create DBus message");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   // send message and get a handle for a reply
 | |
|   RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
 | |
|       dbus_connection_send_with_reply_and_block(mConnection, msg, -1, nullptr));
 | |
| 
 | |
| #ifdef MOZ_LOGGING
 | |
|   if (!reply) {
 | |
|     LOG("  failed to get DBus reply");
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return reply ? NS_OK : NS_ERROR_FAILURE;
 | |
| }
 |