diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2011-04-28 06:19:58 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2011-04-28 06:19:58 +0000 |
commit | fa9d7b6082456caf8e490d50bc5d343277a2c67b (patch) | |
tree | 42fa8b593e554f30357234384779ee406d23e311 /lib | |
parent | 7c46124c1f9b4e99b5ca7e36469b292d77b6663f (diff) |
Implement a new authentication method allowing aucat and midicat to
work over TCP, for instance, to expose the sound card of one machine
with other machines of the network.
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.
TCP is enabled on the server with the new -L option, and on the client
side hostnames are specified with a new optional component in the
device name.
hints from damien, dlg and deraadt, tweaks from jmc
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libsndio/amsg.h | 4 | ||||
-rw-r--r-- | lib/libsndio/aucat.c | 168 | ||||
-rw-r--r-- | lib/libsndio/sndio.7 | 36 |
3 files changed, 200 insertions, 8 deletions
diff --git a/lib/libsndio/amsg.h b/lib/libsndio/amsg.h index c37068dca0a..d6370a2628f 100644 --- a/lib/libsndio/amsg.h +++ b/lib/libsndio/amsg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: amsg.h,v 1.1 2011/04/27 21:20:36 ratchov Exp $ */ +/* $OpenBSD: amsg.h,v 1.2 2011/04/28 06:19:57 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -23,7 +23,9 @@ * socket and option names */ #define AUCAT_PATH "aucat" +#define AUCAT_PORT 11025 #define MIDICAT_PATH "midicat" +#define MIDICAT_PORT 11041 #define DEFAULT_OPT "default" /* diff --git a/lib/libsndio/aucat.c b/lib/libsndio/aucat.c index 4466dddb896..76e71153e24 100644 --- a/lib/libsndio/aucat.c +++ b/lib/libsndio/aucat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aucat.c,v 1.45 2011/04/18 23:57:35 ratchov Exp $ */ +/* $OpenBSD: aucat.c,v 1.46 2011/04/28 06:19:57 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -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,7 @@ #include "aucat.h" #include "debug.h" + /* * read a message, return 0 if not completed */ @@ -192,6 +198,134 @@ aucat_wdata(struct aucat *hdl, const void *buf, size_t len, unsigned wbpf, int * } int +aucat_mkcookie(unsigned char *cookie) +{ + struct stat sb; + char buf[PATH_MAX], tmp[PATH_MAX], *path; + ssize_t len; + int fd; + + /* + * try to load the cookie + */ + 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: + /* + * generate a new cookie + */ + arc4random_buf(cookie, AMSG_COOKIELEN); + + /* + * try to save the cookie + */ + if (path == NULL) + return 1; + if (strlcpy(tmp, path, PATH_MAX) >= PATH_MAX || + strlcat(tmp, ".XXXXXXXX", PATH_MAX) >= PATH_MAX) { + DPRINTF("%s: too long\n", path); + return 1; + } + fd = mkstemp(tmp); + if (fd < 0) { + DPERROR(tmp); + return 1; + } + if (write(fd, cookie, AMSG_COOKIELEN) < 0) { + DPERROR(tmp); + unlink(tmp); + close(fd); + return 1; + } + close(fd); + if (rename(tmp, path) < 0) { + DPERROR(tmp); + unlink(tmp); + } + return 1; +} + +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 +366,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 +396,13 @@ aucat_open(struct aucat *hdl, const char *str, unsigned mode, int isaudio) 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; @@ -263,6 +416,13 @@ aucat_open(struct aucat *hdl, const char *str, unsigned mode, int isaudio) * say hello to server */ AMSG_INIT(&hdl->wmsg); + hdl->wmsg.cmd = AMSG_AUTH; + if (!aucat_mkcookie(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; diff --git a/lib/libsndio/sndio.7 b/lib/libsndio/sndio.7 index fd4632d0b84..1c5237c66c2 100644 --- a/lib/libsndio/sndio.7 +++ b/lib/libsndio/sndio.7 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sndio.7,v 1.3 2011/04/16 11:58:41 ratchov Exp $ +.\" $OpenBSD: sndio.7,v 1.4 2011/04/28 06:19:57 ratchov Exp $ .\" .\" Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 16 2011 $ +.Dd $Mdocdate: April 28 2011 $ .Dt SNDIO 7 .Os .Sh NAME @@ -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,8 +152,32 @@ 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 AUCAT_COOKIE +Path to file containing the session cookie to be used +when connecting to +.Xr aucat +or +.Xr midicat . .It Ev AUDIODEVICE Audio device to use if the application provides no device chooser. |