use a cookie for authentication

This commit is contained in:
Alexandre Ratchov 2011-04-16 18:30:24 +02:00
parent 2a4059ae60
commit 0663ca6f54
6 changed files with 160 additions and 21 deletions

View File

@ -41,6 +41,7 @@ struct amsg {
#define AMSG_SETVOL 9 /* set volume */ #define AMSG_SETVOL 9 /* set volume */
#define AMSG_HELLO 10 /* say hello, check versions and so ... */ #define AMSG_HELLO 10 /* say hello, check versions and so ... */
#define AMSG_BYE 11 /* ask server to drop connection */ #define AMSG_BYE 11 /* ask server to drop connection */
#define AMSG_AUTH 12 /* send authentication cookie */
uint32_t cmd; uint32_t cmd;
uint32_t __pad; uint32_t __pad;
union { union {
@ -79,6 +80,10 @@ struct amsg {
char opt[12]; /* profile name */ char opt[12]; /* profile name */
char who[12]; /* hint for leases */ char who[12]; /* hint for leases */
} hello; } hello;
struct amsg_auth {
#define AMSG_COOKIELEN 16
uint8_t cookie[AMSG_COOKIELEN];
} auth;
} u; } u;
}; };

View File

@ -533,12 +533,14 @@ Note that the sequencer must use
.Va aucat:0 .Va aucat:0
as the MTC source, i.e. the audio server, not the audio player. as the MTC source, i.e. the audio server, not the audio player.
.Sh ENVIRONMENT .Sh ENVIRONMENT
.Bl -tag -width "AUDIODEVICE" -compact .Bl -tag -width "AUCAT_COOKIE" -compact
.It Ev AUDIODEVICE .It Ev AUDIODEVICE
.Xr sndio 7 .Xr sndio 7
audio device to use if the audio device to use if the
.Fl f .Fl f
option is not specified. option is not specified.
.It Ev AUCAT_COOKIE
file containing a user's session cookie.
.El .El
.Sh EXAMPLES .Sh EXAMPLES
The following will mix and play two stereo streams, The following will mix and play two stereo streams,

View File

@ -96,15 +96,16 @@ struct ctl_ops ctl_sockops = {
sock_quitreq sock_quitreq
}; };
unsigned sock_sesrefs = 0; /* connections to the session */ 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 void
sock_close(struct file *arg) sock_close(struct file *arg)
{ {
struct sock *f = (struct sock *)arg; struct sock *f = (struct sock *)arg;
sock_sesrefs--; if (f->pstate != SOCK_AUTH)
sock_sesrefs--;
pipe_close(&f->pipe.file); pipe_close(&f->pipe.file);
if (f->dev) { if (f->dev) {
dev_unref(f->dev); dev_unref(f->dev);
@ -337,22 +338,13 @@ sock_new(struct fileops *ops, int fd)
close(fd); close(fd);
return NULL; 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"); f = (struct sock *)pipe_new(ops, fd, "sock");
if (f == NULL) { if (f == NULL) {
close(fd); close(fd);
return NULL; return NULL;
} }
f->pstate = SOCK_HELLO; f->pstate = SOCK_AUTH;
f->mode = 0; f->mode = 0;
f->opt = NULL; f->opt = NULL;
f->dev = NULL; f->dev = NULL;
@ -982,6 +974,23 @@ sock_midiattach(struct sock *f)
dev_midiattach(f->dev, rbuf, wbuf); 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 int
sock_hello(struct sock *f) sock_hello(struct sock *f)
{ {
@ -1323,6 +1332,30 @@ sock_execmsg(struct sock *f)
f->rtodo = sizeof(struct amsg); f->rtodo = sizeof(struct amsg);
f->rstate = SOCK_RMSG; f->rstate = SOCK_RMSG;
break; 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: case AMSG_HELLO:
#ifdef DEBUG #ifdef DEBUG
if (debug_level >= 3) { if (debug_level >= 3) {

View File

@ -42,13 +42,14 @@ struct sock {
#define SOCK_WMSG 1 /* amsg being written */ #define SOCK_WMSG 1 /* amsg being written */
#define SOCK_WDATA 2 /* data chunk being written */ #define SOCK_WDATA 2 /* data chunk being written */
unsigned wstate; /* state of the write-end FSM */ unsigned wstate; /* state of the write-end FSM */
#define SOCK_HELLO 0 /* waiting for HELLO message */ #define SOCK_AUTH 0 /* waiting for AUTH message */
#define SOCK_INIT 1 /* parameter negotiation */ #define SOCK_HELLO 1 /* waiting for HELLO message */
#define SOCK_START 2 /* filling play buffers */ #define SOCK_INIT 2 /* parameter negotiation */
#define SOCK_READY 3 /* play buffers full */ #define SOCK_START 3 /* filling play buffers */
#define SOCK_RUN 4 /* attached to the mix / sub */ #define SOCK_READY 4 /* play buffers full */
#define SOCK_STOP 5 /* draining rec buffers */ #define SOCK_RUN 5 /* attached to the mix / sub */
#define SOCK_MIDI 6 /* raw byte stream (midi) */ #define SOCK_STOP 6 /* draining rec buffers */
#define SOCK_MIDI 7 /* raw byte stream (midi) */
unsigned pstate; /* one of the above */ unsigned pstate; /* one of the above */
unsigned mode; /* bitmask of MODE_XXX */ unsigned mode; /* bitmask of MODE_XXX */
struct aparams rpar; /* read (ie play) parameters */ struct aparams rpar; /* read (ie play) parameters */

View File

@ -17,10 +17,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h> #include <sys/un.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <poll.h> #include <poll.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -194,6 +196,70 @@ aucat_wdata(struct aucat *hdl, const void *buf, size_t len, unsigned wbpf, int *
return n; 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 int
aucat_open(struct aucat *hdl, const char *str, char *sock, unsigned mode, int nbio) 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 * say hello to server
*/ */
AMSG_INIT(&hdl->wmsg); 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.cmd = AMSG_HELLO;
hdl->wmsg.u.hello.version = AMSG_VERSION; hdl->wmsg.u.hello.version = AMSG_VERSION;
hdl->wmsg.u.hello.mode = mode; hdl->wmsg.u.hello.mode = mode;

View File

@ -146,6 +146,25 @@ MIDI port controlling the first
.Xr aucat 1 .Xr aucat 1
audio server. audio server.
.El .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 .Sh ENVIRONMENT
.Bl -tag -width "AUDIODEVICEXXX" -compact .Bl -tag -width "AUDIODEVICEXXX" -compact
.It Ev AUDIODEVICE .It Ev AUDIODEVICE
@ -154,6 +173,12 @@ no device chooser.
.It Ev MIDIDEVICE .It Ev MIDIDEVICE
MIDI port to use if the application provides MIDI port to use if the application provides
no MIDI port chooser. 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 .El
.Pp .Pp
Environment variables are ignored by programs Environment variables are ignored by programs