diff --git a/src/wayland-os.c b/src/wayland-os.c index f00ead4b..6bf8543e 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -27,6 +27,8 @@ #include "../config.h" +#include +#include #include #include #include @@ -129,6 +131,34 @@ wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) #error "Don't know how to read ucred on this platform" #endif +int +wl_os_socket_peersec(int sockfd, char **security_context) +{ +#if defined(SO_PEERSEC) + socklen_t len = NAME_MAX; + char *context = NULL; + int r; + + do { + char *new_context = realloc(context, len); + if (!new_context) { + free(context); + return -1; + } + context = new_context; + + r = getsockopt(sockfd, SOL_SOCKET, SO_PEERSEC, context, &len); + if (r < 0 && errno != ERANGE) { + free(context); + return -1; + } + } while (r < 0 && errno == ERANGE); + + *security_context = context; +#endif + return 0; +} + int wl_os_dupfd_cloexec(int fd, int minfd) { diff --git a/src/wayland-os.h b/src/wayland-os.h index 068fd2fe..3d9aeab4 100644 --- a/src/wayland-os.h +++ b/src/wayland-os.h @@ -35,6 +35,9 @@ wl_os_socket_cloexec(int domain, int type, int protocol); int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid); +int +wl_os_socket_peersec(int sockfd, char **security_context); + int wl_os_dupfd_cloexec(int fd, int minfd); diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index c8a64772..673099bf 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -327,6 +327,10 @@ void wl_client_get_credentials(const struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid); +void +wl_client_get_security_context(struct wl_client *client, + char **security_context); + int wl_client_get_fd(struct wl_client *client); diff --git a/src/wayland-server.c b/src/wayland-server.c index c81d98f1..3d5d5efc 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -82,6 +82,7 @@ struct wl_client { pid_t pid; uid_t uid; gid_t gid; + char *security_context; bool error; struct wl_priv_signal resource_created_signal; void *data; @@ -654,6 +655,40 @@ wl_client_get_credentials(const struct wl_client *client, *gid = client->gid; } +/** Return Security context for the client + * + * \param client The display object + * \param security_context Returns the security_context, or NULL if + * a security context could not be obtained. + * + * This function returns the security context for the given client. + * The credentials come from getsockopt() with SO_PEERSEC, on the + * client socket fd. + * + * Be aware that for clients that a compositor forks and execs and + * then connects using socketpair(), this function will return the + * security context for the compositor. The security context for + * the socketpair are set at creation time in the compositor. + * + * \memberof wl_client + */ +WL_EXPORT void +wl_client_get_security_context(struct wl_client *client, + char **security_context) +{ + // Only initalise the security context if we have to + // so we don't waste heap space. + if (!client->security_context) { + if (wl_os_socket_peersec(wl_connection_get_fd(client->connection), + &client->security_context) != 0) { + *security_context = NULL; + return; + } + } + + *security_context = client->security_context; +} + /** Get the file descriptor for the client * * \param client The display object @@ -1019,6 +1054,8 @@ wl_client_destroy(struct wl_client *client) wl_priv_signal_final_emit(&client->destroy_late_signal, client); + free(client->security_context); + wl_list_remove(&client->resource_created_signal.listener_list); if (client->data_dtor)