How to send method call by dbus-send? - dbus

I am analyzing Chromium OS.
I have captured a dbus method call using dbus-monitor and want to reappear it by dbus-send.
Below is what I want to reappear.
my-chromiumos ! # dbus-monitor --system "path=/org/chromium/SessionManager"
method call time=1632639141.486152 sender=:1.325 -> destination=org.chromium.SessionManager serial=402 path=/org/chromium/SessionManager; interface=org.chromium.SessionManagerInterface; member=RestartJob
file descriptor
inode: 489350
type: socket
address family: unix
name #
peer #
array [
string "/opt/google/chrome/chrome"
string "--gpu-sandbox-failures-fatal=no"
string "--enable-logging"
string "--use-cras"
string "--use-gl=egl"
string "--user-data-dir=/home/chronos"
string "--vmodule=*night_light*=1,*/ash/wm/tablet_mode/*=1,wizard_controller=1,*/webui/chromeos/login/*=1,*/browser/chromeos/login/screens/*=1,enrollment_screen_handler=1,*/browser/chromeos/login/enrollment/*=1,*/ui/ozone/*=1,*/ui/display/manager/chromeos/*=1"
string "--enable-wayland-server"
string "--aura-legacy-power-button"
string "--login-profile=user"
string "--system-developer-mode"
string "--bwsi"
string "--homepage=chrome://newtab/"
string "--incognito"
string "--log-level=1"
string "--login-user=$guest"
]
uint32 0

Please take a look at dbus-send documentation for more details.
dbus-send --dest=org.chromium.SessionManager \
--print-reply \
--type=method_call \
/org/chromium/SessionManager \
org.chromium.SessionManagerInterface.RestartJob
It looks like the above method call do not take any argument, but you should confirm with the available API documentation.
Also, I found this Chrome OS D-Bus Best Practices guide, please take a look at it as well.

Related

Display special character in json log with syslog-ng

