diff --git a/demo/wfdctl.vala b/demo/wfdctl.vala index bfba80e..e3b99b0 100644 --- a/demo/wfdctl.vala +++ b/demo/wfdctl.vala @@ -476,6 +476,8 @@ private class WfdCtl : GLib.Application return "playing"; case 7: return "tearing down"; + case 8: + return "destroyed"; } return "unknown"; diff --git a/res/gstencoder.vala b/res/gstencoder.vala index bffb80f..e8c4aa1 100644 --- a/res/gstencoder.vala +++ b/res/gstencoder.vala @@ -319,14 +319,13 @@ internal class GstEncoder : DispdEncoder, GLib.Object 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); + 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 */ - unowned string unique_name = conn.unique_name; - ssize_t r = Posix.write(3, - (void *) unique_name.data, - unique_name.length); + ssize_t r = Posix.write(3, (void *) bus_info.data, bus_info.length); if(0 > r) { throw new DispdEncoderError.CANT_RETURN_UNIQUE_NAME("%s", Posix.strerror(Posix.errno)); diff --git a/src/disp/disp.h b/src/disp/disp.h index 8f690e5..8a57564 100644 --- a/src/disp/disp.h +++ b/src/disp/disp.h @@ -83,8 +83,16 @@ enum wfd_audio_server_type int wfd_out_session_new(struct wfd_session **out, unsigned int id, struct wfd_sink *sink); -struct wfd_session * wfd_session_ref(struct wfd_session *s); -void wfd_session_unref(struct wfd_session *s); +struct wfd_session * _wfd_session_ref(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); 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); 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); -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); int wfd_session_set_client_uid(struct wfd_session *s, uid_t uid); uid_t wfd_session_get_client_gid(struct wfd_session *s); diff --git a/src/disp/dispd-encoder.c b/src/disp/dispd-encoder.c index 32974af..bb45769 100644 --- a/src/disp/dispd-encoder.c +++ b/src/disp/dispd-encoder.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "dispd-encoder.h" #include "shl_macro.h" #include "shl_log.h" @@ -42,26 +43,30 @@ struct dispd_encoder sd_bus_slot *name_disappeared_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; dispd_encoder_state_change_handler handler; void *userdata; }; -static int dispd_encoder_new(struct dispd_encoder **out); -static int on_unique_readable(sd_event_source *source, +static int dispd_encoder_new(struct dispd_encoder **out, + uid_t bus_owner, + gid_t bus_group); +static int on_bus_info_readable(sd_event_source *source, int fd, uint32_t events, void *userdata); static void dispd_encoder_set_state(struct dispd_encoder *e, 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; sigset_t mask; - char disp[16], auth[256]; + char disp[16], runtime_path[256]; 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); 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, * so we can controll it through DBus */ r = dup2(fd, 3); if(0 > r) { - return log_ERRNO(); + log_vERRNO(); + goto error; } if(fd != 3) { 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, (char *[]){ (char *) cmd, NULL }, (char *[]){ disp, - auth, + runtime_path, "G_MESSAGES_DEBUG=all", NULL }); + if(0 > r) { + log_vERRNO(); + goto error; + } + +error: _exit(1); - return 0; } 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; - 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_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) { - pid_t pid; _dispd_encoder_unref_ struct dispd_encoder *e = NULL; int fds[2] = { -1, -1 }; + pid_t pid; int r; assert_ret(out); 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) { goto end; } - r = pipe(fds); + r = pipe2(fds, O_NONBLOCK); if(0 > r) { goto end; } pid = fork(); if(0 > pid) { - r = pid; + r = log_ERRNO(); goto kill_encoder; } else if(!pid) { close(fds[0]); - r = dispd_encoder_exec("gstencoder", fds[1], s); - if(0 > r) { - log_warning("failed to exec encoder: %s", strerror(errno)); - } - _exit(1); + dispd_encoder_exec("gstencoder", fds[1], s); } 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, fds[0], EPOLLIN, - on_unique_readable, + on_bus_info_readable, dispd_encoder_ref(e)); if(0 > r) { goto close_pipe; @@ -262,11 +285,14 @@ end: 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(bus_addr); e = calloc(1, sizeof(struct dispd_encoder)); if(!e) { @@ -274,16 +300,22 @@ static int dispd_encoder_new(struct dispd_encoder **out) } e->ref = 1; - *out = e; - e = NULL; + e->bus_owner = bus_owner; + 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; } struct dispd_encoder * dispd_encoder_ref(struct dispd_encoder *e) { - assert_retv(e, NULL); - assert_retv(0 < e->ref, NULL); + assert_retv(e, e); + assert_retv(0 < e->ref, e); ++ 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, * once we get here, it means no sources and slots exist anymore */ if(e->bus) { + sd_bus_detach_event(e->bus); sd_bus_unref(e->bus); } - if(e->name) { - free(e->name); + if(e->bus_name) { + free(e->bus_name); } +// if(e->bus_addr) { +// free(e->bus_addr); +// } + free(e); } @@ -448,7 +485,7 @@ static int on_encoder_disappeared(sd_bus_message *m, struct dispd_encoder *e = userdata; 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); if(0 > r) { @@ -463,43 +500,123 @@ static int on_encoder_disappeared(sd_bus_message *m, 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, uint32_t events, void *userdata) { struct dispd_encoder *e = userdata; - char buf[1024]; - ssize_t r; + char buf[512]; + int r; - r = read(fd, buf, sizeof(buf) - 1); + r = read_line(fd, buf, sizeof(buf) - 1); if(0 > r) { - if(EAGAIN == errno) { - return 0; - } - + log_vERR(r); goto error; } else if(!r) { - log_warning("no bus name returned from encoder: %s", - strerror(errno)); + log_warning("no bus name returned from encoder"); + r = -ENOENT; goto error; } // TODO remove heading and trailing speces from buf before strdup() - buf[r] = '\0'; log_info("got bus name from encoder: %s", buf); - e->name = strdup(buf); - if(!e->name) { + e->bus_name = strdup(buf); + if(!e->bus_name) { + log_vERRNO(); goto error; } - // TODO connect to encoder through user session bus - r = sd_bus_default_system(&e->bus); + r = read_line(fd, buf, sizeof(buf) - 1); if(0 > r) { + log_vERR(r); 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), "type='signal'," @@ -508,36 +625,52 @@ static int on_unique_readable(sd_event_source *source, "interface='org.freedesktop.DBus.Properties'," "member='PropertiesChanged'," "arg0='org.freedesktop.miracle.encoder'", - e->name); + e->bus_name); + if(0 > r) { + log_vERRNO(); + goto error; + } + r = sd_bus_add_match(e->bus, &e->state_change_notify_slot, buf, on_encoder_properties_changed, dispd_encoder_ref(e)); if(0 > r) { + log_vERRNO(); goto error; } - snprintf(buf, sizeof(buf), + r = snprintf(buf, sizeof(buf), "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0namespace='%s'", - e->name); + e->bus_name); + if(0 > r) { + log_vERRNO(); + goto error; + } + r = sd_bus_add_match(e->bus, &e->name_disappeared_slot, buf, on_encoder_disappeared, dispd_encoder_ref(e)); + if(0 > r) { + log_vERRNO(); + goto error; + } dispd_encoder_set_state(e, DISPD_ENCODER_STATE_SPAWNED); goto end; error: - log_vERRNO(); + seteuid(0); + log_debug("<<< uid=%d, euid=%d", getuid(), geteuid()); dispd_encoder_kill_child(e); end: 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, &call, - e->name, + e->bus_name, "/org/freedesktop/miracle/encoder", "org.freedesktop.miracle.encoder", "Configure"); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = sd_bus_message_open_container(call, 'a', "{iv}"); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } sink = wfd_out_session_get_sink(s); @@ -636,7 +769,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s) "s", sink->peer->remote_address); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = config_append(call, @@ -644,7 +777,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s) "u", s->stream.rtp_port); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } if(s->stream.rtcp_port) { @@ -653,7 +786,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s) "u", s->stream.rtcp_port); 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", sink->peer->local_address); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } if(s->stream.rtcp_port) { @@ -671,7 +804,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s) "u", s->stream.rtcp_port); 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", rect->x); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = config_append(call, @@ -690,7 +823,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s) "u", rect->y); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = config_append(call, @@ -698,7 +831,7 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s) "u", rect->width); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = config_append(call, @@ -706,23 +839,32 @@ int dispd_encoder_configure(struct dispd_encoder *e, struct wfd_session *s) "u", rect->height); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } } r = sd_bus_message_close_container(call); 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); if(0 > r) { log_warning("%s: %s", error.name, error.message); - sd_bus_error_free(&error); - return log_ERRNO(); + log_vERR(r); } - 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) @@ -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, &call, - e->name, + e->bus_name, "/org/freedesktop/miracle/encoder", "org.freedesktop.miracle.encoder", method); @@ -747,6 +889,13 @@ static int dispd_encoder_call(struct dispd_encoder *e, const char *method) 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); if(0 > r) { 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; error: +// seteuid(0); +// log_debug("<<< uid=%d, euid=%d", getuid(), geteuid()); dispd_encoder_kill_child(e); return r; diff --git a/src/disp/dispd.c b/src/disp/dispd.c index 3ed7c40..ec78b83 100644 --- a/src/disp/dispd.c +++ b/src/disp/dispd.c @@ -73,7 +73,7 @@ int ctl_wfd_new(struct ctl_wfd **out, sd_event *loop, sd_bus *bus) error: ctl_wfd_free(wfd); - return log_ERRNO(); + return log_ERR(r); } 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); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = shl_htable_insert_str(&wfd->sinks, wfd_sink_to_htable(s), NULL); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } ++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)); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } ++wfd->n_sessions; @@ -367,7 +367,7 @@ void ctl_fn_peer_new(struct ctl_peer *p) r = wfd_sube_parse(sube_str, &sube); if(0 > r) { log_debug("peer %s has invalid subelement", p->label); - return log_vERRNO(); + return log_vERR(r); } if(wfd_sube_device_is_sink(&sube)) { diff --git a/src/disp/wfd-dbus.c b/src/disp/wfd-dbus.c index fd96746..9313f83 100644 --- a/src/disp/wfd-dbus.c +++ b/src/disp/wfd-dbus.c @@ -410,17 +410,67 @@ static int wfd_dbus_find_session(sd_bus *bus, 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, void *userdata, sd_bus_error *ret_error) { - struct wfd_sink *sink = userdata; _wfd_session_unref_ struct wfd_session *sess = 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; const char *disp, *disp_auth; const char *audio_dev; struct wfd_rectangle rect; + pid_t pid; + uid_t uid; + gid_t gid; int r; r = sd_bus_message_read(m, @@ -433,7 +483,7 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m, &rect.height, &audio_dev); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } 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); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } wfd_session_set_disp_type(sess, WFD_DISPLAY_SERVER_TYPE_X); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } 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); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = wfd_session_set_disp_params(sess, disp_params); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = wfd_session_set_disp_auth(sess, disp_auth); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = wfd_session_set_disp_dimension(sess, &rect); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = wfd_session_set_audio_type(sess, WFD_AUDIO_SERVER_TYPE_PULSE_AUDIO); 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) { - 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); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = wfd_dbus_get_session_path(sess, &path); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } r = sd_bus_reply_method_return(m, "o", path); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } return 0; @@ -748,7 +843,7 @@ static int wfd_dbus_shutdown(sd_bus_message *m, r = sd_bus_reply_method_return(m, NULL); if(0 > r) { - return log_ERRNO(); + return log_ERR(r); } return 0; diff --git a/src/disp/wfd-out-session.c b/src/disp/wfd-out-session.c index acc36b8..7e55491 100644 --- a/src/disp/wfd-out-session.c +++ b/src/disp/wfd-out-session.c @@ -53,7 +53,6 @@ int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink) { _wfd_session_unref_ struct wfd_session *s; - struct wfd_out_session *os; int r; assert_ret(out); @@ -73,9 +72,8 @@ int wfd_out_session_new(struct wfd_session **out, return log_ERR(r); } - os = wfd_out_session(s); - os->fd = -1; - os->sink = sink; + wfd_out_session(s)->fd = -1; + wfd_out_session(s)->sink = sink; *out = wfd_session_ref(s); @@ -237,6 +235,8 @@ void wfd_out_session_destroy(struct wfd_session *s) dispd_encoder_unref(os->encoder); os->encoder = NULL; } + + os->sink = NULL; } 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: if(wfd_session_is_state(s, WFD_SESSION_STATE_SETTING_UP)) { r = dispd_encoder_configure(wfd_out_session(s)->encoder, s); - log_vERR(r); + if(0 > r) { + log_vERR(r); + } } break; case DISPD_ENCODER_STATE_CONFIGURED: if(wfd_session_is_state(s, WFD_SESSION_STATE_SETTING_UP)) { r = dispd_encoder_start(e); - log_vERR(r); + if(0 > r) { + log_vERR(r); + } } break; 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); break; case DISPD_ENCODER_STATE_TERMINATED: - wfd_session_set_state(s, WFD_SESSION_STATE_TEARING_DOWN); wfd_session_teardown(s); break; default: diff --git a/src/disp/wfd-session.c b/src/disp/wfd-session.c index 938e7ae..35db848 100644 --- a/src/disp/wfd-session.c +++ b/src/disp/wfd-session.c @@ -71,10 +71,7 @@ static int wfd_session_do_request(struct wfd_session *s, assert_ret(s); assert_ret(rtsp_message_id_is_valid(id)); assert_ret(out); - - if(!s->rtsp_disp_tbl[id].request) { - return log_ERR(-ENOTSUP); - } + assert_retv(s->rtsp_disp_tbl[id].request, -ENOTSUP); r = (*s->rtsp_disp_tbl[id].request)(s, args, out); 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(req); assert_ret(rep); - - if(!s->rtsp_disp_tbl[id].handle_request) { - return log_ERR(-ENOTSUP); - } + assert_retv(s->rtsp_disp_tbl[id].handle_request, -ENOTSUP); r = (*s->rtsp_disp_tbl[id].handle_request)(s, req, @@ -217,7 +211,6 @@ int wfd_session_teardown(struct wfd_session *s) assert_ret(wfd_session_is_established(s)); assert_ret(session_vtbl[s->dir].teardown); - r = session_vtbl[s->dir].teardown(s); if(0 > r) { return log_ERR(r); @@ -283,6 +276,11 @@ int wfd_session_destroy(struct wfd_session *s) 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[1] = 0; s->last_request = RTSP_M_UNKNOWN; @@ -292,7 +290,7 @@ int wfd_session_destroy(struct wfd_session *s) return 0; } -struct wfd_session * wfd_session_ref(struct wfd_session *s) +struct wfd_session * _wfd_session_ref(struct wfd_session *s) { if(s) { ++ s->ref; @@ -301,7 +299,7 @@ struct wfd_session * wfd_session_ref(struct wfd_session *s) return s; } -void wfd_session_unref(struct wfd_session *s) +void _wfd_session_unref(struct wfd_session *s) { if(!s) { return; @@ -495,6 +493,30 @@ static int wfd_session_post_handle_request_n_reply(struct wfd_session *s, 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, struct rtsp_message *m, void *userdata) @@ -507,13 +529,19 @@ static int wfd_session_handle_request(struct rtsp *bus, time_t sec; 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); if(RTSP_M_UNKNOWN == id) { - if(m) { - log_debug("unable to map request to id: %s", - (char *) rtsp_message_get_raw(m)); - } - r = -EPROTO; + log_debug("unable to map request to id: %s", + (char *) rtsp_message_get_raw(m)); + r = log_ERR(-EPROTO); goto error; } @@ -526,11 +554,13 @@ static int wfd_session_handle_request(struct rtsp *bus, m, &rep); if(0 > r) { + log_vERR(r); goto error; } r = sd_event_now(ctl_wfd_get_loop(), CLOCK_REALTIME, &usec); if(0 > r) { + log_vERR(r); goto error; } @@ -541,16 +571,19 @@ static int wfd_session_handle_request(struct rtsp *bus, r = rtsp_message_append(rep, "<&>", "Date", date); if(0 > r) { + log_vERR(r); goto error; } r = rtsp_message_seal(rep); if(0 > r) { + log_vERR(r); goto error; } r = rtsp_send(bus, rep); if(0 > r) { + log_vERR(r); 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); if(0 > r) { + log_vERR(r); goto error; } return 0; error: - wfd_session_destroy(s); + schedule_defered_destroy(s); - return log_ERR(r); + return r; } static int wfd_session_handle_reply(struct rtsp *bus, @@ -613,7 +647,7 @@ static int wfd_session_handle_reply(struct rtsp *bus, goto end; error: - wfd_session_destroy(s); + schedule_defered_destroy(s); end: wfd_session_unref(s); @@ -628,6 +662,9 @@ int wfd_session_init(struct wfd_session *s, s->ref = 1; s->id = id; s->dir = dir; + s->client_uid = -1; + s->client_gid = -1; + s->client_pid = -1; s->rtsp_disp_tbl = disp_tbl; return 0; @@ -904,7 +941,8 @@ const char * wfd_session_get_audio_dev_name(struct wfd_session *s) 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; @@ -924,6 +962,82 @@ int wfd_session_set_audio_dev_name(struct wfd_session *s, char *audio_dev_name) 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) { if(s && *s) { diff --git a/src/disp/wfd-session.h b/src/disp/wfd-session.h index 459582e..e4b4e3a 100644 --- a/src/disp/wfd-session.h +++ b/src/disp/wfd-session.h @@ -118,9 +118,13 @@ struct wfd_session char *disp_params; char *disp_auth; struct wfd_rectangle disp_dimen; - enum wfd_audio_server_type audio_type; 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, diff --git a/src/disp/wfd-sink.c b/src/disp/wfd-sink.c index b08adb7..431b8c7 100644 --- a/src/disp/wfd-sink.c +++ b/src/disp/wfd-sink.c @@ -143,7 +143,6 @@ int wfd_sink_create_session(struct wfd_sink *sink, struct wfd_session **out) return r; } - sink->session = wfd_session_ref(sess); *out = wfd_session_ref(sess); wfd_fn_sink_properties_changed(sink, "Session"); diff --git a/src/shared/util.h b/src/shared/util.h index 5b85742..23413b0 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -37,6 +37,11 @@ static inline void cleanup_sd_bus_message(sd_bus_message **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) { 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 _cleanup_sd_bus_message_ _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_enumerate_ _shl_cleanup_(cleanup_udev_enumerate)