1
0
Эх сурвалжийг харах

Imported Upstream version 4.5.0.1

Oleg Moskalenko 10 жил өмнө
parent
commit
d4bc5ecf23

+ 8 - 0
ChangeLog

@@ -1,3 +1,11 @@
+9/13/2015 Oleg Moskalenko <[email protected]>
+Version 4.5.0.1 'dan Eider':
+	- multiple realms based on oAuth (third-party authorization);
+	- STUN attributes conflict resolution;
+	- SIGHUP handler fixed;
+	- error message logging improved;
+	- mongo test db files fixed.
+	
 7/18/2015 Oleg Moskalenko <[email protected]>
 Version 4.4.5.4 'Ardee West':
 	- moved to github.

+ 27 - 10
INSTALL

@@ -744,6 +744,7 @@ CREATE TABLE oauth_key (
 	timestamp bigint default 0,
 	lifetime integer default 0,
 	as_rs_alg varchar(64) default '',
+	realm varchar(127) default '',
 	primary key (kid)
 ); 
 
@@ -763,6 +764,8 @@ The oauth_key table fields meanings are:
 		"A256GCM", "A128GCM" (see 
 		http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-5.1).
 		The default value is "A256GCM";
+	
+	realm - (optional) can be used to set the user realm (if the field is not empty).
 
 # Https access admin users.
 # Leave this table empty if you do not want 
@@ -852,6 +855,9 @@ may be located in different places.
 
   $ sudo /etc/init.d/postgresql stop
   $ sudo /etc/init.d/postgresql start
+  
+  The scripts may also be in /usr/local/etc/init.d, or in /etc/rc.d/, or
+  in /usr/local/etc/rc.d/ .
 
 5) Check /etc/passwd file to find out which user account is used for the 
 PostgreSQL admin access on your system (it may be "pgsql", or "postgres", 
@@ -859,10 +865,10 @@ or "postgresql"). Let's assume that this is "postgres" account.
 
 6) Create a database for the TURN purposes, with name, say, "turn":
 
-   $ createdb -U postgres turn
+   $ createdb -U postgres coturn
 
 7) Create a user for the TURN with name, say, "turn":
-   $ psql -U postgres turn
+   $ psql -U postgres coturn
      turn=# create user turn with password 'turn';
      turn=# 
      Ctrl-D
@@ -873,13 +879,17 @@ The database schema for the TURN server is very minimalistic and is located
 in project's turndb/schema.sql file, or in the system's 
 PREFIX/share/turnserver/schema.sql file after the turnserver installation:
 
-$ cat turndb/schema.sql | psql -U turn -d turn
+$ cat turndb/schema.sql | psql -U turn -d coturn
 	NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "turnusers_lt_pkey" for table "turnusers_lt"
 	CREATE TABLE
 	CREATE TABLE
 
 See the SQLite section for the detailed database schema explanation.
 
+To fill the database with test data:
+
+cat turndb/testsqldbsetup.sql | psql -U turn -d coturn
+
 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 
 the hmac keys and modify the database with your favorite tools.
@@ -930,13 +940,13 @@ Fill in users, for example:
 
 XVII. MySQL (MariaDB) setup
 
-The MySQL setup is similar to PostgreSQL (same idea), and is well documented 
+The MySQL setup is similar to PostgreSQL (the same idea), and is well documented 
 on their site http://www.mysql.org. The TURN Server database schema is the 
 same as for PostgreSQL and you can find it in turndb/schema.sql file, or 
 in the system's PREFIX/share/turnserver/schema.sql file after the turnserver 
 installation.
 
-The general setup idea is the same as for PostgreSQL:
+The general setup is similar to PostgreSQL setup procedure:
 
 1) Check that the mysql server access is OK. Immediately after the MySQL server 
 installation, it must be accessible, at the very minimum, at the localhost with
@@ -945,25 +955,32 @@ the root account.
 2) Login into mysql console from root account:
 
   $ sudo bash
-  # mysql -p mysql
+  # mysql mysql
+  
+(or mysql -p mysql if mysql account password set)
   
 3) Add 'turn' user with 'turn' password (for example):
 
   > create user 'turn'@'localhost' identified by 'turn';
   
-4) Create database 'turn' (for example) and grant privileges to user 'turn':
+4) Create database 'coturn' (for example) and grant privileges to user 'turn':
 
-  > create database turn;
-  > grant all on turn.* to 'turn'@'localhost';
+  > create database coturn;
+  > grant all on coturn.* to 'turn'@'localhost';
   > flush privileges;
   Ctrl-D
   
 5) Create database schema:
 
-  $ mysql -p -u turn turn < turndb/schema.sql
+  $ mysql -p -u turn coturn < turndb/schema.sql
   Enter password: turn
   $
   
+  Fill in test database data, if this is a test database
+  (not a production database):
+  
+  $ mysql -p -u turn coturn < turndb/testsqldbsetup.sql
+  
 6) Fill in users, for example:
 
   Shared secret for the TURN REST API (realm north.gov):

+ 8 - 3
README.md

