This commit is contained in:
hippoz 2023-01-03 19:06:44 +02:00
parent f7da39acea
commit de00067fd1
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
2 changed files with 94 additions and 38 deletions

114
server.c
View file

@ -1,3 +1,5 @@
#define _GNU_SOURCE 1
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
@ -130,7 +132,7 @@ int jb_server_client_assign_unique_name(struct jb_server *s, int i)
return -1; return -1;
} }
if (snprintf(name, 16, ":%"PRIu32, id) < 0) { if (snprintf(name, 16, ":1.%"PRIu32, id) < 0) {
return -1; return -1;
} }
@ -241,8 +243,10 @@ int jb_server_broadcast_message(struct jb_server *s, wire_message_t *msg, wire_c
.data_len = 4096, .data_len = 4096,
}; };
uint32_t previous_cursor = ctx->byte_cursor;
TRYST(wire_compose_unicast_reply(&reply_ctx, ctx, msg, sender_unique_name)); TRYST(wire_compose_unicast_reply(&reply_ctx, ctx, msg, sender_unique_name));
TRYST(send(c->fd, reply_data, reply_ctx.byte_cursor, 0)); TRYST(send(c->fd, reply_data, reply_ctx.byte_cursor, 0));
ctx->byte_cursor = previous_cursor;
} }
} }
} }
@ -293,23 +297,18 @@ int jb_server_unicast_message(struct jb_server *s, wire_message_t *msg, wire_con
} \ } \
} while(0) \ } while(0) \
int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data, size_t data_len) int jb_server_client_process_message(struct jb_server *s, int i, wire_context_t *ctx)
{ {
struct jb_client *client = &s->clients[i]; struct jb_client *client = &s->clients[i];
wire_message_t msg = {0}; wire_message_t msg = {0};
wire_context_t ctx = {
.byte_cursor = 0,
.data = data,
.data_len = data_len,
};
if (wire_parse_message(&ctx, &msg) < 0) { if (wire_parse_message(ctx, &msg) < 0) {
printf("parsing failed\n"); printf("parsing failed\n");
return -1; return -1;
} }
printf("process_message: processed %d/%zu bytes\n", ctx.byte_cursor, data_len); printf("process_message: processed %d/%zu bytes\n", ctx->byte_cursor, ctx->data_len);
wire_message_field_t *destination_field = &msg.fields[DBUS_HEADER_FIELD_DESTINATION]; wire_message_field_t *destination_field = &msg.fields[DBUS_HEADER_FIELD_DESTINATION];
wire_message_field_t *member_field = &msg.fields[DBUS_HEADER_FIELD_MEMBER]; wire_message_field_t *member_field = &msg.fields[DBUS_HEADER_FIELD_MEMBER];
@ -356,7 +355,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
printf("assigned unique name '%s' to connection %d\n", s->names[unique_name_index].name, i); printf("assigned unique name '%s' to connection %d\n", s->names[unique_name_index].name, i);
} else if (strcmp(member, "RequestName") == 0) { } else if (strcmp(member, "RequestName") == 0) {
char *name = TRYPTR(wire_get_string(&ctx)); char *name = TRYPTR(wire_get_string(ctx));
int name_len = strlen(name); int name_len = strlen(name);
if (name_len < 1 || name_len > 256) { if (name_len < 1 || name_len > 256) {
return -1; return -1;
@ -380,7 +379,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
printf("client '%s' (index=%d) now owns name '%s'\n", s->names[client->unique_name_index].name, i, name_str); printf("client '%s' (index=%d) now owns name '%s'\n", s->names[client->unique_name_index].name, i, name_str);
} }
} else if (strcmp(member, "GetNameOwner") == 0) { } else if (strcmp(member, "GetNameOwner") == 0) {
char *name = TRYPTR(wire_get_string(&ctx)); char *name = TRYPTR(wire_get_string(ctx));
int name_len = strlen(name); int name_len = strlen(name);
if (name_len < 1 || name_len > 256) { if (name_len < 1 || name_len > 256) {
return -1; return -1;
@ -396,7 +395,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
TRYPTR(wire_set_string(&reply_ctx, s->names[target->unique_name_index].name)); TRYPTR(wire_set_string(&reply_ctx, s->names[target->unique_name_index].name));
} _reply_end() } _reply_end()
} else if (strcmp(member, "NameHasOwner") == 0) { } else if (strcmp(member, "NameHasOwner") == 0) {
char *name = TRYPTR(wire_get_string(&ctx)); char *name = TRYPTR(wire_get_string(ctx));
int name_len = strlen(name); int name_len = strlen(name);
if (name_len < 1 || name_len > 256) { if (name_len < 1 || name_len > 256) {
return -1; return -1;
@ -440,32 +439,21 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
} else if (strcmp(member, "StartServiceByName") == 0) { } else if (strcmp(member, "StartServiceByName") == 0) {
// TODO: stub (does nothing and always returns success) // TODO: stub (does nothing and always returns success)
char *name = TRYPTR(wire_get_string(&ctx)); char *name = TRYPTR(wire_get_string(ctx));
int name_len = strlen(name); int name_len = strlen(name);
if (name_len < 1 || name_len > 256) { if (name_len < 1 || name_len > 256) {
return -1; return -1;
} }
/* unused flags value */ /* unused flags value */
TRYPTR(wire_get_u32(&ctx)); TRYPTR(wire_get_u32(ctx));
printf("FIXME: STUB: StartServiceByName: %s\n", name); printf("FIXME: STUB: StartServiceByName: %s\n", name);
_reply_begin("u") { _reply_begin("u") {
TRYPTR(wire_set_u32(&reply_ctx, 1)); TRYPTR(wire_set_u32(&reply_ctx, 1));
} _reply_end() } _reply_end()
} else if (strcmp(member, "GetConnectionUnixProcessID") == 0) {
// TODO: stub (returns an error)
char *name = TRYPTR(wire_get_string(&ctx));
int name_len = strlen(name);
if (name_len < 1 || name_len > 256) {
return -1;
}
printf("FIXME: STUB: GetConnectionUnixProcessID: %s\n", name);
_reply_error("xyz.hippoz.jitterbug.NotImplemented");
} else if (strcmp(member, "AddMatch") == 0) { } else if (strcmp(member, "AddMatch") == 0) {
char *match = TRYPTR(wire_get_string(&ctx)); char *match = TRYPTR(wire_get_string(ctx));
int match_len = strlen(match); int match_len = strlen(match);
if (match_len < 1 || match_len > MATCH_RULE_MAX) { if (match_len < 1 || match_len > MATCH_RULE_MAX) {
return -1; return -1;
@ -479,7 +467,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
} else if (strcmp(member, "RemoveMatch") == 0) { } else if (strcmp(member, "RemoveMatch") == 0) {
// TODO: stub (does nothing and always returns success) // TODO: stub (does nothing and always returns success)
char *match = TRYPTR(wire_get_string(&ctx)); char *match = TRYPTR(wire_get_string(ctx));
int match_len = strlen(match); int match_len = strlen(match);
if (match_len < 1 || match_len > MATCH_RULE_MAX) { if (match_len < 1 || match_len > MATCH_RULE_MAX) {
return -1; return -1;
@ -488,6 +476,39 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
printf("FIXME: STUB: RemoveMatch: %s\n", match); printf("FIXME: STUB: RemoveMatch: %s\n", match);
_reply_begin("") {} _reply_end() _reply_begin("") {} _reply_end()
} else if (strcmp(member, "GetConnectionStats") == 0) {
// TODO: stub (always returns empty array)
printf("FIXME: STUB: GetConnectionStats\n");
_reply_begin("as") {
TRYPTR(wire_set_u32(&reply_ctx, 0));
// empty arrays still need to align
TRYPTR(wire_write_align(&reply_ctx, 8));
} _reply_end()
} else if (strcmp(member, "GetConnectionUnixProcessID") == 0) {
char *name = TRYPTR(wire_get_string(ctx));
int name_len = strlen(name);
if (name_len < 1 || name_len > 256) {
return -1;
}
struct jb_client *target = jb_server_name_find_client(s, name);
if (!target || target->unique_name_index < 0 || target->fd < 0) {
_reply_error("org.freedesktop.DBus.Error.NameHasNoOwner");
return 0;
}
struct ucred cred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(target->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1) {
_reply_error("xyz.hippoz.jitterbug.FailedToGetPID");
return 0;
}
_reply_begin("u") {
TRYPTR(wire_set_u32(&reply_ctx, cred.pid));
} _reply_end()
} else if (strcmp(member, "GetAllMatchRules") == 0) { } else if (strcmp(member, "GetAllMatchRules") == 0) {
_reply_begin("a{sas}") { _reply_begin("a{sas}") {
uint32_t *outer_array_len = TRYPTR(wire_set_u32(&reply_ctx, 0)); uint32_t *outer_array_len = TRYPTR(wire_set_u32(&reply_ctx, 0));
@ -534,8 +555,10 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
} break; } break;
case DBUS_MESSAGE_METHOD_RETURN: { case DBUS_MESSAGE_METHOD_RETURN: {
// we assume that method returns without any destination field are directed at their sender
// TODO: this is probably not correct
if (!destination_field->present) { if (!destination_field->present) {
return -1; destination_field->t.str = s->names[client->unique_name_index].name;
} }
should_forward = true; should_forward = true;
@ -557,22 +580,41 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
} }
if (destination_field->present) { if (destination_field->present) {
/* unicast */ /* unicast */
if (jb_server_unicast_message(s, &msg, &ctx, destination_field->t.str, s->names[client->unique_name_index].name) < 0) { if (jb_server_unicast_message(s, &msg, ctx, destination_field->t.str, s->names[client->unique_name_index].name) < 0) {
_reply_error("xyz.hippoz.jitterbug.UnicastFailed"); _reply_error("xyz.hippoz.jitterbug.UnicastFailed");
return 0; return 0;
} }
} else { } else {
/* broadcast */ /* broadcast */
if (jb_server_broadcast_message(s, &msg, &ctx, s->names[client->unique_name_index].name) < 0) { if (jb_server_broadcast_message(s, &msg, ctx, s->names[client->unique_name_index].name) < 0) {
_reply_error("xyz.hippoz.jitterbug.BroadcastFailed"); _reply_error("xyz.hippoz.jitterbug.BroadcastFailed");
return 0; return 0;
} }
} }
} }
if (ctx.byte_cursor < ctx.data_len && ctx.data[ctx.byte_cursor] == 'l') { return 0;
// another message }
TRYST(jb_server_client_process_message(s, i, ctx.data + ctx.byte_cursor, ctx.data_len - ctx.byte_cursor));
int jb_server_client_drain_messages(struct jb_server *s, int ci, uint8_t *data, uint32_t data_len)
{
wire_context_t ctx = {
.byte_cursor = 0,
.data = data,
.data_len = data_len
};
TRYST(jb_server_client_process_message(s, ci, &ctx));
for (int i = 0; i < 10; i++) {
if (ctx.byte_cursor >= ctx.data_len || ctx.data[ctx.byte_cursor] != 'l') {
// no more messages
break;
}
ctx.data = ctx.data + ctx.byte_cursor;
ctx.data_len = ctx.data_len - ctx.byte_cursor;
ctx.byte_cursor = 0;
TRYST(jb_server_client_process_message(s, ci, &ctx));
} }
return 0; return 0;
@ -655,7 +697,7 @@ int jb_server_turn(struct jb_server *s)
static const char auth_ok[] = "OK aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"; static const char auth_ok[] = "OK aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n";
static const char auth_list[] = "REJECTED EXTERNAL\r\n"; static const char auth_list[] = "REJECTED EXTERNAL\r\n";
static const char auth_data[] = "DATA\r\n"; static const char auth_data[] = "DATA\r\n";
static const int data_buffer_len = 4096; static const int data_buffer_len = 8192;
// We can keep a padding of null bytes for the data buffer. In the event that, for // We can keep a padding of null bytes for the data buffer. In the event that, for
// example, a string function is called on a char array without a proper ending null // example, a string function is called on a char array without a proper ending null
@ -752,7 +794,7 @@ int jb_server_turn(struct jb_server *s)
char *first_message_begin = data + 7; /* 7 = length of "BEGIN\r\n" */ char *first_message_begin = data + 7; /* 7 = length of "BEGIN\r\n" */
if (*first_message_begin == 'l' || *first_message_begin == 'B') { if (*first_message_begin == 'l' || *first_message_begin == 'B') {
// This looks like a D-Bus message. Let's process it! // This looks like a D-Bus message. Let's process it!
if (jb_server_client_process_message(s, i, (uint8_t *)first_message_begin, data_buffer_len - 7) < 0) { if (jb_server_client_drain_messages(s, i, (uint8_t *)first_message_begin, data_buffer_len - 7) < 0) {
_client_die("failed to process message"); _client_die("failed to process message");
} }
} }
@ -765,7 +807,7 @@ int jb_server_turn(struct jb_server *s)
} break; } break;
case JB_CLIENT_STATE_READY: { case JB_CLIENT_STATE_READY: {
if (jb_server_client_process_message(s, i, (uint8_t*)data, data_buffer_len) < 0) { if (jb_server_client_drain_messages(s, i, (uint8_t*)data, data_buffer_len) < 0) {
_client_die("failed to process message"); _client_die("failed to process message");
} }
} break; } break;

18
wire.c
View file

@ -182,6 +182,20 @@ int wire_compose_reply(wire_context_t *c, wire_message_t *msg, const char *signa
/* header fields */ /* header fields */
{ {
/* SENDER */
{
/* byte (field code) */
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SENDER));
/* variant */
/* signature */
TRYPTR(wire_set_signature(c, "s"));
/* string */
TRYPTR(wire_set_string(c, "org.freedesktop.DBus"));
// need to align to 8 byte boundry after each array element?
TRYPTR(wire_write_align(c, 8));
}
/* SIGNATURE */ /* SIGNATURE */
{ {
/* byte (field code) */ /* byte (field code) */
@ -336,7 +350,7 @@ int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_me
if (signature_field->present) { if (signature_field->present) {
TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SIGNATURE)); TRYPTR(wire_set_u8(c, DBUS_HEADER_FIELD_SIGNATURE));
TRYPTR(wire_set_signature(c, "g")); TRYPTR(wire_set_signature(c, "g"));
TRYPTR(wire_set_string(c, signature_field->t.str)); TRYPTR(wire_set_signature(c, signature_field->t.str));
TRYPTR(wire_write_align(c, 8)); TRYPTR(wire_write_align(c, 8));
} }
@ -356,7 +370,7 @@ int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_me
// header ends on an 8 byte alignment // header ends on an 8 byte alignment
TRYPTR(wire_write_align(c, 8)); TRYPTR(wire_write_align(c, 8));
if (c->byte_cursor + msg->body_length > c->data_len) { if (c->byte_cursor + msg->body_length >= c->data_len || msg_c->byte_cursor + msg->body_length >= msg_c->data_len) {
return -1; return -1;
} }