Skip to content

Commit

Permalink
[raop] Add support for Apple TV device verification, required by tvOS…
Browse files Browse the repository at this point in the history
… 10.2 (fix for issue #377)

- also change how speakers are saved/retrieved from the db
- add generic authorization methods in outputs.c and player.c
- let filescanner read *.verification files (containing PIN)
- configure options to enable and disable, since libsodium is required
  • Loading branch information
ejurgensen committed Jun 19, 2017
1 parent 736979a commit f63d103
Show file tree
Hide file tree
Showing 15 changed files with 2,074 additions and 272 deletions.
31 changes: 25 additions & 6 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ dnl Build with libcurl
FORK_ARG_WITH_CHECK([FORKED_OPTS], [libcurl support], [libcurl], [LIBCURL],
[libcurl], [curl_global_init], [curl/curl.h])

dnl Build with libsodium
FORK_ARG_WITH_CHECK([FORKED_OPTS], [libsodium support], [libsodium], [LIBSODIUM],
[libsodium], [sodium_init], [sodium.h])

dnl Build with libplist
FORK_ARG_WITH_CHECK([FORKED_OPTS], [libplist support], [libplist], [LIBPLIST],
[libplist >= 0.16], [plist_dict_get_item], [plist/plist.h])

dnl Build with libevent_pthreads
FORK_ARG_WITH_CHECK([FORKED_OPTS], [libevent_pthreads support],
[libevent_pthreads], [LIBEVENT_PTHREADS], [libevent_pthreads],
Expand Down Expand Up @@ -300,12 +308,6 @@ AS_IF([[test "x$with_avahi" = "xno"]],
[AC_MSG_ERROR([[Avahi client or Bonjour DNS_SD required, please install one.]])])])
AM_CONDITIONAL([COND_AVAHI], [[test "x$with_avahi" = "xyes"]])

dnl iTunes playlists with libplist
FORK_ARG_ENABLE([iTunes Music Library XML support], [itunes], [ITUNES],
[FORK_MODULES_CHECK([FORKED_OPTS], [LIBPLIST], [libplist >= 0.16],
[plist_dict_get_item], [plist/plist.h])])
AM_CONDITIONAL([COND_ITUNES], [[test "x$enable_itunes" = "xyes"]])

