From 5736eb2811410105068520bb211abdfa53b91bf5 Mon Sep 17 00:00:00 2001 From: Oleg Moskalenko Date: Mon, 13 Oct 2014 00:50:14 -0700 Subject: [PATCH] Imported Upstream version 4.2.1.2 --- AUTHORS | 4 + ChangeLog | 18 + INSTALL | 72 +- README.turnadmin | 2 + README.turnserver | 8 + README.turnutils | 4 + STATUS | 2 + TODO | 13 +- configure | 52 +- examples/etc/turnserver.conf | 12 +- .../secure_relay_with_db_mongo.sh | 3 +- .../secure_relay_with_db_mysql.sh | 3 +- .../secure_relay_with_db_mysql_ssl.sh | 3 +- .../secure_relay_with_db_psql.sh | 5 +- .../secure_relay_with_db_redis.sh | 3 +- man/man1/turnadmin.1 | 4 +- man/man1/turnserver.1 | 14 +- man/man1/turnutils.1 | 8 +- rpm/build.settings.sh | 2 +- rpm/turnserver.spec | 4 +- src/apps/common/apputils.c | 55 +- src/apps/common/apputils.h | 21 + src/apps/common/hiredis_libevent2.c | 10 +- src/apps/common/ns_turn_utils.c | 200 ++++- src/apps/common/ns_turn_utils.h | 3 +- src/apps/relay/dbdrivers/dbd_mongo.c | 431 +++++++-- src/apps/relay/dbdrivers/dbd_mysql.c | 279 ++++-- src/apps/relay/dbdrivers/dbd_pgsql.c | 176 +++- src/apps/relay/dbdrivers/dbd_redis.c | 213 ++++- src/apps/relay/dbdrivers/dbdriver.c | 5 +- src/apps/relay/dbdrivers/dbdriver.h | 6 + src/apps/relay/dtls_listener.c | 16 +- src/apps/relay/mainrelay.c | 62 +- src/apps/relay/mainrelay.h | 6 +- src/apps/relay/netengine.c | 83 +- src/apps/relay/ns_ioalib_engine_impl.c | 147 +++- src/apps/relay/ns_ioalib_impl.h | 5 +- src/apps/relay/tls_listener.c | 2 - src/apps/relay/turncli.c | 10 +- src/apps/relay/userdb.c | 349 ++++++-- src/apps/relay/userdb.h | 15 +- src/apps/rfc5769/rfc5769check.c | 180 ++++ src/apps/uclient/mainuclient.c | 43 +- src/apps/uclient/session.h | 6 + src/apps/uclient/startuclient.c | 72 +- src/apps/uclient/uclient.c | 107 ++- src/apps/uclient/uclient.h | 7 + src/client++/TurnMsgLib.h | 7 +- src/client/ns_turn_ioaddr.c | 68 +- src/client/ns_turn_msg.c | 817 +++++++++++++++++- src/client/ns_turn_msg.h | 10 +- src/client/ns_turn_msg_defs.h | 1 + src/client/ns_turn_msg_defs_new.h | 119 ++- src/ns_turn_defs.h | 43 +- src/server/ns_turn_ioalib.h | 4 +- src/server/ns_turn_maps.c | 76 ++ src/server/ns_turn_maps.h | 1 + src/server/ns_turn_server.c | 299 ++++--- src/server/ns_turn_server.h | 16 +- src/server/ns_turn_session.h | 18 +- turndb/schema.mongo.sh | 1 + turndb/schema.sql | 13 + turndb/schema.userdb.redis | 40 +- turndb/testmongosetup.sh | 12 + turndb/testredisdbsetup.sh | 12 + turndb/testsqldbsetup.sql | 3 + 66 files changed, 3635 insertions(+), 670 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4e984eed..9b07296e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -47,3 +47,7 @@ Mutsutoshi Yoshimoto Federico Pinna MongoDB support (since v4.1.0.1) + +Bradley T. Hughes + FreeBSD port + (since v4.1.2.1) diff --git a/ChangeLog b/ChangeLog index 9e29c956..86ad9dad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +10/05/2014 Oleg Moskalenko +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 Version 4.1.2.1 'Vitari': - The origin attribute is verified in the subsequent diff --git a/INSTALL b/INSTALL index 61bb168c..d158a1c9 100644 --- a/INSTALL +++ b/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 diff --git a/README.turnadmin b/README.turnadmin index 121c6066..bd0bc514 100644 --- a/README.turnadmin +++ b/README.turnadmin @@ -241,3 +241,5 @@ to see the man page. Mutsutoshi Yoshimoto Federico Pinna + + Bradley T. Hughes diff --git a/README.turnserver b/README.turnserver index 7bd560be..31812e4e 100644 --- a/README.turnserver +++ b/README.turnserver @@ -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 Federico Pinna + + Bradley T. Hughes diff --git a/README.turnutils b/README.turnutils index beb3e8d5..618800b4 100644 --- a/README.turnutils +++ b/README.turnutils @@ -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 Federico Pinna + + Bradley T. Hughes diff --git a/STATUS b/STATUS index 6d4090fa..d5cd76e0 100644 --- a/STATUS +++ b/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. diff --git a/TODO b/TODO index e839426f..ead7305b 100644 --- a/TODO +++ b/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 ### diff --git a/configure b/configure index a36a504b..d7e2ee77 100755 --- a/configure +++ b/configure @@ -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 +#include +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 diff --git a/examples/etc/turnserver.conf b/examples/etc/turnserver.conf index b35391f8..0d1aef0b 100644 --- a/examples/etc/turnserver.conf +++ b/examples/etc/turnserver.conf @@ -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 diff --git a/examples/scripts/longtermsecuredb/secure_relay_with_db_mongo.sh b/examples/scripts/longtermsecuredb/secure_relay_with_db_mongo.sh index f5120014..fd793c72 100755 --- a/examples/scripts/longtermsecuredb/secure_relay_with_db_mongo.sh +++ b/examples/scripts/longtermsecuredb/secure_relay_with_db_mongo.sh @@ -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 $@ diff --git a/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql.sh b/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql.sh index e53c8ef5..198f7c6e 100755 --- a/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql.sh +++ b/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql.sh @@ -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 $@ diff --git a/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql_ssl.sh b/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql_ssl.sh index c107168b..773020a4 100755 --- a/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql_ssl.sh +++ b/examples/scripts/longtermsecuredb/secure_relay_with_db_mysql_ssl.sh @@ -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 $@ diff --git a/examples/scripts/longtermsecuredb/secure_relay_with_db_psql.sh b/examples/scripts/longtermsecuredb/secure_relay_with_db_psql.sh index 4f1245d9..86949285 100755 --- a/examples/scripts/longtermsecuredb/secure_relay_with_db_psql.sh +++ b/examples/scripts/longtermsecuredb/secure_relay_with_db_psql.sh @@ -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 $@ diff --git a/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh b/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh index 9800883f..6a18c40c 100755 --- a/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh +++ b/examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh @@ -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 $@ diff --git a/man/man1/turnadmin.1 b/man/man1/turnadmin.1 index 72dd3e6f..e47caf77 100644 --- a/man/man1/turnadmin.1 +++ b/man/man1/turnadmin.1 @@ -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 Mutsutoshi Yoshimoto .PP Federico Pinna +.PP +Bradley T. Hughes diff --git a/man/man1/turnserver.1 b/man/man1/turnserver.1 index 2e3878da..cd6d82f7 100644 --- a/man/man1/turnserver.1 +++ b/man/man1/turnserver.1 @@ -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 Mutsutoshi Yoshimoto .PP Federico Pinna +.PP +Bradley T. Hughes diff --git a/man/man1/turnutils.1 b/man/man1/turnutils.1 index 4182b7f7..ec39407f 100644 --- a/man/man1/turnutils.1 +++ b/man/man1/turnutils.1 @@ -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 Mutsutoshi Yoshimoto .PP Federico Pinna +.PP +Bradley T. Hughes diff --git a/rpm/build.settings.sh b/rpm/build.settings.sh index acbe1a2b..84d5ac35 100755 --- a/rpm/build.settings.sh +++ b/rpm/build.settings.sh @@ -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 diff --git a/rpm/turnserver.spec b/rpm/turnserver.spec index 0dcaba2e..a014ae7e 100644 --- a/rpm/turnserver.spec +++ b/rpm/turnserver.spec @@ -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 + - Sync to 4.2.1.2 * Thu Aug 14 2014 Oleg Moskalenko - Sync to 4.1.2.1 * Tue Jul 29 2014 Oleg Moskalenko diff --git a/src/apps/common/apputils.c b/src/apps/common/apputils.c index 0ef52c05..e76e3910 100644 --- a/src/apps/common/apputils.c +++ b/src/apps/common/apputils.c @@ -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); + } + } + + } +} + ////////////////////////////////////////////////////////////// diff --git a/src/apps/common/apputils.h b/src/apps/common/apputils.h index 21815c4c..0868d6e9 100644 --- a/src/apps/common/apputils.h +++ b/src/apps/common/apputils.h @@ -36,6 +36,7 @@ #include #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); diff --git a/src/apps/common/hiredis_libevent2.c b/src/apps/common/hiredis_libevent2.c index 2b6837eb..24ca2fa0 100644 --- a/src/apps/common/hiredis_libevent2.c +++ b/src/apps/common/hiredis_libevent2.c @@ -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__); } } diff --git a/src/apps/common/ns_turn_utils.c b/src/apps/common/ns_turn_utils.c index 211d9f8f..4406d007 100644 --- a/src/apps/common/ns_turn_utils.c +++ b/src/apps/common/ns_turn_utils.c @@ -32,6 +32,8 @@ #include "ns_turn_ioalib.h" #include "ns_turn_msg_defs.h" +#include + #include #include @@ -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 +#include +#include + +using namespace std; + +static volatile int tmm_init = 0; +static pthread_mutex_t tm; + +typedef void* ptrtype; +typedef set ptrs_t; +typedef map str_to_ptrs_t; +typedef map 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 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 + +////////////////////////////////////////////////////////////////// diff --git a/src/apps/common/ns_turn_utils.h b/src/apps/common/ns_turn_utils.h index 3b0a92e6..1df95651 100644 --- a/src/apps/common/ns_turn_utils.h +++ b/src/apps/common/ns_turn_utils.h @@ -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 - #ifdef __cplusplus extern "C" { #endif diff --git a/src/apps/relay/dbdrivers/dbd_mongo.c b/src/apps/relay/dbdrivers/dbd_mongo.c index d6ae37ec..e8478b2b 100644 --- a/src/apps/relay/dbdrivers/dbd_mongo.c +++ b/src/apps/relay/dbdrivers/dbd_mongo.c @@ -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) { diff --git a/src/apps/relay/dbdrivers/dbd_mysql.c b/src/apps/relay/dbdrivers/dbd_mysql.c index dee2feb9..6f3c07ee 100644 --- a/src/apps/relay/dbdrivers/dbd_mysql.c +++ b/src/apps/relay/dbdrivers/dbd_mysql.c @@ -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) { diff --git a/src/apps/relay/dbdrivers/dbd_pgsql.c b/src/apps/relay/dbdrivers/dbd_pgsql.c index 28737027..0a8b317f 100644 --- a/src/apps/relay/dbdrivers/dbd_pgsql.c +++ b/src/apps/relay/dbdrivers/dbd_pgsql.c @@ -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;iikm_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;ihost) 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;iszkid, 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) { diff --git a/src/apps/relay/dbdrivers/dbdriver.c b/src/apps/relay/dbdrivers/dbdriver.c index 807ad715..abf797fd 100644 --- a/src/apps/relay/dbdrivers/dbdriver.c +++ b/src/apps/relay/dbdrivers/dbdriver.c @@ -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; } - - diff --git a/src/apps/relay/dbdrivers/dbdriver.h b/src/apps/relay/dbdrivers/dbdriver.h index d123e93e..29e8ef20 100644 --- a/src/apps/relay/dbdrivers/dbdriver.h +++ b/src/apps/relay/dbdrivers/dbdriver.h @@ -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 ////////////////// diff --git a/src/apps/relay/dtls_listener.c b/src/apps/relay/dtls_listener.c index e763f496..a68aad0e 100644 --- a/src/apps/relay/dtls_listener.c +++ b/src/apps/relay/dtls_listener.c @@ -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 ); } diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c index f29fc79e..9b6bcb6d 100644 --- a/src/apps/relay/mainrelay.c +++ b/src/apps/relay/mainrelay.c @@ -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 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); } diff --git a/src/apps/relay/mainrelay.h b/src/apps/relay/mainrelay.h index d105b459..0b684c95 100644 --- a/src/apps/relay/mainrelay.h +++ b/src/apps/relay/mainrelay.h @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -65,8 +66,6 @@ #include #include -#include - #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 //////////////// diff --git a/src/apps/relay/netengine.c b/src/apps/relay/netengine.c index 5adb222d..a63bc3c7 100644 --- a/src/apps/relay/netengine.c +++ b/src/apps/relay/netengine.c @@ -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;jaddrs[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=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; diff --git a/src/apps/relay/ns_ioalib_engine_impl.c b/src/apps/relay/ns_ioalib_engine_impl.c index 8e71ad36..c42a5e00 100644 --- a/src/apps/relay/ns_ioalib_engine_impl.c +++ b/src/apps/relay/ns_ioalib_engine_impl.c @@ -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; } diff --git a/src/apps/relay/ns_ioalib_impl.h b/src/apps/relay/ns_ioalib_impl.h index 9a3d8a27..998860a7 100644 --- a/src/apps/relay/ns_ioalib_impl.h +++ b/src/apps/relay/ns_ioalib_impl.h @@ -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 */ diff --git a/src/apps/relay/tls_listener.c b/src/apps/relay/tls_listener.c index 53a605e8..03208b4a 100644 --- a/src/apps/relay/tls_listener.c +++ b/src/apps/relay/tls_listener.c @@ -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; diff --git a/src/apps/relay/turncli.c b/src/apps/relay/turncli.c index 6b3a2306..a2656e6b 100644 --- a/src/apps/relay/turncli.c +++ b/src/apps/relay/turncli.c @@ -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; diff --git a/src/apps/relay/userdb.c b/src/apps/relay/userdb.c index 94af2867..7505da77 100644 --- a/src/apps/relay/userdb.c +++ b/src/apps/relay/userdb.c @@ -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;iuserdb); + 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;iranges_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)); diff --git a/src/apps/relay/userdb.h b/src/apps/relay/userdb.h index a529d1bb..6e5b96fb 100644 --- a/src/apps/relay/userdb.h +++ b/src/apps/relay/userdb.h @@ -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); diff --git a/src/apps/rfc5769/rfc5769check.c b/src/apps/rfc5769/rfc5769check.c index a8dc6cf0..d2aa46b2 100644 --- a/src/apps/rfc5769/rfc5769check.c +++ b/src/apps/rfc5769/rfc5769check.c @@ -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;i1) + 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; } diff --git a/src/apps/uclient/mainuclient.c b/src/apps/uclient/mainuclient.c index 37566b95..646831dc 100644 --- a/src/apps/uclient/mainuclient.c +++ b/src/apps/uclient/mainuclient.c @@ -46,6 +46,7 @@ #include #include +#include /////////////// 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': diff --git a/src/apps/uclient/session.h b/src/apps/uclient/session.h index 5635c529..66a2d52b 100644 --- a/src/apps/uclient/session.h +++ b/src/apps/uclient/session.h @@ -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; diff --git a/src/apps/uclient/startuclient.c b/src/apps/uclient/startuclient.c index 734df9bc..db9457cb 100644 --- a/src/apps/uclient/startuclient.c +++ b/src/apps/uclient/startuclient.c @@ -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(); diff --git a/src/apps/uclient/uclient.c b/src/apps/uclient/uclient.c index 77cc57a8..65a46d41 100644 --- a/src/apps/uclient/uclient.c +++ b/src/apps/uclient/uclient.c @@ -38,6 +38,7 @@ #include #include +#include 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; } } diff --git a/src/apps/uclient/uclient.h b/src/apps/uclient/uclient.h index ab56bf8b..8891f988 100644 --- a/src/apps/uclient/uclient.h +++ b/src/apps/uclient/uclient.h @@ -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); diff --git a/src/client++/TurnMsgLib.h b/src/client++/TurnMsgLib.h index b5b46abb..008bbc05 100644 --- a/src/client++/TurnMsgLib.h +++ b/src/client++/TurnMsgLib.h @@ -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; diff --git a/src/client/ns_turn_ioaddr.c b/src/client/ns_turn_ioaddr.c index 26925f36..13fb33d1 100644 --- a/src/client/ns_turn_ioaddr.c +++ b/src/client/ns_turn_ioaddr.c @@ -29,6 +29,8 @@ */ #include "ns_turn_ioaddr.h" +#include +#include ////////////////////////////////////////////////////////////// @@ -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; diff --git a/src/client/ns_turn_msg.c b/src/client/ns_turn_msg.c index 514d68ca..c2106aea 100644 --- a/src/client/ns_turn_msg.c +++ b/src/client/ns_turn_msg.c @@ -39,6 +39,8 @@ #include #include +/////////// + #include /////////// @@ -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;i0) { + 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(lifetimeSTUN_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(lifetimeSTUN_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>\n",name); + size_t i; + for(i = 0;i",(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;ienc_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; +} + /////////////////////////////////////////////////////////////// diff --git a/src/client/ns_turn_msg.h b/src/client/ns_turn_msg.h index f8abfac8..09e29d01 100644 --- a/src/client/ns_turn_msg.h +++ b/src/client/ns_turn_msg.h @@ -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 diff --git a/src/client/ns_turn_msg_defs.h b/src/client/ns_turn_msg_defs.h index 11548456..cde11dd6 100644 --- a/src/client/ns_turn_msg_defs.h +++ b/src/client/ns_turn_msg_defs.h @@ -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) diff --git a/src/client/ns_turn_msg_defs_new.h b/src/client/ns_turn_msg_defs_new.h index 57b64c2a..82909716 100644 --- a/src/client/ns_turn_msg_defs_new.h +++ b/src/client/ns_turn_msg_defs_new.h @@ -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__ diff --git a/src/ns_turn_defs.h b/src/ns_turn_defs.h index 1eba81b7..ef53e765 100644 --- a/src/ns_turn_defs.h +++ b/src/ns_turn_defs.h @@ -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)) diff --git a/src/server/ns_turn_ioalib.h b/src/server/ns_turn_ioalib.h index 73ddf09b..3a29e8dd 100644 --- a/src/server/ns_turn_ioalib.h +++ b/src/server/ns_turn_ioalib.h @@ -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 ///////////////////////////// diff --git a/src/server/ns_turn_maps.c b/src/server/ns_turn_maps.c index 7fc1bc76..623e7535 100644 --- a/src/server/ns_turn_maps.c +++ b/src/server/ns_turn_maps.c @@ -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 { diff --git a/src/server/ns_turn_maps.h b/src/server/ns_turn_maps.h index 3a873aa6..636e7aac 100644 --- a/src/server/ns_turn_maps.h +++ b/src/server/ns_turn_maps.h @@ -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 ////////////////// diff --git a/src/server/ns_turn_server.c b/src/server/ns_turn_server.c index de00da58..0904d7ca 100644 --- a/src/server/ns_turn_server.c +++ b/src/server/ns_turn_server.c @@ -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;irelay_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)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(); diff --git a/src/server/ns_turn_server.h b/src/server/ns_turn_server.h index 1aba589e..3506e617 100644 --- a/src/server/ns_turn_server.h +++ b/src/server/ns_turn_server.h @@ -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); diff --git a/src/server/ns_turn_session.h b/src/server/ns_turn_session.h index cfb469ab..c1a2c70e 100644 --- a/src/server/ns_turn_session.h +++ b/src/server/ns_turn_session.h @@ -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; }; diff --git a/turndb/schema.mongo.sh b/turndb/schema.mongo.sh index c340a1be..867dbb66 100755 --- a/turndb/schema.mongo.sh +++ b/turndb/schema.mongo.sh @@ -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 diff --git a/turndb/schema.sql b/turndb/schema.sql index 36dee3cc..cdbb48de 100644 --- a/turndb/schema.sql +++ b/turndb/schema.sql @@ -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) +); diff --git a/turndb/schema.userdb.redis b/turndb/schema.userdb.redis index 69b5f2ef..371645e1 100644 --- a/turndb/schema.userdb.redis +++ b/turndb/schema.userdb.redis @@ -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/". 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 diff --git a/turndb/testmongosetup.sh b/turndb/testmongosetup.sh index 067d5d56..93fcdcdd 100755 --- a/turndb/testmongosetup.sh +++ b/turndb/testmongosetup.sh @@ -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 diff --git a/turndb/testredisdbsetup.sh b/turndb/testredisdbsetup.sh index 888fe672..e939f202 100755 --- a/turndb/testredisdbsetup.sh +++ b/turndb/testredisdbsetup.sh @@ -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 ! diff --git a/turndb/testsqldbsetup.sql b/turndb/testsqldbsetup.sql index 32b390ed..19e92eba 100644 --- a/turndb/testsqldbsetup.sql +++ b/turndb/testsqldbsetup.sql @@ -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','','','');