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

working on sqlite support

mom040267 11 жил өмнө
parent
commit
b9ef9f4c61

+ 3 - 1
ChangeLog

@@ -1,6 +1,8 @@
 11/10/2014 Oleg Moskalenko <[email protected]>
-Version 4.2.3.2 'Monza':
+Version 4.3.1.1 'Tolomei':
 	- TLS connection procedure improved in uclient test program.
+	- Flat-file user database is no longer supported.
+	- SQLite supported as the default user database (TODO).
 	
 11/07/2014 Oleg Moskalenko <[email protected]>
 Version 4.2.3.1 'Monza':

+ 13 - 4
INSTALL

@@ -211,7 +211,7 @@ If you do not want to use the rpath linking option, or you OS or compiler
 do not allows that, then after the installation, you may have to adjust the 
 system-wide shared library search path by using "ldconfig -n <libdirname>" 
 (Linux), "ldconfig -m <libdirname>" (BSD) or "crle -u -l <libdirname>" 
-(Solaris). Your system must be able to find the libevent2, openssl and 
+(Solaris). Your system must be able to find the sqlite, libevent2, openssl and 
 (optionally) PostgreSQL and/or MySQL (MariaDB) and/or MongoDB and/or Redis 
 shared libraries, either with the help of the system-wide library search 
 configuration or by using LD_LIBRARY_PATH. "make install" will make a 
@@ -274,8 +274,9 @@ The code is compatible with C++ compiler, and a C++ compiler
 VII. WHICH EXTRA LIBRARIES AND UTILITIES YOU NEED 
 
 In addition to common *NIX OS services and libraries, to compile this code, 
-OpenSSL (version 1.0.0a or better recommended) and libevent2 (version 2.0.5 
-or better) are required, the PostgreSQL C client development setup is 
+OpenSSL (version 1.0.0a or better recommended), sqlite C development library,
+and libevent2 (version 2.0.5 or better) are required, 
+the PostgreSQL C client development setup is 
 optional, the MySQL (MariaDB) C client development setup is optional, the MongoDB
 C Driver and the Hiredis development files for Redis database access are optional.
 For fully functional build, the extra set of libraries must be installed
@@ -283,9 +284,10 @@ in full version (the development headers and the libraries to link with).
 For runtime, only runtime setup is required. If the build is modified for 
 static linking, then even runtime installation is not needed.
 
-OpenSSL, libevent2, PostgreSQL, MySQL (or MariaDB) and Hiredis 
+OpenSSL, SQLite, libevent2, PostgreSQL, MySQL (or MariaDB) and Hiredis 
 libraries can be downloaded from their web sites:
  - http://www.openssl.org (required);
+ - http://www.sqlite.org (required);
  - http://www.libevent.org (required);
  - http://www.postgresql.org (optional);
  - http://www.mysql.org (or http://mariadb.org) (optional);
@@ -315,6 +317,8 @@ installation:
 
 		$ cd /usr/ports/security/openssl/
 		$ sudo make install clean
+		$ cd /usr/ports/databases/sqlite3/
+		$ sudo make install clean
 		$ cd /usr/ports/devel/libevent2/
 		$ sudo make install clean
 		$ cd /usr/ports/databases/postgresql84-client/ (or any other version)
@@ -327,6 +331,7 @@ installation:
 	**) Linux Ubuntu 11.10+, Debian Wheezy, Mint 14+:
 		
 		$ sudo apt-get install libssl-dev
+		$ sudo apt-get install sqlite3-dev
 		$ sudo apt-get install libevent-dev
 		$ sudo apt-get install libpq-dev
 		$ sudo apt-get install mysql-client
@@ -338,6 +343,8 @@ installation:
 	***) Fedora:
 
 	$ sudo yum install openssl-devel
+	$ sudo yum install sqlite
+	$ sudo yum install sqlite-devel
 	$ sudo yum install libevent
 	$ sudo yum install libevent-devel
 	$ sudo yum install postgresql-devel
@@ -446,6 +453,8 @@ If you have a system with older libevent, then you have to install the new
 libevent2 from their web site. It was tested with older *NIXes 
 (like FreeBSD 6.x) and it works just fine.
 
+NOTE: SQLite must be of version 3.x.
+
 NOTE: For extra security features (DTLS and SHA256) support, OpenSSL version 
 1.0.0a or newer is recommended. Older versions do not support DTLS, reliably, 
 in some cases. For example, the Debian 'Squeeze' Linux supplies 0.9.8 version 

+ 4 - 4
Makefile.in

@@ -27,8 +27,8 @@ IMPL_DEPS = ${COMMON_DEPS} ${IMPL_HEADERS} ${IMPL_MODS}
 HIREDIS_HEADERS = src/apps/common/hiredis_libevent2.h
 HIREDIS_MODS = src/apps/common/hiredis_libevent2.c
 
-USERDB_HEADERS = src/apps/relay/dbdrivers/dbdriver.h src/apps/relay/dbdrivers/dbd_pgsql.h src/apps/relay/dbdrivers/dbd_mysql.h src/apps/relay/dbdrivers/dbd_mongo.h src/apps/relay/dbdrivers/dbd_redis.h
-USERDB_MODS = src/apps/relay/dbdrivers/dbdriver.c src/apps/relay/dbdrivers/dbd_pgsql.c src/apps/relay/dbdrivers/dbd_mysql.c src/apps/relay/dbdrivers/dbd_mongo.c src/apps/relay/dbdrivers/dbd_redis.c
+USERDB_HEADERS = src/apps/relay/dbdrivers/dbdriver.h src/apps/relay/dbdrivers/dbd_sqlite.h src/apps/relay/dbdrivers/dbd_pgsql.h src/apps/relay/dbdrivers/dbd_mysql.h src/apps/relay/dbdrivers/dbd_mongo.h src/apps/relay/dbdrivers/dbd_redis.h
+USERDB_MODS = src/apps/relay/dbdrivers/dbdriver.c src/apps/relay/dbdrivers/dbd_sqlite.c src/apps/relay/dbdrivers/dbd_pgsql.c src/apps/relay/dbdrivers/dbd_mysql.c src/apps/relay/dbdrivers/dbd_mongo.c src/apps/relay/dbdrivers/dbd_redis.c
 
 SERVERAPP_HEADERS = src/apps/relay/userdb.h src/apps/relay/tls_listener.h src/apps/relay/mainrelay.h src/apps/relay/turncli.h src/apps/relay/dtls_listener.h src/apps/relay/libtelnet.h ${HIREDIS_HEADERS} ${USERDB_HEADERS}
 SERVERAPP_MODS = src/apps/relay/mainrelay.c src/apps/relay/netengine.c src/apps/relay/libtelnet.c src/apps/relay/turncli.c src/apps/relay/userdb.c src/apps/relay/tls_listener.c src/apps/relay/dtls_listener.c ${HIREDIS_MODS} ${USERDB_MODS}
@@ -142,7 +142,7 @@ install:	all ${MAKE_DEPS}
 	${INSTALL_DATA} turndb/schema.stats.redis ${DESTDIR}${DOCSDIR}
 	${INSTALL_DATA} turndb/schema.stats.redis ${DESTDIR}${SCHEMADIR}
 	${INSTALL_DATA} examples/etc/turnserver.conf ${DESTDIR}${CONFDIR}/turnserver.conf.default
-	${INSTALL_DATA} examples/etc/turnuserdb.conf ${DESTDIR}${CONFDIR}/turnuserdb.conf.default
+	${INSTALL_DATA} examples/var/db/turdb ${DESTDIR}/var/db/turndb
 	${INSTALL_DIR} examples/etc ${DESTDIR}${EXAMPLESDIR}
 	${INSTALL_DIR} examples/scripts ${DESTDIR}${EXAMPLESDIR}
 	${RMCMD} ${DESTDIR}${EXAMPLESDIR}/scripts/rfc5769.sh
@@ -169,7 +169,7 @@ deinstall:	${MAKE_DEPS}
 	${RMCMD} ${DESTDIR}${LIBDIR}/libturnclient.a
 	${RMCMD} ${DESTDIR}${EXAMPLESDIR}/
 	${RMCMD} ${DESTDIR}${CONFDIR}/turnserver.conf.default
-	${RMCMD} ${DESTDIR}${CONFDIR}/turnuserdb.conf.default
+	${RMCMD} ${DESTDIR}/var/db/turndb
 	${RMCMD} ${DESTDIR}${TURNINCLUDEDIR}
 
 uninstall:	deinstall

+ 5 - 13
README.turnadmin

@@ -77,17 +77,11 @@ Commands:
 -g, --set-realm-option		Set realm params: max-bps, total-quota, user-quota.
 
 -G, --list-realm-options	List realm params.
-
-NOTE: if you are using the flat file for the user database, then you will have 
-to use a text editor to set or show the shared secrets.
-
-NOTE: the origin functionality is not supported with flat user db file, 
-a "real" database must be used.
   
 Options with required values:  
 
--b, --userdb		File-based user database file name (default - turnuserdb.conf).
-			See the --userdb option in the turnserver section.
+-b, --db, --userdb		SQLite user database file name (default - /var/db/turndb).
+			See the same option in the turnserver section.
 -e, --psql-userdb	PostgreSQL user database connection string.
 			See the --psql-userdb option in the turnserver section.
 -M, --mysql-userdb	MySQL user database connection string.
@@ -112,11 +106,11 @@ Generate a key:
 
 $ turnadmin -k -u <username> -r <realm> -p <password>
   