@@ -1,5 +1,9 @@
 **_This project evolved from rfc5766-turn-server project (https://code.google.com/p/rfc5766-turn-server/). There are many new advanced TURN specs which are going far beyond the original RFC 5766 document. This project takes the code of rfc5766-turn-server as the starter, and adds new advanced features to it._**
 
+[Downloads page](https://github.com/coturn/coturn/wiki/Downloads)
+
+[Wiki pages](https://github.com/coturn/coturn/wiki/)
+
 # Free open source implementation of TURN and STUN Server #
 
 The TURN Server is a VoIP media traffic NAT traversal server and gateway. It can be used as a general-purpose network traffic TURN server and gateway, too.
@@ -16,13 +20,13 @@ TURN specs:
   * RFC 6062 - TCP relaying TURN extension
   * RFC 6156 - IPv6 extension for TURN
   * RFC 7443 - ALPN support for STUN & TURN
+  * RFC 7635 - oAuth third-party TURN/STUN authorization
   * DTLS support (http://tools.ietf.org/html/draft-petithuguenin-tram-turn-dtls-00).
   * Mobile ICE (MICE) support (http://tools.ietf.org/html/draft-wing-tram-turn-mobility-02).
   * TURN REST API (http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00)
   * Origin field in TURN (Multi-tenant TURN Server) (https://tools.ietf.org/html/draft-ietf-tram-stun-origin-05)
   * TURN Bandwidth draft specs (http://tools.ietf.org/html/draft-thomson-tram-turn-bandwidth-01)
-  * TURN-bis (with dual allocation) draft specs (http://tools.ietf.org/html/draft-ietf-tram-turnbis-04)
-  * Third-party authorization support (http://tools.ietf.org/html/draft-ietf-tram-turn-third-party-authz-16).
+  * TURN-bis (with dual allocation) draft specs (http://tools.ietf.org/html/draft-ietf-tram-turnbis-04).
 
 STUN specs:
 
@@ -31,6 +35,7 @@ STUN specs:
   * RFC 5769 - test vectors for STUN protocol testing
   * RFC 5780 - NAT behavior discovery support
   * RFC 7443 - ALPN support for STUN & TURN
+  * RFC 7635 - oAuth third-party TURN/STUN authorization
 
 Supported ICE and related specs:
 
@@ -116,4 +121,4 @@ email:[email protected]
 
 ### Feedback is very welcome (bugs, issues, suggestions, stories, questions). ###
 
-### Volunteers are welcome, too. ###
+### Volunteers are welcome, too. ###

+ 1 - 1
README.turnserver

@@ -181,7 +181,7 @@ Flags:
 			The actual value of the secret is defined either by option static-auth-secret,
 			or can be found in the turn_secret table in the database.
 			
---oauth			Support oAuth authentication, as in the third-party TURN specs document.
+--oauth			Support oAuth authentication, as in the third-party STUN/TURN RFC 7635.
 			
 --dh566			Use 566 bits predefined DH TLS key. Default size of the key is 1066.
 

+ 3 - 0
STATUS

@@ -123,6 +123,9 @@ supported in the client library).
 53) SHA384 and SHA512 support added (experimental).
 
 54) native SCTP experimental support.
+
+55) Multi-tenant implementation based upon third-party authorization
+(oAuth).
  
 Things to be implemented in future (the development roadmap) 
 are described in the TODO file.

BIN
examples/var/db/turndb


+ 1 - 1
man/man1/turnadmin.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "19 July 2015" "" ""
+.TH TURN 1 "13 September 2015" "" ""
 .SH GENERAL INFORMATION
 
 \fIturnadmin\fP is a TURN administration tool. This tool can be used to manage 

+ 2 - 2
man/man1/turnserver.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "19 July 2015" "" ""
+.TH TURN 1 "13 September 2015" "" ""
 .SH GENERAL INFORMATION
 
 The \fBTURN Server\fP project contains the source code of a TURN server and TURN client 
@@ -265,7 +265,7 @@ or can be found in the turn_secret table in the database.
 .TP
 .B
 \fB\-\-oauth\fP
-Support oAuth authentication, as in the third\-party TURN specs document.
+Support oAuth authentication, as in the third\-party STUN/TURN RFC 7635.
 .TP
 .B
 \fB\-\-dh566\fP

+ 1 - 1
man/man1/turnutils.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "19 July 2015" "" ""
+.TH TURN 1 "13 September 2015" "" ""
 .SH GENERAL INFORMATION
 
 A set of turnutils_* programs provides some utility functionality to be used

+ 1 - 1
rpm/build.settings.sh

@@ -2,7 +2,7 @@
 
 # Common settings script.
 
-TURNVERSION=4.4.5.4
+TURNVERSION=4.5.0.1
 BUILDDIR=~/rpmbuild
 ARCH=`uname -p`
 TURNSERVER_GIT_URL=https://github.com/coturn/coturn.git

+ 3 - 1
rpm/turnserver.spec

@@ -1,5 +1,5 @@
 Name:		turnserver
-Version:	4.4.5.4
+Version:	4.5.0.1
 Release:	0%{dist}
 Summary:	Coturn TURN Server
 
@@ -289,6 +289,8 @@ fi
 %{_includedir}/turn/client/TurnMsgLib.h
 
 %changelog
+* Sun Sep 13 2015 Oleg Moskalenko <[email protected]>
+  - Sync to 4.5.0.1
 * Sat Jul 18 2015 Oleg Moskalenko <[email protected]>
   - Sync to 4.4.5.4
 * Sat Jun 20 2015 Oleg Moskalenko <[email protected]>

+ 1 - 0
src/apps/common/apputils.h

@@ -142,6 +142,7 @@ struct _oauth_key_data_raw {
 	u64bits timestamp;
 	u32bits lifetime;
 	char as_rs_alg[OAUTH_ALG_SIZE+1];
+	char realm[STUN_MAX_REALM_SIZE+1];
 };
 
 typedef struct _oauth_key_data_raw oauth_key_data_raw;

+ 8 - 2
src/apps/common/ns_turn_utils.c

@@ -236,6 +236,7 @@ static int to_syslog = 0;
 static int simple_log = 0;
 static char log_fn[FILE_STR_LEN]="\0";
 static char log_fn_base[FILE_STR_LEN]="\0";
+static volatile int to_reset_log_file = 0;
 
 static turn_mutex log_mutex;
 static int log_mutex_inited = 0;
@@ -344,13 +345,18 @@ static void set_log_file_name_func(char *base, char *f, size_t fsz)
 static void sighup_callback_handler(int signum)
 {
 	if(signum == SIGHUP) {
-		printf("%s: resetting the log file\n",__FUNCTION__);
-		reset_rtpprintf();
+		to_reset_log_file = 1;
 	}
 }
 
 static void set_rtpfile(void)
 {
+	if(to_reset_log_file) {
+		printf("%s: resetting the log file\n",__FUNCTION__);
+		reset_rtpprintf();
+		to_reset_log_file = 0;
+	}
+
 	if(to_syslog) {
 		return;
 	} else if (!_rtpfile) {

+ 13 - 3
src/apps/relay/dbdrivers/dbd_mongo.c

@@ -255,6 +255,7 @@ static int mongo_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 	BSON_APPEND_INT32(&fields, "lifetime", 1);
 	BSON_APPEND_INT32(&fields, "timestamp", 1);
 	BSON_APPEND_INT32(&fields, "as_rs_alg", 1);
+	BSON_APPEND_INT32(&fields, "realm", 1);
 	BSON_APPEND_INT32(&fields, "ikm_key", 1);
 
 	mongoc_cursor_t * cursor;
@@ -277,6 +278,9 @@ static int mongo_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 			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, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
+				STRCPY(key->realm,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));
 			}
@@ -341,6 +345,7 @@ static int mongo_set_oauth_key(oauth_key_data_raw *key) {
   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, "realm", (const char *)key->realm);
   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);
@@ -477,7 +482,7 @@ static int mongo_list_users(u08bits *realm, secrets_list_t *users, secrets_list_
   return ret;
 }
 
-static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
+static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
 
   const char * collection_name = "oauth_key";
   mongoc_collection_t * collection = mongo_get_collection(collection_name);
@@ -501,6 +506,7 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
   BSON_APPEND_INT32(&fields, "lifetime", 1);
   BSON_APPEND_INT32(&fields, "timestamp", 1);
   BSON_APPEND_INT32(&fields, "as_rs_alg", 1);
+  BSON_APPEND_INT32(&fields, "realm", 1);
   BSON_APPEND_INT32(&fields, "ikm_key", 1);
 
   mongoc_cursor_t * cursor;
@@ -525,6 +531,9 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
     	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, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
+    	    STRCPY(key->realm,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));
     	}
@@ -537,6 +546,7 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
     	if(kids) {
     		add_to_secrets_list(kids,key->kid);
     		add_to_secrets_list(teas,key->as_rs_alg);
+    		add_to_secrets_list(realms,key->realm);
 			{
 				char ts[256];
 				snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@@ -548,9 +558,9 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 				add_to_secrets_list(lts,lt);
 			}
     	} else {
-    		printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
+    		printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
     						key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
-    						key->as_rs_alg);
+    						key->as_rs_alg, key->realm);
     	}
     }
     mongoc_cursor_destroy(cursor);

