From patchwork Mon Sep 9 15:48:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Boxer X-Patchwork-Id: 14986 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id EAA5444A26B for ; Mon, 9 Sep 2019 18:56:17 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id C8A94687F56; Mon, 9 Sep 2019 18:56:17 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f176.google.com (mail-lj1-f176.google.com [209.85.208.176]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id AEB796802AB for ; Mon, 9 Sep 2019 18:56:11 +0300 (EEST) Received: by mail-lj1-f176.google.com with SMTP id q22so8710486ljj.2 for ; Mon, 09 Sep 2019 08:56:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=1Sxl5+3GdIA6S24cqREXA6Ri4xdi2VokIGBCxh2W3Q0=; b=k2TqJq4liylI1xfK3LTQei3nBn98UVBgAw1p+8XIEy6s96DWThmjswHUaD2AC9a3Qy jgiJJQpooKjoW4jaMFNQMdU1vNjb9C9+ZKAzhsu4BPUKCh+2+KvqGwUE4P8jJ5F6HyOQ umReksm81n9bU4yQhVULaQykNGWAfhHAVkwHNrA2N4Qv1UQCWA+mhl+FNLuOLYFLWOe/ xFzW5fjulzGrF1pxZVrQj6aP6Y3s1btqji4OlETPFEq1Y/tucrezjQBz/j+xUvDkzrox /Jv1MeebIkY+q/hDT8K/HOUquQSLOvxhBOVxw0X6AUdsnMSYg8onJQRGQMx8YjfXTk8R fHhw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=1Sxl5+3GdIA6S24cqREXA6Ri4xdi2VokIGBCxh2W3Q0=; b=ZE5RFk0A3PC7fz5xPWLDF0whLnatJX/LLy5NPi1/f0BripPIDep8M20ooZD/AIoJVA nlkhdqJUkMRqOpx8M+65w/s5Zd5yvU1atO3Su3S8hfDJSUC5oYgbZgneygI0EbWgcGu5 Vwf+r4qBp6I+xGFhixjRSIJVZEpDh0vaT47OqxJ/DRUEBBievypy64Xqq3jBA6qzu126 kxNAOcdYaQutRLriHvYhsoVC0bQJJe5IlL7qGlS8saKfdFEJsxnGdvAJO/7y7njUo+mW tLwrxfGTZC8zhcLTxuENtSFN8wa8ZECmDOQM2dqwMqTn7SqCAG0EzCnS4P69uUh1HZtq j6CA== X-Gm-Message-State: APjAAAWncZ48TD0Y73fWNa06YktbSm1I8ZlQerywdH0mAJbvtxm2kKC4 dWMLhF4URRaeaaEqyr3k2uL7k/LXabz277bI+4mdyWMWet4= X-Google-Smtp-Source: APXvYqyijY7SJO484NVg7K6GTccPe9ZGEttCMDlS8+QQfBinw1OrRdsIWVr2E4HatcFxZzUDG2V6fjlaUqWcfOK7igM= X-Received: by 2002:a2e:93d7:: with SMTP id p23mr17031172ljh.100.1568044147785; Mon, 09 Sep 2019 08:49:07 -0700 (PDT) MIME-Version: 1.0 From: Aaron Boxer Date: Mon, 9 Sep 2019 11:48:56 -0400 Message-ID: To: FFmpeg development discussions and patches X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: [FFmpeg-devel] [PATCH] libsrt: add password ACL support using new streamID specification X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Hello! SRT has added a new stream ID specification allowing extraction of various fields from the user password. This patch adds support for using an ACL to check user credentials - base on this Haivision sample code: https://github.com/Haivision/srt/blob/master/testing/srt-test-live.cpp Thanks, Aaron From 8a11e0d673872049b8260cb08f3c7cb40f9a1297 Mon Sep 17 00:00:00 2001 From: Aaron Boxer Date: Wed, 14 Aug 2019 08:26:17 -0400 Subject: [PATCH] libsrt: support streamid spec --- libavformat/libsrt.c | 135 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/libavformat/libsrt.c b/libavformat/libsrt.c index b5568089fa..d597e5fce4 100644 --- a/libavformat/libsrt.c +++ b/libavformat/libsrt.c @@ -34,6 +34,9 @@ #include "os_support.h" #include "url.h" + +static srt_listen_callback_fn libsrt_listen_callback; + /* This is for MPEG-TS and it's a default SRTO_PAYLOADSIZE for SRTT_LIVE (8 TS packets) */ #ifndef SRT_LIVE_DEFAULT_PAYLOAD_SIZE #define SRT_LIVE_DEFAULT_PAYLOAD_SIZE 1316 @@ -62,6 +65,7 @@ typedef struct SRTContext { int64_t maxbw; int pbkeylen; char *passphrase; + char* user_passphrase_list; int mss; int ffs; int ipttl; @@ -101,6 +105,7 @@ static const AVOption libsrt_options[] = { { "maxbw", "Maximum bandwidth (bytes per second) that the connection can use", OFFSET(maxbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "pbkeylen", "Crypto key len in bytes {16,24,32} Default: 16 (128-bit)", OFFSET(pbkeylen), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32, .flags = D|E }, { "passphrase", "Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto", OFFSET(passphrase), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, + { "user_passphrase_list", "Comma separated list users and passphrases, of form usrr1=pass1,usr2=pass2,...", OFFSET(user_passphrase_list), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, { "mss", "The Maximum Segment Size", OFFSET(mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1500, .flags = D|E }, { "ffs", "Flight flag size (window size) (in bytes)", OFFSET(ffs), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "ipttl", "IP Time To Live", OFFSET(ipttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E }, @@ -196,10 +201,134 @@ static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int fd, int wr } } +typedef struct _libsrt_parsed_param { + char *key; + char *val; +} libsrt_parsed_param; + + +/** + * Parse a key-value string into an array of key/value structs. + * + * The key-value string should be a null terminated string of parameters separated + * by a delimiter. Each parameter are checked for the equal sign character. + * If the equal sign character appears in the parameter, it will be used as a null terminator + * and the part that comes after it will be the value of the parameter. + * + * + * param: keyvalue: the key-value string to parse. The string will be modified. + * param: delimiter: the character that separates the key/value pairs + * from each other. + * param: params: an array of parsed_param structs to hold the result. + * param: max_params: maximum number of parameters to parse. + * + * Return: the number of parsed items. -1 if there was an error. + */ +static int libsrt_parse_key_value(char *keyvalue, const char* delimiter, + libsrt_parsed_param *params, int max_params) +{ + int i = 0; + char *token = NULL; + + if (!keyvalue || *keyvalue == '\0') + return -1; + if (!params || max_params == 0) + return 0; + + token = strtok( keyvalue, delimiter ); + while (token != NULL && i < max_params) { + params[i].key = token; + params[i].val = NULL; + if ((params[i].val = strchr( params[i].key, '=' )) != NULL) { + size_t val_len = strlen( params[i].val ); + /* make key into a zero-delimited string */ + *(params[i].val) = '\0'; + /* make sure val is not empty */ + if (val_len > 1) { + params[i].val++; + /* make sure key is not empty */ + if (params[i].key[0]) + i++; + }; + } + token = strtok( NULL, delimiter ); + } + + return i; +} + +/* callback to parse streamid */ +static int libsrt_listen_callback(void* opaq, SRTSOCKET ns, int hsversion, const struct sockaddr* peeraddr, const char* streamid) +{ + const char* username = NULL; + const char* expected_passphrase = NULL; + static const char stdhdr [] = "#!::"; + uint32_t* pattern = (uint32_t*)stdhdr; + uint8_t found = 0; + libsrt_parsed_param key_values[256]; + URLContext *h = (URLContext*)opaq; + int num_key_values; + int i; + + if (hsversion != 5) { + av_log(h, AV_LOG_ERROR,"ERROR: hsversion expected 5\n"); + return -1; + } + if (!peeraddr) { + av_log(h, AV_LOG_ERROR,"ERROR: null peeraddr\n"); + return -1; + } + + /* Try the "standard interpretation" with username at key 'u' */ + if (strlen(streamid) > 4 && *(uint32_t*)streamid == *pattern){ + num_key_values = libsrt_parse_key_value((char*)(streamid-4), ",", key_values, sizeof(key_values)); + if (num_key_values == -1) { + av_log(h, AV_LOG_ERROR,"ERROR: null streamid \n"); + return -1; + } + for (int i = 0; i < num_key_values; ++i){ + if (key_values[i].key && strcmp(key_values[i].key,"u")== 0){ + username = key_values[i].val; + found = 1; + } + } + if (!found) { + av_log(h, AV_LOG_ERROR,"User not found, returning false.\n"); + return -1; + } + } + else { + /* By default the username is the whole streamid */ + username = streamid; + } + + num_key_values = libsrt_parse_key_value(( (SRTContext*)h->priv_data)->user_passphrase_list, ",", key_values, sizeof(key_values)); + for (i = 0; i < num_key_values; ++i){ + if (key_values[i].key && strcmp(key_values[i].key, username) == 0){ + expected_passphrase = key_values[i].val; + break; + } + } + if (!expected_passphrase) { + av_log(h, AV_LOG_ERROR,"Cannot find password for user '%s'\n", username ); + return -1; + } + + av_log(h, AV_LOG_INFO,"Setting password '%s' for user '%s'\n", expected_passphrase, username ); + if (srt_setsockflag(ns, SRTO_PASSPHRASE, expected_passphrase, strlen(expected_passphrase))){ + av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_PASSPHRASE) failed\n"); + } + + return 0; + +} + static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int timeout) { int ret; int reuse = 1; + SRTContext *c = h->priv_data; + if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) { av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_REUSEADDR) failed\n"); } @@ -210,6 +339,9 @@ static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t ret = srt_listen(fd, 1); if (ret) return libsrt_neterrno(h); + /* add callback if there is a user passphrase list */ + if (c->user_passphrase_list) + (void)srt_listen_callback(fd, &libsrt_listen_callback, h); while ((ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback))) { switch (ret) { @@ -495,6 +627,9 @@ static int libsrt_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "passphrase", p)) { s->passphrase = av_strndup(buf, strlen(buf)); } + if (av_find_info_tag(buf, sizeof(buf), "user_passphrase_list", p)) { + s->user_passphrase_list = av_strndup(buf, strlen(buf)); + } if (av_find_info_tag(buf, sizeof(buf), "mss", p)) { s->mss = strtol(buf, NULL, 10); } -- 2.20.1