Replace hard-coded strings with macros, replace PATH_MAX with actual

string length, validate audio and midi device numbers
This commit is contained in:
Alexandre Ratchov 2015-10-02 14:28:17 +02:00
parent 0a39548f4d
commit 5d431d3616
8 changed files with 137 additions and 36 deletions

View File

@ -19,12 +19,28 @@
#include <stdint.h> #include <stdint.h>
/* /*
* socket and option names * unix-domain socket name is:
*
* DIR [ '-' UID ] '/' FILE UNIT
*
* example: "/tmp/aucat-1000/aucat0"
*
*/
#define SOCKPATH_DIR "/tmp/aucat"
#define SOCKPATH_FILE "aucat"
#define SOCKPATH_MAX (1 + \
sizeof(SOCKPATH_DIR) - 1 + \
sizeof(char) + \
sizeof(int) * 3 + \
sizeof(char) + \
sizeof(SOCKPATH_FILE) - 1 + \
sizeof(int) * 3)
/*
* server TCP base port number
*/ */
#define AUCAT_PATH "aucat"
#define AUCAT_PORT 11025 #define AUCAT_PORT 11025
#define DEFAULT_OPT "default"
/* /*
* WARNING: since the protocol may be simultaneously used by static * WARNING: since the protocol may be simultaneously used by static

View File

@ -244,10 +244,12 @@ _aucat_wdata(struct aucat *hdl, const void *buf, size_t len,
static int static int
aucat_mkcookie(unsigned char *cookie) aucat_mkcookie(unsigned char *cookie)
{ {
#define COOKIE_SUFFIX "/.aucat_cookie"
#define TEMPL_SUFFIX ".XXXXXXXX"
struct stat sb; struct stat sb;
char *home, path[PATH_MAX], tmp[PATH_MAX]; char *home, *path = NULL, *tmp = NULL;
ssize_t len; size_t home_len, path_len;
int fd; int fd, len;
/* /*
* try to load the cookie * try to load the cookie
@ -255,7 +257,13 @@ aucat_mkcookie(unsigned char *cookie)
home = issetugid() ? NULL : getenv("HOME"); home = issetugid() ? NULL : getenv("HOME");
if (home == NULL) if (home == NULL)
goto bad_gen; goto bad_gen;
snprintf(path, PATH_MAX, "%s/.aucat_cookie", home); home_len = strlen(home);
path = malloc(home_len + sizeof(COOKIE_SUFFIX));
if (path == NULL)
goto bad_gen;
memcpy(path, home, home_len);
memcpy(path + home_len, COOKIE_SUFFIX, sizeof(COOKIE_SUFFIX));
path_len = home_len + sizeof(COOKIE_SUFFIX) - 1;
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) { if (fd < 0) {
if (errno != ENOENT) if (errno != ENOENT)
@ -280,7 +288,7 @@ aucat_mkcookie(unsigned char *cookie)
goto bad_close; goto bad_close;
} }
close(fd); close(fd);
return 1; goto done;
bad_close: bad_close:
close(fd); close(fd);
bad_gen: bad_gen:
@ -290,36 +298,44 @@ bad_gen:
#ifdef HAVE_ARC4RANDOM #ifdef HAVE_ARC4RANDOM
arc4random_buf(cookie, AMSG_COOKIELEN); arc4random_buf(cookie, AMSG_COOKIELEN);
#else #else
if (!random_bytes(cookie, AMSG_COOKIELEN)) if (!random_bytes(cookie, AMSG_COOKIELEN)) {
if (path)
free(path);
return 0; return 0;
}
#endif #endif
/* /*
* try to save the cookie * try to save the cookie
*/ */
if (home == NULL) if (home == NULL)
return 1; goto done;
if (strlcpy(tmp, path, PATH_MAX) >= PATH_MAX || tmp = malloc(path_len + sizeof(TEMPL_SUFFIX));
strlcat(tmp, ".XXXXXXXX", PATH_MAX) >= PATH_MAX) { if (tmp == NULL)
DPRINTF("%s: too long\n", path); goto done;
return 1; memcpy(tmp, path, path_len);
} memcpy(tmp + path_len, TEMPL_SUFFIX, sizeof(TEMPL_SUFFIX));
fd = mkstemp(tmp); fd = mkstemp(tmp);
if (fd < 0) { if (fd < 0) {
DPERROR(tmp); DPERROR(tmp);
return 1; goto done;
} }
if (write(fd, cookie, AMSG_COOKIELEN) < 0) { if (write(fd, cookie, AMSG_COOKIELEN) < 0) {
DPERROR(tmp); DPERROR(tmp);
unlink(tmp); unlink(tmp);
close(fd); close(fd);
return 1; goto done;
} }
close(fd); close(fd);
if (rename(tmp, path) < 0) { if (rename(tmp, path) < 0) {
DPERROR(tmp); DPERROR(tmp);
unlink(tmp); unlink(tmp);
} }
done:
if (tmp)
free(tmp);
if (path)
free(path);
return 1; return 1;
} }
@ -381,7 +397,7 @@ aucat_connect_un(struct aucat *hdl, unsigned int unit)
uid = geteuid(); uid = geteuid();
snprintf(ca.sun_path, sizeof(ca.sun_path), snprintf(ca.sun_path, sizeof(ca.sun_path),
"/tmp/aucat-%u/%s%u", uid, AUCAT_PATH, unit); SOCKPATH_DIR "-%u/" SOCKPATH_FILE "%u", uid, unit);
ca.sun_family = AF_UNIX; ca.sun_family = AF_UNIX;
s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (s < 0) if (s < 0)
@ -392,7 +408,7 @@ aucat_connect_un(struct aucat *hdl, unsigned int unit)
DPERROR(ca.sun_path); DPERROR(ca.sun_path);
/* try shared server */ /* try shared server */
snprintf(ca.sun_path, sizeof(ca.sun_path), snprintf(ca.sun_path, sizeof(ca.sun_path),
"/tmp/aucat/%s%u", AUCAT_PATH, unit); SOCKPATH_DIR "/" SOCKPATH_FILE "%u", unit);
while (connect(s, (struct sockaddr *)&ca, len) < 0) { while (connect(s, (struct sockaddr *)&ca, len) < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;

View File

@ -54,3 +54,27 @@ _sndio_parsetype(const char *str, char *type)
return NULL; return NULL;
return str; return str;
} }
const char *
_sndio_parsenum(const char *str, unsigned int *num, unsigned int max)
{
const char *p = str;
unsigned int dig, maxq, maxr, val;
val = 0;
maxq = max / 10;
maxr = max % 10;
for (;;) {
dig = *p - '0';
if (dig >= 10)
break;
if (val > maxq || (val == maxq && dig > maxr))
return NULL;
val = val * 10 + dig;
p++;
}
if (p == str)
return NULL;
*num = val;
return p;
}