I used to handle my log with Syslog. I am currently trying to switch to syslog-ng and also to update the format of my log to follow JSON standard.
First I define a syslog-ng configuration file :
#version: 3.2X
filter f_middleware {
facility("local1");
};
template t_json_filetemplate {
template("{\"timestamp\":\"${ISODATE}\",${MESSAGE}\n");
};
source s_kernel {
file("/proc/kmsg" program_override("kernel"));
};
source s_middleware {
unix-stream("/dev/log");
};
destination d_kernel {
file("/data/logs/kern.log");
};
destination d_middleware {
file("/data/logs/middleware.log", template(t_json_filetemplate));
};
log {
source(s_kernel);
destination(d_kernel);
};
log {
source(s_middleware);
filter(f_middleware);
destination(d_middleware);
};
In my middleware c code, I
openlog("middleware", 0, LOG_LOCAL1);
I format my log with macro in my code to handle the expected json format from my custom server:
#ifdef DEBUG
#define _PRINT_DEBUG(M, ...) \
do { \
syslog(LOG_DEBUG, "\"category\":\"%s\",\"level\":\"DEBUG\",\"message\":\"" M "%s\"}\n", __DIR__, __VA_ARGS__); \
} while (0)
#else
The problem is if I tried to display a file content with Syslog, the end of the message
is truncated. it is working correctly for other types of message of course.
Here for example I try to print the content of the file /proc/cmdline
{"timestamp":"2020-04-20T16:55:50+02:00","category":"XXX_MANAGER","level":"DEBUG","message":"root ptr : root=/dev/xxx
The '}' is missing at the end. It is because there is a '\n' at the end of the file ?
I also tried to add some stuff about escaping in my config file :
destination d_middleware {
file("/data/logs/middleware.log", template("{\"timestamp\":\"${ISODATE}\",${MESSAGE}\n") template-escape(no));
No better result...
A guess that I am using syslog-ng in a bad way...
More complete explanation of the problem after some investigation
https://lists.balabit.hu/pipermail/syslog-ng/2020-April/025836.html
It is because there is a '\n' at the end of the file?
Yes, unix-stream() uses \n to separate messages. You should escape your message in your middleware.
Alternatively, you can use, for example, unix-dgram() with flags(no-parse). You may need to send your data to a SOCK_DGRAM socket in that case, but on Linux, syslog() is actually dgram-based.
From the glibc manual:
openlog may or may not open the /dev/log socket, depending on option. If it does, it tries to open it and connect it as a stream socket. If that doesn’t work, it tries to open it and connect it as a datagram socket.

POST JSON to url using CURL and C

I'm tring to POST JSON data to a url from bash using:
$ curl -v -d '{xxx:200}&apikey=xxxxx' -X POST http://localhost/xxxx/input/post.json -H "Accept: application/json" -H "Content-Type:application/json"
And in C using the following:
int main(void)
{
CURL *easyhandle;
curl_global_init(CURL_GLOBAL_ALL);
easyhandle = curl_easy_init();
if(easyhandle) {
char *data="json={xxx:200}&apikey=xxxxx";
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(easyhandle, CURLOPT_URL, "http://localhost/xxxx/input/post.json");
curl_easy_perform(easyhandle);
curl_easy_cleanup (easyhandle);
}
curl_global_cleanup();
return 0;
}
This is what i'm trying to achieve actually:
http://localhost/xxxx/input/post.json?json={xxx:200}&apikey=xxxxx
It doesn't seem to work. :(
I'm a complete novice to curl. Please help.
Thanks!
Fortunately the server I was sending the data handled POST and GET requests, so the code in question would suffice.
Others with a similar problem can use a simple workaround (If your code doesn't have real time constraints and is not performance intensive). You may fork a bash process using system() from C. This avoids you the trouble of encoding.
What you are trying to do is not performing a POST request but performing a GET request. However, I'm not sure this is a good idea, since GET parameters are limited in length (to something like 2 kB or so), and - as others have already mentioned - they need to be encoded and decoded and all the funky stuff which is a pain in the neck.
The URL pointing to localhost suggests me that you have control over the server code. If you used the POST parameters instead of the GET ones, you could use your current code as-is (which sets the POST body of the request, which is probably the right thing to do -- so you don't have to change your client code, you only have to change the server code.)

How to find methods exposed in a D-Bus interface

Question: Is there any way in which we can find out the methods (and their signatures) which are exposed in a D-Bus interface?
Issue Description: In my phone, I am calling BlueZ methods using D-Bus to adapter interface, when checked on phone 2 of these methods are not available.
Intention is to check if the method name/signatures are modified in other device, I don't have access to code so looking to find the methods in an interface
Using dbus-send, you can list the available services on your system:
Session:
dbus-send --session \
--dest=org.freedesktop.DBus \
--type=method_call \
--print-reply \
/org/freedesktop/DBus \
org.freedesktop.DBus.ListNames
System:
dbus-send --system \
--dest=org.freedesktop.DBus \
--type=method_call \
--print-reply \
/org/freedesktop/DBus \
org.freedesktop.DBus.ListNames
You'll get an answer like that:
array [
string "org.freedesktop.DBus"
string ":1.1"
string ":1.26"
string "org.asamk.Signal"
]
And if you want to list all methods available behind a dbus service, you can still use dbus-send to introspect the dbus service.
For example with org.asamk.Signal:
dbus-send --system --type=method_call --print-reply \
--dest=org.asamk.Signal \
/org/asamk/Signal \
org.freedesktop.DBus.Introspectable.Introspect
You'll get this kind of result (truncated)
<node name="/org/asamk/Signal">
<interface name="org.asamk.Signal">
<method name="sendMessage" >
...parameters
</method>
<method name="sendGroupMessage" >
...parameters
</method>
</interface>
</node>
Here there are 2 methods, sendMessage and sendGroupMessage
You can also take a look at D-Feet.
With an extra google search and dbus understanding, using D-Bus Introspection helps to get the methods (with signatures) exposed on that particular interface. More information available at link.

Can you retrieve a D-Bus property without calling org.freedesktop.DBus.Properties.Get?

Say I want to programmatically get the interface name of my ethernet card. This seems to work:
dbus-send --print-reply \
--type=method_call \
--system \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager/Devices/0 \
org.freedesktop.DBus.Properties.Get \
string:org.freedesktop.NetworkManager.Device \
string:Interface
Which returns:
method return sender=:1.5 -> dest=:1.135 reply_serial=2
variant string "eth0"
Is there some way of cutting out the middleman org.freedesktop.DBus.Properties.Get and retrieve the property more directly? Alas, calling it as a method does not work:
dbus-send --print-reply \
--type=method_call \
--system \
--dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager/Devices/0 \
org.freedesktop.NetworkManager.Device.Interface
Returns:
Error org.freedesktop.DBus.Error.UnknownMethod:
Method "Interface" with signature "" on interface
"org.freedesktop.NetworkManager.Device" doesn't exist
I ask because having to call org.freedesktop.DBus.Properties.Get looks like having to call a object.getProp("someproperty") instead of object.getSomeProperty() in Python/Java/etc.
Yep, you can do that if you use qdbus. I don't have NetworkManager with me, but a command like that should work:
qdbus --system \
org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager/Devices/0 \
org.freedesktop.NetworkManager.Device.Interface
There are various command-line clients for talking to D-Bus, some are more convenient than others. Here's the list of the ones I know.
dbus-send (provided with D-Bus itself)
gdbus (provided by GLib)
qdbus (provided by Qt)
busctl (provided by systemd)
No.
Most likely org.freedesktop.DBus.Properties.GetAll will return you same value, but internally every service implement properties as handlers to messages with org.freedesktop.DBus.Properties.Get/org.freedesktop.DBus.Properties.GetAll method calls.
It looks like object.getProp("someproperty") because it actually is more like this pseudo-code
bus.handleMessage({
service: "org.freedesktop.NetworkManager",
object: "/org/freedesktop/NetworkManager/Devices/0",
iface: "org.freedesktop.NetworkManager.Device.Interface",
body: [ "org.freedesktop.NetworkManager.Device", "Interface"],
thisMessageIsReplyTo: null
})
Internally every method call/signal/reply is just a message with big signature (service name/object path/interface) and body

C string interpolation

I'm building simple http status checker in C. I've got the network part done, but I'm having trouble with string manipulation. Here how it works:
$ ./client http://domain.com/path.html#anchor
200
This utility simply outputs the status of given page on the command line. I need to parse the given string into hostname and request path. I've also built a "template" string with this define:
#define HTTP_GET_MSG "GET %s HTTP/1.1\nUser-Agent: my-agent-0.01\nHost: %s\n\n"
I'd like to know how should I approach the interpolation of parsed url (host and path) into this defined string before send()ing it to the socket?
A simple approach is to use sprintf:
char req[ SOME_SUITABLE_SIZE ];
sprintf( req, HTTP_GET_MSG, host, path );
but this will be vunerable to buffer overruns unless you check the lengths of "host" and "path" beforehand. If your system has snprintf you can avoid this:
snprintf( req, SOME_SUITABLE_SIZE, HTTP_GET_MSG, host, path );

Resources