-Add/update a user in the userdb file or in the database:
+Add/update a user in the in the database:
 
 $ turnadmin -a [-b <userdb-file> | -e <db-connection-string> | -M <db-connection-string> | -N <db-connection-string> ] -u <username> -r <realm> -p <password>
   
-Delete a user from the userdb file or from the database:
+Delete a user from the database:
 
 $ turnadmin -d [-b <userdb-file> | -e <db-connection-string> | -M <db-connection-string> | -N <db-connection-string> ] -u <username> -r <realm>
 
@@ -176,12 +170,10 @@ to see the man page.
 
 /etc/turnserver.conf
 
-/etc/turnuserdb.conf
+/var/db/turndb
 
 /usr/local/etc/turnserver.conf
 
-/usr/local/etc/turnuserdb.conf
-
 =====================================
 
   DIRECTORIES

+ 11 - 23
README.turnserver

@@ -81,11 +81,7 @@ Config file settings:
 
 User database settings:  
 
--b, --userdb	User database file name (default - turnuserdb.conf),
-		for long-term credentials mechanism only.
-		This user file database is being dynamically checked while the 
-		turnserver is working, and the user accounts can be changed 
-		dynamically by editing the database.
+-b, --db, --userdb	SQLite user database file name (default - /var/db/turndb).
 				  
 -e, --psql-userdb	User database connection string for PostgreSQL.
 		This database can be used for long-term and short-term 
@@ -161,11 +157,9 @@ Flags:
 			fingerprints to the messages in this session, regardless of the
 			per-server setting.
 
--a, --lt-cred-mech	Use long-term credentials mechanism (this one you need for WebRTC usage). 
-			This option can be used with either flat file user database or 
-			PostgreSQL DB or MySQL DB or MongoDB or Redis for user keys storage.
--A, --st-cred-mech	Use the short-term credentials mechanism. This option requires
-	                a PostgreSQL or MySQL or MongoDB or Redis DB for short term passwords storage.
+-a, --lt-cred-mech	Use long-term credentials mechanism (this one you need for WebRTC usage).
+
+-A, --st-cred-mech	Use the short-term credentials mechanism.
 
 -z, --no-auth		Do not use any credentials mechanism, allow anonymous access. 
 			Opposite to -a and -A options. This is default option when no 
@@ -568,16 +562,14 @@ for that you have a number of options:
 
 	a) command-line options (-u).
 	
-	b) userdb config file.
-	
-	c) a database table (PostgreSQL or MySQL or MongoDB). You will have to set keys with 
-	turnadmin utility (see docs and wiki for turnadmin). You cannot use open passwords 
-	in the database.
+	b) a database table (SQLite or PostgreSQL or MySQL or MongoDB). You will have to 
+	set keys with turnadmin utility (see docs and wiki for turnadmin). 
+	You cannot use open passwords in the database.
 
-	d) Redis key/value pair(s), if Redis is used. You key use either keys or 
+	c) Redis key/value pair(s), if Redis is used. You key use either keys or 
 	open passwords with Redis; see turndb/testredisdbsetup.sh file.  
 	
-	e) You also can use the TURN REST API. You will need shared secret(s) set
+	d) You also can use the TURN REST API. You will need shared secret(s) set
 	either	through the command line option, or through the config file, or through
 	the database table or Redis key/value pairs.  
 
@@ -724,9 +716,7 @@ For the user database, the turnserver has the following options:
 Obviously, only a few users can be set that way, and their credentials are fixed 
 for the turnserver process lifetime.
 
-2) Users can be set in turnusers.conf flat file DB. The turnserver process periodically 
-re-reads this file, so the user accounts may be changed while the turnserver is running.
-But still a relatively small (up to a hundred ?) number of users can be handled that way.
+2) Users can be stored in SQlite DB. The default SQLite database file is /var/db/turndb.
 
 3) Users can be stored in PostgreSQL database, if the turnserver was compiled with PostgreSQL
 support. Each time turnserver checks user credentials, it reads the database (asynchronously,
@@ -851,12 +841,10 @@ FILES
 
 /etc/turnserver.conf
 
-/etc/turnuserdb.conf
+/var/db/turndb
 
 /usr/local/etc/turnserver.conf
 
-/usr/local/etc/turnuserdb.conf
-
 =================================
 
 DIRECTORIES

+ 1 - 3
README.turnutils

@@ -251,12 +251,10 @@ FILES
 
 /etc/turnserver.conf
 
-/etc/turnuserdb.conf
+/var/db/turndb
 
 /usr/local/etc/turnserver.conf
 
-/usr/local/etc/turnuserdb.conf
-
 =================================
 
 DIRECTORIES

+ 2 - 0
STATUS

@@ -106,6 +106,8 @@ compatibility.
 45) Secure MySQL connection implemented.
 
 46) Third-party security mechanism (through oAuth) implemented.
+
+47) SQLite support added as default database.
  
 Things to be implemented in future (the development roadmap) 
 are described in the TODO file.

+ 53 - 0
configure

@@ -19,6 +19,8 @@ cleanup() {
 	rm -rf ${MONGO_TMPCPROGB}
 	rm -rf ${D_TMPCPROGC}
 	rm -rf ${D_TMPCPROGB}
+	rm -rf ${SQL_TMPCPROGC}
+	rm -rf ${SQL_TMPCPROGO}
 	rm -rf ${E_TMPCPROGC}
 	rm -rf ${E_TMPCPROGO}
 	rm -rf ${HR_TMPCPROGC}
@@ -38,6 +40,19 @@ testlibraw() {
     fi
 }
 
+testsqlite_comp() {
+	SQLITE_LIBS=-lsqlite3
+    ${CC} -c ${SQL_TMPCPROGC} -o ${SQL_TMPCPROGO} ${OSCFLAGS} 2>>/dev/null
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "SQLite development is not installed properly"
+		return 0
+    else
+		DBLIBS="${DBLIBS} ${SQLITE_LIBS}"
+		return 1
+    fi
+}
+
 testlibevent2_comp() {
     ${CC} -c ${E_TMPCPROGC} -o ${E_TMPCPROGO} ${OSCFLAGS} 2>>/dev/null
     ER=$?
@@ -683,6 +698,18 @@ int main(int argc, char** argv) {
 }
 !
 
+SQL_TMPCPROG=__test__ccomp__sqlite__$$
+SQL_TMPCPROGC=${TMPDIR}/${SQL_TMPCPROG}.c
+SQL_TMPCPROGO=${TMPDIR}/${SQL_TMPCPROG}.o
+
+cat > ${SQL_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <sqlite3.h>
+int main(int argc, char** argv) {
+    return (int)(argv[argc][0]);
+}
+!
+
 HR_TMPCPROG=__test__ccomp__hiredis__$$
 HR_TMPCPROGC=${TMPDIR}/${HR_TMPCPROG}.c
 HR_TMPCPROGB=${TMPDIR}/${HR_TMPCPROG}
@@ -932,6 +959,32 @@ else
 	TURN_NO_GCM="-DTURN_NO_GCM"
 fi
 
+###########################
+# Test SQLite setup
+###########################
+
+testlib sqlite3
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+   	${ECHO_CMD} "SQLite library found."
+else
+   	${ECHO_CMD} "ERROR: SQLite3 development library cannot be found."
+   	cleanup
+   	exit
+fi
+	
+testsqlite_comp
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    ${ECHO_CMD} "SQLite development found."
+else
+    ${ECHO_CMD} "ERROR: SQLite development libraries are not installed properly in required location."
+    ${ECHO_CMD} "See the INSTALL file."
+    ${ECHO_CMD} "Abort."
+    cleanup
+    exit
+fi
+
 ###########################
 # Test Libevent2 setup
 ###########################

+ 4 - 9
examples/etc/turnserver.conf

@@ -248,16 +248,11 @@
 #user=ninefingers:youhavetoberealistic
 #
 
-# 'Dynamic' user accounts database file name.
-# Only users for long-term mechanism can be stored in a flat file,
-# short-term mechanism will not work with option, the short-term
-# mechanism required PostgreSQL or MySQL or MongoDB or Redis database.
-# 'Dynamic' long-term user accounts are dynamically checked by the turnserver process, 
-# so that they can be changed while the turnserver is running.
-#
-# Default file name is turnuserdb.conf.
+# SQLite database file name.
+#
+# Default file name is /var/db/turndb
 # 
-#userdb=/usr/local/etc/turnuserdb.conf
+#userdb=/var/db/turndb
 
 # PostgreSQL database connection string in the case that we are using PostgreSQL
 # as the user database.

+ 0 - 23
examples/etc/turnuserdb.conf

@@ -1,23 +0,0 @@
-#This file can be used as user accounts storage for long-term credentials mechanism.
-#
-#username1:key1
-#username2:key2
-# OR:
-#username1:password1
-#username2:password2
-#
-# Keys must be generated by turnadmin utility. The key value depends
-# on user name, realm, and password:
-#
-# Example:
-# $ turnadmin -k -u ninefingers -r north.gov -p youhavetoberealistic
-# Output: 0xbc807ee29df3c9ffa736523fb2c4e8ee
-# ('0x' in the beginning of the key is what differentiates the key from
-# password. If it has 0x then it is a key, otherwise it is a password).
-#
-# The corresponding user account entry in the userdb file will be:
-# 
-#ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee
-# Or, equivalently (less secure):
-#ninefingers:youhavetoberealistic
-#

BIN
examples/var/db/turndb


+ 7 - 15
man/man1/turnadmin.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "09 November 2014" "" ""
+.TH TURN 1 "15 November 2014" "" ""
 .SH GENERAL INFORMATION
 
 \fIturnadmin\fP is a TURN administration tool. This tool can be used to manage 
@@ -126,20 +126,14 @@ Set realm params: max\-bps, total\-quota, user\-quota.
 .B
 \fB\-G\fP, \fB\-\-list\-realm\-options\fP
 List realm params.
-.PP
-NOTE: if you are using the flat file for the user database, then you will have 
-to use a text editor to set or show the shared secrets.
-.PP
-NOTE: the origin functionality is not supported with flat user db file, 
-a "real" database must be used.
 .TP
 .B
 Options with required values:
 .TP
 .B
-\fB\-b\fP, \fB\-\-userdb\fP
-File\-based user database file name (default \- turnuserdb.conf).
-See the \fB\-\-userdb\fP option in the \fIturnserver\fP section.
+\fB\-b\fP, \fB\-\-db\fP, \fB\-\-userdb\fP
+SQLite user database file name (default \- /var/db/turndb).
+See the same option in the \fIturnserver\fP section.
 .TP
 .B
 \fB\-e\fP, \fB\-\-psql\-userdb\fP
@@ -204,11 +198,11 @@ Generate a key:
 .PP
 $ \fIturnadmin\fP \fB\-k\fP \fB\-u\fP <username> \fB\-r\fP <realm> \fB\-p\fP <password>
 .PP
-Add/update a user in the userdb file or in the database:
+Add/update a user in the in the database:
 .PP
 $ \fIturnadmin\fP \fB\-a\fP [\fB\-b\fP <userdb\-file> | \fB\-e\fP <db\-connection\-string> | \fB\-M\fP <db\-connection\-string> | \fB\-N\fP <db\-connection\-string> ] \fB\-u\fP <username> \fB\-r\fP <realm> \fB\-p\fP <password>
 .PP
-Delete a user from the userdb file or from the database:
+Delete a user from the database:
 .PP
 $ \fIturnadmin\fP \fB\-d\fP [\fB\-b\fP <userdb\-file> | \fB\-e\fP <db\-connection\-string> | \fB\-M\fP <db\-connection\-string> | \fB\-N\fP <db\-connection\-string> ] \fB\-u\fP <username> \fB\-r\fP <realm>
 .PP
@@ -267,12 +261,10 @@ to see the man page.
 
 /etc/turnserver.conf
 .PP
-/etc/turnuserdb.conf
+/var/db/turndb
 .PP
 /usr/local/etc/turnserver.conf
 .PP
-/usr/local/etc/turnuserdb.conf
-.PP
 =====================================
 .SS  DIRECTORIES
 

+ 12 - 25
man/man1/turnserver.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "09 November 2014" "" ""
+.TH TURN 1 "15 November 2014" "" ""
 .SH GENERAL INFORMATION
 
 The \fBTURN Server\fP project contains the source code of a TURN server and TURN client 
@@ -131,12 +131,8 @@ installation directory /etc
 User database settings:
 .TP
 .B
-\fB\-b\fP, \fB\-\-userdb\fP
-User database file name (default \- turnuserdb.conf),
-for long\-term credentials mechanism only.
-This user file database is being dynamically checked while the 
-\fIturnserver\fP is working, and the user accounts can be changed 
-dynamically by editing the database.
+\fB\-b\fP, \fB\-\-db\fP, \fB\-\-userdb\fP
+SQLite user database file name (default \- /var/db/turndb).
 .TP
 .B
 \fB\-e\fP, \fB\-\-psql\-userdb\fP
@@ -239,14 +235,11 @@ per\-server setting.
 .TP
 .B
 \fB\-a\fP, \fB\-\-lt\-cred\-mech\fP
-Use long\-term credentials mechanism (this one you need for WebRTC usage). 
-This option can be used with either flat file user database or 
-PostgreSQL DB or MySQL DB or MongoDB or Redis for user keys storage.
+Use long\-term credentials mechanism (this one you need for WebRTC usage).
 .TP
 .B
 \fB\-A\fP, \fB\-\-st\-cred\-mech\fP
-Use the short\-term credentials mechanism. This option requires
-a PostgreSQL or MySQL or MongoDB or Redis DB for short term passwords storage.
+Use the short\-term credentials mechanism.
 .TP
 .B
 \fB\-z\fP, \fB\-\-no\-auth\fP
@@ -807,16 +800,14 @@ for that you have a number of \fIoptions\fP:
 .fam C
         a) command\-line options (\-u).
 
-        b) userdb config file.
+        b) a database table (SQLite or PostgreSQL or MySQL or MongoDB). You will have to 
+        set keys with turnadmin utility (see docs and wiki for turnadmin). 
+        You cannot use open passwords in the database.
 