+ 20 - 13
src/apps/relay/dbdrivers/dbd_mysql.c

@@ -345,7 +345,7 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 	int ret = -1;
 	char statement[TURN_LONG_STRING_SIZE];
 	/* direct user input eliminated - there is no SQL injection problem (since version 4.4.5.3) */
-	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg from oauth_key where kid='%s'",(const char*)kid);
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm from oauth_key where kid='%s'",(const char*)kid);
 
 	MYSQL * myc = get_mydb_connection();
 	if(myc) {
@@ -356,7 +356,7 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 			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)!=4) {
+			} else if(mysql_field_count(myc)!=5) {
 				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
 			} else {
 				MYSQL_ROW row = mysql_fetch_row(mres);
@@ -380,6 +380,9 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 						ns_bcopy(row[3],key->as_rs_alg,lengths[3]);
 						key->as_rs_alg[lengths[3]]=0;
 
+						ns_bcopy(row[4],key->realm,lengths[4]);
+						key->realm[lengths[4]]=0;
+
 						ret = 0;
 					}
 				}
@@ -392,13 +395,13 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 	return ret;
 }
 
-static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
+static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
 
 	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,as_rs_alg,kid from oauth_key order by kid");
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm,kid from oauth_key order by kid");
 
 	MYSQL * myc = get_mydb_connection();
 	if(myc) {
@@ -409,7 +412,7 @@ static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 			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)!=5) {
+			} else if(mysql_field_count(myc)!=6) {
 				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
 			} else {
 				MYSQL_ROW row = mysql_fetch_row(mres);
@@ -433,12 +436,16 @@ static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 						ns_bcopy(row[3],key->as_rs_alg,lengths[3]);
 						key->as_rs_alg[lengths[3]]=0;
 
-						ns_bcopy(row[4],key->kid,lengths[4]);
-						key->kid[lengths[4]]=0;
+						ns_bcopy(row[4],key->realm,lengths[4]);
+						key->realm[lengths[4]]=0;
+
+						ns_bcopy(row[5],key->kid,lengths[5]);
+						key->kid[lengths[5]]=0;
 
 						if(kids) {
 							add_to_secrets_list(kids,key->kid);
 							add_to_secrets_list(teas,key->as_rs_alg);
+							add_to_secrets_list(realms,key->realm);
 							{
 								char ts[256];
 								snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@@ -450,9 +457,9 @@ static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 								add_to_secrets_list(lts,lt);
 							}
 						} else {
-							printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
+							printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
 								key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
-								key->as_rs_alg);
+								key->as_rs_alg,key->realm);
 						}
 					}
 					row = mysql_fetch_row(mres);
@@ -496,13 +503,13 @@ static int mysql_set_oauth_key(oauth_key_data_raw *key)
 	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,as_rs_alg) values('%s','%s',%llu,%lu,'%s')",
+		snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('%s','%s',%llu,%lu,'%s','%s')",
 					  key->kid,key->ikm_key,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,
-					  key->as_rs_alg);
+					  key->as_rs_alg,key->realm);
 		int res = mysql_query(myc, statement);
 		if(res) {
-			snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, as_rs_alg='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
-							  key->as_rs_alg,key->kid);
+			snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, as_rs_alg='%s', realm='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
+							  key->as_rs_alg,key->realm,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));

+ 13 - 10
src/apps/relay/dbdrivers/dbd_pgsql.c

@@ -160,7 +160,7 @@ static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 
 	char statement[TURN_LONG_STRING_SIZE];
 	/* direct user input eliminated - there is no SQL injection problem (since version 4.4.5.3) */
-	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg from oauth_key where kid='%s'",(const char*)kid);
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm from oauth_key where kid='%s'",(const char*)kid);
 
 	PGconn * pqc = get_pqdb_connection();
 	if(pqc) {
@@ -173,6 +173,7 @@ static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 			key->timestamp = (u64bits)strtoll(PQgetvalue(res,0,1),NULL,10);
 			key->lifetime = (u32bits)strtol(PQgetvalue(res,0,2),NULL,10);
 			STRCPY(key->as_rs_alg,PQgetvalue(res,0,3));
+			STRCPY(key->realm,PQgetvalue(res,0,4));
 			STRCPY(key->kid,kid);
 			ret = 0;
 		}
@@ -185,7 +186,7 @@ static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 	return ret;
 }
 
-static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
+static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
 
 	oauth_key_data_raw key_;
 	oauth_key_data_raw *key=&key_;
@@ -193,7 +194,7 @@ static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 	int ret = -1;
 
 	char statement[TURN_LONG_STRING_SIZE];
-	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,kid from oauth_key order by kid");
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm,kid from oauth_key order by kid");
 
 	PGconn * pqc = get_pqdb_connection();
 	if(pqc) {
@@ -209,11 +210,13 @@ static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 				key->timestamp = (u64bits)strtoll(PQgetvalue(res,i,1),NULL,10);
 				key->lifetime = (u32bits)strtol(PQgetvalue(res,i,2),NULL,10);
 				STRCPY(key->as_rs_alg,PQgetvalue(res,i,3));
-				STRCPY(key->kid,PQgetvalue(res,i,4));
+				STRCPY(key->realm,PQgetvalue(res,i,4));
+				STRCPY(key->kid,PQgetvalue(res,i,5));
 
 				if(kids) {
 					add_to_secrets_list(kids,key->kid);
 					add_to_secrets_list(teas,key->as_rs_alg);
+					add_to_secrets_list(realms,key->realm);
 					{
 						char ts[256];
 						snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@@ -225,9 +228,9 @@ static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 						add_to_secrets_list(lts,lt);
 					}
 				} else {
-					printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
+					printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
 						key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
-						key->as_rs_alg);
+						key->as_rs_alg,key->realm);
 				}
 
 				ret = 0;
@@ -275,17 +278,17 @@ static int pgsql_set_oauth_key(oauth_key_data_raw *key) {
   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,as_rs_alg) values('%s','%s',%llu,%lu,'%s')",
+	  snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('%s','%s',%llu,%lu,'%s','%s')",
 			  key->kid,key->ikm_key,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,
-			  key->as_rs_alg);
+			  key->as_rs_alg,key->realm);
 
 	  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, as_rs_alg='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
-				  key->as_rs_alg,key->kid);
+		  snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, as_rs_alg='%s', realm='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
+				  key->as_rs_alg,key->realm,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));

+ 8 - 5
src/apps/relay/dbdrivers/dbd_redis.c

