mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	module-raop: Use new openssl methods
Fix Digest, we need to use the method to generate a new Digest for each request. Use newer openssl methods instead of deprecated ones. The RSA sign still need to be ported.
This commit is contained in:
		
							parent
							
								
									98222ab2ae
								
							
						
					
					
						commit
						9a4a4fe9c4
					
				
					 1 changed files with 173 additions and 139 deletions
				
			
		| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
#include <openssl/err.h>
 | 
					#include <openssl/err.h>
 | 
				
			||||||
#include <openssl/rand.h>
 | 
					#include <openssl/rand.h>
 | 
				
			||||||
#include <openssl/rsa.h>
 | 
					#include <openssl/rsa.h>
 | 
				
			||||||
 | 
					#include <openssl/core_names.h>
 | 
				
			||||||
#include <openssl/engine.h>
 | 
					#include <openssl/engine.h>
 | 
				
			||||||
#include <openssl/aes.h>
 | 
					#include <openssl/aes.h>
 | 
				
			||||||
#include <openssl/md5.h>
 | 
					#include <openssl/md5.h>
 | 
				
			||||||
| 
						 | 
					@ -210,12 +211,15 @@ struct impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char session_id[32];
 | 
						char session_id[32];
 | 
				
			||||||
	char *password;
 | 
						char *password;
 | 
				
			||||||
 | 
						char *auth_method;
 | 
				
			||||||
 | 
						char *realm;
 | 
				
			||||||
 | 
						char *nonce;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int do_disconnect:1;
 | 
						unsigned int do_disconnect:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t key[AES_CHUNK_SIZE]; /* Key for aes-cbc */
 | 
						uint8_t key[AES_CHUNK_SIZE]; /* Key for aes-cbc */
 | 
				
			||||||
	uint8_t iv[AES_CHUNK_SIZE];  /* Initialization vector for cbc */
 | 
						uint8_t iv[AES_CHUNK_SIZE];  /* Initialization vector for cbc */
 | 
				
			||||||
	AES_KEY aes;                 /* AES encryption */
 | 
						EVP_CIPHER_CTX *ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint16_t control_port;
 | 
						uint16_t control_port;
 | 
				
			||||||
	int control_fd;
 | 
						int control_fd;
 | 
				
			||||||