-        c) a database table (PostgreSQL or MySQL or MongoDB). You will have to set keys with 
-        turnadmin utility (see docs and wiki for turnadmin). You cannot use open passwords 
-        in the database.
-
-        d) Redis key/value pair(s), if Redis is used. You key use either keys or 
+        c) Redis key/value pair(s), if Redis is used. You key use either keys or 
         open passwords with Redis; see turndb/testredisdbsetup.sh file.  
 
-        e) You also can use the TURN REST API. You will need shared secret(s) set
+        d) You also can use the TURN REST API. You will need shared secret(s) set
         either  through the command line option, or through the config file, or through
         the database table or Redis key/value pairs.  
 
@@ -980,9 +971,7 @@ Users can be set in the command line, with multiple \fB\-u\fP or \fB\-\-user\fP
 Obviously, only a few users can be set that way, and their credentials are fixed 
 for the \fIturnserver\fP process lifetime.
 .IP 2) 4
-Users can be set in turnusers.conf flat file DB. The \fIturnserver\fP process periodically
-re\-reads this file, so the user accounts may be changed while the \fIturnserver\fP is running.
-But still a relatively small (up to a hundred ?) number of users can be handled that way.
+Users can be stored in SQlite DB. The default SQLite database file is /var/db/turndb.
 .IP 3) 4
 Users can be stored in PostgreSQL database, if the \fIturnserver\fP was compiled with PostgreSQL
 support. Each time \fIturnserver\fP checks user credentials, it reads the database (asynchronously,
@@ -1107,12 +1096,10 @@ it would affect the performance.
 
 /etc/turnserver.conf
 .PP
-/etc/turnuserdb.conf
+/var/db/turndb
 .PP
 /usr/local/etc/turnserver.conf
 .PP
-/usr/local/etc/turnuserdb.conf
-.PP
 =================================
 .SH DIRECTORIES
 

+ 2 - 4
man/man1/turnutils.1

@@ -1,5 +1,5 @@
 .\" Text automatically generated by txt2man
-.TH TURN 1 "09 November 2014" "" ""
+.TH TURN 1 "15 November 2014" "" ""
 .SH GENERAL INFORMATION
 
 A set of turnutils_* programs provides some utility functionality to be used
@@ -374,12 +374,10 @@ to see the man page.
 
 /etc/turnserver.conf
 .PP
-/etc/turnuserdb.conf
+/var/db/turndb
 .PP
 /usr/local/etc/turnserver.conf
 .PP
-/usr/local/etc/turnuserdb.conf
-.PP
 =================================
 .SH DIRECTORIES
 

+ 6 - 4
postinstall.txt

@@ -9,13 +9,15 @@ service, you have to:
 	Use /usr/local/etc/turnserver.conf.default as an example.
 
 	b) For user accounts settings, if using the turnserver 
-	with authentication: create and edit /etc/turnuserdb.conf 
-	file, or set up PostgreSQL or MySQL or MongoDB or Redis database for user accounts.
-	Use /usr/local/etc/turnuserdb.conf.default as example for flat file DB,
-	or use /usr/local/share/turnserver/schema.sql as SQL database schema,
+	with authentication: set up SQLite or PostgreSQL or MySQL or MongoDB or 
+	Redis database for user accounts.
+	Use /usr/local/share/turnserver/schema.sql as SQL database schema,
 	or use /usr/local/share/turnserver/schema.userdb.redis as Redis
 	database schema description and/or /usr/local/share/turnserver/schema.stats.redis
 	as Redis status & statistics database schema description.
+	 
+	The installation process automatically creates /var/db/turndb SQlite database file,
+	with empty tables.
 
 	c) add whatever is necessary to enable start-up daemon for the /usr/local/bin/turnserver.
      

+ 1 - 1
rpm/build.settings.sh

@@ -2,7 +2,7 @@
 
 # Common settings script.
 
-TURNVERSION=4.2.3.2
+TURNVERSION=4.3.1.1
 BUILDDIR=~/rpmbuild
 ARCH=`uname -p`
 TURNSERVER_SVN_URL=http://coturn.googlecode.com/svn

+ 3 - 6
rpm/turnserver.spec

@@ -1,5 +1,5 @@
 Name:		turnserver
-Version:	4.2.3.2
+Version:	4.3.1.1
 Release:	0%{dist}
 Summary:	Coturn TURN Server
 
@@ -112,8 +112,6 @@ DESTDIR=$RPM_BUILD_ROOT make install
 mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig
 install -m644 rpm/turnserver.sysconfig \
 		$RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/turnserver
-mv $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnuserdb.conf.default \
-	$RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnuserdb.conf
 %if 0%{?el6}
 cat $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnserver.conf.default | \
     sed s/#syslog/syslog/g | \
@@ -169,12 +167,12 @@ fi
 %defattr(-,root,root)
 %{_bindir}/turnserver
 %{_bindir}/turnadmin
+%{_localstatedir}/db/turndb
 %{_mandir}/man1/coturn.1.gz
 %{_mandir}/man1/turnserver.1.gz
 %{_mandir}/man1/turnadmin.1.gz
 %dir %attr(-,turnserver,turnserver) %{_sysconfdir}/%{name}
 %config(noreplace) %attr(0644,turnserver,turnserver) %{_sysconfdir}/%{name}/turnserver.conf