@@ -477,6 +477,8 @@ static int redis_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 				if(kw) {
 					if(!strcmp(kw,"as_rs_alg")) {
 						STRCPY(key->as_rs_alg,val);
+					} else if(!strcmp(kw,"realm")) {
+						STRCPY(key->realm,val);
 					} else if(!strcmp(kw,"ikm_key")) {
 						STRCPY(key->ikm_key,val);
 					} else if(!strcmp(kw,"timestamp")) {
@@ -512,8 +514,8 @@ static int redis_set_oauth_key(oauth_key_data_raw *key) {
   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 as_rs_alg %s timestamp %llu lifetime %lu",
-			key->kid,key->ikm_key,key->as_rs_alg,(unsigned long long)key->timestamp,(unsigned long)key->lifetime);
+	snprintf(statement,sizeof(statement),"hmset turn/oauth/kid/%s ikm_key %s as_rs_alg %s timestamp %llu lifetime %lu realm %s",
+			key->kid,key->ikm_key,key->as_rs_alg,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,key->realm);
 	turnFreeRedisReply(redisCommand(rc, statement));
 	turnFreeRedisReply(redisCommand(rc, "save"));
     ret = 0;
@@ -629,7 +631,7 @@ static int redis_list_users(u08bits *realm, secrets_list_t *users, secrets_list_
 	return ret;
 }
 
-static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
+static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
   int ret = -1;
   redisContext *rc = get_redis_connection();
   secrets_list_t keys;
@@ -668,6 +670,7 @@ static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 		if(kids) {
 			add_to_secrets_list(kids,key->kid);
 			add_to_secrets_list(teas,key->as_rs_alg);
+			add_to_secrets_list(realms,key->realm);
 			{
 				char ts[256];
 				snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@@ -679,9 +682,9 @@ static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
 				add_to_secrets_list(lts,lt);
 			}
 		} else {
-			printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
+			printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
 							key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
-							key->as_rs_alg);
+							key->as_rs_alg,key->realm);
 		}
 	}
   }

+ 10 - 7
src/apps/relay/dbdrivers/dbd_sqlite.c

@@ -157,7 +157,7 @@ static void init_sqlite_database(sqlite3 *sqliteconnection) {
 		"CREATE TABLE denied_peer_ip (realm varchar(127) default '', ip_range varchar(256), primary key (realm,ip_range))",
 		"CREATE TABLE turn_origin_to_realm (origin varchar(127),realm varchar(127),primary key (origin))",
 		"CREATE TABLE turn_realm_option (realm varchar(127) default '',	opt varchar(32),	value varchar(128),	primary key (realm,opt))",
-		"CREATE TABLE oauth_key (kid varchar(128),ikm_key varchar(256),timestamp bigint default 0,lifetime integer default 0,as_rs_alg varchar(64) default '',primary key (kid))",
+		"CREATE TABLE oauth_key (kid varchar(128),ikm_key varchar(256),timestamp bigint default 0,lifetime integer default 0,as_rs_alg varchar(64) default '',realm varchar(127) default '',primary key (kid))",
 		"CREATE TABLE admin_user (name varchar(32), realm varchar(127), password varchar(127), primary key (name))",
 		NULL
 	};
@@ -299,7 +299,7 @@ static int sqlite_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 	int rc = 0;
 
 	/* direct user input eliminated - there is no SQL injection problem (since version 4.4.5.3) */
-	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg from oauth_key where kid='%s'",(const char*)kid);
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm from oauth_key where kid='%s'",(const char*)kid);
 
 	sqlite3 *sqliteconnection = get_sqlite_connection();
 	if(sqliteconnection) {
@@ -315,6 +315,7 @@ static int sqlite_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 				key->timestamp = (u64bits)strtoll((const char*)sqlite3_column_text(st, 1),NULL,10);
 				key->lifetime = (u32bits)strtol((const char*)sqlite3_column_text(st, 2),NULL,10);
 				STRCPY(key->as_rs_alg,sqlite3_column_text(st, 3));
+				STRCPY(key->realm,sqlite3_column_text(st, 4));
 				STRCPY(key->kid,kid);
 				ret = 0;
 			}
@@ -331,7 +332,7 @@ static int sqlite_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
 	return ret;
 }
 
-static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
+static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
 
 	oauth_key_data_raw key_;
 	oauth_key_data_raw *key=&key_;
@@ -343,7 +344,7 @@ static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secr
 	char statement[TURN_LONG_STRING_SIZE];
 	sqlite3_stmt *st = NULL;
 	int rc = 0;
