mirror of
https://github.com/coturn/coturn.git
synced 2026-05-05 10:46:10 +02:00
Imported Upstream version 4.2.1.2
This commit is contained in:
parent
f746731b8d
commit
5736eb2811
4
AUTHORS
4
AUTHORS
@ -47,3 +47,7 @@ Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
|
||||
Federico Pinna <fpinna@vivocha.com>
|
||||
MongoDB support
|
||||
(since v4.1.0.1)
|
||||
|
||||
Bradley T. Hughes <bradleythughes@fastmail.fm>
|
||||
FreeBSD port
|
||||
(since v4.1.2.1)
|
||||
|
||||
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
||||
10/05/2014 Oleg Moskalenko <mom040267@gmail.com>
|
||||
Version 4.2.1.2 'Monza':
|
||||
- oAuth security experimental implementation;
|
||||
- The "TLS renegotiation" DoS attack prevention implemented;
|
||||
- FQDN as relay-ip and listener-ip parameters (issue 6)
|
||||
(patch provided by Iñaki Baz Castillo);
|
||||
- redis user key operation fixed.
|
||||
- redis, mysql and psql db operations fixed.
|
||||
- SHA-256 memory leak fixed.
|
||||
- Mobility ticket retransmission fixed.
|
||||
- Move debian package from SVN to GIT.
|
||||
- Move secondary download area to coturn.net.
|
||||
- Quota allocation fixed.
|
||||
- Core dump fixed.
|
||||
- Bandwidth allocation fixed.
|
||||
- Memory code clening.
|
||||
- Logging fixed.
|
||||
|
||||
08/14/2014 Oleg Moskalenko <mom040267@gmail.com>
|
||||
Version 4.1.2.1 'Vitari':
|
||||
- The origin attribute is verified in the subsequent
|
||||
|
||||
72
INSTALL
72
INSTALL
@ -706,6 +706,15 @@ CREATE TABLE turnusers_lt (
|
||||
PRIMARY KEY (realm,name)
|
||||
);
|
||||
|
||||
The field hmackey contains HEX string representation of the key.
|
||||
We do not store the user open passwords for long-term credentials, for security reasons.
|
||||
Storing only the HMAC key has its own implications - if you change the realm,
|
||||
you will have to update the HMAC keys of all users, because the realm is
|
||||
used for the HMAC key generation.
|
||||
|
||||
The key must be 32 characters (HEX representation of 16 bytes) for SHA1,
|
||||
or 64 characters (HEX representation of 32 bytes) for SHA256.
|
||||
|
||||
# Table for short-term credentials mechanism authorisation:
|
||||
#
|
||||
CREATE TABLE turnusers_st (
|
||||
@ -760,14 +769,56 @@ CREATE TABLE turn_realm_option (
|
||||
primary key (realm,opt)
|
||||
);
|
||||
|
||||
The field hmackey contains HEX string representation of the key.
|
||||
We do not store the user open passwords for long-term credentials, for security reasons.
|
||||
Storing only the HMAC key has its own implications - if you change the realm,
|
||||
you will have to update the HMAC keys of all users, because the realm is
|
||||
used for the HMAC key generation.
|
||||
# oAuth key storage table.
|
||||
#
|
||||
CREATE TABLE oauth_key (
|
||||
kid varchar(128), /*
|
||||
ikm_key varchar(256) default '',
|
||||
timestamp bigint default 0,
|
||||
lifetime integer default 0,
|
||||
hkdf_hash_func varchar(64) default '',
|
||||
as_rs_alg varchar(64) default '',
|
||||
as_rs_key varchar(256) default '',
|
||||
auth_alg varchar(64) default '',
|
||||
auth_key varchar(256) default '',
|
||||
primary key (kid)
|
||||
);
|
||||
|
||||
The key must be 32 characters (HEX representation of 16 bytes) for SHA1,
|
||||
or 64 characters (HEX representation of 32 bytes) for SHA256.
|
||||
The oauth_key table fields meanings are:
|
||||
|
||||
kid: the kid of the key;
|
||||
|
||||
ikm_key - (optional) base64-encoded key ("input keying material");
|
||||
The ikm_key is not needed if the as_rs_key and auth_key are defined
|
||||
explicitly in the database;
|
||||
|
||||
timestamp - (optional) the timestamp (in seconds) when the key
|
||||
lifetime started;
|
||||
|
||||
lifetime - (optional) the key lifetime in seconds; the default value
|
||||
is 0 - unlimited lifetime.
|
||||
|
||||
hkdf_hash_func - (optional) hash function for HKDF procedure; the
|
||||
valid values are SHA-1 and SHA-256, with SHA-256 as default;
|
||||
The hkdf_hash_func is not needed if the as_rs_key and auth_key
|
||||
are defined explicitly in the database;
|
||||
|
||||
as_rs_alg - oAuth token encryption algorithm; the valid values are
|
||||
"AES-128-CBC" and "AES-256-CBC", , "AEAD-AES-128-GCM",
|
||||
"AEAD-AES-256-GCM".
|
||||
The default value is "AES-256-CBC";
|
||||
|
||||
as_rs_key - (optional) base64-encoded AS-RS key. If not defined, then
|
||||
calculated with ikm_key and hkdf_hash_func. The as_rs_key length
|
||||
is defined by as_rs_alg.
|
||||
|
||||
auth_alg - (optional) oAuth token authentication algorithm; the valid values are
|
||||
"HMAC-SHA-256-128", "HMAC-SHA-256" and "HMAC-SHA-1".
|
||||
The default value is "HMAC-SHA-256-128".
|
||||
|
||||
auth_key - (optional) base64-encoded AUTH key. If not defined, then
|
||||
calculated with ikm_key and hkdf_hash_func. The auth_key length
|
||||
is defined by auth_alg.
|
||||
|
||||
You can use turnadmin program to manage the database - you can either use
|
||||
turnadmin to add/modify/delete users, or you can use turnadmin to produce
|
||||
@ -930,6 +981,11 @@ Or in the turnserver.conf file:
|
||||
|
||||
mongo-userdb="mongodb://localhost:27017/turndb"
|
||||
|
||||
The meanings of the MongoDB keys are the same as for the other databases, see the
|
||||
explanations for the Postgres, for example.
|
||||
|
||||
See the file testmongosetup.sh for the database structure examples.
|
||||
|
||||
XVII. Redis setup
|
||||
|
||||
The Redis setup is well documented on their site http://redis.io.
|
||||
@ -998,6 +1054,8 @@ Redis TURN admin commands:
|
||||
|
||||
$ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u gorst -r north.gov -p hero
|
||||
$ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic
|
||||
|
||||
See the file testredisdbsetup.sh for the data structure examples.
|
||||
|
||||
XVIII. Performance tuning
|
||||
|
||||
|
||||
@ -241,3 +241,5 @@ to see the man page.
|
||||
Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
|
||||
|
||||
Federico Pinna <fpinna@vivocha.com>
|
||||
|
||||
Bradley T. Hughes <bradleythughes@fastmail.fm>
|
||||
|
||||
@ -190,6 +190,8 @@ Flags:
|
||||
This option can be used with long-term credentials mechanisms only -
|
||||
it does not make much sense with the short-term mechanism.
|
||||
|
||||
--oauth Support oAuth authentication, as in the third-party TURN specs document.
|
||||
|
||||
--dh566 Use 566 bits predefined DH TLS key. Default size of the key is 1066.
|
||||
|
||||
--dh2066 Use 2066 bits predefined DH TLS key. Default size of the key is 1066.
|
||||
@ -420,6 +422,10 @@ Options with required values:
|
||||
value can be changed on-the-fly by a separate program, so this is why
|
||||
that other mode is dynamic. Multiple shared secrets can be used
|
||||
(both in the database and in the "static" fashion).
|
||||
|
||||
--server-name Server name used for
|
||||
the oAuth authentication purposes.
|
||||
The default value is the realm name.
|
||||
|
||||
--cert Certificate file, PEM format. Same file
|
||||
search rules applied as for the configuration
|
||||
@ -928,3 +934,5 @@ https://groups.google.com/forum/?fromgroups=#!forum/turn-server-project-rfc5766-
|
||||
Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
|
||||
|
||||
Federico Pinna <fpinna@vivocha.com>
|
||||
|
||||
Bradley T. Hughes <bradleythughes@fastmail.fm>
|
||||
|
||||
@ -117,6 +117,8 @@ Flags:
|
||||
|
||||
-Z Dual allocation (SSODA draft support).
|
||||
|
||||
-J Use oAuth with default test key kid='north'.
|
||||
|
||||
Options with required values:
|
||||
|
||||
-l Message length (Default: 100 Bytes).
|
||||
@ -337,3 +339,5 @@ SEE ALSO
|
||||
Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
|
||||
|
||||
Federico Pinna <fpinna@vivocha.com>
|
||||
|
||||
Bradley T. Hughes <bradleythughes@fastmail.fm>
|
||||
|
||||
2
STATUS
2
STATUS
@ -104,6 +104,8 @@ compatibility.
|
||||
44) Double (dual) allocation added (SSODA draft).
|
||||
|
||||
45) Secure MySQL connection implemented.
|
||||
|
||||
46) Third-party security mechanism (through oAuth) implemented.
|
||||
|
||||
Things to be implemented in future (the development roadmap)
|
||||
are described in the TODO file.
|
||||
|
||||
13
TODO
13
TODO
@ -47,7 +47,6 @@
|
||||
|
||||
==================================================================
|
||||
|
||||
1) New security oAuth draft.
|
||||
|
||||
==================================================================
|
||||
|
||||
@ -57,13 +56,13 @@
|
||||
|
||||
1) For extra difficult NAT/FWs, consider implementing Websockets.
|
||||
|
||||
2) MS TURN, MS STUN extensions.
|
||||
2) ALPN with TLS and DTLS (when OpenSSL 1.0.2 is available).
|
||||
|
||||
3) ALPN with TLS and DTLS (when OpenSSL 1.0.2 is available).
|
||||
3) Redirect draft.
|
||||
|
||||
4) Redirect draft.
|
||||
4) DTLS 1.2 (when available).
|
||||
|
||||
5) DTLS 1.2 (when available).
|
||||
5) TURN Proxy ? http://tools.ietf.org/html/draft-schwartz-rtcweb-return-00
|
||||
|
||||
==================================================================
|
||||
|
||||
@ -95,6 +94,10 @@
|
||||
|
||||
4) Ganglia monitoring.
|
||||
|
||||
5) Web API to the database (oAuth keys, for example).
|
||||
|
||||
6) Key exchange mechanism for oAuth.
|
||||
|
||||
==================================================================
|
||||
|
||||
### VIII. CODING STUFF ###
|
||||
|
||||
52
configure
vendored
52
configure
vendored
@ -9,6 +9,8 @@ cleanup() {
|
||||
rm -rf ${TH_TMPCPROGB}
|
||||
rm -rf ${DTLS_TMPCPROGC}
|
||||
rm -rf ${DTLS_TMPCPROGB}
|
||||
rm -rf ${GCM_TMPCPROGC}
|
||||
rm -rf ${GCM_TMPCPROGB}
|
||||
rm -rf ${PQ_TMPCPROGC}
|
||||
rm -rf ${PQ_TMPCPROGB}
|
||||
rm -rf ${MYSQL_TMPCPROGC}
|
||||
@ -237,6 +239,21 @@ dtls_testlib() {
|
||||
fi
|
||||
}
|
||||
|
||||
gcm_testlib() {
|
||||
|
||||
if [ -z "${TURN_NO_GCM}" ] ; then
|
||||
${CC} ${GCM_TMPCPROGC} -o ${GCM_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} 2>>/dev/null
|
||||
ER=$?
|
||||
if [ ${ER} -eq 0 ] ; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
testdaemon() {
|
||||
|
||||
${CC} ${D_TMPCPROGC} -o ${D_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} 2>>/dev/null
|
||||
@ -567,7 +584,7 @@ SYSTEM=`uname`
|
||||
|
||||
if [ "${SYSTEM}" = "SunOS" ] ; then
|
||||
# Solaris ? is this you ?!
|
||||
OSCFLAGS="${OSCFLAGS} -D__EXTENSIONS__ -D_XOPEN_SOURCE=500"
|
||||
OSCFLAGS="${OSCFLAGS} -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 -DTURN_NO_GETDOMAINNAME"
|
||||
fi
|
||||
|
||||
#########################
|
||||
@ -628,6 +645,19 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
!
|
||||
|
||||
GCM_TMPCPROG=__test__ccomp__gcm__$$
|
||||
GCM_TMPCPROGC=${TMPDIR}/${GCM_TMPCPROG}.c
|
||||
GCM_TMPCPROGB=${TMPDIR}/${GCM_TMPCPROG}
|
||||
|
||||
cat > ${GCM_TMPCPROGC} <<!
|
||||
#include <stdlib.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/evp.h>
|
||||
int main(int argc, char** argv) {
|
||||
return (int)EVP_CIPH_GCM_MODE;
|
||||
}
|
||||
!
|
||||
|
||||
D_TMPCPROG=__test__ccomp__daemon__$$
|
||||
D_TMPCPROGC=${TMPDIR}/${D_TMPCPROG}.c
|
||||
D_TMPCPROGB=${TMPDIR}/${D_TMPCPROG}
|
||||
@ -885,6 +915,24 @@ else
|
||||
TURN_NO_DTLS="-DTURN_NO_DTLS"
|
||||
fi
|
||||
|
||||
###########################
|
||||
# Can we use GCM cipher ?
|
||||
###########################
|
||||
|
||||
if [ -z ${TURN_NO_GCM} ] ; then
|
||||
|
||||
gcm_testlib
|
||||
ER=$?
|
||||
if [ ${ER} -eq 0 ] ; then
|
||||
${ECHO_CMD} "WARNING: Cannot find GCM support."
|
||||
${ECHO_CMD} "Turning GCM off."
|
||||
TURN_NO_GCM="-DTURN_NO_GCM"
|
||||
fi
|
||||
|
||||
else
|
||||
TURN_NO_GCM="-DTURN_NO_GCM"
|
||||
fi
|
||||
|
||||
###########################
|
||||
# Test Libevent2 setup
|
||||
###########################
|
||||
@ -1044,7 +1092,7 @@ fi
|
||||
# So, what we have now:
|
||||
###############################
|
||||
|
||||
OSCFLAGS="${OSCFLAGS} ${TURN_NO_THREAD_BARRIERS} ${TURN_NO_DTLS} ${TURN_NO_TLS} -DINSTALL_PREFIX=${PREFIX}"
|
||||
OSCFLAGS="${OSCFLAGS} ${TURN_NO_THREAD_BARRIERS} ${TURN_NO_DTLS} ${TURN_NO_GCM} ${TURN_NO_TLS} -DINSTALL_PREFIX=${PREFIX}"
|
||||
|
||||
if ! [ -z "${TURN_ACCEPT_RPATH}" ] ; then
|
||||
if [ -z "${TURN_DISABLE_RPATH}" ] ; then
|
||||
|
||||
@ -208,7 +208,17 @@
|
||||
# in user database (if present). The database-stored value can be changed on-the-fly
|
||||
# by a separate program, so this is why that other mode is 'dynamic'.
|
||||
#
|
||||
#static-auth-secret
|
||||
#static-auth-secret=north
|
||||
|
||||
# Server name used for
|
||||
# the oAuth authentication purposes.
|
||||
# The default value is the realm name.
|
||||
#
|
||||
#server-name=blackdow.carleon.gov
|
||||
|
||||
# Flag to support oAuth authentication.
|
||||
#
|
||||
#oauth
|
||||
|
||||
# 'Static' user accounts for long term credentials mechanism, only.
|
||||
# This option cannot be used with TURN REST API or with short-term credentials
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
# 8) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
|
||||
# 9) "--log-file=stdout" means that all log output will go to the stdout.
|
||||
# 10) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
|
||||
# 11) --oauth - accept oAuth security dialog
|
||||
# Other parameters (config file name, etc) are default.
|
||||
|
||||
if [ -d examples ] ; then
|
||||
@ -30,4 +31,4 @@ fi
|
||||
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
|
||||
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/
|
||||
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --mongo-userdb="mongodb://localhost/coturn" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --mongo-userdb="mongodb://localhost/coturn" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 --oauth $@
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
# 8) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
|
||||
# 9) "--log-file=stdout" means that all log output will go to the stdout.
|
||||
# 10) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
|
||||
# 11) --oauth - accept oAuth security dialog
|
||||
# Other parameters (config file name, etc) are default.
|
||||
|
||||
if [ -d examples ] ; then
|
||||
@ -31,4 +32,4 @@ fi
|
||||
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --server-name="blackdow.carleon.gov" -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 --oauth $@
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
# 8) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
|
||||
# 9) "--log-file=stdout" means that all log output will go to the stdout.
|
||||
# 10) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
|
||||
# 11) --oauth - accept oAuth security dialog
|
||||
# Other parameters (config file name, etc) are default.
|
||||
|
||||
if [ -d examples ] ; then
|
||||
@ -32,4 +33,4 @@ fi
|
||||
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --mysql-userdb="host=localhost dbname=turn user=turn password=turn cipher=DHE-RSA-AES256-SHA connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --server-name="blackdow.carleon.gov" -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --mysql-userdb="host=localhost dbname=coturn user=turn password=turn cipher=DHE-RSA-AES256-SHA connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 --oauth $@
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
# 8) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
|
||||
# 9) "--log-file=stdout" means that all log output will go to the stdout.
|
||||
# 10) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
|
||||
# 11) --oauth - accept oAuth security dialog
|
||||
# Other parameters (config file name, etc) are default.
|
||||
|
||||
if [ -d examples ] ; then
|
||||
@ -31,7 +32,7 @@ fi
|
||||
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --psql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --server-name="blackdow.carleon.gov" -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --psql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 --oauth $@
|
||||
|
||||
# Newer PostgreSQL style connection string example:
|
||||
# PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --psql-userdb=postgresql://turn:turn@/turn --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@
|
||||
# PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --server-name="blackdow.carleon.gov" -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --psql-userdb=postgresql://turn:turn@/turn --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 --oauth $@
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
# 9) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
|
||||
# 10) "--log-file=stdout" means that all log output will go to the stdout.
|
||||
# 11) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
|
||||
# 12) --oauth - accept oAuth security dialog
|
||||
# Other parameters (config file name, etc) are default.
|
||||
|
||||
if [ -d examples ] ; then
|
||||
@ -34,4 +35,4 @@ fi
|
||||
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
|
||||
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" --redis-statsdb="ip=127.0.0.1 dbname=3 password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@
|
||||
PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --server-name="blackdow.carleon.gov" --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" --redis-statsdb="ip=127.0.0.1 dbname=3 password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 --oauth $@
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.\" Text automatically generated by txt2man
|
||||
.TH TURN 1 "18 August 2014" "" ""
|
||||
.TH TURN 1 "28 September 2014" "" ""
|
||||
.SH GENERAL INFORMATION
|
||||
|
||||
\fIturnadmin\fP is a TURN administration tool. This tool can be used to manage
|
||||
@ -330,3 +330,5 @@ Peter Dunkley <peter.dunkley@crocodilertc.net>
|
||||
Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
|
||||
.PP
|
||||
Federico Pinna <fpinna@vivocha.com>
|
||||
.PP
|
||||
Bradley T. Hughes <bradleythughes@fastmail.fm>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.\" Text automatically generated by txt2man
|
||||
.TH TURN 1 "18 August 2014" "" ""
|
||||
.TH TURN 1 "28 September 2014" "" ""
|
||||
.SH GENERAL INFORMATION
|
||||
|
||||
The \fBTURN Server\fP project contains the source code of a TURN server and TURN client
|
||||
@ -276,6 +276,10 @@ This option can be used with long\-term credentials mechanisms only \-
|
||||
it does not make much sense with the short\-term mechanism.
|
||||
.TP
|
||||
.B
|
||||
\fB\-\-oauth\fP
|
||||
Support oAuth authentication.
|
||||
.TP
|
||||
.B
|
||||
\fB\-\-dh566\fP
|
||||
Use 566 bits predefined DH TLS key. Default size of the key is 1066.
|
||||
.TP
|
||||
@ -612,6 +616,12 @@ that other mode is dynamic. Multiple shared secrets can be used
|
||||
(both in the database and in the "static" fashion).
|
||||
.TP
|
||||
.B
|
||||
\fB\-\-server\-name\fP
|
||||
Server name used for
|
||||
the oAuth authentication purposes.
|
||||
The default value is the realm name.
|
||||
.TP
|
||||
.B
|
||||
\fB\-\-cert\fP
|
||||
Certificate file, PEM format. Same file
|
||||
search rules applied as for the configuration
|
||||
@ -1176,3 +1186,5 @@ Peter Dunkley <peter.dunkley@crocodilertc.net>
|
||||
Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
|
||||
.PP
|
||||
Federico Pinna <fpinna@vivocha.com>
|
||||
.PP
|
||||
Bradley T. Hughes <bradleythughes@fastmail.fm>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.\" Text automatically generated by txt2man
|
||||
.TH TURN 1 "18 August 2014" "" ""
|
||||
.TH TURN 1 "28 September 2014" "" ""
|
||||
.SH GENERAL INFORMATION
|
||||
|
||||
A set of turnutils_* programs provides some utility functionality to be used
|
||||
@ -177,6 +177,10 @@ Random disconnect after a few initial packets.
|
||||
Dual allocation (SSODA draft support).
|
||||
.TP
|
||||
.B
|
||||
\fB\-J\fP
|
||||
Use oAuth with default test key kid='north'.
|
||||
.TP
|
||||
.B
|
||||
Options with required values:
|
||||
.TP
|
||||
.B
|
||||
@ -455,3 +459,5 @@ Peter Dunkley <peter.dunkley@crocodilertc.net>
|
||||
Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
|
||||
.PP
|
||||
Federico Pinna <fpinna@vivocha.com>
|
||||
.PP
|
||||
Bradley T. Hughes <bradleythughes@fastmail.fm>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
# Common settings script.
|
||||
|
||||
TURNVERSION=4.1.2.1
|
||||
TURNVERSION=4.2.1.2
|
||||
BUILDDIR=~/rpmbuild
|
||||
ARCH=`uname -p`
|
||||
TURNSERVER_SVN_URL=http://coturn.googlecode.com/svn
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
Name: turnserver
|
||||
Version: 4.1.2.1
|
||||
Version: 4.2.1.2
|
||||
Release: 0%{dist}
|
||||
Summary: Coturn TURN Server
|
||||
|
||||
@ -294,6 +294,8 @@ fi
|
||||
%{_includedir}/turn/client/TurnMsgLib.h
|
||||
|
||||
%changelog
|
||||
* Sun Oct 05 2014 Oleg Moskalenko <mom040267@gmail.com>
|
||||
- Sync to 4.2.1.2
|
||||
* Thu Aug 14 2014 Oleg Moskalenko <mom040267@gmail.com>
|
||||
- Sync to 4.1.2.1
|
||||
* Tue Jul 29 2014 Oleg Moskalenko <mom040267@gmail.com>
|
||||
|
||||
@ -549,7 +549,7 @@ void set_execdir(void)
|
||||
/* On some systems, this may give us the execution path */
|
||||
char *_var = getenv("_");
|
||||
if(_var && *_var) {
|
||||
_var = strdup(_var);
|
||||
_var = turn_strdup(_var);
|
||||
char *edir=_var;
|
||||
if(edir[0]!='.')
|
||||
edir = strstr(edir,"/");
|
||||
@ -559,7 +559,7 @@ void set_execdir(void)
|
||||
edir = dirname(_var);
|
||||
if(c_execdir)
|
||||
turn_free(c_execdir,strlen(c_execdir)+1);
|
||||
c_execdir = strdup(edir);
|
||||
c_execdir = turn_strdup(edir);
|
||||
turn_free(_var,strlen(_var)+1);
|
||||
}
|
||||
}
|
||||
@ -604,7 +604,7 @@ char* find_config_file(const char *config_file, int print_file_name)
|
||||
FILE *f = fopen(config_file, "r");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
full_path_to_config_file = strdup(config_file);
|
||||
full_path_to_config_file = turn_strdup(config_file);
|
||||
}
|
||||
} else {
|
||||
int i = 0;
|
||||
@ -899,4 +899,53 @@ struct event_base *turn_event_base_new(void)
|
||||
return event_base_new_with_config(cfg);
|
||||
}
|
||||
|
||||
/////////// OAUTH /////////////////
|
||||
|
||||
void convert_oauth_key_data_raw(const oauth_key_data_raw *raw, oauth_key_data *oakd)
|
||||
{
|
||||
if(raw && oakd) {
|
||||
|
||||
ns_bzero(oakd,sizeof(oauth_key_data));
|
||||
|
||||
oakd->timestamp = (turn_time_t)raw->timestamp;
|
||||
oakd->lifetime = raw->lifetime;
|
||||
|
||||
ns_bcopy(raw->as_rs_alg,oakd->as_rs_alg,sizeof(oakd->as_rs_alg));
|
||||
ns_bcopy(raw->auth_alg,oakd->auth_alg,sizeof(oakd->auth_alg));
|
||||
ns_bcopy(raw->hkdf_hash_func,oakd->hkdf_hash_func,sizeof(oakd->hkdf_hash_func));
|
||||
ns_bcopy(raw->kid,oakd->kid,sizeof(oakd->kid));
|
||||
|
||||
if(raw->ikm_key[0]) {
|
||||
size_t ikm_key_size = 0;
|
||||
char *ikm_key = (char*)base64_decode(raw->ikm_key,strlen(raw->ikm_key),&ikm_key_size);
|
||||
if(ikm_key) {
|
||||
ns_bcopy(ikm_key,oakd->ikm_key,ikm_key_size);
|
||||
oakd->ikm_key_size = ikm_key_size;
|
||||
turn_free(ikm_key,ikm_key_size);
|
||||
}
|
||||
}
|
||||
|
||||
if(raw->as_rs_key[0]) {
|
||||
size_t as_rs_key_size = 0;
|
||||
char *as_rs_key = (char*)base64_decode(raw->as_rs_key,strlen(raw->as_rs_key),&as_rs_key_size);
|
||||
if(as_rs_key) {
|
||||
ns_bcopy(as_rs_key,oakd->as_rs_key,as_rs_key_size);
|
||||
oakd->as_rs_key_size = as_rs_key_size;
|
||||
turn_free(as_rs_key,as_rs_key_size);
|
||||
}
|
||||
}
|
||||
|
||||
if(raw->auth_key[0]) {
|
||||
size_t auth_key_size = 0;
|
||||
char *auth_key = (char*)base64_decode(raw->auth_key,strlen(raw->auth_key),&auth_key_size);
|
||||
if(auth_key) {
|
||||
ns_bcopy(auth_key,oakd->auth_key,auth_key_size);
|
||||
oakd->auth_key_size = auth_key_size;
|
||||
turn_free(auth_key,auth_key_size);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "ns_turn_ioaddr.h"
|
||||
#include "ns_turn_msg_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -69,6 +70,22 @@ enum _TURN_TLS_TYPE {
|
||||
|
||||
typedef enum _TURN_TLS_TYPE TURN_TLS_TYPE;
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
struct _oauth_key_data_raw {
|
||||
char kid[OAUTH_KID_SIZE+1];
|
||||
char ikm_key[OAUTH_KEY_SIZE+1];
|
||||
u64bits timestamp;
|
||||
u32bits lifetime;
|
||||
char hkdf_hash_func[OAUTH_HASH_FUNC_SIZE+1];
|
||||
char as_rs_alg[OAUTH_ALG_SIZE+1];
|
||||
char as_rs_key[OAUTH_KEY_SIZE+1];
|
||||
char auth_alg[OAUTH_ALG_SIZE+1];
|
||||
char auth_key[OAUTH_KEY_SIZE+1];
|
||||
};
|
||||
|
||||
typedef struct _oauth_key_data_raw oauth_key_data_raw;
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
||||
#define EVENT_DEL(ev) if(ev) { event_del(ev); event_free(ev); ev=NULL; }
|
||||
@ -150,6 +167,10 @@ unsigned char *base64_decode(const char *data,
|
||||
|
||||
const char* turn_get_ssl_method(SSL *ssl, const char* mdefault);
|
||||
|
||||
////////////// OAUTH UTILS ////////////////
|
||||
|
||||
void convert_oauth_key_data_raw(const oauth_key_data_raw *raw, oauth_key_data *oakd);
|
||||
|
||||
//////////// Event Base /////////////////////
|
||||
|
||||
struct event_base *turn_event_base_new(void);
|
||||
|
||||
@ -91,7 +91,7 @@ static void redisLibeventReadEvent(int fd, short event, void *arg) {
|
||||
} while((len<0)&&(errno == EINTR));
|
||||
if(len<1) {
|
||||
e->invalid = 1;
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Redis connection broken: e=0x%lx\n", __FUNCTION__, (unsigned long)e);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Redis connection broken: e=0x%lx\n", __FUNCTION__, ((unsigned long)e));
|
||||
}
|
||||
}
|
||||
if(redis_le_valid(e)) {
|
||||
@ -213,7 +213,7 @@ void send_message_to_redis(redis_context_handle rch, const char *command, const
|
||||
|
||||
if((redisAsyncCommand(ac, NULL, e, rm.format, rm.arg)!=REDIS_OK)) {
|
||||
e->invalid = 1;
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Redis connection broken: ac=0x%lx, e=0x%x\n", __FUNCTION__,(unsigned long)ac,(unsigned long)e);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Redis connection broken: ac=0x%lx, e=0x%lx\n", __FUNCTION__,(unsigned long)ac,(unsigned long)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -250,10 +250,10 @@ redis_context_handle redisLibeventAttach(struct event_base *base, char *ip0, int
|
||||
e->allocated = 1;
|
||||
e->context = ac;
|
||||
e->base = base;
|
||||
e->ip = strdup(ip);
|
||||
e->ip = turn_strdup(ip);
|
||||
e->port = port;
|
||||
if(pwd)
|
||||
e->pwd = strdup(pwd);
|
||||
e->pwd = turn_strdup(pwd);
|
||||
e->db = db;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
@ -372,7 +372,7 @@ static void redis_reconnect(struct redisLibeventEvents *e)
|
||||
}
|
||||
|
||||
if(redis_le_valid(e)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Re-connected to redis, async\n", __FUNCTION__);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: Re-connected to redis, async\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,6 +32,8 @@
|
||||
#include "ns_turn_ioalib.h"
|
||||
#include "ns_turn_msg_defs.h"
|
||||
|
||||
#include <event2/http.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <pthread.h>
|
||||
@ -293,11 +295,11 @@ static void set_log_file_name_func(char *base, char *f, size_t fsz)
|
||||
}
|
||||
|
||||
char logdate[125];
|
||||
char *tail=strdup(".log");
|
||||
char *tail=turn_strdup(".log");
|
||||
|
||||
get_date(logdate,sizeof(logdate));
|
||||
|
||||
char *base1=strdup(base);
|
||||
char *base1=turn_strdup(base);
|
||||
|
||||
int len=(int)strlen(base1);
|
||||
|
||||
@ -317,11 +319,11 @@ static void set_log_file_name_func(char *base, char *f, size_t fsz)
|
||||
break;
|
||||
else if(base1[len]=='.') {
|
||||
turn_free(tail,strlen(tail)+1);
|
||||
tail=strdup(base1+len);
|
||||
tail=turn_strdup(base1+len);
|
||||
base1[len]=0;
|
||||
if(strlen(tail)<2) {
|
||||
turn_free(tail,strlen(tail)+1);
|
||||
tail = strdup(".log");
|
||||
tail = turn_strdup(".log");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -654,3 +656,193 @@ int get_canonic_origin(const char* o, char *co, int sz)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if defined(TURN_MEMORY_DEBUG)
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static volatile int tmm_init = 0;
|
||||
static pthread_mutex_t tm;
|
||||
|
||||
typedef void* ptrtype;
|
||||
typedef set<ptrtype> ptrs_t;
|
||||
typedef map<string,ptrs_t> str_to_ptrs_t;
|
||||
typedef map<ptrtype,string> ptr_to_str_t;
|
||||
|
||||
static str_to_ptrs_t str_to_ptrs;
|
||||
static ptr_to_str_t ptr_to_str;
|
||||
|
||||
static void tm_init(void) {
|
||||
if(!tmm_init) {
|
||||
pthread_mutex_init(&tm,NULL);
|
||||
tmm_init = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_tm_ptr(void *ptr, const char *id) {
|
||||
|
||||
UNUSED_ARG(ptr);
|
||||
UNUSED_ARG(id);
|
||||
|
||||
if(!ptr)
|
||||
return;
|
||||
|
||||
string sid(id);
|
||||
|
||||
str_to_ptrs_t::iterator iter;
|
||||
|
||||
pthread_mutex_lock(&tm);
|
||||
|
||||
iter = str_to_ptrs.find(sid);
|
||||
|
||||
if(iter == str_to_ptrs.end()) {
|
||||
set<ptrtype> sp;
|
||||
sp.insert(ptr);
|
||||
str_to_ptrs[sid]=sp;
|
||||
} else {
|
||||
iter->second.insert(ptr);
|
||||
}
|
||||
|
||||
ptr_to_str[ptr]=sid;
|
||||
|
||||
pthread_mutex_unlock(&tm);
|
||||
}
|
||||
|
||||
static void del_tm_ptr(void *ptr, const char *id) {
|
||||
|
||||
UNUSED_ARG(ptr);
|
||||
UNUSED_ARG(id);
|
||||
|
||||
if(!ptr)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&tm);
|
||||
|
||||
ptr_to_str_t::iterator pts_iter = ptr_to_str.find(ptr);
|
||||
if(pts_iter == ptr_to_str.end()) {
|
||||
|
||||
printf("Tring to free unknown pointer (1): %s\n",id);
|
||||
|
||||
} else {
|
||||
|
||||
string sid = pts_iter->second;
|
||||
ptr_to_str.erase(pts_iter);
|
||||
|
||||
str_to_ptrs_t::iterator iter = str_to_ptrs.find(sid);
|
||||
|
||||
if(iter == str_to_ptrs.end()) {
|
||||
|
||||
printf("Tring to free unknown pointer (2): %s\n",id);
|
||||
|
||||
} else {
|
||||
|
||||
iter->second.erase(ptr);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&tm);
|
||||
}
|
||||
|
||||
static void tm_id(char *id, const char* file, int line) {
|
||||
sprintf(id,"%s:%d",file,line);
|
||||
}
|
||||
|
||||
#define TM_START() char id[128];tm_id(id,file,line);tm_init()
|
||||
|
||||
extern "C" void tm_print_func(void);
|
||||
void tm_print_func(void) {
|
||||
pthread_mutex_lock(&tm);
|
||||
printf("=============================================\n");
|
||||
for(str_to_ptrs_t::const_iterator iter=str_to_ptrs.begin();iter != str_to_ptrs.end();++iter) {
|
||||
if(iter->second.size())
|
||||
printf("%s: %s: %d\n",__FUNCTION__,iter->first.c_str(),(int)(iter->second.size()));
|
||||
}
|
||||
printf("=============================================\n");
|
||||
pthread_mutex_unlock(&tm);
|
||||
}
|
||||
|
||||
extern "C" void *turn_malloc_func(size_t sz, const char* file, int line);
|
||||
void *turn_malloc_func(size_t sz, const char* file, int line) {
|
||||
|
||||
TM_START();
|
||||
|
||||
void *ptr = malloc(sz);
|
||||
|
||||
add_tm_ptr(ptr,id);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extern "C" void *turn_realloc_func(void *ptr, size_t old_sz, size_t new_sz, const char* file, int line);
|
||||
void *turn_realloc_func(void *ptr, size_t old_sz, size_t new_sz, const char* file, int line) {
|
||||
|
||||
UNUSED_ARG(old_sz);
|
||||
|
||||
TM_START();
|
||||
|
||||
if(ptr)
|
||||
del_tm_ptr(ptr,id);
|
||||
|
||||
ptr = realloc(ptr,new_sz);
|
||||
|
||||
add_tm_ptr(ptr,id);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extern "C" void turn_free_func(void *ptr, size_t sz, const char* file, int line);
|
||||
void turn_free_func(void *ptr, size_t sz, const char* file, int line) {
|
||||
|
||||
UNUSED_ARG(sz);
|
||||
|
||||
TM_START();
|
||||
|
||||
del_tm_ptr(ptr,id);
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
extern "C" void turn_free_simple(void *ptr);
|
||||
void turn_free_simple(void *ptr) {
|
||||
|
||||
tm_init();
|
||||
|
||||
del_tm_ptr(ptr,__FUNCTION__);
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
extern "C" void *turn_calloc_func(size_t number, size_t size, const char* file, int line);
|
||||
void *turn_calloc_func(size_t number, size_t size, const char* file, int line) {
|
||||
|
||||
TM_START();
|
||||
|
||||
void *ptr = calloc(number,size);
|
||||
|
||||
add_tm_ptr(ptr,id);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extern "C" char *turn_strdup_func(const char* s, const char* file, int line);
|
||||
char *turn_strdup_func(const char* s, const char* file, int line) {
|
||||
|
||||
TM_START();
|
||||
|
||||
char *ptr = strdup(s);
|
||||
|
||||
add_tm_ptr(ptr,id);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -32,13 +32,12 @@
|
||||
#define __TURN_ULIB__
|
||||
|
||||
#if !defined(TURN_LOG_FUNC)
|
||||
//#define TURN_LOG_FUNC(level, ...) printf (__VA_ARGS__)
|
||||
#define TURN_LOG_FUNC turn_log_func_default
|
||||
#endif
|
||||
|
||||
#include "ns_turn_ioaddr.h"
|
||||
|
||||
#include <event2/http.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@ -52,8 +52,10 @@ static void mongo_logger(mongoc_log_level_t log_level, const char * log_domain,
|
||||
UNUSED_ARG(log_domain);
|
||||
UNUSED_ARG(user_data);
|
||||
|
||||
TURN_LOG_LEVEL l;
|
||||
TURN_LOG_LEVEL l = TURN_LOG_LEVEL_INFO;
|
||||
|
||||
UNUSED_ARG(l);
|
||||
|
||||
switch(log_level) {
|
||||
case MONGOC_LOG_LEVEL_ERROR:
|
||||
l = TURN_LOG_LEVEL_ERROR;
|
||||
@ -72,7 +74,7 @@ static void MongoFree(MONGO * info) {
|
||||
if(info) {
|
||||
if(info->uri) mongoc_uri_destroy(info->uri);
|
||||
if(info->client) mongoc_client_destroy(info->client);
|
||||
turn_free(info, sizeof(MONGO));
|
||||
turn_free(info, sizeof(MONGO));
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,6 +236,79 @@ static int mongo_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
|
||||
bson_destroy(&fields);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mongo_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
|
||||
|
||||
mongoc_collection_t * collection = mongo_get_collection("oauth_key");
|
||||
|
||||
if (!collection)
|
||||
return -1;
|
||||
|
||||
bson_t query;
|
||||
bson_init(&query);
|
||||
BSON_APPEND_UTF8(&query, "kid", (const char *)kid);
|
||||
|
||||
bson_t fields;
|
||||
bson_init(&fields);
|
||||
BSON_APPEND_INT32(&fields, "lifetime", 1);
|
||||
BSON_APPEND_INT32(&fields, "timestamp", 1);
|
||||
BSON_APPEND_INT32(&fields, "as_rs_alg", 1);
|
||||
BSON_APPEND_INT32(&fields, "as_rs_key", 1);
|
||||
BSON_APPEND_INT32(&fields, "auth_alg", 1);
|
||||
BSON_APPEND_INT32(&fields, "auth_key", 1);
|
||||
BSON_APPEND_INT32(&fields, "hkdf_hash_func", 1);
|
||||
BSON_APPEND_INT32(&fields, "ikm_key", 1);
|
||||
|
||||
mongoc_cursor_t * cursor;
|
||||
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 1, 0,
|
||||
&query, &fields, NULL);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
ns_bzero(key,sizeof(oauth_key_data_raw));
|
||||
STRCPY(key->kid,kid);
|
||||
|
||||
if (!cursor) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
|
||||
"Error querying MongoDB collection 'oauth_key'\n");
|
||||
} else {
|
||||
const bson_t * item;
|
||||
uint32_t length;
|
||||
bson_iter_t iter;
|
||||
if (mongoc_cursor_next(cursor, &item)) {
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "as_rs_alg") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->as_rs_alg,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "as_rs_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->as_rs_key,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "auth_alg") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->auth_alg,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "auth_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->auth_key,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "ikm_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->ikm_key,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "hkdf_hash_func") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->hkdf_hash_func,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "timestamp") && BSON_ITER_HOLDS_INT64(&iter)) {
|
||||
key->timestamp = (u64bits)bson_iter_int64(&iter);
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "lifetime") && BSON_ITER_HOLDS_INT32(&iter)) {
|
||||
key->lifetime = (u32bits)bson_iter_int32(&iter);
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
mongoc_cursor_destroy(cursor);
|
||||
}
|
||||
mongoc_collection_destroy(collection);
|
||||
bson_destroy(&query);
|
||||
bson_destroy(&fields);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mongo_get_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
mongoc_collection_t * collection = mongo_get_collection("turnusers_st");
|
||||
@ -302,7 +377,43 @@ static int mongo_set_user_key(u08bits *usname, u08bits *realm, const char *key)
|
||||
int ret = -1;
|
||||
|
||||
if (!mongoc_collection_update(collection, MONGOC_UPDATE_UPSERT, &query, &doc, NULL, NULL)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating secret key information\n");
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating user key information\n");
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
mongoc_collection_destroy(collection);
|
||||
bson_destroy(&doc);
|
||||
bson_destroy(&query);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mongo_set_oauth_key(oauth_key_data_raw *key) {
|
||||
|
||||
mongoc_collection_t * collection = mongo_get_collection("oauth_key");
|
||||
|
||||
if(!collection)
|
||||
return -1;
|
||||
|
||||
bson_t query;
|
||||
bson_init(&query);
|
||||
BSON_APPEND_UTF8(&query, "kid", (const char *)key->kid);
|
||||
|
||||
bson_t doc;
|
||||
bson_init(&doc);
|
||||
BSON_APPEND_UTF8(&doc, "kid", (const char *)key->kid);
|
||||
BSON_APPEND_UTF8(&doc, "as_rs_alg", (const char *)key->as_rs_alg);
|
||||
BSON_APPEND_UTF8(&doc, "as_rs_key", (const char *)key->as_rs_key);
|
||||
BSON_APPEND_UTF8(&doc, "auth_alg", (const char *)key->auth_alg);
|
||||
BSON_APPEND_UTF8(&doc, "auth_key", (const char *)key->auth_key);
|
||||
BSON_APPEND_UTF8(&doc, "hkdf_hash_func", (const char *)key->hkdf_hash_func);
|
||||
BSON_APPEND_UTF8(&doc, "ikm_key", (const char *)key->ikm_key);
|
||||
BSON_APPEND_INT64(&doc, "timestamp", (int64_t)key->timestamp);
|
||||
BSON_APPEND_INT32(&doc, "lifetime", (int32_t)key->lifetime);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
if (!mongoc_collection_update(collection, MONGOC_UPDATE_UPSERT, &query, &doc, NULL, NULL)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating oauth key information\n");
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
@ -364,6 +475,29 @@ static int mongo_del_user(u08bits *usname, int is_st, u08bits *realm) {
|
||||
bson_destroy(&query);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mongo_del_oauth_key(const u08bits *kid) {
|
||||
|
||||
mongoc_collection_t * collection = mongo_get_collection("oauth_key");
|
||||
|
||||
if(!collection)
|
||||
return -1;
|
||||
|
||||
bson_t query;
|
||||
bson_init(&query);
|
||||
BSON_APPEND_UTF8(&query, "kid", (const char *)kid);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
if (!mongoc_collection_delete(collection, MONGOC_DELETE_SINGLE_REMOVE, &query, NULL, NULL)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting oauth key information\n");
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
mongoc_collection_destroy(collection);
|
||||
bson_destroy(&query);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mongo_list_users(int is_st, u08bits *realm) {
|
||||
const char * collection_name = is_st ? "turnusers_st" : "turnusers_lt";
|
||||
@ -425,6 +559,92 @@ static int mongo_list_users(int is_st, u08bits *realm) {
|
||||
bson_destroy(&fields);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mongo_list_oauth_keys(void) {
|
||||
|
||||
const char * collection_name = "oauth_key";
|
||||
mongoc_collection_t * collection = mongo_get_collection(collection_name);
|
||||
|
||||
if(!collection)
|
||||
return -1;
|
||||
|
||||
bson_t query;
|
||||
bson_init(&query);
|
||||
|
||||
bson_t child;
|
||||
bson_append_document_begin(&query, "$orderby", -1, &child);
|
||||
bson_append_int32(&child, "kid", -1, 1);
|
||||
bson_append_document_end(&query, &child);
|
||||
bson_append_document_begin(&query, "$query", -1, &child);
|
||||
bson_append_document_end(&query, &child);
|
||||
|
||||
bson_t fields;
|
||||
bson_init(&fields);
|
||||
BSON_APPEND_INT32(&fields, "kid", 1);
|
||||
BSON_APPEND_INT32(&fields, "lifetime", 1);
|
||||
BSON_APPEND_INT32(&fields, "timestamp", 1);
|
||||
BSON_APPEND_INT32(&fields, "as_rs_alg", 1);
|
||||
BSON_APPEND_INT32(&fields, "as_rs_key", 1);
|
||||
BSON_APPEND_INT32(&fields, "auth_alg", 1);
|
||||
BSON_APPEND_INT32(&fields, "auth_key", 1);
|
||||
BSON_APPEND_INT32(&fields, "hkdf_hash_func", 1);
|
||||
BSON_APPEND_INT32(&fields, "ikm_key", 1);
|
||||
|
||||
mongoc_cursor_t * cursor;
|
||||
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
if (!cursor) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection '%s'\n", collection_name);
|
||||
} else {
|
||||
const bson_t * item;
|
||||
oauth_key_data_raw key_;
|
||||
oauth_key_data_raw *key=&key_;
|
||||
uint32_t length;
|
||||
bson_iter_t iter;
|
||||
while (mongoc_cursor_next(cursor, &item)) {
|
||||
|
||||
ns_bzero(key,sizeof(oauth_key_data_raw));
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "kid") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->kid,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "as_rs_alg") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->as_rs_alg,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "as_rs_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->as_rs_key,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "auth_alg") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->auth_alg,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "auth_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->auth_key,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "ikm_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->ikm_key,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "hkdf_hash_func") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
STRCPY(key->hkdf_hash_func,bson_iter_utf8(&iter, &length));
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "timestamp") && BSON_ITER_HOLDS_INT64(&iter)) {
|
||||
key->timestamp = (u64bits)bson_iter_int64(&iter);
|
||||
}
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "lifetime") && BSON_ITER_HOLDS_INT32(&iter)) {
|
||||
key->lifetime = (u32bits)bson_iter_int32(&iter);
|
||||
}
|
||||
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n",
|
||||
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func,
|
||||
key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key);
|
||||
}
|
||||
mongoc_cursor_destroy(cursor);
|
||||
ret = 0;
|
||||
}
|
||||
mongoc_collection_destroy(collection);
|
||||
bson_destroy(&query);
|
||||
bson_destroy(&fields);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mongo_show_secret(u08bits *realm) {
|
||||
mongoc_collection_t * collection = mongo_get_collection("turn_secret");
|
||||
@ -642,7 +862,8 @@ static int mongo_set_realm_option_one(u08bits *realm, unsigned long value, const
|
||||
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
|
||||
bson_init(&doc);
|
||||
|
||||
char * _k = (char *)turn_malloc(9 + strlen(opt));
|
||||
size_t klen = 9 + strlen(opt);
|
||||
char * _k = (char *)turn_malloc(klen);
|
||||
strcpy(_k, "options.");
|
||||
strcat(_k, opt);
|
||||
|
||||
@ -655,7 +876,7 @@ static int mongo_set_realm_option_one(u08bits *realm, unsigned long value, const
|
||||
BSON_APPEND_INT32(&child, _k, 1);
|
||||
bson_append_document_end(&doc, &child);
|
||||
}
|
||||
free(_k);
|
||||
turn_free(_k,klen);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
@ -792,113 +1013,129 @@ static int mongo_get_ip_list(const char *kind, ip_range_list_t * list) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void mongo_reread_realms(secrets_list_t * realms_list) {
|
||||
|
||||
UNUSED_ARG(realms_list);
|
||||
|
||||
mongoc_collection_t * collection = mongo_get_collection("realm");
|
||||
mongoc_collection_t * collection = mongo_get_collection("realm");
|
||||
|
||||
if(!collection)
|
||||
return;
|
||||
if (!collection)
|
||||
return;
|
||||
|
||||
bson_t query;
|
||||
bson_init(&query);
|
||||
bson_t query;
|
||||
bson_init(&query);
|
||||
|
||||
bson_t fields;
|
||||
bson_init(&fields);
|
||||
BSON_APPEND_INT32(&fields, "realm", 1);
|
||||
BSON_APPEND_INT32(&fields, "origin", 1);
|
||||
BSON_APPEND_INT32(&fields, "options", 1);
|
||||
|
||||
mongoc_cursor_t * cursor;
|
||||
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
|
||||
bson_t fields;
|
||||
bson_init(&fields);
|
||||
BSON_APPEND_INT32(&fields, "realm", 1);
|
||||
BSON_APPEND_INT32(&fields, "origin", 1);
|
||||
BSON_APPEND_INT32(&fields, "options", 1);
|
||||
|
||||
if (!cursor) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'realm'\n");
|
||||
} else {
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(free);
|
||||
mongoc_cursor_t * cursor;
|
||||
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0,
|
||||
&query, &fields, NULL);
|
||||
|
||||
const bson_t * item;
|
||||
uint32_t length;
|
||||
bson_iter_t iter;
|
||||
if (!cursor) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
|
||||
"Error querying MongoDB collection 'realm'\n");
|
||||
} else {
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(turn_free_simple);
|
||||
|
||||
while (mongoc_cursor_next(cursor, &item)) {
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
char * _realm = strdup(bson_iter_utf8(&iter, &length));
|
||||
const bson_t * item;
|
||||
uint32_t length;
|
||||
bson_iter_t iter;
|
||||
|
||||
get_realm(_realm);
|
||||
while (mongoc_cursor_next(cursor, &item)) {
|
||||
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "origin") && BSON_ITER_HOLDS_ARRAY(&iter)) {
|
||||
const uint8_t *docbuf = NULL;
|
||||
uint32_t doclen = 0;
|
||||
bson_t origin_array;
|
||||
bson_iter_t origin_iter;
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "realm")
|
||||
&& BSON_ITER_HOLDS_UTF8(&iter)) {
|
||||
|
||||
bson_iter_array(&iter, &doclen, &docbuf);
|
||||
bson_init_static(&origin_array, docbuf, doclen);
|
||||
char * _realm = turn_strdup(bson_iter_utf8(&iter, &length));
|
||||
|
||||
if (bson_iter_init(&origin_iter, &origin_array)) {
|
||||
while(bson_iter_next(&origin_iter)) {
|
||||
if (BSON_ITER_HOLDS_UTF8(&origin_iter)) {
|
||||
char * _origin = strdup(bson_iter_utf8(&origin_iter, &length));
|
||||
char *rval = strdup(_realm);
|
||||
ur_string_map_value_type value = (ur_string_map_value_type)(rval);
|
||||
ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type) _origin, value);
|
||||
free(_origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
realm_params_t* rp = get_realm(_realm);
|
||||
lock_realms();
|
||||
rp->options.perf_options.max_bps = turn_params.max_bps;
|
||||
rp->options.perf_options.total_quota = turn_params.total_quota;
|
||||
rp->options.perf_options.user_quota = turn_params.user_quota;
|
||||
unlock_realms();
|
||||
get_realm(_realm);
|
||||
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "options") && BSON_ITER_HOLDS_DOCUMENT(&iter)) {
|
||||
const uint8_t *docbuf = NULL;
|
||||
uint32_t doclen = 0;
|
||||
bson_t options;
|
||||
bson_iter_t options_iter;
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter,
|
||||
"origin") && BSON_ITER_HOLDS_ARRAY(&iter)) {
|
||||
const uint8_t *docbuf = NULL;
|
||||
uint32_t doclen = 0;
|
||||
bson_t origin_array;
|
||||
bson_iter_t origin_iter;
|
||||
|
||||
bson_iter_document(&iter, &doclen, &docbuf);
|
||||
bson_init_static(&options, docbuf, doclen);
|
||||
bson_iter_array(&iter, &doclen, &docbuf);
|
||||
bson_init_static(&origin_array, docbuf, doclen);
|
||||
|
||||
if (bson_iter_init(&options_iter, &options)) {
|
||||
while(bson_iter_next(&options_iter)) {
|
||||
const char * _k = bson_iter_key(&options_iter);
|
||||
int32_t _v = 0;
|
||||
if (BSON_ITER_HOLDS_DOUBLE(&options_iter)) {
|
||||
_v = (int32_t)bson_iter_double(&options_iter);
|
||||
} else if (BSON_ITER_HOLDS_INT32(&options_iter)) {
|
||||
_v = bson_iter_int32(&options_iter);
|
||||
} else if (BSON_ITER_HOLDS_INT64(&options_iter)) {
|
||||
_v = (int32_t)bson_iter_int64(&options_iter);
|
||||
}
|
||||
if (_v) {
|
||||
if(!strcmp(_k,"max-bps"))
|
||||
rp->options.perf_options.max_bps = (band_limit_t)_v;
|
||||
else if(!strcmp(_k,"total-quota"))
|
||||
rp->options.perf_options.total_quota = (vint)_v;
|
||||
else if(!strcmp(_k,"user-quota"))
|
||||
rp->options.perf_options.user_quota = (vint)_v;
|
||||
if (bson_iter_init(&origin_iter, &origin_array)) {
|
||||
while (bson_iter_next(&origin_iter)) {
|
||||
if (BSON_ITER_HOLDS_UTF8(&origin_iter)) {
|
||||
char* _origin = turn_strdup(bson_iter_utf8(&origin_iter, &length));
|
||||
char *rval = turn_strdup(_realm);
|
||||
ur_string_map_value_type value =
|
||||
(ur_string_map_value_type) (rval);
|
||||
ur_string_map_put(o_to_realm_new,
|
||||
(const ur_string_map_key_type) _origin,
|
||||
value);
|
||||
turn_free(_origin,strlen(_origin)+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
realm_params_t* rp = get_realm(_realm);
|
||||
lock_realms();
|
||||
rp->options.perf_options.max_bps = turn_params.max_bps;
|
||||
rp->options.perf_options.total_quota = turn_params.total_quota;
|
||||
rp->options.perf_options.user_quota = turn_params.user_quota;
|
||||
unlock_realms();
|
||||
|
||||
if (bson_iter_init(&iter, item) && bson_iter_find(&iter,
|
||||
"options") && BSON_ITER_HOLDS_DOCUMENT(&iter)) {
|
||||
const uint8_t *docbuf = NULL;
|
||||
uint32_t doclen = 0;
|
||||
bson_t options;
|
||||
bson_iter_t options_iter;
|
||||
|
||||
bson_iter_document(&iter, &doclen, &docbuf);
|
||||
bson_init_static(&options, docbuf, doclen);
|
||||
|
||||
if (bson_iter_init(&options_iter, &options)) {
|
||||
while (bson_iter_next(&options_iter)) {
|
||||
const char * _k = bson_iter_key(&options_iter);
|
||||
int32_t _v = 0;
|
||||
if (BSON_ITER_HOLDS_DOUBLE(&options_iter)) {
|
||||
_v = (int32_t) bson_iter_double(&options_iter);
|
||||
} else if (BSON_ITER_HOLDS_INT32(&options_iter)) {
|
||||
_v = bson_iter_int32(&options_iter);
|
||||
} else if (BSON_ITER_HOLDS_INT64(&options_iter)) {
|
||||
_v = (int32_t) bson_iter_int64(&options_iter);
|
||||
}
|
||||
if (_v) {
|
||||
if (!strcmp(_k, "max-bps"))
|
||||
rp->options.perf_options.max_bps
|
||||
= (band_limit_t) _v;
|
||||
else if (!strcmp(_k, "total-quota"))
|
||||
rp->options.perf_options.total_quota
|
||||
= (vint) _v;
|
||||
else if (!strcmp(_k, "user-quota"))
|
||||
rp->options.perf_options.user_quota
|
||||
= (vint) _v;
|
||||
else {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown realm option: %s\n", _k);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
|
||||
"Unknown realm option: %s\n", _k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(_realm);
|
||||
}
|
||||
}
|
||||
update_o_to_realm(o_to_realm_new);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
}
|
||||
mongoc_collection_destroy(collection);
|
||||
bson_destroy(&query);
|
||||
bson_destroy(&fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
turn_free(_realm,strlen(_realm)+1);
|
||||
}
|
||||
}
|
||||
update_o_to_realm(o_to_realm_new);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
}
|
||||
mongoc_collection_destroy(collection);
|
||||
bson_destroy(&query);
|
||||
bson_destroy(&fields);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -921,7 +1158,11 @@ static turn_dbdriver_t driver = {
|
||||
&mongo_list_realm_options,
|
||||
&mongo_auth_ping,
|
||||
&mongo_get_ip_list,
|
||||
&mongo_reread_realms
|
||||
&mongo_reread_realms,
|
||||
&mongo_set_oauth_key,
|
||||
&mongo_get_oauth_key,
|
||||
&mongo_del_oauth_key,
|
||||
&mongo_list_oauth_keys
|
||||
};
|
||||
|
||||
turn_dbdriver_t * get_mongo_dbdriver(void) {
|
||||
|
||||
@ -76,7 +76,7 @@ static Myconninfo *MyconninfoParse(char *userdb, char **errmsg) {
|
||||
Myconninfo *co = (Myconninfo*)turn_malloc(sizeof(Myconninfo));
|
||||
ns_bzero(co,sizeof(Myconninfo));
|
||||
if(userdb) {
|
||||
char *s0=strdup(userdb);
|
||||
char *s0=turn_strdup(userdb);
|
||||
char *s = s0;
|
||||
|
||||
while(s && *s) {
|
||||
@ -93,44 +93,44 @@ static Myconninfo *MyconninfoParse(char *userdb, char **errmsg) {
|
||||
MyconninfoFree(co);
|
||||
co = NULL;
|
||||
if(errmsg) {
|
||||
*errmsg = strdup(s);
|
||||
*errmsg = turn_strdup(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*seq = 0;
|
||||
if(!strcmp(s,"host"))
|
||||
co->host = strdup(seq+1);
|
||||
co->host = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ip"))
|
||||
co->host = strdup(seq+1);
|
||||
co->host = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"addr"))
|
||||
co->host = strdup(seq+1);
|
||||
co->host = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ipaddr"))
|
||||
co->host = strdup(seq+1);
|
||||
co->host = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"hostaddr"))
|
||||
co->host = strdup(seq+1);
|
||||
co->host = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"dbname"))
|
||||
co->dbname = strdup(seq+1);
|
||||
co->dbname = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"db"))
|
||||
co->dbname = strdup(seq+1);
|
||||
co->dbname = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"database"))
|
||||
co->dbname = strdup(seq+1);
|
||||
co->dbname = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"user"))
|
||||
co->user = strdup(seq+1);
|
||||
co->user = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"uname"))
|
||||
co->user = strdup(seq+1);
|
||||
co->user = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"name"))
|
||||
co->user = strdup(seq+1);
|
||||
co->user = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"username"))
|
||||
co->user = strdup(seq+1);
|
||||
co->user = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"password"))
|
||||
co->password = strdup(seq+1);
|
||||
co->password = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"pwd"))
|
||||
co->password = strdup(seq+1);
|
||||
co->password = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"passwd"))
|
||||
co->password = strdup(seq+1);
|
||||
co->password = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"secret"))
|
||||
co->password = strdup(seq+1);
|
||||
co->password = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"port"))
|
||||
co->port = (unsigned int)atoi(seq+1);
|
||||
else if(!strcmp(s,"p"))
|
||||
@ -140,30 +140,30 @@ static Myconninfo *MyconninfoParse(char *userdb, char **errmsg) {
|
||||
else if(!strcmp(s,"timeout"))
|
||||
co->connect_timeout = (unsigned int)atoi(seq+1);
|
||||
else if(!strcmp(s,"key"))
|
||||
co->key = strdup(seq+1);
|
||||
co->key = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ssl-key"))
|
||||
co->key = strdup(seq+1);
|
||||
co->key = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ca"))
|
||||
co->ca = strdup(seq+1);
|
||||
co->ca = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ssl-ca"))
|
||||
co->ca = strdup(seq+1);
|
||||
co->ca = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"capath"))
|
||||
co->capath = strdup(seq+1);
|
||||
co->capath = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ssl-capath"))
|
||||
co->capath = strdup(seq+1);
|
||||
co->capath = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"cert"))
|
||||
co->cert = strdup(seq+1);
|
||||
co->cert = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ssl-cert"))
|
||||
co->cert = strdup(seq+1);
|
||||
co->cert = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"cipher"))
|
||||
co->cipher = strdup(seq+1);
|
||||
co->cipher = turn_strdup(seq+1);
|
||||
else if(!strcmp(s,"ssl-cipher"))
|
||||
co->cipher = strdup(seq+1);
|
||||
co->cipher = turn_strdup(seq+1);
|
||||
else {
|
||||
MyconninfoFree(co);
|
||||
co = NULL;
|
||||
if(errmsg) {
|
||||
*errmsg = strdup(s);
|
||||
*errmsg = turn_strdup(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -176,13 +176,13 @@ static Myconninfo *MyconninfoParse(char *userdb, char **errmsg) {
|
||||
|
||||
if(co) {
|
||||
if(!(co->dbname))
|
||||
co->dbname=strdup("0");
|
||||
co->dbname=turn_strdup("0");
|
||||
if(!(co->host))
|
||||
co->host=strdup("127.0.0.1");
|
||||
co->host=turn_strdup("127.0.0.1");
|
||||
if(!(co->user))
|
||||
co->user=strdup("");
|
||||
co->user=turn_strdup("");
|
||||
if(!(co->password))
|
||||
co->password=strdup("");
|
||||
co->password=turn_strdup("");
|
||||
}
|
||||
|
||||
return co;
|
||||
@ -335,7 +335,9 @@ static int mysql_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
|
||||
}
|
||||
|
||||
static int mysql_get_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
int ret = 1;
|
||||
|
||||
int ret = -1;
|
||||
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"select password from turnusers_st where name='%s'",usname);
|
||||
|
||||
@ -372,9 +374,143 @@ static int mysql_get_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
|
||||
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key from oauth_key where kid='%s'",(const char*)kid);
|
||||
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
int res = mysql_query(myc, statement);
|
||||
if(res) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
|
||||
} else {
|
||||
MYSQL_RES *mres = mysql_store_result(myc);
|
||||
if(!mres) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
|
||||
} else if(mysql_field_count(myc)!=8) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
|
||||
} else {
|
||||
MYSQL_ROW row = mysql_fetch_row(mres);
|
||||
if(row && row[0]) {
|
||||
unsigned long *lengths = mysql_fetch_lengths(mres);
|
||||
if(lengths) {
|
||||
STRCPY((char*)key->kid,kid);
|
||||
ns_bcopy(row[0],key->ikm_key,lengths[0]);
|
||||
key->ikm_key[lengths[0]]=0;
|
||||
|
||||
char stimestamp[128];
|
||||
ns_bcopy(row[1],stimestamp,lengths[1]);
|
||||
stimestamp[lengths[1]]=0;
|
||||
key->timestamp = (u64bits)strtoull(stimestamp,NULL,10);
|
||||
|
||||
char slifetime[128];
|
||||
ns_bcopy(row[2],slifetime,lengths[2]);
|
||||
slifetime[lengths[2]]=0;
|
||||
key->lifetime = (u32bits)strtoul(slifetime,NULL,10);
|
||||
|
||||
ns_bcopy(row[3],key->hkdf_hash_func,lengths[3]);
|
||||
key->hkdf_hash_func[lengths[3]]=0;
|
||||
|
||||
ns_bcopy(row[4],key->as_rs_alg,lengths[4]);
|
||||
key->as_rs_alg[lengths[4]]=0;
|
||||
|
||||
ns_bcopy(row[5],key->as_rs_key,lengths[5]);
|
||||
key->as_rs_key[lengths[5]]=0;
|
||||
|
||||
ns_bcopy(row[6],key->auth_alg,lengths[6]);
|
||||
key->auth_alg[lengths[6]]=0;
|
||||
|
||||
ns_bcopy(row[7],key->auth_key,lengths[7]);
|
||||
key->auth_key[lengths[7]]=0;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mres)
|
||||
mysql_free_result(mres);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mysql_list_oauth_keys(void) {
|
||||
|
||||
oauth_key_data_raw key_;
|
||||
oauth_key_data_raw *key=&key_;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key,kid from oauth_key order by kid");
|
||||
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
int res = mysql_query(myc, statement);
|
||||
if(res) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
|
||||
} else {
|
||||
MYSQL_RES *mres = mysql_store_result(myc);
|
||||
if(!mres) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
|
||||
} else if(mysql_field_count(myc)!=9) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
|
||||
} else {
|
||||
MYSQL_ROW row = mysql_fetch_row(mres);
|
||||
while(row) {
|
||||
unsigned long *lengths = mysql_fetch_lengths(mres);
|
||||
if(lengths) {
|
||||
|
||||
ns_bcopy(row[0],key->ikm_key,lengths[0]);
|
||||
key->ikm_key[lengths[0]]=0;
|
||||
|
||||
char stimestamp[128];
|
||||
ns_bcopy(row[1],stimestamp,lengths[1]);
|
||||
stimestamp[lengths[1]]=0;
|
||||
key->timestamp = (u64bits)strtoull(stimestamp,NULL,10);
|
||||
|
||||
char slifetime[128];
|
||||
ns_bcopy(row[2],slifetime,lengths[2]);
|
||||
slifetime[lengths[2]]=0;
|
||||
key->lifetime = (u32bits)strtoul(slifetime,NULL,10);
|
||||
|
||||
ns_bcopy(row[3],key->hkdf_hash_func,lengths[3]);
|
||||
key->hkdf_hash_func[lengths[3]]=0;
|
||||
ns_bcopy(row[4],key->as_rs_alg,lengths[4]);
|
||||
key->as_rs_alg[lengths[4]]=0;
|
||||
|
||||
ns_bcopy(row[5],key->as_rs_key,lengths[5]);
|
||||
key->as_rs_key[lengths[5]]=0;
|
||||
|
||||
ns_bcopy(row[6],key->auth_alg,lengths[6]);
|
||||
key->auth_alg[lengths[6]]=0;
|
||||
|
||||
ns_bcopy(row[7],key->auth_key,lengths[7]);
|
||||
key->auth_key[lengths[7]]=0;
|
||||
|
||||
ns_bcopy(row[8],key->kid,lengths[8]);
|
||||
key->kid[lengths[8]]=0;
|
||||
|
||||
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n",
|
||||
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func,
|
||||
key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key);
|
||||
}
|
||||
row = mysql_fetch_row(mres);
|
||||
}
|
||||
}
|
||||
|
||||
if(mres)
|
||||
mysql_free_result(mres);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mysql_set_user_key(u08bits *usname, u08bits *realm, const char *key) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
@ -390,9 +526,30 @@ static int mysql_set_user_key(u08bits *usname, u08bits *realm, const char *key)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mysql_set_oauth_key(oauth_key_data_raw *key) {
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key) values('%s','%s',%llu,%lu,'%s','%s','%s','%s','%s')",
|
||||
key->kid,key->ikm_key,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,
|
||||
key->hkdf_hash_func,key->as_rs_alg,key->as_rs_key,key->auth_alg,key->auth_key);
|
||||
int res = mysql_query(myc, statement);
|
||||
if(res) {
|
||||
snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, hkdf_hash_func = '%s', as_rs_alg='%s',as_rs_key='%s',auth_alg='%s',auth_key='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
|
||||
key->hkdf_hash_func,key->as_rs_alg,key->as_rs_key,key->auth_alg,key->auth_key,key->kid);
|
||||
res = mysql_query(myc, statement);
|
||||
if(res) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating oauth key information: %s\n",mysql_error(myc));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mysql_set_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
@ -412,7 +569,7 @@ static int mysql_set_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
}
|
||||
|
||||
static int mysql_del_user(u08bits *usname, int is_st, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
@ -430,9 +587,25 @@ static int mysql_del_user(u08bits *usname, int is_st, u08bits *realm) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mysql_del_oauth_key(const u08bits *kid) {
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
snprintf(statement,sizeof(statement),"delete from oauth_key where kid = '%s'",(const char*)kid);
|
||||
int res = mysql_query(myc, statement);
|
||||
if(res) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting oauth key information: %s\n",mysql_error(myc));
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mysql_list_users(int is_st, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
@ -478,7 +651,7 @@ static int mysql_list_users(int is_st, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int mysql_show_secret(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
|
||||
|
||||
@ -517,7 +690,7 @@ static int mysql_show_secret(u08bits *realm) {
|
||||
}
|
||||
|
||||
static int mysql_del_secret(u08bits *secret, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success=1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
@ -533,7 +706,7 @@ static int mysql_del_secret(u08bits *secret, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int mysql_set_secret(u08bits *secret, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
@ -553,7 +726,7 @@ static int mysql_set_secret(u08bits *secret, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int mysql_add_origin(u08bits *origin, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if (myc) {
|
||||
@ -572,7 +745,7 @@ static int mysql_add_origin(u08bits *origin, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int mysql_del_origin(u08bits *origin) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if (myc) {
|
||||
@ -591,7 +764,7 @@ static int mysql_del_origin(u08bits *origin) {
|
||||
}
|
||||
|
||||
static int mysql_list_origins(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
@ -632,7 +805,7 @@ static int mysql_list_origins(u08bits *realm) {
|
||||
}
|
||||
|
||||
static int mysql_set_realm_option_one(u08bits *realm, unsigned long value, const char* opt) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if (myc) {
|
||||
@ -657,7 +830,7 @@ static int mysql_set_realm_option_one(u08bits *realm, unsigned long value, const
|
||||
}
|
||||
|
||||
static int mysql_list_realm_options(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
@ -719,7 +892,7 @@ static void mysql_auth_ping(void * rch) {
|
||||
}
|
||||
|
||||
static int mysql_get_ip_list(const char *kind, ip_range_list_t * list) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
MYSQL * myc = get_mydb_connection();
|
||||
if(myc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
@ -745,7 +918,7 @@ static int mysql_get_ip_list(const char *kind, ip_range_list_t * list) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if(mres)
|
||||
@ -766,7 +939,7 @@ static void mysql_reread_realms(secrets_list_t * realms_list) {
|
||||
MYSQL_RES *mres = mysql_store_result(myc);
|
||||
if(mres && mysql_field_count(myc)==2) {
|
||||
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(free);
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(turn_free_simple);
|
||||
|
||||
for(;;) {
|
||||
MYSQL_ROW row = mysql_fetch_row(mres);
|
||||
@ -780,7 +953,7 @@ static void mysql_reread_realms(secrets_list_t * realms_list) {
|
||||
char oval[513];
|
||||
ns_bcopy(row[0],oval,sz);
|
||||
oval[sz]=0;
|
||||
char *rval=strdup(row[1]);
|
||||
char *rval=turn_strdup(row[1]);
|
||||
get_realm(rval);
|
||||
ur_string_map_value_type value = (ur_string_map_value_type)rval;
|
||||
ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type) oval, value);
|
||||
@ -893,7 +1066,11 @@ static turn_dbdriver_t driver = {
|
||||
&mysql_list_realm_options,
|
||||
&mysql_auth_ping,
|
||||
&mysql_get_ip_list,
|
||||
&mysql_reread_realms
|
||||
&mysql_reread_realms,
|
||||
&mysql_set_oauth_key,
|
||||
&mysql_get_oauth_key,
|
||||
&mysql_del_oauth_key,
|
||||
&mysql_list_oauth_keys
|
||||
};
|
||||
|
||||
turn_dbdriver_t * get_mysql_dbdriver(void) {
|
||||
|
||||
@ -86,7 +86,7 @@ static PGconn *get_pqdb_connection(void) {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int pgsql_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
PGconn * pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
@ -114,7 +114,7 @@ static int pgsql_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int pgsql_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
PGconn * pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
@ -148,7 +148,7 @@ static int pgsql_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
|
||||
}
|
||||
|
||||
static int pgsql_get_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"select password from turnusers_st where name='%s'",usname);
|
||||
|
||||
@ -174,9 +174,89 @@ static int pgsql_get_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
|
||||
|
||||
int ret = -1;
|
||||
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key from oauth_key where kid='%s'",(const char*)kid);
|
||||
|
||||
PGconn * pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
PGresult *res = PQexec(pqc, statement);
|
||||
|
||||
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res)!=1)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
|
||||
} else {
|
||||
STRCPY((char*)key->ikm_key,PQgetvalue(res,0,0));
|
||||
key->timestamp = (u64bits)strtoll(PQgetvalue(res,0,1),NULL,10);
|
||||
key->lifetime = (u32bits)strtol(PQgetvalue(res,0,2),NULL,10);
|
||||
STRCPY((char*)key->hkdf_hash_func,PQgetvalue(res,0,3));
|
||||
STRCPY((char*)key->as_rs_alg,PQgetvalue(res,0,4));
|
||||
STRCPY((char*)key->as_rs_key,PQgetvalue(res,0,5));
|
||||
STRCPY((char*)key->auth_alg,PQgetvalue(res,0,6));
|
||||
STRCPY((char*)key->auth_key,PQgetvalue(res,0,7));
|
||||
STRCPY((char*)key->kid,kid);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if(res) {
|
||||
PQclear(res);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pgsql_list_oauth_keys(void) {
|
||||
|
||||
oauth_key_data_raw key_;
|
||||
oauth_key_data_raw *key=&key_;
|
||||
|
||||
int ret = -1;
|
||||
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key,kid from oauth_key order by kid");
|
||||
|
||||
PGconn * pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
PGresult *res = PQexec(pqc, statement);
|
||||
|
||||
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
|
||||
} else {
|
||||
int i = 0;
|
||||
for(i=0;i<PQntuples(res);i++) {
|
||||
|
||||
STRCPY((char*)key->ikm_key,PQgetvalue(res,i,0));
|
||||
key->timestamp = (u64bits)strtoll(PQgetvalue(res,i,1),NULL,10);
|
||||
key->lifetime = (u32bits)strtol(PQgetvalue(res,i,2),NULL,10);
|
||||
STRCPY((char*)key->hkdf_hash_func,PQgetvalue(res,i,3));
|
||||
STRCPY((char*)key->as_rs_alg,PQgetvalue(res,i,4));
|
||||
STRCPY((char*)key->as_rs_key,PQgetvalue(res,i,5));
|
||||
STRCPY((char*)key->auth_alg,PQgetvalue(res,i,6));
|
||||
STRCPY((char*)key->auth_key,PQgetvalue(res,i,7));
|
||||
STRCPY((char*)key->kid,PQgetvalue(res,i,8));
|
||||
|
||||
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n",
|
||||
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func,
|
||||
key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(res) {
|
||||
PQclear(res);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pgsql_set_user_key(u08bits *usname, u08bits *realm, const char *key) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
@ -201,9 +281,40 @@ static int pgsql_set_user_key(u08bits *usname, u08bits *realm, const char *key)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int pgsql_set_oauth_key(oauth_key_data_raw *key) {
|
||||
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key) values('%s','%s',%llu,%lu,'%s','%s','%s','%s','%s')",
|
||||
key->kid,key->ikm_key,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,
|
||||
key->hkdf_hash_func,key->as_rs_alg,key->as_rs_key,key->auth_alg,key->auth_key);
|
||||
|
||||
PGresult *res = PQexec(pqc, statement);
|
||||
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
|
||||
if(res) {
|
||||
PQclear(res);
|
||||
}
|
||||
snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, hkdf_hash_func = '%s', as_rs_alg='%s',as_rs_key='%s',auth_alg='%s',auth_key='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
|
||||
key->hkdf_hash_func,key->as_rs_alg,key->as_rs_key,key->auth_alg,key->auth_key,key->kid);
|
||||
res = PQexec(pqc, statement);
|
||||
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating oauth_key information: %s\n",PQerrorMessage(pqc));
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
if(res) {
|
||||
PQclear(res);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pgsql_set_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
@ -229,7 +340,7 @@ static int pgsql_set_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
}
|
||||
|
||||
static int pgsql_del_user(u08bits *usname, int is_st, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
@ -246,9 +357,30 @@ static int pgsql_del_user(u08bits *usname, int is_st, u08bits *realm) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pgsql_del_oauth_key(const u08bits *kid) {
|
||||
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
snprintf(statement,sizeof(statement),"delete from oauth_key where kid = '%s'",(const char*)kid);
|
||||
|
||||
PGresult *res = PQexec(pqc, statement);
|
||||
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting oauth_key information: %s\n",PQerrorMessage(pqc));
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
if(res) {
|
||||
PQclear(res);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pgsql_list_users(int is_st, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
@ -285,7 +417,7 @@ static int pgsql_list_users(int is_st, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int pgsql_show_secret(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
|
||||
|
||||
@ -314,7 +446,7 @@ static int pgsql_show_secret(u08bits *realm) {
|
||||
}
|
||||
|
||||
static int pgsql_del_secret(u08bits *secret, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success=1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
@ -334,7 +466,7 @@ static int pgsql_del_secret(u08bits *secret, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int pgsql_set_secret(u08bits *secret, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
@ -358,7 +490,7 @@ static int pgsql_set_secret(u08bits *secret, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int pgsql_add_origin(u08bits *origin, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
@ -377,7 +509,7 @@ static int pgsql_add_origin(u08bits *origin, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int pgsql_del_origin(u08bits *origin) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
@ -396,7 +528,7 @@ static int pgsql_del_origin(u08bits *origin) {
|
||||
}
|
||||
|
||||
static int pgsql_list_origins(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
@ -430,7 +562,7 @@ static int pgsql_list_origins(u08bits *realm) {
|
||||
}
|
||||
|
||||
static int pgsql_set_realm_option_one(u08bits *realm, unsigned long value, const char* opt) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
@ -458,7 +590,7 @@ static int pgsql_set_realm_option_one(u08bits *realm, unsigned long value, const
|
||||
}
|
||||
|
||||
static int pgsql_list_realm_options(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
PGconn *pqc = get_pqdb_connection();
|
||||
@ -514,7 +646,7 @@ static void pgsql_auth_ping(void * rch) {
|
||||
}
|
||||
|
||||
static int pgsql_get_ip_list(const char *kind, ip_range_list_t * list) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
PGconn * pqc = get_pqdb_connection();
|
||||
if(pqc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
@ -550,7 +682,7 @@ static void pgsql_reread_realms(secrets_list_t * realms_list) {
|
||||
|
||||
if(res && (PQresultStatus(res) == PGRES_TUPLES_OK)) {
|
||||
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(free);
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(turn_free_simple);
|
||||
|
||||
int i = 0;
|
||||
for(i=0;i<PQntuples(res);i++) {
|
||||
@ -559,7 +691,7 @@ static void pgsql_reread_realms(secrets_list_t * realms_list) {
|
||||
char *rval = PQgetvalue(res,i,1);
|
||||
if(rval) {
|
||||
get_realm(rval);
|
||||
ur_string_map_value_type value = strdup(rval);
|
||||
ur_string_map_value_type value = turn_strdup(rval);
|
||||
ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type) oval, value);
|
||||
}
|
||||
}
|
||||
@ -655,7 +787,11 @@ static turn_dbdriver_t driver = {
|
||||
&pgsql_list_realm_options,
|
||||
&pgsql_auth_ping,
|
||||
&pgsql_get_ip_list,
|
||||
&pgsql_reread_realms
|
||||
&pgsql_reread_realms,
|
||||
&pgsql_set_oauth_key,
|
||||
&pgsql_get_oauth_key,
|
||||
&pgsql_del_oauth_key,
|
||||
&pgsql_list_oauth_keys
|
||||
};
|
||||
|
||||
turn_dbdriver_t * get_pgsql_dbdriver(void) {
|
||||
|
||||
@ -59,7 +59,7 @@ typedef struct _Ryconninfo Ryconninfo;
|
||||
static void RyconninfoFree(Ryconninfo *co) {
|
||||
if(co) {
|
||||
if(co->host) turn_free(co->host, strlen(co->host)+1);
|
||||
if(co->dbname) turn_free(co->dbname, strlen(co->username)+1);
|
||||
if(co->dbname) turn_free(co->dbname, strlen(co->dbname)+1);
|
||||
if(co->password) turn_free(co->password, strlen(co->password)+1);
|
||||
ns_bzero(co,sizeof(Ryconninfo));
|
||||
}
|
||||
@ -69,7 +69,7 @@ static Ryconninfo *RyconninfoParse(const char *userdb, char **errmsg) {
|
||||
Ryconninfo *co = (Ryconninfo*) turn_malloc(sizeof(Ryconninfo));
|
||||
ns_bzero(co,sizeof(Ryconninfo));
|
||||
if (userdb) {
|
||||
char *s0 = strdup(userdb);
|
||||
char *s0 = turn_strdup(userdb);
|
||||
char *s = s0;
|
||||
|
||||
while (s && *s) {
|
||||
@ -87,28 +87,28 @@ static Ryconninfo *RyconninfoParse(const char *userdb, char **errmsg) {
|
||||
RyconninfoFree(co);
|
||||
co = NULL;
|
||||
if (errmsg) {
|
||||
*errmsg = strdup(s);
|
||||
*errmsg = turn_strdup(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*seq = 0;
|
||||
if (!strcmp(s, "host"))
|
||||
co->host = strdup(seq + 1);
|
||||
co->host = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "ip"))
|
||||
co->host = strdup(seq + 1);
|
||||
co->host = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "addr"))
|
||||
co->host = strdup(seq + 1);
|
||||
co->host = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "ipaddr"))
|
||||
co->host = strdup(seq + 1);
|
||||
co->host = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "hostaddr"))
|
||||
co->host = strdup(seq + 1);
|
||||
co->host = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "dbname"))
|
||||
co->dbname = strdup(seq + 1);
|
||||
co->dbname = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "db"))
|
||||
co->dbname = strdup(seq + 1);
|
||||
co->dbname = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "database"))
|
||||
co->dbname = strdup(seq + 1);
|
||||
co->dbname = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "user"))
|
||||
;
|
||||
else if (!strcmp(s, "uname"))
|
||||
@ -118,13 +118,13 @@ static Ryconninfo *RyconninfoParse(const char *userdb, char **errmsg) {
|
||||
else if (!strcmp(s, "username"))
|
||||
;
|
||||
else if (!strcmp(s, "password"))
|
||||
co->password = strdup(seq + 1);
|
||||
co->password = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "pwd"))
|
||||
co->password = strdup(seq + 1);
|
||||
co->password = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "passwd"))
|
||||
co->password = strdup(seq + 1);
|
||||
co->password = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "secret"))
|
||||
co->password = strdup(seq + 1);
|
||||
co->password = turn_strdup(seq + 1);
|
||||
else if (!strcmp(s, "port"))
|
||||
co->port = (unsigned int) atoi(seq + 1);
|
||||
else if (!strcmp(s, "p"))
|
||||
@ -137,7 +137,7 @@ static Ryconninfo *RyconninfoParse(const char *userdb, char **errmsg) {
|
||||
RyconninfoFree(co);
|
||||
co = NULL;
|
||||
if (errmsg) {
|
||||
*errmsg = strdup(s);
|
||||
*errmsg = turn_strdup(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -150,11 +150,11 @@ static Ryconninfo *RyconninfoParse(const char *userdb, char **errmsg) {
|
||||
|
||||
if(co) {
|
||||
if(!(co->dbname))
|
||||
co->dbname=strdup("0");
|
||||
co->dbname=turn_strdup("0");
|
||||
if(!(co->host))
|
||||
co->host=strdup("127.0.0.1");
|
||||
co->host=turn_strdup("127.0.0.1");
|
||||
if(!(co->password))
|
||||
co->password=strdup("");
|
||||
co->password=turn_strdup("");
|
||||
}
|
||||
|
||||
return co;
|
||||
@ -268,7 +268,7 @@ static redisContext *get_redis_connection(void) {
|
||||
|
||||
if(redisconnection) {
|
||||
if(redisconnection->err) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot connect to redis, err=%d, flags=0x%x\n", __FUNCTION__,(int)redisconnection->err,(unsigned long)redisconnection->flags);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot connect to redis, err=%d, flags=0x%lx\n", __FUNCTION__,(int)redisconnection->err,(unsigned long)redisconnection->flags);
|
||||
redisFree(redisconnection);
|
||||
pud->connection = NULL;
|
||||
redisconnection = NULL;
|
||||
@ -397,7 +397,7 @@ static int set_redis_realm_opt(char *realm, const char* key, unsigned long *valu
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int redis_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
redisReply *reply = (redisReply*)redisCommand(rc, "keys turn/realm/%s/secret/*", (char*)realm);
|
||||
@ -448,7 +448,7 @@ static int redis_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int redis_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext * rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char s[TURN_LONG_STRING_SIZE];
|
||||
@ -472,7 +472,7 @@ static int redis_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
|
||||
}
|
||||
turnFreeRedisReply(rget);
|
||||
}
|
||||
if(ret != 0) {
|
||||
if(ret == 0) {
|
||||
snprintf(s,sizeof(s),"get turn/realm/%s/user/%s/password", (char*)realm, usname);
|
||||
rget = (redisReply *)redisCommand(rc, s);
|
||||
if(rget) {
|
||||
@ -492,9 +492,57 @@ static int redis_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
|
||||
int ret = -1;
|
||||
redisContext * rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char s[TURN_LONG_STRING_SIZE];
|
||||
ns_bzero(key,sizeof(oauth_key_data_raw));
|
||||
STRCPY(key->kid,kid);
|
||||
snprintf(s,sizeof(s),"hgetall turn/oauth/kid/%s", (const char*)kid);
|
||||
redisReply *reply = (redisReply *)redisCommand(rc, s);
|
||||
if(reply) {
|
||||
if (reply->type == REDIS_REPLY_ERROR)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error: %s\n", reply->str);
|
||||
else if (reply->type != REDIS_REPLY_ARRAY) {
|
||||
if (reply->type != REDIS_REPLY_NIL)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unexpected type: %d\n", reply->type);
|
||||
} else if(reply->elements > 1) {
|
||||
size_t i;
|
||||
for (i = 0; i < (reply->elements)/2; ++i) {
|
||||
char *kw = reply->element[2*i]->str;
|
||||
char *val = reply->element[2*i+1]->str;
|
||||
if(kw) {
|
||||
if(!strcmp(kw,"as_rs_alg")) {
|
||||
STRCPY(key->as_rs_alg,val);
|
||||
} else if(!strcmp(kw,"as_rs_key")) {
|
||||
STRCPY(key->as_rs_key,val);
|
||||
} else if(!strcmp(kw,"auth_key")) {
|
||||
STRCPY(key->auth_key,val);
|
||||
} else if(!strcmp(kw,"auth_alg")) {
|
||||
STRCPY(key->auth_alg,val);
|
||||
} else if(!strcmp(kw,"ikm_key")) {
|
||||
STRCPY(key->ikm_key,val);
|
||||
} else if(!strcmp(kw,"hkdf_hash_func")) {
|
||||
STRCPY(key->hkdf_hash_func,val);
|
||||
} else if(!strcmp(kw,"timestamp")) {
|
||||
key->timestamp = (u64bits)strtoull(val,NULL,10);
|
||||
} else if(!strcmp(kw,"lifetime")) {
|
||||
key->lifetime = (u32bits)strtoul(val,NULL,10);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
turnFreeRedisReply(reply);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_get_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext * rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char s[TURN_LONG_STRING_SIZE];
|
||||
@ -518,7 +566,7 @@ static int redis_get_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
}
|
||||
|
||||
static int redis_set_user_key(u08bits *usname, u08bits *realm, const char *key) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
@ -531,22 +579,36 @@ static int redis_set_user_key(u08bits *usname, u08bits *realm, const char *key)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_set_oauth_key(oauth_key_data_raw *key) {
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"hmset turn/oauth/kid/%s ikm_key '%s' hkdf_hash_func '%s' as_rs_alg '%s' as_rs_key '%s' auth_alg '%s' auth_key '%s' timestamp %llu lifetime %lu",
|
||||
key->kid,key->ikm_key,key->hkdf_hash_func,key->as_rs_alg,key->as_rs_key,key->auth_alg,key->auth_key,(unsigned long long)key->timestamp,(unsigned long)key->lifetime);
|
||||
turnFreeRedisReply(redisCommand(rc, statement));
|
||||
turnFreeRedisReply(redisCommand(rc, "save"));
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_set_user_pwd(u08bits *usname, st_password_t pwd) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"set turn/user/%s/password %s",usname,pwd);
|
||||
turnFreeRedisReply(redisCommand(rc, statement));
|
||||
snprintf(statement,sizeof(statement),"set turn/user/%s/password %s",usname,pwd);
|
||||
turnFreeRedisReply(redisCommand(rc, statement));
|
||||
turnFreeRedisReply(redisCommand(rc, "save"));
|
||||
ret = 0;
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_del_user(u08bits *usname, int is_st, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
@ -565,9 +627,22 @@ static int redis_del_user(u08bits *usname, int is_st, u08bits *realm) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_del_oauth_key(const u08bits *kid) {
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
snprintf(statement,sizeof(statement),"del turn/oauth/kid/%s",(const char*)kid);
|
||||
turnFreeRedisReply(redisCommand(rc, statement));
|
||||
turnFreeRedisReply(redisCommand(rc, "save"));
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_list_users(int is_st, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
secrets_list_t keys;
|
||||
@ -656,9 +731,57 @@ static int redis_list_users(int is_st, u08bits *realm) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_list_oauth_keys(void) {
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
secrets_list_t keys;
|
||||
size_t isz = 0;
|
||||
init_secrets_list(&keys);
|
||||
|
||||
if(rc) {
|
||||
|
||||
redisReply *reply = NULL;
|
||||
|
||||
reply = (redisReply*)redisCommand(rc, "keys turn/oauth/kid/*");
|
||||
if(reply) {
|
||||
|
||||
if (reply->type == REDIS_REPLY_ERROR) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error: %s\n", reply->str);
|
||||
} else if (reply->type != REDIS_REPLY_ARRAY) {
|
||||
if (reply->type != REDIS_REPLY_NIL) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unexpected type: %d\n", reply->type);
|
||||
}
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < reply->elements; ++i) {
|
||||
add_to_secrets_list(&keys,reply->element[i]->str);
|
||||
}
|
||||
}
|
||||
turnFreeRedisReply(reply);
|
||||
}
|
||||
}
|
||||
|
||||
for(isz=0;isz<keys.sz;++isz) {
|
||||
char *s = keys.secrets[isz];
|
||||
s += strlen("turn/oauth/kid/");
|
||||
oauth_key_data_raw key_;
|
||||
oauth_key_data_raw *key=&key_;
|
||||
if(redis_get_oauth_key((const u08bits*)s,key) == 0) {
|
||||
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n",
|
||||
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func,
|
||||
key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key);
|
||||
}
|
||||
}
|
||||
|
||||
clean_secrets_list(&keys);
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redis_show_secret(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
@ -713,7 +836,7 @@ static int redis_show_secret(u08bits *realm) {
|
||||
}
|
||||
|
||||
static int redis_del_secret(u08bits *secret, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
@ -773,7 +896,7 @@ static int redis_del_secret(u08bits *secret, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int redis_set_secret(u08bits *secret, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
@ -791,7 +914,7 @@ static int redis_set_secret(u08bits *secret, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int redis_add_origin(u08bits *origin, u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char s[TURN_LONG_STRING_SIZE];
|
||||
@ -806,7 +929,7 @@ static int redis_add_origin(u08bits *origin, u08bits *realm) {
|
||||
}
|
||||
|
||||
static int redis_del_origin(u08bits *origin) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char s[TURN_LONG_STRING_SIZE];
|
||||
@ -821,7 +944,7 @@ static int redis_del_origin(u08bits *origin) {
|
||||
}
|
||||
|
||||
static int redis_list_origins(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
@ -879,7 +1002,7 @@ static int redis_list_origins(u08bits *realm) {
|
||||
}
|
||||
|
||||
static int redis_set_realm_option_one(u08bits *realm, unsigned long value, const char* opt) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char s[TURN_LONG_STRING_SIZE];
|
||||
@ -897,7 +1020,7 @@ static int redis_set_realm_option_one(u08bits *realm, unsigned long value, const
|
||||
}
|
||||
|
||||
static int redis_list_realm_options(u08bits *realm) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
donot_print_connection_success = 1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
@ -972,7 +1095,7 @@ static void redis_auth_ping(void * rch) {
|
||||
}
|
||||
|
||||
static int redis_get_ip_list(const char *kind, ip_range_list_t * list) {
|
||||
int ret = 1;
|
||||
int ret = -1;
|
||||
redisContext *rc = get_redis_connection();
|
||||
if(rc) {
|
||||
char statement[TURN_LONG_STRING_SIZE];
|
||||
@ -1029,7 +1152,7 @@ static void redis_reread_realms(secrets_list_t * realms_list) {
|
||||
redisReply *reply = (redisReply*) redisCommand(rc, "keys turn/origin/*");
|
||||
if (reply) {
|
||||
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(free);
|
||||
ur_string_map *o_to_realm_new = ur_string_map_create(turn_free_simple);
|
||||
|
||||
secrets_list_t keys;
|
||||
|
||||
@ -1065,7 +1188,7 @@ static void redis_reread_realms(secrets_list_t * realms_list) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unexpected type: %d\n", rget->type);
|
||||
} else {
|
||||
get_realm(rget->str);
|
||||
ur_string_map_value_type value = strdup(rget->str);
|
||||
ur_string_map_value_type value = turn_strdup(rget->str);
|
||||
ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type) origin, value);
|
||||
}
|
||||
turnFreeRedisReply(rget);
|
||||
@ -1134,7 +1257,11 @@ static turn_dbdriver_t driver = {
|
||||
&redis_list_realm_options,
|
||||
&redis_auth_ping,
|
||||
&redis_get_ip_list,
|
||||
&redis_reread_realms
|
||||
&redis_reread_realms,
|
||||
&redis_set_oauth_key,
|
||||
&redis_get_oauth_key,
|
||||
&redis_del_oauth_key,
|
||||
&redis_list_oauth_keys
|
||||
};
|
||||
|
||||
turn_dbdriver_t * get_redis_dbdriver(void) {
|
||||
|
||||
@ -30,6 +30,9 @@
|
||||
*/
|
||||
|
||||
#include "../mainrelay.h"
|
||||
|
||||
#include "apputils.h"
|
||||
|
||||
#include "dbdriver.h"
|
||||
#include "dbd_pgsql.h"
|
||||
#include "dbd_mysql.h"
|
||||
@ -86,5 +89,3 @@ turn_dbdriver_t * get_dbdriver() {
|
||||
return _driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -34,6 +34,8 @@
|
||||
|
||||
#include "../userdb.h"
|
||||
|
||||
#include "ns_turn_msg_defs_new.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -59,6 +61,10 @@ typedef struct _turn_dbdriver_t {
|
||||
void (*auth_ping)(void * rch);
|
||||
int (*get_ip_list)(const char *kind, ip_range_list_t * list);
|
||||
void (*reread_realms)(secrets_list_t * realms_list);
|
||||
int (*set_oauth_key)(oauth_key_data_raw *key);
|
||||
int (*get_oauth_key)(const u08bits *kid, oauth_key_data_raw *key);
|
||||
int (*del_oauth_key)(const u08bits *kid);
|
||||
int (*list_oauth_keys)(void);
|
||||
} turn_dbdriver_t;
|
||||
|
||||
/////////// USER DB CHECK //////////////////
|
||||
|
||||
@ -229,9 +229,6 @@ static ioa_socket_handle dtls_accept_client_connection(
|
||||
|
||||
ioa_socket_handle ioas = create_ioa_socket_from_ssl(server->e, sock, ssl, DTLS_SOCKET, CLIENT_SOCKET, remote_addr, local_addr);
|
||||
if(ioas) {
|
||||
|
||||
ioas->listener_server = server;
|
||||
|
||||
addr_cpy(&(server->sm.m.sm.nd.src_addr),remote_addr);
|
||||
server->sm.m.sm.nd.recv_ttl = TTL_IGNORE;
|
||||
server->sm.m.sm.nd.recv_tos = TOS_IGNORE;
|
||||
@ -437,7 +434,6 @@ static int handle_udp_packet(dtls_listener_relay_server_type *server,
|
||||
__FUNCTION__, (char*) saddr,(char*) rsaddr);
|
||||
}
|
||||
s->e = ioa_eng;
|
||||
s->listener_server = server;
|
||||
add_socket_to_map(s, amap);
|
||||
open_client_connection_session(ts, &(sm->m.sm));
|
||||
}
|
||||
@ -565,7 +561,6 @@ static int create_new_connected_udp_socket(
|
||||
"Accepted DTLS connection from");
|
||||
|
||||
ret->ssl = connecting_ssl;
|
||||
ret->listener_server = server;
|
||||
|
||||
ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh);
|
||||
server->sm.m.sm.nd.nbh = NULL;
|
||||
@ -583,9 +578,8 @@ static void udp_server_input_handler(evutil_socket_t fd, short what, void* arg)
|
||||
{
|
||||
int cycle = 0;
|
||||
|
||||
ioa_socket_handle s = (ioa_socket_handle)arg;
|
||||
|
||||
dtls_listener_relay_server_type* server = (dtls_listener_relay_server_type*)s->listener_server;
|
||||
dtls_listener_relay_server_type* server = (dtls_listener_relay_server_type*)arg;
|
||||
ioa_socket_handle s = server->udp_listen_s;
|
||||
|
||||
FUNCSTART;
|
||||
|
||||
@ -726,8 +720,6 @@ static int create_server_socket(dtls_listener_relay_server_type* server, int rep
|
||||
|
||||
server->udp_listen_s = create_ioa_socket_from_fd(server->e, udp_listen_fd, NULL, UDP_SOCKET, LISTENER_SOCKET, NULL, &(server->addr));
|
||||
|
||||
server->udp_listen_s->listener_server = server;
|
||||
|
||||
set_sock_buf_size(udp_listen_fd,UR_SERVER_SOCK_BUF_SIZE);
|
||||
|
||||
if(sock_bind_to_device(udp_listen_fd, (unsigned char*)server->ifname)<0) {
|
||||
@ -756,7 +748,7 @@ static int create_server_socket(dtls_listener_relay_server_type* server, int rep
|
||||
|
||||
server->udp_listen_ev = event_new(server->e->event_base,udp_listen_fd,
|
||||
EV_READ|EV_PERSIST,udp_server_input_handler,
|
||||
server->udp_listen_s);
|
||||
server);
|
||||
|
||||
event_add(server->udp_listen_ev,NULL);
|
||||
}
|
||||
@ -827,7 +819,7 @@ static int reopen_server_socket(dtls_listener_relay_server_type* server, evutil_
|
||||
|
||||
server->udp_listen_ev = event_new(server->e->event_base, udp_listen_fd,
|
||||
EV_READ | EV_PERSIST, udp_server_input_handler,
|
||||
server->udp_listen_s);
|
||||
server);
|
||||
|
||||
event_add(server->udp_listen_ev, NULL );
|
||||
}
|
||||
|
||||
@ -85,6 +85,7 @@ LOW_DEFAULT_PORTS_BOUNDARY,HIGH_DEFAULT_PORTS_BOUNDARY,0,0,0,"",
|
||||
0,NULL,0,NULL,DEFAULT_GENERAL_RELAY_SERVERS_NUMBER,0,
|
||||
////////////// Auth server /////////////////////////////////////
|
||||
{NULL,NULL,NULL,0,NULL},
|
||||
"","",0,
|
||||
/////////////// AUX SERVERS ////////////////
|
||||
{NULL,0,{0,NULL}},0,
|
||||
/////////////// ALTERNATE SERVERS ////////////////
|
||||
@ -463,6 +464,10 @@ static char Usage[] = "Usage: turnserver [options]\n"
|
||||
" That database value can be changed on-the-fly\n"
|
||||
" by a separate program, so this is why it is 'dynamic'.\n"
|
||||
" Multiple shared secrets can be used (both in the database and in the \"static\" fashion).\n"
|
||||
" --server-name Server name used for\n"
|
||||
" the oAuth authentication purposes.\n"
|
||||
" The default value is the realm name.\n"
|
||||
" --oauth Support oAuth authentication.\n"
|
||||
" -n Do not use configuration file, take all parameters from the command line only.\n"
|
||||
" --cert <filename> Certificate file, PEM format. Same file search rules\n"
|
||||
" applied as for the configuration file.\n"
|
||||
@ -677,7 +682,9 @@ enum EXTRA_OPTS {
|
||||
CHECK_ORIGIN_CONSISTENCY_OPT,
|
||||
ADMIN_MAX_BPS_OPT,
|
||||
ADMIN_TOTAL_QUOTA_OPT,
|
||||
ADMIN_USER_QUOTA_OPT
|
||||
ADMIN_USER_QUOTA_OPT,
|
||||
SERVER_NAME_OPT,
|
||||
OAUTH_OPT
|
||||
};
|
||||
|
||||
struct myoption {
|
||||
@ -731,6 +738,8 @@ static const struct myoption long_options[] = {
|
||||
{ "static-auth-secret", required_argument, NULL, STATIC_AUTH_SECRET_VAL_OPT },
|
||||
/* deprecated: */ { "secret-ts-exp-time", optional_argument, NULL, AUTH_SECRET_TS_EXP },
|
||||
{ "realm", required_argument, NULL, 'r' },
|
||||
{ "server-name", required_argument, NULL, SERVER_NAME_OPT },
|
||||
{ "oauth", optional_argument, NULL, OAUTH_OPT },
|
||||
{ "user-quota", required_argument, NULL, 'q' },
|
||||
{ "total-quota", required_argument, NULL, 'Q' },
|
||||
{ "max-bps", required_argument, NULL, 's' },
|
||||
@ -859,6 +868,12 @@ static void set_option(int c, char *value)
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case SERVER_NAME_OPT:
|
||||
STRCPY(turn_params.oauth_server_name,value);
|
||||
break;
|
||||
case OAUTH_OPT:
|
||||
turn_params.oauth = get_bool_value(value);
|
||||
break;
|
||||
case NO_SSLV2_OPT:
|
||||
turn_params.no_sslv2 = get_bool_value(value);
|
||||
break;
|
||||
@ -1019,7 +1034,7 @@ static void set_option(int c, char *value)
|
||||
if(value) {
|
||||
char *div = strchr(value,'/');
|
||||
if(div) {
|
||||
char *nval=strdup(value);
|
||||
char *nval=turn_strdup(value);
|
||||
div = strchr(nval,'/');
|
||||
div[0]=0;
|
||||
++div;
|
||||
@ -1556,7 +1571,6 @@ static int adminmain(int argc, char **argv)
|
||||
static void print_features(unsigned long mfn)
|
||||
{
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\nRFC 3489/5389/5766/5780/6062/6156 STUN/TURN Server\nVersion %s\n",TURN_SOFTWARE);
|
||||
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\nMax number of open files/sockets allowed for this process: %lu\n",mfn);
|
||||
if(turn_params.net_engine_version == 1)
|
||||
mfn = mfn/3;
|
||||
@ -1581,6 +1595,12 @@ static void print_features(unsigned long mfn)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "DTLS supported\n");
|
||||
#endif
|
||||
|
||||
#if defined(TURN_NO_GCM)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "AEAD is not supported\n");
|
||||
#else
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "AEAD supported\n");
|
||||
#endif
|
||||
|
||||
#if !defined(TURN_NO_HIREDIS)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Redis supported\n");
|
||||
#else
|
||||
@ -1678,6 +1698,15 @@ static void drop_privileges(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void init_domain(void)
|
||||
{
|
||||
#if !defined(TURN_NO_GETDOMAINNAME)
|
||||
getdomainname(turn_params.domain,sizeof(turn_params.domain)-1);
|
||||
if(!strcmp(turn_params.domain,"(none)"))
|
||||
turn_params.domain[0]=0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c = 0;
|
||||
@ -1692,7 +1721,8 @@ int main(int argc, char **argv)
|
||||
redis_async_init();
|
||||
#endif
|
||||
|
||||
create_new_realm(NULL);
|
||||
init_domain();
|
||||
create_default_realm();
|
||||
|
||||
init_turn_server_addrs_list(&turn_params.alternate_servers_list);
|
||||
init_turn_server_addrs_list(&turn_params.tls_alternate_servers_list);
|
||||
@ -1755,8 +1785,8 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
ns_bzero(&turn_params.default_users_db,sizeof(default_users_db_t));
|
||||
turn_params.default_users_db.ram_db.static_accounts = ur_string_map_create(free);
|
||||
turn_params.default_users_db.ram_db.dynamic_accounts = ur_string_map_create(free);
|
||||
turn_params.default_users_db.ram_db.static_accounts = ur_string_map_create(turn_free_simple);
|
||||
turn_params.default_users_db.ram_db.dynamic_accounts = ur_string_map_create(turn_free_simple);
|
||||
|
||||
if(strstr(argv[0],"turnadmin"))
|
||||
return adminmain(argc,argv);
|
||||
@ -1779,6 +1809,16 @@ int main(int argc, char **argv)
|
||||
|
||||
read_config_file(argc,argv,1);
|
||||
|
||||
if(!get_realm(NULL)->options.name[0]) {
|
||||
STRCPY(get_realm(NULL)->options.name,turn_params.domain);
|
||||
}
|
||||
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Domain name: %s\n",turn_params.domain);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Default realm: %s\n",get_realm(NULL)->options.name);
|
||||
if(turn_params.oauth && turn_params.oauth_server_name[0]) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "oAuth server name: %s\n",turn_params.oauth_server_name);
|
||||
}
|
||||
|
||||
optind = 0;
|
||||
|
||||
while (((c = getopt_long(argc, argv, OPTIONS, uo.u.o, NULL)) != -1)) {
|
||||
@ -1878,7 +1918,7 @@ int main(int argc, char **argv)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "===========Discovering listener addresses: =========\n");
|
||||
int maddrs = make_local_listeners_list();
|
||||
if((maddrs<1) || !turn_params.listener.addrs_number) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot configure any meaningful IP listener address\n", __FUNCTION__);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot configure any meaningful IP listener address\n", __FUNCTION__);
|
||||
fprintf(stderr,"\n%s\n", Usage);
|
||||
exit(-1);
|
||||
}
|
||||
@ -1913,7 +1953,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (!turn_params.relays_number) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "You must specify the relay address(es)\n",
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: You must specify the relay address(es)\n",
|
||||
__FUNCTION__);
|
||||
fprintf(stderr,"\n%s\n", Usage);
|
||||
exit(-1);
|
||||
@ -2305,7 +2345,7 @@ static void set_ctx(SSL_CTX* ctx, const char *protocol)
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(nid);
|
||||
if (!ecdh) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
|
||||
"%s: ERROR: allocate EC suite\n");
|
||||
"%s: ERROR: allocate EC suite\n",__FUNCTION__);
|
||||
} else {
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
@ -2339,10 +2379,10 @@ static void set_ctx(SSL_CTX* ctx, const char *protocol)
|
||||
}
|
||||
|
||||
if(!dh) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: cannot allocate DH suite\n");
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: cannot allocate DH suite\n",__FUNCTION__);
|
||||
} else {
|
||||
if (1 != SSL_CTX_set_tmp_dh (ctx, dh)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: cannot set DH\n");
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: cannot set DH\n",__FUNCTION__);
|
||||
}
|
||||
DH_free (dh);
|
||||
}
|
||||
|
||||
@ -51,6 +51,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
@ -65,8 +66,6 @@
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "ns_turn_utils.h"
|
||||
#include "ns_turn_khash.h"
|
||||
|
||||
@ -272,6 +271,9 @@ typedef struct _turn_params_ {
|
||||
////////////// Auth server ////////////////
|
||||
|
||||
struct auth_server authserver;
|
||||
char oauth_server_name[1025];
|
||||
char domain[1025];
|
||||
int oauth;
|
||||
|
||||
/////////////// AUX SERVERS ////////////////
|
||||
|
||||
|
||||
@ -107,7 +107,6 @@ static band_limit_t allocate_bps(band_limit_t bps, int positive)
|
||||
|
||||
if(turn_params.bps_capacity_allocated >= bps) {
|
||||
turn_params.bps_capacity_allocated -= bps;
|
||||
ret = turn_params.bps_capacity_allocated;
|
||||
} else {
|
||||
turn_params.bps_capacity_allocated = 0;
|
||||
}
|
||||
@ -115,6 +114,7 @@ static band_limit_t allocate_bps(band_limit_t bps, int positive)
|
||||
|
||||
pthread_mutex_unlock(&mutex_bps);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ static void add_aux_server_list(const char *saddr, turn_server_addrs_list_t *lis
|
||||
if(make_ioa_addr_from_full_string((const u08bits*)saddr, 0, &addr)!=0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong full address format: %s\n",saddr);
|
||||
} else {
|
||||
list->addrs = (ioa_addr*)realloc(list->addrs,sizeof(ioa_addr)*(list->size+1));
|
||||
list->addrs = (ioa_addr*)turn_realloc(list->addrs,0,sizeof(ioa_addr)*(list->size+1));
|
||||
addr_cpy(&(list->addrs[(list->size)++]),&addr);
|
||||
{
|
||||
u08bits s[1025];
|
||||
@ -196,7 +196,7 @@ static void add_alt_server(const char *saddr, int default_port, turn_server_addr
|
||||
if(make_ioa_addr_from_full_string((const u08bits*)saddr, default_port, &addr)!=0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong IP address format: %s\n",saddr);
|
||||
} else {
|
||||
list->addrs = (ioa_addr*)realloc(list->addrs,sizeof(ioa_addr)*(list->size+1));
|
||||
list->addrs = (ioa_addr*)turn_realloc(list->addrs,0,sizeof(ioa_addr)*(list->size+1));
|
||||
addr_cpy(&(list->addrs[(list->size)++]),&addr);
|
||||
{
|
||||
u08bits s[1025];
|
||||
@ -233,7 +233,7 @@ static void del_alt_server(const char *saddr, int default_port, turn_server_addr
|
||||
if(found) {
|
||||
|
||||
size_t j;
|
||||
ioa_addr *new_addrs = (ioa_addr*)malloc(sizeof(ioa_addr)*(list->size-1));
|
||||
ioa_addr *new_addrs = (ioa_addr*)turn_malloc(sizeof(ioa_addr)*(list->size-1));
|
||||
for(j=0;j<i;++j) {
|
||||
addr_cpy(&(new_addrs[j]),&(list->addrs[j]));
|
||||
}
|
||||
@ -241,7 +241,7 @@ static void del_alt_server(const char *saddr, int default_port, turn_server_addr
|
||||
addr_cpy(&(new_addrs[j]),&(list->addrs[j+1]));
|
||||
}
|
||||
|
||||
free(list->addrs);
|
||||
turn_free(list->addrs,0);
|
||||
list->addrs = new_addrs;
|
||||
list->size -= 1;
|
||||
|
||||
@ -286,6 +286,10 @@ void add_listener_addr(const char* addr) {
|
||||
if(make_ioa_addr((const u08bits*)addr,0,&baddr)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"Cannot add a listener address: %s\n",addr);
|
||||
} else {
|
||||
|
||||
char sbaddr[129];
|
||||
addr_to_string_no_port(&baddr,(u08bits*)sbaddr);
|
||||
|
||||
size_t i = 0;
|
||||
for(i=0;i<turn_params.listener.addrs_number;++i) {
|
||||
if(addr_eq(turn_params.listener.encaddrs[turn_params.listener.addrs_number-1],&baddr)) {
|
||||
@ -294,12 +298,12 @@ void add_listener_addr(const char* addr) {
|
||||
}
|
||||
++turn_params.listener.addrs_number;
|
||||
++turn_params.listener.services_number;
|
||||
turn_params.listener.addrs = (char**)realloc(turn_params.listener.addrs, sizeof(char*)*turn_params.listener.addrs_number);
|
||||
turn_params.listener.addrs[turn_params.listener.addrs_number-1]=strdup(addr);
|
||||
turn_params.listener.encaddrs = (ioa_addr**)realloc(turn_params.listener.encaddrs, sizeof(ioa_addr*)*turn_params.listener.addrs_number);
|
||||
turn_params.listener.addrs = (char**)turn_realloc(turn_params.listener.addrs, 0, sizeof(char*)*turn_params.listener.addrs_number);
|
||||
turn_params.listener.addrs[turn_params.listener.addrs_number-1]=turn_strdup(sbaddr);
|
||||
turn_params.listener.encaddrs = (ioa_addr**)turn_realloc(turn_params.listener.encaddrs, 0, sizeof(ioa_addr*)*turn_params.listener.addrs_number);
|
||||
turn_params.listener.encaddrs[turn_params.listener.addrs_number-1]=(ioa_addr*)turn_malloc(sizeof(ioa_addr));
|
||||
addr_cpy(turn_params.listener.encaddrs[turn_params.listener.addrs_number-1],&baddr);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Listener address to use: %s\n",addr);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Listener address to use: %s\n",sbaddr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,8 +325,8 @@ int add_relay_addr(const char* addr) {
|
||||
}
|
||||
|
||||
++turn_params.relays_number;
|
||||
turn_params.relay_addrs = (char**)realloc(turn_params.relay_addrs, sizeof(char*)*turn_params.relays_number);
|
||||
turn_params.relay_addrs[turn_params.relays_number-1]=strdup(sbaddr);
|
||||
turn_params.relay_addrs = (char**)turn_realloc(turn_params.relay_addrs, 0, sizeof(char*)*turn_params.relays_number);
|
||||
turn_params.relay_addrs[turn_params.relays_number-1]=turn_strdup(sbaddr);
|
||||
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Relay address to use: %s\n",sbaddr);
|
||||
return 1;
|
||||
@ -374,6 +378,8 @@ static void auth_server_receive_message(struct bufferevent *bev, void *ptr)
|
||||
|
||||
if(am.ct == TURN_CREDENTIALS_SHORT_TERM) {
|
||||
st_password_t pwd;
|
||||
am.in_oauth = 0;
|
||||
am.out_oauth = 0;
|
||||
if(get_user_pwd(am.username,pwd)<0) {
|
||||
am.success = 0;
|
||||
} else {
|
||||
@ -382,7 +388,7 @@ static void auth_server_receive_message(struct bufferevent *bev, void *ptr)
|
||||
}
|
||||
} else {
|
||||
hmackey_t key;
|
||||
if(get_user_key(am.username,am.realm,key,am.in_buffer.nbh)<0) {
|
||||
if(get_user_key(am.in_oauth,&(am.out_oauth),&(am.max_session_time),am.username,am.realm,key,am.in_buffer.nbh)<0) {
|
||||
am.success = 0;
|
||||
} else {
|
||||
ns_bcopy(key,am.key,sizeof(hmackey_t));
|
||||
@ -451,7 +457,6 @@ static int send_socket_to_general_relay(ioa_engine_handle e, struct message_to_r
|
||||
int success = 0;
|
||||
|
||||
if(!rdest) {
|
||||
success = -1;
|
||||
goto label_end;
|
||||
}
|
||||
|
||||
@ -486,12 +491,14 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
int message_integrity, MESSAGE_TO_RELAY_TYPE rmt, ioa_net_data *nd,
|
||||
int can_resume)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = -1;
|
||||
|
||||
struct message_to_relay sm;
|
||||
ns_bzero(&sm,sizeof(struct message_to_relay));
|
||||
sm.t = rmt;
|
||||
|
||||
ioa_socket_handle s_to_delete = s;
|
||||
|
||||
struct relay_server *rs = NULL;
|
||||
if(id>=TURNSERVER_ID_BOUNDARY_BETWEEN_TCP_AND_UDP) {
|
||||
size_t dest = id-TURNSERVER_ID_BOUNDARY_BETWEEN_TCP_AND_UDP;
|
||||
@ -500,7 +507,6 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
TURN_LOG_LEVEL_ERROR,
|
||||
"%s: Too large UDP relay number: %d, rmt=%d, total=%d\n",
|
||||
__FUNCTION__,(int)dest,(int)rmt, (int)get_real_udp_relay_servers_number());
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
rs = udp_relay_servers[dest];
|
||||
@ -509,7 +515,6 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
TURN_LOG_LEVEL_ERROR,
|
||||
"%s: Wrong UDP relay number: %d, rmt=%d, total=%d\n",
|
||||
__FUNCTION__,(int)dest,(int)rmt, (int)get_real_udp_relay_servers_number());
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
@ -519,7 +524,6 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
TURN_LOG_LEVEL_ERROR,
|
||||
"%s: Too large general relay number: %d, rmt=%d, total=%d\n",
|
||||
__FUNCTION__,(int)dest,(int)rmt, (int)get_real_general_relay_servers_number());
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
rs = general_relay_servers[dest];
|
||||
@ -528,7 +532,6 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
TURN_LOG_LEVEL_ERROR,
|
||||
"%s: Wrong general relay number: %d, rmt=%d, total=%d\n",
|
||||
__FUNCTION__,(int)dest,(int)rmt, (int)get_real_general_relay_servers_number());
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -550,6 +553,8 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
sm.m.cb_sm.can_resume = can_resume;
|
||||
|
||||
nd->nbh = NULL;
|
||||
s_to_delete = NULL;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -563,17 +568,19 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
sm.m.sm.nd.recv_ttl = nd->recv_ttl;
|
||||
sm.m.sm.nd.nbh = nd->nbh;
|
||||
sm.m.sm.can_resume = can_resume;
|
||||
|
||||
nd->nbh = NULL;
|
||||
s_to_delete = NULL;
|
||||
ret = 0;
|
||||
|
||||
} else {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Empty buffer with mobile socket\n",__FUNCTION__);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: UNKNOWN RMT message: %d\n",__FUNCTION__,(int)rmt);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -588,16 +595,19 @@ static int send_socket_to_relay(turnserver_id id, u64bits cid, stun_tid *tid, io
|
||||
"%s: Empty output buffer\n",
|
||||
__FUNCTION__);
|
||||
ret = -1;
|
||||
s_to_delete = s;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if(ret < 0) {
|
||||
IOA_CLOSE_SOCKET(s);
|
||||
if(nd) {
|
||||
ioa_network_buffer_delete(NULL, nd->nbh);
|
||||
nd->nbh = NULL;
|
||||
}
|
||||
|
||||
IOA_CLOSE_SOCKET(s_to_delete);
|
||||
if(nd && nd->nbh) {
|
||||
ioa_network_buffer_delete(NULL, nd->nbh);
|
||||
nd->nbh = NULL;
|
||||
}
|
||||
|
||||
if(ret<0) {
|
||||
if(rmt == RMT_MOBILE_SOCKET) {
|
||||
ioa_network_buffer_delete(NULL, sm.m.sm.nd.nbh);
|
||||
sm.m.sm.nd.nbh = NULL;
|
||||
@ -713,6 +723,7 @@ static int handle_relay_message(relay_server_handle rs, struct message_to_relay
|
||||
"%s: socket wrongly preset: 0x%lx : 0x%lx\n",
|
||||
__FUNCTION__, (long) s->read_event, (long) s->bev);
|
||||
IOA_CLOSE_SOCKET(s);
|
||||
sm->m.sm.s = NULL;
|
||||
} else {
|
||||
s->e = rs->ioa_eng;
|
||||
open_client_connection_session(&(rs->server), &(sm->m.sm));
|
||||
@ -726,7 +737,13 @@ static int handle_relay_message(relay_server_handle rs, struct message_to_relay
|
||||
|
||||
turnserver_accept_tcp_client_data_connection(&(rs->server), sm->m.cb_sm.connection_id,
|
||||
&(sm->m.cb_sm.tid), sm->m.cb_sm.s, sm->m.cb_sm.message_integrity, &(sm->m.cb_sm.nd),
|
||||
sm->m.cb_sm.can_resume);
|
||||
/*sm->m.cb_sm.can_resume*/
|
||||
/* Note: we cannot resume this call, it must be authenticated in-place.
|
||||
* There are two reasons for that:
|
||||
* 1) Technical. That's very difficult with the current code structure.
|
||||
* 2) Security (more important). We do not want 'stealing' connections between the users.
|
||||
* */
|
||||
0);
|
||||
|
||||
ioa_network_buffer_delete(rs->ioa_eng, sm->m.cb_sm.nd.nbh);
|
||||
sm->m.cb_sm.nd.nbh = NULL;
|
||||
@ -744,6 +761,7 @@ static int handle_relay_message(relay_server_handle rs, struct message_to_relay
|
||||
"%s: mobile socket wrongly preset: 0x%lx : 0x%lx\n",
|
||||
__FUNCTION__, (long) s->read_event, (long) s->bev);
|
||||
IOA_CLOSE_SOCKET(s);
|
||||
sm->m.sm.s = NULL;
|
||||
} else {
|
||||
s->e = rs->ioa_eng;
|
||||
open_client_connection_session(&(rs->server), &(sm->m.sm));
|
||||
@ -764,7 +782,7 @@ static int handle_relay_message(relay_server_handle rs, struct message_to_relay
|
||||
|
||||
static void handle_relay_auth_message(struct relay_server *rs, struct auth_message *am)
|
||||
{
|
||||
am->resume_func(am->success, am->key, am->pwd,
|
||||
am->resume_func(am->success, am->out_oauth, am->max_session_time, am->key, am->pwd,
|
||||
&(rs->server), am->ctxkey, &(am->in_buffer));
|
||||
if (am->in_buffer.nbh) {
|
||||
ioa_network_buffer_delete(rs->ioa_eng, am->in_buffer.nbh);
|
||||
@ -1521,6 +1539,9 @@ void run_listener_server(struct listener_server *ls)
|
||||
run_events(ls->event_base, ls->ioa_eng);
|
||||
|
||||
rollover_logfile();
|
||||
|
||||
tm_print();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1590,7 +1611,8 @@ static void setup_relay_server(struct relay_server *rs, ioa_engine_handle e, int
|
||||
&turn_params.secure_stun, turn_params.shatype, &turn_params.mobility,
|
||||
turn_params.server_relay,
|
||||
send_turn_session_info,
|
||||
allocate_bps);
|
||||
allocate_bps,
|
||||
turn_params.oauth, turn_params.oauth_server_name);
|
||||
|
||||
if(to_set_rfc5780) {
|
||||
set_rfc5780(&(rs->server), get_alt_addr, send_message_from_listener_to_client);
|
||||
@ -1686,6 +1708,9 @@ static void* run_auth_server_thread(void *arg)
|
||||
read_userdb_file(0);
|
||||
update_white_and_black_lists();
|
||||
auth_ping(authserver->rch);
|
||||
#if defined(DB_TEST)
|
||||
run_db_test();
|
||||
#endif
|
||||
}
|
||||
|
||||
return arg;
|
||||
|
||||
@ -80,6 +80,8 @@ struct turn_sock_extended_err {
|
||||
|
||||
#define TRIAL_EFFORTS_TO_SEND (2)
|
||||
|
||||
#define SSL_MAX_RENEG_NUMBER (3)
|
||||
|
||||
const int predef_timer_intervals[PREDEF_TIMERS_NUM] = {30,60,90,120,240,300,360,540,600,700,800,900,1800,3600};
|
||||
|
||||
/************** Forward function declarations ******/
|
||||
@ -186,6 +188,8 @@ static void log_socket_event(ioa_socket_handle s, const char *msg, int error) {
|
||||
if(error)
|
||||
ll = TURN_LOG_LEVEL_ERROR;
|
||||
|
||||
UNUSED_ARG(ll);
|
||||
|
||||
{
|
||||
char sraddr[129]="\0";
|
||||
char sladdr[129]="\0";
|
||||
@ -365,7 +369,7 @@ ioa_engine_handle create_ioa_engine(super_memory_t *sm,
|
||||
}
|
||||
|
||||
if (!relays_number || !relay_addrs || !tp) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot create TURN engine\n", __FUNCTION__);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot create TURN engine\n", __FUNCTION__);
|
||||
return NULL;
|
||||
} else {
|
||||
ioa_engine_handle e = (ioa_engine_handle)allocate_super_memory_region(sm, sizeof(ioa_engine));
|
||||
@ -574,7 +578,7 @@ ioa_timer_handle set_ioa_timer(ioa_engine_handle e, int secs, int ms, ioa_timer_
|
||||
te->e = e;
|
||||
te->ev = ev;
|
||||
te->cb = cb;
|
||||
te->txt = strdup(txt);
|
||||
te->txt = turn_strdup(txt);
|
||||
|
||||
if(!ms) {
|
||||
tv.tv_usec = 0;
|
||||
@ -1446,16 +1450,23 @@ void add_socket_to_map(ioa_socket_handle s, ur_addr_map *amap)
|
||||
&(s->remote_addr),
|
||||
(ur_addr_map_value_type)s);
|
||||
s->sockets_container = amap;
|
||||
|
||||
//printf("%s: 111.111: amap=0x%lx: ne=%lu, sz=%lu\n",__FUNCTION__,(unsigned long)amap,(unsigned long)ur_addr_map_num_elements(amap),(unsigned long)ur_addr_map_size(amap));
|
||||
}
|
||||
}
|
||||
|
||||
void delete_socket_from_map(ioa_socket_handle s)
|
||||
{
|
||||
if(s && s->sockets_container) {
|
||||
|
||||
//ur_addr_map *amap = s->sockets_container;
|
||||
|
||||
ur_addr_map_del(s->sockets_container,
|
||||
&(s->remote_addr),
|
||||
NULL);
|
||||
s->sockets_container = NULL;
|
||||
|
||||
//printf("%s: 111.222: amap=0x%lx: ne=%lu, sz=%lu\n",__FUNCTION__,(unsigned long)amap,(unsigned long)ur_addr_map_num_elements(amap),(unsigned long)ur_addr_map_size(amap));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1476,18 +1487,20 @@ ioa_socket_handle create_ioa_socket_from_fd(ioa_engine_handle e,
|
||||
ret->magic = SOCKET_MAGIC;
|
||||
|
||||
ret->fd = fd;
|
||||
ret->family = local_addr->ss.sa_family;
|
||||
ret->st = st;
|
||||
ret->sat = sat;
|
||||
ret->e = e;
|
||||
|
||||
if (local_addr) {
|
||||
ret->family = local_addr->ss.sa_family;
|
||||
ret->bound = 1;
|
||||
addr_cpy(&(ret->local_addr), local_addr);
|
||||
}
|
||||
|
||||
if (remote_addr) {
|
||||
ret->connected = 1;
|
||||
if(!(ret->family))
|
||||
ret->family = remote_addr->ss.sa_family;
|
||||
addr_cpy(&(ret->remote_addr), remote_addr);
|
||||
}
|
||||
|
||||
@ -1500,6 +1513,44 @@ ioa_socket_handle create_ioa_socket_from_fd(ioa_engine_handle e,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ssl_info_callback(SSL *ssl, int where, int ret) {
|
||||
|
||||
UNUSED_ARG(ret);
|
||||
|
||||
if (0 != (where & SSL_CB_HANDSHAKE_START)) {
|
||||
ioa_socket_handle s = (ioa_socket_handle)SSL_get_app_data(ssl);
|
||||
if(s) {
|
||||
++(s->ssl_renegs);
|
||||
}
|
||||
} else if (0 != (where & SSL_CB_HANDSHAKE_DONE)) {
|
||||
if(ssl->s3) {
|
||||
ioa_socket_handle s = (ioa_socket_handle)SSL_get_app_data(ssl);
|
||||
if(s) {
|
||||
if(s->ssl_renegs>SSL_MAX_RENEG_NUMBER) {
|
||||
ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*ssl_info_callback_t)(const SSL *ssl,int type,int val);
|
||||
|
||||
static void set_socket_ssl(ioa_socket_handle s, SSL *ssl)
|
||||
{
|
||||
if(s && (s->ssl != ssl)) {
|
||||
if(s->ssl) {
|
||||
SSL_set_app_data(s->ssl,NULL);
|
||||
SSL_set_info_callback(s->ssl, (ssl_info_callback_t)NULL);
|
||||
}
|
||||
s->ssl = ssl;
|
||||
if(ssl) {
|
||||
SSL_set_app_data(ssl,s);
|
||||
SSL_set_info_callback(ssl, (ssl_info_callback_t)ssl_info_callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Only must be called for DTLS_SOCKET */
|
||||
ioa_socket_handle create_ioa_socket_from_ssl(ioa_engine_handle e, ioa_socket_handle parent_s, SSL* ssl, SOCKET_TYPE st, SOCKET_APP_TYPE sat, const ioa_addr *remote_addr, const ioa_addr *local_addr)
|
||||
{
|
||||
@ -1509,7 +1560,7 @@ ioa_socket_handle create_ioa_socket_from_ssl(ioa_engine_handle e, ioa_socket_han
|
||||
ioa_socket_handle ret = create_ioa_socket_from_fd(e, parent_s->fd, parent_s, st, sat, remote_addr, local_addr);
|
||||
|
||||
if(ret) {
|
||||
ret->ssl = ssl;
|
||||
set_socket_ssl(ret,ssl);
|
||||
if(st == DTLS_SOCKET)
|
||||
STRCPY(ret->orig_ctx_type,"DTLSv1.0");
|
||||
}
|
||||
@ -1576,16 +1627,16 @@ void detach_socket_net_data(ioa_socket_handle s)
|
||||
if(s->list_ev) {
|
||||
evconnlistener_free(s->list_ev);
|
||||
s->list_ev = NULL;
|
||||
s->acb = NULL;
|
||||
s->acbarg = NULL;
|
||||
}
|
||||
s->acb = NULL;
|
||||
s->acbarg = NULL;
|
||||
if(s->conn_bev) {
|
||||
bufferevent_disable(s->conn_bev,EV_READ|EV_WRITE);
|
||||
bufferevent_free(s->conn_bev);
|
||||
s->conn_bev=NULL;
|
||||
s->conn_arg=NULL;
|
||||
s->conn_cb=NULL;
|
||||
}
|
||||
s->conn_arg=NULL;
|
||||
s->conn_cb=NULL;
|
||||
if(s->bev) {
|
||||
bufferevent_disable(s->bev,EV_READ|EV_WRITE);
|
||||
bufferevent_free(s->bev);
|
||||
@ -1694,13 +1745,16 @@ ioa_socket_handle detach_ioa_socket(ioa_socket_handle s, int full_detach)
|
||||
|
||||
ret->magic = SOCKET_MAGIC;
|
||||
|
||||
ret->username_hash = s->username_hash;
|
||||
ret->realm_hash = s->realm_hash;
|
||||
|
||||
ret->ssl = s->ssl;
|
||||
set_socket_ssl(ret,s->ssl);
|
||||
ret->fd = s->fd;
|
||||
|
||||
ret->family = s->family;
|
||||
if(s->parent_s)
|
||||
ret->family = s->parent_s->family;
|
||||
else
|
||||
ret->family = s->family;
|
||||
|
||||
ret->st = s->st;
|
||||
ret->sat = s->sat;
|
||||
ret->bound = s->bound;
|
||||
@ -1752,7 +1806,7 @@ ioa_socket_handle detach_ioa_socket(ioa_socket_handle s, int full_detach)
|
||||
ret->current_tos = s->current_tos;
|
||||
ret->default_tos = s->default_tos;
|
||||
|
||||
s->ssl = NULL;
|
||||
set_socket_ssl(s,NULL);
|
||||
s->fd = -1;
|
||||
}
|
||||
|
||||
@ -1795,6 +1849,8 @@ void set_ioa_socket_sub_session(ioa_socket_handle s, tcp_connection *tc)
|
||||
int get_ioa_socket_address_family(ioa_socket_handle s) {
|
||||
if(!s) {
|
||||
return AF_INET;
|
||||
} else if(s->done) {
|
||||
return s->family;
|
||||
} else if(s->parent_s) {
|
||||
return s->parent_s->family;
|
||||
} else {
|
||||
@ -1821,7 +1877,7 @@ void set_ioa_socket_app_type(ioa_socket_handle s, SOCKET_APP_TYPE sat) {
|
||||
if(s)
|
||||
s->sat = sat;
|
||||
}
|
||||
|
||||
|
||||
ioa_addr* get_local_addr_from_ioa_socket(ioa_socket_handle s)
|
||||
{
|
||||
if (s && (s->magic == SOCKET_MAGIC) && !(s->done)) {
|
||||
@ -1855,6 +1911,7 @@ ioa_addr* get_local_addr_from_ioa_socket(ioa_socket_handle s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1866,6 +1923,7 @@ ioa_addr* get_remote_addr_from_ioa_socket(ioa_socket_handle s)
|
||||
return &(s->remote_addr);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -2324,7 +2382,7 @@ static int socket_input_worker(ioa_socket_handle s)
|
||||
#if defined(SSL_TXT_TLSV1_2)
|
||||
case TURN_TLS_v1_2:
|
||||
if(s->e->tls_ctx_v1_2) {
|
||||
s->ssl = SSL_new(s->e->tls_ctx_v1_2);
|
||||
set_socket_ssl(s,SSL_new(s->e->tls_ctx_v1_2));
|
||||
STRCPY(s->orig_ctx_type,"TLSv1.2");
|
||||
}
|
||||
break;
|
||||
@ -2332,35 +2390,37 @@ static int socket_input_worker(ioa_socket_handle s)
|
||||
#if defined(SSL_TXT_TLSV1_1)
|
||||
case TURN_TLS_v1_1:
|
||||
if(s->e->tls_ctx_v1_1) {
|
||||
s->ssl = SSL_new(s->e->tls_ctx_v1_1);
|
||||
set_socket_ssl(s,SSL_new(s->e->tls_ctx_v1_1));
|
||||
STRCPY(s->orig_ctx_type,"TLSv1.1");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TURN_TLS_v1_0:
|
||||
if(s->e->tls_ctx_v1_0) {
|
||||
s->ssl = SSL_new(s->e->tls_ctx_v1_0);
|
||||
set_socket_ssl(s,SSL_new(s->e->tls_ctx_v1_0));
|
||||
STRCPY(s->orig_ctx_type,"TLSv1.0");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(s->e->tls_ctx_ssl23) {
|
||||
s->ssl = SSL_new(s->e->tls_ctx_ssl23);
|
||||
set_socket_ssl(s,SSL_new(s->e->tls_ctx_ssl23));
|
||||
STRCPY(s->orig_ctx_type,"SSLv23");
|
||||
} else {
|
||||
s->tobeclosed = 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
s->bev = bufferevent_openssl_socket_new(s->e->event_base,
|
||||
if(s->ssl) {
|
||||
s->bev = bufferevent_openssl_socket_new(s->e->event_base,
|
||||
s->fd,
|
||||
s->ssl,
|
||||
BUFFEREVENT_SSL_ACCEPTING,
|
||||
BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS);
|
||||
bufferevent_setcb(s->bev, socket_input_handler_bev, socket_output_handler_bev,
|
||||
eventcb_bev, s);
|
||||
bufferevent_setwatermark(s->bev, EV_READ|EV_WRITE, 0, BUFFEREVENT_HIGH_WATERMARK);
|
||||
bufferevent_enable(s->bev, EV_READ|EV_WRITE); /* Start reading. */
|
||||
bufferevent_setcb(s->bev, socket_input_handler_bev, socket_output_handler_bev,
|
||||
eventcb_bev, s);
|
||||
bufferevent_setwatermark(s->bev, EV_READ|EV_WRITE, 0, BUFFEREVENT_HIGH_WATERMARK);
|
||||
bufferevent_enable(s->bev, EV_READ|EV_WRITE); /* Start reading. */
|
||||
}
|
||||
} else
|
||||
#endif //TURN_NO_TLS
|
||||
{
|
||||
@ -3212,7 +3272,7 @@ int register_callback_on_ioa_socket(ioa_engine_handle e, ioa_socket_handle s, in
|
||||
#if !defined(TURN_NO_TLS)
|
||||
if(!(s->ssl)) {
|
||||
//??? how we can get to this point ???
|
||||
s->ssl = SSL_new(e->tls_ctx_ssl23);
|
||||
set_socket_ssl(s,SSL_new(e->tls_ctx_ssl23));
|
||||
STRCPY(s->orig_ctx_type,"SSLv23");
|
||||
s->bev = bufferevent_openssl_socket_new(s->e->event_base,
|
||||
s->fd,
|
||||
@ -3301,14 +3361,9 @@ static u32bits string_hash(const u08bits *str) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
int check_username_hash(ioa_socket_handle s, u08bits *username, u08bits *realm)
|
||||
int check_realm_hash(ioa_socket_handle s, u08bits *realm)
|
||||
{
|
||||
if(s) {
|
||||
if(username && username[0]) {
|
||||
if(s->username_hash != string_hash(username)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(realm && realm[0]) {
|
||||
if(s->realm_hash != string_hash(realm)) {
|
||||
return 0;
|
||||
@ -3318,12 +3373,9 @@ int check_username_hash(ioa_socket_handle s, u08bits *username, u08bits *realm)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_username_hash(ioa_socket_handle s, u08bits *username, u08bits *realm)
|
||||
void set_realm_hash(ioa_socket_handle s, u08bits *realm)
|
||||
{
|
||||
if(s) {
|
||||
if(username && username[0]) {
|
||||
s->username_hash = string_hash(username);
|
||||
}
|
||||
if(realm && realm[0]) {
|
||||
s->realm_hash = string_hash(realm);
|
||||
}
|
||||
@ -3570,11 +3622,11 @@ static void init_super_memory_region(super_memory_t *r)
|
||||
if(r) {
|
||||
ns_bzero(r,sizeof(super_memory_t));
|
||||
|
||||
r->super_memory = (char**)malloc(sizeof(char*));
|
||||
r->super_memory[0] = (char*)malloc(TURN_SM_SIZE);
|
||||
r->super_memory = (char**)turn_malloc(sizeof(char*));
|
||||
r->super_memory[0] = (char*)turn_malloc(TURN_SM_SIZE);
|
||||
ns_bzero(r->super_memory[0],TURN_SM_SIZE);
|
||||
|
||||
r->sm_allocated = (size_t*)malloc(sizeof(size_t*));
|
||||
r->sm_allocated = (size_t*)turn_malloc(sizeof(size_t*));
|
||||
r->sm_allocated[0] = 0;
|
||||
|
||||
r->sm_total_sz = TURN_SM_SIZE;
|
||||
@ -3594,7 +3646,7 @@ void init_super_memory(void)
|
||||
|
||||
super_memory_t* new_super_memory_region(void)
|
||||
{
|
||||
super_memory_t* r = (super_memory_t*)malloc(sizeof(super_memory_t));
|
||||
super_memory_t* r = (super_memory_t*)turn_malloc(sizeof(super_memory_t));
|
||||
init_super_memory_region(r);
|
||||
return r;
|
||||
}
|
||||
@ -3605,11 +3657,14 @@ void* allocate_super_memory_region_func(super_memory_t *r, size_t size, const ch
|
||||
UNUSED_ARG(func);
|
||||
UNUSED_ARG(line);
|
||||
|
||||
if(!r)
|
||||
return malloc(size);
|
||||
|
||||
void *ret = NULL;
|
||||
|
||||
if(!r) {
|
||||
ret = turn_malloc(size);
|
||||
ns_bzero(ret, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&r->mutex_sm);
|
||||
|
||||
size = ((size_t)((size+sizeof(void*))/(sizeof(void*)))) * sizeof(void*);
|
||||
@ -3638,10 +3693,10 @@ void* allocate_super_memory_region_func(super_memory_t *r, size_t size, const ch
|
||||
|
||||
if(!region) {
|
||||
r->sm_chunk += 1;
|
||||
r->super_memory = (char**)realloc(r->super_memory,(r->sm_chunk+1) * sizeof(char*));
|
||||
r->super_memory[r->sm_chunk] = (char*)malloc(TURN_SM_SIZE);
|
||||
r->super_memory = (char**)turn_realloc(r->super_memory,0,(r->sm_chunk+1) * sizeof(char*));
|
||||
r->super_memory[r->sm_chunk] = (char*)turn_malloc(TURN_SM_SIZE);
|
||||
ns_bzero(r->super_memory[r->sm_chunk],TURN_SM_SIZE);
|
||||
r->sm_allocated = (size_t*)realloc(r->sm_allocated,(r->sm_chunk+1) * sizeof(size_t*));
|
||||
r->sm_allocated = (size_t*)turn_realloc(r->sm_allocated,0,(r->sm_chunk+1) * sizeof(size_t*));
|
||||
r->sm_allocated[r->sm_chunk] = 0;
|
||||
region = r->super_memory[r->sm_chunk];
|
||||
rsz = r->sm_allocated + r->sm_chunk;
|
||||
@ -3660,8 +3715,10 @@ void* allocate_super_memory_region_func(super_memory_t *r, size_t size, const ch
|
||||
|
||||
pthread_mutex_unlock(&r->mutex_sm);
|
||||
|
||||
if(!ret)
|
||||
ret = malloc(size);
|
||||
if(!ret) {
|
||||
ret = turn_malloc(size);
|
||||
ns_bzero(ret, size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -170,7 +170,6 @@ struct _ioa_socket
|
||||
{
|
||||
evutil_socket_t fd;
|
||||
struct _ioa_socket *parent_s;
|
||||
void *listener_server;
|
||||
u32bits magic;
|
||||
ur_addr_map *sockets_container; /* relay container for UDP sockets */
|
||||
struct bufferevent *bev;
|
||||
@ -179,6 +178,7 @@ struct _ioa_socket
|
||||
SOCKET_TYPE st;
|
||||
SOCKET_APP_TYPE sat;
|
||||
SSL* ssl;
|
||||
u32bits ssl_renegs;
|
||||
int in_write;
|
||||
char orig_ctx_type[16];
|
||||
int bound;
|
||||
@ -213,7 +213,6 @@ struct _ioa_socket
|
||||
connect_cb conn_cb;
|
||||
void *conn_arg;
|
||||
//Transferable sockets user data
|
||||
u32bits username_hash;
|
||||
u32bits realm_hash;
|
||||
//Accept:
|
||||
struct evconnlistener *list_ev;
|
||||
@ -235,7 +234,7 @@ typedef struct _timer_event
|
||||
|
||||
/* realm */
|
||||
|
||||
void create_new_realm(char* name);
|
||||
void create_default_realm(void);
|
||||
int get_realm_data(char* name, realm_params_t* rp);
|
||||
|
||||
/* engine handling */
|
||||
|
||||
@ -98,8 +98,6 @@ static void server_input_handler(struct evconnlistener *l, evutil_socket_t fd,
|
||||
|
||||
if (ioas) {
|
||||
|
||||
ioas->listener_server = server;
|
||||
|
||||
server->sm.m.sm.nd.recv_ttl = TTL_IGNORE;
|
||||
server->sm.m.sm.nd.recv_tos = TOS_IGNORE;
|
||||
server->sm.m.sm.nd.nbh = NULL;
|
||||
|
||||
@ -465,7 +465,7 @@ static int print_session(ur_map_key_type key, ur_map_value_type value, void *arg
|
||||
csarg->user_names = (char**)turn_realloc(csarg->user_names,
|
||||
(size_t)value * sizeof(char*),
|
||||
csarg->users_number * sizeof(char*));
|
||||
csarg->user_names[(size_t)value] = strdup((char*)tsi->username);
|
||||
csarg->user_names[(size_t)value] = turn_strdup((char*)tsi->username);
|
||||
csarg->user_counters[(size_t)value] = 0;
|
||||
ur_string_map_put(csarg->users, (ur_string_map_key_type)(char*)tsi->username, value);
|
||||
}
|
||||
@ -820,9 +820,9 @@ static void cli_print_configuration(struct cli_session* cs)
|
||||
cli_print_flag(cs,1,"Short-term authorization mechanism",0);
|
||||
else
|
||||
cli_print_flag(cs,1,"Anonymous credentials",0);
|
||||
cli_print_flag(cs,turn_params.use_auth_secret_with_timestamp,"REST API support",0);
|
||||
cli_print_flag(cs,turn_params.use_auth_secret_with_timestamp,"TURN REST API support",0);
|
||||
if(turn_params.use_auth_secret_with_timestamp && turn_params.rest_api_separator)
|
||||
cli_print_uint(cs,turn_params.rest_api_separator,"REST API separator ASCII number",0);
|
||||
cli_print_uint(cs,turn_params.rest_api_separator,"TURN REST API separator ASCII number",0);
|
||||
|
||||
myprintf(cs,"\n");
|
||||
|
||||
@ -939,7 +939,7 @@ static int run_cli_input(struct cli_session* cs, const char *buf0, unsigned int
|
||||
|
||||
if(cs && buf0 && cs->ts && cs->bev) {
|
||||
|
||||
char *buf = (char*)malloc(len+1);
|
||||
char *buf = (char*)turn_malloc(len+1);
|
||||
ns_bcopy(buf0,buf,len);
|
||||
buf[len]=0;
|
||||
|
||||
@ -1078,7 +1078,7 @@ static int run_cli_input(struct cli_session* cs, const char *buf0, unsigned int
|
||||
type_cli_cursor(cs);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
turn_free(buf,len+1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@ -65,15 +65,6 @@
|
||||
//////////// REALM //////////////
|
||||
|
||||
static realm_params_t *default_realm_params_ptr = NULL;
|
||||
static const realm_params_t _default_realm_params =
|
||||
{
|
||||
1,
|
||||
{
|
||||
"\0", /* name */
|
||||
{0,0,0}
|
||||
},
|
||||
{0,NULL}
|
||||
};
|
||||
|
||||
static ur_string_map *realms = NULL;
|
||||
static turn_mutex o_to_realm_mutex;
|
||||
@ -95,40 +86,30 @@ void update_o_to_realm(ur_string_map * o_to_realm_new) {
|
||||
TURN_MUTEX_UNLOCK(&o_to_realm_mutex);
|
||||
}
|
||||
|
||||
void create_new_realm(char* name)
|
||||
void create_default_realm()
|
||||
{
|
||||
realm_params_t *ret = NULL;
|
||||
|
||||
if((name == NULL)||(name[0]==0)) {
|
||||
if(default_realm_params_ptr) {
|
||||
return;
|
||||
}
|
||||
/* init everything: */
|
||||
TURN_MUTEX_INIT_RECURSIVE(&o_to_realm_mutex);
|
||||
init_secrets_list(&realms_list);
|
||||
o_to_realm = ur_string_map_create(free);
|
||||
default_realm_params_ptr = (realm_params_t*)malloc(sizeof(realm_params_t));
|
||||
ns_bcopy(&_default_realm_params,default_realm_params_ptr,sizeof(realm_params_t));
|
||||
realms = ur_string_map_create(NULL);
|
||||
ur_string_map_lock(realms);
|
||||
ret = default_realm_params_ptr;
|
||||
} else {
|
||||
ur_string_map_value_type value = 0;
|
||||
ur_string_map_lock(realms);
|
||||
if (!ur_string_map_get(realms, (const ur_string_map_key_type) name, &value)) {
|
||||
ret = (realm_params_t*)turn_malloc(sizeof(realm_params_t));
|
||||
ns_bcopy(default_realm_params_ptr,ret,sizeof(realm_params_t));
|
||||
STRCPY(ret->options.name,name);
|
||||
value = (ur_string_map_value_type)ret;
|
||||
ur_string_map_put(realms, (const ur_string_map_key_type) name, value);
|
||||
add_to_secrets_list(&realms_list, name);
|
||||
} else {
|
||||
ur_string_map_unlock(realms);
|
||||
return;
|
||||
}
|
||||
if(default_realm_params_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret->status.alloc_counters = ur_string_map_create(NULL);
|
||||
static realm_params_t _default_realm_params =
|
||||
{
|
||||
1,
|
||||
{
|
||||
"\0", /* name */
|
||||
{0,0,0}
|
||||
},
|
||||
{0,NULL}
|
||||
};
|
||||
|
||||
/* init everything: */
|
||||
TURN_MUTEX_INIT_RECURSIVE(&o_to_realm_mutex);
|
||||
init_secrets_list(&realms_list);
|
||||
o_to_realm = ur_string_map_create(turn_free_simple);
|
||||
default_realm_params_ptr = &_default_realm_params;
|
||||
realms = ur_string_map_create(NULL);
|
||||
ur_string_map_lock(realms);
|
||||
default_realm_params_ptr->status.alloc_counters = ur_string_map_create(NULL);
|
||||
ur_string_map_unlock(realms);
|
||||
}
|
||||
|
||||
@ -188,12 +169,12 @@ int get_realm_options_by_origin(char *origin, realm_options_t* ro)
|
||||
ur_string_map_value_type value = 0;
|
||||
TURN_MUTEX_LOCK(&o_to_realm_mutex);
|
||||
if (ur_string_map_get(o_to_realm, (ur_string_map_key_type) origin, &value) && value) {
|
||||
char *realm = strdup((char*)value);
|
||||
char *realm = turn_strdup((char*)value);
|
||||
TURN_MUTEX_UNLOCK(&o_to_realm_mutex);
|
||||
realm_params_t rp;
|
||||
get_realm_data(realm, &rp);
|
||||
ns_bcopy(&(rp.options),ro,sizeof(realm_options_t));
|
||||
free(realm);
|
||||
turn_free(realm,strlen(realm)+1);
|
||||
return 1;
|
||||
} else {
|
||||
TURN_MUTEX_UNLOCK(&o_to_realm_mutex);
|
||||
@ -310,9 +291,9 @@ const char* get_secrets_list_elem(secrets_list_t *sl, size_t i)
|
||||
void add_to_secrets_list(secrets_list_t *sl, const char* elem)
|
||||
{
|
||||
if(sl && elem) {
|
||||
sl->secrets = (char**)realloc(sl->secrets,(sizeof(char*)*(sl->sz+1)));
|
||||
sl->secrets[sl->sz] = strdup(elem);
|
||||
sl->sz += 1;
|
||||
sl->secrets = (char**)turn_realloc(sl->secrets,0,(sizeof(char*)*(sl->sz+1)));
|
||||
sl->secrets[sl->sz] = turn_strdup(elem);
|
||||
sl->sz += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,7 +365,7 @@ static turn_time_t get_rest_api_timestamp(char *usname)
|
||||
|
||||
static char *get_real_username(char *usname)
|
||||
{
|
||||
if(turn_params.use_auth_secret_with_timestamp) {
|
||||
if(usname[0] && turn_params.use_auth_secret_with_timestamp) {
|
||||
char *col=strchr(usname,turn_params.rest_api_separator);
|
||||
if(col) {
|
||||
if(col == usname) {
|
||||
@ -403,7 +384,7 @@ static char *get_real_username(char *usname)
|
||||
usname = col+1;
|
||||
} else {
|
||||
*col=0;
|
||||
usname = strdup(usname);
|
||||
usname = turn_strdup(usname);
|
||||
*col=turn_params.rest_api_separator;
|
||||
return usname;
|
||||
}
|
||||
@ -411,16 +392,145 @@ static char *get_real_username(char *usname)
|
||||
}
|
||||
}
|
||||
|
||||
return strdup(usname);
|
||||
return turn_strdup(usname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Long-term mechanism password retrieval
|
||||
* Password retrieval
|
||||
*/
|
||||
int get_user_key(u08bits *usname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh)
|
||||
int get_user_key(int in_oauth, int *out_oauth, int *max_session_time, u08bits *usname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if(max_session_time)
|
||||
*max_session_time = 0;
|
||||
|
||||
if(in_oauth && out_oauth && usname && usname[0] && realm && realm[0]) {
|
||||
|
||||
stun_attr_ref sar = stun_attr_get_first_by_type_str(ioa_network_buffer_data(nbh),
|
||||
ioa_network_buffer_get_size(nbh),
|
||||
STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN);
|
||||
if(sar) {
|
||||
|
||||
int len = stun_attr_get_len(sar);
|
||||
const u08bits *value = stun_attr_get_value(sar);
|
||||
|
||||
*out_oauth = 1;
|
||||
|
||||
if(len>0 && value) {
|
||||
|
||||
turn_dbdriver_t * dbd = get_dbdriver();
|
||||
|
||||
if (dbd && dbd->get_oauth_key) {
|
||||
|
||||
oauth_key_data_raw rawKey;
|
||||
ns_bzero(&rawKey,sizeof(rawKey));
|
||||
|
||||
int gres = (*(dbd->get_oauth_key))(usname,&rawKey);
|
||||
if(gres<0)
|
||||
return ret;
|
||||
|
||||
if(!rawKey.kid[0])
|
||||
return ret;
|
||||
|
||||
if(rawKey.lifetime) {
|
||||
if(!turn_time_before(turn_time(),(turn_time_t)(rawKey.timestamp + rawKey.lifetime+OAUTH_TIME_DELTA))) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
oauth_key_data okd;
|
||||
ns_bzero(&okd,sizeof(okd));
|
||||
|
||||
convert_oauth_key_data_raw(&rawKey, &okd);
|
||||
|
||||
char err_msg[1025] = "\0";
|
||||
size_t err_msg_size = sizeof(err_msg) - 1;
|
||||
|
||||
oauth_key okey;
|
||||
ns_bzero(&okey,sizeof(okey));
|
||||
|
||||
if (convert_oauth_key_data(&okd, &okey, err_msg, err_msg_size) < 0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s\n", err_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oauth_token dot;
|
||||
ns_bzero((&dot),sizeof(dot));
|
||||
|
||||
encoded_oauth_token etoken;
|
||||
ns_bzero(&etoken,sizeof(etoken));
|
||||
|
||||
if((size_t)len > sizeof(etoken.token)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Encoded oAuth token is too large\n");
|
||||
return -1;
|
||||
}
|
||||
ns_bcopy(value,etoken.token,(size_t)len);
|
||||
etoken.size = (size_t)len;
|
||||
|
||||
const char* server_name = (char*)turn_params.oauth_server_name;
|
||||
if(!(server_name && server_name[0])) {
|
||||
server_name = (char*)realm;
|
||||
}
|
||||
|
||||
if (decode_oauth_token((const u08bits *) server_name, &etoken,&okey, &dot) < 0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot decode oauth token\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(dot.enc_block.key_length) {
|
||||
case SHA1SIZEBYTES:
|
||||
if(turn_params.shatype != SHATYPE_SHA1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(1): %d\n",(int)dot.enc_block.key_length);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SHA256SIZEBYTES:
|
||||
if(turn_params.shatype != SHATYPE_SHA256) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(2): %d\n",(int)dot.enc_block.key_length);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length);
|
||||
return -1;
|
||||
};
|
||||
|
||||
st_password_t pwdtmp;
|
||||
if(stun_check_message_integrity_by_key_str(TURN_CREDENTIALS_LONG_TERM,
|
||||
ioa_network_buffer_data(nbh),
|
||||
ioa_network_buffer_get_size(nbh),
|
||||
dot.enc_block.mac_key,
|
||||
pwdtmp,
|
||||
turn_params.shatype,NULL)>0) {
|
||||
|
||||
turn_time_t lifetime = (turn_time_t)(dot.enc_block.lifetime);
|
||||
if(lifetime) {
|
||||
turn_time_t ts = (turn_time_t)(dot.enc_block.timestamp >> 16);
|
||||
turn_time_t to = ts + lifetime + OAUTH_TIME_DELTA;
|
||||
turn_time_t ct = turn_time();
|
||||
if(!turn_time_before(ct,to)) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "oAuth token is too old\n");
|
||||
return -1;
|
||||
}
|
||||
if(max_session_time) {
|
||||
*max_session_time = to - ct;
|
||||
}
|
||||
}
|
||||
|
||||
ns_bcopy(dot.enc_block.mac_key,key,dot.enc_block.key_length);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(out_oauth && *out_oauth) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(turn_params.use_auth_secret_with_timestamp) {
|
||||
|
||||
turn_time_t ctime = (turn_time_t) time(NULL);
|
||||
@ -527,7 +637,7 @@ int get_user_key(u08bits *usname, u08bits *realm, hmackey_t key, ioa_network_buf
|
||||
|
||||
turn_dbdriver_t * dbd = get_dbdriver();
|
||||
if (dbd && dbd->get_user_key) {
|
||||
ret = (*dbd->get_user_key)(usname, realm, key);
|
||||
ret = (*(dbd->get_user_key))(usname, realm, key);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -548,7 +658,7 @@ int get_user_pwd(u08bits *usname, st_password_t pwd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
u08bits *start_user_check(turnserver_id id, turn_credential_type ct, u08bits *usname, u08bits *realm, get_username_resume_cb resume, ioa_net_data *in_buffer, u64bits ctxkey, int *postpone_reply)
|
||||
u08bits *start_user_check(turnserver_id id, turn_credential_type ct, int in_oauth, int *out_oauth, u08bits *usname, u08bits *realm, get_username_resume_cb resume, ioa_net_data *in_buffer, u64bits ctxkey, int *postpone_reply)
|
||||
{
|
||||
*postpone_reply = 1;
|
||||
|
||||
@ -556,6 +666,8 @@ u08bits *start_user_check(turnserver_id id, turn_credential_type ct, u08bits *us
|
||||
ns_bzero(&am,sizeof(struct auth_message));
|
||||
am.id = id;
|
||||
am.ct = ct;
|
||||
am.in_oauth = in_oauth;
|
||||
am.out_oauth = *out_oauth;
|
||||
STRCPY(am.username,usname);
|
||||
STRCPY(am.realm,realm);
|
||||
am.resume_func = resume;
|
||||
@ -568,11 +680,11 @@ u08bits *start_user_check(turnserver_id id, turn_credential_type ct, u08bits *us
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int check_new_allocation_quota(u08bits *user, u08bits *realm)
|
||||
int check_new_allocation_quota(u08bits *user, int oauth, u08bits *realm)
|
||||
{
|
||||
int ret = 0;
|
||||
if (user) {
|
||||
u08bits *username = (u08bits*)get_real_username((char*)user);
|
||||
if (user || oauth) {
|
||||
u08bits *username = oauth ? (u08bits*)turn_strdup("") : (u08bits*)get_real_username((char*)user);
|
||||
realm_params_t *rp = get_realm((char*)realm);
|
||||
ur_string_map_lock(rp->status.alloc_counters);
|
||||
if (rp->options.perf_options.total_quota && (rp->status.total_current_allocs >= rp->options.perf_options.total_quota)) {
|
||||
@ -595,28 +707,30 @@ int check_new_allocation_quota(u08bits *user, u08bits *realm)
|
||||
} else {
|
||||
++(rp->status.total_current_allocs);
|
||||
}
|
||||
turn_free(username,strlen(username)+1);
|
||||
turn_free(username,strlen((char*)username)+1);
|
||||
ur_string_map_unlock(rp->status.alloc_counters);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void release_allocation_quota(u08bits *user, u08bits *realm)
|
||||
void release_allocation_quota(u08bits *user, int oauth, u08bits *realm)
|
||||
{
|
||||
if (user) {
|
||||
u08bits *username = (u08bits*)get_real_username((char*)user);
|
||||
u08bits *username = oauth ? (u08bits*)turn_strdup("") : (u08bits*)get_real_username((char*)user);
|
||||
realm_params_t *rp = get_realm((char*)realm);
|
||||
ur_string_map_lock(rp->status.alloc_counters);
|
||||
ur_string_map_value_type value = 0;
|
||||
ur_string_map_get(rp->status.alloc_counters, (ur_string_map_key_type) username, &value);
|
||||
if (value) {
|
||||
value = (ur_string_map_value_type)(((size_t)value) - 1);
|
||||
ur_string_map_put(rp->status.alloc_counters, (ur_string_map_key_type) username, value);
|
||||
if(username[0]) {
|
||||
ur_string_map_value_type value = 0;
|
||||
ur_string_map_get(rp->status.alloc_counters, (ur_string_map_key_type) username, &value);
|
||||
if (value) {
|
||||
value = (ur_string_map_value_type)(((size_t)value) - 1);
|
||||
ur_string_map_put(rp->status.alloc_counters, (ur_string_map_key_type) username, value);
|
||||
}
|
||||
}
|
||||
if (rp->status.total_current_allocs)
|
||||
--(rp->status.total_current_allocs);
|
||||
ur_string_map_unlock(rp->status.alloc_counters);
|
||||
turn_free(username, strlen(username)+1);
|
||||
turn_free(username, strlen((char*)username)+1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -725,8 +839,8 @@ int add_user_account(char *user, int dynamic)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key format: %s\n",s);
|
||||
} if(convert_string_key_to_binary(keysource, *key, sz)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key: %s\n",s);
|
||||
free(usname);
|
||||
free(key);
|
||||
turn_free(usname,strlen(usname)+1);
|
||||
turn_free(key,sizeof(hmackey_t));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@ -743,7 +857,7 @@ int add_user_account(char *user, int dynamic)
|
||||
ur_string_map_unlock(turn_params.default_users_db.ram_db.static_accounts);
|
||||
}
|
||||
turn_params.default_users_db.ram_db.users_number++;
|
||||
free(usname);
|
||||
turn_free(usname,strlen(usname)+1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -1039,8 +1153,8 @@ int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08b
|
||||
}
|
||||
|
||||
add_and_cont:
|
||||
content = (char**)realloc(content, sizeof(char*) * (++csz));
|
||||
content[csz - 1] = strdup(s0);
|
||||
content = (char**)turn_realloc(content, 0, sizeof(char*) * (++csz));
|
||||
content[csz - 1] = turn_strdup(s0);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
@ -1054,12 +1168,12 @@ int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08b
|
||||
for(i=0;i<sz;i++) {
|
||||
snprintf(us+strlen(us),sizeof(us)-strlen(us),"%02x",(unsigned int)key[i]);
|
||||
}
|
||||
content = (char**)realloc(content,sizeof(char*)*(++csz));
|
||||
content[csz-1]=strdup(us);
|
||||
content = (char**)turn_realloc(content,0,sizeof(char*)*(++csz));
|
||||
content[csz-1]=turn_strdup(us);
|
||||
}
|
||||
|
||||
if(!full_path_to_userdb_file)
|
||||
full_path_to_userdb_file=strdup(pud->userdb);
|
||||
full_path_to_userdb_file=turn_strdup(pud->userdb);
|
||||
|
||||
size_t dirsz = strlen(full_path_to_userdb_file)+21;
|
||||
char *dir = (char*)turn_malloc(dirsz+1);
|
||||
@ -1085,7 +1199,7 @@ int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08b
|
||||
fclose(f);
|
||||
|
||||
rename(dir,full_path_to_userdb_file);
|
||||
free(dir);
|
||||
turn_free(dir,dirsz+1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1101,6 +1215,75 @@ void auth_ping(redis_context_handle rch)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////// TEST /////////////////
|
||||
|
||||
#if defined(DB_TEST)
|
||||
|
||||
void run_db_test(void)
|
||||
{
|
||||
turn_dbdriver_t * dbd = get_dbdriver();
|
||||
if (dbd) {
|
||||
|
||||
printf("DB TEST 1:\n");
|
||||
dbd->list_oauth_keys();
|
||||
|
||||
printf("DB TEST 2:\n");
|
||||
oauth_key_data_raw key_;
|
||||
oauth_key_data_raw *key=&key_;
|
||||
dbd->get_oauth_key((const u08bits*)"north",key);
|
||||
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n",
|
||||
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func,
|
||||
key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key);
|
||||
|
||||
printf("DB TEST 3:\n");
|
||||
|
||||
STRCPY(key->as_rs_alg,"as_rs_alg");
|
||||
STRCPY(key->as_rs_key,"as_rs_key");
|
||||
STRCPY(key->auth_alg,"auth_alg");
|
||||
STRCPY(key->auth_key,"auth_key");
|
||||
STRCPY(key->hkdf_hash_func,"hkdf");
|
||||
STRCPY(key->ikm_key,"ikm_key");
|
||||
STRCPY(key->kid,"kid");
|
||||
key->timestamp = 123;
|
||||
key->lifetime = 456;
|
||||
dbd->del_oauth_key((const u08bits*)"kid");
|
||||
dbd->set_oauth_key(key);
|
||||
dbd->list_oauth_keys();
|
||||
|
||||
printf("DB TEST 4:\n");
|
||||
dbd->get_oauth_key((const u08bits*)"kid",key);
|
||||
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n",
|
||||
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func,
|
||||
key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key);
|
||||
|
||||
printf("DB TEST 5:\n");
|
||||
dbd->del_oauth_key((const u08bits*)"kid");
|
||||
dbd->list_oauth_keys();
|
||||
|
||||
printf("DB TEST 6:\n");
|
||||
|
||||
dbd->get_oauth_key((const u08bits*)"north",key);
|
||||
|
||||
oauth_key_data oakd;
|
||||
convert_oauth_key_data_raw(key, &oakd);
|
||||
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key_size=%d, auth_alg=%s, auth_key_size=%d\n",
|
||||
oakd.kid, oakd.ikm_key, (unsigned long long)oakd.timestamp, (unsigned long)oakd.lifetime, oakd.hkdf_hash_func,
|
||||
oakd.as_rs_alg, (int)oakd.as_rs_key_size, oakd.auth_alg, (int)oakd.auth_key_size);
|
||||
|
||||
oauth_key oak;
|
||||
char err_msg[1025];
|
||||
err_msg[0]=0;
|
||||
if(convert_oauth_key_data(&oakd,&oak,err_msg,sizeof(err_msg)-1)<0) {
|
||||
printf(" ERROR: %s\n",err_msg);
|
||||
} else {
|
||||
printf(" OK!\n");
|
||||
}
|
||||
printf("DB TEST END\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///////////////// WHITE/BLACK IP LISTS ///////////////////
|
||||
|
||||
#if !defined(TURN_NO_RWLOCK)
|
||||
@ -1213,15 +1396,15 @@ static void ip_list_free(ip_range_list_t *l)
|
||||
size_t i;
|
||||
for(i=0;i<l->ranges_number;++i) {
|
||||
if(l->ranges && l->ranges[i])
|
||||
free(l->ranges[i]);
|
||||
turn_free(l->ranges[i],0);
|
||||
if(l->encaddrsranges && l->encaddrsranges[i])
|
||||
free(l->encaddrsranges[i]);
|
||||
turn_free(l->encaddrsranges[i],0);
|
||||
}
|
||||
if(l->ranges)
|
||||
free(l->ranges);
|
||||
turn_free(l->ranges,0);
|
||||
if(l->encaddrsranges)
|
||||
free(l->encaddrsranges);
|
||||
free(l);
|
||||
turn_free(l->encaddrsranges,0);
|
||||
turn_free(l,sizeof(ip_range_list_t));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1251,7 +1434,7 @@ void update_white_and_black_lists(void)
|
||||
|
||||
int add_ip_list_range(const char * range0, ip_range_list_t * list)
|
||||
{
|
||||
char *range = strdup(range0);
|
||||
char *range = turn_strdup(range0);
|
||||
|
||||
char* separator = strchr(range, '-');
|
||||
|
||||
@ -1263,14 +1446,14 @@ int add_ip_list_range(const char * range0, ip_range_list_t * list)
|
||||
|
||||
if (make_ioa_addr((const u08bits*) range, 0, &min) < 0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong address format: %s\n", range);
|
||||
free(range);
|
||||
turn_free(range,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (separator) {
|
||||
if (make_ioa_addr((const u08bits*) separator + 1, 0, &max) < 0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong address format: %s\n", separator + 1);
|
||||
free(range);
|
||||
turn_free(range,0);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@ -1282,9 +1465,9 @@ int add_ip_list_range(const char * range0, ip_range_list_t * list)
|
||||
*separator = '-';
|
||||
|
||||
++(list->ranges_number);
|
||||
list->ranges = (char**) realloc(list->ranges, sizeof(char*) * list->ranges_number);
|
||||
list->ranges = (char**) turn_realloc(list->ranges, 0, sizeof(char*) * list->ranges_number);
|
||||
list->ranges[list->ranges_number - 1] = range;
|
||||
list->encaddrsranges = (ioa_addr_range**) realloc(list->encaddrsranges, sizeof(ioa_addr_range*) * list->ranges_number);
|
||||
list->encaddrsranges = (ioa_addr_range**) turn_realloc(list->encaddrsranges, 0, sizeof(ioa_addr_range*) * list->ranges_number);
|
||||
|
||||
list->encaddrsranges[list->ranges_number - 1] = (ioa_addr_range*) turn_malloc(sizeof(ioa_addr_range));
|
||||
|
||||
|
||||
@ -86,6 +86,9 @@ void update_o_to_realm(ur_string_map * o_to_realm_new);
|
||||
struct auth_message {
|
||||
turnserver_id id;
|
||||
turn_credential_type ct;
|
||||
int in_oauth;
|
||||
int out_oauth;
|
||||
int max_session_time;
|
||||
u08bits username[STUN_MAX_USERNAME_SIZE + 1];
|
||||
u08bits realm[STUN_MAX_REALM_SIZE + 1];
|
||||
hmackey_t key;
|
||||
@ -187,14 +190,18 @@ void add_to_secrets_list(secrets_list_t *sl, const char* elem);
|
||||
|
||||
/////////// USER DB CHECK //////////////////
|
||||
|
||||
int get_user_key(u08bits *uname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh);
|
||||
int get_user_key(int in_oauth, int *out_oauth, int *max_session_time, u08bits *uname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh);
|
||||
int get_user_pwd(u08bits *uname, st_password_t pwd);
|
||||
u08bits *start_user_check(turnserver_id id, turn_credential_type ct, u08bits *uname, u08bits *realm, get_username_resume_cb resume, ioa_net_data *in_buffer, u64bits ctxkey, int *postpone_reply);
|
||||
int check_new_allocation_quota(u08bits *username, u08bits *realm);
|
||||
void release_allocation_quota(u08bits *username, u08bits *realm);
|
||||
u08bits *start_user_check(turnserver_id id, turn_credential_type ct, int in_oauth, int *out_oauth, u08bits *uname, u08bits *realm, get_username_resume_cb resume, ioa_net_data *in_buffer, u64bits ctxkey, int *postpone_reply);
|
||||
int check_new_allocation_quota(u08bits *username, int oauth, u08bits *realm);
|
||||
void release_allocation_quota(u08bits *username, int oauth, u08bits *realm);
|
||||
|
||||
/////////// Handle user DB /////////////////
|
||||
|
||||
#if defined(DB_TEST)
|
||||
void run_db_test(void);
|
||||
#endif
|
||||
|
||||
void read_userdb_file(int to_print);
|
||||
void auth_ping(redis_context_handle rch);
|
||||
void reread_realms(void);
|
||||
|
||||
@ -39,6 +39,178 @@
|
||||
#include "apputils.h"
|
||||
#include "stun_buffer.h"
|
||||
|
||||
//////////// OAUTH //////////////////
|
||||
|
||||
static const char* shas[]={"SHA1",
|
||||
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
|
||||
"SHA256",
|
||||
#endif
|
||||
NULL};
|
||||
static const char* encs[]={"AES-256-CBC","AES-128-CBC",
|
||||
#if !defined(TURN_NO_GCM)
|
||||
"AEAD_AES_128_GCM", "AEAD_AES_256_GCM",
|
||||
#endif
|
||||
NULL};
|
||||
static const char* hmacs[]={"HMAC-SHA-1",
|
||||
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
|
||||
"HMAC-SHA-256","HMAC-SHA-256-128",
|
||||
#endif
|
||||
NULL};
|
||||
|
||||
static int print_extra = 0;
|
||||
|
||||
void print_field5769(const char* name, const void* f0, size_t len);
|
||||
void print_field5769(const char* name, const void* f0, size_t len) {
|
||||
const unsigned char* f = (const unsigned char*)f0;
|
||||
printf("\nfield %s %lu==>>\n",name,(unsigned long)len);
|
||||
size_t i;
|
||||
for(i = 0;i<len;++i) {
|
||||
printf("\\x%x",(unsigned int)f[i]);
|
||||
}
|
||||
printf("\n<<==field %s\n",name);
|
||||
}
|
||||
|
||||
static int check_oauth(void) {
|
||||
|
||||
const char server_name[33] = "blackdow.carleon.gov";
|
||||
|
||||
size_t i_hmacs,i_shas,i_encs;
|
||||
|
||||
const char long_term_password[33] = "HGkj32KJGiuy098sdfaqbNjOiaz71923";
|
||||
|
||||
size_t ltp_output_length=0;
|
||||
|
||||
const char* base64encoded_ltp = base64_encode((const unsigned char *)long_term_password,
|
||||
strlen(long_term_password),
|
||||
<p_output_length);
|
||||
|
||||
const char mac_key[33] = "ZksjpweoixXmvn67534m";
|
||||
const size_t mac_key_length=strlen(mac_key);
|
||||
const uint64_t token_timestamp = (uint64_t)(92470300704768LL);
|
||||
const uint32_t token_lifetime = 3600;
|
||||
|
||||
const char kid[33] = "2783466234";
|
||||
const turn_time_t key_timestamp = 1234567890;
|
||||
const turn_time_t key_lifetime = 3600;
|
||||
|
||||
const char aead_nonce[OAUTH_AEAD_NONCE_SIZE+1] = "h4j3k2l2n4b5";
|
||||
|
||||
for (i_hmacs = 0; hmacs[i_hmacs]; ++i_hmacs) {
|
||||
|
||||
for (i_shas = 0; shas[i_shas]; ++i_shas) {
|
||||
|
||||
for (i_encs = 0; encs[i_encs]; ++i_encs) {
|
||||
|
||||
printf("oauth token %s:%s:%s:",hmacs[i_hmacs],shas[i_shas],encs[i_encs]);
|
||||
|
||||
if(print_extra)
|
||||
printf("\n");
|
||||
|
||||
oauth_token ot;
|
||||
ot.enc_block.key_length = (uint16_t)mac_key_length;
|
||||
STRCPY(ot.enc_block.mac_key,mac_key);
|
||||
ot.enc_block.timestamp = token_timestamp;
|
||||
ot.enc_block.lifetime = token_lifetime;
|
||||
|
||||
oauth_token dot;
|
||||
ns_bzero((&dot),sizeof(dot));
|
||||
oauth_key key;
|
||||
ns_bzero(&key,sizeof(key));
|
||||
|
||||
{
|
||||
oauth_key_data okd;
|
||||
ns_bzero(&okd,sizeof(okd));
|
||||
|
||||
{
|
||||
oauth_key_data_raw okdr;
|
||||
ns_bzero(&okdr,sizeof(okdr));
|
||||
|
||||
STRCPY(okdr.kid,kid);
|
||||
STRCPY(okdr.ikm_key,base64encoded_ltp);
|
||||
STRCPY(okdr.as_rs_alg, encs[i_encs]);
|
||||
STRCPY(okdr.auth_alg, hmacs[i_hmacs]);
|
||||
STRCPY(okdr.hkdf_hash_func, shas[i_shas]);
|
||||
okdr.timestamp = key_timestamp;
|
||||
okdr.lifetime = key_lifetime;
|
||||
|
||||
convert_oauth_key_data_raw(&okdr, &okd);
|
||||
|
||||
char err_msg[1025] = "\0";
|
||||
size_t err_msg_size = sizeof(err_msg) - 1;
|
||||
|
||||
if (convert_oauth_key_data(&okd, &key, err_msg,
|
||||
err_msg_size) < 0) {
|
||||
fprintf(stderr, "%s\n", err_msg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(print_extra) {
|
||||
print_field5769("AS-RS",key.as_rs_key,key.as_rs_key_size);
|
||||
print_field5769("AUTH",key.auth_key,key.auth_key_size);
|
||||
}
|
||||
|
||||
{
|
||||
encoded_oauth_token etoken;
|
||||
ns_bzero(&etoken,sizeof(etoken));
|
||||
|
||||
if (encode_oauth_token((const u08bits *) server_name, &etoken,
|
||||
&key, &ot, (const u08bits*)aead_nonce) < 0) {
|
||||
fprintf(stderr, "%s: cannot encode oauth token\n",
|
||||
__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(print_extra) {
|
||||
print_field5769("encoded token",etoken.token,etoken.size);
|
||||
}
|
||||
|
||||
if (decode_oauth_token((const u08bits *) server_name, &etoken,
|
||||
&key, &dot) < 0) {
|
||||
fprintf(stderr, "%s: cannot decode oauth token\n",
|
||||
__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp((char*) ot.enc_block.mac_key,
|
||||
(char*) dot.enc_block.mac_key)) {
|
||||
fprintf(stderr, "%s: wrong mac key: %s, must be %s\n",
|
||||
__FUNCTION__, (char*) dot.enc_block.mac_key,
|
||||
(char*) ot.enc_block.mac_key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ot.enc_block.key_length != dot.enc_block.key_length) {
|
||||
fprintf(stderr, "%s: wrong key length: %d, must be %d\n",
|
||||
__FUNCTION__, (int) dot.enc_block.key_length,
|
||||
(int) ot.enc_block.key_length);
|
||||
return -1;
|
||||
}
|
||||
if (ot.enc_block.timestamp != dot.enc_block.timestamp) {
|
||||
fprintf(stderr, "%s: wrong timestamp: %llu, must be %llu\n",
|
||||
__FUNCTION__,
|
||||
(unsigned long long) dot.enc_block.timestamp,
|
||||
(unsigned long long) ot.enc_block.timestamp);
|
||||
return -1;
|
||||
}
|
||||
if (ot.enc_block.lifetime != dot.enc_block.lifetime) {
|
||||
fprintf(stderr, "%s: wrong lifetime: %lu, must be %lu\n",
|
||||
__FUNCTION__,
|
||||
(unsigned long) dot.enc_block.lifetime,
|
||||
(unsigned long) ot.enc_block.lifetime);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("OK\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
static SHATYPE shatype = SHATYPE_SHA1;
|
||||
@ -50,6 +222,9 @@ int main(int argc, const char **argv)
|
||||
UNUSED_ARG(argc);
|
||||
UNUSED_ARG(argv);
|
||||
|
||||
if(argc>1)
|
||||
print_extra = 1;
|
||||
|
||||
set_logfile("stdout");
|
||||
set_system_parameters(0);
|
||||
|
||||
@ -401,5 +576,10 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if(check_oauth()<0)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
/////////////// extern definitions /////////////////////
|
||||
|
||||
@ -97,6 +98,14 @@ band_limit_t bps = 0;
|
||||
|
||||
int dual_allocation = 0;
|
||||
|
||||
int oauth = 0;
|
||||
oauth_key okey_array[2];
|
||||
|
||||
static oauth_key_data_raw okdr_array[2] = {
|
||||
{"north","Y2FybGVvbg==",0,0,"SHA-256","AES-256-CBC","","HMAC-SHA-256-128",""},
|
||||
{"oldempire","YXVsY3Vz",0,0,"SHA-256","AEAD-AES-256-GCM","","",""}
|
||||
};
|
||||
|
||||
//////////////// local definitions /////////////////
|
||||
|
||||
static char Usage[] =
|
||||
@ -130,6 +139,7 @@ static char Usage[] =
|
||||
" -G Generate extra requests (create permissions, channel bind).\n"
|
||||
" -B Random disconnect after a few initial packets.\n"
|
||||
" -Z Dual allocation.\n"
|
||||
" -J Use oAuth with default test key kid='north'.\n"
|
||||
"Options:\n"
|
||||
" -l Message length (Default: 100 Bytes).\n"
|
||||
" -i Certificate file (for secure connections only, optional).\n"
|
||||
@ -204,8 +214,35 @@ int main(int argc, char **argv)
|
||||
|
||||
ns_bzero(local_addr, sizeof(local_addr));
|
||||
|
||||
while ((c = getopt(argc, argv, "a:d:p:l:n:L:m:e:r:u:w:i:k:z:W:C:E:F:o:ZvsyhcxXgtTSAPDNOUHMRIGB")) != -1) {
|
||||
while ((c = getopt(argc, argv, "a:d:p:l:n:L:m:e:r:u:w:i:k:z:W:C:E:F:o:ZvsyhcxXgtTSAPDNOUHMRIGBJ")) != -1) {
|
||||
switch (c){
|
||||
case 'J': {
|
||||
|
||||
oauth = 1;
|
||||
|
||||
if(use_short_term) {
|
||||
fprintf(stderr,"Short-term mechanism cannot be used together with oAuth.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
oauth_key_data okd_array[2];
|
||||
convert_oauth_key_data_raw(&okdr_array[0], &okd_array[0]);
|
||||
convert_oauth_key_data_raw(&okdr_array[1], &okd_array[1]);
|
||||
|
||||
char err_msg[1025] = "\0";
|
||||
size_t err_msg_size = sizeof(err_msg) - 1;
|
||||
|
||||
if (convert_oauth_key_data(&okd_array[0], &okey_array[0], err_msg, err_msg_size) < 0) {
|
||||
fprintf(stderr, "%s\n", err_msg);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (convert_oauth_key_data(&okd_array[1], &okey_array[1], err_msg, err_msg_size) < 0) {
|
||||
fprintf(stderr, "%s\n", err_msg);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
bps = (band_limit_t)atol(optarg);
|
||||
break;
|
||||
@ -262,6 +299,10 @@ int main(int argc, char **argv)
|
||||
dual_allocation = 1;
|
||||
break;
|
||||
case 'A':
|
||||
if(oauth) {
|
||||
fprintf(stderr,"Short-term mechanism cannot be used together with oAuth.\n");
|
||||
exit(-1);
|
||||
}
|
||||
use_short_term = 1;
|
||||
break;
|
||||
case 'u':
|
||||
|
||||
@ -80,6 +80,12 @@ typedef struct {
|
||||
int broken;
|
||||
u08bits nonce[STUN_MAX_NONCE_SIZE+1];
|
||||
u08bits realm[STUN_MAX_REALM_SIZE+1];
|
||||
/* oAuth */
|
||||
int oauth;
|
||||
u08bits server_name[STUN_MAX_SERVER_NAME_SIZE+1];
|
||||
hmackey_t key;
|
||||
int key_set;
|
||||
int cok;
|
||||
/* RFC 6062 */
|
||||
app_tcp_conn_info **tcp_conn;
|
||||
size_t tcp_conn_number;
|
||||
|
||||
@ -360,9 +360,9 @@ static int clnet_allocate(int verbose,
|
||||
}
|
||||
|
||||
if(!dos)
|
||||
stun_set_allocate_request(&message, 800, af4, af6, relay_transport, mobility);
|
||||
stun_set_allocate_request(&message, UCLIENT_SESSION_LIFETIME, af4, af6, relay_transport, mobility);
|
||||
else
|
||||
stun_set_allocate_request(&message, 300, af4, af6, relay_transport, mobility);
|
||||
stun_set_allocate_request(&message, UCLIENT_SESSION_LIFETIME/3, af4, af6, relay_transport, mobility);
|
||||
|
||||
if(bps)
|
||||
stun_attr_add_bandwidth_str(message.buf, (size_t*)(&(message.len)), bps);
|
||||
@ -433,13 +433,8 @@ static int clnet_allocate(int verbose,
|
||||
allocate_finished = 1;
|
||||
|
||||
if(clnet_info->nonce[0] || use_short_term) {
|
||||
SHATYPE sht = clnet_info->shatype;
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
message.buf, (size_t)(message.len), g_uname,
|
||||
clnet_info->realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in allocate message received from server\n");
|
||||
if(check_integrity(clnet_info, &message)<0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
@ -500,13 +495,14 @@ static int clnet_allocate(int verbose,
|
||||
current_reservation_token = rtv;
|
||||
if (verbose)
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
|
||||
"%s: rtv=%llu\n", __FUNCTION__, rtv);
|
||||
"%s: rtv=%llu\n", __FUNCTION__, (long long unsigned int)rtv);
|
||||
|
||||
read_mobility_ticket(clnet_info, &message);
|
||||
|
||||
} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
|
||||
&err_code,err_msg,sizeof(err_msg),
|
||||
clnet_info->realm,clnet_info->nonce)) {
|
||||
clnet_info->realm,clnet_info->nonce,
|
||||
clnet_info->server_name, &(clnet_info->oauth))) {
|
||||
if(err_code == SHA_TOO_WEAK_ERROR_CODE && (clnet_info->shatype == SHATYPE_SHA1)) {
|
||||
clnet_info->shatype = SHATYPE_SHA256;
|
||||
recalculate_restapi_hmac();
|
||||
@ -524,13 +520,8 @@ static int clnet_allocate(int verbose,
|
||||
if(err_code == 300) {
|
||||
|
||||
if(clnet_info->nonce[0] || use_short_term) {
|
||||
SHATYPE sht = clnet_info->shatype;
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
message.buf, (size_t)(message.len), g_uname,
|
||||
clnet_info->realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in allocate message received from server\n");
|
||||
if(check_integrity(clnet_info, &message)<0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ioa_addr alternate_server;
|
||||
@ -551,7 +542,7 @@ static int clnet_allocate(int verbose,
|
||||
return -1;
|
||||
} else {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
|
||||
"trying allocate again...\n", err_code);
|
||||
"trying allocate again %d...\n", err_code);
|
||||
sleep(1);
|
||||
reopen_socket = 1;
|
||||
}
|
||||
@ -642,9 +633,8 @@ static int clnet_allocate(int verbose,
|
||||
|
||||
stun_buffer message;
|
||||
stun_init_request(STUN_METHOD_REFRESH, &message);
|
||||
uint32_t lt = htonl(600);
|
||||
stun_attr_add(&message, STUN_ATTRIBUTE_LIFETIME, (const char*) <,
|
||||
4);
|
||||
uint32_t lt = htonl(UCLIENT_SESSION_LIFETIME);
|
||||
stun_attr_add(&message, STUN_ATTRIBUTE_LIFETIME, (const char*) <, 4);
|
||||
|
||||
if(clnet_info->s_mobile_id[0]) {
|
||||
stun_attr_add(&message, STUN_ATTRIBUTE_MOBILITY_TICKET, (const char*)clnet_info->s_mobile_id, strlen(clnet_info->s_mobile_id));
|
||||
@ -665,6 +655,11 @@ static int clnet_allocate(int verbose,
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "refresh sent\n");
|
||||
}
|
||||
refresh_sent = 1;
|
||||
|
||||
if(clnet_info->s_mobile_id[0]) {
|
||||
usleep(10000);
|
||||
send_buffer(clnet_info, &message, 0,0);
|
||||
}
|
||||
} else {
|
||||
perror("send");
|
||||
exit(1);
|
||||
@ -682,6 +677,10 @@ static int clnet_allocate(int verbose,
|
||||
|
||||
int len = recv_buffer(clnet_info, &message, 1, 0);
|
||||
|
||||
if(clnet_info->s_mobile_id[0]) {
|
||||
len = recv_buffer(clnet_info, &message, 1, 0);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
if (verbose) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
|
||||
@ -698,7 +697,8 @@ static int clnet_allocate(int verbose,
|
||||
}
|
||||
} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
|
||||
&err_code,err_msg,sizeof(err_msg),
|
||||
clnet_info->realm,clnet_info->nonce)) {
|
||||
clnet_info->realm,clnet_info->nonce,
|
||||
clnet_info->server_name, &(clnet_info->oauth))) {
|
||||
if(err_code == SHA_TOO_WEAK_ERROR_CODE && (clnet_info->shatype == SHATYPE_SHA1)) {
|
||||
clnet_info->shatype = SHATYPE_SHA256;
|
||||
recalculate_restapi_hmac();
|
||||
@ -786,13 +786,8 @@ static int turn_channel_bind(int verbose, uint16_t *chn,
|
||||
cb_received = 1;
|
||||
|
||||
if(clnet_info->nonce[0] || use_short_term) {
|
||||
SHATYPE sht = clnet_info->shatype;
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
message.buf, (size_t)(message.len), g_uname,
|
||||
clnet_info->realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in channel bind message received from server\n");
|
||||
if(check_integrity(clnet_info, &message)<0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
@ -801,7 +796,8 @@ static int turn_channel_bind(int verbose, uint16_t *chn,
|
||||
}
|
||||
} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
|
||||
&err_code,err_msg,sizeof(err_msg),
|
||||
clnet_info->realm,clnet_info->nonce)) {
|
||||
clnet_info->realm,clnet_info->nonce,
|
||||
clnet_info->server_name, &(clnet_info->oauth))) {
|
||||
if(err_code == SHA_TOO_WEAK_ERROR_CODE && (clnet_info->shatype == SHATYPE_SHA1)) {
|
||||
clnet_info->shatype = SHATYPE_SHA256;
|
||||
recalculate_restapi_hmac();
|
||||
@ -900,13 +896,8 @@ static int turn_create_permission(int verbose, app_ur_conn_info *clnet_info,
|
||||
cp_received = 1;
|
||||
|
||||
if(clnet_info->nonce[0] || use_short_term) {
|
||||
SHATYPE sht = clnet_info->shatype;
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
message.buf, (size_t)(message.len), g_uname,
|
||||
clnet_info->realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in create permission message received from server\n");
|
||||
if(check_integrity(clnet_info, &message)<0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
@ -914,7 +905,8 @@ static int turn_create_permission(int verbose, app_ur_conn_info *clnet_info,
|
||||
}
|
||||
} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
|
||||
&err_code,err_msg,sizeof(err_msg),
|
||||
clnet_info->realm,clnet_info->nonce)) {
|
||||
clnet_info->realm,clnet_info->nonce,
|
||||
clnet_info->server_name, &(clnet_info->oauth))) {
|
||||
if(err_code == SHA_TOO_WEAK_ERROR_CODE && (clnet_info->shatype == SHATYPE_SHA1)) {
|
||||
clnet_info->shatype = SHATYPE_SHA256;
|
||||
recalculate_restapi_hmac();
|
||||
@ -1486,13 +1478,8 @@ static int turn_tcp_connection_bind(int verbose, app_ur_conn_info *clnet_info, a
|
||||
if (stun_is_success_response(&message)) {
|
||||
|
||||
if(clnet_info->nonce[0] || use_short_term) {
|
||||
SHATYPE sht = clnet_info->shatype;
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
message.buf, (size_t)(message.len), g_uname,
|
||||
clnet_info->realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in connect bind message received from server\n");
|
||||
if(check_integrity(clnet_info, &message)<0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(stun_get_method(&message)!=STUN_METHOD_CONNECTION_BIND)
|
||||
@ -1504,7 +1491,8 @@ static int turn_tcp_connection_bind(int verbose, app_ur_conn_info *clnet_info, a
|
||||
atc->tcp_data_bound = 1;
|
||||
} else if (stun_is_challenge_response_str(message.buf, (size_t)message.len,
|
||||
&err_code,err_msg,sizeof(err_msg),
|
||||
clnet_info->realm,clnet_info->nonce)) {
|
||||
clnet_info->realm,clnet_info->nonce,
|
||||
clnet_info->server_name, &(clnet_info->oauth))) {
|
||||
if(err_code == SHA_TOO_WEAK_ERROR_CODE && (clnet_info->shatype == SHATYPE_SHA1)) {
|
||||
clnet_info->shatype = SHATYPE_SHA256;
|
||||
recalculate_restapi_hmac();
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
static int verbose_packets=0;
|
||||
|
||||
@ -510,13 +511,9 @@ static int client_read(app_ur_session *elem, int is_tcp_data, app_tcp_conn_info
|
||||
} else if (stun_is_indication(&(elem->in_buffer))) {
|
||||
|
||||
if(use_short_term) {
|
||||
SHATYPE sht = elem->pinfo.shatype;
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
elem->in_buffer.buf, (size_t)(elem->in_buffer.len), g_uname,
|
||||
elem->pinfo.realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in indication message 0x%x received from server\n",(unsigned int)stun_get_method(&(elem->in_buffer)));
|
||||
|
||||
if(check_integrity(&(elem->pinfo), &(elem->in_buffer))<0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t method = stun_get_method(&elem->in_buffer);
|
||||
@ -569,13 +566,8 @@ static int client_read(app_ur_session *elem, int is_tcp_data, app_tcp_conn_info
|
||||
} else if (stun_is_success_response(&(elem->in_buffer))) {
|
||||
|
||||
if(elem->pinfo.nonce[0] || use_short_term) {
|
||||
SHATYPE sht = elem->pinfo.shatype;
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
elem->in_buffer.buf, (size_t)(elem->in_buffer.len), g_uname,
|
||||
elem->pinfo.realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in success message 0x%x received from server\n",(unsigned int)stun_get_method(&(elem->in_buffer)));
|
||||
if(check_integrity(&(elem->pinfo), &(elem->in_buffer))<0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(is_TCP_relay() && (stun_get_method(&(elem->in_buffer)) == STUN_METHOD_CONNECT)) {
|
||||
@ -595,7 +587,8 @@ static int client_read(app_ur_session *elem, int is_tcp_data, app_tcp_conn_info
|
||||
return rc;
|
||||
} else if (stun_is_challenge_response_str(elem->in_buffer.buf, (size_t)elem->in_buffer.len,
|
||||
&err_code,err_msg,sizeof(err_msg),
|
||||
clnet_info->realm,clnet_info->nonce)) {
|
||||
clnet_info->realm,clnet_info->nonce,
|
||||
clnet_info->server_name, &(clnet_info->oauth))) {
|
||||
if(err_code == SHA_TOO_WEAK_ERROR_CODE && (elem->pinfo.shatype == SHATYPE_SHA1)) {
|
||||
elem->pinfo.shatype = SHATYPE_SHA256;
|
||||
recalculate_restapi_hmac();
|
||||
@ -1437,9 +1430,93 @@ int add_integrity(app_ur_conn_info *clnet_info, stun_buffer *message)
|
||||
return -1;
|
||||
}
|
||||
} else if(clnet_info->nonce[0]) {
|
||||
if(stun_attr_add_integrity_by_user_str(message->buf, (size_t*)&(message->len), g_uname,
|
||||
|
||||
if(oauth && clnet_info->oauth) {
|
||||
|
||||
u16bits method = stun_get_method_str(message->buf, message->len);
|
||||
|
||||
int cok = clnet_info->cok;
|
||||
|
||||
if(((method == STUN_METHOD_ALLOCATE) || (method == STUN_METHOD_REFRESH)) || !(clnet_info->key_set))
|
||||
{
|
||||
|
||||
cok=(random())%2;
|
||||
if(cok<0) cok=-cok;
|
||||
clnet_info->cok = cok;
|
||||
oauth_token otoken;
|
||||
encoded_oauth_token etoken;
|
||||
u08bits nonce[12];
|
||||
RAND_bytes((unsigned char*)nonce,12);
|
||||
long halflifetime = OAUTH_SESSION_LIFETIME/2;
|
||||
long random_lifetime = 0;
|
||||
while(!random_lifetime) {
|
||||
random_lifetime = random();
|
||||
}
|
||||
if(random_lifetime<0) random_lifetime=-random_lifetime;
|
||||
random_lifetime = random_lifetime % halflifetime;
|
||||
otoken.enc_block.lifetime = (uint32_t)(halflifetime + random_lifetime);
|
||||
otoken.enc_block.timestamp = ((uint64_t)turn_time()) << 16;
|
||||
if(shatype == SHATYPE_SHA256) {
|
||||
otoken.enc_block.key_length = 32;
|
||||
} else {
|
||||
otoken.enc_block.key_length = 20;
|
||||
}
|
||||
RAND_bytes((unsigned char *)(otoken.enc_block.mac_key), otoken.enc_block.key_length);
|
||||
if(encode_oauth_token(clnet_info->server_name, &etoken, &(okey_array[cok]), &otoken, nonce)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO," Cannot encode token\n");
|
||||
return -1;
|
||||
}
|
||||
stun_attr_add_str(message->buf, (size_t*)&(message->len), STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN,
|
||||
(const u08bits*)etoken.token, (int)etoken.size);
|
||||
|
||||
ns_bcopy(otoken.enc_block.mac_key,clnet_info->key,otoken.enc_block.key_length);
|
||||
clnet_info->key_set = 1;
|
||||
}
|
||||
|
||||
if(stun_attr_add_integrity_by_key_str(message->buf, (size_t*)&(message->len), (u08bits*)okey_array[cok].kid,
|
||||
clnet_info->realm, clnet_info->key, clnet_info->nonce, clnet_info->shatype)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO," Cannot add integrity to the message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//self-test:
|
||||
{
|
||||
st_password_t pwd;
|
||||
if(stun_check_message_integrity_by_key_str(get_turn_credentials_type(),
|
||||
message->buf, (size_t)(message->len), clnet_info->key, pwd, clnet_info->shatype, NULL)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR," Self-test of integrity does not comple correctly !\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(stun_attr_add_integrity_by_user_str(message->buf, (size_t*)&(message->len), g_uname,
|
||||
clnet_info->realm, g_upwd, clnet_info->nonce, clnet_info->shatype)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO," Cannot add integrity to the message\n");
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO," Cannot add integrity to the message\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_integrity(app_ur_conn_info *clnet_info, stun_buffer *message)
|
||||
{
|
||||
SHATYPE sht = clnet_info->shatype;
|
||||
|
||||
if(oauth && clnet_info->oauth) {
|
||||
|
||||
st_password_t pwd;
|
||||
|
||||
return stun_check_message_integrity_by_key_str(get_turn_credentials_type(),
|
||||
message->buf, (size_t)(message->len), clnet_info->key, pwd, sht, NULL);
|
||||
|
||||
} else {
|
||||
|
||||
if(stun_check_message_integrity_str(get_turn_credentials_type(),
|
||||
message->buf, (size_t)(message->len), g_uname,
|
||||
clnet_info->realm, g_upwd, sht)<1) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Wrong integrity in a message received from server\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,6 +86,12 @@ extern int dual_allocation;
|
||||
|
||||
extern char origin[STUN_MAX_ORIGIN_SIZE+1];
|
||||
|
||||
extern int oauth;
|
||||
extern oauth_key okey_array[2];
|
||||
|
||||
#define UCLIENT_SESSION_LIFETIME (777)
|
||||
#define OAUTH_SESSION_LIFETIME (555)
|
||||
|
||||
#define is_TCP_relay() (relay_transport == STUN_ATTRIBUTE_TRANSPORT_TCP_VALUE)
|
||||
|
||||
void start_mclient(const char *remote_address, int port,
|
||||
@ -100,6 +106,7 @@ void client_input_handler(evutil_socket_t fd, short what, void* arg);
|
||||
turn_credential_type get_turn_credentials_type(void);
|
||||
|
||||
int add_integrity(app_ur_conn_info *clnet_info, stun_buffer *message);
|
||||
int check_integrity(app_ur_conn_info *clnet_info, stun_buffer *message);
|
||||
|
||||
void recalculate_restapi_hmac(void);
|
||||
|
||||
|
||||
@ -665,8 +665,9 @@ public:
|
||||
*/
|
||||
static bool isChallengeResponse(const u08bits* buf, size_t sz,
|
||||
int &err_code, u08bits *err_msg, size_t err_msg_size,
|
||||
u08bits *realm, u08bits *nonce) {
|
||||
return stun_is_challenge_response_str(buf, sz, &err_code, err_msg, err_msg_size, realm, nonce);
|
||||
u08bits *realm, u08bits *nonce,
|
||||
u08bits *server_name, int *oauth) {
|
||||
return stun_is_challenge_response_str(buf, sz, &err_code, err_msg, err_msg_size, realm, nonce, server_name, oauth);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -970,7 +971,7 @@ public:
|
||||
size_t err_msg_size=sizeof(err_msg);
|
||||
u08bits srealm[0xFFFF];
|
||||
u08bits snonce[0xFFFF];
|
||||
ret = stun_is_challenge_response_str(_buffer, _sz, &err_code, err_msg, err_msg_size, srealm, snonce);
|
||||
ret = stun_is_challenge_response_str(_buffer, _sz, &err_code, err_msg, err_msg_size, srealm, snonce, NULL, NULL);
|
||||
if(ret) {
|
||||
realm = (char*)srealm;
|
||||
nonce = (char*)snonce;
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
*/
|
||||
|
||||
#include "ns_turn_ioaddr.h"
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
@ -202,7 +204,61 @@ int make_ioa_addr(const u08bits* saddr, int port, ioa_addr *addr) {
|
||||
#endif
|
||||
addr->s6.sin6_port = nswap16(port);
|
||||
} else {
|
||||
return -1;
|
||||
struct addrinfo addr_hints;
|
||||
struct addrinfo *addr_result = NULL;
|
||||
int err;
|
||||
|
||||
memset(&addr_hints, 0, sizeof(struct addrinfo));
|
||||
addr_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
addr_hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
|
||||
addr_hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
|
||||
addr_hints.ai_protocol = 0; /* Any protocol */
|
||||
addr_hints.ai_canonname = NULL;
|
||||
addr_hints.ai_addr = NULL;
|
||||
addr_hints.ai_next = NULL;
|
||||
|
||||
err = getaddrinfo((const char*)saddr, NULL, &addr_hints, &addr_result);
|
||||
if ((err != 0)||(!addr_result)) {
|
||||
fprintf(stderr,"error resolving '%s' hostname: %s\n",saddr,gai_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int family = AF_INET;
|
||||
struct addrinfo *addr_result_orig = addr_result;
|
||||
int found = 0;
|
||||
|
||||
beg_af:
|
||||
|
||||
while(!found && addr_result) {
|
||||
|
||||
if(addr_result->ai_family == family) {
|
||||
ns_bcopy(addr_result->ai_addr, addr, addr_result->ai_addrlen);
|
||||
if (addr_result->ai_family == AF_INET) {
|
||||
addr->s4.sin_port = nswap16(port);
|
||||
#if defined(TURN_HAS_SIN_LEN) /* tested when configured */
|
||||
addr->s4.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
} else if (addr_result->ai_family == AF_INET6) {
|
||||
addr->s6.sin6_port = nswap16(port);
|
||||
#if defined(SIN6_LEN) /* this define is required by IPv6 if used */
|
||||
addr->s6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
found = 1;
|
||||
}
|
||||
|
||||
addr_result = addr_result->ai_next;
|
||||
}
|
||||
|
||||
if(!found && family == AF_INET) {
|
||||
family = AF_INET6;
|
||||
addr_result = addr_result_orig;
|
||||
goto beg_af;
|
||||
}
|
||||
|
||||
freeaddrinfo(addr_result_orig);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -257,7 +313,7 @@ int make_ioa_addr_from_full_string(const u08bits* saddr, int default_port, ioa_a
|
||||
port = default_port;
|
||||
ret = make_ioa_addr((u08bits*)sa,port,addr);
|
||||
}
|
||||
turn_free(s,strlen(s)+1);
|
||||
free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -437,10 +493,10 @@ static size_t msz = 0;
|
||||
void ioa_addr_add_mapping(ioa_addr *apub, ioa_addr *apriv)
|
||||
{
|
||||
size_t new_size = msz + sizeof(ioa_addr*);
|
||||
public_addrs = (ioa_addr**)turn_realloc(public_addrs, msz, new_size);
|
||||
private_addrs = (ioa_addr**)turn_realloc(private_addrs, msz, new_size);
|
||||
public_addrs[mcount]=(ioa_addr*)turn_malloc(sizeof(ioa_addr));
|
||||
private_addrs[mcount]=(ioa_addr*)turn_malloc(sizeof(ioa_addr));
|
||||
public_addrs = (ioa_addr**)realloc(public_addrs, new_size);
|
||||
private_addrs = (ioa_addr**)realloc(private_addrs, new_size);
|
||||
public_addrs[mcount]=(ioa_addr*)malloc(sizeof(ioa_addr));
|
||||
private_addrs[mcount]=(ioa_addr*)malloc(sizeof(ioa_addr));
|
||||
addr_cpy(public_addrs[mcount],apub);
|
||||
addr_cpy(private_addrs[mcount],apriv);
|
||||
++mcount;
|
||||
|
||||
@ -39,6 +39,8 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
///////////
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
///////////
|
||||
@ -85,7 +87,7 @@ int stun_method_str(u16bits method, char *smethod)
|
||||
};
|
||||
|
||||
if(smethod) {
|
||||
STRCPY(smethod,s);
|
||||
ns_bcopy(s,smethod,strlen(s)+1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -101,7 +103,7 @@ long turn_random(void)
|
||||
|
||||
void turn_random32_size(u32bits *ar, size_t sz)
|
||||
{
|
||||
if(!RAND_bytes((unsigned char *)ar, sz<<2)<0) {
|
||||
if(!RAND_bytes((unsigned char *)ar, sz<<2)) {
|
||||
size_t i;
|
||||
for(i=0;i<sz;++i) {
|
||||
ar[i] = (u32bits)random();
|
||||
@ -114,14 +116,16 @@ int stun_calculate_hmac(const u08bits *buf, size_t len, const u08bits *key, size
|
||||
ERR_clear_error();
|
||||
UNUSED_ARG(shatype);
|
||||
|
||||
#if !defined(OPENSSL_NO_SHA256) && defined(SSL_TXT_SHA256)
|
||||
if(shatype == SHATYPE_SHA256) {
|
||||
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
|
||||
if (!HMAC(EVP_sha256(), key, keylen, buf, len, hmac, hmac_len)) {
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
#else
|
||||
fprintf(stderr,"SHA256 is not supported\n");
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
} else
|
||||
if (!HMAC(EVP_sha1(), key, keylen, buf, len, hmac, hmac_len)) {
|
||||
return -1;
|
||||
}
|
||||
@ -139,7 +143,7 @@ int stun_produce_integrity_key_str(u08bits *uname, u08bits *realm, u08bits *upwd
|
||||
size_t plen = strlen((s08bits*)upwd);
|
||||
size_t sz = ulen+1+rlen+1+plen+1+10;
|
||||
size_t strl = ulen+1+rlen+1+plen;
|
||||
u08bits *str = (u08bits*)malloc(sz+1);
|
||||
u08bits *str = (u08bits*)turn_malloc(sz+1);
|
||||
|
||||
strncpy((s08bits*)str,(s08bits*)uname,sz);
|
||||
str[ulen]=':';
|
||||
@ -148,23 +152,26 @@ int stun_produce_integrity_key_str(u08bits *uname, u08bits *realm, u08bits *upwd
|
||||
strncpy((s08bits*)str+ulen+1+rlen+1,(s08bits*)upwd,sz-ulen-1-rlen-1);
|
||||
str[strl]=0;
|
||||
|
||||
#if !defined(OPENSSL_NO_SHA256) && defined(SSL_TXT_SHA256)
|
||||
if(shatype == SHATYPE_SHA256) {
|
||||
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
|
||||
unsigned int keylen = 0;
|
||||
EVP_MD_CTX ctx;
|
||||
EVP_DigestInit(&ctx,EVP_sha256());
|
||||
EVP_DigestUpdate(&ctx,str,strl);
|
||||
EVP_DigestFinal(&ctx,key,&keylen);
|
||||
} else
|
||||
EVP_MD_CTX_cleanup(&ctx);
|
||||
#else
|
||||
fprintf(stderr,"SHA256 is not supported\n");
|
||||
return -1;
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
MD5_CTX ctx;
|
||||
MD5_Init(&ctx);
|
||||
MD5_Update(&ctx,str,strl);
|
||||
MD5_Final(key,&ctx);
|
||||
}
|
||||
|
||||
free(str);
|
||||
turn_free(str,sz+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -325,7 +332,7 @@ int stun_is_error_response_str(const u08bits* buf, size_t len, int *err_code, u0
|
||||
}
|
||||
|
||||
int stun_is_challenge_response_str(const u08bits* buf, size_t len, int *err_code, u08bits *err_msg, size_t err_msg_size,
|
||||
u08bits *realm, u08bits *nonce)
|
||||
u08bits *realm, u08bits *nonce, u08bits *server_name, int *oauth)
|
||||
{
|
||||
int ret = stun_is_error_response_str(buf, len, err_code, err_msg, err_msg_size);
|
||||
|
||||
@ -333,11 +340,31 @@ int stun_is_challenge_response_str(const u08bits* buf, size_t len, int *err_code
|
||||
|
||||
stun_attr_ref sar = stun_attr_get_first_by_type_str(buf,len,STUN_ATTRIBUTE_REALM);
|
||||
if(sar) {
|
||||
|
||||
int found_oauth = 0;
|
||||
|
||||
const u08bits *value = stun_attr_get_value(sar);
|
||||
if(value) {
|
||||
size_t vlen = (size_t)stun_attr_get_len(sar);
|
||||
ns_bcopy(value,realm,vlen);
|
||||
realm[vlen]=0;
|
||||
|
||||
{
|
||||
stun_attr_ref sar = stun_attr_get_first_by_type_str(buf,len,STUN_ATTRIBUTE_THIRD_PARTY_AUTHORIZATION);
|
||||
if(sar) {
|
||||
const u08bits *value = stun_attr_get_value(sar);
|
||||
if(value) {
|
||||
size_t vlen = (size_t)stun_attr_get_len(sar);
|
||||
if(vlen>0) {
|
||||
if(server_name) {
|
||||
ns_bcopy(value,server_name,vlen);
|
||||
}
|
||||
found_oauth = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sar = stun_attr_get_first_by_type_str(buf,len,STUN_ATTRIBUTE_NONCE);
|
||||
if(sar) {
|
||||
value = stun_attr_get_value(sar);
|
||||
@ -345,6 +372,9 @@ int stun_is_challenge_response_str(const u08bits* buf, size_t len, int *err_code
|
||||
vlen = (size_t)stun_attr_get_len(sar);
|
||||
ns_bcopy(value,nonce,vlen);
|
||||
nonce[vlen]=0;
|
||||
if(oauth) {
|
||||
*oauth = found_oauth;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -836,12 +866,14 @@ int stun_set_binding_response_str(u08bits* buf, size_t *len, stun_tid* tid,
|
||||
} else {
|
||||
old_stun_init_success_response_str(STUN_METHOD_BINDING, buf, len, tid, cookie);
|
||||
}
|
||||
if(!old_stun) {
|
||||
if(!old_stun && reflexive_addr) {
|
||||
if (stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, reflexive_addr) < 0)
|
||||
return -1;
|
||||
}
|
||||
if (stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_MAPPED_ADDRESS, reflexive_addr) < 0)
|
||||
return -1;
|
||||
if(reflexive_addr) {
|
||||
if (stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_MAPPED_ADDRESS, reflexive_addr) < 0)
|
||||
return -1;
|
||||
}
|
||||
} else if (!old_stun) {
|
||||
stun_init_error_response_str(STUN_METHOD_BINDING, buf, len, error_code, reason, tid);
|
||||
} else {
|
||||
@ -936,10 +968,16 @@ void stun_tid_generate_in_message_str(u08bits* buf, stun_tid* id) {
|
||||
|
||||
/////////////////// TIME ////////////////////////////////////////////////////////
|
||||
|
||||
u32bits stun_adjust_allocate_lifetime(u32bits lifetime) {
|
||||
if(!lifetime) return STUN_DEFAULT_ALLOCATE_LIFETIME;
|
||||
else if(lifetime<STUN_MIN_ALLOCATE_LIFETIME) return STUN_MIN_ALLOCATE_LIFETIME;
|
||||
else if(lifetime>STUN_MAX_ALLOCATE_LIFETIME) return STUN_MAX_ALLOCATE_LIFETIME;
|
||||
turn_time_t stun_adjust_allocate_lifetime(turn_time_t lifetime, turn_time_t max_lifetime) {
|
||||
|
||||
if(!lifetime) lifetime = STUN_DEFAULT_ALLOCATE_LIFETIME;
|
||||
else if(lifetime<STUN_MIN_ALLOCATE_LIFETIME) lifetime = STUN_MIN_ALLOCATE_LIFETIME;
|
||||
else if(lifetime>STUN_MAX_ALLOCATE_LIFETIME) lifetime = STUN_MAX_ALLOCATE_LIFETIME;
|
||||
|
||||
if(max_lifetime && (max_lifetime < lifetime)) {
|
||||
lifetime = max_lifetime;
|
||||
}
|
||||
|
||||
return lifetime;
|
||||
}
|
||||
|
||||
@ -1442,13 +1480,8 @@ int stun_attr_add_integrity_str(turn_credential_type ct, u08bits *buf, size_t *l
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stun_attr_add_integrity_by_user_str(u08bits *buf, size_t *len, u08bits *uname, u08bits *realm, u08bits *upwd, u08bits *nonce, SHATYPE shatype)
|
||||
int stun_attr_add_integrity_by_key_str(u08bits *buf, size_t *len, u08bits *uname, u08bits *realm, hmackey_t key, u08bits *nonce, SHATYPE shatype)
|
||||
{
|
||||
hmackey_t key;
|
||||
|
||||
if(stun_produce_integrity_key_str(uname, realm, upwd, key, shatype)<0)
|
||||
return -1;
|
||||
|
||||
if(stun_attr_add_str(buf, len, STUN_ATTRIBUTE_USERNAME, uname, strlen((s08bits*)uname))<0)
|
||||
return -1;
|
||||
|
||||
@ -1462,6 +1495,16 @@ int stun_attr_add_integrity_by_user_str(u08bits *buf, size_t *len, u08bits *unam
|
||||
return stun_attr_add_integrity_str(TURN_CREDENTIALS_LONG_TERM, buf, len, key, p, shatype);
|
||||
}
|
||||
|
||||
int stun_attr_add_integrity_by_user_str(u08bits *buf, size_t *len, u08bits *uname, u08bits *realm, u08bits *upwd, u08bits *nonce, SHATYPE shatype)
|
||||
{
|
||||
hmackey_t key;
|
||||
|
||||
if(stun_produce_integrity_key_str(uname, realm, upwd, key, shatype)<0)
|
||||
return -1;
|
||||
|
||||
return stun_attr_add_integrity_by_key_str(buf, len, uname, realm, key, nonce, shatype);
|
||||
}
|
||||
|
||||
int stun_attr_add_integrity_by_user_short_term_str(u08bits *buf, size_t *len, u08bits *uname, st_password_t pwd, SHATYPE shatype)
|
||||
{
|
||||
if(stun_attr_add_str(buf, len, STUN_ATTRIBUTE_USERNAME, uname, strlen((s08bits*)uname))<0)
|
||||
@ -1543,7 +1586,7 @@ int stun_check_message_integrity_by_key_str(turn_credential_type ct, u08bits *bu
|
||||
if(bcmp(old_hmac,new_hmac,shasize))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return +1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1630,4 +1673,728 @@ int stun_attr_add_padding_str(u08bits *buf, size_t *len, u16bits padding_len)
|
||||
return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_PADDING, avalue, padding_len);
|
||||
}
|
||||
|
||||
/* OAUTH */
|
||||
|
||||
#define OAUTH_ERROR(...) fprintf(stderr,__VA_ARGS__)
|
||||
|
||||
static void remove_spaces(char *s)
|
||||
{
|
||||
char *sfns = s;
|
||||
while(*sfns) {
|
||||
if(*sfns != ' ')
|
||||
break;
|
||||
++sfns;
|
||||
}
|
||||
if(*sfns) {
|
||||
if(sfns != s) {
|
||||
while(*sfns && (*sfns != ' ')) {
|
||||
*s = *sfns;
|
||||
++s;
|
||||
++sfns;
|
||||
};
|
||||
*s = 0;
|
||||
} else {
|
||||
while(*s) {
|
||||
if(*s == ' ') {
|
||||
*s = 0;
|
||||
break;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void normalize_algorithm(char *s)
|
||||
{
|
||||
char c = *s;
|
||||
while(c) {
|
||||
if(c=='_') *s='-';
|
||||
else if((c>='a')&&(c<='z')) {
|
||||
*s = c - 'a' + 'A';
|
||||
}
|
||||
++s;
|
||||
c = *s;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t calculate_enc_key_length(ENC_ALG a)
|
||||
{
|
||||
switch(a) {
|
||||
case AES_128_CBC:
|
||||
case AEAD_AES_128_GCM:
|
||||
return 16;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
static size_t calculate_auth_key_length(AUTH_ALG a)
|
||||
{
|
||||
switch(a) {
|
||||
case AUTH_ALG_HMAC_SHA_1:
|
||||
return 20;
|
||||
case AUTH_ALG_HMAC_SHA_256_128:
|
||||
return 32;
|
||||
case AUTH_ALG_HMAC_SHA_256:
|
||||
return 32;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
static size_t calculate_auth_output_length(AUTH_ALG a)
|
||||
{
|
||||
switch(a) {
|
||||
case AUTH_ALG_HMAC_SHA_1:
|
||||
return 20;
|
||||
case AUTH_ALG_HMAC_SHA_256_128:
|
||||
return 16;
|
||||
case AUTH_ALG_HMAC_SHA_256:
|
||||
return 32;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
static int calculate_key(char *key, size_t key_size, char *new_key, size_t new_key_size, SHATYPE shatype,
|
||||
char *err_msg, size_t err_msg_size)
|
||||
{
|
||||
//Extract:
|
||||
u08bits prk[128];
|
||||
unsigned int prk_len = 0;
|
||||
stun_calculate_hmac((const u08bits *)key, key_size, (const u08bits *)"", 0, prk, &prk_len, shatype);
|
||||
|
||||
//Expand:
|
||||
u08bits buf[128];
|
||||
buf[0]=1;
|
||||
u08bits hmac[128];
|
||||
unsigned int hmac_len = 0;
|
||||
stun_calculate_hmac((const u08bits *)buf, 1, prk, prk_len, hmac, &hmac_len, shatype);
|
||||
ns_bcopy(hmac,new_key,hmac_len);
|
||||
|
||||
//Check
|
||||
if(new_key_size>hmac_len) {
|
||||
ns_bcopy(hmac,buf,hmac_len);
|
||||
buf[hmac_len]=2;
|
||||
u08bits hmac1[128];
|
||||
unsigned int hmac1_len = 0;
|
||||
stun_calculate_hmac((const u08bits *)buf, hmac_len+1, prk, prk_len, hmac1, &hmac1_len, shatype);
|
||||
ns_bcopy(hmac1,new_key+hmac_len,hmac1_len);
|
||||
if(new_key_size > (hmac_len + hmac1_len)) {
|
||||
if(err_msg) {
|
||||
snprintf(err_msg,err_msg_size,"Wrong HKDF procedure (key sizes): output.sz=%lu, hmac(1)=%lu, hmac(2)=%lu",(unsigned long)new_key_size,(unsigned long)hmac_len,(unsigned long)hmac1_len);
|
||||
}
|
||||
OAUTH_ERROR("Wrong HKDF procedure (key sizes): output.sz=%lu, hmac(1)=%lu, hmac(2)=%lu",(unsigned long)new_key_size,(unsigned long)hmac_len,(unsigned long)hmac1_len);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int convert_oauth_key_data(const oauth_key_data *oakd0, oauth_key *key, char *err_msg, size_t err_msg_size)
|
||||
{
|
||||
if(oakd0 && key) {
|
||||
|
||||
oauth_key_data oakd_obj;
|
||||
ns_bcopy(oakd0,&oakd_obj,sizeof(oauth_key_data));
|
||||
oauth_key_data *oakd = &oakd_obj;
|
||||
|
||||
if(!(oakd->ikm_key_size)) {
|
||||
if(!(oakd->as_rs_key_size)) {
|
||||
if(err_msg) {
|
||||
snprintf(err_msg,err_msg_size,"AS-RS key is not defined");
|
||||
}
|
||||
OAUTH_ERROR("AS-RS key is not defined\n");
|
||||
return -1;
|
||||
}
|
||||
if(!(oakd->auth_key_size)) {
|
||||
//AEAD ?
|
||||
}
|
||||
}
|
||||
|
||||
remove_spaces(oakd->kid);
|
||||
|
||||
remove_spaces(oakd->hkdf_hash_func);
|
||||
remove_spaces(oakd->as_rs_alg);
|
||||
remove_spaces(oakd->auth_alg);
|
||||
|
||||
normalize_algorithm(oakd->hkdf_hash_func);
|
||||
normalize_algorithm(oakd->as_rs_alg);
|
||||
normalize_algorithm(oakd->auth_alg);
|
||||
|
||||
if(!(oakd->kid[0])) {
|
||||
if(err_msg) {
|
||||
snprintf(err_msg,err_msg_size,"KID is not defined");
|
||||
}
|
||||
OAUTH_ERROR("KID is not defined\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ns_bzero(key,sizeof(oauth_key));
|
||||
|
||||
STRCPY(key->kid,oakd->kid);
|
||||
|
||||
ns_bcopy(oakd->as_rs_key,key->as_rs_key,sizeof(key->as_rs_key));
|
||||
key->as_rs_key_size = oakd->as_rs_key_size;
|
||||
ns_bcopy(oakd->auth_key,key->auth_key,sizeof(key->auth_key));
|
||||
key->auth_key_size = oakd->auth_key_size;
|
||||
ns_bcopy(oakd->ikm_key,key->ikm_key,sizeof(key->ikm_key));
|
||||
key->ikm_key_size = oakd->ikm_key_size;
|
||||
|
||||
key->timestamp = oakd->timestamp;
|
||||
key->lifetime = oakd->lifetime;
|
||||
|
||||
if(!(key->timestamp)) key->timestamp = OAUTH_DEFAULT_TIMESTAMP;
|
||||
if(!(key->lifetime)) key->lifetime = OAUTH_DEFAULT_LIFETIME;
|
||||
|
||||
key->hkdf_hash_func = SHATYPE_SHA256;
|
||||
if(!strcmp(oakd->hkdf_hash_func,"SHA1") || !strcmp(oakd->hkdf_hash_func,"SHA-1")) {
|
||||
key->hkdf_hash_func = SHATYPE_SHA1;
|
||||
} else if(!strcmp(oakd->hkdf_hash_func,"SHA256") || !strcmp(oakd->hkdf_hash_func,"SHA-256")) {
|
||||
key->hkdf_hash_func = SHATYPE_SHA256;
|
||||
} else if(oakd->hkdf_hash_func[0]) {
|
||||
if(err_msg) {
|
||||
snprintf(err_msg,err_msg_size,"Wrong HKDF hash function algorithm: %s",oakd->hkdf_hash_func);
|
||||
}
|
||||
OAUTH_ERROR("Wrong HKDF hash function algorithm: %s\n",oakd->hkdf_hash_func);
|
||||
return -1;
|
||||
}
|
||||
|
||||
key->auth_alg = AUTH_ALG_DEFAULT;
|
||||
if(!strcmp(oakd->auth_alg,"HMAC-SHA-1") || !strcmp(oakd->auth_alg,"HMAC-SHA1")) {
|
||||
key->auth_alg = AUTH_ALG_HMAC_SHA_1;
|
||||
} else if(!strcmp(oakd->auth_alg,"HMAC-SHA-256")) {
|
||||
key->auth_alg = AUTH_ALG_HMAC_SHA_256;
|
||||
} else if(!strcmp(oakd->auth_alg,"HMAC-SHA-256-128")) {
|
||||
key->auth_alg = AUTH_ALG_HMAC_SHA_256_128;
|
||||
} else if(oakd->auth_alg[0]) {
|
||||
if(err_msg) {
|
||||
snprintf(err_msg,err_msg_size,"Wrong oAuth token hash algorithm: %s (1)\n",oakd->auth_alg);
|
||||
}
|
||||
key->auth_alg = AUTH_ALG_ERROR;
|
||||
OAUTH_ERROR("Wrong oAuth token hash algorithm: %s (2)\n",oakd->auth_alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
key->as_rs_alg = ENC_ALG_DEFAULT;
|
||||
if(!strcmp(oakd->as_rs_alg,"AES-128-CBC")) {
|
||||
key->as_rs_alg = AES_128_CBC;
|
||||
} else if(!strcmp(oakd->as_rs_alg,"AES-256-CBC")) {
|
||||
key->as_rs_alg = AES_256_CBC;
|
||||
} else if(!strcmp(oakd->as_rs_alg,"AEAD-AES-128-GCM")) {
|
||||
key->as_rs_alg = AEAD_AES_128_GCM;
|
||||
} else if(!strcmp(oakd->as_rs_alg,"AEAD-AES-256-GCM")) {
|
||||
key->as_rs_alg = AEAD_AES_256_GCM;
|
||||
} else if(oakd->as_rs_alg[0]) {
|
||||
if(err_msg) {
|
||||
snprintf(err_msg,err_msg_size,"Wrong oAuth token encryption algorithm: %s (2)\n",oakd->as_rs_alg);
|
||||
}
|
||||
OAUTH_ERROR("Wrong oAuth token encryption algorithm: %s (3)\n",oakd->as_rs_alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(key->auth_alg == AUTH_ALG_UNDEFINED) {
|
||||
//AEAD
|
||||
key->auth_key_size = 0;
|
||||
key->auth_key[0] = 0;
|
||||
} else if(!(key->auth_key_size)) {
|
||||
key->auth_key_size = calculate_auth_key_length(key->auth_alg);
|
||||
if(calculate_key(key->ikm_key,key->ikm_key_size,key->auth_key,key->auth_key_size,key->hkdf_hash_func,err_msg,err_msg_size)<0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!(key->as_rs_key_size)) {
|
||||
key->as_rs_key_size = calculate_enc_key_length(key->as_rs_alg);
|
||||
if(calculate_key(key->ikm_key,key->ikm_key_size,key->as_rs_key,key->as_rs_key_size,key->hkdf_hash_func,err_msg,err_msg_size)<0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *get_cipher_type(ENC_ALG enc_alg)
|
||||
{
|
||||
switch(enc_alg) {
|
||||
case AES_256_CBC:
|
||||
return EVP_aes_256_cbc();
|
||||
case AES_128_CBC:
|
||||
return EVP_aes_128_cbc();
|
||||
#if !defined(TURN_NO_GCM)
|
||||
case AEAD_AES_128_GCM:
|
||||
return EVP_aes_128_gcm();
|
||||
case AEAD_AES_256_GCM:
|
||||
return EVP_aes_256_gcm();
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
OAUTH_ERROR("%s: Unsupported enc algorithm: %d\n",__FUNCTION__,(int)enc_alg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const EVP_MD *get_auth_type(AUTH_ALG aa)
|
||||
{
|
||||
switch(aa) {
|
||||
case AUTH_ALG_HMAC_SHA_1:
|
||||
return EVP_sha1();
|
||||
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
|
||||
case AUTH_ALG_HMAC_SHA_256_128:
|
||||
case AUTH_ALG_HMAC_SHA_256:
|
||||
return EVP_sha256();
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
};
|
||||
OAUTH_ERROR("%s: Unknown auth algorithm: %d\n",__FUNCTION__,(int)aa);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void update_hmac_len(AUTH_ALG aa, unsigned int *hmac_len)
|
||||
{
|
||||
if(hmac_len) {
|
||||
switch(aa) {
|
||||
case AUTH_ALG_HMAC_SHA_256_128:
|
||||
*hmac_len = 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static int my_EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
int *outl, const unsigned char *in, int inl)
|
||||
{
|
||||
int cycle = 0;
|
||||
int out_len = 0;
|
||||
while((out_len<inl)&&(++cycle<128)) {
|
||||
int tmp_outl=0;
|
||||
unsigned char *ptr = NULL;
|
||||
if(out)
|
||||
ptr = out+out_len;
|
||||
int ret = EVP_EncryptUpdate(ctx, ptr, &tmp_outl, in+out_len, inl-out_len);
|
||||
out_len += tmp_outl;
|
||||
if(ret<1)
|
||||
return ret;
|
||||
}
|
||||
*outl = out_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int my_EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
int *outl, const unsigned char *in, int inl)
|
||||
{
|
||||
int cycle = 0;
|
||||
int out_len = 0;
|
||||
while((out_len<inl)&&(++cycle<128)) {
|
||||
int tmp_outl=0;
|
||||
unsigned char *ptr = NULL;
|
||||
if(out)
|
||||
ptr = out+out_len;
|
||||
int ret = EVP_DecryptUpdate(ctx, ptr, &tmp_outl, in+out_len, inl-out_len);
|
||||
out_len += tmp_outl;
|
||||
if(ret<1)
|
||||
return ret;
|
||||
}
|
||||
*outl = out_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void print_field(const char* name, const unsigned char* f, size_t len);
|
||||
void print_field(const char* name, const unsigned char* f, size_t len) {
|
||||
printf("\nfield %s==>>\n",name);
|
||||
size_t i;
|
||||
for(i = 0;i<len;++i) {
|
||||
printf("<0x%x>",(unsigned int)f[i]);
|
||||
}
|
||||
printf("\n<<==field %s\n",name);
|
||||
}
|
||||
|
||||
static int encode_oauth_token_normal(const u08bits *server_name, encoded_oauth_token *etoken, const oauth_key *key, const oauth_token *dtoken)
|
||||
{
|
||||
if(server_name && etoken && key && dtoken && (dtoken->enc_block.key_length<=128)) {
|
||||
|
||||
unsigned char orig_field[MAX_ENCODED_OAUTH_TOKEN_SIZE];
|
||||
ns_bzero(orig_field,sizeof(orig_field));
|
||||
|
||||
size_t len = 0;
|
||||
*((uint16_t*)(orig_field+len)) = nswap16(dtoken->enc_block.key_length);
|
||||
len +=2;
|
||||
|
||||
ns_bcopy(dtoken->enc_block.mac_key,orig_field+len,dtoken->enc_block.key_length);
|
||||
len += dtoken->enc_block.key_length;
|
||||
|
||||
*((uint64_t*)(orig_field+len)) = nswap64(dtoken->enc_block.timestamp);
|
||||
len += 8;
|
||||
|
||||
*((uint32_t*)(orig_field+len)) = nswap32(dtoken->enc_block.lifetime);
|
||||
len += 4;
|
||||
|
||||
const EVP_CIPHER * cipher = get_cipher_type(key->as_rs_alg);
|
||||
if(!cipher)
|
||||
return -1;
|
||||
|
||||
unsigned char *encoded_field = (unsigned char*)etoken->token;
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
EVP_EncryptInit_ex(&ctx, cipher, NULL, (const unsigned char *)key->as_rs_key, NULL);
|
||||
EVP_CIPHER_CTX_set_padding(&ctx,1);
|
||||
int outl=0;
|
||||
my_EVP_EncryptUpdate(&ctx, encoded_field, &outl, orig_field, (int)len);
|
||||
if(outl % OAUTH_ENC_ALG_BLOCK_SIZE) {
|
||||
int tmp_outl = 0;
|
||||
EVP_EncryptFinal_ex(&ctx, encoded_field + outl, &tmp_outl);
|
||||
outl += tmp_outl;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
size_t sn_len = strlen((const char*)server_name);
|
||||
ns_bcopy(server_name,encoded_field+outl,sn_len);
|
||||
outl += sn_len;
|
||||
|
||||
const EVP_MD *md = get_auth_type(key->auth_alg);
|
||||
if(!md)
|
||||
return -1;
|
||||
|
||||
unsigned int hmac_len = EVP_MD_size(md);
|
||||
if (!HMAC(md, key->auth_key, key->auth_key_size, encoded_field, outl, encoded_field + outl, &hmac_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
update_hmac_len(key->auth_alg, &hmac_len);
|
||||
|
||||
ns_bcopy(encoded_field + outl, encoded_field + outl - sn_len, hmac_len);
|
||||
outl -= sn_len;
|
||||
outl += hmac_len; //encoded+hmac
|
||||
|
||||
etoken->size = outl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int decode_oauth_token_normal(const u08bits *server_name, const encoded_oauth_token *etoken, const oauth_key *key, oauth_token *dtoken)
|
||||
{
|
||||
if(server_name && etoken && key && dtoken) {
|
||||
|
||||
size_t mac_size = calculate_auth_output_length(key->auth_alg);
|
||||
size_t min_encoded_field_size = 2+4+8+1;
|
||||
if(etoken->size < mac_size+min_encoded_field_size) {
|
||||
OAUTH_ERROR("%s: token size too small: %d, mac_size=%d, min_encoded_field_size=%d\n",__FUNCTION__,(int)etoken->size,(int)mac_size,(int)min_encoded_field_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const unsigned char* encoded_field = (const unsigned char*)etoken->token;
|
||||
unsigned int encoded_field_size = (unsigned int)etoken->size-mac_size;
|
||||
const unsigned char* mac = ((const unsigned char*)etoken->token) + etoken->size - mac_size;
|
||||
|
||||
{
|
||||
const EVP_MD *md = get_auth_type(key->auth_alg);
|
||||
if(!md)
|
||||
return -1;
|
||||
unsigned int hmac_len = EVP_MD_size(md);
|
||||
update_hmac_len(key->auth_alg,&hmac_len);
|
||||
if(hmac_len != mac_size) {
|
||||
OAUTH_ERROR("%s: mac size is wrong: %d, must be %d\n",__FUNCTION__,(int)mac_size,(int)hmac_len);
|
||||
return -1;
|
||||
}
|
||||
unsigned char efield[MAX_ENCODED_OAUTH_TOKEN_SIZE];
|
||||
unsigned char check_mac[MAXSHASIZE];
|
||||
ns_bcopy(encoded_field,efield,encoded_field_size);
|
||||
size_t sn_len = strlen((const char*)server_name);
|
||||
ns_bcopy(server_name,efield+encoded_field_size,sn_len);
|
||||
if (!HMAC(md, key->auth_key, key->auth_key_size, efield, encoded_field_size+sn_len, check_mac, &hmac_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ns_bcmp(check_mac,mac,mac_size)) {
|
||||
OAUTH_ERROR("%s: token integrity check failed\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char decoded_field[MAX_ENCODED_OAUTH_TOKEN_SIZE];
|
||||
|
||||
const EVP_CIPHER * cipher = get_cipher_type(key->as_rs_alg);
|
||||
if(!cipher)
|
||||
return -1;
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
EVP_DecryptInit_ex(&ctx, cipher, NULL, (const unsigned char *)key->as_rs_key, NULL);
|
||||
EVP_CIPHER_CTX_set_padding(&ctx,1);
|
||||
int outl=0;
|
||||
my_EVP_DecryptUpdate(&ctx, decoded_field, &outl, encoded_field, (int)encoded_field_size);
|
||||
|
||||
int tmp_outl = 0;
|
||||
EVP_DecryptFinal_ex(&ctx, decoded_field + outl, &tmp_outl);
|
||||
outl += tmp_outl;
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
dtoken->enc_block.key_length = nswap16(*((uint16_t*)(decoded_field+len)));
|
||||
len += 2;
|
||||
|
||||
ns_bcopy(decoded_field+len,dtoken->enc_block.mac_key,dtoken->enc_block.key_length);
|
||||
len += dtoken->enc_block.key_length;
|
||||
|
||||
dtoken->enc_block.timestamp = nswap64(*((uint64_t*)(decoded_field+len)));
|
||||
len += 8;
|
||||
|
||||
dtoken->enc_block.lifetime = nswap32(*((uint32_t*)(decoded_field+len)));
|
||||
len += 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(TURN_NO_GCM)
|
||||
|
||||
static void generate_random_nonce(unsigned char *nonce, size_t sz) {
|
||||
if(!RAND_bytes(nonce, sz)) {
|
||||
size_t i;
|
||||
for(i=0;i<sz;++i) {
|
||||
nonce[i] = (unsigned char)random();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int encode_oauth_token_aead(const u08bits *server_name, encoded_oauth_token *etoken, const oauth_key *key, const oauth_token *dtoken, const u08bits* nonce0)
|
||||
{
|
||||
if(server_name && etoken && key && dtoken && (dtoken->enc_block.key_length<128)) {
|
||||
|
||||
unsigned char orig_field[MAX_ENCODED_OAUTH_TOKEN_SIZE];
|
||||
ns_bzero(orig_field,sizeof(orig_field));
|
||||
|
||||
size_t len = 0;
|
||||
*((uint16_t*)(orig_field+len)) = nswap16(dtoken->enc_block.key_length);
|
||||
len +=2;
|
||||
|
||||
ns_bcopy(dtoken->enc_block.mac_key,orig_field+len,dtoken->enc_block.key_length);
|
||||
len += dtoken->enc_block.key_length;
|
||||
|
||||
*((uint64_t*)(orig_field+len)) = nswap64(dtoken->enc_block.timestamp);
|
||||
len += 8;
|
||||
|
||||
*((uint32_t*)(orig_field+len)) = nswap32(dtoken->enc_block.lifetime);
|
||||
len += 4;
|
||||
|
||||
const EVP_CIPHER * cipher = get_cipher_type(key->as_rs_alg);
|
||||
if(!cipher)
|
||||
return -1;
|
||||
|
||||
unsigned char *encoded_field = (unsigned char*)etoken->token;
|
||||
|
||||
unsigned char nonce[OAUTH_AEAD_NONCE_SIZE];
|
||||
if(nonce0) {
|
||||
ns_bcopy(nonce0,nonce,sizeof(nonce));
|
||||
} else {
|
||||
generate_random_nonce(nonce, sizeof(nonce));
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
|
||||
/* Initialize the encryption operation. */
|
||||
if(1 != EVP_EncryptInit_ex(&ctx, cipher, NULL, NULL, NULL))
|
||||
return -1;
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(&ctx,1);
|
||||
|
||||
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
|
||||
if(1 != EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, OAUTH_AEAD_NONCE_SIZE, NULL))
|
||||
return -1;
|
||||
|
||||
/* Initialize key and IV */
|
||||
if(1 != EVP_EncryptInit_ex(&ctx, NULL, NULL, (const unsigned char *)key->as_rs_key, nonce))
|
||||
return -1;
|
||||
|
||||
int outl=0;
|
||||
size_t sn_len = strlen((const char*)server_name);
|
||||
|
||||
/* Provide any AAD data. This can be called zero or more times as
|
||||
* required
|
||||
*/
|
||||
if(1 != my_EVP_EncryptUpdate(&ctx, NULL, &outl, server_name, (int)sn_len))
|
||||
return -1;
|
||||
|
||||
outl=0;
|
||||
|
||||
if(1 != my_EVP_EncryptUpdate(&ctx, encoded_field, &outl, orig_field, (int)len))
|
||||
return -1;
|
||||
|
||||
int tmp_outl = 0;
|
||||
EVP_EncryptFinal_ex(&ctx, encoded_field + outl, &tmp_outl);
|
||||
outl += tmp_outl;
|
||||
|
||||
EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, OAUTH_AEAD_TAG_SIZE, encoded_field + outl);
|
||||
outl += OAUTH_AEAD_TAG_SIZE;
|
||||
|
||||
ns_bcopy(nonce, encoded_field + outl, OAUTH_AEAD_NONCE_SIZE);
|
||||
outl += OAUTH_AEAD_NONCE_SIZE; //encoded+tag+hmac
|
||||
|
||||
etoken->size = outl;
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int decode_oauth_token_aead(const u08bits *server_name, const encoded_oauth_token *etoken, const oauth_key *key, oauth_token *dtoken)
|
||||
{
|
||||
if(server_name && etoken && key && dtoken) {
|
||||
|
||||
size_t min_encoded_field_size = 2+4+8+OAUTH_AEAD_NONCE_SIZE+OAUTH_AEAD_TAG_SIZE+1;
|
||||
if(etoken->size < min_encoded_field_size) {
|
||||
OAUTH_ERROR("%s: token size too small: %d\n",__FUNCTION__,(int)etoken->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const unsigned char* encoded_field = (const unsigned char*)etoken->token;
|
||||
unsigned int encoded_field_size = (unsigned int)etoken->size-OAUTH_AEAD_NONCE_SIZE - OAUTH_AEAD_TAG_SIZE;
|
||||
const unsigned char* nonce = ((const unsigned char*)etoken->token) + encoded_field_size + OAUTH_AEAD_TAG_SIZE;
|
||||
|
||||
unsigned char tag[OAUTH_AEAD_TAG_SIZE];
|
||||
ns_bcopy(((const unsigned char*)etoken->token) + encoded_field_size, tag ,sizeof(tag));
|
||||
|
||||
unsigned char decoded_field[MAX_ENCODED_OAUTH_TOKEN_SIZE];
|
||||
|
||||
const EVP_CIPHER * cipher = get_cipher_type(key->as_rs_alg);
|
||||
if(!cipher) {
|
||||
OAUTH_ERROR("%s: Cannot find cipher for algorithm: %d\n",__FUNCTION__,(int)key->as_rs_alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
/* Initialize the decryption operation. */
|
||||
if(1 != EVP_DecryptInit_ex(&ctx, cipher, NULL, NULL, NULL)) {
|
||||
OAUTH_ERROR("%s: Cannot initialize decryption\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//EVP_CIPHER_CTX_set_padding(&ctx,1);
|
||||
|
||||
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
|
||||
if(1 != EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, OAUTH_AEAD_NONCE_SIZE, NULL)) {
|
||||
OAUTH_ERROR("%s: Cannot set nonce length\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize key and IV */
|
||||
if(1 != EVP_DecryptInit_ex(&ctx, NULL, NULL, (const unsigned char *)key->as_rs_key, nonce)) {
|
||||
OAUTH_ERROR("%s: Cannot set nonce\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set expected tag value. A restriction in OpenSSL 1.0.1c and earlier
|
||||
+ * required the tag before any AAD or ciphertext */
|
||||
EVP_CIPHER_CTX_ctrl (&ctx, EVP_CTRL_GCM_SET_TAG, OAUTH_AEAD_TAG_SIZE, tag);
|
||||
|
||||
int outl=0;
|
||||
size_t sn_len = strlen((const char*)server_name);
|
||||
|
||||
/* Provide any AAD data. This can be called zero or more times as
|
||||
* required
|
||||
*/
|
||||
if(1 != my_EVP_DecryptUpdate(&ctx, NULL, &outl, server_name, (int)sn_len)) {
|
||||
OAUTH_ERROR("%s: Cannot decrypt update server_name: %s, len=%d\n",__FUNCTION__,server_name,(int)sn_len);
|
||||
return -1;
|
||||
}
|
||||
if(1 != my_EVP_DecryptUpdate(&ctx, decoded_field, &outl, encoded_field, (int)encoded_field_size)) {
|
||||
OAUTH_ERROR("%s: Cannot decrypt update\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tmp_outl = 0;
|
||||
if(EVP_DecryptFinal_ex(&ctx, decoded_field + outl, &tmp_outl)<1) {
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
OAUTH_ERROR("%s: token integrity check failed\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
outl += tmp_outl;
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
dtoken->enc_block.key_length = nswap16(*((uint16_t*)(decoded_field+len)));
|
||||
len += 2;
|
||||
|
||||
ns_bcopy(decoded_field+len,dtoken->enc_block.mac_key,dtoken->enc_block.key_length);
|
||||
len += dtoken->enc_block.key_length;
|
||||
|
||||
dtoken->enc_block.timestamp = nswap64(*((uint64_t*)(decoded_field+len)));
|
||||
len += 8;
|
||||
|
||||
dtoken->enc_block.lifetime = nswap32(*((uint32_t*)(decoded_field+len)));
|
||||
len += 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int encode_oauth_token(const u08bits *server_name, encoded_oauth_token *etoken, const oauth_key *key, const oauth_token *dtoken, const u08bits *nonce)
|
||||
{
|
||||
UNUSED_ARG(nonce);
|
||||
if(server_name && etoken && key && dtoken) {
|
||||
switch(key->as_rs_alg) {
|
||||
case AES_256_CBC:
|
||||
case AES_128_CBC:
|
||||
return encode_oauth_token_normal(server_name, etoken,key,dtoken);
|
||||
#if !defined(TURN_NO_GCM)
|
||||
case AEAD_AES_128_GCM:
|
||||
case AEAD_AES_256_GCM:
|
||||
return encode_oauth_token_aead(server_name, etoken,key,dtoken,nonce);
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr,"Unsupported AS_RS algorithm: %d\n",(int)key->as_rs_alg);
|
||||
break;
|
||||
};
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int decode_oauth_token(const u08bits *server_name, const encoded_oauth_token *etoken, const oauth_key *key, oauth_token *dtoken)
|
||||
{
|
||||
if(server_name && etoken && key && dtoken) {
|
||||
switch(key->as_rs_alg) {
|
||||
case AES_256_CBC:
|
||||
case AES_128_CBC:
|
||||
return decode_oauth_token_normal(server_name, etoken,key,dtoken);
|
||||
#if !defined(TURN_NO_GCM)
|
||||
case AEAD_AES_128_GCM:
|
||||
case AEAD_AES_256_GCM:
|
||||
return decode_oauth_token_aead(server_name, etoken,key,dtoken);
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr,"Unsupported AS_RS algorithm: %d\n",(int)key->as_rs_alg);
|
||||
break;
|
||||
};
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
@ -90,7 +90,7 @@ u16bits stun_make_error_response(u16bits method);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
u32bits stun_adjust_allocate_lifetime(u32bits lifetime);
|
||||
turn_time_t stun_adjust_allocate_lifetime(turn_time_t lifetime, turn_time_t max_lifetime);
|
||||
|
||||
///////////// STR ////////////////////////////////////////////////
|
||||
|
||||
@ -116,7 +116,7 @@ int stun_is_command_message_offset_str(const u08bits* buf, size_t blen, int offs
|
||||
int stun_is_request_str(const u08bits* buf, size_t len);
|
||||
int stun_is_success_response_str(const u08bits* buf, size_t len);
|
||||
int stun_is_error_response_str(const u08bits* buf, size_t len, int *err_code, u08bits *err_msg, size_t err_msg_size);
|
||||
int stun_is_challenge_response_str(const u08bits* buf, size_t len, int *err_code, u08bits *err_msg, size_t err_msg_size, u08bits *realm, u08bits *nonce);
|
||||
int stun_is_challenge_response_str(const u08bits* buf, size_t len, int *err_code, u08bits *err_msg, size_t err_msg_size, u08bits *realm, u08bits *nonce, u08bits *server_name, int *oauth);
|
||||
int stun_is_response_str(const u08bits* buf, size_t len);
|
||||
int stun_is_indication_str(const u08bits* buf, size_t len);
|
||||
u16bits stun_get_method_str(const u08bits *buf, size_t len);
|
||||
@ -183,6 +183,7 @@ void print_bin_func(const char *name, size_t len, const void *s, const char *fun
|
||||
int stun_check_message_integrity_by_key_str(turn_credential_type ct, u08bits *buf, size_t len, hmackey_t key, st_password_t pwd, SHATYPE shatype, int *too_weak);
|
||||
int stun_check_message_integrity_str(turn_credential_type ct, u08bits *buf, size_t len, u08bits *uname, u08bits *realm, u08bits *upwd, SHATYPE shatype);
|
||||
int stun_attr_add_integrity_str(turn_credential_type ct, u08bits *buf, size_t *len, hmackey_t key, st_password_t pwd, SHATYPE shatype);
|
||||
int stun_attr_add_integrity_by_key_str(u08bits *buf, size_t *len, u08bits *uname, u08bits *realm, hmackey_t key, u08bits *nonce, SHATYPE shatype);
|
||||
int stun_attr_add_integrity_by_user_str(u08bits *buf, size_t *len, u08bits *uname, u08bits *realm, u08bits *upwd, u08bits *nonce, SHATYPE shatype);
|
||||
int stun_attr_add_integrity_by_user_short_term_str(u08bits *buf, size_t *len, u08bits *uname, st_password_t pwd, SHATYPE shatype);
|
||||
size_t get_hmackey_size(SHATYPE shatype);
|
||||
@ -209,6 +210,11 @@ int stun_attr_add_padding_str(u08bits *buf, size_t *len, u16bits padding_len);
|
||||
/* HTTP */
|
||||
int is_http_get(const char *s, size_t blen);
|
||||
|
||||
/* OAUTH */
|
||||
int convert_oauth_key_data(const oauth_key_data *oakd, oauth_key *key, char *err_msg, size_t err_msg_size);
|
||||
int decode_oauth_token(const u08bits *server_name, const encoded_oauth_token *etoken, const oauth_key *key, oauth_token *dtoken);
|
||||
int encode_oauth_token(const u08bits *server_name, encoded_oauth_token *etoken, const oauth_key *key, const oauth_token *dtoken, const u08bits *nonce);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
#define STUN_MAX_USERNAME_SIZE (513)
|
||||
#define STUN_MAX_REALM_SIZE (127)
|
||||
#define STUN_MAX_NONCE_SIZE (127)
|
||||
#define STUN_MAX_SERVER_NAME_SIZE (1025)
|
||||
#define STUN_MAX_PWD_SIZE (127)
|
||||
|
||||
#define STUN_MAGIC_COOKIE (0x2112A442)
|
||||
|
||||
@ -38,6 +38,12 @@
|
||||
#define STUN_ATTRIBUTE_ORIGIN (0x802F)
|
||||
/* <<== Origin */
|
||||
|
||||
/* Bandwidth */
|
||||
|
||||
#define STUN_ATTRIBUTE_NEW_BANDWIDTH (0x8000 + STUN_ATTRIBUTE_BANDWIDTH)
|
||||
|
||||
/* <<== Bandwidth */
|
||||
|
||||
/* SHA AGILITY ==>> */
|
||||
|
||||
#define SHA1SIZEBYTES (20)
|
||||
@ -46,7 +52,9 @@
|
||||
#define MAXSHASIZE (128)
|
||||
|
||||
enum _SHATYPE {
|
||||
SHATYPE_SHA1 = 0,
|
||||
SHATYPE_ERROR = -1,
|
||||
SHATYPE_DEFAULT=0,
|
||||
SHATYPE_SHA1=SHATYPE_DEFAULT,
|
||||
SHATYPE_SHA256
|
||||
};
|
||||
|
||||
@ -58,10 +66,113 @@ typedef enum _SHATYPE SHATYPE;
|
||||
|
||||
/* <<== SHA AGILITY */
|
||||
|
||||
/* Bandwidth */
|
||||
/* OAUTH TOKEN ENC ALG ==> */
|
||||
|
||||
#define STUN_ATTRIBUTE_NEW_BANDWIDTH (0x8000 + STUN_ATTRIBUTE_BANDWIDTH)
|
||||
enum _ENC_ALG {
|
||||
ENC_ALG_ERROR=-1,
|
||||
ENC_ALG_DEFAULT=0,
|
||||
AES_256_CBC=ENC_ALG_DEFAULT,
|
||||
AES_128_CBC,
|
||||
AEAD_AES_128_GCM,
|
||||
AEAD_AES_256_GCM,
|
||||
ENG_ALG_NUM
|
||||
};
|
||||
|
||||
/* <<== Bandwidth */
|
||||
typedef enum _ENC_ALG ENC_ALG;
|
||||
|
||||
/* <<== OAUTH TOKEN ENC ALG */
|
||||
|
||||
/* OAUTH TOKEN AUTH ALG ==> */
|
||||
|
||||
enum _AUTH_ALG {
|
||||
AUTH_ALG_ERROR = -1,
|
||||
AUTH_ALG_UNDEFINED = 0,
|
||||
AUTH_ALG_DEFAULT = 1,
|
||||
AUTH_ALG_HMAC_SHA_256_128 = AUTH_ALG_DEFAULT,
|
||||
AUTH_ALG_HMAC_SHA_1,
|
||||
AUTH_ALG_HMAC_SHA_256
|
||||
};
|
||||
|
||||
typedef enum _AUTH_ALG AUTH_ALG;
|
||||
|
||||
/* <<== OAUTH TOKEN AUTH ALG */
|
||||
|
||||
/**
|
||||
* oAuth struct
|
||||
*/
|
||||
|
||||
#define STUN_ATTRIBUTE_THIRD_PARTY_AUTHORIZATION (0x8031)
|
||||
#define STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN (0x0031)
|
||||
|
||||
#define OAUTH_KID_SIZE (128)
|
||||
#define OAUTH_HASH_FUNC_SIZE (64)
|
||||
#define OAUTH_ALG_SIZE (64)
|
||||
#define OAUTH_KEY_SIZE (256)
|
||||
#define OAUTH_AEAD_NONCE_SIZE (12)
|
||||
#define OAUTH_AEAD_TAG_SIZE (16)
|
||||
#define OAUTH_ENC_ALG_BLOCK_SIZE (16)
|
||||
|
||||
#define OAUTH_DEFAULT_LIFETIME (0)
|
||||
#define OAUTH_DEFAULT_TIMESTAMP (turn_time())
|
||||
|
||||
#define OAUTH_TIME_DELTA (5)
|
||||
|
||||
struct _oauth_key_data {
|
||||
char kid[OAUTH_KID_SIZE+1];
|
||||
char ikm_key[OAUTH_KEY_SIZE+1];
|
||||
size_t ikm_key_size;
|
||||
turn_time_t timestamp;
|
||||
turn_time_t lifetime;
|
||||
char hkdf_hash_func[OAUTH_HASH_FUNC_SIZE+1];
|
||||
char as_rs_alg[OAUTH_ALG_SIZE+1];
|
||||
char as_rs_key[OAUTH_KEY_SIZE+1];
|
||||
size_t as_rs_key_size;
|
||||
char auth_alg[OAUTH_ALG_SIZE+1];
|
||||
char auth_key[OAUTH_KEY_SIZE+1];
|
||||
size_t auth_key_size;
|
||||
};
|
||||
|
||||
typedef struct _oauth_key_data oauth_key_data;
|
||||
|
||||
struct _oauth_key {
|
||||
char kid[OAUTH_KID_SIZE+1];
|
||||
char ikm_key[OAUTH_KEY_SIZE+1];
|
||||
size_t ikm_key_size;
|
||||
turn_time_t timestamp;
|
||||
turn_time_t lifetime;
|
||||
SHATYPE hkdf_hash_func;
|
||||
ENC_ALG as_rs_alg;
|
||||
char as_rs_key[OAUTH_KEY_SIZE+1];
|
||||
size_t as_rs_key_size;
|
||||
AUTH_ALG auth_alg;
|
||||
char auth_key[OAUTH_KEY_SIZE+1];
|
||||
size_t auth_key_size;
|
||||
};
|
||||
|
||||
typedef struct _oauth_key oauth_key;
|
||||
|
||||
struct _oauth_encrypted_block {
|
||||
uint16_t key_length;
|
||||
uint8_t mac_key[MAXSHASIZE];
|
||||
uint64_t timestamp;
|
||||
uint32_t lifetime;
|
||||
};
|
||||
|
||||
typedef struct _oauth_encrypted_block oauth_encrypted_block;
|
||||
|
||||
struct _oauth_token {
|
||||
oauth_encrypted_block enc_block;
|
||||
};
|
||||
|
||||
typedef struct _oauth_token oauth_token;
|
||||
|
||||
#define MAX_ENCODED_OAUTH_TOKEN_SIZE (1024)
|
||||
|
||||
struct _encoded_oauth_token {
|
||||
char token[MAX_ENCODED_OAUTH_TOKEN_SIZE];
|
||||
size_t size;
|
||||
};
|
||||
|
||||
typedef struct _encoded_oauth_token encoded_oauth_token;
|
||||
|
||||
#endif //__LIB_TURN_MSG_DEFS_NEW__
|
||||
|
||||
@ -31,8 +31,8 @@
|
||||
#ifndef __IOADEFS__
|
||||
#define __IOADEFS__
|
||||
|
||||
#define TURN_SERVER_VERSION "4.1.2.1"
|
||||
#define TURN_SERVER_VERSION_NAME "Vitari"
|
||||
#define TURN_SERVER_VERSION "4.2.1.2"
|
||||
#define TURN_SERVER_VERSION_NAME "Monza"
|
||||
#define TURN_SOFTWARE "Coturn-" TURN_SERVER_VERSION " '" TURN_SERVER_VERSION_NAME "'"
|
||||
|
||||
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
||||
@ -76,6 +76,7 @@ extern "C" {
|
||||
|
||||
#define ns_bcopy(src,dst,sz) bcopy((src),(dst),(sz))
|
||||
#define ns_bzero(ptr,sz) bzero((ptr),(sz))
|
||||
#define ns_bcmp(ptr1,ptr2,sz) bcmp((ptr1),(ptr2),(sz))
|
||||
|
||||
#define nswap16(s) ntohs(s)
|
||||
#define nswap32(ul) ntohl(ul)
|
||||
@ -110,10 +111,40 @@ static inline u64bits _ioa_ntoh64(u64bits v)
|
||||
#define ioa_ntoh64 _ioa_ntoh64
|
||||
#define ioa_hton64 _ioa_ntoh64
|
||||
|
||||
#define turn_malloc(sz) malloc(sz)
|
||||
#define turn_free(ptr,sz) free(ptr)
|
||||
#define turn_realloc(ptr, old_sz, new_sz) realloc((ptr),(new_sz))
|
||||
#define turn_calloc(number, sz) calloc((number),(sz))
|
||||
#if defined(TURN_MEMORY_DEBUG)
|
||||
|
||||
#if defined(TURN_LOG_FUNC)
|
||||
#undef TURN_LOG_FUNC
|
||||
#endif
|
||||
|
||||
#define TURN_LOG_FUNC(level, ...) printf (__VA_ARGS__)
|
||||
|
||||
void tm_print_func(void);
|
||||
void *turn_malloc_func(size_t sz, const char* file, int line);
|
||||
void *turn_realloc_func(void *ptr, size_t old_sz, size_t new_sz, const char* file, int line);
|
||||
void turn_free_func(void *ptr, size_t sz, const char* file, int line);
|
||||
void turn_free_simple(void *ptr);
|
||||
void *turn_calloc_func(size_t number, size_t size, const char* file, int line);
|
||||
char *turn_strdup_func(const char* s, const char* file, int line);
|
||||
|
||||
#define tm_print() tm_print_func()
|
||||
#define turn_malloc(sz) turn_malloc_func((size_t)(sz),__FUNCTION__,__LINE__)
|
||||
#define turn_free(ptr,sz) turn_free_func((ptr),(size_t)(sz),__FUNCTION__,__LINE__)
|
||||
#define turn_realloc(ptr, old_sz, new_sz) turn_realloc_func((ptr),(size_t)(old_sz),(size_t)(new_sz),__FUNCTION__,__LINE__)
|
||||
#define turn_calloc(number, sz) turn_calloc_func((number),(size_t)(sz),__FUNCTION__,__LINE__)
|
||||
#define turn_strdup(s) turn_strdup_func((s),__FUNCTION__,__LINE__)
|
||||
|
||||
#else
|
||||
|
||||
#define tm_print()
|
||||
#define turn_malloc(sz) malloc((size_t)(sz))
|
||||
#define turn_free(ptr,sz) free((ptr))
|
||||
#define turn_realloc(ptr, old_sz, new_sz) realloc((ptr),(size_t)(new_sz))
|
||||
#define turn_calloc(number, sz) calloc((number),(size_t)(sz))
|
||||
#define turn_strdup(s) strdup((s))
|
||||
#define turn_free_simple free
|
||||
|
||||
#endif
|
||||
|
||||
#define turn_time() ((turn_time_t)time(NULL))
|
||||
|
||||
|
||||
@ -242,8 +242,8 @@ void set_do_not_use_df(ioa_socket_handle s);
|
||||
int ioa_socket_tobeclosed(ioa_socket_handle s);
|
||||
void set_ioa_socket_tobeclosed(ioa_socket_handle s);
|
||||
void close_ioa_socket_after_processing_if_necessary(ioa_socket_handle s);
|
||||
int check_username_hash(ioa_socket_handle s, u08bits *username, u08bits *realm);
|
||||
void set_username_hash(ioa_socket_handle s, u08bits *username, u08bits *realm);
|
||||
int check_realm_hash(ioa_socket_handle s, u08bits *realm);
|
||||
void set_realm_hash(ioa_socket_handle s, u08bits *realm);
|
||||
|
||||
////////////////// Base64 /////////////////////////////
|
||||
|
||||
|
||||
@ -692,6 +692,48 @@ static void addr_list_foreach(addr_list_header* slh, ur_addr_map_func func) {
|
||||
}
|
||||
}
|
||||
|
||||
static size_t addr_list_num_elements(const addr_list_header* slh) {
|
||||
|
||||
size_t ret = 0;
|
||||
|
||||
if (slh) {
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ADDR_ARRAY_SIZE; ++i) {
|
||||
const addr_elem *elem = &(slh->main_list[i]);
|
||||
if (elem->value) {
|
||||
++ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (slh->extra_list) {
|
||||
for (i = 0; i < slh->extra_sz; ++i) {
|
||||
addr_elem *elem = &(slh->extra_list[i]);
|
||||
if (elem->value) {
|
||||
++ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t addr_list_size(const addr_list_header* slh) {
|
||||
|
||||
size_t ret = 0;
|
||||
|
||||
if (slh) {
|
||||
|
||||
ret += ADDR_ARRAY_SIZE;
|
||||
|
||||
ret += slh->extra_sz;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static addr_elem* addr_list_get(addr_list_header* slh, const ioa_addr* key) {
|
||||
|
||||
if(!slh || !key) return NULL;
|
||||
@ -863,6 +905,40 @@ void ur_addr_map_foreach(ur_addr_map* map, ur_addr_map_func func) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t ur_addr_map_num_elements(const ur_addr_map* map) {
|
||||
|
||||
size_t ret = 0;
|
||||
|
||||
if (ur_addr_map_valid(map)) {
|
||||
u32bits i = 0;
|
||||
for (i = 0; i < ADDR_MAP_SIZE; i++) {
|
||||
|
||||
const addr_list_header* slh = &(map->lists[i]);
|
||||
|
||||
ret += addr_list_num_elements(slh);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t ur_addr_map_size(const ur_addr_map* map) {
|
||||
|
||||
size_t ret = 0;
|
||||
|
||||
if (ur_addr_map_valid(map)) {
|
||||
u32bits i = 0;
|
||||
for (i = 0; i < ADDR_MAP_SIZE; i++) {
|
||||
|
||||
const addr_list_header* slh = &(map->lists[i]);
|
||||
|
||||
ret += addr_list_size(slh);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//////////////////// STRING LISTS ///////////////////////////////////
|
||||
|
||||
typedef struct _string_list {
|
||||
|
||||
@ -216,6 +216,7 @@ int ur_addr_map_del(ur_addr_map* map, ioa_addr* key,ur_addr_map_func func);
|
||||
*/
|
||||
void ur_addr_map_foreach(ur_addr_map* map, ur_addr_map_func func);
|
||||
|
||||
size_t ur_addr_map_num_elements(const ur_addr_map* map);
|
||||
size_t ur_addr_map_size(const ur_addr_map* map);
|
||||
|
||||
//////////////// UR STRING MAP //////////////////
|
||||
|
||||
@ -150,12 +150,12 @@ static int inc_quota(ts_ur_super_session* ss, u08bits *username)
|
||||
if(ss && !(ss->quota_used) && ss->server && ((turn_turnserver*)ss->server)->chquotacb && username) {
|
||||
|
||||
if(((turn_turnserver*)ss->server)->ct == TURN_CREDENTIALS_LONG_TERM) {
|
||||
if(!(ss->realm_set)) {
|
||||
if(!(ss->origin_set)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if((((turn_turnserver*)ss->server)->chquotacb)(username, (u08bits*)ss->realm_options.name)<0) {
|
||||
if((((turn_turnserver*)ss->server)->chquotacb)(username, ss->oauth, (u08bits*)ss->realm_options.name)<0) {
|
||||
|
||||
return -1;
|
||||
|
||||
@ -176,14 +176,20 @@ static void dec_quota(ts_ur_super_session* ss)
|
||||
|
||||
ss->quota_used = 0;
|
||||
|
||||
(((turn_turnserver*)ss->server)->raqcb)(ss->username, ss->oauth, (u08bits*)ss->realm_options.name);
|
||||
}
|
||||
}
|
||||
|
||||
static void dec_bps(ts_ur_super_session* ss)
|
||||
{
|
||||
if(ss && ss->server) {
|
||||
|
||||
if(ss->bps) {
|
||||
if(((turn_turnserver*)ss->server)->allocate_bps_func) {
|
||||
((turn_turnserver*)ss->server)->allocate_bps_func(ss->bps,0);
|
||||
}
|
||||
ss->bps = 0;
|
||||
}
|
||||
|
||||
(((turn_turnserver*)ss->server)->raqcb)(ss->username, (u08bits*)ss->realm_options.name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -881,7 +887,7 @@ static int update_channel_lifetime(ts_ur_super_session *ss, ch_info* chn)
|
||||
|
||||
/////////////// TURN ///////////////////////////
|
||||
|
||||
#define SKIP_ATTRIBUTES case STUN_ATTRIBUTE_PRIORITY: case STUN_ATTRIBUTE_FINGERPRINT: case STUN_ATTRIBUTE_MESSAGE_INTEGRITY: break; \
|
||||
#define SKIP_ATTRIBUTES case STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN: case STUN_ATTRIBUTE_PRIORITY: case STUN_ATTRIBUTE_FINGERPRINT: case STUN_ATTRIBUTE_MESSAGE_INTEGRITY: break; \
|
||||
case STUN_ATTRIBUTE_USERNAME: case STUN_ATTRIBUTE_REALM: case STUN_ATTRIBUTE_NONCE: case STUN_ATTRIBUTE_ORIGIN: \
|
||||
sar = stun_attr_get_next_str(ioa_network_buffer_data(in_buffer->nbh),\
|
||||
ioa_network_buffer_get_size(in_buffer->nbh), sar); \
|
||||
@ -961,7 +967,7 @@ static int handle_turn_allocate(turn_turnserver *server,
|
||||
} else {
|
||||
|
||||
u08bits transport = 0;
|
||||
u32bits lifetime = 0;
|
||||
turn_time_t lifetime = 0;
|
||||
int even_port = -1;
|
||||
int dont_fragment = 0;
|
||||
u64bits in_reservation_token = 0;
|
||||
@ -1158,7 +1164,7 @@ static int handle_turn_allocate(turn_turnserver *server,
|
||||
}
|
||||
}
|
||||
|
||||
lifetime = stun_adjust_allocate_lifetime(lifetime);
|
||||
lifetime = stun_adjust_allocate_lifetime(lifetime, ss->max_session_time_auth);
|
||||
u64bits out_reservation_token = 0;
|
||||
|
||||
if(inc_quota(ss, username)<0) {
|
||||
@ -1173,7 +1179,7 @@ static int handle_turn_allocate(turn_turnserver *server,
|
||||
if(max_bps && (!bps || (bps && (bps>max_bps)))) {
|
||||
bps = max_bps;
|
||||
}
|
||||
if(bps) {
|
||||
if(bps && (ss->bps == 0)) {
|
||||
ss->bps = server->allocate_bps_func(bps,1);
|
||||
if(!(ss->bps)) {
|
||||
*err_code = 486;
|
||||
@ -1281,8 +1287,6 @@ static int handle_turn_allocate(turn_turnserver *server,
|
||||
|
||||
if (*err_code) {
|
||||
|
||||
dec_quota(ss);
|
||||
|
||||
if(!(*reason)) {
|
||||
*reason = (const u08bits *)"Cannot create relay endpoint(s)";
|
||||
}
|
||||
@ -1364,6 +1368,24 @@ static int handle_turn_allocate(turn_turnserver *server,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void copy_auth_parameters(ts_ur_super_session *orig_ss, ts_ur_super_session *ss) {
|
||||
if(orig_ss && ss) {
|
||||
dec_quota(ss);
|
||||
ns_bcopy(orig_ss->nonce,ss->nonce,sizeof(ss->nonce));
|
||||
ss->nonce_expiration_time = orig_ss->nonce_expiration_time;
|
||||
ns_bcopy(&(orig_ss->realm_options),&(ss->realm_options),sizeof(ss->realm_options));
|
||||
ns_bcopy(orig_ss->username,ss->username,sizeof(ss->username));
|
||||
ss->hmackey_set = orig_ss->hmackey_set;
|
||||
ns_bcopy(orig_ss->hmackey,ss->hmackey,sizeof(ss->hmackey));
|
||||
ss->oauth = orig_ss->oauth;
|
||||
ns_bcopy(orig_ss->origin,ss->origin,sizeof(ss->origin));
|
||||
ss->origin_set = orig_ss->origin_set;
|
||||
ns_bcopy(orig_ss->pwd,ss->pwd,sizeof(ss->pwd));
|
||||
ss->max_session_time_auth = orig_ss->max_session_time_auth;
|
||||
inc_quota(ss,ss->username);
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_turn_refresh(turn_turnserver *server,
|
||||
ts_ur_super_session *ss, stun_tid *tid, int *resp_constructed,
|
||||
int *err_code, const u08bits **reason, u16bits *unknown_attrs, u16bits *ua_num,
|
||||
@ -1378,8 +1400,8 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<ALLOC_PROTOCOLS_NUMBER; ++i) {
|
||||
if(a->relay_sessions[i].s) {
|
||||
int family = get_local_addr_from_ioa_socket(a->relay_sessions[i].s)->ss.sa_family;
|
||||
if(a->relay_sessions[i].s && !ioa_socket_tobeclosed(a->relay_sessions[i].s)) {
|
||||
int family = get_ioa_socket_address_family(a->relay_sessions[i].s);
|
||||
if(AF_INET == family) {
|
||||
af4c = 1;
|
||||
} else if(AF_INET6 == family) {
|
||||
@ -1396,7 +1418,7 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
|
||||
} else {
|
||||
|
||||
u32bits lifetime = 0;
|
||||
turn_time_t lifetime = 0;
|
||||
int to_delete = 0;
|
||||
mobile_id_t mid = 0;
|
||||
char smid[sizeof(ss->s_mobile_id)] = "\0";
|
||||
@ -1411,9 +1433,6 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
if(!(*(server->mobility))) {
|
||||
*err_code = 405;
|
||||
*reason = (const u08bits *)"Mobility forbidden";
|
||||
} if(is_allocation_valid(a)) {
|
||||
*err_code = 400;
|
||||
*reason = (const u08bits *)"Mobility ticket cannot be used for a stable, already established allocation";
|
||||
} else {
|
||||
int smid_len = stun_attr_get_len(sar);
|
||||
if(smid_len>0 && (((size_t)smid_len)<sizeof(smid))) {
|
||||
@ -1421,6 +1440,10 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
if(smid_val) {
|
||||
ns_bcopy(smid_val, smid, (size_t)smid_len);
|
||||
mid = string_to_mobile_id(smid);
|
||||
if(is_allocation_valid(a) && (mid != ss->old_mobile_id)) {
|
||||
*err_code = 400;
|
||||
*reason = (const u08bits *)"Mobility ticket cannot be used for a stable, already established allocation";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*err_code = 400;
|
||||
@ -1526,7 +1549,7 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
} else {
|
||||
|
||||
ts_ur_super_session *orig_ss = get_session_from_mobile_map(server, mid);
|
||||
if(!orig_ss) {
|
||||
if(!orig_ss || orig_ss->to_be_closed || ioa_socket_tobeclosed(orig_ss->client_socket)) {
|
||||
*err_code = 404;
|
||||
*reason = (const u08bits *)"Allocation not found";
|
||||
} else if(orig_ss == ss) {
|
||||
@ -1547,8 +1570,17 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
|
||||
//Check security:
|
||||
int postpone_reply = 0;
|
||||
check_stun_auth(server, orig_ss, tid, resp_constructed, err_code, reason, in_buffer, nbh,
|
||||
STUN_METHOD_REFRESH, &message_integrity, &postpone_reply, can_resume);
|
||||
|
||||
if(!(ss->hmackey_set)) {
|
||||
copy_auth_parameters(orig_ss,ss);
|
||||
}
|
||||
|
||||
if(check_stun_auth(server, ss, tid, resp_constructed, err_code, reason, in_buffer, nbh,
|
||||
STUN_METHOD_REFRESH, &message_integrity, &postpone_reply, can_resume)<0) {
|
||||
if(!(*err_code)) {
|
||||
*err_code = 401;
|
||||
}
|
||||
}
|
||||
|
||||
if(postpone_reply) {
|
||||
|
||||
@ -1560,8 +1592,9 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
|
||||
if (to_delete)
|
||||
lifetime = 0;
|
||||
else
|
||||
lifetime = stun_adjust_allocate_lifetime(lifetime);
|
||||
else {
|
||||
lifetime = stun_adjust_allocate_lifetime(lifetime, ss->max_session_time_auth);
|
||||
}
|
||||
|
||||
if (af4c && refresh_relay_connection(server, orig_ss, lifetime, 0, 0, 0,
|
||||
err_code, AF_INET) < 0) {
|
||||
@ -1579,37 +1612,41 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
*reason = (const u08bits *)"Cannot refresh relay connection (internal error)";
|
||||
}
|
||||
|
||||
} else if(!to_delete && orig_ss && (inc_quota(orig_ss, orig_ss->username)<0)) {
|
||||
|
||||
*err_code = 486;
|
||||
*reason = (const u08bits *)"Allocation Quota Reached";
|
||||
|
||||
} else {
|
||||
|
||||
//Transfer socket:
|
||||
|
||||
ioa_socket_handle s = detach_ioa_socket(ss->client_socket,0);
|
||||
ioa_socket_handle s = detach_ioa_socket(ss->client_socket,1);
|
||||
|
||||
ss->to_be_closed = 1;
|
||||
|
||||
if(!s) {
|
||||
dec_quota(orig_ss);
|
||||
*err_code = 500;
|
||||
} else {
|
||||
|
||||
if(attach_socket_to_session(server, s, orig_ss) < 0) {
|
||||
IOA_CLOSE_SOCKET(s);
|
||||
if(orig_ss->client_socket != s) {
|
||||
IOA_CLOSE_SOCKET(s);
|
||||
}
|
||||
*err_code = 500;
|
||||
dec_quota(orig_ss);
|
||||
} else {
|
||||
|
||||
if(ss->hmackey_set) {
|
||||
copy_auth_parameters(ss,orig_ss);
|
||||
}
|
||||
|
||||
delete_session_from_mobile_map(ss);
|
||||
delete_session_from_mobile_map(orig_ss);
|
||||
put_session_into_mobile_map(orig_ss);
|
||||
|
||||
//Use new buffer and redefine ss:
|
||||
nbh = ioa_network_buffer_allocate(server->e);
|
||||
|
||||
dec_quota(ss);
|
||||
ss = orig_ss;
|
||||
inc_quota(ss,ss->username);
|
||||
|
||||
ss->old_mobile_id = mid;
|
||||
size_t len = ioa_network_buffer_get_size(nbh);
|
||||
|
||||
turn_report_allocation_set(&(ss->alloc), lifetime, 1);
|
||||
@ -1641,7 +1678,6 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
|
||||
if ((server->fingerprint) || ss->enforce_fingerprints) {
|
||||
if (stun_attr_add_fingerprint_str(ioa_network_buffer_data(nbh), &len) < 0) {
|
||||
dec_quota(ss);
|
||||
*err_code = 500;
|
||||
ioa_network_buffer_delete(server->e, nbh);
|
||||
return -1;
|
||||
@ -1669,8 +1705,9 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
|
||||
if (to_delete)
|
||||
lifetime = 0;
|
||||
else
|
||||
lifetime = stun_adjust_allocate_lifetime(lifetime);
|
||||
else {
|
||||
lifetime = stun_adjust_allocate_lifetime(lifetime, ss->max_session_time_auth);
|
||||
}
|
||||
|
||||
if(!af4 && !af6) {
|
||||
af4 = af4c;
|
||||
@ -1699,10 +1736,18 @@ static int handle_turn_refresh(turn_turnserver *server,
|
||||
|
||||
size_t len = ioa_network_buffer_get_size(nbh);
|
||||
stun_init_success_response_str(STUN_METHOD_REFRESH, ioa_network_buffer_data(nbh), &len, tid);
|
||||
u32bits lt = nswap32(lifetime);
|
||||
|
||||
if(ss->s_mobile_id[0]) {
|
||||
stun_attr_add_str(ioa_network_buffer_data(nbh), &len,
|
||||
STUN_ATTRIBUTE_MOBILITY_TICKET,
|
||||
(u08bits*)ss->s_mobile_id,strlen(ss->s_mobile_id));
|
||||
ioa_network_buffer_set_size(nbh,len);
|
||||
}
|
||||
|
||||
u32bits lt = nswap32(lifetime);
|
||||
stun_attr_add_str(ioa_network_buffer_data(nbh), &len, STUN_ATTRIBUTE_LIFETIME,
|
||||
(const u08bits*) <, 4);
|
||||
|
||||
ioa_network_buffer_set_size(nbh,len);
|
||||
|
||||
*resp_constructed = 1;
|
||||
@ -1872,8 +1917,18 @@ static void tcp_peer_connection_completed_callback(int success, void *arg)
|
||||
|
||||
} else {
|
||||
tc->state = TC_STATE_FAILED;
|
||||
if(!err_code)
|
||||
if(!err_code) {
|
||||
err_code = 447;
|
||||
}
|
||||
{
|
||||
char ls[257]="\0";
|
||||
char rs[257]="\0";
|
||||
ioa_addr *laddr = get_local_addr_from_ioa_socket(ss->client_socket);
|
||||
if(laddr)
|
||||
addr_to_string(laddr,(u08bits*)ls);
|
||||
addr_to_string(&(tc->peer_addr),(u08bits*)rs);
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: failure to connect from %s to %s\n", __FUNCTION__, ls,rs);
|
||||
}
|
||||
const u08bits *reason = (const u08bits *)"Connection Timeout or Failure";
|
||||
stun_init_error_response_str(STUN_METHOD_CONNECT, ioa_network_buffer_data(nbh), &len, err_code, reason, &(tc->tid));
|
||||
}
|
||||
@ -1980,8 +2035,10 @@ static int tcp_start_connection_to_peer(turn_turnserver *server, ts_ur_super_ses
|
||||
}
|
||||
|
||||
tc->state = TC_STATE_CLIENT_TO_PEER_CONNECTING;
|
||||
IOA_CLOSE_SOCKET(tc->peer_s);
|
||||
tc->peer_s = tcs;
|
||||
if(tc->peer_s != tcs) {
|
||||
IOA_CLOSE_SOCKET(tc->peer_s);
|
||||
tc->peer_s = tcs;
|
||||
}
|
||||
set_ioa_socket_sub_session(tc->peer_s,tc);
|
||||
|
||||
FUNCEND;
|
||||
@ -2004,6 +2061,11 @@ static void tcp_peer_accept_connection(ioa_socket_handle s, void *arg)
|
||||
|
||||
allocation *a = &(ss->alloc);
|
||||
ioa_addr *peer_addr = get_remote_addr_from_ioa_socket(s);
|
||||
if(!peer_addr) {
|
||||
close_ioa_socket(s);
|
||||
FUNCEND;
|
||||
return;
|
||||
}
|
||||
|
||||
tcp_connection *tc = get_tcp_connection_by_peer(a, peer_addr);
|
||||
if(tc) {
|
||||
@ -2049,8 +2111,7 @@ static void tcp_peer_accept_connection(ioa_socket_handle s, void *arg)
|
||||
|
||||
if(register_callback_on_ioa_socket(server->e, s, IOA_EV_READ, tcp_peer_input_handler, tc, 1)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: cannot set TCP peer data input callback\n", __FUNCTION__);
|
||||
close_ioa_socket(s);
|
||||
tc->peer_s = NULL;
|
||||
IOA_CLOSE_SOCKET(tc->peer_s);
|
||||
tc->state = TC_STATE_UNKNOWN;
|
||||
FUNCEND;
|
||||
return;
|
||||
@ -2188,7 +2249,12 @@ static int handle_turn_connection_bind(turn_turnserver *server,
|
||||
|
||||
u16bits method = STUN_METHOD_CONNECTION_BIND;
|
||||
|
||||
if (is_allocation_valid(a)) {
|
||||
if(ss->to_be_closed) {
|
||||
|
||||
*err_code = 400;
|
||||
*reason = (const u08bits *)"Bad request";
|
||||
|
||||
} else if (is_allocation_valid(a)) {
|
||||
|
||||
*err_code = 400;
|
||||
*reason = (const u08bits *)"Bad request: CONNECTION_BIND cannot be issued after allocation";
|
||||
@ -2243,7 +2309,7 @@ static int handle_turn_connection_bind(turn_turnserver *server,
|
||||
if(server->send_socket_to_relay) {
|
||||
turnserver_id sid = (id & 0xFF000000)>>24;
|
||||
ioa_socket_handle s = ss->client_socket;
|
||||
if(s) {
|
||||
if(s && !ioa_socket_tobeclosed(s)) {
|
||||
ioa_socket_handle new_s = detach_ioa_socket(s,1);
|
||||
if(new_s) {
|
||||
if(server->send_socket_to_relay(sid, id, tid, new_s, message_integrity, RMT_CB_SOCKET, in_buffer, can_resume)<0) {
|
||||
@ -2292,6 +2358,8 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
|
||||
int err_code = 0;
|
||||
const u08bits *reason = NULL;
|
||||
|
||||
ioa_socket_handle s_to_delete = s;
|
||||
|
||||
if(tcid && tid && s) {
|
||||
|
||||
tc = get_tcp_connection_by_id(server->tcp_relay_connections, tcid);
|
||||
@ -2306,27 +2374,32 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
|
||||
} else {
|
||||
ss = (ts_ur_super_session*)(a->owner);
|
||||
|
||||
//Check security:
|
||||
int postpone_reply = 0;
|
||||
check_stun_auth(server, ss, tid, &resp_constructed, &err_code, &reason, in_buffer, nbh,
|
||||
if(ss->to_be_closed || ioa_socket_tobeclosed(ss->client_socket)) {
|
||||
err_code = 404;
|
||||
} else {
|
||||
//Check security:
|
||||
int postpone_reply = 0;
|
||||
check_stun_auth(server, ss, tid, &resp_constructed, &err_code, &reason, in_buffer, nbh,
|
||||
STUN_METHOD_CONNECTION_BIND, &message_integrity, &postpone_reply, can_resume);
|
||||
|
||||
if(postpone_reply) {
|
||||
if(postpone_reply) {
|
||||
|
||||
ioa_network_buffer_delete(server->e, nbh);
|
||||
return 0;
|
||||
ioa_network_buffer_delete(server->e, nbh);
|
||||
return 0;
|
||||
|
||||
} else if(!err_code) {
|
||||
tc->state = TC_STATE_READY;
|
||||
tc->client_s = s;
|
||||
set_ioa_socket_session(s,ss);
|
||||
set_ioa_socket_sub_session(s,tc);
|
||||
set_ioa_socket_app_type(s,TCP_CLIENT_DATA_SOCKET);
|
||||
if(register_callback_on_ioa_socket(server->e, s, IOA_EV_READ, tcp_client_input_handler_rfc6062data, tc, 1)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: cannot set TCP client data input callback\n", __FUNCTION__);
|
||||
err_code = 500;
|
||||
} else {
|
||||
IOA_EVENT_DEL(tc->conn_bind_timeout);
|
||||
} else if(!err_code) {
|
||||
tc->state = TC_STATE_READY;
|
||||
tc->client_s = s;
|
||||
s_to_delete = NULL;
|
||||
set_ioa_socket_session(s,ss);
|
||||
set_ioa_socket_sub_session(s,tc);
|
||||
set_ioa_socket_app_type(s,TCP_CLIENT_DATA_SOCKET);
|
||||
if(register_callback_on_ioa_socket(server->e, s, IOA_EV_READ, tcp_client_input_handler_rfc6062data, tc, 1)<0) {
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: cannot set TCP client data input callback\n", __FUNCTION__);
|
||||
err_code = 500;
|
||||
} else {
|
||||
IOA_EVENT_DEL(tc->conn_bind_timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2374,6 +2447,7 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
|
||||
if(ss && !err_code) {
|
||||
send_data_from_ioa_socket_nbh(s, NULL, nbh, TTL_IGNORE, TOS_IGNORE);
|
||||
tcp_deliver_delayed_buffer(&(tc->ub_to_client),s,ss);
|
||||
IOA_CLOSE_SOCKET(s_to_delete);
|
||||
FUNCEND;
|
||||
return 0;
|
||||
} else {
|
||||
@ -2387,13 +2461,7 @@ int turnserver_accept_tcp_client_data_connection(turn_turnserver *server, tcp_co
|
||||
}
|
||||
}
|
||||
|
||||
if(s) {
|
||||
if(tc && (s==tc->client_s)) {
|
||||
;
|
||||
} else {
|
||||
close_ioa_socket(s);
|
||||
}
|
||||
}
|
||||
IOA_CLOSE_SOCKET(s_to_delete);
|
||||
|
||||
FUNCEND;
|
||||
return -1;
|
||||
@ -2691,7 +2759,7 @@ static int handle_turn_binding(turn_turnserver *server,
|
||||
|
||||
;
|
||||
|
||||
} else if(ss->client_socket) {
|
||||
} else if(ss->client_socket && get_remote_addr_from_ioa_socket(ss->client_socket)) {
|
||||
|
||||
size_t len = ioa_network_buffer_get_size(nbh);
|
||||
if (stun_set_binding_response_str(ioa_network_buffer_data(nbh), &len, tid,
|
||||
@ -3065,6 +3133,21 @@ static int create_challenge_response(ts_ur_super_session *ss, stun_tid *tid, int
|
||||
char *realm = ss->realm_options.name;
|
||||
stun_attr_add_str(ioa_network_buffer_data(nbh), &len, STUN_ATTRIBUTE_REALM,
|
||||
(u08bits*)realm, (int)(strlen((s08bits*)(realm))));
|
||||
|
||||
if(ss->server) {
|
||||
turn_turnserver* server = (turn_turnserver*)ss->server;
|
||||
if(server->oauth) {
|
||||
const char *server_name = server->oauth_server_name;
|
||||
if(!(server_name && server_name[0])) {
|
||||
server_name = realm;
|
||||
}
|
||||
stun_attr_add_str(ioa_network_buffer_data(nbh), &len,
|
||||
STUN_ATTRIBUTE_THIRD_PARTY_AUTHORIZATION,
|
||||
(const u08bits*)(server_name),
|
||||
strlen(server_name));
|
||||
}
|
||||
}
|
||||
|
||||
ioa_network_buffer_set_size(nbh,len);
|
||||
return 0;
|
||||
}
|
||||
@ -3073,7 +3156,7 @@ static int create_challenge_response(ts_ur_super_session *ss, stun_tid *tid, int
|
||||
#define min(a,b) ((a)<=(b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static void resume_processing_after_username_check(int success, hmackey_t hmackey, st_password_t pwd, turn_turnserver *server, u64bits ctxkey, ioa_net_data *in_buffer)
|
||||
static void resume_processing_after_username_check(int success, int oauth, int max_session_time, hmackey_t hmackey, st_password_t pwd, turn_turnserver *server, u64bits ctxkey, ioa_net_data *in_buffer)
|
||||
{
|
||||
|
||||
if(server && in_buffer && in_buffer->nbh) {
|
||||
@ -3085,6 +3168,8 @@ static void resume_processing_after_username_check(int success, hmackey_t hmack
|
||||
if(success) {
|
||||
ns_bcopy(hmackey,ss->hmackey,sizeof(hmackey_t));
|
||||
ss->hmackey_set = 1;
|
||||
ss->oauth = oauth;
|
||||
ss->max_session_time_auth = (turn_time_t)max_session_time;
|
||||
ns_bcopy(pwd,ss->pwd,sizeof(st_password_t));
|
||||
}
|
||||
|
||||
@ -3239,18 +3324,23 @@ static int check_stun_auth(turn_turnserver *server,
|
||||
|
||||
if(ss->username[0]) {
|
||||
if(strcmp((char*)ss->username,(char*)usname)) {
|
||||
if(method == STUN_METHOD_ALLOCATE) {
|
||||
*err_code = 437;
|
||||
*reason = (const u08bits*)"Allocation mismatch: wrong credentials";
|
||||
if(ss->oauth) {
|
||||
ss->hmackey_set = 0;
|
||||
STRCPY(ss->username,usname);
|
||||
} else {
|
||||
*err_code = 441;
|
||||
*reason = (const u08bits*)"Wrong credentials";
|
||||
if(method == STUN_METHOD_ALLOCATE) {
|
||||
*err_code = 437;
|
||||
*reason = (const u08bits*)"Allocation mismatch: wrong credentials";
|
||||
} else {
|
||||
*err_code = 441;
|
||||
*reason = (const u08bits*)"Wrong credentials";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
STRCPY(ss->username,usname);
|
||||
set_username_hash(ss->client_socket,ss->username,(u08bits*)ss->realm_options.name);
|
||||
set_realm_hash(ss->client_socket,(u08bits*)ss->realm_options.name);
|
||||
}
|
||||
|
||||
if(server->ct != TURN_CREDENTIALS_SHORT_TERM) {
|
||||
@ -3287,29 +3377,24 @@ static int check_stun_auth(turn_turnserver *server,
|
||||
|
||||
/* Password */
|
||||
if(!(ss->hmackey_set) && (ss->pwd[0] == 0)) {
|
||||
ur_string_map_value_type ukey = NULL;
|
||||
if(can_resume) {
|
||||
ukey = (server->userkeycb)(server->id, server->ct, usname, realm, resume_processing_after_username_check, in_buffer, ss->id, postpone_reply);
|
||||
(server->userkeycb)(server->id, server->ct, server->oauth, &(ss->oauth), usname, realm, resume_processing_after_username_check, in_buffer, ss->id, postpone_reply);
|
||||
if(*postpone_reply) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* we always return NULL for short-term credentials here */
|
||||
if(!ukey) {
|
||||
/* direct user pattern is supported only for long-term credentials */
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
|
||||
"%s: Cannot find credentials of user <%s>\n",
|
||||
__FUNCTION__, (char*)usname);
|
||||
*err_code = 401;
|
||||
*reason = (const u08bits*)"Unauthorised";
|
||||
if(server->ct != TURN_CREDENTIALS_SHORT_TERM) {
|
||||
return create_challenge_response(ss,tid,resp_constructed,err_code,reason,nbh,method);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
/* direct user pattern is supported only for long-term credentials */
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
|
||||
"%s: Cannot find credentials of user <%s>\n",
|
||||
__FUNCTION__, (char*)usname);
|
||||
*err_code = 401;
|
||||
*reason = (const u08bits*)"Unauthorised";
|
||||
if(server->ct != TURN_CREDENTIALS_SHORT_TERM) {
|
||||
return create_challenge_response(ss,tid,resp_constructed,err_code,reason,nbh,method);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
ns_bcopy(ukey,ss->hmackey,16);
|
||||
ss->hmackey_set = 1;
|
||||
}
|
||||
|
||||
/* Check integrity */
|
||||
@ -3335,7 +3420,7 @@ static int check_stun_auth(turn_turnserver *server,
|
||||
}
|
||||
|
||||
if(can_resume) {
|
||||
(server->userkeycb)(server->id, server->ct, usname, realm, resume_processing_after_username_check, in_buffer, ss->id, postpone_reply);
|
||||
(server->userkeycb)(server->id, server->ct, server->oauth, &(ss->oauth), usname, realm, resume_processing_after_username_check, in_buffer, ss->id, postpone_reply);
|
||||
if(*postpone_reply) {
|
||||
return 0;
|
||||
}
|
||||
@ -3473,7 +3558,7 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss,
|
||||
}
|
||||
|
||||
/* check that the realm is the same as in the original request */
|
||||
if(ss->realm_set) {
|
||||
if(ss->origin_set) {
|
||||
stun_attr_ref sar = stun_attr_get_first_str(ioa_network_buffer_data(in_buffer->nbh),
|
||||
ioa_network_buffer_get_size(in_buffer->nbh));
|
||||
|
||||
@ -3530,7 +3615,7 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss,
|
||||
}
|
||||
|
||||
/* get the initial origin value */
|
||||
if(!err_code && !(ss->realm_set) && (method == STUN_METHOD_ALLOCATE)) {
|
||||
if(!err_code && !(ss->origin_set) && (method == STUN_METHOD_ALLOCATE)) {
|
||||
|
||||
stun_attr_ref sar = stun_attr_get_first_str(ioa_network_buffer_data(in_buffer->nbh),
|
||||
ioa_network_buffer_get_size(in_buffer->nbh));
|
||||
@ -3561,7 +3646,7 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss,
|
||||
ioa_network_buffer_get_size(in_buffer->nbh), sar);
|
||||
}
|
||||
|
||||
ss->realm_set = 1;
|
||||
ss->origin_set = 1;
|
||||
}
|
||||
|
||||
if(!err_code && !(*resp_constructed) && !no_response) {
|
||||
@ -3985,6 +4070,7 @@ int shutdown_client_connection(turn_turnserver *server, ts_ur_super_session *ss,
|
||||
|
||||
report_turn_session_info(server,ss,1);
|
||||
dec_quota(ss);
|
||||
dec_bps(ss);
|
||||
|
||||
if(!force && ss->is_mobile) {
|
||||
|
||||
@ -4187,10 +4273,10 @@ static int create_relay_connection(turn_turnserver* server,
|
||||
ns_bzero(newelem, sizeof(relay_endpoint_session));
|
||||
newelem->s = s;
|
||||
|
||||
if(!check_username_hash(newelem->s,ss->username,(u08bits*)ss->realm_options.name)) {
|
||||
if(!check_realm_hash(newelem->s,(u08bits*)ss->realm_options.name)) {
|
||||
IOA_CLOSE_SOCKET(newelem->s);
|
||||
*err_code = 508;
|
||||
*reason = (const u08bits *)"Cannot find a valid reserved socket for this username";
|
||||
*reason = (const u08bits *)"Cannot find a valid reserved socket for this realm";
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -4228,11 +4314,11 @@ static int create_relay_connection(turn_turnserver* server,
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_username_hash(newelem->s,ss->username,(u08bits*)ss->realm_options.name);
|
||||
set_realm_hash(newelem->s,(u08bits*)ss->realm_options.name);
|
||||
|
||||
if (rtcp_s) {
|
||||
if (out_reservation_token && *out_reservation_token) {
|
||||
set_username_hash(rtcp_s,ss->username,(u08bits*)ss->realm_options.name);
|
||||
set_realm_hash(rtcp_s,(u08bits*)ss->realm_options.name);
|
||||
/* OK */
|
||||
} else {
|
||||
IOA_CLOSE_SOCKET(newelem->s);
|
||||
@ -4244,8 +4330,8 @@ static int create_relay_connection(turn_turnserver* server,
|
||||
}
|
||||
|
||||
/* RFC6156: do not use DF when IPv6 is involved: */
|
||||
if((get_local_addr_from_ioa_socket(newelem->s)->ss.sa_family == AF_INET6) ||
|
||||
(get_local_addr_from_ioa_socket(ss->client_socket)->ss.sa_family == AF_INET6))
|
||||
if((get_ioa_socket_address_family(newelem->s) == AF_INET6) ||
|
||||
(get_ioa_socket_address_family(ss->client_socket) == AF_INET6))
|
||||
set_do_not_use_df(newelem->s);
|
||||
|
||||
if(get_ioa_socket_type(newelem->s) != TCP_SOCKET) {
|
||||
@ -4261,7 +4347,7 @@ static int create_relay_connection(turn_turnserver* server,
|
||||
ioa_timer_handle ev = set_ioa_timer(server->e, lifetime, 0,
|
||||
client_ss_allocation_timeout_handler, newelem, 0,
|
||||
"client_ss_allocation_timeout_handler");
|
||||
set_allocation_lifetime_ev(a, server->ctime + lifetime, ev, get_local_addr_from_ioa_socket(newelem->s)->ss.sa_family);
|
||||
set_allocation_lifetime_ev(a, server->ctime + lifetime, ev, get_ioa_socket_address_family(newelem->s));
|
||||
|
||||
set_ioa_socket_session(newelem->s, ss);
|
||||
}
|
||||
@ -4324,7 +4410,7 @@ static int read_client_connection(turn_turnserver *server,
|
||||
|
||||
FUNCSTART;
|
||||
|
||||
if (!server || !ss || !in_buffer || !(ss->client_socket)) {
|
||||
if (!server || !ss || !in_buffer || !(ss->client_socket) || ss->to_be_closed || ioa_socket_tobeclosed(ss->client_socket)) {
|
||||
FUNCEND;
|
||||
return -1;
|
||||
}
|
||||
@ -4444,6 +4530,7 @@ static int read_client_connection(turn_turnserver *server,
|
||||
SOCKET_TYPE st = get_ioa_socket_type(ss->client_socket);
|
||||
if((st == TCP_SOCKET)||(st==TLS_SOCKET)||(st==TENTATIVE_TCP_SOCKET)) {
|
||||
if(is_http_get((char*)ioa_network_buffer_data(in_buffer->nbh), ioa_network_buffer_get_size(in_buffer->nbh)))
|
||||
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: HTTP request: %s\n", __FUNCTION__, (char*)ioa_network_buffer_data(in_buffer->nbh));
|
||||
write_http_echo(server,ss);
|
||||
}
|
||||
}
|
||||
@ -4459,7 +4546,7 @@ static int attach_socket_to_session(turn_turnserver* server, ioa_socket_handle s
|
||||
int ret = -1;
|
||||
FUNCSTART;
|
||||
|
||||
if(s && server && ss) {
|
||||
if(s && server && ss && !ioa_socket_tobeclosed(s)) {
|
||||
|
||||
if(ss->client_socket != s) {
|
||||
|
||||
@ -4692,7 +4779,8 @@ void init_turn_server(turn_turnserver* server,
|
||||
send_socket_to_relay_cb send_socket_to_relay,
|
||||
vintp secure_stun, SHATYPE shatype, vintp mobility, int server_relay,
|
||||
send_turn_session_info_cb send_turn_session_info,
|
||||
allocate_bps_cb allocate_bps_func) {
|
||||
allocate_bps_cb allocate_bps_func,
|
||||
int oauth, const char* oauth_server_name) {
|
||||
|
||||
if (!server)
|
||||
return;
|
||||
@ -4716,6 +4804,9 @@ void init_turn_server(turn_turnserver* server,
|
||||
server->mobility = mobility;
|
||||
server->server_relay = server_relay;
|
||||
server->send_turn_session_info = send_turn_session_info;
|
||||
server->oauth = oauth;
|
||||
if(oauth)
|
||||
server->oauth_server_name = oauth_server_name;
|
||||
if(mobility)
|
||||
server->mobile_connections_map = ur_map_create();
|
||||
|
||||
|
||||
@ -90,10 +90,10 @@ typedef enum {
|
||||
struct _turn_turnserver;
|
||||
typedef struct _turn_turnserver turn_turnserver;
|
||||
|
||||
typedef void (*get_username_resume_cb)(int success, hmackey_t hmackey, st_password_t pwd, turn_turnserver *server, u64bits ctxkey, ioa_net_data *in_buffer);
|
||||
typedef u08bits *(*get_user_key_cb)(turnserver_id id, turn_credential_type ct, u08bits *uname, u08bits *realm, get_username_resume_cb resume, ioa_net_data *in_buffer, u64bits ctxkey, int *postpone_reply);
|
||||
typedef int (*check_new_allocation_quota_cb)(u08bits *username, u08bits *realm);
|
||||
typedef void (*release_allocation_quota_cb)(u08bits *username, u08bits *realm);
|
||||
typedef void (*get_username_resume_cb)(int success, int oauth, int max_session_time, hmackey_t hmackey, st_password_t pwd, turn_turnserver *server, u64bits ctxkey, ioa_net_data *in_buffer);
|
||||
typedef u08bits *(*get_user_key_cb)(turnserver_id id, turn_credential_type ct, int in_oauth, int *out_oauth, u08bits *uname, u08bits *realm, get_username_resume_cb resume, ioa_net_data *in_buffer, u64bits ctxkey, int *postpone_reply);
|
||||
typedef int (*check_new_allocation_quota_cb)(u08bits *username, int oauth, u08bits *realm);
|
||||
typedef void (*release_allocation_quota_cb)(u08bits *username, int oauth, u08bits *realm);
|
||||
typedef int (*send_socket_to_relay_cb)(turnserver_id id, u64bits cid, stun_tid *tid, ioa_socket_handle s, int message_integrity, MESSAGE_TO_RELAY_TYPE rmt, ioa_net_data *nd, int can_resume);
|
||||
typedef int (*send_turn_session_info_cb)(struct turn_session_info *tsi);
|
||||
|
||||
@ -160,6 +160,10 @@ struct _turn_turnserver {
|
||||
|
||||
/* Bandwidth draft: */
|
||||
allocate_bps_cb allocate_bps_func;
|
||||
|
||||
/* oAuth: */
|
||||
int oauth;
|
||||
const char* oauth_server_name;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////
|
||||
@ -195,7 +199,9 @@ void init_turn_server(turn_turnserver* server,
|
||||
vintp mobility,
|
||||
int server_relay,
|
||||
send_turn_session_info_cb send_turn_session_info,
|
||||
allocate_bps_cb allocate_bps_func);
|
||||
allocate_bps_cb allocate_bps_func,
|
||||
int oauth,
|
||||
const char* oauth_server_name);
|
||||
|
||||
ioa_engine_handle turn_server_get_engine(turn_turnserver *s);
|
||||
|
||||
|
||||
@ -72,16 +72,23 @@ struct _ts_ur_super_session {
|
||||
ioa_socket_handle client_socket;
|
||||
allocation alloc;
|
||||
ioa_timer_handle to_be_allocated_timeout_ev;
|
||||
int enforce_fingerprints;
|
||||
int is_tcp_relay;
|
||||
int to_be_closed;
|
||||
/* Auth */
|
||||
u08bits nonce[NONCE_MAX_SIZE];
|
||||
turn_time_t nonce_expiration_time;
|
||||
u08bits username[STUN_MAX_USERNAME_SIZE+1];
|
||||
hmackey_t hmackey;
|
||||
int hmackey_set;
|
||||
st_password_t pwd;
|
||||
int enforce_fingerprints;
|
||||
int is_tcp_relay;
|
||||
int to_be_closed;
|
||||
int quota_used;
|
||||
int oauth;
|
||||
turn_time_t max_session_time_auth;
|
||||
/* Realm */
|
||||
realm_options_t realm_options;
|
||||
int origin_set;
|
||||
s08bits origin[STUN_MAX_ORIGIN_SIZE + 1];
|
||||
/* Stats */
|
||||
u32bits received_packets;
|
||||
u32bits sent_packets;
|
||||
@ -97,11 +104,8 @@ struct _ts_ur_super_session {
|
||||
/* Mobile */
|
||||
int is_mobile;
|
||||
mobile_id_t mobile_id;
|
||||
mobile_id_t old_mobile_id;
|
||||
char s_mobile_id[33];
|
||||
/* Realm */
|
||||
realm_options_t realm_options;
|
||||
int realm_set;
|
||||
s08bits origin[STUN_MAX_ORIGIN_SIZE + 1];
|
||||
/* Bandwidth */
|
||||
band_limit_t bps;
|
||||
};
|
||||
|
||||
@ -8,6 +8,7 @@ db.turnusers_lt.ensureIndex({ realm: 1, name: 1 }, { unique: 1 });
|
||||
db.turnusers_st.ensureIndex({ name: 1 }, { unique: 1 });
|
||||
db.turn_secret.ensureIndex({ realm: 1 }, { unique: 1 });
|
||||
db.realm.ensureIndex({ realm: 1 }, { unique: 1 });
|
||||
db.oauth_key.ensureIndex({ kid: 1 }, {unique: 1 });
|
||||
|
||||
exit
|
||||
|
||||
|
||||
@ -39,3 +39,16 @@ CREATE TABLE turn_realm_option (
|
||||
value varchar(128),
|
||||
primary key (realm,opt)
|
||||
);
|
||||
|
||||
CREATE TABLE oauth_key (
|
||||
kid varchar(128),
|
||||
ikm_key varchar(256) default '',
|
||||
timestamp bigint default 0,
|
||||
lifetime integer default 0,
|
||||
hkdf_hash_func varchar(64) default '',
|
||||
as_rs_alg varchar(64) default '',
|
||||
as_rs_key varchar(256) default '',
|
||||
auth_alg varchar(64) default '',
|
||||
auth_key varchar(256) default '',
|
||||
primary key (kid)
|
||||
);
|
||||
|
||||
@ -37,6 +37,41 @@ the option values are "static" (they remain the same for the lifetime of
|
||||
the turnserver process) but the database records can be dynamically changed
|
||||
and they will be almost immediately "seen" by the turnserver process.
|
||||
|
||||
5) For the oAuth authentication, there is a hash structure with the key
|
||||
"turn/oauth/kid/<kid-value>". The kid structure fields are:
|
||||
|
||||
ikm_key - (optional) base64-encoded key ("input keying material");
|
||||
The ikm_key is not needed if the as_rs_key and auth_key are defined
|
||||
explicitly in the database;
|
||||
|
||||
timestamp - (optional) the timestamp (in seconds) when the key
|
||||
lifetime started;
|
||||
|
||||
lifetime - (optional) the key lifetime in seconds; the default value
|
||||
is 0 - unlimited lifetime.
|
||||
|
||||
hkdf_hash_func - (optional) hash function for HKDF procedure; the
|
||||
valid values are SHA-1 and SHA-256, with SHA-256 as default;
|
||||
The hkdf_hash_func is not needed if the as_rs_key and auth_key
|
||||
are defined explicitly in the database;
|
||||
|
||||
as_rs_alg - oAuth token encryption algorithm; the valid values are
|
||||
"AES-128-CBC" and "AES-256-CBC", , "AEAD-AES-128-GCM",
|
||||
"AEAD-AES-256-GCM".
|
||||
The default value is "AES-256-CBC";
|
||||
|
||||
as_rs_key - (optional) base64-encoded AS-RS key. If not defined, then
|
||||
calculated with ikm_key and hkdf_hash_func. The as_rs_key length
|
||||
is defined by as_rs_alg.
|
||||
|
||||
auth_alg - (optional) oAuth token authentication algorithm; the valid values are
|
||||
"HMAC-SHA-256-128", "HMAC-SHA-256" and "HMAC-SHA-1".
|
||||
The default value is "HMAC-SHA-256-128".
|
||||
|
||||
auth_key - (optional) base64-encoded AUTH key. If not defined, then
|
||||
calculated with ikm_key and hkdf_hash_func. The auth_key length
|
||||
is defined by auth_alg.
|
||||
|
||||
II. Extra realms data in the database
|
||||
|
||||
We can use more than one realm with the same instance of the TURN server.
|
||||
@ -68,6 +103,7 @@ This example sets user database for:
|
||||
* The realm performance parameters: "max_bps",
|
||||
"total_quota" and "user_quota" (same names as the turnserver
|
||||
configuration options, with the same meanings).
|
||||
* The oAuth data for the key with kid "north" and key value "carleon".
|
||||
|
||||
The shell command would be:
|
||||
|
||||
@ -109,6 +145,8 @@ set turn/denied-peer-ip/234567 "123::45"
|
||||
|
||||
set turn/allowed-peer-ip/345678 "172.17.13.200"
|
||||
|
||||
hmset turn/oauth/kid/north ikm_key Y2FybGVvbg== hkdf_hash_func 'SHA-256' as_rs_alg 'AES-128-CBC' auth_alg 'HMAC-SHA-256-128'
|
||||
|
||||
save
|
||||
|
||||
!
|
||||
@ -116,7 +154,7 @@ save
|
||||
IV. Redis database configuration parameters
|
||||
|
||||
TURN Server connects to the Redis and keeps the same connection during the
|
||||
TURN server lifetime. That means that we have to take care about that
|
||||
TURN Server process lifetime. That means that we have to take care about that
|
||||
connection - it must not expire.
|
||||
|
||||
You have to take care about Redis connection parameters, the timeout and the
|
||||
|
||||
@ -41,6 +41,18 @@ db.allowed_peer_ip.insert({ ip_range: '172.17.13.200' });
|
||||
db.denied_peer_ip.insert({ ip_range: '172.17.13.133-172.17.14.56' });
|
||||
db.denied_peer_ip.insert({ ip_range: '123::45' });
|
||||
|
||||
db.oauth_key.insert({ kid: 'north',
|
||||
ikm_key: 'Y2FybGVvbg==',
|
||||
hkdf_hash_func: 'SHA-256',
|
||||
as_rs_alg: 'AES-256-CBC',
|
||||
auth_alg: 'HMAC-SHA-256-128' });
|
||||
|
||||
db.oauth_key.insert({ kid: 'oldempire',
|
||||
ikm_key: 'YXVsY3Vz',
|
||||
hkdf_hash_func: 'SHA-256',
|
||||
as_rs_alg: 'AEAD-AES-256-GCM',
|
||||
auth_alg: '' });
|
||||
|
||||
exit
|
||||
|
||||
EOF
|
||||
|
||||
@ -7,11 +7,17 @@ AUTH turn
|
||||
|
||||
set turn/realm/north.gov/user/ninefingers/key "bc807ee29df3c9ffa736523fb2c4e8ee"
|
||||
set turn/realm/north.gov/user/gorst/key "7da2270ccfa49786e0115366d3a3d14d"
|
||||
|
||||
set turn/realm/north.gov/user/bethod/key "3b4125e139811b8577a214c24273fee27b15ff397631c7775b980785a229e6bd"
|
||||
|
||||
set turn/realm/crinna.org/user/whirrun/key "6972e85e51f36e53b0b61759c5a5219a"
|
||||
set turn/realm/crinna.org/user/stranger-come-knocking/key "d43cb678560259a1839bff61c19de15e"
|
||||
|
||||
set turn/realm/north.gov/user/ninefingers/password "youhavetoberealistic"
|
||||
set turn/realm/north.gov/user/gorst/password "hero"
|
||||
|
||||
set turn/realm/north.gov/user/bethod/password "king-of-north"
|
||||
|
||||
set turn/realm/crinna.org/user/whirrun/password "sword"
|
||||
set turn/realm/crinna.org/user/stranger-come-knocking/password "civilization"
|
||||
|
||||
@ -20,6 +26,9 @@ set turn/realm/crinna.org/secret/777888999 "north"
|
||||
|
||||
set turn/user/ninefingers/password "youhavetoberealistic"
|
||||
set turn/user/gorst/password "hero"
|
||||
|
||||
set turn/user/bethod/password "king-of-north"
|
||||
|
||||
set turn/user/whirrun/password "sword"
|
||||
set turn/user/stranger-come-knocking/password "civilization"
|
||||
|
||||
@ -38,6 +47,9 @@ set turn/denied-peer-ip/234567 "123::45"
|
||||
|
||||
set turn/allowed-peer-ip/345678 "172.17.13.200"
|
||||
|
||||
hmset turn/oauth/kid/north ikm_key Y2FybGVvbg== hkdf_hash_func 'SHA-256' as_rs_alg 'AES-256-CBC' auth_alg 'HMAC-SHA-256-128'
|
||||
hmset turn/oauth/kid/oldempire ikm_key YXVsY3Vz hkdf_hash_func 'SHA-256' as_rs_alg 'AEAD-AES-256-GCM'
|
||||
|
||||
save
|
||||
|
||||
!
|
||||
|
||||
@ -26,3 +26,6 @@ insert into allowed_peer_ip (ip_range) values('172.17.13.200');
|
||||
|
||||
insert into denied_peer_ip (ip_range) values('172.17.13.133-172.17.14.56');
|
||||
insert into denied_peer_ip (ip_range) values('123::45');
|
||||
|
||||
insert into oauth_key (kid,ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key) values('north','Y2FybGVvbg==',0,0,'SHA-256','AES-256-CBC','','HMAC-SHA-256-128','');
|
||||
insert into oauth_key (kid,ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key) values('oldempire','YXVsY3Vz',0,0,'SHA-256','AEAD-AES-256-GCM','','','');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user