-%config(noreplace) %attr(0644,turnserver,turnserver) %{_sysconfdir}/%{name}/turnuserdb.conf
 %config(noreplace) %{_sysconfdir}/sysconfig/turnserver
 %if 0%{?el6}
 %config %{_sysconfdir}/rc.d/init.d/turnserver
@@ -203,7 +201,6 @@ fi
 %{_datadir}/%{name}/etc/turn_server_cert.pem
 %{_datadir}/%{name}/etc/turn_server_pkey.pem
 %{_datadir}/%{name}/etc/turnserver.conf
-%{_datadir}/%{name}/etc/turnuserdb.conf
 %dir %{_datadir}/%{name}/scripts
 %{_datadir}/%{name}/scripts/peer.sh
 %{_datadir}/%{name}/scripts/readme.txt
@@ -295,7 +292,7 @@ fi
 
 %changelog
 * Mon Nov 10 2014 Oleg Moskalenko <[email protected]>
-  - Sync to 4.2.3.2
+  - Sync to 4.3.1.1
 * Thu Nov 07 2014 Oleg Moskalenko <[email protected]>
   - Sync to 4.2.3.1
 * Sun Oct 26 2014 Oleg Moskalenko <[email protected]>

+ 818 - 0
src/apps/relay/dbdrivers/dbd_sqlite.c

