Re: [hackers] [slstatus][PATCH] Use the sioctl_open(3) OpenBSD API to access audio controls
Hi, thanks for the great work! These changes are upstream now. Regards, Aaron On 20-05-09 Sat, Ingo Feinerer wrote: Starting with OpenBSD 6.7 regular users cannot access raw audio devices anymore, for improved security. Instead use the sioctl_open(3) API to access and manipulate audio controls exposed by sndiod(8). On the first call a permanent connection is established with the running sndiod daemon, and call-back functions are registered which are triggered when audio controls are changed (e.g., a USB headset is attached) or when the volume is modified. On subsequent calls we poll for changes; if there are no volume changes this costs virtually nothing. Joint work with Alexandre Ratchov. --- LICENSE | 3 +- components/volume.c | 210 +--- config.def.h| 1 + config.mk | 1 + 4 files changed, 163 insertions(+), 52 deletions(-) diff --git a/LICENSE b/LICENSE index 0eec587..c61489f 100644 --- a/LICENSE +++ b/LICENSE @@ -19,7 +19,8 @@ Copyright 2018 David Demelier Copyright 2018-2019 Michael Buch Copyright 2018 Ian Remmler Copyright 2016-2019 Joerg Jung -Copyright 2019 Ingo Feinerer +Copyright 2019-2020 Ingo Feinerer +Copyright 2020 Alexandre Ratchov Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/components/volume.c b/components/volume.c index 61cec90..b6665da 100644 --- a/components/volume.c +++ b/components/volume.c @@ -8,69 +8,177 @@ #include "../util.h" #if defined(__OpenBSD__) - #include + #include + #include + #include + #include + + struct control { + LIST_ENTRY(control) next; + unsigned intaddr; + #define CTRL_NONE 0 + #define CTRL_LEVEL 1 + #define CTRL_MUTE 2 + unsigned inttype; + unsigned intmaxval; + unsigned intval; + }; + + static LIST_HEAD(, control) controls = LIST_HEAD_INITIALIZER(controls); + static struct pollfd *pfds; + static struct sioctl_hdl *hdl; + static int initialized; + + /* +* Call-back to obtain the description of all audio controls. +*/ + static void + ondesc(void *unused, struct sioctl_desc *desc, int val) + { + struct control *c, *ctmp; + unsigned int type = CTRL_NONE; + + if (desc == NULL) + return; + + /* Delete existing audio control with the same address. */ + LIST_FOREACH_SAFE(c, &controls, next, ctmp) { + if (desc->addr == c->addr) { + LIST_REMOVE(c, next); + free(c); + break; + } + } + + /* Only match output.level and output.mute audio controls. */ + if (desc->group[0] != 0 || + strcmp(desc->node0.name, "output") != 0) + return; + if (desc->type == SIOCTL_NUM && + strcmp(desc->func, "level") == 0) + type = CTRL_LEVEL; + else if (desc->type == SIOCTL_SW && +strcmp(desc->func, "mute") == 0) + type = CTRL_MUTE; + else + return; + + c = malloc(sizeof(struct control)); + if (c == NULL) { + warn("sndio: failed to allocate audio control\n"); + return; + } + + c->addr = desc->addr; + c->type = type; + c->maxval = desc->maxval; + c->val = val; + LIST_INSERT_HEAD(&controls, c, next); + } + + /* +* Call-back invoked whenever an audio control changes. +*/ + static void + onval(void *unused, unsigned int addr, unsigned int val) + { + struct control *c; + + LIST_FOREACH(c, &controls, next) { + if (c->addr == addr) + break; + } + c->val = val; + } + + static void + cleanup(void) + { + struct control *c; + + if (hdl) { + sioctl_close(hdl); + hdl = NULL; + } + + free(pfds); + pfds = NULL; + + while (!LIST_EMPTY(&controls)) { + c = LIST_FIRST(&controls); + LIST_REMOVE(c, next); + free(c); + } + } + + static int + init(void) + { + hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0); + if (hdl == NULL) { +
[hackers] [slstatus][PATCH] Use the sioctl_open(3) OpenBSD API to access audio controls
Starting with OpenBSD 6.7 regular users cannot access raw audio devices anymore, for improved security. Instead use the sioctl_open(3) API to access and manipulate audio controls exposed by sndiod(8). On the first call a permanent connection is established with the running sndiod daemon, and call-back functions are registered which are triggered when audio controls are changed (e.g., a USB headset is attached) or when the volume is modified. On subsequent calls we poll for changes; if there are no volume changes this costs virtually nothing. Joint work with Alexandre Ratchov. --- LICENSE | 3 +- components/volume.c | 210 +--- config.def.h| 1 + config.mk | 1 + 4 files changed, 163 insertions(+), 52 deletions(-) diff --git a/LICENSE b/LICENSE index 0eec587..c61489f 100644 --- a/LICENSE +++ b/LICENSE @@ -19,7 +19,8 @@ Copyright 2018 David Demelier Copyright 2018-2019 Michael Buch Copyright 2018 Ian Remmler Copyright 2016-2019 Joerg Jung -Copyright 2019 Ingo Feinerer +Copyright 2019-2020 Ingo Feinerer +Copyright 2020 Alexandre Ratchov Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/components/volume.c b/components/volume.c index 61cec90..b6665da 100644 --- a/components/volume.c +++ b/components/volume.c @@ -8,69 +8,177 @@ #include "../util.h" #if defined(__OpenBSD__) - #include + #include + #include + #include + #include + + struct control { + LIST_ENTRY(control) next; + unsigned intaddr; + #define CTRL_NONE 0 + #define CTRL_LEVEL 1 + #define CTRL_MUTE 2 + unsigned inttype; + unsigned intmaxval; + unsigned intval; + }; + + static LIST_HEAD(, control) controls = LIST_HEAD_INITIALIZER(controls); + static struct pollfd *pfds; + static struct sioctl_hdl *hdl; + static int initialized; + + /* +* Call-back to obtain the description of all audio controls. +*/ + static void + ondesc(void *unused, struct sioctl_desc *desc, int val) + { + struct control *c, *ctmp; + unsigned int type = CTRL_NONE; + + if (desc == NULL) + return; + + /* Delete existing audio control with the same address. */ + LIST_FOREACH_SAFE(c, &controls, next, ctmp) { + if (desc->addr == c->addr) { + LIST_REMOVE(c, next); + free(c); + break; + } + } + + /* Only match output.level and output.mute audio controls. */ + if (desc->group[0] != 0 || + strcmp(desc->node0.name, "output") != 0) + return; + if (desc->type == SIOCTL_NUM && + strcmp(desc->func, "level") == 0) + type = CTRL_LEVEL; + else if (desc->type == SIOCTL_SW && +strcmp(desc->func, "mute") == 0) + type = CTRL_MUTE; + else + return; + + c = malloc(sizeof(struct control)); + if (c == NULL) { + warn("sndio: failed to allocate audio control\n"); + return; + } + + c->addr = desc->addr; + c->type = type; + c->maxval = desc->maxval; + c->val = val; + LIST_INSERT_HEAD(&controls, c, next); + } + + /* +* Call-back invoked whenever an audio control changes. +*/ + static void + onval(void *unused, unsigned int addr, unsigned int val) + { + struct control *c; + + LIST_FOREACH(c, &controls, next) { + if (c->addr == addr) + break; + } + c->val = val; + } + + static void + cleanup(void) + { + struct control *c; + + if (hdl) { + sioctl_close(hdl); + hdl = NULL; + } + + free(pfds); + pfds = NULL; + + while (!LIST_EMPTY(&controls)) { + c = LIST_FIRST(&controls); + LIST_REMOVE(c, next); + free(c); + } + } + + static int + init(void) + { + hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0); + if (hdl == NULL) { + warn("sndio: cannot open device"); + goto failed; +