mirror of https://github.com/ericonr/sndio.git
use a cookie for authentication
This commit is contained in:
parent
2a4059ae60
commit
0663ca6f54
|
@ -41,6 +41,7 @@ struct amsg {
|
|||
#define AMSG_SETVOL 9 /* set volume */
|
||||
#define AMSG_HELLO 10 /* say hello, check versions and so ... */
|
||||
#define AMSG_BYE 11 /* ask server to drop connection */
|
||||
#define AMSG_AUTH 12 /* send authentication cookie */
|
||||
uint32_t cmd;
|
||||
uint32_t __pad;
|
||||
union {
|
||||
|
@ -79,6 +80,10 @@ struct amsg {
|
|||
char opt[12]; /* profile name */
|
||||
char who[12]; /* hint for leases */
|
||||
} hello;
|
||||
struct amsg_auth {
|
||||
#define AMSG_COOKIELEN 16
|
||||
uint8_t cookie[AMSG_COOKIELEN];
|
||||
} auth;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
|
|
@ -533,12 +533,14 @@ Note that the sequencer must use
|
|||
.Va aucat:0
|
||||
as the MTC source, i.e. the audio server, not the audio player.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width "AUDIODEVICE" -compact
|
||||
.Bl -tag -width "AUCAT_COOKIE" -compact
|
||||
.It Ev AUDIODEVICE
|
||||
.Xr sndio 7
|
||||
audio device to use if the
|
||||
.Fl f
|
||||
option is not specified.
|
||||
.It Ev AUCAT_COOKIE
|
||||
file containing a user's session cookie.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
The following will mix and play two stereo streams,
|
||||
|
|
55
aucat/sock.c
55
aucat/sock.c
|
@ -97,13 +97,14 @@ struct ctl_ops ctl_sockops = {
|
|||
};
|
||||
|
||||
unsigned sock_sesrefs = 0; /* connections to the session */
|
||||
uid_t sock_sesuid; /* owner of the session */
|
||||
uint8_t sock_sescookie[AMSG_COOKIELEN]; /* owner of the session */
|
||||
|
||||
void
|
||||
sock_close(struct file *arg)
|
||||
{
|
||||
struct sock *f = (struct sock *)arg;
|
||||
|
||||
if (f->pstate != SOCK_AUTH)
|
||||
sock_sesrefs--;
|
||||
pipe_close(&f->pipe.file);
|
||||
if (f->dev) {
|
||||
|
@ -337,22 +338,13 @@ sock_new(struct fileops *ops, int fd)
|
|||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
if (sock_sesrefs == 0) {
|
||||
/* start a new session */
|
||||
sock_sesuid = uid;
|
||||
} else if (uid != sock_sesuid) {
|
||||
/* session owned by another user, drop connection */
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
sock_sesrefs++;
|
||||
|
||||
f = (struct sock *)pipe_new(ops, fd, "sock");
|
||||
if (f == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
f->pstate = SOCK_HELLO;
|
||||
f->pstate = SOCK_AUTH;
|
||||
f->mode = 0;
|
||||
f->opt = NULL;
|
||||
f->dev = NULL;
|
||||
|
@ -982,6 +974,23 @@ sock_midiattach(struct sock *f)
|
|||
dev_midiattach(f->dev, rbuf, wbuf);
|
||||
}
|
||||
|
||||
int
|
||||
sock_auth(struct sock *f)
|
||||
{
|
||||
struct amsg_auth *p = &f->rmsg.u.auth;
|
||||
|
||||
if (sock_sesrefs == 0) {
|
||||
/* start a new session */
|
||||
memcpy(sock_sescookie, p->cookie, AMSG_COOKIELEN);
|
||||
} else if (memcmp(sock_sescookie, p->cookie, AMSG_COOKIELEN) != 0) {
|
||||
/* another session is active, drop connection */
|
||||
return 0;
|
||||
}
|
||||
sock_sesrefs++;
|
||||
f->pstate = SOCK_HELLO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
sock_hello(struct sock *f)
|
||||
{
|
||||
|
@ -1323,6 +1332,30 @@ sock_execmsg(struct sock *f)
|
|||
f->rtodo = sizeof(struct amsg);
|
||||
f->rstate = SOCK_RMSG;
|
||||
break;
|
||||
case AMSG_AUTH:
|
||||
#ifdef DEBUG
|
||||
if (debug_level >= 3) {
|
||||
sock_dbg(f);
|
||||
dbg_puts(": AUTH message\n");
|
||||
}
|
||||
#endif
|
||||
if (f->pstate != SOCK_AUTH) {
|
||||
#ifdef DEBUG
|
||||
if (debug_level >= 1) {
|
||||
sock_dbg(f);
|
||||
dbg_puts(": AUTH, bad state\n");
|
||||
}
|
||||
#endif
|
||||
aproc_del(f->pipe.file.rproc);
|
||||
return 0;
|
||||
}
|
||||
if (!sock_auth(f)) {
|
||||
aproc_del(f->pipe.file.rproc);
|
||||
return 0;
|
||||
}
|
||||
f->rstate = SOCK_RMSG;
|
||||
f->rtodo = sizeof(struct amsg);
|
||||
break;
|
||||
case AMSG_HELLO:
|
||||
#ifdef DEBUG
|
||||
if (debug_level >= 3) {
|
||||
|
|
15
aucat/sock.h
15
aucat/sock.h
|
@ -42,13 +42,14 @@ struct sock {
|
|||
#define SOCK_WMSG 1 /* amsg being written */
|
||||
#define SOCK_WDATA 2 /* data chunk being written */
|
||||
unsigned wstate; /* state of the write-end FSM */
|
||||
#define SOCK_HELLO 0 /* waiting for HELLO message */
|
||||
#define SOCK_INIT 1 /* parameter negotiation */
|
||||
#define SOCK_START 2 /* filling play buffers */
|
||||
#define SOCK_READY 3 /* play buffers full */
|
||||
#define SOCK_RUN 4 /* attached to the mix / sub */
|
||||
#define SOCK_STOP 5 /* draining rec buffers */
|
||||
#define SOCK_MIDI 6 /* raw byte stream (midi) */
|
||||
#define SOCK_AUTH 0 /* waiting for AUTH message */
|
||||
#define SOCK_HELLO 1 /* waiting for HELLO message */
|
||||
#define SOCK_INIT 2 /* parameter negotiation */
|
||||
#define SOCK_START 3 /* filling play buffers */
|
||||
#define SOCK_READY 4 /* play buffers full */
|
||||
#define SOCK_RUN 5 /* attached to the mix / sub */
|
||||
#define SOCK_STOP 6 /* draining rec buffers */
|
||||
#define SOCK_MIDI 7 /* raw byte stream (midi) */
|
||||
unsigned pstate; /* one of the above */
|
||||
unsigned mode; /* bitmask of MODE_XXX */
|
||||
struct aparams rpar; /* read (ie play) parameters */
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -194,6 +196,70 @@ aucat_wdata(struct aucat *hdl, const void *buf, size_t len, unsigned wbpf, int *
|
|||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
aucat_gencookie(unsigned char *cookie)
|
||||
{
|
||||
arc4random_buf(cookie, AMSG_COOKIELEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
aucat_savecookie(char *path, unsigned char *cookie)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0600);
|
||||
if (fd < 0) {
|
||||
DPERROR(path);
|
||||
return;
|
||||
}
|
||||
if (write(fd, cookie, AMSG_COOKIELEN) < 0) {
|
||||
DPERROR(path);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
aucat_loadcookie(unsigned char *cookie)
|
||||
{
|
||||
char buf[PATH_MAX], *path;
|
||||
int fd, len, res;
|
||||
|
||||
path = issetugid() ? NULL : getenv("AUCAT_COOKIE");
|
||||
if (path == NULL) {
|
||||
path = issetugid() ? NULL : getenv("HOME");
|
||||
if (path == NULL)
|
||||
goto bad_gen;
|
||||
snprintf(buf, PATH_MAX, "%s/.aucat_cookie", path);
|
||||
path = buf;
|
||||
}
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (errno != ENOENT)
|
||||
DPERROR(path);
|
||||
goto bad_gen;
|
||||
}
|
||||
len = read(fd, cookie, AMSG_COOKIELEN);
|
||||
if (len < 0) {
|
||||
DPERROR(path);
|
||||
goto bad_close;
|
||||
}
|
||||
if (len != AMSG_COOKIELEN) {
|
||||
DPRINTF("%s: short read\n", path);
|
||||
goto bad_close;
|
||||
}
|
||||
close(fd);
|
||||
return 1;
|
||||
bad_close:
|
||||
close(fd);
|
||||
bad_gen:
|
||||
res = aucat_gencookie(cookie);
|
||||
if (path != NULL)
|
||||
aucat_savecookie(path, cookie);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nbio)
|
||||
{
|
||||
|
@ -256,6 +322,13 @@ aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nb
|
|||
* say hello to server
|
||||
*/
|
||||
AMSG_INIT(&hdl->wmsg);
|
||||
hdl->wmsg.cmd = AMSG_AUTH;
|
||||
if (!aucat_loadcookie(hdl->wmsg.u.auth.cookie))
|
||||
goto bad_connect;
|
||||
hdl->wtodo = sizeof(struct amsg);
|
||||
if (!aucat_wmsg(hdl, &eof))
|
||||
goto bad_connect;
|
||||
AMSG_INIT(&hdl->wmsg);
|
||||
hdl->wmsg.cmd = AMSG_HELLO;
|
||||
hdl->wmsg.u.hello.version = AMSG_VERSION;
|
||||
hdl->wmsg.u.hello.mode = mode;
|
||||
|
|
|
@ -146,6 +146,25 @@ MIDI port controlling the first
|
|||
.Xr aucat 1
|
||||
audio server.
|
||||
.El
|
||||
.Sh AUTHENTICATION
|
||||
If a shared
|
||||
.Xr aucat 1
|
||||
or
|
||||
.Xr midicat 1
|
||||
server is running, for privacy reasons only one user may have
|
||||
connections to it at a given time
|
||||
(though the same user could have multiple connections to it).
|
||||
Users are identified by their
|
||||
.Em session cookie ,
|
||||
which is automatically generated by audio or MIDI applications
|
||||
upon the first connection to the server.
|
||||
The cookie is stored in
|
||||
.Pa "$HOME/.aucat_cookie"
|
||||
and contains 128 bits of raw random data generated with
|
||||
.Xr arc4random 3 .
|
||||
.Pp
|
||||
If a session needs to be shared between multiple users, they
|
||||
can connect to the server using the same cookie.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width "AUDIODEVICEXXX" -compact
|
||||
.It Ev AUDIODEVICE
|
||||
|
@ -154,6 +173,12 @@ no device chooser.
|
|||
.It Ev MIDIDEVICE
|
||||
MIDI port to use if the application provides
|
||||
no MIDI port chooser.
|
||||
.It AUCAT_COOKIE
|
||||
Path to file containing the session cookie to be used
|
||||
when connecting to
|
||||
.Xr aucat
|
||||
or
|
||||
.Xr midicat
|
||||
.El
|
||||
.Pp
|
||||
Environment variables are ignored by programs
|
||||
|
|
Loading…
Reference in New Issue