@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ * Copyright (C) 2014 Vivocha S.p.A.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "../mainrelay.h"
+#include "dbd_sqlite.h"
+
+#include <sqlite3.h>
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+
+static int donot_print_connection_success = 0;
+
+static PGconn *get_pqdb_connection(void) {
+	persistent_users_db_t *pud = get_persistent_users_db();
+
+	PGconn *pqdbconnection = (PGconn*)(pud->connection);
+	if(pqdbconnection) {
+		ConnStatusType status = PQstatus(pqdbconnection);
+		if(status != CONNECTION_OK) {
+			PQfinish(pqdbconnection);
+			pqdbconnection = NULL;
+		}
+	}
+	if(!pqdbconnection) {
+		char *errmsg=NULL;
+		PQconninfoOption *co = PQconninfoParse(pud->userdb, &errmsg);
+		if(!co) {
+			if(errmsg) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection <%s>, connection string format error: %s\n",pud->userdb,errmsg);
+				turn_free(errmsg,strlen(errmsg)+1);
+			} else {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, unknown connection string format error\n",pud->userdb);
+			}
+		} else {
+			PQconninfoFree(co);
+			if(errmsg)
+				turn_free(errmsg,strlen(errmsg)+1);
+			pqdbconnection = PQconnectdb(pud->userdb);
+			if(!pqdbconnection) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, runtime error\n",pud->userdb);
+			} else {
+				ConnStatusType status = PQstatus(pqdbconnection);
+				if(status != CONNECTION_OK) {
+					PQfinish(pqdbconnection);
+					pqdbconnection = NULL;
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, runtime error\n",pud->userdb);
+				} else if(!donot_print_connection_success){
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "PostgreSQL DB connection success: %s\n",pud->userdb);
+				}
+			}
+		}
+		pud->connection = pqdbconnection;
+	}
+	return pqdbconnection;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static int pgsql_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
+  int ret = -1;
+	PGconn * pqc = get_pqdb_connection();
+	if(pqc) {
+		char statement[TURN_LONG_STRING_SIZE];
+		snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
+		PGresult *res = PQexec(pqc, statement);
+
+		if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
+		} else {
+			int i = 0;
+			for(i=0;i<PQntuples(res);i++) {
+				char *kval = PQgetvalue(res,i,0);
+				if(kval) {
+					add_to_secrets_list(sl,kval);
+				}
+			}
+			ret = 0;
+		}
+
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
+  int ret = -1;
+	PGconn * pqc = get_pqdb_connection();
+	if(pqc) {
+		char statement[TURN_LONG_STRING_SIZE];
+		snprintf(statement,sizeof(statement),"select hmackey from turnusers_lt where name='%s' and realm='%s'",usname,realm);
+		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 {
+			char *kval = PQgetvalue(res,0,0);
+			int len = PQgetlength(res,0,0);
+			if(kval) {
+				size_t sz = get_hmackey_size(turn_params.shatype);
+				if(((size_t)len<sz*2)||(strlen(kval)<sz*2)) {
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key format: %s, user %s\n",kval,usname);
+				} else if(convert_string_key_to_binary(kval, key, sz)<0) {
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key: %s, user %s\n",kval,usname);
+				} else {
+					ret = 0;
+				}
+			} else {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong hmackey data for user %s: NULL\n",usname);
+			}
+		}
+
+		if(res)
+			PQclear(res);
+
+	}
+  return ret;
+}
+  
+static int pgsql_get_user_pwd(u08bits *usname, st_password_t pwd) {
+  int ret = -1;
+	char statement[TURN_LONG_STRING_SIZE];
+	snprintf(statement,sizeof(statement),"select password from turnusers_st where name='%s'",usname);
+
+	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 {
+			char *kval = PQgetvalue(res,0,0);
+			if(kval) {
+				strncpy((char*)pwd,kval,sizeof(st_password_t));
+				ret = 0;
+			} else {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong password data for user %s: NULL\n",usname);
+			}
+		}
+
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+
+static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
+
+	int ret = -1;
+
+	char statement[TURN_LONG_STRING_SIZE];
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key from oauth_key where kid='%s'",(const char*)kid);
+
+	PGconn * pqc = get_pqdb_connection();
+	if(pqc) {
+		PGresult *res = PQexec(pqc, statement);
+
+		if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res)!=1)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
+		} else {
+			STRCPY((char*)key->ikm_key,PQgetvalue(res,0,0));
+			key->timestamp = (u64bits)strtoll(PQgetvalue(res,0,1),NULL,10);
+			key->lifetime = (u32bits)strtol(PQgetvalue(res,0,2),NULL,10);
+			STRCPY((char*)key->hkdf_hash_func,PQgetvalue(res,0,3));
+			STRCPY((char*)key->as_rs_alg,PQgetvalue(res,0,4));
+			STRCPY((char*)key->as_rs_key,PQgetvalue(res,0,5));
+			STRCPY((char*)key->auth_alg,PQgetvalue(res,0,6));
+			STRCPY((char*)key->auth_key,PQgetvalue(res,0,7));
+			STRCPY((char*)key->kid,kid);
+			ret = 0;
+		}
+
+		if(res) {
+			PQclear(res);
+		}
+	}
+
+	return ret;
+}
+
+static int pgsql_list_oauth_keys(void) {
+
+	oauth_key_data_raw key_;
+	oauth_key_data_raw *key=&key_;
+
+	int ret = -1;
+
+	char statement[TURN_LONG_STRING_SIZE];
+	snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key,kid from oauth_key order by kid");
+
+	PGconn * pqc = get_pqdb_connection();
+	if(pqc) {
+		PGresult *res = PQexec(pqc, statement);
+
+		if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
+		} else {
+			int i = 0;
+			for(i=0;i<PQntuples(res);i++) {
+
+				STRCPY((char*)key->ikm_key,PQgetvalue(res,i,0));
+				key->timestamp = (u64bits)strtoll(PQgetvalue(res,i,1),NULL,10);
+				key->lifetime = (u32bits)strtol(PQgetvalue(res,i,2),NULL,10);
+				STRCPY((char*)key->hkdf_hash_func,PQgetvalue(res,i,3));
+				STRCPY((char*)key->as_rs_alg,PQgetvalue(res,i,4));
+				STRCPY((char*)key->as_rs_key,PQgetvalue(res,i,5));
+				STRCPY((char*)key->auth_alg,PQgetvalue(res,i,6));
+				STRCPY((char*)key->auth_key,PQgetvalue(res,i,7));
+				STRCPY((char*)key->kid,PQgetvalue(res,i,8));
+
+				printf("  kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n",
+						key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func,
+						key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key);
+
+				ret = 0;
+			}
+		}
+
+		if(res) {
+			PQclear(res);
+		}
+	}
+
+	return ret;
+}
+  
+static int pgsql_set_user_key(u08bits *usname, u08bits *realm, const char *key) {
+  int ret = -1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+	  snprintf(statement,sizeof(statement),"insert into turnusers_lt (realm,name,hmackey) values('%s','%s','%s')",realm,usname,key);
+
+		PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+			if(res) {
+				PQclear(res);
+			}
+		  snprintf(statement,sizeof(statement),"update turnusers_lt set hmackey='%s' where name='%s' and realm='%s'",key,usname,realm);
+			res = PQexec(pqc, statement);
+			if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating user information: %s\n",PQerrorMessage(pqc));
+			} else {
+			  ret = 0;
+			}
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  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;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+	  snprintf(statement,sizeof(statement),"insert into turnusers_st values('%s','%s')",usname,pwd);
+    PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+			if(res) {
+				PQclear(res);
+			}
+		  snprintf(statement,sizeof(statement),"update turnusers_st set password='%s' where name='%s'",pwd,usname);
+			res = PQexec(pqc, statement);
+			if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating user information: %s\n",PQerrorMessage(pqc));
+			} else {
+			  ret = 0;
+			}
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_del_user(u08bits *usname, int is_st, u08bits *realm) {
+  int ret = -1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		if(is_st) {
+		  snprintf(statement,sizeof(statement),"delete from turnusers_st where name='%s'",usname);
+		} else {
+		  snprintf(statement,sizeof(statement),"delete from turnusers_lt where name='%s' and realm='%s'",usname,realm);
+		}
+		PGresult *res = PQexec(pqc, statement);
+		if(res) {
+			PQclear(res);
+      ret = 0;
+		}
+	}
+  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;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		if(is_st) {
+		  snprintf(statement,sizeof(statement),"select name,'' from turnusers_st order by name");
+		} else if(realm && realm[0]) {
+		  snprintf(statement,sizeof(statement),"select name,realm from turnusers_lt where realm='%s' order by name",realm);
+		} else {
+		  snprintf(statement,sizeof(statement),"select name,realm from turnusers_lt order by name");
+		}
+		PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
+		} else {
+			int i = 0;
+			for(i=0;i<PQntuples(res);i++) {
+				char *kval = PQgetvalue(res,i,0);
+				if(kval) {
+					char *rval = PQgetvalue(res,i,1);
+					if(rval && *rval) {
+						printf("%s[%s]\n",kval,rval);
+					} else {
+						printf("%s\n",kval);
+					}
+				}
+			}
+			ret = 0;
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_show_secret(u08bits *realm) {
+  int ret = -1;
+	char statement[TURN_LONG_STRING_SIZE];
+	snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
+
+	donot_print_connection_success=1;
+
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
+		} else {
+			int i = 0;
+			for(i=0;i<PQntuples(res);i++) {
+				char *kval = PQgetvalue(res,i,0);
+				if(kval) {
+					printf("%s\n",kval);
+				}
+			}
+      ret = 0;
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_del_secret(u08bits *secret, u08bits *realm) {
+  int ret = -1;
+	donot_print_connection_success=1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if (pqc) {
+		if(!secret || (secret[0]==0))
+		  snprintf(statement,sizeof(statement),"delete from turn_secret where realm='%s'",realm);
+		else
+		  snprintf(statement,sizeof(statement),"delete from turn_secret where value='%s' and realm='%s'",secret,realm);
+
+		PGresult *res = PQexec(pqc, statement);
+		if (res) {
+			PQclear(res);
+      ret = 0;
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_set_secret(u08bits *secret, u08bits *realm) {
+  int ret = -1;
+	donot_print_connection_success = 1;
+  char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if (pqc) {
+	  snprintf(statement,sizeof(statement),"insert into turn_secret (realm,value) values('%s','%s')",realm,secret);
+	  PGresult *res = PQexec(pqc, statement);
+	  if (!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+	    TURN_LOG_FUNC(
+			  TURN_LOG_LEVEL_ERROR,
+			  "Error inserting/updating secret key information: %s\n",
+			  PQerrorMessage(pqc));
+	  } else {
+	    ret = 0;
+	  }
+	  if (res) {
+	    PQclear(res);
+	  }
+	}
+
+  return ret;
+}
+  
+static int pgsql_add_origin(u08bits *origin, u08bits *realm) {
+  int ret = -1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		snprintf(statement,sizeof(statement),"insert into turn_origin_to_realm (origin,realm) values('%s','%s')",origin,realm);
+		PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting origin information: %s\n",PQerrorMessage(pqc));
+		} else {
+		  ret = 0;
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_del_origin(u08bits *origin) {
+  int ret = -1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		snprintf(statement,sizeof(statement),"delete from turn_origin_to_realm where origin='%s'",origin);
+		PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting origin information: %s\n",PQerrorMessage(pqc));
+		} else {
+		  ret = 0;
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_list_origins(u08bits *realm) {
+  int ret = -1;
+	donot_print_connection_success = 1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		if(realm && realm[0]) {
+		  snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm where realm='%s' order by origin",realm);
+		} else {
+		  snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm order by origin,realm");
+		}
+		PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
+		} else {
+			int i = 0;
+			for(i=0;i<PQntuples(res);i++) {
+				char *oval = PQgetvalue(res,i,0);
+				if(oval) {
+					char *rval = PQgetvalue(res,i,1);
+					if(rval) {
+						printf("%s ==>> %s\n",oval,rval);
+					}
+				}
+			}
+      ret = 0;
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_set_realm_option_one(u08bits *realm, unsigned long value, const char* opt) {
+  int ret = -1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		{
+			snprintf(statement,sizeof(statement),"delete from turn_realm_option where realm='%s' and opt='%s'",realm,opt);
+			PGresult *res = PQexec(pqc, statement);
+			if(res) {
+				PQclear(res);
+			}
+		}
+		if(value>0) {
+			snprintf(statement,sizeof(statement),"insert into turn_realm_option (realm,opt,value) values('%s','%s','%lu')",realm,opt,(unsigned long)value);
+			PGresult *res = PQexec(pqc, statement);
+			if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting realm option information: %s\n",PQerrorMessage(pqc));
+			} else {
+			  ret = 0;
+			}
+			if(res) {
+				PQclear(res);
+			}
+		}
+	}
+  return ret;
+}
+  
+static int pgsql_list_realm_options(u08bits *realm) {
+  int ret = -1;
+	donot_print_connection_success = 1;
+	char statement[TURN_LONG_STRING_SIZE];
+	PGconn *pqc = get_pqdb_connection();
+	if(pqc) {
+		if(realm && realm[0]) {
+			snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option where realm='%s' order by realm,opt",realm);
+		} else {
+			snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option order by realm,opt");
+		}
+		PGresult *res = PQexec(pqc, statement);
+		if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
+		} else {
+			int i = 0;
+			for(i=0;i<PQntuples(res);i++) {
+				char *rval = PQgetvalue(res,i,0);
+				if(rval) {
+					char *oval = PQgetvalue(res,i,1);
+					if(oval) {
+						char *vval = PQgetvalue(res,i,2);
+						if(vval) {
+							printf("%s[%s]=%s\n",oval,rval,vval);
+						}
+					}
+				}
+			}
+      ret = 0;
+		}
+		if(res) {
+			PQclear(res);
+		}
+	}
+  return ret;
+}
+  
+static void pgsql_auth_ping(void * rch) {
+	UNUSED_ARG(rch);
+	donot_print_connection_success = 1;
+	PGconn * pqc = get_pqdb_connection();
+	if(pqc) {
+		char statement[TURN_LONG_STRING_SIZE];
+		STRCPY(statement,"select value from turn_secret");
+		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));
+		}
+
+		if(res) {
+			PQclear(res);
+		}
+	}
+}
+  
+
+static int pgsql_get_ip_list(const char *kind, ip_range_list_t * list)
+{
+	int ret = -1;
+	PGconn * pqc = get_pqdb_connection();
+	if (pqc) {
+		char statement[TURN_LONG_STRING_SIZE];
+		snprintf(statement, sizeof(statement), "select ip_range,realm from %s_peer_ip", kind);
+		PGresult *res = PQexec(pqc, statement);
+
+		if (!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
+			static int wrong_table_reported = 0;
+			if(!wrong_table_reported) {
+				wrong_table_reported = 1;
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s; probably, the tables 'allowed_peer_ip' and/or 'denied_peer_ip' have to be upgraded to include the realm column.\n",PQerrorMessage(pqc));
+			}
+			snprintf(statement, sizeof(statement), "select ip_range,'' from %s_peer_ip", kind);
+			res = PQexec(pqc, statement);
+		}
+
+		if (res && (PQresultStatus(res) == PGRES_TUPLES_OK)) {
+			int i = 0;
+			for (i = 0; i < PQntuples(res); i++) {
+				char *kval = PQgetvalue(res, i, 0);
+				char *rval = PQgetvalue(res, i, 1);
+				if (kval) {
+					add_ip_list_range(kval, rval, list);
+				}
+			}
+			ret = 0;
+		}
+
+		if (res) {
+			PQclear(res);
+		}
+	}
+	return ret;
+}
+  
+static void pgsql_reread_realms(secrets_list_t * realms_list) {
+	PGconn * pqc = get_pqdb_connection();
+	if(pqc) {
+		char statement[TURN_LONG_STRING_SIZE];
+
+		{
+			snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm");
+			PGresult *res = PQexec(pqc, statement);
+
+			if(res && (PQresultStatus(res) == PGRES_TUPLES_OK)) {
+
+				ur_string_map *o_to_realm_new = ur_string_map_create(turn_free_simple);
+
+				int i = 0;
+				for(i=0;i<PQntuples(res);i++) {
+					char *oval = PQgetvalue(res,i,0);
+					if(oval) {
+						char *rval = PQgetvalue(res,i,1);
+						if(rval) {
+							get_realm(rval);
+							ur_string_map_value_type value = turn_strdup(rval);
+							ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type) oval, value);
+						}
+					}
+				}
+
+        update_o_to_realm(o_to_realm_new);
+			}
+
+			if(res) {
+				PQclear(res);
+			}
+		}
+
+		{
+			{
+				size_t i = 0;
+				size_t rlsz = 0;
+
+				lock_realms();
+				rlsz = realms_list->sz;
+				unlock_realms();
+
+				for (i = 0; i<rlsz; ++i) {
+
+					char *realm = realms_list->secrets[i];
+
+					realm_params_t* rp = get_realm(realm);
+
+					lock_realms();
+					rp->options.perf_options.max_bps = turn_params.max_bps;
+					unlock_realms();
+
+					lock_realms();
+					rp->options.perf_options.total_quota = turn_params.total_quota;
+					unlock_realms();
+
+					lock_realms();
+					rp->options.perf_options.user_quota = turn_params.user_quota;
+					unlock_realms();
+
+				}
+			}
+
+			snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option");
+			PGresult *res = PQexec(pqc, statement);
+
+			if(res && (PQresultStatus(res) == PGRES_TUPLES_OK)) {
+
+				int i = 0;
+				for(i=0;i<PQntuples(res);i++) {
+					char *rval = PQgetvalue(res,i,0);
+					char *oval = PQgetvalue(res,i,1);
+					char *vval = PQgetvalue(res,i,2);
+					if(rval && oval && vval) {
+						realm_params_t* rp = get_realm(rval);
+						if(!strcmp(oval,"max-bps"))
+							rp->options.perf_options.max_bps = (band_limit_t)atol(vval);
+						else if(!strcmp(oval,"total-quota"))
+							rp->options.perf_options.total_quota = (vint)atoi(vval);
+						else if(!strcmp(oval,"user-quota"))
+							rp->options.perf_options.user_quota = (vint)atoi(vval);
+						else {
+							TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown realm option: %s\n", oval);
+						}
+					}
+				}
+			}
+
+			if(res) {
+				PQclear(res);
+			}
+		}
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static turn_dbdriver_t driver = {
+  &pgsql_get_auth_secrets,
+  &pgsql_get_user_key,
+  &pgsql_get_user_pwd,
+  &pgsql_set_user_key,
+  &pgsql_set_user_pwd,
+  &pgsql_del_user,
+  &pgsql_list_users,
+  &pgsql_show_secret,
+  &pgsql_del_secret,
+  &pgsql_set_secret,
+  &pgsql_add_origin,
+  &pgsql_del_origin,
+  &pgsql_list_origins,
+  &pgsql_set_realm_option_one,
+  &pgsql_list_realm_options,
+  &pgsql_auth_ping,
+  &pgsql_get_ip_list,
+  &pgsql_reread_realms,
+  &pgsql_set_oauth_key,
+  &pgsql_get_oauth_key,
+  &pgsql_del_oauth_key,
+  &pgsql_list_oauth_keys
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#endif
+
+turn_dbdriver_t * get_sqlite_dbdriver(void) {
+	//TODO
+  return NULL;
+}

+ 49 - 0
src/apps/relay/dbdrivers/dbd_sqlite.h

@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ * Copyright (C) 2014 Vivocha S.p.A.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __DBD_SQLITE__
+#define __DBD_SQLITE__
+
+#include "dbdriver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+turn_dbdriver_t * get_sqlite_dbdriver(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/// __DBD_SQLITE__///
+

+ 4 - 0
src/apps/relay/dbdrivers/dbdriver.c

@@ -34,6 +34,7 @@
 #include "apputils.h"
 
 #include "dbdriver.h"
+#include "dbd_sqlite.h"
 #include "dbd_pgsql.h"
 #include "dbd_mysql.h"
 #include "dbd_mongo.h"
@@ -62,6 +63,9 @@ persistent_users_db_t * get_persistent_users_db(void) {
 turn_dbdriver_t * get_dbdriver() {
   if (!_driver) {
     switch(turn_params.default_users_db.userdb_type) {
+    case TURN_USERDB_TYPE_SQLITE:
+    	_driver = get_sqlite_dbdriver();
+    	break;
 #if !defined(TURN_NO_PQ)
     case TURN_USERDB_TYPE_PQ:
       _driver = get_pgsql_dbdriver();

+ 18 - 33
src/apps/relay/mainrelay.c

@@ -95,7 +95,7 @@ LOW_DEFAULT_PORTS_BOUNDARY,HIGH_DEFAULT_PORTS_BOUNDARY,0,0,0,"",
 /////////////// MISC PARAMS ////////////////
 0,0,0,0,0,SHATYPE_SHA1,':',0,0,TURN_CREDENTIALS_NONE,0,0,0,0,0,0,
 ///////////// Users DB //////////////
-{ TURN_USERDB_TYPE_FILE, {"\0",NULL}, {0,NULL,NULL, {NULL,0}} }
+{ TURN_USERDB_TYPE_SQLITE, {"\0",NULL}, {0,NULL,NULL, {NULL,0}} }
 
 };
 
@@ -386,17 +386,14 @@ static char Usage[] = "Usage: turnserver [options]\n"
 " -V, --Verbose					Extra verbose mode, very annoying (for debug purposes only).\n"
 " -o, --daemon					Start process as daemon (detach from current shell).\n"
 " -f, --fingerprint				Use fingerprints in the TURN messages.\n"
-" -a, --lt-cred-mech				Use the long-term credential mechanism. This option can be used with either\n"
-"		                                flat file user database or PostgreSQL DB or MySQL DB for user keys storage.\n"
-" -A, --st-cred-mech				Use the short-term credential mechanism. This option requires\n"
-"		                                a PostgreSQL or MySQL DB for short term passwords storage.\n"
+" -a, --lt-cred-mech				Use the long-term credential mechanism.\n"
+" -A, --st-cred-mech				Use the short-term credential mechanism.\n"
 " -z, --no-auth					Do not use any credential mechanism, allow anonymous access.\n"
 " -u, --user			<user:pwd>	User account, in form 'username:password', for long-term credentials.\n"
 "						Cannot be used with TURN REST API or with short-term credentials.\n"
 " -r, --realm			<realm>		The default realm to be used for the users when no explicit\n"
-"						origin/realm relationship was found in the database, or if the TURN\n"
-"						server is not using any database (just the commands-line settings\n"
-"						and the userdb file). Must be used with long-term credentials \n"
+"						origin/realm relationship was found in the database.\n"
+"						Must be used with long-term credentials \n"
 "						mechanism or with TURN REST API.\n"
 " --check-origin-consistency			The flag that sets the origin consistency check:\n"
 "						across the session, all requests must have the same\n"
@@ -415,7 +412,7 @@ static char Usage[] = "Usage: turnserver [options]\n"
 "						Total bytes-per-second bandwidth the TURN server is allowed to allocate\n"
 "						for the sessions, combined (input and output network streams are treated separately).\n"
 " -c				<filename>	Configuration file name (default - turnserver.conf).\n"
-" -b, --userdb			<filename>	User database file name (default - turnuserdb.conf) for long-term credentials only.\n"
+" -b, , --db, --userdb	<filename>		SQLite database file name (default - "DEFAULT_USERDB_FILE").\n"
 #if !defined(TURN_NO_PQ)
 " -e, --psql-userdb, --sql-userdb <conn-string>	PostgreSQL database connection string, if used (default - empty, no PostreSQL DB used).\n"
 "		                                This database can be used for long-term and short-term credentials mechanisms,\n"
@@ -569,7 +566,7 @@ static char Usage[] = "Usage: turnserver [options]\n"
 "\n";
 
 static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
-	"Commands:\n"
+	"\nCommands:\n\n"
 	"	-k, --key			generate long-term credential mechanism key for a user\n"
 	"	-a, --add			add/update a long-term mechanism user\n"
 	"	-A, --add-st			add/update a short-term mechanism user\n"
@@ -577,7 +574,6 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
 	"	-D, --delete-st			delete a short-term mechanism user\n"
 	"	-l, --list			list all long-term mechanism users\n"
 	"	-L, --list-st			list all short-term mechanism users\n"
-#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
 	"	-s, --set-secret=<value>	Add shared secret for TURN RESP API\n"
 	"	-S, --show-secret		Show stored shared secrets for TURN REST API\n"
 	"	-X, --delete-secret=<value>	Delete a shared secret\n"
@@ -587,9 +583,8 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
 	"	-I, --list-origins		List origin-to-realm relations.\n"
 	"	-g, --set-realm-option		Set realm params: max-bps, total-quota, user-quota.\n"
 	"	-G, --list-realm-options	List realm params.\n"
-#endif
-	"Options with mandatory values:\n"
-	"	-b, --userdb			User database file, if flat DB file is used.\n"
+	"\nOptions with mandatory values:\n\n"
+	"	-b, --db, --userdb		SQLite database file, default value is "DEFAULT_USERDB_FILE".\n"
 #if !defined(TURN_NO_PQ)
 	"	-e, --psql-userdb, --sql-userdb	PostgreSQL user database connection string, if PostgreSQL DB is used.\n"
 #endif
@@ -720,6 +715,7 @@ static const struct myoption long_options[] = {
 				{ "no-auth", optional_argument, NULL, 'z' },
 				{ "user", required_argument, NULL, 'u' },
 				{ "userdb", required_argument, NULL, 'b' },
+				{ "db", required_argument, NULL, 'b' },
 #if !defined(TURN_NO_PQ)
 				{ "psql-userdb", required_argument, NULL, 'e' },
 				{ "sql-userdb", required_argument, NULL, 'e' },
@@ -808,15 +804,14 @@ static const struct myoption admin_long_options[] = {
 				{ "delete", no_argument, NULL, 'd' },
 				{ "list", no_argument, NULL, 'l' },
 				{ "list-st", no_argument, NULL, 'L' },
-#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
 				{ "set-secret", required_argument, NULL, 's' },
 				{ "show-secret", no_argument, NULL, 'S' },
 				{ "delete-secret", required_argument, NULL, 'X' },
 				{ "delete-all-secrets", no_argument, NULL, DEL_ALL_AUTH_SECRETS_OPT },
-#endif
 				{ "add-st", no_argument, NULL, 'A' },
 				{ "delete-st", no_argument, NULL, 'D' },
 				{ "userdb", required_argument, NULL, 'b' },
+				{ "db", required_argument, NULL, 'b' },
 #if !defined(TURN_NO_PQ)
 				{ "psql-userdb", required_argument, NULL, 'e' },
 				{ "sql-userdb", required_argument, NULL, 'e' },
@@ -834,7 +829,6 @@ static const struct myoption admin_long_options[] = {
 				{ "realm", required_argument, NULL, 'r' },
 				{ "password", required_argument, NULL, 'p' },
 				{ "sha256", no_argument, NULL, 'H' },
-#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
 				{ "add-origin", no_argument, NULL, 'O' },
 				{ "del-origin", no_argument, NULL, 'R' },
 				{ "list-origins", required_argument, NULL, 'I' },
@@ -844,7 +838,6 @@ static const struct myoption admin_long_options[] = {
 				{ "user-quota", required_argument, NULL, ADMIN_USER_QUOTA_OPT },
 				{ "total-quota", required_argument, NULL, ADMIN_TOTAL_QUOTA_OPT },
 				{ "max-bps", required_argument, NULL, ADMIN_MAX_BPS_OPT },
-#endif
 				{ "help", no_argument, NULL, 'h' },
 				{ NULL, no_argument, NULL, 0 }
 };
@@ -1113,7 +1106,7 @@ static void set_option(int c, char *value)
 		break;
 	case 'b':
 		STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
-		turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_FILE;
+		turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_SQLITE;
 		break;
 #if !defined(TURN_NO_PQ)
 	case 'e':
@@ -1461,7 +1454,6 @@ static int adminmain(int argc, char **argv)
 			ct = TA_LIST_USERS;
 			is_st = 1;
 			break;
-#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
 		case 's':
 			ct = TA_SET_SECRET;
 			STRCPY(secret,optarg);
@@ -1477,10 +1469,9 @@ static int adminmain(int argc, char **argv)
 		case DEL_ALL_AUTH_SECRETS_OPT:
 			ct = TA_DEL_SECRET;
 			break;
-#endif
 		case 'b':
 		  STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
-		  turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_FILE;
+		  turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_SQLITE;
 		  break;
 #if !defined(TURN_NO_PQ)
 		case 'e':
@@ -1544,12 +1535,7 @@ static int adminmain(int argc, char **argv)
 		}
 	}
 
-	if(is_st && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_FILE)) {
-		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "ERROR: you have to use a PostgreSQL or MySQL database with short-term credentials\n");
-		exit(-1);
-	}
-
-	if(!strlen(turn_params.default_users_db.persistent_users_db.userdb) && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_FILE))
+	if(!strlen(turn_params.default_users_db.persistent_users_db.userdb) && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_SQLITE))
 		STRCPY(turn_params.default_users_db.persistent_users_db.userdb,DEFAULT_USERDB_FILE);
 
 	if(ct == TA_COMMAND_UNKNOWN) {
@@ -1601,6 +1587,8 @@ static void print_features(unsigned long mfn)
 	TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "AEAD supported\n");
 #endif
 
+	TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "SQLite supported\n");
+
 #if !defined(TURN_NO_HIREDIS)
 	TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Redis supported\n");
 #else
@@ -1851,10 +1839,9 @@ int main(int argc, char **argv)
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "\nCONFIG: WARNING: --server-relay: NON-STANDARD AND DANGEROUS OPTION.\n");
 	}
 