dnl Spotify with dynamic linking to libspotify
FORK_ARG_ENABLE([Spotify support], [spotify], [SPOTIFY],
[AS_IF([[test "x$with_json" = "xno"]],
Expand Down Expand Up @@ -352,10 +354,27 @@ FORK_ARG_ENABLE([Chromecast support], [chromecast], [CHROMECAST],
AM_CONDITIONAL([COND_CHROMECAST], [[test "x$enable_chromecast" = "xyes"]])
AM_CONDITIONAL([COND_PROTOBUF_OLD], [[test "x$protobuf_old" = "xyes"]])

dnl iTunes playlists with libplist
FORK_ARG_DISABLE([iTunes Music Library XML support], [itunes], [ITUNES],
[AS_IF([[test "x$with_libplist" = "xno"]],
[AC_MSG_ERROR([[iTunes Music Library XML support requires libplist]])])
])
AM_CONDITIONAL([COND_ITUNES], [[test "x$enable_itunes" = "xyes"]])

dnl MPD support
FORK_ARG_DISABLE([MPD client protocol support], [mpd], [MPD])
AM_CONDITIONAL([COND_MPD], [[test "x$enable_mpd" = "xyes"]])

dnl Apple device verification
FORK_ARG_DISABLE([Apple TV device verification], [verification], [RAOP_VERIFICATION],
[
AS_IF([[test "x$with_libsodium" = "xno"]],
[AC_MSG_ERROR([[Apple TV device verification requires libsodium]])])
AS_IF([[test "x$with_libplist" = "xno"]],
[AC_MSG_ERROR([[Apple TV device verification requires libplist]])])
])
AM_CONDITIONAL([COND_RAOP_VERIFICATION], [[test "x$enable_verification" = "xyes"]])

dnl Defining users and groups
AC_ARG_WITH([daapd_user],
[AS_HELP_STRING([--with-daapd-user=USER],
Expand Down
7 changes: 6 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ if COND_MPD
MPD_SRC=mpd.c mpd.h
endif

if COND_RAOP_VERIFICATION
RAOP_VERIFICATION_SRC=outputs/raop_verification.c outputs/raop_verification.h
endif

if COND_ALSA
ALSA_SRC=outputs/alsa.c
endif
Expand Down Expand Up @@ -112,7 +116,8 @@ forked_daapd_SOURCES = main.c \
input.h input.c \
inputs/file_http.c inputs/pipe.c \
outputs.h outputs.c \
outputs/raop.c outputs/streaming.c outputs/dummy.c outputs/fifo.c \
outputs/raop.c $(RAOP_VERIFICATION_SRC) \
outputs/streaming.c outputs/dummy.c outputs/fifo.c \
$(ALSA_SRC) $(PULSEAUDIO_SRC) $(CHROMECAST_SRC) \
evrtsp/rtsp.c evrtsp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h \
$(SPOTIFY_SRC) \
Expand Down
92 changes: 14 additions & 78 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -3824,21 +3824,21 @@ db_admin_delete(const char *key)

/* Speakers */
int
db_speaker_save(uint64_t id, int selected, int volume, const char *name)
db_speaker_save(struct output_device *device)
{
#define Q_TMPL "INSERT OR REPLACE INTO speakers (id, selected, volume, name) VALUES (%" PRIi64 ", %d, %d, '%q');"
#define Q_TMPL "INSERT OR REPLACE INTO speakers (id, selected, volume, name, auth_key) VALUES (%" PRIi64 ", %d, %d, %Q, %Q);"
char *query;

query = sqlite3_mprintf(Q_TMPL, id, selected, volume, name);
query = sqlite3_mprintf(Q_TMPL, device->id, device->selected, device->volume, device->name, device->auth_key);

return db_query_run(query, 1, 0);
#undef Q_TMPL
}

int
db_speaker_get(uint64_t id, int *selected, int *volume)
db_speaker_get(struct output_device *device, uint64_t id)
{
#define Q_TMPL "SELECT s.selected, s.volume FROM speakers s WHERE s.id = %" PRIi64 ";"
#define Q_TMPL "SELECT s.selected, s.volume, s.name, s.auth_key FROM speakers s WHERE s.id = %" PRIi64 ";"
sqlite3_stmt *stmt;
char *query;
int ret;
Expand All @@ -3847,7 +3847,6 @@ db_speaker_get(uint64_t id, int *selected, int *volume)
if (!query)
{
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");

return -1;
}

Expand All @@ -3857,7 +3856,6 @@ db_speaker_get(uint64_t id, int *selected, int *volume)
if (ret != SQLITE_OK)
{
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));

ret = -1;
goto out;
}
Expand All @@ -3867,15 +3865,20 @@ db_speaker_get(uint64_t id, int *selected, int *volume)
{
if (ret != SQLITE_DONE)
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));

sqlite3_finalize(stmt);

ret = -1;
goto out;
}

*selected = sqlite3_column_int(stmt, 0);
*volume = sqlite3_column_int(stmt, 1);
device->id = id;
device->selected = sqlite3_column_int(stmt, 0);
device->volume = sqlite3_column_int(stmt, 1);

free(device->name);
device->name = safe_strdup((char *)sqlite3_column_text(stmt, 2));

free(device->auth_key);
device->auth_key = safe_strdup((char *)sqlite3_column_text(stmt, 3));

#ifdef DB_PROFILE
while (db_blocking_step(stmt) == SQLITE_ROW)
Expand All @@ -3893,73 +3896,6 @@ db_speaker_get(uint64_t id, int *selected, int *volume)
#undef Q_TMPL
}

int
db_speaker_auth_save(uint64_t id, const char *authkey)
{
#define Q_TMPL "UPDATE speakers SET authkey = '%q' WHERE id = %" PRIi64 ";"
char *query;

query = sqlite3_mprintf(Q_TMPL, authkey, id);

return db_query_run(query, 1, 0);
#undef Q_TMPL
}

char *
db_speaker_auth_get(uint64_t id)
{
#define Q_TMPL "SELECT authkey FROM speakers WHERE id = %" PRIi64 ";"
sqlite3_stmt *stmt;
char *query;
char *out;
int ret;

out = NULL;

query = sqlite3_mprintf(Q_TMPL, id);
if (!query)
{
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
return NULL;
}

DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);

ret = db_blocking_prepare_v2(query, -1, &stmt, NULL);
if (ret != SQLITE_OK)
{
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
goto out;
}

ret = db_blocking_step(stmt);
if (ret != SQLITE_ROW)
{
if (ret != SQLITE_DONE)
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));

sqlite3_finalize(stmt);
goto out;
}

out = (char *)sqlite3_column_text(stmt, 0);
if (out)
out = strdup(out);

#ifdef DB_PROFILE
while (db_blocking_step(stmt) == SQLITE_ROW)
; /* EMPTY */
#endif

sqlite3_finalize(stmt);

out:
sqlite3_free(query);
return out;

#undef Q_TMPL
}