View File

@ -22,7 +22,7 @@
#define DPRINTFN(n, ...) \ #define DPRINTFN(n, ...) \
do { \ do { \
if (_sndio_debug >= (n)) \ if (_sndio_debug >= (n)) \
fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, __VA_ARGS__); \
} while(0) } while(0)
@ -47,5 +47,6 @@ extern int _sndio_debug;
#endif #endif
const char *_sndio_parsetype(const char *, char *); const char *_sndio_parsetype(const char *, char *);
const char *_sndio_parsenum(const char *, unsigned int *, unsigned int);
#endif #endif

View File

@ -31,6 +31,8 @@
#include "debug.h" #include "debug.h"
#include "mio_priv.h" #include "mio_priv.h"
#define DEVNAME_PREFIX "hw:"
#ifdef DEBUG #ifdef DEBUG
static snd_output_t *output = NULL; static snd_output_t *output = NULL;
#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err)) #define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err))
@ -40,6 +42,7 @@ static snd_output_t *output = NULL;
struct mio_alsa_hdl { struct mio_alsa_hdl {
struct mio_hdl mio; struct mio_hdl mio;
char *devname;
snd_rawmidi_t *in, *out; snd_rawmidi_t *in, *out;
int infds, onfds, nfds, events; int infds, onfds, nfds, events;
}; };
@ -64,7 +67,7 @@ struct mio_hdl *
mio_alsa_open(const char *str, unsigned int mode, int nbio) mio_alsa_open(const char *str, unsigned int mode, int nbio)
{ {
struct mio_alsa_hdl *hdl; struct mio_alsa_hdl *hdl;
char path[PATH_MAX]; size_t len;
int rc; int rc;
switch (*str) { switch (*str) {
@ -84,11 +87,20 @@ mio_alsa_open(const char *str, unsigned int mode, int nbio)
if (rc < 0) if (rc < 0)
DALSA("couldn't attach to stderr", rc); DALSA("couldn't attach to stderr", rc);
#endif #endif
snprintf(path, sizeof(path), "hw:%s", str); len = strlen(str);
hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX));
if (hdl->devname == NULL) {
free(hdl);
return NULL;
}
memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1);
memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, str, len + 1);
hdl->in = hdl->out = NULL; hdl->in = hdl->out = NULL;
rc = snd_rawmidi_open(&hdl->in, &hdl->out, path, SND_RAWMIDI_NONBLOCK); rc = snd_rawmidi_open(&hdl->in, &hdl->out,
hdl->devname, SND_RAWMIDI_NONBLOCK);
if (rc) { if (rc) {
DALSA("could't open port", rc); DALSA("could't open port", rc);
free(hdl->devname);
free(hdl); free(hdl);
return NULL; return NULL;
} }
@ -111,6 +123,7 @@ mio_alsa_close(struct mio_hdl *sh)
snd_rawmidi_drain(hdl->out); snd_rawmidi_drain(hdl->out);
snd_rawmidi_close(hdl->out); snd_rawmidi_close(hdl->out);
} }
free(hdl->devname);
free(hdl); free(hdl);
} }

