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 /usr.bin/aucat | |
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 'usr.bin/aucat')
-rw-r--r-- | usr.bin/aucat/aucat.1 | 20 | ||||
-rw-r--r-- | usr.bin/aucat/aucat.c | 62 | ||||
-rw-r--r-- | usr.bin/aucat/listen.c | 67 | ||||
-rw-r--r-- | usr.bin/aucat/listen.h | 3 | ||||
-rw-r--r-- | usr.bin/aucat/midicat.1 | 16 | ||||
-rw-r--r-- | usr.bin/aucat/sock.c | 73 | ||||
-rw-r--r-- | usr.bin/aucat/sock.h | 17 |
7 files changed, 209 insertions, 49 deletions
diff --git a/usr.bin/aucat/aucat.1 b/usr.bin/aucat/aucat.1 index 539e33b6f91..bce07ff0d4b 100644 --- a/usr.bin/aucat/aucat.1 +++ b/usr.bin/aucat/aucat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: aucat.1,v 1.75 2011/03/21 16:33:17 okan Exp $ +.\" $OpenBSD: aucat.1,v 1.76 2011/04/28 06:19:57 ratchov Exp $ .\" .\" Copyright (c) 2006 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: March 21 2011 $ +.Dd $Mdocdate: April 28 2011 $ .Dt AUCAT 1 .Os .Sh NAME @@ -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 to request mono streams to 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 any network. .It Fl l Detach and become a daemon. .It Fl m Ar mode @@ -533,7 +545,9 @@ 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 AUCAT_COOKIE +file containing user's session cookie. .It Ev AUDIODEVICE .Xr sndio 7 audio device to use if the diff --git a/usr.bin/aucat/aucat.c b/usr.bin/aucat/aucat.c index 2f59d1eac6d..cc4121b04cc 100644 --- a/usr.bin/aucat/aucat.c +++ b/usr.bin/aucat/aucat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aucat.c,v 1.112 2011/04/27 21:20:36 ratchov Exp $ */ +/* $OpenBSD: aucat.c,v 1.113 2011/04/28 06:19:57 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -258,6 +258,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) { @@ -318,6 +328,20 @@ cfmid_add(struct cfmidlist *list, char *path) } 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; @@ -414,11 +438,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); } @@ -426,9 +450,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; @@ -447,6 +473,7 @@ aucat_main(int argc, char **argv) l_flag = 0; n_flag = 0; SLIST_INIT(&cfdevs); + SLIST_INIT(&cfnets); nfile = nsock = 0; /* @@ -485,7 +512,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 @@ -505,6 +532,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; @@ -766,6 +796,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(); @@ -825,7 +860,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); } @@ -833,9 +868,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; @@ -852,6 +889,7 @@ midicat_main(int argc, char **argv) d_flag = 0; l_flag = 0; SLIST_INIT(&cfdevs); + SLIST_INIT(&cfnets); nsock = 0; /* @@ -910,6 +948,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); @@ -1033,6 +1074,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(); diff --git a/usr.bin/aucat/listen.c b/usr.bin/aucat/listen.c index 35b316b30ac..d99d3d9f543 100644 --- a/usr.bin/aucat/listen.c +++ b/usr.bin/aucat/listen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: listen.c,v 1.13 2011/04/27 17:58:43 deraadt Exp $ */ +/* $OpenBSD: listen.c,v 1.14 2011/04/28 06:19:57 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -19,6 +19,10 @@ #include <sys/signal.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> @@ -89,6 +93,67 @@ listen_new_un(char *path) 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 listen_nfds(struct file *f) { return 1; diff --git a/usr.bin/aucat/listen.h b/usr.bin/aucat/listen.h index d063af50c05..638ad65d1ce 100644 --- a/usr.bin/aucat/listen.h +++ b/usr.bin/aucat/listen.h @@ -1,4 +1,4 @@ -/* $OpenBSD: listen.h,v 1.6 2011/04/19 00:02:29 ratchov Exp $ */ +/* $OpenBSD: listen.h,v 1.7 2011/04/28 06:19:57 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -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 *); diff --git a/usr.bin/aucat/midicat.1 b/usr.bin/aucat/midicat.1 index 44cf8c96717..5f335bb5466 100644 --- a/usr.bin/aucat/midicat.1 +++ b/usr.bin/aucat/midicat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: midicat.1,v 1.14 2011/03/21 16:33:17 okan Exp $ +.\" $OpenBSD: midicat.1,v 1.15 2011/04/28 06:19:57 ratchov Exp $ .\" .\" Copyright (c) 2006 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: March 21 2011 $ +.Dd $Mdocdate: April 28 2011 $ .Dt MIDICAT 1 .Os .Sh NAME @@ -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 any network. .It Fl l Detach and become a daemon. .It Fl o Ar file diff --git a/usr.bin/aucat/sock.c b/usr.bin/aucat/sock.c index a8db9ec6793..74a6a156953 100644 --- a/usr.bin/aucat/sock.c +++ b/usr.bin/aucat/sock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sock.c,v 1.56 2011/04/16 11:24:18 ratchov Exp $ */ +/* $OpenBSD: sock.c,v 1.57 2011/04/28 06:19:57 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -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; @@ -1320,6 +1317,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) { diff --git a/usr.bin/aucat/sock.h b/usr.bin/aucat/sock.h index 266ddc42530..e844850fbb2 100644 --- a/usr.bin/aucat/sock.h +++ b/usr.bin/aucat/sock.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sock.h,v 1.18 2010/10/21 18:57:42 ratchov Exp $ */ +/* $OpenBSD: sock.h,v 1.19 2011/04/28 06:19:57 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -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 */ |