void
db_speaker_clear_all(void)
{
Expand Down
13 changes: 4 additions & 9 deletions src/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <sqlite3.h>

#include "outputs.h"

enum index_type {
I_NONE,
Expand Down Expand Up @@ -675,18 +676,12 @@ db_admin_get(const char *key);
int
db_admin_delete(const char *key);

/* Speakers */
/* Speakers/outputs */
int
db_speaker_save(uint64_t id, int selected, int volume, const char *name);
db_speaker_save(struct output_device *device);

int
db_speaker_get(uint64_t id, int *selected, int *volume);

int
db_speaker_auth_save(uint64_t id, const char *authkey);

char *
db_speaker_auth_get(uint64_t id);
db_speaker_get(struct output_device *device, uint64_t id);

void
db_speaker_clear_all(void);
Expand Down
2 changes: 1 addition & 1 deletion src/db_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
" selected INTEGER NOT NULL," \
" volume INTEGER NOT NULL," \
" name VARCHAR(255) DEFAULT NULL," \
" authkey VARCHAR(2048) DEFAULT NULL" \
" auth_key VARCHAR(2048) DEFAULT NULL" \
");"

#define T_INOTIFY \
Expand Down
4 changes: 2 additions & 2 deletions src/db_upgrade.c
Original file line number Diff line number Diff line change
Expand Up @@ -1548,7 +1548,7 @@ static const struct db_upgrade_query db_upgrade_v1903_queries[] =


#define U_V1904_ALTER_SPEAKERS_ADD_AUTHKEY \
"ALTER TABLE speakers ADD COLUMN authkey VARCHAR(2048) DEFAULT NULL;"
"ALTER TABLE speakers ADD COLUMN auth_key VARCHAR(2048) DEFAULT NULL;"

#define U_V1904_SCVER_MAJOR \
"UPDATE admin SET value = '19' WHERE key = 'schema_version_major';"
Expand All @@ -1557,7 +1557,7 @@ static const struct db_upgrade_query db_upgrade_v1903_queries[] =

static const struct db_upgrade_query db_upgrade_v1904_queries[] =
{
{ U_V1904_ALTER_SPEAKERS_ADD_AUTHKEY, "alter table speakers add column authkey" },
{ U_V1904_ALTER_SPEAKERS_ADD_AUTHKEY, "alter table speakers add column auth_key" },

{ U_V1904_SCVER_MAJOR, "set schema_version_major to 19" },
{ U_V1904_SCVER_MINOR, "set schema_version_minor to 04" },
Expand Down
4 changes: 2 additions & 2 deletions src/library/filescanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,8 @@ process_file(char *file, struct stat *sb, int type, int flags, int dir_id)
case FILE_CTRL_RAOP_VERIFICATION:
if (flags & F_SCAN_BULK)
DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file);
// else
// kickoff(player_raop_verification_kickoff, file, 1);
else
kickoff(player_raop_verification_kickoff, file, 1);
break;

case FILE_CTRL_LASTFM:
Expand Down
3 changes: 3 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,9 @@ main(int argc, char **argv)
#ifdef MPD
strcat(buildopts, " --enable-mpd");
#endif
#ifdef RAOP_VERIFICATION
strcat(buildopts, " --enable-verification");
#endif
#ifdef HAVE_ALSA
strcat(buildopts, " --with-alsa");
#endif
Expand Down
31 changes: 20 additions & 11 deletions src/outputs.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,22 @@ outputs_device_probe(struct output_device *device, output_status_cb cb)
void
outputs_device_free(struct output_device *device)
{
if (!device)
return;

if (outputs[device->type]->disabled)
DPRINTF(E_LOG, L_PLAYER, "BUG! Freeing device from a disabled output?\n");

if (device->session)
DPRINTF(E_LOG, L_PLAYER, "BUG! Freeing device with active session?\n");

if (outputs[device->type]->device_free_extra)
outputs[device->type]->device_free_extra(device);

if (device->name)
free(device->name);

if (device->v4_address)
free(device->v4_address);

if (device->v6_address)
free(device->v6_address);

if (device->session)
DPRINTF(E_LOG, L_PLAYER, "BUG! Freeing device with active session?\n");
free(device->name);
free(device->auth_key);
free(device->v4_address);
free(device->v6_address);

free(device);
}
Expand Down Expand Up @@ -313,6 +312,16 @@ outputs_metadata_free(struct output_metadata *omd)
}
}

void
outputs_authorize(enum output_types type, const char *pin)
{
if (outputs[type]->disabled)
return;

if (outputs[type]->authorize)
outputs[type]->authorize(pin);
}

int
outputs_priority(struct output_device *device)
{
Expand Down
10 changes: 9 additions & 1 deletion src/outputs.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,11 @@ struct output_device
unsigned advertised:1;
unsigned has_password:1;
unsigned has_video:1;
unsigned requires_auth:1;

// Password if relevant
// Credentials if relevant
const char *password;
char *auth_key;

// Device volume
int volume;
Expand Down Expand Up @@ -187,6 +189,9 @@ struct output_definition
// Flush all sessions, the return must be number of sessions pending the flush
int (*flush)(output_status_cb cb, uint64_t rtptime);

// Authorize an output with a pin-code (probably coming from the filescanner)
void (*authorize)(const char *pin);

// Change the call back associated with a session
void (*status_cb)(struct output_session *session, output_status_cb cb);

Expand Down Expand Up @@ -242,6 +247,9 @@ outputs_metadata_prune(uint64_t rtptime);
void
outputs_metadata_free(struct output_metadata *omd);

void
outputs_authorize(enum output_types type, const char *pin);

int
outputs_priority(struct output_device *device);

Expand Down
Loading

0 comments on commit f63d103

Please sign in to comment.