This diffs enables aucat and midicat to work over TCP, which allows a
sound card to be shared between machines, doing strange things with
ssh port forwarding and so on.
Roughly, the first client generates a 128-bit random number (aka the
session cookie), saves it in $HOME/.aucat_cookie and sends it to the
server. Successive clients load the cookie from $HOME/.aucat_cookie
and send it to the server but the server accepts only clients whose
cookie matches the session cookie. When all clients are gone, the
session is over, and another cookie could start a new session, and so
on. Nothing new so far, aucat always used to work this way, except
that it used uids returned by getpeereid() as cookies.
This gives a simple workaround for "the _mpd problem", when the user
has two uids that used not to be allowed to share the audio
session. Now the user could simply copy the cookie to all of his uids.
Hostnames are specified with a new optional component in the device
name, and TCP is enabled in the server with the new -L option; see
sndio(7) and aucat(1) for hints.
Example of network setup:
On foo.domain.com do:
aucat -L0.0.0.0
On bar.domain.com do:
export AUDIODEVICE=aucat:foo.domain.com/0
mpg321 /music/myfile.mp3
Example for mpd-style setup: start mpd as _mpd from /etc/rc or
whatever and then steal its cookie:
cp ~_mpd/.aucat_cookie ~/
chown joe:joe .aucat_cookie
mplayer /whatever.avi
-- Alexandre
Index: lib/libsndio/aucat.c
===================================================================
RCS file: /cvs/src/lib/libsndio/aucat.c,v
retrieving revision 1.45
diff -u -p -r1.45 aucat.c
--- lib/libsndio/aucat.c 18 Apr 2011 23:57:35 -0000 1.45
+++ lib/libsndio/aucat.c 19 Apr 2011 17:27:31 -0000
@@ -17,10 +17,15 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
@@ -30,6 +35,10 @@
#include "aucat.h"
#include "debug.h"
+#ifndef DEV_RANDOM
+#define DEV_RANDOM "/dev/arandom"
+#endif
+
/*
* read a message, return 0 if not completed
*/
@@ -192,6 +201,149 @@ aucat_wdata(struct aucat *hdl, const voi
}
int
+aucat_gencookie(unsigned char *cookie)
+{
+ int fd;
+ ssize_t n, len;
+
+ fd = open(DEV_RANDOM, O_RDONLY);
+ if (fd < 0) {
+ DPERROR(DEV_RANDOM);
+ return 0;
+ }
+ len = AMSG_COOKIELEN;
+ while (len > 0) {
+ n = read(fd, cookie, AMSG_COOKIELEN);
+ if (n < 0) {
+ DPERROR(DEV_RANDOM);
+ close(fd);
+ return 0;
+ }
+ if (n == 0) {
+ close(fd);
+ return 0;
+ }
+ cookie += n;
+ len -= n;
+ }
+ close(fd);
+ 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)
+{
+ struct stat sb;
+ 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;
+ }
+ if (fstat(fd, &sb) < 0) {
+ DPERROR(path);
+ goto bad_close;
+ }
+ if (sb.st_mode & 0077) {
+ DPRINTF("%s has wrong permissions\n", path);
+ goto bad_close;
+ }
+ 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_connect_tcp(struct aucat *hdl, char *host, char *unit, int isaudio)
+{
+ int s, error;
+ struct addrinfo *ailist, *ai, aihints;
+ unsigned port;
+ char serv[NI_MAXSERV];
+
+ if (sscanf(unit, "%u", &port) != 1) {
+ DPRINTF("%s: bad unit number\n", unit);
+ return 0;
+ }
+ if (isaudio)
+ port += AUCAT_PORT;
+ else
+ port += MIDICAT_PORT;
+ snprintf(serv, sizeof(serv), "%u", port);
+ memset(&aihints, 0, sizeof(struct addrinfo));
+ aihints.ai_socktype = SOCK_STREAM;
+ aihints.ai_protocol = IPPROTO_TCP;
+ error = getaddrinfo(host, serv, &aihints, &ailist);
+ if (error) {
+ DPRINTF("%s: %s\n", host, gai_strerror(error));
+ return 0;
+ }
+ s = -1;
+ for (ai = ailist; ai != NULL; ai = ai->ai_next) {
+ s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s < 0) {
+ DPERROR("socket");
+ continue;
+ }
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+ DPERROR("connect");
+ close(s);
+ s = -1;
+ continue;
+ }
+ break;
+ }
+ freeaddrinfo(ailist);
+ if (s < 0)
+ return 0;
+ hdl->fd = s;
+ return 1;
+}
+
+int
aucat_connect_un(struct aucat *hdl, char *unit, int isaudio)
{
struct sockaddr_un ca;
@@ -232,9 +384,23 @@ int
aucat_open(struct aucat *hdl, const char *str, unsigned mode, int isaudio)
{
extern char *__progname;
- int eof;
+ int eof, hashost;
char unit[4], *sep, *opt;
+ char host[NI_MAXHOST];
+ sep = strchr(str, '/');
+ if (sep == NULL) {
+ hashost = 0;
+ } else {
+ if (sep - str >= sizeof(host)) {
+ DPRINTF("aucat_open: %s: host too long\n", str);
+ return 0;
+ }
+ memcpy(host, str, sep - str);
+ host[sep - str] = '\0';
+ hashost = 1;
+ str = sep + 1;
+ }
sep = strchr(str, '.');
if (sep == NULL) {
opt = "default";
@@ -248,8 +414,13 @@ aucat_open(struct aucat *hdl, const char
strlcpy(unit, str, opt - str);
}
DPRINTF("aucat_init: trying %s -> %s.%s\n", str, unit, opt);
- if (!aucat_connect_un(hdl, unit, isaudio))
- return 0;
+ if (hashost) {
+ if (!aucat_connect_tcp(hdl, host, unit, isaudio))
+ return 0;
+ } else {
+ if (!aucat_connect_un(hdl, unit, isaudio))
+ return 0;
+ }
if (fcntl(hdl->fd, F_SETFD, FD_CLOEXEC) < 0) {
DPERROR("FD_CLOEXEC");
goto bad_connect;
@@ -262,6 +433,13 @@ aucat_open(struct aucat *hdl, const char
/*
* 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;
Index: lib/libsndio/sndio.7
===================================================================
RCS file: /cvs/src/lib/libsndio/sndio.7,v
retrieving revision 1.3
diff -u -p -r1.3 sndio.7
--- lib/libsndio/sndio.7 16 Apr 2011 11:58:41 -0000 1.3
+++ lib/libsndio/sndio.7 19 Apr 2011 17:27:31 -0000
@@ -72,7 +72,7 @@ or
.Xr midicat 1
service has a name of the form:
.Bd -literal -offset center
-type:unit[.option]
+type:[hostname/]unit[.option]
.Ed
.Pp
This information is used by audio and MIDI applications to determine
@@ -101,6 +101,12 @@ software MIDI thru boxes, hardware
ports and
.Xr aucat 1
control through MIDI respectively.
+.It Pa hostname
+The hostname where the remote
+.Xr aucat 1
+or
+.Xr midicat 1
+server to connect to is running.
.It Pa unit
For hardware audio or MIDI devices, this corresponds to
the character device minor number.
@@ -146,6 +152,24 @@ 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.
+.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 +178,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
Index: usr.bin/aucat/amsg.h
===================================================================
RCS file: /cvs/src/usr.bin/aucat/amsg.h,v
retrieving revision 1.20
diff -u -p -r1.20 amsg.h
--- usr.bin/aucat/amsg.h 16 Apr 2011 11:24:18 -0000 1.20
+++ usr.bin/aucat/amsg.h 19 Apr 2011 17:27:41 -0000
@@ -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;
};
Index: usr.bin/aucat/aucat.1
===================================================================
RCS file: /cvs/src/usr.bin/aucat/aucat.1,v
retrieving revision 1.75
diff -u -p -r1.75 aucat.1
--- usr.bin/aucat/aucat.1 21 Mar 2011 16:33:17 -0000 1.75
+++ usr.bin/aucat/aucat.1 19 Apr 2011 17:27:42 -0000
@@ -33,6 +33,7 @@
.Op Fl h Ar fmt
.Op Fl i Ar file
.Op Fl j Ar flag
+.Op Fl L Ar addr
.Op Fl m Ar mode
.Op Fl o Ar file
.Op Fl q Ar device
@@ -140,6 +141,17 @@ For instance, this feature could be used
be sent on multiple outputs or to record a stereo input into a mono stream.
The default is
.Ar on .
+.It Fl L Ar addr
+Specify a local network address to listen on in server mode,
+.Nm
+will listen on TCP port 11025+n, where n is the unit number
+specified with
+.Fl U .
+Without this option,
+.Nm
+listens on the
+.Ux Ns -domain
+socket only, and is not reachable from the network.
.It Fl l
Detach and become a daemon.
.It Fl m Ar mode
@@ -533,12 +545,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 user's session cookie.
.El
.Sh EXAMPLES
The following will mix and play two stereo streams,
Index: usr.bin/aucat/aucat.c
===================================================================
RCS file: /cvs/src/usr.bin/aucat/aucat.c,v
retrieving revision 1.110
diff -u -p -r1.110 aucat.c
--- usr.bin/aucat/aucat.c 19 Apr 2011 00:02:28 -0000 1.110
+++ usr.bin/aucat/aucat.c 19 Apr 2011 17:27:43 -0000
@@ -257,6 +257,16 @@ struct cfdev {
SLIST_HEAD(cfdevlist, cfdev);
+/*
+ * local network addresse to listen on
+ */
+struct cfnet {
+ SLIST_ENTRY(cfnet) entry;
+ char *addr;
+};
+
+SLIST_HEAD(cfnetlist, cfnet);
+
void
cfdev_add(struct cfdevlist *list, struct cfdev *templ, char *path)
{
@@ -317,6 +327,20 @@ cfmid_add(struct cfmidlist *list, char *
}
void
+cfnet_add(struct cfnetlist *list, char *addr)
+{
+ struct cfnet *cn;
+
+ cn = malloc(sizeof(struct cfnet));
+ if (cn == NULL) {
+ perror("malloc");
+ abort();
+ }
+ cn->addr = addr;
+ SLIST_INSERT_HEAD(list, cn, entry);
+}
+
+void
setsig(void)
{
struct sigaction sa;
@@ -413,11 +437,11 @@ aucat_usage(void)
{
(void)fputs("usage: " PROG_AUCAT " [-dlnu] [-a flag] [-b nframes] "
"[-C min:max] [-c min:max] [-e enc]\n\t"
- "[-f device] [-h fmt] [-i file] [-j flag] [-m mode]"
- "[-o file] [-q device]\n\t"
- "[-r rate] [-s name] [-t mode] [-U unit] "
- "[-v volume] [-x policy]\n\t"
- "[-z nframes]\n",
+ "[-f device] [-h fmt] [-i file] [-j flag] [-L addr] [-m mode] "
+ "[-o file]\n\t"
+ "[-q device] [-r rate] [-s name] [-t mode] [-U unit] "
+ "[-v volume]\n\t"
+ "[-x policy] [-z nframes]\n",
stderr);
}
@@ -425,9 +449,11 @@ int
aucat_main(int argc, char **argv)
{
struct cfdevlist cfdevs;
+ struct cfnetlist cfnets;
struct cfmid *cm;
struct cfstr *cs;
struct cfdev *cd;
+ struct cfnet *cn;
int c, u_flag, d_flag, l_flag, n_flag, unit;
char base[PATH_MAX], path[PATH_MAX];
unsigned mode, rate;
@@ -446,6 +472,7 @@ aucat_main(int argc, char **argv)
l_flag = 0;
n_flag = 0;
SLIST_INIT(&cfdevs);
+ SLIST_INIT(&cfnets);
nfile = nsock = 0;
/*
@@ -484,7 +511,7 @@ aucat_main(int argc, char **argv)
cd->round = 0;
cd->hold = 1;
- while ((c = getopt(argc, argv,
"a:dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:t:j:z:")) != -1) {
+ while ((c = getopt(argc, argv,
"a:dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:L:t:j:z:")) != -1) {
switch (c) {
case 'd':
#ifdef DEBUG
@@ -504,6 +531,9 @@ aucat_main(int argc, char **argv)
if (str)
errx(1, "%s: unit number is %s", optarg, str);
break;
+ case 'L':
+ cfnet_add(&cfnets, optarg);
+ break;
case 'm':
cs->mode = opt_mode();
cd->mode = cs->mode;
@@ -765,6 +795,11 @@ aucat_main(int argc, char **argv)
snprintf(path, sizeof(path), "%s/%s%u", base,
AUCAT_PATH, unit);
listen_new_un(path);
+ while (!SLIST_EMPTY(&cfnets)) {
+ cn = SLIST_FIRST(&cfnets);
+ SLIST_REMOVE_HEAD(&cfnets, entry);
+ listen_new_tcp(cn->addr, AUCAT_PORT + unit);
+ }
}
if (geteuid() == 0)
privdrop();
@@ -824,7 +859,7 @@ void
midicat_usage(void)
{
(void)fputs("usage: " PROG_MIDICAT " [-dl] "
- "[-i file] [-o file] [-q port] [-s name] [-U unit]\n",
+ "[-i file] [-L addr] [-o file] [-q port] [-s name] [-U unit]\n",
stderr);
}
@@ -832,9 +867,11 @@ int
midicat_main(int argc, char **argv)
{
struct cfdevlist cfdevs;
+ struct cfnetlist cfnets;
struct cfmid *cm;
struct cfstr *cs;
struct cfdev *cd;
+ struct cfnet *cn;
int c, d_flag, l_flag, unit, fd;
char base[PATH_MAX], path[PATH_MAX];
struct file *stdx;
@@ -851,6 +888,7 @@ midicat_main(int argc, char **argv)
d_flag = 0;
l_flag = 0;
SLIST_INIT(&cfdevs);
+ SLIST_INIT(&cfnets);
nsock = 0;
/*
@@ -909,6 +947,9 @@ midicat_main(int argc, char **argv)
if (str)
errx(1, "%s: unit number is %s", optarg, str);
break;
+ case 'L':
+ cfnet_add(&cfnets, optarg);
+ break;
default:
midicat_usage();
exit(1);
@@ -1032,6 +1073,11 @@ midicat_main(int argc, char **argv)
snprintf(path, sizeof(path), "%s/%s%u", base,
MIDICAT_PATH, unit);
listen_new_un(path);
+ while (!SLIST_EMPTY(&cfnets)) {
+ cn = SLIST_FIRST(&cfnets);
+ SLIST_REMOVE_HEAD(&cfnets, entry);
+ listen_new_tcp(cn->addr, MIDICAT_PORT + unit);
+ }
}
if (geteuid() == 0)
privdrop();
Index: usr.bin/aucat/conf.h
===================================================================
RCS file: /cvs/src/usr.bin/aucat/conf.h,v
retrieving revision 1.19
diff -u -p -r1.19 conf.h
--- usr.bin/aucat/conf.h 18 Apr 2011 23:59:15 -0000 1.19
+++ usr.bin/aucat/conf.h 19 Apr 2011 17:27:44 -0000
@@ -35,6 +35,8 @@ extern int debug_level;
*/
#define AUCAT_PATH "aucat"
#define MIDICAT_PATH "midicat"
+#define AUCAT_PORT 11025
+#define MIDICAT_PORT 11041
#define DEFAULT_OPT "default"
/*
Index: usr.bin/aucat/listen.c
===================================================================
RCS file: /cvs/src/usr.bin/aucat/listen.c,v
retrieving revision 1.12
diff -u -p -r1.12 listen.c
--- usr.bin/aucat/listen.c 19 Apr 2011 00:02:29 -0000 1.12
+++ usr.bin/aucat/listen.c 19 Apr 2011 17:27:44 -0000
@@ -18,6 +18,10 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -86,6 +90,67 @@ listen_new_un(char *path)
bad_close:
close(sock);
exit(1);
+}
+
+void
+listen_new_tcp(char *addr, unsigned port)
+{
+ char *host, serv[sizeof(unsigned) * 3 + 1];
+ struct addrinfo *ailist, *ai, aihints;
+ struct listen *f;
+ int s, error, opt = 1, n = 0;
+
+ /*
+ * obtain a list of possible addresses for the host/port
+ */
+ memset(&aihints, 0, sizeof(struct addrinfo));
+ snprintf(serv, sizeof(serv), "%u", port);
+ host = strcmp(addr, "*") == 0 ? NULL : addr;
+ aihints.ai_flags |= AI_PASSIVE;
+ aihints.ai_socktype = SOCK_STREAM;
+ aihints.ai_protocol = IPPROTO_TCP;
+ error = getaddrinfo(host, serv, &aihints, &ailist);
+ if (error) {
+ fprintf(stderr, "%s: %s\n", addr, gai_strerror(error));
+ exit(1);
+ }
+
+ /*
+ * for each address, try create a listening socket bound on
+ * that address
+ */
+ for (ai = ailist; ai != NULL; ai = ai->ai_next) {
+ s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s < 0) {
+ perror("socket");
+ continue;
+ }
+ opt = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int))
< 0) {
+ perror("setsockopt");
+ goto bad_close;
+ }
+ if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+ perror("bind");
+ goto bad_close;
+ }
+ if (listen(s, 1) < 0) {
+ perror("listen");
+ goto bad_close;
+ }
+ f = (struct listen *)file_new(&listen_ops, addr, 1);
+ if (f == NULL) {
+ bad_close:
+ close(s);
+ continue;
+ }
+ f->path = NULL;
+ f->fd = s;
+ n++;
+ }
+ freeaddrinfo(ailist);
+ if (n == 0)
+ exit(1);
}
int
Index: usr.bin/aucat/listen.h
===================================================================
RCS file: /cvs/src/usr.bin/aucat/listen.h,v
retrieving revision 1.6
diff -u -p -r1.6 listen.h
--- usr.bin/aucat/listen.h 19 Apr 2011 00:02:29 -0000 1.6
+++ usr.bin/aucat/listen.h 19 Apr 2011 17:27:44 -0000
@@ -29,6 +29,7 @@ struct listen {
};
void listen_new_un(char *);
+void listen_new_tcp(char *, unsigned);
int listen_nfds(struct file *);
int listen_pollfd(struct file *, struct pollfd *, int);
int listen_revents(struct file *, struct pollfd *);
Index: usr.bin/aucat/midicat.1
===================================================================
RCS file: /cvs/src/usr.bin/aucat/midicat.1,v
retrieving revision 1.14
diff -u -p -r1.14 midicat.1
--- usr.bin/aucat/midicat.1 21 Mar 2011 16:33:17 -0000 1.14
+++ usr.bin/aucat/midicat.1 19 Apr 2011 17:27:44 -0000
@@ -24,6 +24,7 @@
.Nm midicat
.Op Fl dl
.Op Fl i Ar file
+.Op Fl L Ar addr
.Op Fl o Ar file
.Op Fl q Ar port
.Op Fl s Ar name
@@ -57,6 +58,17 @@ Read data to send from this file.
If the option argument is
.Sq -
then standard input will be used.
+.It Fl L Ar addr
+Specify a local network address to listen on in server mode,
+.Nm
+will listen on TCP port 11041+n, where n is the unit number
+specified with
+.Fl U .
+Without this option,
+.Nm
+listens on the
+.Ux Ns -domain
+socket only, and is not reachable from the network.
.It Fl l
Detach and become a daemon.
.It Fl o Ar file
Index: usr.bin/aucat/sock.c
===================================================================
RCS file: /cvs/src/usr.bin/aucat/sock.c,v
retrieving revision 1.56
diff -u -p -r1.56 sock.c
--- usr.bin/aucat/sock.c 16 Apr 2011 11:24:18 -0000 1.56
+++ usr.bin/aucat/sock.c 19 Apr 2011 17:27:45 -0000
@@ -93,15 +93,16 @@ struct ctl_ops ctl_sockops = {
sock_quitreq
};
-unsigned sock_sesrefs = 0; /* connections to the session */
-uid_t sock_sesuid; /* owner of the session */
+unsigned sock_sesrefs = 0; /* connections to the session */
+uint8_t sock_sescookie[AMSG_COOKIELEN]; /* owner of the session */
void
sock_close(struct file *arg)
{
struct sock *f = (struct sock *)arg;
- sock_sesrefs--;
+ if (f->pstate != SOCK_AUTH)
+ sock_sesrefs--;
pipe_close(&f->pipe.file);
if (f->dev) {
dev_unref(f->dev);
@@ -322,34 +323,13 @@ sock_new(struct fileops *ops, int fd)
{
struct aproc *rproc, *wproc;
struct sock *f;
- uid_t uid, gid;
-
- /*
- * ensure that all connections belong to the same user,
- * for privacy reasons.
- *
- * XXX: is there a portable way of doing this ?
- */
- if (getpeereid(fd, &uid, &gid) < 0) {
- 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;
@@ -980,6 +960,23 @@ sock_midiattach(struct sock *f)
}
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)
{
struct amsg_hello *p = &f->rmsg.u.hello;
@@ -1319,6 +1316,30 @@ sock_execmsg(struct sock *f)
ctl_slotvol(f->dev->midi, f->slot, m->u.vol.ctl);
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
Index: usr.bin/aucat/sock.h
===================================================================
RCS file: /cvs/src/usr.bin/aucat/sock.h,v
retrieving revision 1.18
diff -u -p -r1.18 sock.h
--- usr.bin/aucat/sock.h 21 Oct 2010 18:57:42 -0000 1.18
+++ usr.bin/aucat/sock.h 19 Apr 2011 17:27:45 -0000
@@ -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 */