-	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,kid from oauth_key order by kid");
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm,kid from oauth_key order by kid");
 
 	sqlite3 *sqliteconnection = get_sqlite_connection();
 	if(sqliteconnection) {
@@ -361,11 +362,13 @@ static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secr
 					key->timestamp = (u64bits)strtoll((const char*)sqlite3_column_text(st, 1),NULL,10);
 					key->lifetime = (u32bits)strtol((const char*)sqlite3_column_text(st, 2),NULL,10);
 					STRCPY(key->as_rs_alg,sqlite3_column_text(st, 3));
-					STRCPY(key->kid,sqlite3_column_text(st, 4));
+					STRCPY(key->realm,sqlite3_column_text(st, 4));
+					STRCPY(key->kid,sqlite3_column_text(st, 5));
 
 					if(kids) {
 						add_to_secrets_list(kids,key->kid);
 						add_to_secrets_list(teas,key->as_rs_alg);
+						add_to_secrets_list(realms,key->realm);
 						{
 							char ts[256];
 							snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@@ -449,8 +452,8 @@ static int sqlite_set_oauth_key(oauth_key_data_raw *key)
 		snprintf(
 						statement,
 						sizeof(statement),
-						"insert or replace into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('%s','%s',%llu,%lu,'%s')",
-						key->kid, key->ikm_key, (unsigned long long) key->timestamp, (unsigned long) key->lifetime, key->as_rs_alg);
+						"insert or replace into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('%s','%s',%llu,%lu,'%s','%s')",
+						key->kid, key->ikm_key, (unsigned long long) key->timestamp, (unsigned long) key->lifetime, key->as_rs_alg, key->realm);
 
 		sqlite_lock(1);
 

+ 1 - 1
src/apps/relay/dbdrivers/dbdriver.h

@@ -68,7 +68,7 @@ typedef struct _turn_dbdriver_t {
   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)(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts);
+  int (*list_oauth_keys)(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms);
   int (*get_admin_user)(const u08bits *usname, u08bits *realm, password_t pwd);
   int (*set_admin_user)(const u08bits *usname, const u08bits *realm, const password_t pwd);
   int (*del_admin_user)(const u08bits *usname);

+ 1 - 1
src/apps/relay/netengine.c

@@ -805,7 +805,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->out_oauth, am->max_session_time, am->key, am->pwd,
-				&(rs->server), am->ctxkey, &(am->in_buffer));
+				&(rs->server), am->ctxkey, &(am->in_buffer), am->realm);
 	if (am->in_buffer.nbh) {
 		ioa_network_buffer_delete(rs->ioa_eng, am->in_buffer.nbh);
 		am->in_buffer.nbh = NULL;

+ 2 - 36
src/apps/relay/ns_ioalib_engine_impl.c

@@ -708,10 +708,10 @@ int ioa_socket_check_bandwidth(ioa_socket_handle s, ioa_network_buffer_handle nb
 	return 1;
 }
 
-int get_ioa_socket_from_reservation(ioa_engine_handle e, u64bits in_reservation_token, ioa_socket_handle *s, u08bits *realm)
+int get_ioa_socket_from_reservation(ioa_engine_handle e, u64bits in_reservation_token, ioa_socket_handle *s)
 {
   if (e && in_reservation_token && s) {
-    *s = rtcp_map_get(e->map_rtcp, in_reservation_token, realm);
+    *s = rtcp_map_get(e->map_rtcp, in_reservation_token);
     if (*s) {
       return 0;
     }
@@ -1652,8 +1652,6 @@ ioa_socket_handle detach_ioa_socket(ioa_socket_handle s)
 
 		ret->magic = SOCKET_MAGIC;
 
-		ret->realm_hash = s->realm_hash;
-
 		SSL* ssl = s->ssl;
 		set_socket_ssl(s,NULL);
 		set_socket_ssl(ret,ssl);
@@ -3417,38 +3415,6 @@ void set_ioa_socket_tobeclosed(ioa_socket_handle s)
 		s->tobeclosed = 1;
 }
 
-static u32bits string_hash(const u08bits *str) {
-
-  u32bits hash = 0;
-  int c = 0;
-
-  while ((c = *str++))
-    hash = c + (hash << 6) + (hash << 16) - hash;
-
-  return hash;
-}
-
-int check_realm_hash(ioa_socket_handle s, u08bits *realm)
-{
-	if(s) {
-		if(realm && realm[0]) {
-			if(s->realm_hash != string_hash(realm)) {
-				return 0;
-			}
-		}
-	}
-	return 1;
-}
-
-void set_realm_hash(ioa_socket_handle s, u08bits *realm)
-{
-	if(s) {
-		if(realm && realm[0]) {
-			s->realm_hash = string_hash(realm);
-		}
-	}
-}
-
 /*
  * Network buffer functions
  */

+ 0 - 2
src/apps/relay/ns_ioalib_impl.h

@@ -221,8 +221,6 @@ struct _ioa_socket
 	struct bufferevent *conn_bev;
 	connect_cb conn_cb;
 	void *conn_arg;
-	//Transferable sockets user data
-	u32bits realm_hash;
 	//Accept:
 	struct evconnlistener *list_ev;
 	accept_cb acb;

+ 37 - 7
src/apps/relay/turn_admin_server.c

@@ -1369,6 +1369,7 @@ typedef enum _AS_FORM AS_FORM;
 #define HR_ADD_IP_KIND "aipk"
 #define HR_UPDATE_PARAMETER "togglepar"
 #define HR_ADD_OAUTH_KID "oauth_kid"
+#define HR_ADD_OAUTH_REALM "oauth_realm"
 #define HR_ADD_OAUTH_TS "oauth_ts"
 #define HR_ADD_OAUTH_LT "oauth_lt"
 #define HR_ADD_OAUTH_IKM "oauth_ikm"
@@ -2773,12 +2774,13 @@ static size_t https_print_oauth_keys(struct str_buffer* sb)
 	size_t ret = 0;
 	const turn_dbdriver_t * dbd = get_dbdriver();
 	if (dbd && dbd->list_oauth_keys) {
-		secrets_list_t kids,teas,tss,lts;
+		secrets_list_t kids,teas,tss,lts,realms;
 		init_secrets_list(&kids);
 		init_secrets_list(&teas);
 		init_secrets_list(&tss);
 		init_secrets_list(&lts);
-		dbd->list_oauth_keys(&kids,&teas,&tss,&lts);
+		init_secrets_list(&realms);
+		dbd->list_oauth_keys(&kids,&teas,&tss,&lts,&realms);
 
 		size_t sz = get_secrets_list_size(&kids);
 		size_t i;
@@ -2807,6 +2809,9 @@ static size_t https_print_oauth_keys(struct str_buffer* sb)
 			str_buffer_append(sb,"<td>");
 			str_buffer_append(sb,get_secrets_list_elem(&teas,i));
 			str_buffer_append(sb,"</td>");
+			str_buffer_append(sb,"<td>");
+			str_buffer_append(sb,get_secrets_list_elem(&realms,i));
+			str_buffer_append(sb,"</td>");
 
 			{
 				str_buffer_append(sb,"<td> <a href=\"");
@@ -2824,6 +2829,9 @@ static size_t https_print_oauth_keys(struct str_buffer* sb)
 
 		clean_secrets_list(&kids);
 		clean_secrets_list(&teas);
+		clean_secrets_list(&tss);
+		clean_secrets_list(&lts);
+		clean_secrets_list(&realms);
 	}
 
 	return ret;
@@ -2889,9 +2897,13 @@ static void write_https_oauth_show_keys(ioa_socket_handle s, const char* kid)
 	}
 }
 
-static void write_https_oauth_page(ioa_socket_handle s, const char* add_kid, const char* add_ikm,
+static void write_https_oauth_page(ioa_socket_handle s,
+				const char* add_kid,
+				const char* add_ikm,
 				const char* add_tea,
-				const char *add_ts, const char* add_lt,
+				const char *add_ts,
+				const char* add_lt,
+				const char* add_realm,
 				const char* msg)
 {
 	if(s && !ioa_socket_tobeclosed(s)) {
@@ -2956,12 +2968,12 @@ static void write_https_oauth_page(ioa_socket_handle s, const char* add_kid, con
 
 				str_buffer_append(sb,"</td></tr>\r\n");
 
-				str_buffer_append(sb,"<tr><td colspan=\"2\">");
+				str_buffer_append(sb,"<tr><td colspan=\"1\">");
 
 				{
 					if(!add_ikm) add_ikm = "";
 
-					str_buffer_append(sb,"  <br>Base64-encoded input keying material (required):<br><textarea wrap=\"soft\" cols=70 rows=4 name=\"");
+					str_buffer_append(sb,"  <br>Base64-encoded input keying material (required):<br><textarea wrap=\"soft\" cols=40 rows=4 name=\"");
 					str_buffer_append(sb,HR_ADD_OAUTH_IKM);
 					str_buffer_append(sb,"\" maxLength=256 >");
 					str_buffer_append(sb,(const char*)add_ikm);
@@ -2971,6 +2983,18 @@ static void write_https_oauth_page(ioa_socket_handle s, const char* add_kid, con
 
 				str_buffer_append(sb,"</td><td>");
 
+				{
+					if(!add_realm) add_realm = "";
+
+					str_buffer_append(sb,"  <br>Realm (optional): <input type=\"text\" name=\"");
+					str_buffer_append(sb,HR_ADD_OAUTH_REALM);
+					str_buffer_append(sb,"\" value=\"");
+					str_buffer_append(sb,(const char*)add_realm);
+					str_buffer_append(sb,"\"><br>\r\n");
+				}
+
+				str_buffer_append(sb,"</td><td>");
+
 				{
 					str_buffer_append(sb,"<br>Token encryption algorithm (required):<br>\r\n");
 
@@ -3008,6 +3032,7 @@ static void write_https_oauth_page(ioa_socket_handle s, const char* add_kid, con
 			str_buffer_append(sb,"<th>Timestamp, secs</th>");
 			str_buffer_append(sb,"<th>Lifetime,secs</th>");
 			str_buffer_append(sb,"<th>Token encryption algorithm</th>");
+			str_buffer_append(sb,"<th>Realm</th>");
 			str_buffer_append(sb,"<th> </th>");
 			str_buffer_append(sb,"</tr>\r\n");
 
@@ -3495,6 +3520,7 @@ static void handle_https(ioa_socket_handle s, ioa_network_buffer_handle nbh)
 					const char* add_lt = "0";
 					const char* add_ikm = "";
 					const char* add_tea = "";
+					const char* add_realm = "";
 					const char* msg = "";
 
 					add_kid = get_http_header_value(hr,HR_ADD_OAUTH_KID,"");
@@ -3503,6 +3529,7 @@ static void handle_https(ioa_socket_handle s, ioa_network_buffer_handle nbh)
 						add_ts = get_http_header_value(hr,HR_ADD_OAUTH_TS,"");
 						add_lt = get_http_header_value(hr,HR_ADD_OAUTH_LT,"");
 						add_tea = get_http_header_value(hr,HR_ADD_OAUTH_TEA,"");
+						add_realm = get_http_header_value(hr,HR_ADD_OAUTH_REALM,"");
 
 						int keys_ok = (add_ikm[0] != 0);
 						if(!keys_ok) {
@@ -3526,6 +3553,8 @@ static void handle_https(ioa_socket_handle s, ioa_network_buffer_handle nbh)
 								key.timestamp = (u64bits)strtoull(add_ts,NULL,10);
 							}
 
+							if(add_realm && add_realm[0]) STRCPY(key.realm,add_realm);
+
 							STRCPY(key.ikm_key,add_ikm);
 							STRCPY(key.as_rs_alg,add_tea);
 
@@ -3539,12 +3568,13 @@ static void handle_https(ioa_socket_handle s, ioa_network_buffer_handle nbh)
 									add_lt = "0";
 									add_ikm = "";
 									add_tea = "";
+									add_realm = "";
 								}
 							}
 						}
 					}
 
-					write_https_oauth_page(s,add_kid,add_ikm,add_tea,add_ts,add_lt,msg);
+					write_https_oauth_page(s,add_kid,add_ikm,add_tea,add_ts,add_lt,add_realm,msg);
 				}
 				break;
 			}

+ 4 - 0
src/apps/relay/userdb.c

@@ -517,6 +517,10 @@ int get_user_key(int in_oauth, int *out_oauth, int *max_session_time, u08bits *u
 
 						ns_bcopy(dot.enc_block.mac_key,key,dot.enc_block.key_length);
 
+						if(rawKey.realm[0]) {
+							ns_bcopy(rawKey.realm,realm,sizeof(rawKey.realm));
+						}
+
 						ret = 0;
 					}
 				}

+ 4 - 4
src/apps/uclient/mainuclient.c

@@ -102,9 +102,9 @@ int oauth = 0;
 oauth_key okey_array[3];
 
 static oauth_key_data_raw okdr_array[3] = {
-		{"north","MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK",0,0,"A256GCM"},
-		{"union","MTIzNDU2Nzg5MDEyMzQ1Ngo=",0,0,"A128GCM"},
-		{"oldempire","MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK",0,0,"A256GCM"}
+		{"north","MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK",0,0,"A256GCM","crinna.org"},
+		{"union","MTIzNDU2Nzg5MDEyMzQ1Ngo=",0,0,"A128GCM","north.gov"},
+		{"oldempire","MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK",0,0,"A256GCM",""}
 };
 
 //////////////// local definitions /////////////////
@@ -137,7 +137,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 (implies -c).\n"
-  "	-J	Use oAuth with default test key kid='north' or 'oldempire'.\n"
+  "	-J	Use oAuth with default test keys kid='north', 'union' or 'oldempire'.\n"
   "Options:\n"
   "	-l	Message length (Default: 100 Bytes).\n"
   "	-i	Certificate file (for secure connections only, optional).\n"

+ 0 - 6
src/client/ns_turn_msg_defs.h

@@ -148,12 +148,6 @@
 #define STUN_ATTRIBUTE_TRANSPORT_DTLS_VALUE (250)
 /* <<== RFC 6062 */
 
-/* Mobility ==>> */
-#define STUN_ATTRIBUTE_MOBILITY_TICKET (0x802E)
-#define STUN_ATTRIBUTE_MOBILITY_EVENT (0x802)
-#define STUN_ATTRIBUTE_MOBILITY_SUPPORT (0x8000)
-/* <<== Mobility */
-
 /* SHA ==>> */
 
 #define SHA1SIZEBYTES (20)

+ 5 - 0
src/client/ns_turn_msg_defs_experimental.h

@@ -38,6 +38,11 @@
 #define STUN_ATTRIBUTE_ORIGIN (0x802F)
 /* <<== Origin */
 
+/* Mobility ==>> */
+/* conflicts with third-party authorization ! 0x802E is used for third-party authorization now */
+#define STUN_ATTRIBUTE_MOBILITY_TICKET (0x8030)
+/* <<== Mobility */
+
 /* Bandwidth */
 
 #define STUN_ATTRIBUTE_NEW_BANDWIDTH (0x8000 + STUN_ATTRIBUTE_BANDWIDTH)

+ 2 - 2
src/ns_turn_defs.h

@@ -31,8 +31,8 @@
 #ifndef __IOADEFS__
 #define __IOADEFS__
 
-#define TURN_SERVER_VERSION "4.4.5.4"
-#define TURN_SERVER_VERSION_NAME "Ardee West"
+#define TURN_SERVER_VERSION "4.5.0.1"
+#define TURN_SERVER_VERSION_NAME "dan Eider"
 #define TURN_SOFTWARE "Coturn-" TURN_SERVER_VERSION " '" TURN_SERVER_VERSION_NAME "'"
 
 #if (defined(__unix__) || defined(unix)) && !defined(USG)

+ 1 - 3
src/server/ns_turn_ioalib.h

@@ -227,7 +227,7 @@ int create_relay_ioa_sockets(ioa_engine_handle e, ioa_socket_handle client_s,
 
 ioa_socket_handle  ioa_create_connecting_tcp_relay_socket(ioa_socket_handle s, ioa_addr *peer_addr, connect_cb cb, void *arg);
 
-int get_ioa_socket_from_reservation(ioa_engine_handle e, u64bits in_reservation_token, ioa_socket_handle *s, u08bits *realm);
+int get_ioa_socket_from_reservation(ioa_engine_handle e, u64bits in_reservation_token, ioa_socket_handle *s);
 
 int get_ioa_socket_address_family(ioa_socket_handle s);
 int is_stream_socket(int st);
@@ -260,8 +260,6 @@ 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_realm_hash(ioa_socket_handle s, u08bits *realm);
-void set_realm_hash(ioa_socket_handle s, u08bits *realm);
 
 ////////////////// Base64 /////////////////////////////
 

+ 2 - 2
src/server/ns_turn_maps.c

@@ -1029,11 +1029,11 @@ struct _ur_string_map {
   TURN_MUTEX_DECLARE(mutex)
 };
 
-static unsigned long string_hash(const ur_string_map_key_type key) {
+static u32bits string_hash(const ur_string_map_key_type key) {
 
   u08bits *str=(u08bits*)key;
 
-  unsigned long hash = 0;
+  u32bits hash = 0;
   int c = 0;
 
   while ((c = *str++))

+ 2 - 6
src/server/ns_turn_maps_rtcp.c

@@ -214,7 +214,7 @@ int rtcp_map_put(rtcp_map* map, rtcp_token_type token, ioa_socket_handle s) {
  * >=0 - success
  * <0 - not found
  */
-ioa_socket_handle rtcp_map_get(rtcp_map* map, rtcp_token_type token, u08bits *realm) {
+ioa_socket_handle rtcp_map_get(rtcp_map* map, rtcp_token_type token) {
 	ioa_socket_handle s = NULL;
 	if (rtcp_map_valid(map)) {
 		ur_map_value_type value;
@@ -224,11 +224,7 @@ ioa_socket_handle rtcp_map_get(rtcp_map* map, rtcp_token_type token, u08bits *re
 			rtcp_alloc_type* rval = (rtcp_alloc_type*) value;
 			if (rval) {
 				s = rval->s;
-				if(!check_realm_hash(s,realm)) {
-					s = NULL;
-				} else {
-					rtcp_map_del_savefd(map, token);
-				}
+				rtcp_map_del_savefd(map, token);
 			}
 		}
 		TURN_MUTEX_UNLOCK(&map->mutex);

+ 1 - 1
src/server/ns_turn_maps_rtcp.h

@@ -61,7 +61,7 @@ int rtcp_map_put(rtcp_map* map, rtcp_token_type key, ioa_socket_handle s);
  * >=0 - success
  * <0 - not found
  */
-ioa_socket_handle rtcp_map_get(rtcp_map* map, rtcp_token_type token, u08bits *realm);
+ioa_socket_handle rtcp_map_get(rtcp_map* map, rtcp_token_type token);
 
 /**
  * @ret:

+ 18 - 13
src/server/ns_turn_server.c

@@ -77,7 +77,7 @@ static inline void log_method(ts_ur_super_session* ss, const char *method, int e
 				(unsigned long long)(ss->id), (const char*)(ss->realm_options.name),(const char*)(ss->username),method);
 		}
 	  } else {
-		  if(!reason) reason=(const u08bits*)"Unknown error";
+		  if(!reason) reason=get_default_reason(err_code);
 		  if(ss->origin[0]) {
 			  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
 					  "session %018llu: origin <%s> realm <%s> user <%s>: incoming packet %s processed, error %d: %s\n",
@@ -3191,7 +3191,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,  int oauth, int max_session_time, hmackey_t hmackey, 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, password_t pwd, turn_turnserver *server, u64bits ctxkey, ioa_net_data *in_buffer, u08bits *realm)
 {
 
 	if(server && in_buffer && in_buffer->nbh) {
@@ -3206,6 +3206,11 @@ static void resume_processing_after_username_check(int success,  int oauth, int
 				ss->oauth = oauth;
 				ss->max_session_time_auth = (turn_time_t)max_session_time;
 				ns_bcopy(pwd,ss->pwd,sizeof(password_t));
+				if(realm && realm[0] && strcmp((char*)realm,ss->realm_options.name)) {
+					dec_quota(ss);
+					get_realm_options_by_name((char*)realm, &(ss->realm_options));
+					inc_quota(ss,ss->username);
+				}
 			}
 
 			read_client_connection(server,ss,in_buffer,0,0);
@@ -3318,14 +3323,18 @@ static int check_stun_auth(turn_turnserver *server,
 			get_realm_options_by_name((char *)realm, &(ss->realm_options));
 
 		} else if(strcmp((char*)realm, (char*)(ss->realm_options.name))) {
-			if(method == STUN_METHOD_ALLOCATE) {
-				*err_code = 437;
-				*reason = (const u08bits*)"Allocation mismatch: wrong credentials: the realm value is incorrect";
+			if(!(ss->oauth)){
+				if(method == STUN_METHOD_ALLOCATE) {
+					*err_code = 437;
+					*reason = (const u08bits*)"Allocation mismatch: wrong credentials: the realm value is incorrect";
+				} else {
+					*err_code = 441;
+					*reason = (const u08bits*)"Wrong credentials: the realm value is incorrect";
+				}
+				return -1;
 			} else {
-				*err_code = 441;
-				*reason = (const u08bits*)"Wrong credentials: the realm value is incorrect";
+				ns_bcopy(ss->realm_options.name,realm,sizeof(ss->realm_options.name));
 			}
-			return -1;
 		}
 	}
 
@@ -3366,7 +3375,6 @@ static int check_stun_auth(turn_turnserver *server,
 		}
 	} else {
 		STRCPY(ss->username,usname);
-		set_realm_hash(ss->client_socket,(u08bits*)ss->realm_options.name);
 	}
 
 	{
@@ -4261,7 +4269,7 @@ static int create_relay_connection(turn_turnserver* server,
 
 			ioa_socket_handle s = NULL;
 
-			if ((get_ioa_socket_from_reservation(server->e, in_reservation_token,&s,(u08bits*)ss->realm_options.name) < 0)||
+			if ((get_ioa_socket_from_reservation(server->e, in_reservation_token,&s) < 0)||
 				!s ||
 				ioa_socket_tobeclosed(s)) {
 
@@ -4317,11 +4325,8 @@ static int create_relay_connection(turn_turnserver* server,
 			return -1;
 		}
 
-		set_realm_hash(newelem->s,(u08bits*)ss->realm_options.name);
-
 		if (rtcp_s) {
 			if (out_reservation_token && *out_reservation_token) {
-				set_realm_hash(rtcp_s,(u08bits*)ss->realm_options.name);
 				/* OK */
 			} else {
 				IOA_CLOSE_SOCKET(newelem->s);

+ 1 - 1
src/server/ns_turn_server.h

@@ -90,7 +90,7 @@ typedef enum {
 struct _turn_turnserver;
 typedef struct _turn_turnserver turn_turnserver;
 
-typedef void (*get_username_resume_cb)(int success, int oauth, int max_session_time, hmackey_t hmackey, password_t pwd, turn_turnserver *server, u64bits ctxkey, ioa_net_data *in_buffer);
+typedef void (*get_username_resume_cb)(int success, int oauth, int max_session_time, hmackey_t hmackey, password_t pwd, turn_turnserver *server, u64bits ctxkey, ioa_net_data *in_buffer, u08bits* realm);
 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);

+ 1 - 0
turndb/schema.sql

@@ -43,6 +43,7 @@ CREATE TABLE oauth_key (
 	timestamp bigint default 0,
 	lifetime integer default 0,
 	as_rs_alg varchar(64) default '',
+	realm varchar(127),
 	primary key (kid)
 );
 

+ 18 - 9
turndb/schema.userdb.redis

@@ -46,6 +46,9 @@ and they will be almost immediately "seen" by the turnserver process.
 		"A256GCM", "A128GCM" (see 
 		http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-5.1).
 		The default value is "A256GCM".
+
+	realm - optionally, a kid can be assigned to a realm that is different
+		from the default realm.
 		
 5) admin users (over https interface) are maintained as keys of form:
 "turn/admin_user/<username> with hash members "password" and,
@@ -54,15 +57,21 @@ optionally, "realm".
 II. Extra realms data in the database
 
 We can use more than one realm with the same instance of the TURN server.
-This is done through the ORIGIN mechanism - users with different ORIGINS
-are placed into different realms. The database includes information about the
-relationships between the ORIGIN and realms, and about the extra realms
-database numbers.
+This is done in two ways:
+
+  1) through the third-party authentication option. An oAuth kid can be optionally
+  assigned to a realm. When the user provides kid, and the database record
+  for that kid contains a non-empty non-default realm, then the user is treated
+  as belonging to that realm.
+  2) the ORIGIN mechanism - users with different ORIGINS
+  are placed into different realms. The database includes information about the
+  relationships between the ORIGIN and realms, and about the extra realms
+  database numbers.
 	The relationship between ORIGIN and realm is set as keys of form:
-"turn/origin/<origin>" with the realm-names as the value. Many different
-ORIGIN keys may have the same realm. If the ORIGIN value is not found in 
-the database or the ORIGIN field is missed in the initial allocate 
-request, then the default realm is assumed.
+	"turn/origin/<origin>" with the realm-names as the value. Many different
+	ORIGIN keys may have the same realm. If the ORIGIN value is not found in 
+	the database or the ORIGIN field is missed in the initial allocate 
+	request, then the default realm is assumed.
 
 III) Example of a Redis default user database setup.
 
@@ -82,7 +91,7 @@ This example sets user database for:
   	"total_quota" and "user_quota" (same names as the turnserver 
   	configuration options, with the same meanings).
   * The oAuth data for the key with kid "oldempire" and key value
-  "12345678901234567890123456789012".
+  "12345678901234567890123456789012", and default realm.
   * The admin user 'skarling', realm 'north.gov', with password 'hoodless';
   * The global admin user 'bayaz' with password 'magi';  
   

+ 6 - 4
turndb/testmongosetup.sh

@@ -28,8 +28,8 @@ db.turn_secret.insert({ realm: 'north.gov', value: 'bloody9' });
 db.turn_secret.insert({ realm: 'crinna.org', value: 'north' });
 db.turn_secret.insert({ realm: 'crinna.org', value: 'library' });
 
-db.admin_user.insert({ name: 'skarling', realm: 'north.gov', password: '$5$6fc35c3b0c7d4633$27fca7574f9b79d0cb93ae03e45379470cbbdfcacdd6401f97ebc620f31f54f2' });
-db.admin_user.insert({ name: 'bayaz', realm: '', password: '$5$e018513e9de69e73$5cbdd2e29e04ca46aeb022268a7460d3a3468de193dcb2b95f064901769f455f' });
+db.admin_user.insert({ name: 'skarling', realm: 'north.gov', password: '\$5\$6fc35c3b0c7d4633\$27fca7574f9b79d0cb93ae03e45379470cbbdfcacdd6401f97ebc620f31f54f2' });
+db.admin_user.insert({ name: 'bayaz', realm: '', password: '\$5\$e018513e9de69e73\$5cbdd2e29e04ca46aeb022268a7460d3a3468de193dcb2b95f064901769f455f' });
 
 db.realm.insert({
   realm: 'north.gov',
@@ -56,10 +56,12 @@ db.realm.insert({
 
 db.oauth_key.insert({ kid: 'north', 
 					ikm_key: 'MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK', 
-					as_rs_alg: 'A256GCM'});
+					as_rs_alg: 'A256GCM',
+					realm: 'crinna.org'});
 db.oauth_key.insert({ kid: 'union', 
 					ikm_key: 'MTIzNDU2Nzg5MDEyMzQ1Ngo=', 
-					as_rs_alg: 'A128GCM'});
+					as_rs_alg: 'A128GCM',
+					realm: 'north.gov'});
 db.oauth_key.insert({ kid: 'oldempire', 
 					ikm_key: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK', 
 					as_rs_alg: 'A256GCM'});

+ 2 - 2
turndb/testredisdbsetup.sh

@@ -38,8 +38,8 @@ sadd turn/realm/crinna.org/allowed-peer-ip "172.17.13.202"
 sadd turn/realm/north.gov/denied-peer-ip "172.17.13.133-172.17.14.56" "172.17.17.133-172.17.19.56" "123::45"
 sadd turn/realm/crinna.org/denied-peer-ip "123::77"
 
-hmset turn/oauth/kid/north ikm_key 'MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK' as_rs_alg 'A256GCM'
-hmset turn/oauth/kid/union ikm_key 'MTIzNDU2Nzg5MDEyMzQ1Ngo=' as_rs_alg 'A128GCM'
+hmset turn/oauth/kid/north ikm_key 'MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK' as_rs_alg 'A256GCM' realm 'crinna.org'
+hmset turn/oauth/kid/union ikm_key 'MTIzNDU2Nzg5MDEyMzQ1Ngo=' as_rs_alg 'A128GCM' realm 'north.gov'
 hmset turn/oauth/kid/oldempire ikm_key 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK' as_rs_alg 'A256GCM'
 
 hmset turn/admin_user/skarling realm 'north.gov' password '\$5\$6fc35c3b0c7d4633\$27fca7574f9b79d0cb93ae03e45379470cbbdfcacdd6401f97ebc620f31f54f2'

+ 3 - 3
turndb/testsqldbsetup.sql

@@ -31,6 +31,6 @@ insert into denied_peer_ip (ip_range) values('123::45');
 insert into denied_peer_ip (realm,ip_range) values('north.gov','172.17.17.133-172.17.19.56');
 insert into denied_peer_ip (realm,ip_range) values('crinna.org','123::77');
 
-insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('north','MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK',0,0,'A256GCM');
-insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('union','MTIzNDU2Nzg5MDEyMzQ1Ngo=',0,0,'A128GCM');
-insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('oldempire','MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK',0,0,'A256GCM');
+insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('north','MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK',0,0,'A256GCM','crinna.org');
+insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('union','MTIzNDU2Nzg5MDEyMzQ1Ngo=',0,0,'A128GCM','north.gov');
+insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('oldempire','MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK',0,0,'A256GCM','');