| 
						 | 
					@ -269,20 +273,9 @@ static inline void bit_writer(uint8_t **p, int *pos, uint8_t data, int len)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int aes_encrypt(struct impl *impl, uint8_t *data, int len)
 | 
					static int aes_encrypt(struct impl *impl, uint8_t *data, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t nv[AES_CHUNK_SIZE];
 | 
						int i = len & ~0xf, clen = i;
 | 
				
			||||||
    uint8_t *buffer;
 | 
						EVP_EncryptInit(impl->ctx, EVP_aes_128_cbc(), impl->key, impl->iv);
 | 
				
			||||||
    int i, j;
 | 
						EVP_EncryptUpdate(impl->ctx, data, &clen, data, i);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    memcpy(nv, impl->iv, AES_CHUNK_SIZE);
 | 
					 | 
				
			||||||
    for (i = 0; i + AES_CHUNK_SIZE <= len; i += AES_CHUNK_SIZE) {
 | 
					 | 
				
			||||||
        buffer = data + i;
 | 
					 | 
				
			||||||
        for (j = 0; j < AES_CHUNK_SIZE; j++)
 | 
					 | 
				
			||||||
            buffer[j] ^= nv[j];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AES_encrypt(buffer, buffer, &impl->aes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        memcpy(nv, buffer, AES_CHUNK_SIZE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
	return i;
 | 
						return i;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -706,6 +699,126 @@ on_control_source_io(void *data, int fd, uint32_t mask)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void base64_encode(const uint8_t *data, size_t len, char *enc, char pad)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static const char tab[] =
 | 
				
			||||||
 | 
						    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
						for (i = 0; i < len; i += 3) {
 | 
				
			||||||
 | 
							uint32_t v;
 | 
				
			||||||
 | 
							v  =              data[i+0]      << 16;
 | 
				
			||||||
 | 
							v |= (i+1 < len ? data[i+1] : 0) << 8;
 | 
				
			||||||
 | 
							v |= (i+2 < len ? data[i+2] : 0);
 | 
				
			||||||
 | 
							*enc++ =             tab[(v >> (3*6)) & 0x3f];
 | 
				
			||||||
 | 
							*enc++ =             tab[(v >> (2*6)) & 0x3f];
 | 
				
			||||||
 | 
							*enc++ = i+1 < len ? tab[(v >> (1*6)) & 0x3f] : pad;
 | 
				
			||||||
 | 
							*enc++ = i+2 < len ? tab[(v >> (0*6)) & 0x3f] : pad;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						*enc = '\0';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t base64_decode(const char *data, size_t len, uint8_t *dec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t tab[] = {
 | 
				
			||||||
 | 
							62, -1, -1, -1, 63, 52, 53, 54, 55, 56,
 | 
				
			||||||
 | 
							57, 58, 59, 60, 61, -1, -1, -1, -1, -1,
 | 
				
			||||||
 | 
							-1, -1,  0,  1,  2,  3,  4,  5,  6,  7,
 | 
				
			||||||
 | 
							 8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
 | 
				
			||||||
 | 
							18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
 | 
				
			||||||
 | 
							-1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
 | 
				
			||||||
 | 
							32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
 | 
				
			||||||
 | 
							42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };
 | 
				
			||||||
 | 
						size_t i, j;
 | 
				
			||||||
 | 
						for (i = 0, j = 0; i < len; i += 4) {
 | 
				
			||||||
 | 
							uint32_t v;
 | 
				
			||||||
 | 
							v =                          tab[data[i+0]-43]  << (3*6);
 | 
				
			||||||
 | 
							v |=                         tab[data[i+1]-43]  << (2*6);
 | 
				
			||||||
 | 
							v |= (data[i+2] == '=' ? 0 : tab[data[i+2]-43]) << (1*6);
 | 
				
			||||||
 | 
							v |= (data[i+3] == '=' ? 0 : tab[data[i+3]-43]);
 | 
				
			||||||
 | 
							                      dec[j++] = (v >> 16) & 0xff;
 | 
				
			||||||
 | 
							if (data[i+2] != '=') dec[j++] = (v >> 8)  & 0xff;
 | 
				
			||||||
 | 
							if (data[i+3] != '=') dec[j++] =  v        & 0xff;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return j;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_PRINTF_FUNC(2,3)
 | 
				
			||||||
 | 
					static int MD5_hash(char hash[MD5_HASH_LENGTH+1], const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char d[MD5_DIGEST_LENGTH];
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						va_list args;
 | 
				
			||||||
 | 
						char buffer[1024];
 | 
				
			||||||
 | 
						unsigned int size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(args, fmt);
 | 
				
			||||||
 | 
						vsnprintf(buffer, sizeof(buffer), fmt, args);
 | 
				
			||||||
 | 
						va_end(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size = MD5_DIGEST_LENGTH;
 | 
				
			||||||
 | 
						EVP_Digest(buffer, strlen(buffer), d, &size, EVP_md5(), NULL);
 | 
				
			||||||
 | 
						for (i = 0; i < MD5_DIGEST_LENGTH; i++)
 | 
				
			||||||
 | 
							sprintf(&hash[2*i], "%02x", (uint8_t) d[i]);
 | 
				
			||||||
 | 
						hash[MD5_HASH_LENGTH] = '\0';
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rtsp_add_auth(struct impl *impl, const char *method)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char auth[1024];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (impl->auth_method == NULL)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spa_streq(impl->auth_method, "Basic")) {
 | 
				
			||||||
 | 
							char buf[256];
 | 
				
			||||||
 | 
							char enc[512];
 | 
				
			||||||
 | 
							spa_scnprintf(buf, sizeof(buf), "%s:%s", DEFAULT_USER_NAME, impl->password);
 | 
				
			||||||
 | 
							base64_encode((uint8_t*)buf, strlen(buf), enc, '=');
 | 
				
			||||||
 | 
							spa_scnprintf(auth, sizeof(auth), "Basic %s", enc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (spa_streq(impl->auth_method, "Digest")) {
 | 
				
			||||||
 | 
							const char *url;
 | 
				
			||||||
 | 
							char h1[MD5_HASH_LENGTH+1];
 | 
				
			||||||
 | 
							char h2[MD5_HASH_LENGTH+1];
 | 
				
			||||||
 | 
							char resp[MD5_HASH_LENGTH+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							url = pw_rtsp_client_get_url(impl->rtsp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							MD5_hash(h1, "%s:%s:%s", DEFAULT_USER_NAME, impl->realm, impl->password);
 | 
				
			||||||
 | 
							MD5_hash(h2, "%s:%s", method, url);
 | 
				
			||||||
 | 
							MD5_hash(resp, "%s:%s:%s", h1, impl->nonce, h2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pw_log_warn("%s:%s", method, url);
 | 
				
			||||||
 | 
							spa_scnprintf(auth, sizeof(auth),
 | 
				
			||||||
 | 
									"username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
 | 
				
			||||||
 | 
									DEFAULT_USER_NAME, impl->realm, impl->nonce, url, resp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_properties_setf(impl->headers, "Authorization", "%s %s",
 | 
				
			||||||
 | 
								impl->auth_method, auth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						pw_log_error("error adding auth");
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rtsp_send(struct impl *impl, const char *method,
 | 
				
			||||||
 | 
							const char *content_type, const char *content,
 | 
				
			||||||
 | 
							int (*reply) (void *data, int status, const struct spa_dict *headers))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtsp_add_auth(impl, method);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res = pw_rtsp_client_send(impl->rtsp, method, &impl->headers->dict,
 | 
				
			||||||
 | 
								content_type, content, reply, impl);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rtsp_flush_reply(void *data, int status, const struct spa_dict *headers)
 | 
					static int rtsp_flush_reply(void *data, int status, const struct spa_dict *headers)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pw_log_info("reply %d", status);
 | 
						pw_log_info("reply %d", status);
 | 
				
			||||||
| 
						 | 
					@ -725,8 +838,7 @@ static int rtsp_do_flush(struct impl *impl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->recording = false;
 | 
						impl->recording = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = pw_rtsp_client_send(impl->rtsp, "FLUSH", &impl->headers->dict,
 | 
						res = rtsp_send(impl, "FLUSH", NULL, NULL, rtsp_flush_reply);
 | 
				
			||||||
			NULL, NULL, rtsp_flush_reply, impl);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_properties_set(impl->headers, "Range", NULL);
 | 
						pw_properties_set(impl->headers, "Range", NULL);
 | 
				
			||||||
	pw_properties_set(impl->headers, "RTP-Info", NULL);
 | 
						pw_properties_set(impl->headers, "RTP-Info", NULL);
 | 
				
			||||||
| 
						 | 
					@ -770,8 +882,7 @@ static int rtsp_record_reply(void *data, int status, const struct spa_dict *head
 | 
				
			||||||
	impl->recording = true;
 | 
						impl->recording = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(progress, sizeof(progress), "progress: %s/%s/%s\r\n", "0", "0", "0");
 | 
						snprintf(progress, sizeof(progress), "progress: %s/%s/%s\r\n", "0", "0", "0");
 | 
				
			||||||
	return pw_rtsp_client_send(impl->rtsp, "SET_PARAMETER", NULL,
 | 
						return rtsp_send(impl, "SET_PARAMETER", "text/parameters", progress, NULL);
 | 
				
			||||||
			"text/parameters", progress, NULL, NULL);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rtsp_do_record(struct impl *impl)
 | 
					static int rtsp_do_record(struct impl *impl)
 | 
				
			||||||
| 
						 | 
					@ -785,8 +896,7 @@ static int rtsp_do_record(struct impl *impl)
 | 
				
			||||||
	pw_properties_setf(impl->headers, "RTP-Info",
 | 
						pw_properties_setf(impl->headers, "RTP-Info",
 | 
				
			||||||
			"seq=%u;rtptime=%u", impl->seq, impl->rtptime);
 | 
								"seq=%u;rtptime=%u", impl->seq, impl->rtptime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = pw_rtsp_client_send(impl->rtsp, "RECORD", &impl->headers->dict,
 | 
						res = rtsp_send(impl, "RECORD", NULL, NULL, rtsp_record_reply);
 | 
				
			||||||
			NULL, NULL, rtsp_record_reply, impl);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_properties_set(impl->headers, "Range", NULL);
 | 
						pw_properties_set(impl->headers, "Range", NULL);
 | 
				
			||||||
	pw_properties_set(impl->headers, "RTP-Info", NULL);
 | 
						pw_properties_set(impl->headers, "RTP-Info", NULL);
 | 
				
			||||||
| 
						 | 
					@ -942,8 +1052,7 @@ static int rtsp_do_setup(struct impl *impl)
 | 
				
			||||||
		return -ENOTSUP;
 | 
							return -ENOTSUP;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = pw_rtsp_client_send(impl->rtsp, "SETUP", &impl->headers->dict,
 | 
						res = rtsp_send(impl, "SETUP", NULL, NULL, rtsp_setup_reply);
 | 
				
			||||||
			NULL, NULL, rtsp_setup_reply, impl);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_properties_set(impl->headers, "Transport", NULL);
 | 
						pw_properties_set(impl->headers, "Transport", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -969,49 +1078,6 @@ static int rtsp_announce_reply(void *data, int status, const struct spa_dict *he
 | 
				
			||||||
	return rtsp_do_setup(impl);
 | 
						return rtsp_do_setup(impl);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void base64_encode(const uint8_t *data, size_t len, char *enc, char pad)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static const char tab[] =
 | 
					 | 
				
			||||||
	    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
					 | 
				
			||||||
	size_t i;
 | 
					 | 
				
			||||||
	for (i = 0; i < len; i += 3) {
 | 
					 | 
				
			||||||
		uint32_t v;
 | 
					 | 
				
			||||||
		v  =              data[i+0]      << 16;
 | 
					 | 
				
			||||||
		v |= (i+1 < len ? data[i+1] : 0) << 8;
 | 
					 | 
				
			||||||
		v |= (i+2 < len ? data[i+2] : 0);
 | 
					 | 
				
			||||||
		*enc++ =             tab[(v >> (3*6)) & 0x3f];
 | 
					 | 
				
			||||||
		*enc++ =             tab[(v >> (2*6)) & 0x3f];
 | 
					 | 
				
			||||||
		*enc++ = i+1 < len ? tab[(v >> (1*6)) & 0x3f] : pad;
 | 
					 | 
				
			||||||
		*enc++ = i+2 < len ? tab[(v >> (0*6)) & 0x3f] : pad;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*enc = '\0';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static size_t base64_decode(const char *data, size_t len, uint8_t *dec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	uint8_t tab[] = {
 | 
					 | 
				
			||||||
		62, -1, -1, -1, 63, 52, 53, 54, 55, 56,
 | 
					 | 
				
			||||||
		57, 58, 59, 60, 61, -1, -1, -1, -1, -1,
 | 
					 | 
				
			||||||
		-1, -1,  0,  1,  2,  3,  4,  5,  6,  7,
 | 
					 | 
				
			||||||
		 8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
 | 
					 | 
				
			||||||
		18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
 | 
					 | 
				
			||||||
		-1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
 | 
					 | 
				
			||||||
		32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
 | 
					 | 
				
			||||||
		42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };
 | 
					 | 
				
			||||||
	size_t i, j;
 | 
					 | 
				
			||||||
	for (i = 0, j = 0; i < len; i += 4) {
 | 
					 | 
				
			||||||
		uint32_t v;
 | 
					 | 
				
			||||||
		v =                          tab[data[i+0]-43]  << (3*6);
 | 
					 | 
				
			||||||
		v |=                         tab[data[i+1]-43]  << (2*6);
 | 
					 | 
				
			||||||
		v |= (data[i+2] == '=' ? 0 : tab[data[i+2]-43]) << (1*6);
 | 
					 | 
				
			||||||
		v |= (data[i+3] == '=' ? 0 : tab[data[i+3]-43]);
 | 
					 | 
				
			||||||
		                      dec[j++] = (v >> 16) & 0xff;
 | 
					 | 
				
			||||||
		if (data[i+2] != '=') dec[j++] = (v >> 8)  & 0xff;
 | 
					 | 
				
			||||||
		if (data[i+3] != '=') dec[j++] =  v        & 0xff;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return j;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int rsa_encrypt(uint8_t *data, int len, uint8_t *res)
 | 
					static int rsa_encrypt(uint8_t *data, int len, uint8_t *res)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RSA *rsa;
 | 
						RSA *rsa;
 | 
				
			||||||
| 
						 | 
					@ -1100,8 +1166,6 @@ static int rtsp_do_announce(struct impl *impl)
 | 
				
			||||||
		    pw_getrandom(impl->iv, sizeof(impl->iv), 0) < 0)
 | 
							    pw_getrandom(impl->iv, sizeof(impl->iv), 0) < 0)
 | 
				
			||||||
			return -errno;
 | 
								return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AES_set_encrypt_key(impl->key, 128, &impl->aes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		i = rsa_encrypt(impl->key, 16, rsakey);
 | 
							i = rsa_encrypt(impl->key, 16, rsakey);
 | 
				
			||||||
	        base64_encode(rsakey, i, key, '=');
 | 
						        base64_encode(rsakey, i, key, '=');
 | 
				
			||||||
	        base64_encode(impl->iv, 16, iv, '=');
 | 
						        base64_encode(impl->iv, 16, iv, '=');
 | 
				
			||||||
| 
						 | 
					@ -1122,8 +1186,7 @@ static int rtsp_do_announce(struct impl *impl)
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return -ENOTSUP;
 | 
							return -ENOTSUP;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	res = pw_rtsp_client_send(impl->rtsp, "ANNOUNCE", &impl->headers->dict,
 | 
						res = rtsp_send(impl, "ANNOUNCE", "application/sdp", sdp, rtsp_announce_reply);
 | 
				
			||||||
			"application/sdp", sdp, rtsp_announce_reply, impl);
 | 
					 | 
				
			||||||
	free(sdp);
 | 
						free(sdp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
| 
						 | 
					@ -1150,24 +1213,6 @@ static int rtsp_do_auth_setup(struct impl *impl)
 | 
				
			||||||
				       rtsp_auth_setup_reply, impl);
 | 
									       rtsp_auth_setup_reply, impl);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *find_attr(char **tokens, const char *key)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	char *p, *s;
 | 
					 | 
				
			||||||
	for (i = 0; tokens[i]; i++) {
 | 
					 | 
				
			||||||
		if (!spa_strstartswith(tokens[i], key))
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		p = tokens[i] + strlen(key);
 | 
					 | 
				
			||||||
		if ((s = rindex(p, '"')) == NULL)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		*s = '\0';
 | 
					 | 
				
			||||||
		if ((s = index(p, '"')) == NULL)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		return s+1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int rtsp_auth_reply(void *data, int status, const struct spa_dict *headers)
 | 
					static int rtsp_auth_reply(void *data, int status, const struct spa_dict *headers)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = data;
 | 
						struct impl *impl = data;
 | 
				
			||||||
| 
						 | 
					@ -1186,37 +1231,37 @@ static int rtsp_auth_reply(void *data, int status, const struct spa_dict *header
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_PRINTF_FUNC(2,3)
 | 
					static const char *find_attr(char **tokens, const char *key)
 | 
				
			||||||
static int MD5_hash(char hash[MD5_HASH_LENGTH+1], const char *fmt, ...)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned char d[MD5_DIGEST_LENGTH];
 | 
					 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	va_list args;
 | 
						char *p, *s;
 | 
				
			||||||
	char buffer[1024];
 | 
						for (i = 0; tokens[i]; i++) {
 | 
				
			||||||
 | 
							if (!spa_strstartswith(tokens[i], key))
 | 
				
			||||||
	va_start(args, fmt);
 | 
								continue;
 | 
				
			||||||
	vsnprintf(buffer, sizeof(buffer), fmt, args);
 | 
							p = tokens[i] + strlen(key);
 | 
				
			||||||
	va_end(args);
 | 
							if ((s = rindex(p, '"')) == NULL)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
	MD5((unsigned char*) buffer, strlen(buffer), d);
 | 
							*s = '\0';
 | 
				
			||||||
	for (i = 0; i < MD5_DIGEST_LENGTH; i++)
 | 
							if ((s = index(p, '"')) == NULL)
 | 
				
			||||||
		sprintf(&hash[2*i], "%02x", (uint8_t) d[i]);
 | 
								continue;
 | 
				
			||||||
	hash[MD5_HASH_LENGTH] = '\0';
 | 
							return s+1;
 | 
				
			||||||
	return 0;
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rtsp_do_auth(struct impl *impl, const struct spa_dict *headers)
 | 
					static int rtsp_do_auth(struct impl *impl, const struct spa_dict *headers)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *str;
 | 
						const char *str, *realm, *nonce;
 | 
				
			||||||
	char **tokens;
 | 
						char **tokens;
 | 
				
			||||||
	int n_tokens;
 | 
						int n_tokens;
 | 
				
			||||||
	char auth[1024];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (impl->password == NULL)
 | 
					 | 
				
			||||||
		return -ENOTSUP;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((str = spa_dict_lookup(headers, "WWW-Authenticate")) == NULL)
 | 
						if ((str = spa_dict_lookup(headers, "WWW-Authenticate")) == NULL)
 | 
				
			||||||
		return -ENOENT;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (impl->password == NULL) {
 | 
				
			||||||
 | 
							pw_log_warn("authentication required but no raop.password property was given");
 | 
				
			||||||
 | 
							return -ENOTSUP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("Auth: %s", str);
 | 
						pw_log_info("Auth: %s", str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1224,45 +1269,23 @@ static int rtsp_do_auth(struct impl *impl, const struct spa_dict *headers)
 | 
				
			||||||
	if (tokens == NULL || tokens[0] == NULL)
 | 
						if (tokens == NULL || tokens[0] == NULL)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spa_streq(tokens[0], "Basic")) {
 | 
						impl->auth_method = strdup(tokens[0]);
 | 
				
			||||||
		char buf[256];
 | 
					 | 
				
			||||||
		char enc[512];
 | 
					 | 
				
			||||||
		spa_scnprintf(buf, sizeof(buf), "%s:%s", DEFAULT_USER_NAME, impl->password);
 | 
					 | 
				
			||||||
		base64_encode((uint8_t*)buf, strlen(buf), enc, '=');
 | 
					 | 
				
			||||||
		spa_scnprintf(auth, sizeof(auth), "Basic %s", enc);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else if (spa_streq(tokens[0], "Digest")) {
 | 
					 | 
				
			||||||
		const char *realm, *nonce, *url;
 | 
					 | 
				
			||||||
		char h1[MD5_HASH_LENGTH+1];
 | 
					 | 
				
			||||||
		char h2[MD5_HASH_LENGTH+1];
 | 
					 | 
				
			||||||
		char resp[MD5_HASH_LENGTH+1];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spa_streq(impl->auth_method, "Digest")) {
 | 
				
			||||||
		realm = find_attr(tokens, "realm");
 | 
							realm = find_attr(tokens, "realm");
 | 
				
			||||||
		nonce = find_attr(tokens, "nonce");
 | 
							nonce = find_attr(tokens, "nonce");
 | 
				
			||||||
		if (realm == NULL || nonce == NULL)
 | 
							if (realm == NULL || nonce == NULL)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		url = pw_rtsp_client_get_url(impl->rtsp);
 | 
							impl->realm = strdup(realm);
 | 
				
			||||||
 | 
							impl->nonce = strdup(nonce);
 | 
				
			||||||
		MD5_hash(h1, "%s:%s:%s", DEFAULT_USER_NAME, realm, impl->password);
 | 
					 | 
				
			||||||
		MD5_hash(h2, "OPTIONS:%s", url);
 | 
					 | 
				
			||||||
		MD5_hash(resp, "%s:%s:%s", h1, nonce, h2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		spa_scnprintf(auth, sizeof(auth),
 | 
					 | 
				
			||||||
				"username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
 | 
					 | 
				
			||||||
				DEFAULT_USER_NAME, realm, nonce, url, resp);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		goto error;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_properties_setf(impl->headers, "Authorization", "%s %s",
 | 
					 | 
				
			||||||
			tokens[0], auth);
 | 
					 | 
				
			||||||
	pw_free_strv(tokens);
 | 
						pw_free_strv(tokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_rtsp_client_send(impl->rtsp, "OPTIONS", &impl->headers->dict,
 | 
						rtsp_send(impl, "OPTIONS", NULL, NULL, rtsp_auth_reply);
 | 
				
			||||||
			NULL, NULL, rtsp_auth_reply, impl);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	pw_free_strv(tokens);
 | 
						pw_free_strv(tokens);
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -1345,6 +1368,12 @@ static void connection_cleanup(struct impl *impl)
 | 
				
			||||||
		close(impl->timing_fd);
 | 
							close(impl->timing_fd);
 | 
				
			||||||
		impl->timing_fd = -1;
 | 
							impl->timing_fd = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						free(impl->auth_method);
 | 
				
			||||||
 | 
						impl->auth_method = NULL;
 | 
				
			||||||
 | 
						free(impl->realm);
 | 
				
			||||||
 | 
						impl->realm = NULL;
 | 
				
			||||||
 | 
						free(impl->nonce);
 | 
				
			||||||
 | 
						impl->nonce = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rtsp_disconnected(void *data)
 | 
					static void rtsp_disconnected(void *data)
 | 
				
			||||||
| 
						 | 
					@ -1690,7 +1719,12 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
				
			||||||
	impl->server_fd = -1;
 | 
						impl->server_fd = -1;
 | 
				
			||||||
	impl->control_fd = -1;
 | 
						impl->control_fd = -1;
 | 
				
			||||||
	impl->timing_fd = -1;
 | 
						impl->timing_fd = -1;
 | 
				
			||||||
 | 
						impl->ctx = EVP_CIPHER_CTX_new();
 | 
				
			||||||
 | 
						if (impl->ctx == NULL) {
 | 
				
			||||||
 | 
							res = -errno;
 | 
				
			||||||
 | 
							pw_log_error( "can't create cipher context: %m");
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (args == NULL)
 | 
						if (args == NULL)
 | 
				
			||||||
		args = "";
 | 
							args = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue