add suppport for user access control by -pw password (HTML digest)

This commit is contained in:
F. Duncanh
2025-04-22 17:13:13 -04:00
parent 2f809eeadd
commit be4fb423c4
17 changed files with 566 additions and 81 deletions

View File

@@ -65,7 +65,7 @@
#include "renderers/video_renderer.h"
#include "renderers/audio_renderer.h"
#define VERSION "1.71"
#define VERSION "1.712beta"
#define SECOND_IN_USECS 1000000
#define SECOND_IN_NSECS 1000000000UL
@@ -74,6 +74,7 @@
#define LOWEST_ALLOWED_PORT 1024
#define HIGHEST_PORT 65535
#define MISSED_FEEDBACK_LIMIT 15
#define MIN_PASSWORD_LENGTH 4
#define DEFAULT_PLAYBIN_VERSION 3
#define BT709_FIX "capssetter caps=\"video/x-h264, colorimetry=bt709\""
#define SRGB_FIX " ! video/x-raw,colorimetry=sRGB,format=RGB ! "
@@ -143,7 +144,9 @@ static std::vector<std::string> allowed_clients;
static std::vector<std::string> blocked_clients;
static bool restrict_clients;
static bool setup_legacy_pairing = false;
static bool require_password = false;
static unsigned char pin_pw = 0; /* 0: no client access control; 1: onscreen pin ; 2: require password (same password for all clients) 3: random pw*/
static std::string password = "";
static guint min_password_length = MIN_PASSWORD_LENGTH;
static unsigned short pin = 0;
static std::string keyfile = "";
static std::string mac_address = "";
@@ -665,6 +668,9 @@ static void print_info (char *name) {
printf(" default pin is random: optionally use fixed pin xxxx\n");
printf("-reg [fn] Keep a register in $HOME/.uxplay.register to verify returning\n");
printf(" client pin-registration; (option: use file \"fn\" for this)\n");
printf("-pw [pwd] Require use of password to control client access;\n");
printf(" (with no pwd, pin entry is required at *each* connection.)\n");
printf(" (option \"-pw\" after \"-pin\" overrides it, and vice versa)\n");
printf("-vsync [x]Mirror mode: sync audio to video using timestamps (default)\n");
printf(" x is optional audio delay: millisecs, decimal, can be neg.\n");
printf("-vsync no Switch off audio/(server)video timestamp synchronization \n");
@@ -1189,7 +1195,7 @@ static void parse_arguments (int argc, char *argv[]) {
exit(1);
} else if (arg == "-pin") {
setup_legacy_pairing = true;
require_password = true;
pin_pw = 1;
if (i < argc - 1 && *argv[i+1] != '-') {
unsigned int n = 9999;
if (!get_value(argv[++i], &n)) {
@@ -1224,7 +1230,20 @@ static void parse_arguments (int argc, char *argv[]) {
keyfile.erase();
keyfile.append("0");
}
} else if (arg == "-dacp") {
} else if (arg == "-pw") {
setup_legacy_pairing = false;
if (!option_has_value(i, argc, arg, argv[i+1])) {
pin_pw = 3;
} else if (i < argc - 1 && *argv[i+1] != '-') {
password.erase();
password.append(argv[++i]);
pin_pw = 2;
if (password.size() < min_password_length) {
fprintf(stderr, "invalid client-access password \"%s\": length must be at least %u characters\n", password.c_str(), min_password_length);
exit(1);
}
}
} else if (arg == "-dacp") {
dacpfile.erase();
if (i < argc - 1 && *argv[i+1] != '-') {
dacpfile.append(argv[++i]);
@@ -1504,12 +1523,16 @@ static void stop_dnssd() {
static int start_dnssd(std::vector<char> hw_addr, std::string name) {
int dnssd_error;
int require_pw = (require_password ? 1 : 0);
if (dnssd) {
LOGE("start_dnssd error: dnssd != NULL");
return 2;
}
dnssd = dnssd_init(name.c_str(), strlen(name.c_str()), hw_addr.data(), hw_addr.size(), &dnssd_error, require_pw);
/* pin_pw controls client access
pin_pw = 1: client must enter pin displayed onscreen (first access only)
= 2: client must enter password (same password for all clients)
= 0: no access control
*/
dnssd = dnssd_init(name.c_str(), strlen(name.c_str()), hw_addr.data(), hw_addr.size(), &dnssd_error, pin_pw);
if (dnssd_error) {
LOGE("Could not initialize dnssd library!: error %d", dnssd_error);
return 1;
@@ -1665,6 +1688,15 @@ extern "C" void display_pin(void *cls, char *pin) {
}
}
extern "C" const char *passwd(void *cls, int *len){
if (pin_pw == 3) {
*len = -1;
return NULL;
}
*len = password.size();
return password.c_str();
}
extern "C" void export_dacp(void *cls, const char *active_remote, const char *dacp_id) {
if (dacpfile.length()) {
FILE *fp = fopen(dacpfile.c_str(), "w");
@@ -1791,6 +1823,7 @@ extern "C" void video_process (void *cls, raop_ntp_t *ntp, video_decode_struct *
data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
pts_mismatch = video_renderer_render_buffer(data->data, &(data->data_len), &(data->nal_count), &(data->ntp_time_remote));
if (pts_mismatch) {
LOGI("adjust timestamps by %8.6f secs", (double) (pts_mismatch / SECOND_IN_NSECS));
remote_clock_offset += pts_mismatch;
}
count++;
@@ -2096,6 +2129,7 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
raop_cbs.display_pin = display_pin;
raop_cbs.register_client = register_client;
raop_cbs.check_register = check_register;
raop_cbs.passwd = passwd;
raop_cbs.export_dacp = export_dacp;
raop_cbs.video_reset = video_reset;
raop_cbs.video_set_codec = video_set_codec;
@@ -2130,7 +2164,7 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
if (show_client_FPS_data) raop_set_plist(raop, "clientFPSdata", 1);
if (audiodelay >= 0) raop_set_plist(raop, "audio_delay_micros", audiodelay);
if (require_password) raop_set_plist(raop, "pin", (int) pin);
if (pin_pw == 1) raop_set_plist(raop, "pin", (int) pin);
if (hls_support) raop_set_plist(raop, "hls", 1);
/* network port selection (ports listed as "0" will be dynamically assigned) */
@@ -2354,7 +2388,7 @@ int main (int argc, char *argv[]) {
video_converter.append(option);
}
if (require_password && registration_list) {
if (pin_pw == 1 && registration_list) {
if (pairing_register == "") {
const char * homedir = get_homedir();
if (homedir) {
@@ -2365,7 +2399,7 @@ int main (int argc, char *argv[]) {
}
/* read in public keys that were previously registered with pair-setup-pin */
if (require_password && registration_list && strlen(pairing_register.c_str())) {
if (pin_pw == 1 && registration_list && strlen(pairing_register.c_str())) {
size_t len = 0;
std::string key;
int clients = 0;
@@ -2386,7 +2420,7 @@ int main (int argc, char *argv[]) {
}
}
if (require_password && keyfile == "0") {
if (pin_pw == 1 && keyfile == "0") {
const char * homedir = get_homedir();
if (homedir) {
keyfile.erase();