1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-03-09 23:38:56 +00:00

miracle-dispd: run encoder with user privilege

now we run encoder with unprivileged user and talk through session bus

Change-Id: I09b3b8b15e5a7c7e9b883b7c9dbac601c13f458c
This commit is contained in:
Derek Dai 2017-04-26 22:49:47 +08:00
parent ba10255f70
commit 6415de46fa
No known key found for this signature in database
GPG key ID: E109CC97553EF009
11 changed files with 507 additions and 123 deletions

View file

@ -476,6 +476,8 @@ private class WfdCtl : GLib.Application
return "playing"; return "playing";
case 7: case 7:
return "tearing down"; return "tearing down";
case 8:
return "destroyed";
} }
return "unknown"; return "unknown";

View file

@ -319,14 +319,13 @@ internal class GstEncoder : DispdEncoder, GLib.Object
public async void prepare() throws Error public async void prepare() throws Error
{ {
conn = yield Bus.get(BusType.SYSTEM); conn = yield Bus.get(BusType.SESSION);
conn.register_object(DispdEncoder.OBJECT_PATH, this as DispdEncoder); conn.register_object(DispdEncoder.OBJECT_PATH, this as DispdEncoder);
string bus_info = "%s\n%s".printf(conn.unique_name,
BusType.get_address_sync(BusType.SESSION));
/* we are ready, tell parent how to communicate with us */ /* we are ready, tell parent how to communicate with us */
unowned string unique_name = conn.unique_name; ssize_t r = Posix.write(3, (void *) bus_info.data, bus_info.length);
ssize_t r = Posix.write(3,
(void *) unique_name.data,
unique_name.length);
if(0 > r) { if(0 > r) {
throw new DispdEncoderError.CANT_RETURN_UNIQUE_NAME("%s", throw new DispdEncoderError.CANT_RETURN_UNIQUE_NAME("%s",
Posix.strerror(Posix.errno)); Posix.strerror(Posix.errno));

View file

@ -83,8 +83,16 @@ enum wfd_audio_server_type
int wfd_out_session_new(struct wfd_session **out, int wfd_out_session_new(struct wfd_session **out,
unsigned int id, unsigned int id,
struct wfd_sink *sink); struct wfd_sink *sink);
struct wfd_session * wfd_session_ref(struct wfd_session *s); struct wfd_session * _wfd_session_ref(struct wfd_session *s);
void wfd_session_unref(struct wfd_session *s); #define wfd_session_ref(s) ( \
log_debug("wfd_session_ref(%p): %d => %d", (s), *(int *) s, 1 + *(int *) s), \
_wfd_session_ref(s) \
)
void _wfd_session_unref(struct wfd_session *s);
#define wfd_session_unref(s) { \
log_debug("wfd_session_unref(%p): %d => %d", (s), *(int *) s, *(int *) s - 1); \
_wfd_session_unref(s); \
}
void wfd_session_unrefp(struct wfd_session **s); void wfd_session_unrefp(struct wfd_session **s);
unsigned int * wfd_session_to_htable(struct wfd_session *s); unsigned int * wfd_session_to_htable(struct wfd_session *s);
@ -117,7 +125,10 @@ int wfd_session_set_disp_dimension(struct wfd_session *s, const struct wfd_recta
enum wfd_audio_server_type wfd_session_get_audio_type(struct wfd_session *s); enum wfd_audio_server_type wfd_session_get_audio_type(struct wfd_session *s);
int wfd_session_set_audio_type(struct wfd_session *s, enum wfd_audio_server_type audio_type); int wfd_session_set_audio_type(struct wfd_session *s, enum wfd_audio_server_type audio_type);
const char * wfd_session_get_audio_dev_name(struct wfd_session *s); const char * wfd_session_get_audio_dev_name(struct wfd_session *s);
int wfd_session_set_audio_dev_name(struct wfd_session *s, char *audio_dev_name); int wfd_session_set_audio_dev_name(struct wfd_session *s, const char *audio_dev_name);
const char * wfd_session_get_runtime_path(struct wfd_session *s);
int wfd_session_set_runtime_path(struct wfd_session *s,
const char *runtime_path);
uid_t wfd_session_get_client_uid(struct wfd_session *s); uid_t wfd_session_get_client_uid(struct wfd_session *s);
int wfd_session_set_client_uid(struct wfd_session *s, uid_t uid); int wfd_session_set_client_uid(struct wfd_session *s, uid_t uid);
uid_t wfd_session_get_client_gid(struct wfd_session *s); uid_t wfd_session_get_client_gid(struct wfd_session *s);

View file

@ -22,6 +22,7 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <fcntl.h>
#include "dispd-encoder.h" #include "dispd-encoder.h"
#include "shl_macro.h" #include "shl_macro.h"
#include "shl_log.h" #include "shl_log.h"
@ -42,26 +43,30 @@ struct dispd_encoder
sd_bus_slot *name_disappeared_slot; sd_bus_slot *name_disappeared_slot;
sd_bus_slot *state_change_notify_slot; sd_bus_slot *state_change_notify_slot;
char *name; uid_t bus_owner;
uid_t bus_group;
char *bus_name;
enum dispd_encoder_state state; enum dispd_encoder_state state;
dispd_encoder_state_change_handler handler; dispd_encoder_state_change_handler handler;
void *userdata; void *userdata;
}; };
static int dispd_encoder_new(struct dispd_encoder **out); static int dispd_encoder_new(struct dispd_encoder **out,
static int on_unique_readable(sd_event_source *source, uid_t bus_owner,
gid_t bus_group);
static int on_bus_info_readable(sd_event_source *source,
int fd, int fd,
uint32_t events, uint32_t events,
void *userdata); void *userdata);
static void dispd_encoder_set_state(struct dispd_encoder *e, static void dispd_encoder_set_state(struct dispd_encoder *e,
enum dispd_encoder_state state); enum dispd_encoder_state state);
static int dispd_encoder_exec(const char *cmd, int fd, struct wfd_session *s) static void dispd_encoder_exec(const char *cmd, int fd, struct wfd_session *s)
{ {
int r; int r;
sigset_t mask; sigset_t mask;
char disp[16], auth[256]; char disp[16], runtime_path[256];
log_info("child forked with pid %d", getpid()); log_info("child forked with pid %d", getpid());
@ -70,30 +75,50 @@ static int dispd_encoder_exec(const char *cmd, int fd, struct wfd_session *s)
sigprocmask(SIG_SETMASK, &mask, NULL); sigprocmask(SIG_SETMASK, &mask, NULL);
snprintf(disp, sizeof(disp), "DISPLAY=%s", wfd_session_get_disp_name(s)); snprintf(disp, sizeof(disp), "DISPLAY=%s", wfd_session_get_disp_name(s));
snprintf(auth, sizeof(auth), "XAUTHORITY=%s", wfd_session_get_disp_auth(s)); snprintf(runtime_path, sizeof(runtime_path), "XDG_RUNTIME_DIR=%s", wfd_session_get_runtime_path(s));
/* after encoder connected to DBus, write unique name to fd 3, /* after encoder connected to DBus, write unique name to fd 3,
* so we can controll it through DBus * so we can controll it through DBus
*/ */
r = dup2(fd, 3); r = dup2(fd, 3);
if(0 > r) { if(0 > r) {
return log_ERRNO(); log_vERRNO();
goto error;
} }
if(fd != 3) { if(fd != 3) {
close(fd); close(fd);
} }
// TODO run encoder as normal user instead of root // TODO drop caps and don't let user raises thier caps
log_debug("uid=%d, euid=%d", getuid(), geteuid());
r = setgid(wfd_session_get_client_gid(s));
if(0 > r) {
log_vERRNO();
goto error;
}
r = setuid(wfd_session_get_client_uid(s));
if(0 > r) {
log_vERRNO();
goto error;
}
log_debug("uid=%d, euid=%d", getuid(), geteuid());
r = execvpe(cmd, r = execvpe(cmd,
(char *[]){ (char *) cmd, NULL }, (char *[]){ (char *) cmd, NULL },
(char *[]){ disp, (char *[]){ disp,
auth, runtime_path,
"G_MESSAGES_DEBUG=all", "G_MESSAGES_DEBUG=all",
NULL NULL
}); });
if(0 > r) {
log_vERRNO();
goto error;
}
error:
_exit(1); _exit(1);
return 0;
} }
static void dispd_encoder_close_pipe(struct dispd_encoder *e) static void dispd_encoder_close_pipe(struct dispd_encoder *e)
@ -184,7 +209,7 @@ static int on_child_terminated(sd_event_source *source,
{ {
struct dispd_encoder *e = userdata; struct dispd_encoder *e = userdata;
log_info("encoder %d terminated", si->si_pid); log_info("encoder process %d terminated", si->si_pid);
dispd_encoder_set_state(e, DISPD_ENCODER_STATE_TERMINATED); dispd_encoder_set_state(e, DISPD_ENCODER_STATE_TERMINATED);
dispd_encoder_cleanup(e); dispd_encoder_cleanup(e);
@ -194,37 +219,35 @@ static int on_child_terminated(sd_event_source *source,
int dispd_encoder_spawn(struct dispd_encoder **out, struct wfd_session *s) int dispd_encoder_spawn(struct dispd_encoder **out, struct wfd_session *s)
{ {
pid_t pid;
_dispd_encoder_unref_ struct dispd_encoder *e = NULL; _dispd_encoder_unref_ struct dispd_encoder *e = NULL;
int fds[2] = { -1, -1 }; int fds[2] = { -1, -1 };
pid_t pid;
int r; int r;
assert_ret(out); assert_ret(out);
assert_ret(s); assert_ret(s);
r = dispd_encoder_new(&e); r = dispd_encoder_new(&e,
wfd_session_get_client_uid(s),
wfd_session_get_client_gid(s));
if(0 > r) { if(0 > r) {
goto end; goto end;
} }
r = pipe(fds); r = pipe2(fds, O_NONBLOCK);
if(0 > r) { if(0 > r) {
goto end; goto end;
} }
pid = fork(); pid = fork();
if(0 > pid) { if(0 > pid) {
r = pid; r = log_ERRNO();
goto kill_encoder; goto kill_encoder;
} }
else if(!pid) { else if(!pid) {
close(fds[0]); close(fds[0]);
r = dispd_encoder_exec("gstencoder", fds[1], s); dispd_encoder_exec("gstencoder", fds[1], s);
if(0 > r) {
log_warning("failed to exec encoder: %s", strerror(errno));
}
_exit(1);
} }
r = sd_event_add_child(ctl_wfd_get_loop(), r = sd_event_add_child(ctl_wfd_get_loop(),
@ -241,7 +264,7 @@ int dispd_encoder_spawn(struct dispd_encoder **out, struct wfd_session *s)
&e->pipe_source, &e->pipe_source,
fds[0], fds[0],
EPOLLIN, EPOLLIN,
on_unique_readable, on_bus_info_readable,
dispd_encoder_ref(e)); dispd_encoder_ref(e));
if(0 > r) { if(0 > r) {
goto close_pipe; goto close_pipe;
@ -262,11 +285,14 @@ end:
return log_ERRNO(); return log_ERRNO();
} }
static int dispd_encoder_new(struct dispd_encoder **out) static int dispd_encoder_new(struct dispd_encoder **out,
uid_t bus_owner,
gid_t bus_group)
{ {
_shl_free_ struct dispd_encoder *e = NULL; _dispd_encoder_unref_ struct dispd_encoder *e = NULL;
assert_ret(out); assert_ret(out);
// assert_ret(bus_addr);
e = calloc(1, sizeof(struct dispd_encoder)); e = calloc(1, sizeof(struct dispd_encoder));
if(!e) { if(!e) {
@ -274,16 +300,22 @@ static int dispd_encoder_new(struct dispd_encoder **out)
} }
e->ref = 1; e->ref = 1;
*out = e; e->bus_owner = bus_owner;
e = NULL; e->bus_group = bus_group;
// e->bus_addr = strdup(bus_addr);
// if(!e->bus_addr) {
// return log_ENOMEM();
// }
*out = dispd_encoder_ref(e);
return 0; return 0;
} }
struct dispd_encoder * dispd_encoder_ref(struct dispd_encoder *e) struct dispd_encoder * dispd_encoder_ref(struct dispd_encoder *e)
{ {
assert_retv(e, NULL); assert_retv(e, e);
assert_retv(0 < e->ref, NULL); assert_retv(0 < e->ref, e);
++ e->ref; ++ e->ref;
@ -310,13 +342,18 @@ void dispd_encoder_unref(struct dispd_encoder *e)
/* since we encrease ref count at creation of every sources and slots, /* since we encrease ref count at creation of every sources and slots,
* once we get here, it means no sources and slots exist anymore */ * once we get here, it means no sources and slots exist anymore */
if(e->bus) { if(e->bus) {
sd_bus_detach_event(e->bus);
sd_bus_unref(e->bus); sd_bus_unref(e->bus);
} }
if(e->name) { if(e->bus_name) {
free(e->name); free(e->bus_name);
} }
// if(e->bus_addr) {
// free(e->bus_addr);
// }
free(e); free(e);
} }
@ -448,7 +485,7 @@ static int on_encoder_disappeared(sd_bus_message *m,
struct dispd_encoder *e = userdata; struct dispd_encoder *e = userdata;
int r; int r;
log_info("encoder %s disappered", e->name); log_info("encoder %s disappered from bus", e->bus_name);
r = dispd_encoder_kill_child(e); r = dispd_encoder_kill_child(e);
if(0 > r) { if(0 > r) {
@ -463,43 +500,123 @@ static int on_encoder_disappeared(sd_bus_message *m,
return 0; return 0;
} }
static int on_unique_readable(sd_event_source *source, static int read_line(int fd, char *b, size_t len)
{
int r;
char *p = b;
assert_ret(0 <= fd);
assert_ret(b);
assert_ret(len);
while((p - b) < (len - 1)) {
r = read(fd, p, 1);
if(0 > r) {
if(EINTR == errno) {
continue;
}
else if(EAGAIN == errno) {
break;
}
return log_ERRNO();
}
else if(!r || '\n' == *p) {
break;
}
++ p;
}
*p = '\0';
return p - b;
}
static int on_bus_info_readable(sd_event_source *source,
int fd, int fd,
uint32_t events, uint32_t events,
void *userdata) void *userdata)
{ {
struct dispd_encoder *e = userdata; struct dispd_encoder *e = userdata;
char buf[1024]; char buf[512];
ssize_t r; int r;
r = read(fd, buf, sizeof(buf) - 1); r = read_line(fd, buf, sizeof(buf) - 1);
if(0 > r) { if(0 > r) {
if(EAGAIN == errno) { log_vERR(r);
return 0;
}
goto error; goto error;
} }
else if(!r) { else if(!r) {
log_warning("no bus name returned from encoder: %s", log_warning("no bus name returned from encoder");
strerror(errno)); r = -ENOENT;
goto error; goto error;
} }
// TODO remove heading and trailing speces from buf before strdup() // TODO remove heading and trailing speces from buf before strdup()
buf[r] = '\0';
log_info("got bus name from encoder: %s", buf); log_info("got bus name from encoder: %s", buf);
e->name = strdup(buf); e->bus_name = strdup(buf);
if(!e->name) { if(!e->bus_name) {
log_vERRNO();
goto error; goto error;
} }
// TODO connect to encoder through user session bus r = read_line(fd, buf, sizeof(buf) - 1);
r = sd_bus_default_system(&e->bus);
if(0 > r) { if(0 > r) {
log_vERR(r);
goto error; goto error;
} }
else if(!r) {
log_warning("no bus address returned from encoder");
r = -ENOENT;
goto error;
}
log_info("got bus address from encoder: %s", buf);
log_debug(">>> uid=%d, euid=%d", getuid(), geteuid());
r = seteuid(e->bus_owner);
if(0 > r) {
log_vERRNO();
goto error;
}
r = sd_bus_new(&e->bus);
if(0 > r) {
log_vERR(r);
goto error;
}
r = sd_bus_set_address(e->bus, buf);
if(0 > r) {
log_vERR(r);
goto error;
}
r = sd_bus_set_bus_client(e->bus, true);
if(0 > r) {
log_vERR(r);
goto error;
}
r = sd_bus_start(e->bus);
if(0 > r) {
log_vERR(r);
goto error;
}
r = sd_bus_attach_event(e->bus, ctl_wfd_get_loop(), 0);
if(0 > r) {
log_vERR(r);
goto error;
}
r = seteuid(0);
if(0 > r) {
log_vERRNO();
goto error;
}
log_debug("<<< uid=%d, euid=%d", getuid(), geteuid());
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf),
"type='signal'," "type='signal',"
@ -508,36 +625,52 @@ static int on_unique_readable(sd_event_source *source,
"interface='org.freedesktop.DBus.Properties'," "interface='org.freedesktop.DBus.Properties',"
"member='PropertiesChanged'," "member='PropertiesChanged',"
"arg0='org.freedesktop.miracle.encoder'", "arg0='org.freedesktop.miracle.encoder'",
e->name); e->bus_name);
if(0 > r) {
log_vERRNO();
goto error;
}
r = sd_bus_add_match(e->bus, r = sd_bus_add_match(e->bus,
&e->state_change_notify_slot, &e->state_change_notify_slot,
buf, buf,
on_encoder_properties_changed, on_encoder_properties_changed,
dispd_encoder_ref(e)); dispd_encoder_ref(e));
if(0 > r) { if(0 > r) {
log_vERRNO();
goto error; goto error;
} }
snprintf(buf, sizeof(buf), r = snprintf(buf, sizeof(buf),
"type='signal'," "type='signal',"
"sender='org.freedesktop.DBus'," "sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus'," "path='/org/freedesktop/DBus',"
"interface='org.freedesktop.DBus'," "interface='org.freedesktop.DBus',"
"member='NameOwnerChanged'," "member='NameOwnerChanged',"
"arg0namespace='%s'", "arg0namespace='%s'",
e->name); e->bus_name);
if(0 > r) {
log_vERRNO();
goto error;
}
r = sd_bus_add_match(e->bus, r = sd_bus_add_match(e->bus,
&e->name_disappeared_slot, &e->name_disappeared_slot,
buf, buf,
on_encoder_disappeared, on_encoder_disappeared,
dispd_encoder_ref(e)); dispd_encoder_ref(e));
if(0 > r) {
log_vERRNO();
goto error;
}
dispd_encoder_set_state(e, DISPD_ENCODER_STATE_SPAWNED); dispd_encoder_set_state(e, DISPD_ENCODER_STATE_SPAWNED);
goto end; goto end;
error: error:
log_vERRNO(); seteuid(0);
log_debug("<<< uid=%d, euid=%d", getuid(), geteuid());
dispd_encoder_kill_child(e); dispd_encoder_kill_child(e);
end: end:
dispd_encoder_close_pipe(e); dispd_encoder_close_pipe(e);
@ -617,17 +750,17 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
r = sd_bus_message_new_method_call(e->bus, r = sd_bus_message_new_method_call(e->bus,
&call, &call,
e->name, e->bus_name,
"/org/freedesktop/miracle/encoder", "/org/freedesktop/miracle/encoder",
"org.freedesktop.miracle.encoder", "org.freedesktop.miracle.encoder",
"Configure"); "Configure");
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = sd_bus_message_open_container(call, 'a', "{iv}"); r = sd_bus_message_open_container(call, 'a', "{iv}");
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
sink = wfd_out_session_get_sink(s); sink = wfd_out_session_get_sink(s);
@ -636,7 +769,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"s", "s",
sink->peer->remote_address); sink->peer->remote_address);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = config_append(call, r = config_append(call,
@ -644,7 +777,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"u", "u",
s->stream.rtp_port); s->stream.rtp_port);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
if(s->stream.rtcp_port) { if(s->stream.rtcp_port) {
@ -653,7 +786,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"u", "u",
s->stream.rtcp_port); s->stream.rtcp_port);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
} }
@ -662,7 +795,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"s", "s",
sink->peer->local_address); sink->peer->local_address);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
if(s->stream.rtcp_port) { if(s->stream.rtcp_port) {
@ -671,7 +804,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"u", "u",
s->stream.rtcp_port); s->stream.rtcp_port);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
} }
@ -682,7 +815,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"u", "u",
rect->x); rect->x);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = config_append(call, r = config_append(call,
@ -690,7 +823,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"u", "u",
rect->y); rect->y);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = config_append(call, r = config_append(call,
@ -698,7 +831,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"u", "u",
rect->width); rect->width);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = config_append(call, r = config_append(call,
@ -706,23 +839,32 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s)
"u", "u",
rect->height); rect->height);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
} }
r = sd_bus_message_close_container(call); r = sd_bus_message_close_container(call);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
}
// log_debug(">>> uid=%d, euid=%d", getuid(), geteuid());
// r = seteuid(e->bus_owner);
if(0 > r) {
log_vERR(r);
goto end;
} }
r = sd_bus_call(e->bus, call, 0, &error, &reply); r = sd_bus_call(e->bus, call, 0, &error, &reply);
if(0 > r) { if(0 > r) {
log_warning("%s: %s", error.name, error.message); log_warning("%s: %s", error.name, error.message);
sd_bus_error_free(&error); log_vERR(r);
return log_ERRNO();
} }
return 0; end:
// seteuid(0);
// log_debug("<<< uid=%d, euid=%d", getuid(), geteuid());
return r;
} }
static int dispd_encoder_call(struct dispd_encoder *e, const char *method) static int dispd_encoder_call(struct dispd_encoder *e, const char *method)
@ -738,7 +880,7 @@ static int dispd_encoder_call(struct dispd_encoder *e, const char *method)
r = sd_bus_message_new_method_call(e->bus, r = sd_bus_message_new_method_call(e->bus,
&call, &call,
e->name, e->bus_name,
"/org/freedesktop/miracle/encoder", "/org/freedesktop/miracle/encoder",
"org.freedesktop.miracle.encoder", "org.freedesktop.miracle.encoder",
method); method);
@ -747,6 +889,13 @@ static int dispd_encoder_call(struct dispd_encoder *e, const char *method)
goto error; goto error;
} }
// log_debug(">>> uid=%d, euid=%d", getuid(), geteuid());
// r = seteuid(e->bus_owner);
if(0 > r) {
log_vERR(r);
goto error;
}
r = sd_bus_call(e->bus, call, 0, &error, &reply); r = sd_bus_call(e->bus, call, 0, &error, &reply);
if(0 > r) { if(0 > r) {
log_warning("%s: %s", error.name, error.message); log_warning("%s: %s", error.name, error.message);
@ -756,6 +905,8 @@ static int dispd_encoder_call(struct dispd_encoder *e, const char *method)
return 0; return 0;
error: error:
// seteuid(0);
// log_debug("<<< uid=%d, euid=%d", getuid(), geteuid());
dispd_encoder_kill_child(e); dispd_encoder_kill_child(e);
return r; return r;

View file

@ -73,7 +73,7 @@ int ctl_wfd_new(struct ctl_wfd **out, sd_event *loop, sd_bus *bus)
error: error:
ctl_wfd_free(wfd); ctl_wfd_free(wfd);
return log_ERRNO(); return log_ERR(r);
} }
static void ctl_wfd_free(struct ctl_wfd *wfd) static void ctl_wfd_free(struct ctl_wfd *wfd)
@ -144,14 +144,14 @@ int ctl_wfd_add_sink(struct ctl_wfd *wfd,
r = wfd_sink_new(&s, p, sube); r = wfd_sink_new(&s, p, sube);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = shl_htable_insert_str(&wfd->sinks, r = shl_htable_insert_str(&wfd->sinks,
wfd_sink_to_htable(s), wfd_sink_to_htable(s),
NULL); NULL);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
++wfd->n_sinks; ++wfd->n_sinks;
@ -209,7 +209,7 @@ int ctl_wfd_add_session(struct ctl_wfd *wfd, struct wfd_session *s)
r = shl_htable_insert_uint(&wfd->sessions, wfd_session_to_htable(s)); r = shl_htable_insert_uint(&wfd->sessions, wfd_session_to_htable(s));
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
++wfd->n_sessions; ++wfd->n_sessions;
@ -367,7 +367,7 @@ void ctl_fn_peer_new(struct ctl_peer *p)
r = wfd_sube_parse(sube_str, &sube); r = wfd_sube_parse(sube_str, &sube);
if(0 > r) { if(0 > r) {
log_debug("peer %s has invalid subelement", p->label); log_debug("peer %s has invalid subelement", p->label);
return log_vERRNO(); return log_vERR(r);
} }
if(wfd_sube_device_is_sink(&sube)) { if(wfd_sube_device_is_sink(&sube)) {

View file

@ -410,17 +410,67 @@ static int wfd_dbus_find_session(sd_bus *bus,
return r; return r;
} }
static int get_user_runtime_path(char **out, sd_bus *bus, uid_t uid)
{
_sd_bus_message_unref_ sd_bus_message *rep = NULL;
_sd_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char p[256];
char *rp;
int r;
assert_ret(out);
assert_ret(bus);
assert_ret(0 < uid);
r = snprintf(p, sizeof(p), "/org/freedesktop/login1/user/_%d", uid);
if(0 > r) {
return log_ERRNO();
}
r = sd_bus_call_method(bus,
"org.freedesktop.login1",
p,
"org.freedesktop.DBus.Properties",
"Get",
&error,
&rep,
"ss",
"org.freedesktop.login1.User",
"RuntimePath");
if(0 > r) {
log_warning("%s: %s", error.name, error.message);
return r;
}
r = sd_bus_message_read(rep, "v", "s", &rp);
if(0 > r) {
return log_ERR(r);
}
*out = strdup(rp);
if(!*out) {
return log_ENOMEM();
}
return 0;
}
static int wfd_dbus_sink_start_session(sd_bus_message *m, static int wfd_dbus_sink_start_session(sd_bus_message *m,
void *userdata, void *userdata,
sd_bus_error *ret_error) sd_bus_error *ret_error)
{ {
struct wfd_sink *sink = userdata;
_wfd_session_unref_ struct wfd_session *sess = NULL; _wfd_session_unref_ struct wfd_session *sess = NULL;
_shl_free_ char *path = NULL, *disp_type_name = NULL, *disp_name = NULL; _shl_free_ char *path = NULL, *disp_type_name = NULL, *disp_name = NULL;
_sd_bus_creds_unref_ sd_bus_creds *creds = NULL;
_shl_free_ char *runtime_path = NULL;
struct wfd_sink *sink = userdata;
char *disp_params; char *disp_params;
const char *disp, *disp_auth; const char *disp, *disp_auth;
const char *audio_dev; const char *audio_dev;
struct wfd_rectangle rect; struct wfd_rectangle rect;
pid_t pid;
uid_t uid;
gid_t gid;
int r; int r;
r = sd_bus_message_read(m, r = sd_bus_message_read(m,
@ -433,7 +483,7 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m,
&rect.height, &rect.height,
&audio_dev); &audio_dev);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = sscanf(disp, "%m[^:]://%ms", r = sscanf(disp, "%m[^:]://%ms",
@ -449,12 +499,12 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m,
r = wfd_sink_create_session(sink, &sess); r = wfd_sink_create_session(sink, &sess);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
wfd_session_set_disp_type(sess, WFD_DISPLAY_SERVER_TYPE_X); wfd_session_set_disp_type(sess, WFD_DISPLAY_SERVER_TYPE_X);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
disp_params = strchr(disp_name, '?'); disp_params = strchr(disp_name, '?');
@ -464,47 +514,92 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m,
r = wfd_session_set_disp_name(sess, disp_name); r = wfd_session_set_disp_name(sess, disp_name);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = wfd_session_set_disp_params(sess, disp_params); r = wfd_session_set_disp_params(sess, disp_params);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = wfd_session_set_disp_auth(sess, disp_auth); r = wfd_session_set_disp_auth(sess, disp_auth);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = wfd_session_set_disp_dimension(sess, &rect); r = wfd_session_set_disp_dimension(sess, &rect);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = wfd_session_set_audio_type(sess, WFD_AUDIO_SERVER_TYPE_PULSE_AUDIO); r = wfd_session_set_audio_type(sess, WFD_AUDIO_SERVER_TYPE_PULSE_AUDIO);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = wfd_session_set_audio_type(sess, WFD_AUDIO_SERVER_TYPE_PULSE_AUDIO); r = wfd_session_set_audio_dev_name(sess, audio_dev);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
}
r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_PID, &creds);
if(0 > r) {
return log_ERR(r);
}
r = sd_bus_creds_get_pid(creds, &pid);
if(0 > r) {
return log_ERR(r);
}
sd_bus_creds_unref(creds);
creds = NULL;
r = sd_bus_creds_new_from_pid(&creds,
pid,
SD_BUS_CREDS_UID | SD_BUS_CREDS_GID);
if(0 > r) {
return log_ERR(r);
}
wfd_session_set_client_pid(sess, gid);
r = sd_bus_creds_get_uid(creds, &uid);
if(0 > r) {
return log_ERR(r);
}
wfd_session_set_client_uid(sess, uid);
sd_bus_creds_get_gid(creds, &gid);
if(0 > r) {
return log_ERR(r);
}
wfd_session_set_client_gid(sess, gid);
r = get_user_runtime_path(&runtime_path,
sd_bus_message_get_bus(m),
uid);
if(0 > r) {
return log_ERR(r);
}
r = wfd_session_set_runtime_path(sess, runtime_path);
if(0 > r) {
return log_ERR(r);
} }
r = wfd_session_start(sess); r = wfd_session_start(sess);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = wfd_dbus_get_session_path(sess, &path); r = wfd_dbus_get_session_path(sess, &path);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
r = sd_bus_reply_method_return(m, "o", path); r = sd_bus_reply_method_return(m, "o", path);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
return 0; return 0;
@ -748,7 +843,7 @@ static int wfd_dbus_shutdown(sd_bus_message *m,
r = sd_bus_reply_method_return(m, NULL); r = sd_bus_reply_method_return(m, NULL);
if(0 > r) { if(0 > r) {
return log_ERRNO(); return log_ERR(r);
} }
return 0; return 0;

View file

@ -53,7 +53,6 @@ int wfd_out_session_new(struct wfd_session **out,
struct wfd_sink *sink) struct wfd_sink *sink)
{ {
_wfd_session_unref_ struct wfd_session *s; _wfd_session_unref_ struct wfd_session *s;
struct wfd_out_session *os;
int r; int r;
assert_ret(out); assert_ret(out);
@ -73,9 +72,8 @@ int wfd_out_session_new(struct wfd_session **out,
return log_ERR(r); return log_ERR(r);
} }
os = wfd_out_session(s); wfd_out_session(s)->fd = -1;
os->fd = -1; wfd_out_session(s)->sink = sink;
os->sink = sink;
*out = wfd_session_ref(s); *out = wfd_session_ref(s);
@ -237,6 +235,8 @@ void wfd_out_session_destroy(struct wfd_session *s)
dispd_encoder_unref(os->encoder); dispd_encoder_unref(os->encoder);
os->encoder = NULL; os->encoder = NULL;
} }
os->sink = NULL;
} }
int wfd_out_session_initiate_request(struct wfd_session *s) int wfd_out_session_initiate_request(struct wfd_session *s)
@ -564,13 +564,17 @@ static void on_encoder_state_changed(struct dispd_encoder *e,
case DISPD_ENCODER_STATE_SPAWNED: case DISPD_ENCODER_STATE_SPAWNED:
if(wfd_session_is_state(s, WFD_SESSION_STATE_SETTING_UP)) { if(wfd_session_is_state(s, WFD_SESSION_STATE_SETTING_UP)) {
r = dispd_encoder_configure(wfd_out_session(s)->encoder, s); r = dispd_encoder_configure(wfd_out_session(s)->encoder, s);
log_vERR(r); if(0 > r) {
log_vERR(r);
}
} }
break; break;
case DISPD_ENCODER_STATE_CONFIGURED: case DISPD_ENCODER_STATE_CONFIGURED:
if(wfd_session_is_state(s, WFD_SESSION_STATE_SETTING_UP)) { if(wfd_session_is_state(s, WFD_SESSION_STATE_SETTING_UP)) {
r = dispd_encoder_start(e); r = dispd_encoder_start(e);
log_vERR(r); if(0 > r) {
log_vERR(r);
}
} }
break; break;
case DISPD_ENCODER_STATE_READY: case DISPD_ENCODER_STATE_READY:
@ -582,7 +586,6 @@ static void on_encoder_state_changed(struct dispd_encoder *e,
wfd_session_set_state(s, WFD_SESSION_STATE_PAUSED); wfd_session_set_state(s, WFD_SESSION_STATE_PAUSED);
break; break;
case DISPD_ENCODER_STATE_TERMINATED: case DISPD_ENCODER_STATE_TERMINATED:
wfd_session_set_state(s, WFD_SESSION_STATE_TEARING_DOWN);
wfd_session_teardown(s); wfd_session_teardown(s);
break; break;
default: default:

View file

@ -71,10 +71,7 @@ static int wfd_session_do_request(struct wfd_session *s,
assert_ret(s); assert_ret(s);
assert_ret(rtsp_message_id_is_valid(id)); assert_ret(rtsp_message_id_is_valid(id));
assert_ret(out); assert_ret(out);
assert_retv(s->rtsp_disp_tbl[id].request, -ENOTSUP);
if(!s->rtsp_disp_tbl[id].request) {
return log_ERR(-ENOTSUP);
}
r = (*s->rtsp_disp_tbl[id].request)(s, args, out); r = (*s->rtsp_disp_tbl[id].request)(s, args, out);
if(0 > r) { if(0 > r) {
@ -95,10 +92,7 @@ static int wfd_session_do_handle_request(struct wfd_session *s,
assert_ret(rtsp_message_id_is_valid(id)); assert_ret(rtsp_message_id_is_valid(id));
assert_ret(req); assert_ret(req);
assert_ret(rep); assert_ret(rep);
assert_retv(s->rtsp_disp_tbl[id].handle_request, -ENOTSUP);
if(!s->rtsp_disp_tbl[id].handle_request) {
return log_ERR(-ENOTSUP);
}
r = (*s->rtsp_disp_tbl[id].handle_request)(s, r = (*s->rtsp_disp_tbl[id].handle_request)(s,
req, req,
@ -217,7 +211,6 @@ int wfd_session_teardown(struct wfd_session *s)
assert_ret(wfd_session_is_established(s)); assert_ret(wfd_session_is_established(s));
assert_ret(session_vtbl[s->dir].teardown); assert_ret(session_vtbl[s->dir].teardown);
r = session_vtbl[s->dir].teardown(s); r = session_vtbl[s->dir].teardown(s);
if(0 > r) { if(0 > r) {
return log_ERR(r); return log_ERR(r);
@ -283,6 +276,11 @@ int wfd_session_destroy(struct wfd_session *s)
s->audio_dev_name = NULL; s->audio_dev_name = NULL;
} }
if(s->runtime_path) {
free(s->runtime_path);
s->runtime_path = NULL;
}
s->rtp_ports[0] = 0; s->rtp_ports[0] = 0;
s->rtp_ports[1] = 0; s->rtp_ports[1] = 0;
s->last_request = RTSP_M_UNKNOWN; s->last_request = RTSP_M_UNKNOWN;
@ -292,7 +290,7 @@ int wfd_session_destroy(struct wfd_session *s)
return 0; return 0;
} }
struct wfd_session * wfd_session_ref(struct wfd_session *s) struct wfd_session * _wfd_session_ref(struct wfd_session *s)
{ {
if(s) { if(s) {
++ s->ref; ++ s->ref;
@ -301,7 +299,7 @@ struct wfd_session * wfd_session_ref(struct wfd_session *s)
return s; return s;
} }
void wfd_session_unref(struct wfd_session *s) void _wfd_session_unref(struct wfd_session *s)
{ {
if(!s) { if(!s) {
return; return;
@ -495,6 +493,30 @@ static int wfd_session_post_handle_request_n_reply(struct wfd_session *s,
return 0; return 0;
} }
static int defered_destroy(struct sd_event_source *source,
void *userdata)
{
struct wfd_session *s = userdata;
wfd_session_destroy(s);
wfd_session_unref(s);
return 0;
}
static inline int schedule_defered_destroy(struct wfd_session *s)
{
int r = sd_event_add_defer(ctl_wfd_get_loop(),
NULL,
defered_destroy,
wfd_session_ref(s));
if(0 > r) {
return log_ERR(r);
}
return 0;
}
static int wfd_session_handle_request(struct rtsp *bus, static int wfd_session_handle_request(struct rtsp *bus,
struct rtsp_message *m, struct rtsp_message *m,
void *userdata) void *userdata)
@ -507,13 +529,19 @@ static int wfd_session_handle_request(struct rtsp *bus,
time_t sec; time_t sec;
int r; int r;
if(!m && rtsp_is_dead(bus)) {
if(WFD_SESSION_STATE_TEARING_DOWN != wfd_session_get_state(s)) {
log_info("rtsp disconnected");
r = log_EPIPE();
}
goto error;
}
id = wfd_session_message_to_id(s, m); id = wfd_session_message_to_id(s, m);
if(RTSP_M_UNKNOWN == id) { if(RTSP_M_UNKNOWN == id) {
if(m) { log_debug("unable to map request to id: %s",
log_debug("unable to map request to id: %s", (char *) rtsp_message_get_raw(m));
(char *) rtsp_message_get_raw(m)); r = log_ERR(-EPROTO);
}
r = -EPROTO;
goto error; goto error;
} }
@ -526,11 +554,13 @@ static int wfd_session_handle_request(struct rtsp *bus,
m, m,
&rep); &rep);
if(0 > r) { if(0 > r) {
log_vERR(r);
goto error; goto error;
} }
r = sd_event_now(ctl_wfd_get_loop(), CLOCK_REALTIME, &usec); r = sd_event_now(ctl_wfd_get_loop(), CLOCK_REALTIME, &usec);
if(0 > r) { if(0 > r) {
log_vERR(r);
goto error; goto error;
} }
@ -541,16 +571,19 @@ static int wfd_session_handle_request(struct rtsp *bus,
r = rtsp_message_append(rep, "<&>", "Date", date); r = rtsp_message_append(rep, "<&>", "Date", date);
if(0 > r) { if(0 > r) {
log_vERR(r);
goto error; goto error;
} }
r = rtsp_message_seal(rep); r = rtsp_message_seal(rep);
if(0 > r) { if(0 > r) {
log_vERR(r);
goto error; goto error;
} }
r = rtsp_send(bus, rep); r = rtsp_send(bus, rep);
if(0 > r) { if(0 > r) {
log_vERR(r);
goto error; goto error;
} }
@ -560,15 +593,16 @@ static int wfd_session_handle_request(struct rtsp *bus,
r = wfd_session_post_handle_request_n_reply(s, id); r = wfd_session_post_handle_request_n_reply(s, id);
if(0 > r) { if(0 > r) {
log_vERR(r);
goto error; goto error;
} }
return 0; return 0;
error: error:
wfd_session_destroy(s); schedule_defered_destroy(s);
return log_ERR(r); return r;
} }
static int wfd_session_handle_reply(struct rtsp *bus, static int wfd_session_handle_reply(struct rtsp *bus,
@ -613,7 +647,7 @@ static int wfd_session_handle_reply(struct rtsp *bus,
goto end; goto end;
error: error:
wfd_session_destroy(s); schedule_defered_destroy(s);
end: end:
wfd_session_unref(s); wfd_session_unref(s);
@ -628,6 +662,9 @@ int wfd_session_init(struct wfd_session *s,
s->ref = 1; s->ref = 1;
s->id = id; s->id = id;
s->dir = dir; s->dir = dir;
s->client_uid = -1;
s->client_gid = -1;
s->client_pid = -1;
s->rtsp_disp_tbl = disp_tbl; s->rtsp_disp_tbl = disp_tbl;
return 0; return 0;
@ -904,7 +941,8 @@ const char * wfd_session_get_audio_dev_name(struct wfd_session *s)
return s->audio_dev_name; return s->audio_dev_name;
} }
int wfd_session_set_audio_dev_name(struct wfd_session *s, char *audio_dev_name) int wfd_session_set_audio_dev_name(struct wfd_session *s,
const char *audio_dev_name)
{ {
char *name; char *name;
@ -924,6 +962,82 @@ int wfd_session_set_audio_dev_name(struct wfd_session *s, char *audio_dev_name)
return 0; return 0;
} }
const char * wfd_session_get_runtime_path(struct wfd_session *s)
{
assert_retv(s, "");
return s->runtime_path;
}
int wfd_session_set_runtime_path(struct wfd_session *s,
const char *runtime_path)
{
char *path;
assert_ret(s);
path = runtime_path ? strdup(runtime_path) : NULL;
if(!path) {
return -ENOMEM;
}
if(s->runtime_path) {
free(s->runtime_path);
}
s->runtime_path = path;
return 0;
}
uid_t wfd_session_get_client_uid(struct wfd_session *s)
{
assert_retv(s, -1);
return s->client_uid;
}
int wfd_session_set_client_uid(struct wfd_session *s, uid_t uid)
{
assert_ret(s);
s->client_uid = uid;
return 0;
}
gid_t wfd_session_get_client_gid(struct wfd_session *s)
{
assert_retv(s, -1);
return s->client_gid;
}
int wfd_session_set_client_gid(struct wfd_session *s, gid_t gid)
{
assert_ret(s);
s->client_gid = gid;
return 0;
}
pid_t wfd_session_get_client_pid(struct wfd_session *s)
{
assert_retv(s, -1);
return s->client_pid;
}
int wfd_session_set_client_pid(struct wfd_session *s, pid_t pid)
{
assert_ret(s);
s->client_pid = pid;
return 0;
}
void wfd_session_unrefp(struct wfd_session **s) void wfd_session_unrefp(struct wfd_session **s)
{ {
if(s && *s) { if(s && *s) {

View file

@ -118,9 +118,13 @@ struct wfd_session
char *disp_params; char *disp_params;
char *disp_auth; char *disp_auth;
struct wfd_rectangle disp_dimen; struct wfd_rectangle disp_dimen;
enum wfd_audio_server_type audio_type; enum wfd_audio_server_type audio_type;
char *audio_dev_name; char *audio_dev_name;
uid_t client_uid;
gid_t client_gid;
gid_t client_pid;
char *runtime_path;
}; };
int wfd_session_init(struct wfd_session *s, int wfd_session_init(struct wfd_session *s,

View file

@ -143,7 +143,6 @@ int wfd_sink_create_session(struct wfd_sink *sink, struct wfd_session **out)
return r; return r;
} }
sink->session = wfd_session_ref(sess);
*out = wfd_session_ref(sess); *out = wfd_session_ref(sess);
wfd_fn_sink_properties_changed(sink, "Session"); wfd_fn_sink_properties_changed(sink, "Session");

View file

@ -37,6 +37,11 @@ static inline void cleanup_sd_bus_message(sd_bus_message **ptr)
sd_bus_message_unref(*ptr); sd_bus_message_unref(*ptr);
} }
static inline void cleanup_sd_bus_creds(sd_bus_creds **ptr)
{
sd_bus_creds_unref(*ptr);
}
static inline void cleanup_udev_device(struct udev_device **ptr) static inline void cleanup_udev_device(struct udev_device **ptr)
{ {
udev_device_unref(*ptr); udev_device_unref(*ptr);
@ -51,6 +56,7 @@ static inline void cleanup_udev_enumerate(struct udev_enumerate **ptr)
#define _sd_bus_error_free_ _shl_cleanup_(sd_bus_error_free) #define _sd_bus_error_free_ _shl_cleanup_(sd_bus_error_free)
#define _cleanup_sd_bus_message_ _shl_cleanup_(cleanup_sd_bus_message) #define _cleanup_sd_bus_message_ _shl_cleanup_(cleanup_sd_bus_message)
#define _sd_bus_message_unref_ _shl_cleanup_(cleanup_sd_bus_message) #define _sd_bus_message_unref_ _shl_cleanup_(cleanup_sd_bus_message)
#define _sd_bus_creds_unref_ _shl_cleanup_(cleanup_sd_bus_creds)
#define _cleanup_udev_device_ _shl_cleanup_(cleanup_udev_device) #define _cleanup_udev_device_ _shl_cleanup_(cleanup_udev_device)
#define _cleanup_udev_enumerate_ _shl_cleanup_(cleanup_udev_enumerate) #define _cleanup_udev_enumerate_ _shl_cleanup_(cleanup_udev_enumerate)