View File

@ -30,6 +30,11 @@
#include "debug.h" #include "debug.h"
#include "mio_priv.h" #include "mio_priv.h"
#define DEVPATH_PREFIX "/dev/rmidi"
#define DEVPATH_MAX (1 + \
sizeof(DEVPATH_PREFIX) - 1 + \
sizeof(int) * 3)
struct mio_rmidi_hdl { struct mio_rmidi_hdl {
struct mio_hdl mio; struct mio_hdl mio;
int fd; int fd;
@ -56,22 +61,27 @@ _mio_rmidi_open(const char *str, unsigned int mode, int nbio)
{ {
int fd, flags; int fd, flags;
struct mio_rmidi_hdl *hdl; struct mio_rmidi_hdl *hdl;
char path[PATH_MAX]; char path[DEVPATH_MAX];
unsigned int devnum;
switch (*str) { switch (*str) {
case '/': case '/':
str++; str++;
break; break;
default: default:
DPRINTF("_sio_sun_open: %s: '/<devnum>' expected\n", str); DPRINTF("_mio_rmidi_open: %s: '/<devnum>' expected\n", str);
return NULL;
}
str = _sndio_parsenum(str, &devnum, 255);
if (str == NULL || *str != '\0') {
DPRINTF("_mio_rmidi_open: can't determine device number\n");
return NULL; return NULL;
} }
hdl = malloc(sizeof(struct mio_rmidi_hdl)); hdl = malloc(sizeof(struct mio_rmidi_hdl));
if (hdl == NULL) if (hdl == NULL)
return NULL; return NULL;
_mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio); _mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio);
snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
snprintf(path, sizeof(path), "/dev/rmidi%s", str);
if (mode == (MIO_OUT | MIO_IN)) if (mode == (MIO_OUT | MIO_IN))
flags = O_RDWR; flags = O_RDWR;
else else

View File

@ -35,6 +35,8 @@
#include "sio_priv.h" #include "sio_priv.h"
#include "bsd-compat.h" #include "bsd-compat.h"
#define DEVNAME_PREFIX "hw:"
#ifdef DEBUG #ifdef DEBUG
static snd_output_t *output = NULL; static snd_output_t *output = NULL;
#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err)) #define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err))
@ -45,6 +47,7 @@ static snd_output_t *output = NULL;
struct sio_alsa_hdl { struct sio_alsa_hdl {
struct sio_hdl sio; struct sio_hdl sio;
struct sio_par par; struct sio_par par;
char *devname;
snd_pcm_t *opcm; snd_pcm_t *opcm;
snd_pcm_t *ipcm; snd_pcm_t *ipcm;
unsigned ibpf, obpf; /* bytes per frame */ unsigned ibpf, obpf; /* bytes per frame */
@ -273,8 +276,8 @@ struct sio_hdl *
_sio_alsa_open(const char *str, unsigned mode, int nbio) _sio_alsa_open(const char *str, unsigned mode, int nbio)
{ {
struct sio_alsa_hdl *hdl; struct sio_alsa_hdl *hdl;
char path[PATH_MAX];
struct sio_par par; struct sio_par par;
size_t len;
int err; int err;
switch (*str) { switch (*str) {
@ -282,7 +285,7 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
str++; str++;
break; break;
default: default:
DPRINTF("_sio_sun_open: %s: '/<devnum>' expected\n", str); DPRINTF("_sio_alsa_open: %s: '/<devnum>' expected\n", str);
return NULL; return NULL;
} }
hdl = malloc(sizeof(struct sio_alsa_hdl)); hdl = malloc(sizeof(struct sio_alsa_hdl));
@ -295,10 +298,14 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
if (err < 0) if (err < 0)
DALSA("couldn't attach to stderr", err); DALSA("couldn't attach to stderr", err);
#endif #endif
len = strlen(str);
snprintf(path, sizeof(path), "hw:%s", str); hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX));
if (hdl->devname == NULL)
goto bad_free_hdl;
memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1);
memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, str, len + 1);
if (mode & SIO_PLAY) { if (mode & SIO_PLAY) {
err = snd_pcm_open(&hdl->opcm, path, err = snd_pcm_open(&hdl->opcm, hdl->devname,
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (err < 0) { if (err < 0) {
DALSA("couldn't open play stream", err); DALSA("couldn't open play stream", err);
@ -306,7 +313,7 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
} }
} }
if (mode & SIO_REC) { if (mode & SIO_REC) {
err = snd_pcm_open(&hdl->ipcm, path, err = snd_pcm_open(&hdl->ipcm, hdl->devname,
SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
if (err < 0) { if (err < 0) {
DALSA("couldn't open rec stream", err); DALSA("couldn't open rec stream", err);
@ -345,6 +352,8 @@ bad_free_opcm:
if (mode & SIO_PLAY) if (mode & SIO_PLAY)
snd_pcm_close(hdl->opcm); snd_pcm_close(hdl->opcm);
bad_free: bad_free:
free(hdl->devname);
bad_free_hdl:
free(hdl); free(hdl);
return NULL; return NULL;
} }
@ -358,6 +367,7 @@ sio_alsa_close(struct sio_hdl *sh)
snd_pcm_close(hdl->opcm); snd_pcm_close(hdl->opcm);
if (hdl->sio.mode & SIO_REC) if (hdl->sio.mode & SIO_REC)
snd_pcm_close(hdl->ipcm); snd_pcm_close(hdl->ipcm);
free(hdl->devname);
free(hdl); free(hdl);
} }

View File

@ -34,6 +34,11 @@
#include "sio_priv.h" #include "sio_priv.h"
#include "bsd-compat.h" #include "bsd-compat.h"
#define DEVPATH_PREFIX "/dev/audio"
#define DEVPATH_MAX (1 + \
sizeof(DEVPATH_PREFIX) - 1 + \
sizeof(int) * 3)
struct sio_sun_hdl { struct sio_sun_hdl {
struct sio_hdl sio; struct sio_hdl sio;
int fd; int fd;
@ -332,7 +337,8 @@ _sio_sun_open(const char *str, unsigned int mode, int nbio)
struct audio_info aui; struct audio_info aui;
struct sio_sun_hdl *hdl; struct sio_sun_hdl *hdl;
struct sio_par par; struct sio_par par;
char path[PATH_MAX]; char path[DEVPATH_MAX];
unsigned int devnum;
switch (*str) { switch (*str) {
case '/': case '/':
@ -342,12 +348,17 @@ _sio_sun_open(const char *str, unsigned int mode, int nbio)
DPRINTF("_sio_sun_open: %s: '/<devnum>' expected\n", str); DPRINTF("_sio_sun_open: %s: '/<devnum>' expected\n", str);
return NULL; return NULL;
} }
str = _sndio_parsenum(str, &devnum, 255);
if (str == NULL || *str != '\0') {
DPRINTF("_sio_sun_open: can't determine device number\n");
return NULL;
}
hdl = malloc(sizeof(struct sio_sun_hdl)); hdl = malloc(sizeof(struct sio_sun_hdl));
if (hdl == NULL) if (hdl == NULL)
return NULL; return NULL;
_sio_create(&hdl->sio, &sio_sun_ops, mode, nbio); _sio_create(&hdl->sio, &sio_sun_ops, mode, nbio);
snprintf(path, sizeof(path), "/dev/audio%s", str); snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
if (mode == (SIO_PLAY | SIO_REC)) if (mode == (SIO_PLAY | SIO_REC))
flags = O_RDWR; flags = O_RDWR;
else else