-	if(!strlen(turn_params.default_users_db.persistent_users_db.userdb) && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_FILE))
+	if(!strlen(turn_params.default_users_db.persistent_users_db.userdb) && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_SQLITE))
 			STRCPY(turn_params.default_users_db.persistent_users_db.userdb,DEFAULT_USERDB_FILE);
 
-	read_userdb_file(0);
 	update_white_and_black_lists();
 
 	argc -= optind;
@@ -1891,9 +1878,7 @@ int main(int argc, char **argv)
 	}
 
 	if(use_lt_credentials) {
-		if(!turn_params.default_users_db.ram_db.users_number && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_FILE) && !turn_params.use_auth_secret_with_timestamp) {
-			TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "\nCONFIGURATION ALERT: you did not specify any user account, (-u option) \n	but you did specified a long-term credentials mechanism option (-a option).\n	The TURN Server will be inaccessible.\n		Check your configuration.\n");
-		} else if(!get_realm(NULL)->options.name[0]) {
+		if(!get_realm(NULL)->options.name[0]) {
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "\nCONFIGURATION ALERT: you did specify the long-term credentials usage\n but you did not specify the default realm option (-r option).\n		Check your configuration.\n");
 		}
 	}

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

@@ -1696,7 +1696,6 @@ static void* run_auth_server_thread(void *arg)
 	while(run_auth_server_flag) {
 		reread_realms();
 		run_events(eb,NULL);
-		read_userdb_file(0);
 		update_white_and_black_lists();
 		auth_ping(authserver->rch);
 #if defined(DB_TEST)

+ 2 - 2
src/apps/relay/turncli.c

@@ -781,8 +781,8 @@ static void cli_print_configuration(struct cli_session* cs)
 
 		if(turn_params.default_users_db.persistent_users_db.userdb[0]) {
 			switch(turn_params.default_users_db.userdb_type) {
-			case TURN_USERDB_TYPE_FILE:
-				cli_print_str(cs,"file","DB type",0);
+			case TURN_USERDB_TYPE_SQLITE:
+				cli_print_str(cs,"SQLite","DB type",0);
 				break;
 #if !defined(TURN_NO_PQ)
 			case TURN_USERDB_TYPE_PQ:

+ 43 - 232
src/apps/relay/userdb.c

@@ -736,83 +736,6 @@ void release_allocation_quota(u08bits *user, int oauth, u08bits *realm)
 
 //////////////////////////////////
 
-void read_userdb_file(int to_print)
-{
-	static char *full_path_to_userdb_file = NULL;
-	static int first_read = 1;
-	static turn_time_t mtime = 0;
-
-	if(turn_params.default_users_db.userdb_type != TURN_USERDB_TYPE_FILE)
-		return;
-	if(turn_params.use_auth_secret_with_timestamp)
-		return;
-
-	FILE *f = NULL;
-
-	persistent_users_db_t *pud = get_persistent_users_db();
-
-	if(full_path_to_userdb_file) {
-		struct stat sb;
-		if(stat(full_path_to_userdb_file,&sb)<0) {
-			perror("File statistics");
-		} else {
-			turn_time_t newmtime = (turn_time_t)(sb.st_mtime);
-			if(mtime == newmtime)
-				return;
-			mtime = newmtime;
-
-		}
-	}
-
-	if (!full_path_to_userdb_file)
-		full_path_to_userdb_file = find_config_file(pud->userdb, first_read);
-
-	if (full_path_to_userdb_file)
-		f = fopen(full_path_to_userdb_file, "r");
-
-	if (f) {
-
-		char sbuf[TURN_LONG_STRING_SIZE];
-
-		ur_string_map_lock(turn_params.default_users_db.ram_db.dynamic_accounts);
-
-		ur_string_map_clean(turn_params.default_users_db.ram_db.dynamic_accounts);
-
-		for (;;) {
-			char *s = fgets(sbuf, sizeof(sbuf) - 1, f);
-			if (!s)
-				break;
-			s = skip_blanks(s);
-			if (s[0] == '#')
-				continue;
-			if (!s[0])
-				continue;
-			size_t slen = strlen(s);
-			while (slen && (s[slen - 1] == 10 || s[slen - 1] == 13))
-				s[--slen] = 0;
-			if (slen) {
-				if(to_print) {
-					char* sc=strstr(s,":");
-					if(sc)
-						sc[0]=0;
-					printf("%s\n",s);
-				} else {
-					add_user_account(s,1);
-				}
-			}
-		}
-
-		ur_string_map_unlock(turn_params.default_users_db.ram_db.dynamic_accounts);
-
-		fclose(f);
-
-	} else if (first_read) {
-	  TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: Cannot find userdb file: %s: going without flat file user database.\n", pud->userdb);
-	} 
-
-	first_read = 0;
-}
-
 int add_user_account(char *user, int dynamic)
 {
 	/* Realm is either default or empty for users taken from file or command-line */
@@ -872,11 +795,9 @@ static int list_users(int is_st, u08bits *realm)
   turn_dbdriver_t * dbd = get_dbdriver();
   if (dbd && dbd->list_users) {
     (*dbd->list_users)(is_st, realm);
-	} else if(!is_st) {
-		read_userdb_file(1);
-	}
+  }
 
-	return 0;
+  return 0;
 }
 
 static int show_secret(u08bits *realm)
@@ -989,217 +910,107 @@ static int list_realm_options(u08bits *realm)
 	return 0;
 }
 
-int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08bits *origin,
-				TURNADMIN_COMMAND_TYPE ct, int is_st,
-				perf_options_t *po) {
+int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08bits *origin, TURNADMIN_COMMAND_TYPE ct, int is_st, perf_options_t *po)
+{
 	hmackey_t key;
-	char skey[sizeof(hmackey_t)*2+1];
+	char skey[sizeof(hmackey_t) * 2 + 1];
 
 	st_password_t passwd;
 
-	if(ct == TA_LIST_USERS) {
+	if (ct == TA_LIST_USERS) {
 		return list_users(is_st, realm);
 	}
 
-	if(ct == TA_LIST_ORIGINS) {
+	if (ct == TA_LIST_ORIGINS) {
 		return list_origins(realm);
 	}
 
-	if(ct == TA_SHOW_SECRET) {
+	if (ct == TA_SHOW_SECRET) {
 		return show_secret(realm);
 	}
 
-	if(ct == TA_SET_SECRET) {
+	if (ct == TA_SET_SECRET) {
 		return set_secret(secret, realm);
 	}
 
-	if(ct == TA_DEL_SECRET) {
+	if (ct == TA_DEL_SECRET) {
 		return del_secret(secret, realm);
 	}
 
-	if(ct == TA_ADD_ORIGIN) {
+	if (ct == TA_ADD_ORIGIN) {
 		must_set_admin_origin(origin);
 		must_set_admin_realm(realm);
-		return add_origin(origin,realm);
+		return add_origin(origin, realm);
 	}
 
-	if(ct == TA_DEL_ORIGIN) {
+	if (ct == TA_DEL_ORIGIN) {
 		must_set_admin_origin(origin);
 		return del_origin(origin);
 	}
 
-	if(ct == TA_SET_REALM_OPTION) {
+	if (ct == TA_SET_REALM_OPTION) {
 		must_set_admin_realm(realm);
-		if(!(po && (po->max_bps!=((band_limit_t)-1) || po->total_quota>=0 || po->user_quota>=0))) {
+		if (!(po && (po->max_bps != ((band_limit_t) -1) || po->total_quota >= 0 || po->user_quota >= 0))) {
 			fprintf(stderr, "The operation cannot be completed: a realm option must be set.\n");
 			exit(-1);
 		}
-		return set_realm_option(realm,po);
+		return set_realm_option(realm, po);
 	}
 
-	if(ct == TA_LIST_REALM_OPTIONS) {
+	if (ct == TA_LIST_REALM_OPTIONS) {
 		return list_realm_options(realm);
 	}
 
 	must_set_admin_user(user);
 
-	if(ct != TA_DELETE_USER) {
+	if (ct != TA_DELETE_USER) {
 
 		must_set_admin_pwd(pwd);
 
-		if(is_st) {
-			strncpy((char*)passwd,(char*)pwd,sizeof(st_password_t));
+		if (is_st) {
+			strncpy((char*) passwd, (char*) pwd, sizeof(st_password_t));
 		} else {
 			stun_produce_integrity_key_str(user, realm, pwd, key, turn_params.shatype);
 			size_t i = 0;
 			size_t sz = get_hmackey_size(turn_params.shatype);
-			int maxsz = (int)(sz*2)+1;
-			char *s=skey;
-			for(i=0;(i<sz) && (maxsz>2);i++) {
-			  snprintf(s,(size_t)(sz*2),"%02x",(unsigned int)key[i]);
-			  maxsz-=2;
-			  s+=2;
+			int maxsz = (int) (sz * 2) + 1;
+			char *s = skey;
+			for (i = 0; (i < sz) && (maxsz > 2); i++) {
+				snprintf(s, (size_t) (sz * 2), "%02x", (unsigned int) key[i]);
+				maxsz -= 2;
+				s += 2;
 			}
-			skey[sz*2]=0;
+			skey[sz * 2] = 0;
 		}
 	}
 
-  turn_dbdriver_t * dbd = get_dbdriver();
+	turn_dbdriver_t * dbd = get_dbdriver();
 
-	if(ct == TA_PRINT_KEY) {
+	if (ct == TA_PRINT_KEY) {
 
-		if(!is_st) {
-			printf("0x%s\n",skey);
+		if (!is_st) {
+			printf("0x%s\n", skey);
 		}
 
-	} else if(dbd) {
+	} else if (dbd) {
 
-		if(!is_st) {
+		if (!is_st) {
 			must_set_admin_realm(realm);
 		}
-    
-    if (ct == TA_DELETE_USER) {
-      if (dbd->del_user) 
-        (*dbd->del_user)(user, is_st, realm);
-    } else if (ct == TA_UPDATE_USER) {
-      if (is_st) {
-        if (dbd->set_user_pwd) 
-          (*dbd->set_user_pwd)(user, passwd);
-      } else {
-        if (dbd->set_user_key) 
-          (*dbd->set_user_key)(user, realm, skey);
-      }
-    }
-    
-	} else if(!is_st) {
-
-		persistent_users_db_t *pud = get_persistent_users_db();
-		char *full_path_to_userdb_file = find_config_file(pud->userdb, 1);
-		FILE *f = full_path_to_userdb_file ? fopen(full_path_to_userdb_file,"r") : NULL;
-		int found = 0;
-		char us[TURN_LONG_STRING_SIZE];
-		size_t i = 0;
-		char **content = NULL;
-		size_t csz = 0;
-
-		STRCPY(us, (char*) user);
-		strncpy(us + strlen(us), ":", sizeof(us)-1-strlen(us));
-		us[sizeof(us)-1]=0;
-
-		if (!f) {
-			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "File %s not found, will be created.\n",pud->userdb);
-		} else {
-
-			char sarg[TURN_LONG_STRING_SIZE];
-			char sbuf[TURN_LONG_STRING_SIZE];
-
-			for (;;) {
-				char *s0 = fgets(sbuf, sizeof(sbuf) - 1, f);
-				if (!s0)
-					break;
-
-				size_t slen = strlen(s0);
-				while (slen && (s0[slen - 1] == 10 || s0[slen - 1] == 13))
-					s0[--slen] = 0;
-
-				char *s = skip_blanks(s0);
-
-				if (s[0] == '#')
-					goto add_and_cont;
-				if (!s[0])
-					goto add_and_cont;
-
-				STRCPY(sarg, s);
-				if (strstr(sarg, us) == sarg) {
-					if (ct == TA_DELETE_USER)
-						continue;
-
-					if (found)
-						continue;
-					found = 1;
-					STRCPY(us, (char*) user);
-					strncpy(us + strlen(us), ":0x", sizeof(us)-1-strlen(us));
-					us[sizeof(us)-1]=0;
-					size_t sz = get_hmackey_size(turn_params.shatype);
-					for (i = 0; i < sz; i++) {
-						snprintf(
-							us + strlen(us),
-							sizeof(us)-strlen(us),
-							"%02x",
-							(unsigned int) key[i]);
-					}
 
-					s0 = us;
-				}
-
-				add_and_cont:
-				content = (char**)turn_realloc(content, 0, sizeof(char*) * (++csz));
-				content[csz - 1] = turn_strdup(s0);
+		if (ct == TA_DELETE_USER) {
+			if (dbd->del_user)
+				(*dbd->del_user)(user, is_st, realm);
+		} else if (ct == TA_UPDATE_USER) {
+			if (is_st) {
+				if (dbd->set_user_pwd)
+					(*dbd->set_user_pwd)(user, passwd);
+			} else {
+				if (dbd->set_user_key)
+					(*dbd->set_user_key)(user, realm, skey);
 			}
-
-			fclose(f);
 		}
 
-		if(!found && (ct == TA_UPDATE_USER)) {
-		  STRCPY(us,(char*)user);
-		  strncpy(us+strlen(us),":0x",sizeof(us)-1-strlen(us));
-		  us[sizeof(us)-1]=0;
-		  size_t sz = get_hmackey_size(turn_params.shatype);
-		  for(i=0;i<sz;i++) {
-		    snprintf(us+strlen(us),sizeof(us)-strlen(us),"%02x",(unsigned int)key[i]);
-		  }
-		  content = (char**)turn_realloc(content,0,sizeof(char*)*(++csz));
-		  content[csz-1]=turn_strdup(us);
-		}
-
-		if(!full_path_to_userdb_file)
-			full_path_to_userdb_file=turn_strdup(pud->userdb);
-
-		size_t dirsz = strlen(full_path_to_userdb_file)+21;
-		char *dir = (char*)turn_malloc(dirsz+1);
-		strncpy(dir,full_path_to_userdb_file,dirsz);
-		dir[dirsz]=0;
-		size_t dlen = strlen(dir);
-		while(dlen) {
-			if(dir[dlen-1]=='/')
-				break;
-			dir[--dlen]=0;
-		}
-		strncpy(dir+strlen(dir),".tmp_userdb",dirsz-strlen(dir));
-
-		f = fopen(dir,"w");
-		if(!f) {
-			perror("file open");
-			exit(-1);
-		}
-
-		for(i=0;i<csz;i++)
-			fprintf(f,"%s\n",content[i]);
-
-		fclose(f);
-
-		rename(dir,full_path_to_userdb_file);
-		turn_free(dir,dirsz+1);
 	}
 
 	return 0;

+ 2 - 3
src/apps/relay/userdb.h

@@ -48,7 +48,7 @@ extern "C" {
 
 //////////// Defines //////////////////////////////
 
-#define DEFAULT_USERDB_FILE "turnuserdb.conf"
+#define DEFAULT_USERDB_FILE "/var/db/turndb"
 
 #define AUTH_SECRET_SIZE (512)
 
@@ -100,7 +100,7 @@ struct auth_message {
 };
 
 enum _TURN_USERDB_TYPE {
-	TURN_USERDB_TYPE_FILE=0
+	TURN_USERDB_TYPE_SQLITE=0
 #if !defined(TURN_NO_PQ)
 	,TURN_USERDB_TYPE_PQ
 #endif
@@ -202,7 +202,6 @@ void release_allocation_quota(u08bits *username, int oauth, u08bits *realm);
 	void run_db_test(void);
 #endif
 
-void read_userdb_file(int to_print);
 void auth_ping(redis_context_handle rch);
 void reread_realms(void);
 int add_user_account(char *user, int dynamic);

+ 2 - 2
src/ns_turn_defs.h

@@ -31,8 +31,8 @@
 #ifndef __IOADEFS__
 #define __IOADEFS__
 
-#define TURN_SERVER_VERSION "4.2.3.2"
-#define TURN_SERVER_VERSION_NAME "Monza"
+#define TURN_SERVER_VERSION "4.3.1.1"
+#define TURN_SERVER_VERSION_NAME "Tolomei"
 #define TURN_SOFTWARE "Coturn-" TURN_SERVER_VERSION " '" TURN_SERVER_VERSION_NAME "'"
 
 #if (defined(__unix__) || defined(unix)) && !defined(USG)