diff --git a/ChangeLog b/ChangeLog index 0e9c117..e9416b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ 11/10/2014 Oleg Moskalenko -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 Version 4.2.3.1 'Monza': diff --git a/INSTALL b/INSTALL index b4140dc..85d314d 100644 --- a/INSTALL +++ b/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 " (Linux), "ldconfig -m " (BSD) or "crle -u -l " -(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 diff --git a/Makefile.in b/Makefile.in index 7a90ea2..e4f3128 100755 --- a/Makefile.in +++ b/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 diff --git a/README.turnadmin b/README.turnadmin index bd0bc51..a2f6b27 100644 --- a/README.turnadmin +++ b/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 -r -p -Add/update a user in the userdb file or in the database: +Add/update a user in the in the database: $ turnadmin -a [-b | -e | -M | -N ] -u -r -p -Delete a user from the userdb file or from the database: +Delete a user from the database: $ turnadmin -d [-b | -e | -M | -N ] -u -r @@ -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 diff --git a/README.turnserver b/README.turnserver index 31812e4..b82b174 100644 --- a/README.turnserver +++ b/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 diff --git a/README.turnutils b/README.turnutils index 106983e..61757a2 100644 --- a/README.turnutils +++ b/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 diff --git a/STATUS b/STATUS index d5cd76e..d908316 100644 --- a/STATUS +++ b/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. diff --git a/configure b/configure index bc31588..bf3e8e4 100755 --- a/configure +++ b/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 +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 ########################### diff --git a/examples/etc/turnserver.conf b/examples/etc/turnserver.conf index 0d1aef0..0e58368 100644 --- a/examples/etc/turnserver.conf +++ b/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. +# SQLite database file name. # -# Default file name is turnuserdb.conf. +# 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. diff --git a/examples/etc/turnuserdb.conf b/examples/etc/turnuserdb.conf deleted file mode 100644 index 340fd00..0000000 --- a/examples/etc/turnuserdb.conf +++ /dev/null @@ -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 -# diff --git a/examples/var/db/turndb b/examples/var/db/turndb new file mode 100644 index 0000000..45de984 Binary files /dev/null and b/examples/var/db/turndb differ diff --git a/man/man1/turnadmin.1 b/man/man1/turnadmin.1 index 41688d1..f58dcbb 100644 --- a/man/man1/turnadmin.1 +++ b/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 \fB\-r\fP \fB\-p\fP .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 | \fB\-e\fP | \fB\-M\fP | \fB\-N\fP ] \fB\-u\fP \fB\-r\fP \fB\-p\fP .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 | \fB\-e\fP | \fB\-M\fP | \fB\-N\fP ] \fB\-u\fP \fB\-r\fP .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 diff --git a/man/man1/turnserver.1 b/man/man1/turnserver.1 index 2f921a9..48391ee 100644 --- a/man/man1/turnserver.1 +++ b/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 diff --git a/man/man1/turnutils.1 b/man/man1/turnutils.1 index 260ca5f..af881a1 100644 --- a/man/man1/turnutils.1 +++ b/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 diff --git a/postinstall.txt b/postinstall.txt index b6546c1..4f06f44 100644 --- a/postinstall.txt +++ b/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. diff --git a/rpm/build.settings.sh b/rpm/build.settings.sh index 4ba01ef..093eed7 100755 --- a/rpm/build.settings.sh +++ b/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 diff --git a/rpm/turnserver.spec b/rpm/turnserver.spec index b207071..49f119e 100644 --- a/rpm/turnserver.spec +++ b/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 - - Sync to 4.2.3.2 + - Sync to 4.3.1.1 * Thu Nov 07 2014 Oleg Moskalenko - Sync to 4.2.3.1 * Sun Oct 26 2014 Oleg Moskalenko diff --git a/src/apps/relay/dbdrivers/dbd_sqlite.c b/src/apps/relay/dbdrivers/dbd_sqlite.c new file mode 100644 index 0000000..6a53df5 --- /dev/null +++ b/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 + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#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;iikm_key,PQgetvalue(res,0,0)); + key->timestamp = (u64bits)strtoll(PQgetvalue(res,0,1),NULL,10); + key->lifetime = (u32bits)strtol(PQgetvalue(res,0,2),NULL,10); + STRCPY((char*)key->hkdf_hash_func,PQgetvalue(res,0,3)); + STRCPY((char*)key->as_rs_alg,PQgetvalue(res,0,4)); + STRCPY((char*)key->as_rs_key,PQgetvalue(res,0,5)); + STRCPY((char*)key->auth_alg,PQgetvalue(res,0,6)); + STRCPY((char*)key->auth_key,PQgetvalue(res,0,7)); + STRCPY((char*)key->kid,kid); + ret = 0; + } + + if(res) { + PQclear(res); + } + } + + return ret; +} + +static int pgsql_list_oauth_keys(void) { + + oauth_key_data_raw key_; + oauth_key_data_raw *key=&key_; + + int ret = -1; + + char statement[TURN_LONG_STRING_SIZE]; + snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,hkdf_hash_func,as_rs_alg,as_rs_key,auth_alg,auth_key,kid from oauth_key order by kid"); + + PGconn * pqc = get_pqdb_connection(); + if(pqc) { + PGresult *res = PQexec(pqc, statement); + + if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc)); + } else { + int i = 0; + for(i=0;iikm_key,PQgetvalue(res,i,0)); + key->timestamp = (u64bits)strtoll(PQgetvalue(res,i,1),NULL,10); + key->lifetime = (u32bits)strtol(PQgetvalue(res,i,2),NULL,10); + STRCPY((char*)key->hkdf_hash_func,PQgetvalue(res,i,3)); + STRCPY((char*)key->as_rs_alg,PQgetvalue(res,i,4)); + STRCPY((char*)key->as_rs_key,PQgetvalue(res,i,5)); + STRCPY((char*)key->auth_alg,PQgetvalue(res,i,6)); + STRCPY((char*)key->auth_key,PQgetvalue(res,i,7)); + STRCPY((char*)key->kid,PQgetvalue(res,i,8)); + + printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, hkdf_hash_func=%s, as_rs_alg=%s, as_rs_key=%s, auth_alg=%s, auth_key=%s\n", + key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime, key->hkdf_hash_func, + key->as_rs_alg, key->as_rs_key, key->auth_alg, key->auth_key); + + ret = 0; + } + } + + if(res) { + PQclear(res); + } + } + + return ret; +} + +static int pgsql_set_user_key(u08bits *usname, u08bits *realm, const char *key) { + int ret = -1; + 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> %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;isz; + unlock_realms(); + + for (i = 0; isecrets[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;ioptions.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; +} diff --git a/src/apps/relay/dbdrivers/dbd_sqlite.h b/src/apps/relay/dbdrivers/dbd_sqlite.h new file mode 100644 index 0000000..c1e9548 --- /dev/null +++ b/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__/// + diff --git a/src/apps/relay/dbdrivers/dbdriver.c b/src/apps/relay/dbdrivers/dbdriver.c index abf797f..ecae703 100644 --- a/src/apps/relay/dbdrivers/dbdriver.c +++ b/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(); diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c index 70600f3..f294a93 100644 --- a/src/apps/relay/mainrelay.c +++ b/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 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 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 Configuration file name (default - turnserver.conf).\n" -" -b, --userdb User database file name (default - turnuserdb.conf) for long-term credentials only.\n" +" -b, , --db, --userdb SQLite database file name (default - "DEFAULT_USERDB_FILE").\n" #if !defined(TURN_NO_PQ) " -e, --psql-userdb, --sql-userdb 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= Add shared secret for TURN RESP API\n" " -S, --show-secret Show stored shared secrets for TURN REST API\n" " -X, --delete-secret= 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"); } } diff --git a/src/apps/relay/netengine.c b/src/apps/relay/netengine.c index e8c44d9..86ae447 100644 --- a/src/apps/relay/netengine.c +++ b/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) diff --git a/src/apps/relay/turncli.c b/src/apps/relay/turncli.c index 2c67aa6..cf12908 100644 --- a/src/apps/relay/turncli.c +++ b/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: diff --git a/src/apps/relay/userdb.c b/src/apps/relay/userdb.c index bb7e780..816a99a 100644 --- a/src/apps/relay/userdb.c +++ b/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;(i2);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;iuserdb); - - 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