diff --git a/README.md b/README.md index 154eb8a..34430fb 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# UxPlay 1.72 (beta): AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows). +# UxPlay 1.72 (beta): AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (also runs on Windows). ### **Now developed at the GitHub site (where ALL user issues should be posted, and latest versions can be found).** - ***NEW in v1.72**: Improved Support for (YouTube) HLS (HTTP Live Streaming) - video with the new "-hls" option.* **Only streaming from the YouTube iOS app + video with the new "-hls" option (introduced in 1.71).* **Only streaming from the YouTube iOS app (in \"m3u8\" protocol) is currently supported**: (streaming using the AirPlay icon in a browser window is **not** yet supported).Click on the airplay icon in the YouTube app to stream video. @@ -13,10 +13,10 @@ GStreamer playbin v3: use "-hls 2" to revert to playbin v2 if some videos fail to play_. - * added support for setting a password (as an alternative to on-screen + * user-requested features: added support for setting a password (as an alternative to on-screen pin codes) to control client access (-pw option); added support for - setting initial audion volume (--vol option), and output of audio-mode - metatdate to file (for display, -md option). + setting initial client audio-streaming volume (-vol option), and output of audio-mode + metadata to file (for display by some external process, -md option). ## Highlights: diff --git a/lib/pairing.c b/lib/pairing.c index c46ed21..b6141bd 100644 --- a/lib/pairing.c +++ b/lib/pairing.c @@ -246,9 +246,10 @@ char *get_token(char **cursor, char *token_name, char start_char, char end_char) bool pairing_digest_verify(const char *method, const char * authorization, const char *password) { /* RFC 2617 HTTP md5 Digest password authentication */ - - char *sentence = (char *) calloc(strlen(authorization) + 1, sizeof(char)); - strncpy(sentence, authorization, strlen(authorization)); + size_t authlen = strlen(authorization); + char *sentence = (char *) malloc(authlen + 1); + memcpy(sentence, authorization, authlen); + *(sentence + authlen) = '\0'; char *username = NULL; char *realm = NULL; char *nonce = NULL; @@ -309,35 +310,50 @@ pairing_digest_verify(const char *method, const char * authorization, const char /* H1 = H(username : realm : password ) */ len = strlen(username) + strlen(realm) + strlen(pwd) + 3; raw = (char *) calloc(len, sizeof(char)); - snprintf(raw, len, "%s:%s:%s", username, realm, pwd); + strncat(raw, username, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + strncat(raw, realm, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + strncat(raw, pwd, len - strlen(raw) - 1); char *hash1 = get_md5(raw); free (raw); #ifdef test_digest - printf("hash1: should be %s, was: %s\n ", HA1, hash1_str); + printf("hash1: should be %s, was: %s\n", HA1, hash1); #endif /* H2 = H(method : uri) */ len = strlen(mthd) + strlen(uri) + 2; raw = (char *) calloc(len, sizeof(char)); - snprintf(raw, len, "%s:%s", mthd, uri); + strncat(raw, mthd, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + strncat(raw, uri, len - strlen(raw) - 1); char *hash2 = get_md5(raw); free (raw); #ifdef test_digest - printf("hash2: should be %s, was: %s\n", HA2, hash2_str); + printf("hash2: should be %s, was: %s\n", HA2, hash2); #endif /* result = H(H1 : nonce (or nonce:nc:cnonce:qop) : H2) */ len = strlen(hash1) + strlen(nonce) + strlen(hash2) + 3; if (qop) { len += strlen(nc) + strlen(cnonce) + strlen(qop) + 3; - raw = (char *) calloc(len, sizeof(char)); - snprintf(raw, len, "%s:%s:%s:%s:%s:%s", hash1, nonce, nc, cnonce, qop, hash2); - } else { - raw = (char *) calloc(len, sizeof(char)); - snprintf(raw, len, "%s:%s:%s", hash1, nonce, hash2); } + raw = (char *) calloc(len, sizeof(char)); + strncat(raw, hash1, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + strncat(raw, nonce, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + if (qop) { + strncat(raw, nc, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + strncat(raw, cnonce, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + strncat(raw, qop, len - strlen(raw) - 1); + strncat(raw, ":", len - strlen(raw) - 1); + } + strncat(raw, hash2, len - strlen(raw) - 1); free (hash1); free (hash2); char *result = get_md5(raw); diff --git a/lib/raop_handlers.h b/lib/raop_handlers.h index d885588..ee1ee67 100644 --- a/lib/raop_handlers.h +++ b/lib/raop_handlers.h @@ -597,18 +597,16 @@ raop_handler_setup(raop_conn_t *conn, } char pin[6] = {'\0'}; snprintf(pin, 5, "%04u", pin_4 % 10000); - printf("*** set new pin = [%s]\n", pin); conn->raop->random_pw = strndup((const char *) pin, 6); - printf("*** stored new pin = [%s]\n", conn->raop->random_pw); - } - if (len == -1 && conn->raop->callbacks.display_pin) { - char *pin = conn->raop->random_pw; - assert(pin); - conn->raop->callbacks.display_pin(conn->raop->callbacks.cls, pin); + if (conn->raop->callbacks.display_pin) { + conn->raop->callbacks.display_pin(conn->raop->callbacks.cls, pin); + } logger_log(conn->raop->logger, LOGGER_INFO, "*** CLIENT MUST NOW ENTER PIN = \"%s\" AS AIRPLAY PASSWORD", pin); - password = (const char *) pin; } if (len && !conn->authenticated) { + if (len == -1) { + password = (const char *) conn->raop->random_pw; + } char nonce_string[33] = { '\0' }; //bool stale = false; //not implemented const char *authorization = NULL; @@ -627,7 +625,6 @@ raop_handler_setup(raop_conn_t *conn, } } if (conn->authenticated && conn->raop->random_pw) { - printf("*********free random_pw\n"); free (conn->raop->random_pw); conn->raop->random_pw = NULL; } @@ -649,8 +646,8 @@ raop_handler_setup(raop_conn_t *conn, } conn->raop->nonce = utils_hex_to_string(nonce, len); char response_text[80] = "Digest realm=\"raop\", nonce=\""; - strncat(response_text, conn->raop->nonce, strlen(conn->raop->nonce)); - strncat(response_text, "\"", 1); + strncat(response_text, conn->raop->nonce, 80 - strlen(response_text) - 1); + strncat(response_text, "\"", 80 - strlen(response_text) - 1); http_response_init(response, "RTSP/1.0", 401, "Unauthorized"); http_response_add_header(response, "WWW-Authenticate", response_text); return; diff --git a/uxplay.cpp b/uxplay.cpp index cbd5362..b94842e 100644 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -1232,9 +1232,7 @@ static void parse_arguments (int argc, char *argv[]) { } } 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] != '-') { + if (i < argc - 1 && *argv[i+1] != '-') { password.erase(); password.append(argv[++i]); pin_pw = 2; @@ -1242,6 +1240,8 @@ static void parse_arguments (int argc, char *argv[]) { fprintf(stderr, "invalid client-access password \"%s\": length must be at least %u characters\n", password.c_str(), min_password_length); exit(1); } + } else { + pin_pw = 3; //a random password (pin) will be displayed at each connection } } else if (arg == "-dacp") { dacpfile.erase();