aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat/rtmpproto.c
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2012-12-31 00:46:14 +0200
committerMartin Storsjö <martin@martin.st>2012-12-31 13:39:09 +0200
commitc1ea44c54d837a69d8285601cfba7aa8df16e053 (patch)
tree37f82dc8697962a5e5cda5b3962d1560c328f075 /libavformat/rtmpproto.c
parent08225d01262b638e1c4c86679a1375e02123fd4d (diff)
downloadffmpeg-c1ea44c54d837a69d8285601cfba7aa8df16e053.tar.gz
rtmp: Add support for limelight authentication
Limelight is a not too uncommon CDN. The authentication scheme is pretty similar to the adobe authentication, but is even closer to normal http digest authentication (but not close enough to warrant sharing code) than the adobe version. Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat/rtmpproto.c')
-rw-r--r--libavformat/rtmpproto.c81
1 files changed, 75 insertions, 6 deletions
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 1ffa748b25..f25a79b0e3 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -1561,19 +1561,81 @@ static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
return 0;
}
+static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
+{
+ uint8_t hash[16];
+ char hashstr1[33], hashstr2[33];
+ const char *realm = "live";
+ const char *method = "publish";
+ const char *qop = "auth";
+ const char *nc = "00000001";
+ char cnonce[10];
+ struct AVMD5 *md5 = av_md5_alloc();
+ if (!md5)
+ return AVERROR(ENOMEM);
+
+ snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
+
+ av_md5_init(md5);
+ av_md5_update(md5, user, strlen(user));
+ av_md5_update(md5, ":", 1);
+ av_md5_update(md5, realm, strlen(realm));
+ av_md5_update(md5, ":", 1);
+ av_md5_update(md5, rt->password, strlen(rt->password));
+ av_md5_final(md5, hash);
+ ff_data_to_hex(hashstr1, hash, 16, 1);
+ hashstr1[32] = '\0';
+
+ av_md5_init(md5);
+ av_md5_update(md5, method, strlen(method));
+ av_md5_update(md5, ":/", 2);
+ av_md5_update(md5, rt->app, strlen(rt->app));
+ av_md5_final(md5, hash);
+ ff_data_to_hex(hashstr2, hash, 16, 1);
+ hashstr2[32] = '\0';
+
+ av_md5_init(md5);
+ av_md5_update(md5, hashstr1, strlen(hashstr1));
+ av_md5_update(md5, ":", 1);
+ if (nonce)
+ av_md5_update(md5, nonce, strlen(nonce));
+ av_md5_update(md5, ":", 1);
+ av_md5_update(md5, nc, strlen(nc));
+ av_md5_update(md5, ":", 1);
+ av_md5_update(md5, cnonce, strlen(cnonce));
+ av_md5_update(md5, ":", 1);
+ av_md5_update(md5, qop, strlen(qop));
+ av_md5_update(md5, ":", 1);
+ av_md5_update(md5, hashstr2, strlen(hashstr2));
+ av_md5_final(md5, hash);
+ ff_data_to_hex(hashstr1, hash, 16, 1);
+
+ snprintf(rt->auth_params, sizeof(rt->auth_params),
+ "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
+ "llnw", user, nonce, cnonce, nc, hashstr1);
+
+ av_free(md5);
+ return 0;
+}
+
static int handle_connect_error(URLContext *s, const char *desc)
{
RTMPContext *rt = s->priv_data;
- char buf[300], *ptr;
+ char buf[300], *ptr, authmod[15];
int i = 0, ret = 0;
const char *user = "", *salt = "", *opaque = NULL,
- *challenge = NULL, *cptr = NULL;
+ *challenge = NULL, *cptr = NULL, *nonce = NULL;
- if (!(cptr = strstr(desc, "authmod=adobe"))) {
+ if (!(cptr = strstr(desc, "authmod=adobe")) &&
+ !(cptr = strstr(desc, "authmod=llnw"))) {
av_log(s, AV_LOG_ERROR,
"Unknown connect error (unsupported authentication method?)\n");
return AVERROR_UNKNOWN;
}
+ cptr += strlen("authmod=");
+ while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
+ authmod[i++] = *cptr++;
+ authmod[i] = '\0';
if (!rt->username[0] || !rt->password[0]) {
av_log(s, AV_LOG_ERROR, "No credentials set\n");
@@ -1597,7 +1659,7 @@ static int handle_connect_error(URLContext *s, const char *desc)
if (strstr(desc, "code=403 need auth")) {
snprintf(rt->auth_params, sizeof(rt->auth_params),
- "?authmod=%s&user=%s", "adobe", rt->username);
+ "?authmod=%s&user=%s", authmod, rt->username);
return 0;
}
@@ -1624,12 +1686,19 @@ static int handle_connect_error(URLContext *s, const char *desc)
opaque = value;
} else if (!strcmp(ptr, "challenge")) {
challenge = value;
+ } else if (!strcmp(ptr, "nonce")) {
+ nonce = value;
}
ptr = next;
}
- if ((ret = do_adobe_auth(rt, user, salt, challenge, opaque)) < 0)
- return ret;
+ if (!strcmp(authmod, "adobe")) {
+ if ((ret = do_adobe_auth(rt, user, salt, challenge, opaque)) < 0)
+ return ret;
+ } else {
+ if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
+ return ret;
+ }
rt->auth_tried = 1;
return 0;