summaryrefslogtreecommitdiff
path: root/usr.bin/aucat
diff options
context:
space:
mode:
authorAlexandre Ratchov <ratchov@cvs.openbsd.org>2010-04-22 17:43:31 +0000
committerAlexandre Ratchov <ratchov@cvs.openbsd.org>2010-04-22 17:43:31 +0000
commitf5dd670f418fc5b9117869578ba44867a6a648e2 (patch)
treebebbc00ffdc0855fe060b4ae82f0e77f1998deba /usr.bin/aucat
parente153255799cfad37e6558a74e851726a9175cc77 (diff)
Allow multiple users to share the same aucat server. If aucat is
run by root, it binds a shared address to the socket, cranks the process priority and drops privileges. sio_open(3) will try to connect to the private socket first (if any), then to the shared socket. Only one user may have connections to aucat at a given time. based on discussions with henning, pyr and others ok jacek, deraadt
Diffstat (limited to 'usr.bin/aucat')
-rw-r--r--usr.bin/aucat/aucat.114
-rw-r--r--usr.bin/aucat/aucat.c55
-rw-r--r--usr.bin/aucat/midicat.114
-rw-r--r--usr.bin/aucat/sock.c39
4 files changed, 110 insertions, 12 deletions
diff --git a/usr.bin/aucat/aucat.1 b/usr.bin/aucat/aucat.1
index 8fe76090f04..dfb35e0467e 100644
--- a/usr.bin/aucat/aucat.1
+++ b/usr.bin/aucat/aucat.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: aucat.1,v 1.68 2010/04/21 06:13:07 ratchov Exp $
+.\" $OpenBSD: aucat.1,v 1.69 2010/04/22 17:43:30 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: April 21 2010 $
+.Dd $Mdocdate: April 22 2010 $
.Dt AUCAT 1
.Os
.Sh NAME
@@ -387,6 +387,16 @@ can be used in server mode
to overcome hardware limitations and allow applications
to run on fixed sample rate devices or on devices
supporting only unusual encodings.
+.Pp
+The
+.Nm
+audio server may be started by the super-user,
+in which case any user will be able to connect to it.
+For privacy reasons, only one user may have connections to it
+at a given time.
+.Pp
+Alternatively, each user may run his instance
+of the server.
It is generally not desirable to have multiple
instances of
.Nm
diff --git a/usr.bin/aucat/aucat.c b/usr.bin/aucat/aucat.c
index d713057cad6..89504bf5601 100644
--- a/usr.bin/aucat/aucat.c
+++ b/usr.bin/aucat/aucat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aucat.c,v 1.85 2010/04/21 06:15:02 ratchov Exp $ */
+/* $OpenBSD: aucat.c,v 1.86 2010/04/22 17:43:30 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -18,11 +18,13 @@
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/resource.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -43,6 +45,16 @@
#include "dbg.h"
#endif
+/*
+ * unprivileged user name
+ */
+#define SNDIO_USER "_sndio"
+
+/*
+ * priority when run as root
+ */
+#define SNDIO_PRIO (-20)
+
#define PROG_AUCAT "aucat"
#define PROG_MIDICAT "midicat"
@@ -303,20 +315,47 @@ getbasepath(char *base, size_t size)
{
uid_t uid;
struct stat sb;
+ mode_t mask;
uid = geteuid();
- snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
- if (mkdir(base, 0700) < 0) {
+ if (uid == 0) {
+ mask = 022;
+ snprintf(base, PATH_MAX, "/tmp/aucat");
+ } else {
+ mask = 077;
+ snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
+ }
+ if (mkdir(base, 0777 & ~mask) < 0) {
if (errno != EEXIST)
err(1, "mkdir(\"%s\")", base);
}
if (stat(base, &sb) < 0)
err(1, "stat(\"%s\")", base);
- if (sb.st_uid != uid || (sb.st_mode & 077) != 0)
+ if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
errx(1, "%s has wrong permissions", base);
}
void
+privdrop(void)
+{
+ struct passwd *pw;
+ struct stat sb;
+
+ if ((pw = getpwnam(SNDIO_USER)) == NULL)
+ err(1, "getpwnam");
+ if (stat(pw->pw_dir, &sb) < 0)
+ err(1, "stat(\"%s\")", pw->pw_dir);
+ if (sb.st_uid != 0 || (sb.st_mode & 022) != 0)
+ errx(1, "%s has wrong permissions", pw->pw_dir);
+ if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) < 0)
+ err(1, "setpriority");
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ err(1, "cannot drop privileges");
+}
+
+void
stopall(char *base)
{
struct file *f;
@@ -647,6 +686,8 @@ aucat_main(int argc, char **argv)
snprintf(path, sizeof(path), "%s/%s%u", base,
DEFAULT_SOFTAUDIO, unit);
listen_new(&listen_ops, path);
+ if (geteuid() == 0)
+ privdrop();
if (!d_flag && daemon(0, 0) < 0)
err(1, "daemon");
}
@@ -705,7 +746,7 @@ aucat_main(int argc, char **argv)
dev_done();
filelist_done();
if (l_flag) {
- if (rmdir(base) < 0 && errno != ENOTEMPTY)
+ if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM)
warn("rmdir(\"%s\")", base);
}
unsetsig();
@@ -817,6 +858,8 @@ midicat_main(int argc, char **argv)
snprintf(path, sizeof(path), "%s/%s%u", base,
DEFAULT_MIDITHRU, unit);
listen_new(&listen_ops, path);
+ if (geteuid() == 0)
+ privdrop();
if (!d_flag && daemon(0, 0) < 0)
err(1, "daemon");
}
@@ -873,7 +916,7 @@ midicat_main(int argc, char **argv)
dev_done();
filelist_done();
if (l_flag) {
- if (rmdir(base) < 0 && errno != ENOTEMPTY)
+ if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM)
warn("rmdir(\"%s\")", base);
}
unsetsig();
diff --git a/usr.bin/aucat/midicat.1 b/usr.bin/aucat/midicat.1
index 6baec0a512c..0d760141c98 100644
--- a/usr.bin/aucat/midicat.1
+++ b/usr.bin/aucat/midicat.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: midicat.1,v 1.9 2010/04/06 20:07:01 ratchov Exp $
+.\" $OpenBSD: midicat.1,v 1.10 2010/04/22 17:43:30 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: April 6 2010 $
+.Dd $Mdocdate: April 22 2010 $
.Dt MIDICAT 1
.Os
.Sh NAME
@@ -101,6 +101,16 @@ This feature is provided to allow multiple applications
acting as sources to keep their connection open while
idling; it does not replace a fully featured MIDI merger.
.Pp
+A
+.Nm
+process may be started by the super-user,
+in which case any user will be able to connect to it.
+For privacy reasons, only one user may have connections to
+it at a given time.
+.Pp
+Alternatively, each user may start its own
+.Nm
+process.
It is generally not desirable to have multiple instances of
.Nm
running in server mode, so it is good practice to start it thus:
diff --git a/usr.bin/aucat/sock.c b/usr.bin/aucat/sock.c
index da0fff1be1c..18f2f8f366f 100644
--- a/usr.bin/aucat/sock.c
+++ b/usr.bin/aucat/sock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sock.c,v 1.43 2010/04/21 06:13:07 ratchov Exp $ */
+/* $OpenBSD: sock.c,v 1.44 2010/04/22 17:43:30 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -15,6 +15,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,11 +38,12 @@ int sock_read(struct sock *);
int sock_write(struct sock *);
int sock_execmsg(struct sock *);
void sock_reset(struct sock *);
+void sock_close(struct file *);
struct fileops sock_ops = {
"sock",
sizeof(struct sock),
- pipe_close,
+ sock_close,
pipe_read,
pipe_write,
NULL, /* start */
@@ -83,6 +87,16 @@ struct ctl_ops ctl_sockops = {
sock_locreq
};
+unsigned sock_sesrefs = 0; /* connections to the session */
+uid_t sock_sesuid; /* owner of the session */
+
+void
+sock_close(struct file *f)
+{
+ sock_sesrefs--;
+ pipe_close(f);
+}
+
void
rsock_done(struct aproc *p)
{
@@ -296,6 +310,27 @@ 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)